macroAssembler_x86#biased_locking_enter[1]代码分析的注释版本:
// 使用Java 11版本源码,见Tips 1
int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, Register tmp_reg, bool swap_reg_contains_mark, Label& done, Label* slow_case, BiasedLockingCounters* counters) {
// 定义对象的markOop地址
Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
Address saved_mark_addr(lock_reg, 0);
// 目前状况:不知道是否可偏向
// 分支1:开始,判断是否可偏向
Label cas_label;
int null_check_offset = -1;
// swap_reg_contains_mark = false
if (!swap_reg_contains_mark) {
null_check_offset = offset();
// 将对象的markOop放入swap_reg
movptr(swap_reg, mark_addr);
}
// 将swap_reg(对象的markOop)放入tmp_reg
movptr(tmp_reg, swap_reg);
// 取markOop后三位(偏向锁标志 + 锁标志)
// markOopDesc::biased_lock_mask_in_place = 0B0111,见Tips 2
// tmp_reg & biased_lock_mask_in_place
andptr(tmp_reg, markOopDesc::biased_lock_mask_in_place);
// 判断是否为偏向锁,见Tips 3
// markOopDesc::biased_lock_pattern = 0B0101
cmpptr(tmp_reg, markOopDesc::biased_lock_pattern);
// 相等,说明处于可偏向状态,继续向下执行
// 不相等,则说明已经不可偏向,跳转到标签cas_label,见Tips 4
jcc(Assembler::notEqual, cas_label);
// 分支1:结束
// 目前状况:可偏向
// 分支2:开始,判断是否重入偏向锁
// 加载obj_reg的markOop到temp_reg中
load_prototype_header(tmp_reg, obj_reg);
xorptr(tmp_reg, swap_reg);
// 当前线程id写入到swap_reg
get_thread(swap_reg);
// 异或操作
// tmp_reg = 对象markOop的线程id
// swap_reg = 线程id
xorptr(swap_reg, tmp_reg);
Register header_reg = swap_reg;
// 设置分代年龄
// age_mask_in_place = 0B0000
andptr(header_reg, ~((int) markOopDesc::age_mask_in_place));
if (counters != NULL) {
cond_inc32(Assembler::zero, ExternalAddress((address) counters->biased_lock_entry_count_addr()));
}
// 相等,说明是线程重入偏向锁,跳转到标签done,见Tips 5
// 不相等,线程id,epoch或markOop后3位不相同,继续向下执行
jcc(Assembler::equal, done);
// 分支2:结束
// 撤销偏向标签
Label try_revoke_bias;
// 重偏向标签
Label try_rebias;
// 目前状况:理论上可偏向,但实际不清楚
// 分支3:开始,判断是否仍旧可偏向
// 可能存在撤销偏向锁的情况,即锁升级
// 判断markOop后三位(偏向锁标志 + 锁标志)
testptr(header_reg, markOopDesc::biased_lock_mask_in_place);
// 相等,说明依旧是偏向锁,继续向下执行
// 不相等,说明锁已经不可偏向,跳转到标签try_revoke_bias
jccb(Assembler::notZero, try_revoke_bias);
// 分支3:结束
// 目前状况:可偏向,epoch不相同
// 分支4:开始,判断是否epoch过期
// 判断epoch是否相同
testptr(header_reg, markOopDesc::epoch_mask_in_place);
// 相同,说明存在线程竞争,继续向下执行
// 不相同,说明epoch过期,跳转到标签try_rebias
jccb(Assembler::notZero, try_rebias);
// 分支4:结束
// 目前状况:可偏向,epoch未过期
// 分支5:开始,尝试CAS替换线程ID
movptr(swap_reg, saved_mark_addr);
// 构造线程id为0,其余与对象markOop相同的markOop写入swap_reg
andptr(swap_reg, markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
// 当前线程id写入到tmp_reg
get_thread(tmp_reg);
// 或操作
// 构造线程id为当前线程,其余与对象markOop相同的markOop写入tmp_reg
orptr(tmp_reg, swap_reg);
// 多核CPU加锁
if (os::is_MP()) {
lock();
}
// CAS替换对象的markOop为tmp_reg中存储的markOop
cmpxchgptr(tmp_reg, mark_addr);
if (counters != NULL) {
cond_inc32(Assembler::zero, ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
}
// CAS的结果不为0(Assembler::notZero),替换失败
// 此时存在锁竞争,进行锁升级,跳转到标签slow_case,见Tips 6
if (slow_case != NULL) {
jcc(Assembler::notZero, *slow_case);
}
// 结果为0,替换成功,不存在竞争,跳转到标签done
jmp(done);
// 分支5:结束
// 标签:重新偏向(try_rebias)开始(与分支5基本相同)
// 针对于分支4,epoch过期的逻辑
bind(try_rebias);
load_prototype_header(tmp_reg, obj_reg);
get_thread(swap_reg);
orptr(tmp_reg, swap_reg);
movptr(swap_reg, saved_mark_addr);
if (os::is_MP()) {
lock();
}
cmpxchgptr(tmp_reg, mark_addr);
if (counters != NULL) {
cond_inc32(Assembler::zero, ExternalAddress((address) counters->rebiased_lock_entry_count_addr()));
}
if (slow_case != NULL) {
jcc(Assembler::notZero, *slow_case);
}
jmp(done);
// 标签:重偏向(try_rebias)结束
// 标签:撤销(try_revoke_bias)开始
// 将对象的markOop重置为klass的markOop
bind(try_revoke_bias);
movptr(swap_reg, saved_mark_addr);
load_prototype_header(tmp_reg, obj_reg);
if (os::is_MP()) {
lock();
}
// CAS替换(撤销)
// 结果为0,说明当前线程撤销偏向锁成功
// 结果不为0,说明撤销偏向锁存在竞争,其他线程撤销成功
cmpxchgptr(tmp_reg, mark_addr);
if (counters != NULL) {
cond_inc32(Assembler::zero, ExternalAddress((address) counters->revoked_lock_entry_count_addr()));
}
// 标签:撤销(try_revoke_bias)结束
bind(cas_label);
return null_check_offset;
}
Tips:
markOopDesc::biased_lock_pattern = 0B0101时,偏向锁处于匿名偏向状态,markOop中并未偏向指定线程,说明是可偏向的状态;jcc可以简单理解为,判断后跳转;biasedLocking#revoke_and_rebias[4]代码分析的注释版本:
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
markOop mark = obj->mark();
if (mark->is_biased_anonymously() && !attempt_rebias) {
// 从monitorenter执行到这里时
// attempt_rebias = true
markOop biased_value = mark;
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
// CAS替换(撤销偏向锁)
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED;
}
} else if (mark->has_bias_pattern()) {
Klass* k = obj->klass();
markOop prototype_header = k->prototype_header();
if (!prototype_header->has_bias_pattern()) {
// klass关闭偏向锁场景
markOop biased_value = mark;
// CAS替换(撤销)
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);
return BIAS_REVOKED;
} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
// epoch过期的场景
if (attempt_rebias) {
// 允许重偏向的场景
markOop biased_value = mark;
markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());
// CAS替换(重偏向)
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED_AND_REBIASED;
}
} else {
// 不允许重偏向的场景
markOop biased_value = mark;
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
// CAS替换(撤销)
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED;
}
}
}
}
// 批量重偏向与批量撤销
HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias);
if (heuristics == HR_NOT_BIASED) {
return NOT_BIASED;
} else if (heuristics == HR_SINGLE_REVOKE) {
Klass *k = obj->klass();
markOop prototype_header = k->prototype_header();
if (mark->biased_locker() == THREAD && prototype_header->bias_epoch() == mark->bias_epoch()) {
ResourceMark rm;
if (TraceBiasedLocking) {
tty->print_cr("Revoking bias by walking my own stack:");
}
BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD);
((JavaThread*) THREAD)->set_cached_monitor_info(NULL);
return cond;
} else {
VM_RevokeBias revoke(&obj, (JavaThread*) THREAD);
VMThread::execute(&revoke);
return revoke.status_code();
}
}
VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, (heuristics == HR_BULK_REBIAS), attempt_rebias);
VMThread::execute(&bulk_revoke);
return bulk_revoke.status_code();
}
Tips:批量撤销和批量重偏向的
macroAssembler_x86#biased_locking_enter#l1107: https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/hotspot/cpu/x86/macroAssembler_x86.cpp#l1107
[2]interp_masm_x86#lock_object#l1232: https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/hotspot/cpu/x86/interp_masm_x86.cpp#l1232
[3]interp_masm_x86#lock_object#l1225: https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/hotspot/cpu/x86/interp_masm_x86.cpp#l1225
[4]biasedLocking#revoke_and_rebias: https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/hotspot/share/runtime/biasedLocking.cpp#l623