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
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
分析,有三个值,内存值V,旧的预期值A,新的修改值B;
如果A==V,那么把B赋值给V,返回V,如果A!=V,直接返回V;
进入
jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) { assert(sizeof(jbyte) == 1, "assumption."); uintptr_t dest_addr = (uintptr_t)dest; uintptr_t offset = dest_addr % sizeof(jint); volatile jint* dest_int = (volatile jint*)(dest_addr - offset); jint cur = *dest_int; jbyte* cur_as_bytes = (jbyte*)(&cur); jint new_val = cur; jbyte* new_val_as_bytes = (jbyte*)(&new_val); new_val_as_bytes[offset] = exchange_value; while (cur_as_bytes[offset] == compare_value) { jint res = cmpxchg(new_val, dest_int, cur);//
if (res == cur) break; cur = res; new_val = cur; new_val_as_bytes[offset] = exchange_value; } return cur_as_bytes[offset]; }
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) {
//
return _Atomic_cmpxchg_long(exchange_value, dest, compare_value, os::is_MP());
}
//
inline jlong _Atomic_cmpxchg_long(jlong exchange_value, volatile jlong* dest, jlong compare_value, int mp) {
#ifdef AMD64 __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp) : "cc", "memory"); return exchange_value; #else return _Atomic_cmpxchg_long_gcc(exchange_value, dest, compare_value, os::is_MP()); #if 0 // The code below does not work presumably because of the bug in gcc // The error message says: // can't find a register in class BREG while reloading asm // However I want to save this code and later replace _Atomic_cmpxchg_long_gcc // with such inline asm code: volatile jlong_accessor evl, cvl, rv; evl.long_value = exchange_value; cvl.long_value = compare_value; int mp = os::is_MP(); __asm__ volatile ("cmp $0, %%esi\n\t" "je 1f \n\t" "lock\n\t" "1: cmpxchg8b (%%edi)\n\t" : "=a"(cvl.words[0]), "=d"(cvl.words[1]) : "a"(cvl.words[0]), "d"(cvl.words[1]), "b"(evl.words[0]), "c"(evl.words[1]), "D"(dest), "S"(mp) : "cc", "memory"); return cvl.long_value; #endif // if 0 #endif // AMD64 }