CAS源码浅析
学过Java的对下面的一定不是很陌生,我来做一个源码浅析,以compareAndSwapInt为例
compareAndSwapInt
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
查看native的源码
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
// 解析相关看下面的源码
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
resolve
inline oop JNIHandles::resolve(jobject handle) {
oop result = NULL;
if (handle != NULL) {
result = resolve_impl<false /* external_guard */ >(handle);
}
return result;
}
resolve_impl
// 如果从 resolve_external_guard 调用 external_guard 为真。
template<bool external_guard>
inline oop JNIHandles::resolve_impl(jobject handle) {
assert(handle != NULL, "precondition");
oop result;
// 1. 先判断是否是jweak
// 是: 将handler 转为 oop
// 否:对象转为 oop* 之后断言判断是否可以读取数据,在转为oop
if (is_jweak(handle)) { // Unlikely
result = resolve_jweak<external_guard>(handle);
} else {
/*
inline oop& JNIHandles::jobject_ref(jobject handle) {
assert(!is_jweak(handle), "precondition");
return *reinterpret_cast<oop*>(handle);
}
*/
result = jobject_ref(handle);
// 作业对象的构造将空值规范化为空作业对象,因此对于非 jweak 指针永远不应为空。
assert(external_guard || result != NULL,
"Invalid value read from jni handle");
result = guard_value<external_guard>(result);
}
return result;
}
is_jweak
// 用于区分 jweak 的 jobject 中的低标记位。
// jweak 类型等价于 jobject,但有些地方我们需要能够将 jweak 值与其他 jobject 区分开来,
// 而 is_weak_global_handle 出于性能原因不适合。为了提供这样的测试,
// 我们将weak_tag_value 添加到由jobject 指定的(对齐的)字节地址以产生相应的jweak。
// 访问一个项目的价值必须考虑到它是一个可能的偏移 jweak。
static const uintptr_t weak_tag_size = 1;
static const uintptr_t weak_tag_alignment = (1u << weak_tag_size); // 例如 1000
static const uintptr_t weak_tag_mask = weak_tag_alignment - 1; // 111 全为1
static const int weak_tag_value = 1;
inline bool JNIHandles::is_jweak(jobject handle) {
STATIC_ASSERT(weak_tag_size == 1);
STATIC_ASSERT(weak_tag_value == 1);
// reinterpret_cast 通过重新解释底层位模式在类型之间进行转换。 reinterpret_cast <新式> ( 表达 )
return (reinterpret_cast<uintptr_t>(handle) & weak_tag_mask) != 0; // weak_tag_mask 全为 1 & ? != 0 至少有一位是 1,有数据
}
resolve_jweak
template<bool external_guard>
oop JNIHandles::resolve_jweak(jweak handle) {
assert(is_jweak(handle), "precondition");
// 找到handler的引用转换为 oop指针类型
oop result = jweak_ref(handle);
// 如果从 resolve_external_guard 调用 external_guard 为真。
// 对于 external_guard 将已删除(并且可能已删除)视为 NULL,
// 否则视为(断言)错误。
result = guard_value<external_guard>(result);
#if INCLUDE_ALL_GCS
if (result != NULL && UseG1GC) {
G1SATBCardTableModRefBS::enqueue(result);
}
#endif // INCLUDE_ALL_GCS
return result;
}
jweak_ref
// 找到handler的引用转换为 oop指针类型
inline oop& JNIHandles::jweak_ref(jobject handle) {
assert(is_jweak(handle), "precondition");
char* ptr = reinterpret_cast<char*>(handle) - weak_tag_value;
return *reinterpret_cast<oop*>(ptr);
}
guard_value
// 如果从 resolve_external_guard 调用 external_guard 为真。
// 对于 external_guard 将已删除(并且可能已删除)视为 NULL,
// 否则视为(断言)错误。
template<bool external_guard>
inline oop JNIHandles::guard_value(oop value) {
if (!external_guard) {
assert(value != badJNIHandle, "Pointing to zapped jni handle area");
assert(value != deleted_handle(), "Used a deleted global handle");
} else if ((value == badJNIHandle) || (value == deleted_handle())) {
value = NULL;
}
return value;
}
index_oop_from_field_offset_long
// 找到 oop的索引
inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) {
// 将field_offset 作为 字节索引
jlong byte_offset = field_offset_to_byte_offset(field_offset);
#ifdef ASSERT
if (p != NULL) {
assert(byte_offset >= 0 && byte_offset <= (jlong)MAX_OBJECT_SIZE, "sane offset");
if (byte_offset == (jint)byte_offset) {
void* ptr_plus_disp = (address)p + byte_offset;
assert((void*)p->obj_field_addr<oop>((jint)byte_offset) == ptr_plus_disp,
"raw [ptr+disp] must be consistent with oop::field_base");
}
jlong p_size = HeapWordSize * (jlong)(p->size());
assert(byte_offset < p_size, err_msg("Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size));
}
#endif
if (sizeof(char*) == sizeof(jint)) // (this constant folds!)
return (address)p + (jint) byte_offset;
else
return (address)p + byte_offset;
}
cmpxchg
unsigned Atomic::cmpxchg(unsigned int exchange_value,
volatile unsigned int* dest, unsigned int compare_value) {
assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
(jint)compare_value);
}
linux 系统
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value)
{
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
__sync_val_compare_and_swap
#ifndef _LP64
extern "C" {
long long unsigned int __sync_val_compare_and_swap_8(
volatile void *ptr,
long long unsigned int oldval,
long long unsigned int newval) {
ShouldNotCallThis();
return 0; // silence compiler warnings
}
};
#endif // !_LP64
plan9汇编
0x0053 00083 (E:\Go\src\study\testSource\Test01.go:12) MOVQ "".&counter+64(SP), CX
0x0058 00088 (E:\Go\src\study\testSource\Test01.go:12) LEAL 1(AX), DX
0x005b 00091 (E:\Go\src\study\testSource\Test01.go:12) LOCK
// CMPXCHG r/m,r 将累加器AL/AX/EAX/RAX中的值与首操作数(目的操作数)比较,如果相等,第2操作数(源操作数)的值装载到首操作数,zf置1。如果不等,首操作数的值装载到AL/AX/EAX/RAX并将zf清0 DX == CX 如果相等 那么直接 CX 赋值到 DX 不相等 将DX 装载,ZF标识清0
0x005c 00092 (E:\Go\src\study\testSource\Test01.go:12) CMPXCHGL DX, (CX)
0x005f 00095 (E:\Go\src\study\testSource\Test01.go:12) SETEQ AL
0x0062 00098 (E:\Go\src\study\testSource\Test01.go:12) MOVB AL, "".ok+50(SP)
最终利用CPU指令CMPXCHG进行CAS的执行。