CAS源码浅析

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的执行。