性能文章>10 偏向锁的退出的调试>

10 偏向锁的退出的调试原创

1年前
283645

前言

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 {

  // identStr
  private String identStr = "xyz";
  int f01;
  int f02;
  int f03;
  int f04;
  int f05;

  // Test25SynchronizeObject
  public 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_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #2                  // String xyz
       7: putfield      #3                  // Field identStr:Ljava/lang/String;
      10: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: new           #4                  // class com/hx/test04/Test26SynchronizeObject
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: dup
      10: astore_2
      11: monitorenter
      12: aload_2
      13: monitorexit
      14: goto          22
      17: astore_3
      18: aload_2
      19: monitorexit
      20: aload_3
      21: athrow
      22: return
    Exception table:
       from    to  target type
          12    14    17   any
          17    20    17   any
}

进入lldb的调试

进入lldb 之后如下, 省略了一部分输出, 不过应该能够看出 当前端点是停在了 javaCalls.cpp -l 410 这里 

Process 2543 resuming
Process 2543 stopped
* thread #5, stop reason = breakpoint 1.1
    frame #0: 0x0000000103923592 libjvm.dylib`::jni_CallStaticVoidMethod(env=0x0000000101005a28, cls=0x00000001001061d0, methodID=0x0000000104905990) at jni.cpp:1989:21
   1986	  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_END
   1992	
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.1
    frame #0: 0x00000001038eba68 libjvm.dylib`JavaCalls::call_helper(result=0x0000700004af3d48, method=0x0000700004af3a48, args=0x0000700004af3a90, __the_thread__=0x0000000101005800) at javaCalls.cpp:410:7
   407 	  { JavaCallWrapper link(method, receiver, result, CHECK);
   408 	    { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner
   409 	
-> 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.1
    frame #0: 0x000000010504fde1
->  0x10504fde1: cmpq   (%rax), %rax
    0x10504fde4: movq   -0x48(%rbp), %rsi
    0x10504fde8: leaq   -0x48(%rbp), %rdx
    0x10504fdec: jmp    0x10504fdfc
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8748
       rbx = 0x00000000000000c3
       rcx = 0x0000000747bb8748
       rdx = 0x0000700003d92638
       rdi = 0x0000000104801800
       rsi = 0x0000700003d92628
       rbp = 0x0000700003d92680
       rsp = 0x0000700003d92628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x00006ffeff58fe00
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff95
       r14 = 0x0000700003d926a8
       r15 = 0x0000000104801800
       rip = 0x000000010504fde1
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 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 = 0x0000000747bb8748
       rbx = 0x00000000000000c3
       rcx = 0x0000000747bb8748
       rdx = 0x0000700003d92638
       rdi = 0x0000000104801800
       rsi = 0x0000700003d92628
       rbp = 0x0000700003d92680
       rsp = 0x0000700003d92628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x00006ffeff58fe00
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff95
       r14 = 0x0000700003d926a8
       r15 = 0x0000000104801800
       rip = 0x000000010504fde1
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 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 200
    0x10604fde0: popq   %rax
    0x10604fde1: cmpq   (%rax), %rax
    // rtop = expressionBottom
    // rbot = oldExpressionBottom
    0x10604fde4: movq   -0x48(%rbp), %rsi
    0x10604fde8: leaq   -0x48(%rbp), %rdx
    0x10604fdec: jmp    0x10604fdfc

    // BasicLockObject's loop
    // if (found) goto 0x1060500d8;
    0x10604fdee: cmpq   0x8(%rsi), %rax
    0x10604fdf2: je     0x1060500d8
    0x10604fdf8: addq   $0x10, %rsi
    0x10604fdfc: cmpq   %rdx, %rsi
    0x10604fdff: jne    0x10604fdee

    // if (!found) InterpreterRuntime::throw_illegal_monitor_state_exception
    0x10604fe01: callq  0x10604fe0b
    0x10604fe06: jmp    0x106050061
    0x10604fe0b: leaq   0x8(%rsp), %rax
    0x10604fe10: movq   %r13, -0x40(%rbp)
    0x10604fe14: cmpq   $0x0, -0x10(%rbp)
    0x10604fe1c: je     0x10604fe99
    0x10604fe22: movq   %rsp, -0x28(%rsp)
    0x10604fe27: subq   $0x80, %rsp
    0x10604fe2e: 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, %rdx
    0x10604fe8f: andq   $-0x10, %rsp
    0x10604fe93: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x10604fe98: hlt    
    0x10604fe99: pushq  %r10
    0x10604fe9b: cmpq   -0x15398b2(%rip), %r12    ; Universe::_narrow_ptrs_base
    0x10604fea2: je     0x10604ff1f
    0x10604fea8: movq   %rsp, -0x28(%rsp)
    0x10604fead: subq   $0x80, %rsp
    0x10604feb4: 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, %rdx
    0x10604ff15: andq   $-0x10, %rsp
    0x10604ff19: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x10604ff1e: hlt    
    0x10604ff1f: popq   %r10
    0x10604ff21: movq   %r15, %rdi
    0x10604ff24: movq   %rbp, 0x218(%r15)
    0x10604ff2b: movq   %rax, 0x208(%r15)
    0x10604ff32: testl  $0xf, %esp
    0x10604ff38: je     0x10604ff50
    0x10604ff3e: subq   $0x8, %rsp
    0x10604ff42: callq  0x1040d2a40               ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:680
    0x10604ff47: addq   $0x8, %rsp
    0x10604ff4b: jmp    0x10604ff55
    0x10604ff50: callq  0x1040d2a40               ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:680
    0x10604ff55: pushq  %rax
    0x10604ff56: pushq  %rdi
    0x10604ff57: pushq  %rsi
    0x10604ff58: pushq  %rdx
    0x10604ff59: pushq  %rcx
    0x10604ff5a: pushq  %r8
    0x10604ff5c: pushq  %r9
    0x10604ff5e: pushq  %r10
    0x10604ff60: pushq  %r11
    0x10604ff62: testl  $0xf, %esp
    0x10604ff68: je     0x10604ff80
    0x10604ff6e: subq   $0x8, %rsp
    0x10604ff72: callq  0x103803ae0               ; Thread::current at thread.hpp:660
    0x10604ff77: addq   $0x8, %rsp
    0x10604ff7b: jmp    0x10604ff85
    0x10604ff80: callq  0x103803ae0               ; Thread::current at thread.hpp:660
    0x10604ff85: popq   %r11
    0x10604ff87: popq   %r10
    0x10604ff89: popq   %r9
    0x10604ff8b: popq   %r8
    0x10604ff8d: popq   %rcx
    0x10604ff8e: popq   %rdx
    0x10604ff8f: popq   %rsi
    0x10604ff90: popq   %rdi
    0x10604ff91: cmpq   %rax, %r15
    0x10604ff94: je     0x106050011
    0x10604ff9a: movq   %rsp, -0x28(%rsp)
    0x10604ff9f: subq   $0x80, %rsp
    0x10604ffa6: 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, %rdx
    0x106050007: andq   $-0x10, %rsp
    0x10605000b: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x106050010: hlt    
    0x106050011: popq   %rax
    0x106050012: movabsq $0x0, %r10
    0x10605001c: movq   %r10, 0x208(%r15)
    0x106050023: movabsq $0x0, %r10
    0x10605002d: movq   %r10, 0x218(%r15)
    0x106050034: movabsq $0x0, %r10
    0x10605003e: movq   %r10, 0x210(%r15)
    0x106050045: cmpq   $0x0, 0x8(%r15)
    0x10605004d: je     0x106050058
    0x106050053: jmp    0x1060007a0
    0x106050058: movq   -0x40(%rbp), %r13
    0x10605005c: movq   -0x38(%rbp), %r14
    0x106050060: retq   
    0x106050061: movq   %rsp, -0x28(%rsp)
    0x106050066: subq   $0x80, %rsp
    0x10605006d: 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, %rdx
    0x1060500ce: andq   $-0x10, %rsp
    0x1060500d2: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x1060500d7: hlt

    // unlock_object
    0x1060500d8: pushq  %rax
    0x1060500d9: movq   %r13, -0x40(%rbp)
    0x1060500dd: leaq   (%rsi), %rax

别看这里 贴了这么多汇编出来, 实际核心的处理主要是 BasicLockObject's loop 这一段 

查询 BasicLockObject 列表, 寻找 BasicLockObject.obj 为 lockObj 的记录, 然后 交给后面的 unlock_object 处理 

如果找不到 表示还没有获取到锁, 抛出 IllegalStateException

unlock_object 的业务

interp_ma**_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 instruction
    const Register header_reg = LP64_ONLY(c_rarg2) NOT_LP64(rbx);  // Will contain the old oopMark
    const Register obj_reg    = LP64_ONLY(c_rarg3) NOT_LP64(rcx);  // Will contain the oop

    save_bcp(); // Save in case of exception

    // Convert from BasicObjectLock structure to object and BasicLock
    // structure Store the BasicLock address into %rax
    lea(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 entry
    movptr(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 structure
    movptr(header_reg, Address(swap_reg,
                               BasicLock::displaced_header_offset_in_bytes()));

    // Test for recursion
    testptr(header_reg, header_reg);

    // zero for recursive case
    jcc(Assembler::zero, done);

    // Atomic swap back the old header
    if (os::is_MP()) lock();
    cmpxchgptr(header_reg, Address(obj_reg, 0));

    // zero for simple unlock of a stack-lock case
    jcc(Assembler::zero, done);

    // Call the runtime routine for slow case.
    movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()),
         obj_reg); // restore obj
    call_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_bcp
    0x1060500d9: movq   %r13, -0x40(%rbp)
    // rax = BasicObjectLock.lock
    // rcx = BasicObjectLock.obj
    // BasicObjectLock.obj = null
    0x1060500dd: leaq   (%rsi), %rax
    0x1060500e0: movq   0x8(%rsi), %rcx
    0x1060500e4: movq   $0x0, 0x8(%rsi)

    // biased_locking_exit
    // if(obj.mark().has_bias_pattern()) goto done;
    0x1060500ec: movq   (%rcx), %rdx
    0x1060500ef: andq   $0x7, %rdx
    0x1060500f3: cmpq   $0x5, %rdx
    0x1060500f7: je     0x106050378

    // rdx = BasicObjectLock.lock.displaced_header
    // if(BasicObjectLock.lock.displaced_header == null) goto done;
    0x1060500fd: movq   (%rax), %rdx
    0x106050100: testq  %rdx, %rdx
    0x106050103: je     0x106050378

    // if(cas(rdx, lockObj.mark_addr, rax)) goto done;
    0x106050109: lock   
    0x10605010a: cmpxchgq %rdx, (%rcx)
    0x10605010e: je     0x106050378

    // BasicObjectLock.obj = lockObj
    // InterpreterRuntime::monitorexit
    0x106050114: movq   %rcx, 0x8(%rsi)
    0x106050118: callq  0x106050122
    0x10605011d: jmp    0x106050378
    0x106050122: leaq   0x8(%rsp), %rax
    0x106050127: movq   %r13, -0x40(%rbp)
    0x10605012b: cmpq   $0x0, -0x10(%rbp)
    0x106050133: je     0x1060501b0
    0x106050139: movq   %rsp, -0x28(%rsp)
    0x10605013e: subq   $0x80, %rsp
    0x106050145: 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, %rdx
    0x1060501a6: andq   $-0x10, %rsp
    0x1060501aa: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x1060501af: hlt    
    0x1060501b0: pushq  %r10
    0x1060501b2: cmpq   -0x1d39bc9(%rip), %r12    ; Universe::_narrow_ptrs_base
    0x1060501b9: je     0x106050236
    0x1060501bf: movq   %rsp, -0x28(%rsp)
    0x1060501c4: subq   $0x80, %rsp
    0x1060501cb: 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, %rdx
    0x10605022c: andq   $-0x10, %rsp
    0x106050230: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x106050235: hlt    
    0x106050236: popq   %r10
    0x106050238: movq   %r15, %rdi
    0x10605023b: movq   %rbp, 0x218(%r15)
    0x106050242: movq   %rax, 0x208(%r15)
    0x106050249: testl  $0xf, %esp
    0x10605024f: je     0x106050267
    0x106050255: subq   $0x8, %rsp
    0x106050259: callq  0x1038d2700               ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:660
    0x10605025e: addq   $0x8, %rsp
    0x106050262: jmp    0x10605026c
    0x106050267: callq  0x1038d2700               ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:660
    0x10605026c: pushq  %rax
    0x10605026d: pushq  %rdi
    0x10605026e: pushq  %rsi
    0x10605026f: pushq  %rdx
    0x106050270: pushq  %rcx
    0x106050271: pushq  %r8
    0x106050273: pushq  %r9
    0x106050275: pushq  %r10
    0x106050277: pushq  %r11
    0x106050279: testl  $0xf, %esp
    0x10605027f: je     0x106050297
    0x106050285: subq   $0x8, %rsp
    0x106050289: callq  0x103003ae0               ; Thread::current at thread.hpp:660
    0x10605028e: addq   $0x8, %rsp
    0x106050292: jmp    0x10605029c
    0x106050297: callq  0x103003ae0               ; Thread::current at thread.hpp:660
    0x10605029c: popq   %r11
    0x10605029e: popq   %r10
    0x1060502a0: popq   %r9
    0x1060502a2: popq   %r8
    0x1060502a4: popq   %rcx
    0x1060502a5: popq   %rdx
    0x1060502a6: popq   %rsi
    0x1060502a7: popq   %rdi
    0x1060502a8: cmpq   %rax, %r15
    0x1060502ab: je     0x106050328
    0x1060502b1: movq   %rsp, -0x28(%rsp)
    0x1060502b6: subq   $0x80, %rsp
    0x1060502bd: 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, %rdx
    0x10605031e: andq   $-0x10, %rsp
    0x106050322: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x106050327: hlt    
    0x106050328: popq   %rax
    0x106050329: movabsq $0x0, %r10
    0x106050333: movq   %r10, 0x208(%r15)
    0x10605033a: movabsq $0x0, %r10
    0x106050344: movq   %r10, 0x218(%r15)
    0x10605034b: movabsq $0x0, %r10
    0x106050355: movq   %r10, 0x210(%r15)
    0x10605035c: cmpq   $0x0, 0x8(%r15)
    0x106050364: je     0x10605036f
    0x10605036a: jmp    0x1060007a0
    0x10605036f: movq   -0x40(%rbp), %r13
    0x106050373: movq   -0x38(%rbp), %r14
    0x106050377: retq

    // done; 
    0x106050378: movq   -0x40(%rbp), %r13
    0x10605037c: popq   %rax
    0x10605037d: movzbl 0x1(%r13), %ebx
    0x106050382: incq   %r13
    0x106050385: 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.1
    frame #0: 0x00000001060500ec
->  0x1060500ec: movq   (%rcx), %rdx
    0x1060500ef: andq   $0x7, %rdx
    0x1060500f3: cmpq   $0x5, %rdx
    0x1060500f7: je     0x106050378
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000700006a3c628
       rbx = 0x00000000000000c3
       rcx = 0x0000000747bb86a0
       rdx = 0x0000700006a3c638
       rdi = 0x0000000101003800
       rsi = 0x0000700006a3c628
       rbp = 0x0000700006a3c680
       rsp = 0x0000700006a3c620
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000104b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x00006fff05a37c00
       r12 = 0x0000000000000000
       r13 = 0x000000011e267f95
       r14 = 0x0000700006a3c6a8
       r15 = 0x0000000101003800
       rip = 0x00000001060500ec
    rflags = 0x0000000000000246
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 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 into
    frame #0: 0x00000001060500ef
->  0x1060500ef: andq   $0x7, %rdx
    0x1060500f3: cmpq   $0x5, %rdx
    0x1060500f7: je     0x106050378
    0x1060500fd: movq   (%rax), %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001060500f3
->  0x1060500f3: cmpq   $0x5, %rdx
    0x1060500f7: je     0x106050378
    0x1060500fd: movq   (%rax), %rdx
    0x106050100: testq  %rdx, %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001060500f7
->  0x1060500f7: je     0x106050378
    0x1060500fd: movq   (%rax), %rdx
    0x106050100: testq  %rdx, %rdx
    0x106050103: je     0x106050378
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x0000000106050378
->  0x106050378: movq   -0x40(%rbp), %r13
    0x10605037c: popq   %rax
    0x10605037d: movzbl 0x1(%r13), %ebx
    0x106050382: 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 给对象添加偏向锁的调试

点赞收藏
分类:标签:
黄金键盘
请先登录,查看4条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

随机一门技术分享之Netty

随机一门技术分享之Netty

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

5
4