10 偏向锁的退出的调试
前言
09 给对象添加偏向锁的调试 , 接着文章 继续调试偏向锁, 我们这里要调试的场景是 偏向锁退出的场景
一下内容基于 jdk9 + lldb-1001.0.13.3
另外一下 运行时数据可能是来自于多次调试, 可能会存在运行时数据 对不上的情况, 但是的条理逻辑会在文字中描述清楚的
偏向锁退出测试用例
package com.hx.test04;/*** SynchronizedObject** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2020-04-03 15:14*/
public class Test26SynchronizeObject implements Cloneable {// identStrprivate String identStr = "xyz";int f01;int f02;int f03;int f04;int f05;// Test25SynchronizeObjectpublic static void main(String[] args) throws Exception {Test26SynchronizeObject lockObj = new Test26SynchronizeObject();synchronized (lockObj) {// Test26SynchronizeObject cloned = (Test26SynchronizeObject) lockObj.clone();
// System.out.println(lockObj.identStr);}}}
对应的字节码信息如下, 下面参照可能需要使用到
master:classes jerry$ javap -c com/hx/test04/Test26SynchronizeObject.class
Compiled from "Test26SynchronizeObject.java"
public class com.hx.test04.Test26SynchronizeObject implements java.lang.Cloneable {int f01;int f02;int f03;int f04;int f05;public com.hx.test04.Test26SynchronizeObject();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."":()V4: aload_05: ldc #2 // String xyz7: putfield #3 // Field identStr:Ljava/lang/String;10: returnpublic static void main(java.lang.String[]) throws java.lang.Exception;Code:0: new #4 // class com/hx/test04/Test26SynchronizeObject3: dup4: invokespecial #5 // Method "":()V7: astore_18: aload_19: dup10: astore_211: monitorenter12: aload_213: monitorexit14: goto 2217: astore_318: aload_219: monitorexit20: aload_321: athrow22: returnException table:from to target type12 14 17 any17 20 17 any
}
进入lldb的调试
进入lldb 之后如下, 省略了一部分输出, 不过应该能够看出 当前端点是停在了 javaCalls.cpp -l 410 这里
Process 2543 resuming
Process 2543 stopped
* thread #5, stop reason = breakpoint 1.1frame #0: 0x0000000103923592 libjvm.dylib`::jni_CallStaticVoidMethod(env=0x0000000101005a28, cls=0x00000001001061d0, methodID=0x0000000104905990) at jni.cpp:1989:211986 va_start(args, methodID);1987 JavaValue jvalue(T_VOID);1988 JNI_ArgumentPusherVaArg ap(methodID, args);
-> 1989 jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK);1990 va_end(args);1991 JNI_END1992
Target 0: (java) stopped.(lldb) br set -f javaCalls.cpp -l 410
Breakpoint 2: where = libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*) + 1496 at javaCalls.cpp:410:7, address = 0x00000001038eba68
(lldb) c
Process 2543 resuming
Process 2543 stopped
* thread #5, stop reason = breakpoint 2.1frame #0: 0x00000001038eba68 libjvm.dylib`JavaCalls::call_helper(result=0x0000700004af3d48, method=0x0000700004af3a48, args=0x0000700004af3a90, __the_thread__=0x0000000101005800) at javaCalls.cpp:410:7407 { JavaCallWrapper link(method, receiver, result, CHECK);408 { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner409
-> 410 StubRoutines::call_stub()(411 (address)&link,412 // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)413 result_val_address, // see NOTE above (compiler problem)
Target 0: (java) stopped.(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010584f980 "XH;"
定位一下当前方法, 当前这里正是在调用 main 方法
(lldb) p method()->print()
{method}- this oop: 0x000000011d36ffd8- method holder: 'com/hx/test04/Test26SynchronizeObject'- constants: 0x000000011d36fc68 constant pool [45] {0x000000011d36fc68} for 'com/hx/test04/Test26SynchronizeObject' cache=0x000000011d370050- access: 0x20000009 public static - name: 'main'- signature: '([Ljava/lang/String;)V'- max stack: 3- max locals: 4- size of params: 1- method size: 11- vtable index: -2- i2i entry: 0x000000010582a700- adapters: AHE@0x00000001018770e0: 0xb0000000 i2c: 0x00000001059a4460 c2i: 0x00000001059a459a c2iUV: 0x00000001059a456d- compiled entry 0x00000001059a459a- code size: 23- code start: 0x000000011d36ff88- code end (excl): 0x000000011d36ff9f- checked ex length: 1- checked ex start: 0x000000011d36ffd4- linenumber start: 0x000000011d36ff9f- localvar length: 2- localvar start: 0x000000011d36ffa8
接着在 monitor_exit 的地方打上一个断点
(lldb) p _active_table._table[9][195]
(address) $1 = 0x000000010504fde0 "XH;"
(lldb) b 0x000000010504fde1
Breakpoint 3: address = 0x000000010504fde1
(lldb) c
Process 2555 resuming
Process 2555 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x000000010504fde1
-> 0x10504fde1: cmpq (%rax), %rax0x10504fde4: movq -0x48(%rbp), %rsi0x10504fde8: leaq -0x48(%rbp), %rdx0x10504fdec: jmp 0x10504fdfc
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000747bb8748rbx = 0x00000000000000c3rcx = 0x0000000747bb8748rdx = 0x0000700003d92638rdi = 0x0000000104801800rsi = 0x0000700003d92628rbp = 0x0000700003d92680rsp = 0x0000700003d92628r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000103b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006ffeff58fe00r12 = 0x0000000000000000r13 = 0x000000011c96ff95r14 = 0x0000700003d926a8r15 = 0x0000000104801800rip = 0x000000010504fde1rflags = 0x0000000000000206cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x000000011c96ff95
0x11c96ff95: c3 a7 00 08 4e 2c c3 2d bf b1 ff 00 2e 42 25 52 ç..N,?-???..B%R
0x11c96ffa5: 00 00 00 00 00 17 00 19 00 1a 00 00 00 00 00 08 ................
(lldb) p ((oopDesc*)0x0000000747bb8748)->print()
com.hx.test04.Test26SynchronizeObject
{0x0000000747bb8748} - klass: 'com/hx/test04/Test26SynchronizeObject'- ---- fields (total size 5 words):- 'f01' 'I' @12 0- 'f02' 'I' @16 0- 'f03' 'I' @20 0- 'f04' 'I' @24 0- 'f05' 'I' @28 0- private 'identStr' 'Ljava/lang/String;' @32 "xyz"{0x0000000747bb8770} (e8f770ee 0)
(lldb) p ((oopDesc*)0x0000000747bb8748)->mark()->biased_locker()->threadObj()->print()
java.lang.Thread
{0x0000000747f069d8} - klass: 'java/lang/Thread'- ---- fields (total size 47 words):- private 'priority' 'I' @12 5- private 'eetop' 'J' @16 4370470912 (4801800 1)- private 'stackSize' 'J' @24 0 (0 0)- private 'nativeParkEventPointer' 'J' @32 0 (0 0)- private 'tid' 'J' @40 1 (1 0)- private volatile 'threadStatus' 'I' @48 5- private 'single_step' 'Z' @52 false- private 'daemon' 'Z' @53 false- private 'stillborn' 'Z' @54 false- private volatile 'name' 'Ljava/lang/String;' @56 "main"{0x0000000747f06b50} (e8fe0d6a 0)- private 'threadQ' 'Ljava/lang/Thread;' @60 NULL (0 0)- private 'target' 'Ljava/lang/Runnable;' @64 NULL (0 e8fe0c85)- private 'group' 'Ljava/lang/ThreadGroup;' @68 a 'java/lang/ThreadGroup'{0x0000000747f06428} (e8fe0c85 e8fc0af7)- private 'contextClassLoader' 'Ljava/lang/ClassLoader;' @72 a 'jdk/internal/loader/ClassLoaders$AppClassLoader'{0x0000000747e057b8} (e8fc0af7 e8fe0d91)- private 'inheritedAccessControlContext' 'Ljava/security/AccessControlContext;' @76 a 'java/security/AccessControlContext'{0x0000000747f06c88} (e8fe0d91 e8fe2fb8)- 'threadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @80 a 'java/lang/ThreadLocal$ThreadLocalMap'{0x0000000747f17dc0} (e8fe2fb8 0)- 'inheritableThreadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @84 NULL (0 0)- volatile 'parkBlocker' 'Ljava/lang/Object;' @88 NULL (0 0)- private volatile 'blocker' 'Lsun/nio/ch/Interruptible;' @92 NULL (0 e8fe0d70)- private final 'blockerLock' 'Ljava/lang/Object;' @96 a 'java/lang/Object'{0x0000000747f06b80} (e8fe0d70 0)- private volatile 'uncaughtExceptionHandler' 'Ljava/lang/Thread$UncaughtExceptionHandler;' @100 NULL (0 0)- 'threadLocalRandomSeed' 'J' @232 0 (0 0)- 'threadLocalRandomProbe' 'I' @240 0- 'threadLocalRandomSecondarySeed' 'I' @244 0
0xc3 表示 monitorenter, 0xa7 表示 goto, 0x4e 表示 astore_3
结合上面的字节码 很容易定位到当前是在执行 monitorexit
并且 lockObj 上面已经添加了 偏向锁
ax 存储的是对象 lockObj
查看一下 栈帧中的信息, 之所以要贴一下 栈帧信息, 是因为 monitorexit 里面的处理需要处理 栈帧中的一部分数据
(lldb) re r
General Purpose Registers:rax = 0x0000000747bb8748rbx = 0x00000000000000c3rcx = 0x0000000747bb8748rdx = 0x0000700003d92638rdi = 0x0000000104801800rsi = 0x0000700003d92628rbp = 0x0000700003d92680rsp = 0x0000700003d92628r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000103b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006ffeff58fe00r12 = 0x0000000000000000r13 = 0x000000011c96ff95r14 = 0x0000700003d926a8r15 = 0x0000000104801800rip = 0x000000010504fde1rflags = 0x0000000000000206cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x0000700003d92628 -c 0x100
0x700003d92628: 48 87 bb 47 07 00 00 00 48 87 bb 47 07 00 00 00 H.?G....H.?G....
0x700003d92638: 28 26 d9 03 00 70 00 00 94 ff 96 1c 01 00 00 00 (&?..p...?......
0x700003d92648: a8 26 d9 03 00 70 00 00 50 00 97 1c 01 00 00 00 ?&?..p..P.......
0x700003d92658: 00 00 00 00 00 00 00 00 28 82 bb 47 07 00 00 00 ........(.?G....
0x700003d92668: d8 ff 96 1c 01 00 00 00 00 00 00 00 00 00 00 00 ??..............
0x700003d92678: a8 26 d9 03 00 70 00 00 10 27 d9 03 00 70 00 00 ?&?..p...'?..p..
0x700003d92688: f1 09 00 05 01 00 00 00 00 00 00 00 00 00 00 00 ?...............
0x700003d92698: 48 87 bb 47 07 00 00 00 48 87 bb 47 07 00 00 00 H.?G....H.?G....
0x700003d926a8: 38 87 bb 47 07 00 00 00 a0 1f 00 00 03 00 00 00 8.?G....?.......
0x700003d926b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x700003d926c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x700003d926d8: 00 30 d9 03 00 70 00 00 20 28 d9 03 00 70 00 00 .0?..p.. (?..p..
0x700003d926e8: 50 2d d9 03 00 70 00 00 0a 00 00 00 00 70 00 00 P-?..p.......p..
0x700003d926f8: d8 ff 96 1c 01 00 00 00 00 a7 02 05 01 00 00 00 ??.......?......
0x700003d92708: a0 2a d9 03 00 70 00 00 e0 28 d9 03 00 70 00 00 ?*?..p..?(?..p..
0x700003d92718: 1d bb 0e 03 01 00 00 00 01 00 00 00 00 70 00 00 .?...........p..0x700003d92628 : 0x0000000747bb8748 : BasicLockObject.lock
0x700003d92630 : 0x0000000747bb8748 : BasicLockObject.obj
0x700003d92638 : 0x700003d92628 : expression bottom
0x700003d92640 : 0x00011c96ff94 : byte code pointer
0x700003d92648 : 0x700003d926a8 : pointer to locals
0x700003d92650 : 0x00011c970050 : constants pool cache
0x700003d92658 : 0x000000000000 : method data oop
0x700003d92660 : 0x0747bb8228 : java mirror
0x700003d92668 : 0x011c96ffd8 : method oop
0x700003d92670 : 0x000000000000 : last java stack pointer
0x700003d92678 : 0x700003d926a8 : old stack pointer
0x700003d92680 : 0x700003d92710 : old frame pointer
0x700003d92688 : 0x01050009f1 : return address[entry_point's address]
0x700003d92690 : 0x000000000000 : ex if exists
0x700003d92698 : 0x0000000747bb8748 : lockObj for monitor enter/exit
0x700003d926a0 : 0x0000000747bb8748 : lockObj
0x700003d926a8 : 0x0000000747bb8738 : args
0x700003d926b0 : 0x0300001fa0 : $mxcsr
查询BasicObjectLock
对应 monitorexit 的汇编的模板代码如下
templateTable_x86.cpp monitorexit
void TemplateTable::monitorexit() {transition(atos, vtos);// check for NULL object__ null_check(rax);const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize);const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;Register rtop = LP64_ONLY(c_rarg1) NOT_LP64(rdx);Register rbot = LP64_ONLY(c_rarg2) NOT_LP64(rbx);Label found;// find matching slot{Label entry, loop;__ movptr(rtop, monitor_block_top); // points to current entry,// starting with top-most entry__ lea(rbot, monitor_block_bot); // points to word before bottom// of monitor block__ jmpb(entry);__ bind(loop);// check if current entry is for same object__ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));// if same object then stop searching__ jcc(Assembler::equal, found);// otherwise advance to next entry__ addptr(rtop, entry_size);__ bind(entry);// check if bottom reached__ cmpptr(rtop, rbot);// if not at bottom then check this entry__ jcc(Assembler::notEqual, loop);}// error handling. Unlocking was not block-structured__ call_VM(noreg, CAST_FROM_FN_PTR(address,InterpreterRuntime::throw_illegal_monitor_state_exception));__ should_not_reach_here();// call run-time routine__ bind(found);__ push_ptr(rax); // make sure object is on stack (contract with oopMaps)__ unlock_object(rtop);__ pop_ptr(rax); // discard object
}
monitorexit 里面 unlock_object 之前对应的汇编如下
lldb) dis -s 0x000000010604fde0 -c 2000x10604fde0: popq %rax0x10604fde1: cmpq (%rax), %rax// rtop = expressionBottom// rbot = oldExpressionBottom0x10604fde4: movq -0x48(%rbp), %rsi0x10604fde8: leaq -0x48(%rbp), %rdx0x10604fdec: jmp 0x10604fdfc// BasicLockObject's loop// if (found) goto 0x1060500d8;0x10604fdee: cmpq 0x8(%rsi), %rax0x10604fdf2: je 0x1060500d80x10604fdf8: addq $0x10, %rsi0x10604fdfc: cmpq %rdx, %rsi0x10604fdff: jne 0x10604fdee// if (!found) InterpreterRuntime::throw_illegal_monitor_state_exception0x10604fe01: callq 0x10604fe0b0x10604fe06: jmp 0x1060500610x10604fe0b: leaq 0x8(%rsp), %rax0x10604fe10: movq %r13, -0x40(%rbp)0x10604fe14: cmpq $0x0, -0x10(%rbp)0x10604fe1c: je 0x10604fe990x10604fe22: movq %rsp, -0x28(%rsp)0x10604fe27: subq $0x80, %rsp0x10604fe2e: movq %rax, 0x78(%rsp)0x10604fe33: movq %rcx, 0x70(%rsp)0x10604fe38: movq %rdx, 0x68(%rsp)0x10604fe3d: movq %rbx, 0x60(%rsp)0x10604fe42: movq %rbp, 0x50(%rsp)0x10604fe47: movq %rsi, 0x48(%rsp)0x10604fe4c: movq %rdi, 0x40(%rsp)0x10604fe51: movq %r8, 0x38(%rsp)0x10604fe56: movq %r9, 0x30(%rsp)0x10604fe5b: movq %r10, 0x28(%rsp)0x10604fe60: movq %r11, 0x20(%rsp)0x10604fe65: movq %r12, 0x18(%rsp)0x10604fe6a: movq %r13, 0x10(%rsp)0x10604fe6f: movq %r14, 0x8(%rsp)0x10604fe74: movq %r15, (%rsp)0x10604fe78: movabsq $0x1048984ed, %rdi ; imm = 0x1048984ED 0x10604fe82: movabsq $0x10604fe22, %rsi ; imm = 0x10604FE22 0x10604fe8c: movq %rsp, %rdx0x10604fe8f: andq $-0x10, %rsp0x10604fe93: callq 0x10436af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x10604fe98: hlt 0x10604fe99: pushq %r100x10604fe9b: cmpq -0x15398b2(%rip), %r12 ; Universe::_narrow_ptrs_base0x10604fea2: je 0x10604ff1f0x10604fea8: movq %rsp, -0x28(%rsp)0x10604fead: subq $0x80, %rsp0x10604feb4: movq %rax, 0x78(%rsp)0x10604feb9: movq %rcx, 0x70(%rsp)0x10604febe: movq %rdx, 0x68(%rsp)0x10604fec3: movq %rbx, 0x60(%rsp)0x10604fec8: movq %rbp, 0x50(%rsp)0x10604fecd: movq %rsi, 0x48(%rsp)0x10604fed2: movq %rdi, 0x40(%rsp)0x10604fed7: movq %r8, 0x38(%rsp)0x10604fedc: movq %r9, 0x30(%rsp)0x10604fee1: movq %r10, 0x28(%rsp)0x10604fee6: movq %r11, 0x20(%rsp)0x10604feeb: movq %r12, 0x18(%rsp)0x10604fef0: movq %r13, 0x10(%rsp)0x10604fef5: movq %r14, 0x8(%rsp)0x10604fefa: movq %r15, (%rsp)0x10604fefe: movabsq $0x1048d4efc, %rdi ; imm = 0x1048D4EFC 0x10604ff08: movabsq $0x10604fea8, %rsi ; imm = 0x10604FEA8 0x10604ff12: movq %rsp, %rdx0x10604ff15: andq $-0x10, %rsp0x10604ff19: callq 0x10436af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x10604ff1e: hlt 0x10604ff1f: popq %r100x10604ff21: movq %r15, %rdi0x10604ff24: movq %rbp, 0x218(%r15)0x10604ff2b: movq %rax, 0x208(%r15)0x10604ff32: testl $0xf, %esp0x10604ff38: je 0x10604ff500x10604ff3e: subq $0x8, %rsp0x10604ff42: callq 0x1040d2a40 ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:6800x10604ff47: addq $0x8, %rsp0x10604ff4b: jmp 0x10604ff550x10604ff50: callq 0x1040d2a40 ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:6800x10604ff55: pushq %rax0x10604ff56: pushq %rdi0x10604ff57: pushq %rsi0x10604ff58: pushq %rdx0x10604ff59: pushq %rcx0x10604ff5a: pushq %r80x10604ff5c: pushq %r90x10604ff5e: pushq %r100x10604ff60: pushq %r110x10604ff62: testl $0xf, %esp0x10604ff68: je 0x10604ff800x10604ff6e: subq $0x8, %rsp0x10604ff72: callq 0x103803ae0 ; Thread::current at thread.hpp:6600x10604ff77: addq $0x8, %rsp0x10604ff7b: jmp 0x10604ff850x10604ff80: callq 0x103803ae0 ; Thread::current at thread.hpp:6600x10604ff85: popq %r110x10604ff87: popq %r100x10604ff89: popq %r90x10604ff8b: popq %r80x10604ff8d: popq %rcx0x10604ff8e: popq %rdx0x10604ff8f: popq %rsi0x10604ff90: popq %rdi0x10604ff91: cmpq %rax, %r150x10604ff94: je 0x1060500110x10604ff9a: movq %rsp, -0x28(%rsp)0x10604ff9f: subq $0x80, %rsp0x10604ffa6: movq %rax, 0x78(%rsp)0x10604ffab: movq %rcx, 0x70(%rsp)0x10604ffb0: movq %rdx, 0x68(%rsp)0x10604ffb5: movq %rbx, 0x60(%rsp)0x10604ffba: movq %rbp, 0x50(%rsp)0x10604ffbf: movq %rsi, 0x48(%rsp)0x10604ffc4: movq %rdi, 0x40(%rsp)0x10604ffc9: movq %r8, 0x38(%rsp)0x10604ffce: movq %r9, 0x30(%rsp)0x10604ffd3: movq %r10, 0x28(%rsp)0x10604ffd8: movq %r11, 0x20(%rsp)0x10604ffdd: movq %r12, 0x18(%rsp)0x10604ffe2: movq %r13, 0x10(%rsp)0x10604ffe7: movq %r14, 0x8(%rsp)0x10604ffec: movq %r15, (%rsp)0x10604fff0: movabsq $0x1048d5043, %rdi ; imm = 0x1048D5043 0x10604fffa: movabsq $0x10604ff9a, %rsi ; imm = 0x10604FF9A 0x106050004: movq %rsp, %rdx0x106050007: andq $-0x10, %rsp0x10605000b: callq 0x10436af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050010: hlt 0x106050011: popq %rax0x106050012: movabsq $0x0, %r100x10605001c: movq %r10, 0x208(%r15)0x106050023: movabsq $0x0, %r100x10605002d: movq %r10, 0x218(%r15)0x106050034: movabsq $0x0, %r100x10605003e: movq %r10, 0x210(%r15)0x106050045: cmpq $0x0, 0x8(%r15)0x10605004d: je 0x1060500580x106050053: jmp 0x1060007a00x106050058: movq -0x40(%rbp), %r130x10605005c: movq -0x38(%rbp), %r140x106050060: retq 0x106050061: movq %rsp, -0x28(%rsp)0x106050066: subq $0x80, %rsp0x10605006d: movq %rax, 0x78(%rsp)0x106050072: movq %rcx, 0x70(%rsp)0x106050077: movq %rdx, 0x68(%rsp)0x10605007c: movq %rbx, 0x60(%rsp)0x106050081: movq %rbp, 0x50(%rsp)0x106050086: movq %rsi, 0x48(%rsp)0x10605008b: movq %rdi, 0x40(%rsp)0x106050090: movq %r8, 0x38(%rsp)0x106050095: movq %r9, 0x30(%rsp)0x10605009a: movq %r10, 0x28(%rsp)0x10605009f: movq %r11, 0x20(%rsp)0x1060500a4: movq %r12, 0x18(%rsp)0x1060500a9: movq %r13, 0x10(%rsp)0x1060500ae: movq %r14, 0x8(%rsp)0x1060500b3: movq %r15, (%rsp)0x1060500b7: movabsq $0x1047f2a69, %rdi ; imm = 0x1047F2A69 0x1060500c1: movabsq $0x106050061, %rsi ; imm = 0x106050061 0x1060500cb: movq %rsp, %rdx0x1060500ce: andq $-0x10, %rsp0x1060500d2: callq 0x10436af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x1060500d7: hlt// unlock_object0x1060500d8: pushq %rax0x1060500d9: movq %r13, -0x40(%rbp)0x1060500dd: leaq (%rsi), %rax
别看这里 贴了这么多汇编出来, 实际核心的处理主要是 BasicLockObject's loop 这一段
查询 BasicLockObject 列表, 寻找 BasicLockObject.obj 为 lockObj 的记录, 然后 交给后面的 unlock_object 处理
如果找不到 表示还没有获取到锁, 抛出 IllegalStateException
unlock_object 的业务
interp_masm_x86.cpp unlock_object
// Unlocks an object. Used in monitorexit bytecode and
// remove_activation. Throws an IllegalMonitorException if object is
// not locked by current thread.
//
// Args:
// rdx, c_rarg1: BasicObjectLock for lock
//
// Kills:
// rax
// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs)
// rscratch1 (scratch reg)
// rax, rbx, rcx, rdx
void InterpreterMacroAssembler::unlock_object(Register lock_reg) {assert(lock_reg == LP64_ONLY(c_rarg1) NOT_LP64(rdx),"The argument is only for looks. It must be c_rarg1");if (UseHeavyMonitors) {call_VM(noreg,CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),lock_reg);} else {Label done;const Register swap_reg = rax; // Must use rax for cmpxchg instructionconst Register header_reg = LP64_ONLY(c_rarg2) NOT_LP64(rbx); // Will contain the old oopMarkconst Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oopsave_bcp(); // Save in case of exception// Convert from BasicObjectLock structure to object and BasicLock// structure Store the BasicLock address into %raxlea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes()));// Load oop into obj_reg(%c_rarg3)movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()));// Free entrymovptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD);if (UseBiasedLocking) {biased_locking_exit(obj_reg, header_reg, done);}// Load the old header from BasicLock structuremovptr(header_reg, Address(swap_reg,BasicLock::displaced_header_offset_in_bytes()));// Test for recursiontestptr(header_reg, header_reg);// zero for recursive casejcc(Assembler::zero, done);// Atomic swap back the old headerif (os::is_MP()) lock();cmpxchgptr(header_reg, Address(obj_reg, 0));// zero for simple unlock of a stack-lock casejcc(Assembler::zero, done);// Call the runtime routine for slow case.movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()),obj_reg); // restore objcall_VM(noreg,CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),lock_reg);bind(done);restore_bcp();}
}
macroAssembler_x86.cpp biased_locking_exit
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {assert(UseBiasedLocking, "why call this otherwise?");// Check for biased locking unlock case, which is a no-op// Note: we do not have to check the thread ID for two reasons.// First, the interpreter checks for IllegalMonitorStateException at// a higher level. Second, if the bias was revoked while we held the// lock, the object could not be rebiased toward another thread, so// the bias bit would be clear.movptr(temp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));andptr(temp_reg, markOopDesc::biased_lock_mask_in_place);cmpptr(temp_reg, markOopDesc::biased_lock_pattern);jcc(Assembler::equal, done);
}
unlock_object 这部分生成的汇编如下
(lldb) dis -s 0x1060500d8 -c 200
-> 0x1060500d8: pushq %rax// 寄存器映射 : swap_reg = rax, obj_reg = rcx, header_reg = rdx// save_bcp0x1060500d9: movq %r13, -0x40(%rbp)// rax = BasicObjectLock.lock// rcx = BasicObjectLock.obj// BasicObjectLock.obj = null0x1060500dd: leaq (%rsi), %rax0x1060500e0: movq 0x8(%rsi), %rcx0x1060500e4: movq $0x0, 0x8(%rsi)// biased_locking_exit// if(obj.mark().has_bias_pattern()) goto done;0x1060500ec: movq (%rcx), %rdx0x1060500ef: andq $0x7, %rdx0x1060500f3: cmpq $0x5, %rdx0x1060500f7: je 0x106050378// rdx = BasicObjectLock.lock.displaced_header// if(BasicObjectLock.lock.displaced_header == null) goto done;0x1060500fd: movq (%rax), %rdx0x106050100: testq %rdx, %rdx0x106050103: je 0x106050378// if(cas(rdx, lockObj.mark_addr, rax)) goto done;0x106050109: lock 0x10605010a: cmpxchgq %rdx, (%rcx)0x10605010e: je 0x106050378// BasicObjectLock.obj = lockObj// InterpreterRuntime::monitorexit0x106050114: movq %rcx, 0x8(%rsi)0x106050118: callq 0x1060501220x10605011d: jmp 0x1060503780x106050122: leaq 0x8(%rsp), %rax0x106050127: movq %r13, -0x40(%rbp)0x10605012b: cmpq $0x0, -0x10(%rbp)0x106050133: je 0x1060501b00x106050139: movq %rsp, -0x28(%rsp)0x10605013e: subq $0x80, %rsp0x106050145: movq %rax, 0x78(%rsp)0x10605014a: movq %rcx, 0x70(%rsp)0x10605014f: movq %rdx, 0x68(%rsp)0x106050154: movq %rbx, 0x60(%rsp)0x106050159: movq %rbp, 0x50(%rsp)0x10605015e: movq %rsi, 0x48(%rsp)0x106050163: movq %rdi, 0x40(%rsp)0x106050168: movq %r8, 0x38(%rsp)0x10605016d: movq %r9, 0x30(%rsp)0x106050172: movq %r10, 0x28(%rsp)0x106050177: movq %r11, 0x20(%rsp)0x10605017c: movq %r12, 0x18(%rsp)0x106050181: movq %r13, 0x10(%rsp)0x106050186: movq %r14, 0x8(%rsp)0x10605018b: movq %r15, (%rsp)0x10605018f: movabsq $0x1040984ed, %rdi ; imm = 0x1040984ED 0x106050199: movabsq $0x106050139, %rsi ; imm = 0x106050139 0x1060501a3: movq %rsp, %rdx0x1060501a6: andq $-0x10, %rsp0x1060501aa: callq 0x103b6af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x1060501af: hlt 0x1060501b0: pushq %r100x1060501b2: cmpq -0x1d39bc9(%rip), %r12 ; Universe::_narrow_ptrs_base0x1060501b9: je 0x1060502360x1060501bf: movq %rsp, -0x28(%rsp)0x1060501c4: subq $0x80, %rsp0x1060501cb: movq %rax, 0x78(%rsp)0x1060501d0: movq %rcx, 0x70(%rsp)0x1060501d5: movq %rdx, 0x68(%rsp)0x1060501da: movq %rbx, 0x60(%rsp)0x1060501df: movq %rbp, 0x50(%rsp)0x1060501e4: movq %rsi, 0x48(%rsp)0x1060501e9: movq %rdi, 0x40(%rsp)0x1060501ee: movq %r8, 0x38(%rsp)0x1060501f3: movq %r9, 0x30(%rsp)0x1060501f8: movq %r10, 0x28(%rsp)0x1060501fd: movq %r11, 0x20(%rsp)0x106050202: movq %r12, 0x18(%rsp)0x106050207: movq %r13, 0x10(%rsp)0x10605020c: movq %r14, 0x8(%rsp)0x106050211: movq %r15, (%rsp)0x106050215: movabsq $0x1040d4efc, %rdi ; imm = 0x1040D4EFC 0x10605021f: movabsq $0x1060501bf, %rsi ; imm = 0x1060501BF 0x106050229: movq %rsp, %rdx0x10605022c: andq $-0x10, %rsp0x106050230: callq 0x103b6af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050235: hlt 0x106050236: popq %r100x106050238: movq %r15, %rdi0x10605023b: movq %rbp, 0x218(%r15)0x106050242: movq %rax, 0x208(%r15)0x106050249: testl $0xf, %esp0x10605024f: je 0x1060502670x106050255: subq $0x8, %rsp0x106050259: callq 0x1038d2700 ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:6600x10605025e: addq $0x8, %rsp0x106050262: jmp 0x10605026c0x106050267: callq 0x1038d2700 ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:6600x10605026c: pushq %rax0x10605026d: pushq %rdi0x10605026e: pushq %rsi0x10605026f: pushq %rdx0x106050270: pushq %rcx0x106050271: pushq %r80x106050273: pushq %r90x106050275: pushq %r100x106050277: pushq %r110x106050279: testl $0xf, %esp0x10605027f: je 0x1060502970x106050285: subq $0x8, %rsp0x106050289: callq 0x103003ae0 ; Thread::current at thread.hpp:6600x10605028e: addq $0x8, %rsp0x106050292: jmp 0x10605029c0x106050297: callq 0x103003ae0 ; Thread::current at thread.hpp:6600x10605029c: popq %r110x10605029e: popq %r100x1060502a0: popq %r90x1060502a2: popq %r80x1060502a4: popq %rcx0x1060502a5: popq %rdx0x1060502a6: popq %rsi0x1060502a7: popq %rdi0x1060502a8: cmpq %rax, %r150x1060502ab: je 0x1060503280x1060502b1: movq %rsp, -0x28(%rsp)0x1060502b6: subq $0x80, %rsp0x1060502bd: movq %rax, 0x78(%rsp)0x1060502c2: movq %rcx, 0x70(%rsp)0x1060502c7: movq %rdx, 0x68(%rsp)0x1060502cc: movq %rbx, 0x60(%rsp)0x1060502d1: movq %rbp, 0x50(%rsp)0x1060502d6: movq %rsi, 0x48(%rsp)0x1060502db: movq %rdi, 0x40(%rsp)0x1060502e0: movq %r8, 0x38(%rsp)0x1060502e5: movq %r9, 0x30(%rsp)0x1060502ea: movq %r10, 0x28(%rsp)0x1060502ef: movq %r11, 0x20(%rsp)0x1060502f4: movq %r12, 0x18(%rsp)0x1060502f9: movq %r13, 0x10(%rsp)0x1060502fe: movq %r14, 0x8(%rsp)0x106050303: movq %r15, (%rsp)0x106050307: movabsq $0x1040d5043, %rdi ; imm = 0x1040D5043 0x106050311: movabsq $0x1060502b1, %rsi ; imm = 0x1060502B1 0x10605031b: movq %rsp, %rdx0x10605031e: andq $-0x10, %rsp0x106050322: callq 0x103b6af60 ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050327: hlt 0x106050328: popq %rax0x106050329: movabsq $0x0, %r100x106050333: movq %r10, 0x208(%r15)0x10605033a: movabsq $0x0, %r100x106050344: movq %r10, 0x218(%r15)0x10605034b: movabsq $0x0, %r100x106050355: movq %r10, 0x210(%r15)0x10605035c: cmpq $0x0, 0x8(%r15)0x106050364: je 0x10605036f0x10605036a: jmp 0x1060007a00x10605036f: movq -0x40(%rbp), %r130x106050373: movq -0x38(%rbp), %r140x106050377: retq// done; 0x106050378: movq -0x40(%rbp), %r130x10605037c: popq %rax0x10605037d: movzbl 0x1(%r13), %ebx0x106050382: incq %r130x106050385: movabsq $0x10430b270, %r10 ; imm = 0x10430B270 0x10605038f: jmpq *(%r10,%rbx,8)0x106050393: nop 0x106050394: nop
通过以上的汇编代码块, 可以整理出一些规则
1. 如果 obj 上面是偏向锁, 那么什么都不用做, 直接 done
2. 如果 obj 对应的 BasicObjectLock.lock.displaced_header 为 null(轻量级锁重入的情况), 直接 done
3. 如果 obj 对应的 locker 为 BasicObjectLock.lock, cas 替换其 mark 为 BasicObjectLock.lock.displaced_header 当前 直接 done
4. 走 InterpreterRuntime::monitorexit
我们这里的偏向锁退出, 直接走的是 1, 检查了一下 锁标记位 和 偏向锁 标记位, 然后 done
* thread #5, stop reason = breakpoint 4.1frame #0: 0x00000001060500ec
-> 0x1060500ec: movq (%rcx), %rdx0x1060500ef: andq $0x7, %rdx0x1060500f3: cmpq $0x5, %rdx0x1060500f7: je 0x106050378
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000700006a3c628rbx = 0x00000000000000c3rcx = 0x0000000747bb86a0rdx = 0x0000700006a3c638rdi = 0x0000000101003800rsi = 0x0000700006a3c628rbp = 0x0000700006a3c680rsp = 0x0000700006a3c620r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000104b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006fff05a37c00r12 = 0x0000000000000000r13 = 0x000000011e267f95r14 = 0x0000700006a3c6a8r15 = 0x0000000101003800rip = 0x00000001060500ecrflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x0000000747bb86a0
0x747bb86a0: 05 38 00 01 01 00 00 00 86 1f 01 f8 00 00 00 00 .8.........?....
0x747bb86b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500ef
-> 0x1060500ef: andq $0x7, %rdx0x1060500f3: cmpq $0x5, %rdx0x1060500f7: je 0x1060503780x1060500fd: movq (%rax), %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500f3
-> 0x1060500f3: cmpq $0x5, %rdx0x1060500f7: je 0x1060503780x1060500fd: movq (%rax), %rdx0x106050100: testq %rdx, %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500f7
-> 0x1060500f7: je 0x1060503780x1060500fd: movq (%rax), %rdx0x106050100: testq %rdx, %rdx0x106050103: je 0x106050378
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000106050378
-> 0x106050378: movq -0x40(%rbp), %r130x10605037c: popq %rax0x10605037d: movzbl 0x1(%r13), %ebx0x106050382: incq %r13
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb86a0)->print()
com.hx.test04.Test26SynchronizeObject
{0x0000000747bb86a0} - klass: 'com/hx/test04/Test26SynchronizeObject'- ---- fields (total size 5 words):- 'f01' 'I' @12 0- 'f02' 'I' @16 0- 'f03' 'I' @20 0- 'f04' 'I' @24 0- 'f05' 'I' @28 0- private 'identStr' 'Ljava/lang/String;' @32 "xyz"{0x0000000747bb86c8} (e8f770d9 0)
(lldb) p ((oopDesc*)0x0000000747bb86a0)->mark()->has_bias_pattern()
(bool) $2 = true
(lldb) p ((oopDesc*)0x0000000747bb86a0)->mark()->biased_locker()->threadObj()->print()
java.lang.Thread
{0x0000000747f069d8} - klass: 'java/lang/Thread'- ---- fields (total size 47 words):- private 'priority' 'I' @12 5- private 'eetop' 'J' @16 4311758848 (1003800 1)- private 'stackSize' 'J' @24 0 (0 0)- private 'nativeParkEventPointer' 'J' @32 0 (0 0)- private 'tid' 'J' @40 1 (1 0)- private volatile 'threadStatus' 'I' @48 5- private 'single_step' 'Z' @52 false- private 'daemon' 'Z' @53 false- private 'stillborn' 'Z' @54 false- private volatile 'name' 'Ljava/lang/String;' @56 "main"{0x0000000747f06b50} (e8fe0d6a 0)- private 'threadQ' 'Ljava/lang/Thread;' @60 NULL (0 0)- private 'target' 'Ljava/lang/Runnable;' @64 NULL (0 e8fe0c85)- private 'group' 'Ljava/lang/ThreadGroup;' @68 a 'java/lang/ThreadGroup'{0x0000000747f06428} (e8fe0c85 e8fc0af7)- private 'contextClassLoader' 'Ljava/lang/ClassLoader;' @72 a 'jdk/internal/loader/ClassLoaders$AppClassLoader'{0x0000000747e057b8} (e8fc0af7 e8fe0d91)- private 'inheritedAccessControlContext' 'Ljava/security/AccessControlContext;' @76 a 'java/security/AccessControlContext'{0x0000000747f06c88} (e8fe0d91 e8fe2fb8)- 'threadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @80 a 'java/lang/ThreadLocal$ThreadLocalMap'{0x0000000747f17dc0} (e8fe2fb8 0)- 'inheritableThreadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @84 NULL (0 0)- volatile 'parkBlocker' 'Ljava/lang/Object;' @88 NULL (0 0)- private volatile 'blocker' 'Lsun/nio/ch/Interruptible;' @92 NULL (0 e8fe0d70)- private final 'blockerLock' 'Ljava/lang/Object;' @96 a 'java/lang/Object'{0x0000000747f06b80} (e8fe0d70 0)- private volatile 'uncaughtExceptionHandler' 'Ljava/lang/Thread$UncaughtExceptionHandler;' @100 NULL (0 0)- 'threadLocalRandomSeed' 'J' @232 0 (0 0)- 'threadLocalRandomProbe' 'I' @240 0- 'threadLocalRandomSecondarySeed' 'I' @244 0
完
参考
09 给对象添加偏向锁的调试
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
