性能文章>09 给对象添加偏向锁的调试>

09 给对象添加偏向锁的调试原创

1年前
343576

前言

锁 这块是 大家在平常的业务开发中基本上都会用到的知识 

大家 平常使用到 synchronized 的时候一定是对它的使用 有一定的了解了, 那么 我们这里来调试一下 其中添加偏向锁的这个流程 

以下的调试内容 仅仅是这块的相关知识的冰山一角, 我能够窥到这一角 也算是很幸运了, 还是 花了一些时间 来整理这一角的相关东西, 并且调试 相当不容易 ... 

lldb 汇编调试的部分需要感谢朋友 "新加坡买买提", 去年 12 月份的时候花了一下午的时间不佞帮助我 

以下内容基于 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_1
      13: invokevirtual #6                  // Method java/lang/Object.clone:()Ljava/lang/Object;
      16: checkcast     #4                  // class com/hx/test04/Test26SynchronizeObject
      19: astore_3
      20: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: aload_1
      24: getfield      #3                  // Field identStr:Ljava/lang/String;
      27: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      30: aload_2
      31: monitorexit
      32: goto          42
      35: astore        4
      37: aload_2
      38: monitorexit
      39: aload         4
      41: athrow
      42: return
    Exception table:
       from    to  target type
          12    32    35   any
          35    39    35   any
}

以下的调试 基于 lldb 命令行, 因为 clion 里面调试似乎是存在问题 

至少是在 我本地的这个环境, 使用 clion 调试会存在问题, 因此 只好是 换成了 lldb 命令行来调试 

    # 1. monitor_enter 的时候, eval : this.code_section->print("monitor_enter")
    monitor_enter.code = 0x0000000112f57ec0 : 0x0000000112f57f23 : 0x0000000113028de0 (99 of 855840)
    monitor_enter.locs = 0x0000000000000000 : 0x0000000000000000 : 0x0000000000000000 (0 of 0) point=0
    # 2. 等待执行到 jvm.cpp 里面的 JVM_Clone 里面的断点
    # 3. 打上汇编断点, 不行 os.die

    # 1. p _active_table._table[9][194]
    # 2. 不行 os.die

 

lldb 调试相关命令如下 

    // 呵呵 clion 里面不行, 可以通过基于命令行的 lldb 命令来调试,
    cd /Users/jerry/ClionProjects/HelloOpenJdk/jdk9/build/macosx-x86_64-normal-serverANDclient-slowdebug/jdk/bin
    lldb -s /Users/jerry/LLDBProjects/Test26SynchronizeObjectDebug.sh -- ./java -cp /Users/jerry/IdeaProjects/HelloWorld/target/classes -XX:BiasedLockingStartupDelay=0 com.hx.test04.Test26SynchronizeObject

 

可以看到这里有一个 -s 后面带了一个文件, 这里面记录的是 进入 lldb 调试之后, 需要执行的一部分命令 

而这部分命令相对比较固定, 因此放到了一个统一的 文件里面, 由 lldb 加载执行 

Test26SynchronizeObjectDebug.sh 文件内容如下, 主要是加了两个端点, 并执行到端点的地方 

run
br set -f jni.cpp -l 1989
c
br set -f javaCalls.cpp -l 410
c
p _active_table._table[9][194]

进入lldb的调试

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

Process 3256 resuming
Process 3256 stopped
* thread #5, stop reason = breakpoint 1.1
    frame #0: 0x0000000103923592 libjvm.dylib`::jni_CallStaticVoidMethod(env=0x0000000100807228, cls=0x000000010010a2d0, methodID=0x00000001001b9870) 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 3256 resuming
Process 3256 stopped
* thread #5, stop reason = breakpoint 2.1
    frame #0: 0x00000001038eba68 libjvm.dylib`JavaCalls::call_helper(result=0x0000700009373d48, method=0x0000700009373a48, args=0x0000700009373a90, __the_thread__=0x0000000100807000) 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 = 0x00000001048cd980 "XH;"

 

定位一下当前方法, 当前这里正是在调用 main 方法 

(lldb) p method()->print()
{method}
 - this oop:          0x000000011d170090
 - method holder:     'com/hx/test04/Test26SynchronizeObject'
 - constants:         0x000000011d16fc78 constant pool [62] {0x000000011d16fc78} for 'com/hx/test04/Test26SynchronizeObject' cache=0x000000011d170108
 - access:            0x20000009  public static 
 - name:              'main'
 - signature:         '([Ljava/lang/String;)V'
 - max stack:         3
 - max locals:        5
 - size of params:    1
 - method size:       11
 - vtable index:      -2
 - i2i entry:         0x00000001048a8700
 - adapters:          AHE@0x000000010101cce0: 0xb0000000 i2c: 0x0000000104a22460 c2i: 0x0000000104a2259a c2iUV: 0x0000000104a2256d
 - compiled entry     0x0000000104a2259a
 - code size:         43
 - code start:        0x000000011d170020
 - code end (excl):   0x000000011d17004b
 - checked ex length: 1
 - checked ex start:  0x000000011d17008c
 - linenumber start:  0x000000011d17004b
 - localvar length:   3
 - localvar start:    0x000000011d170054

接着在 monitor_enter 的地方打上一个断点 

(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010604f980 "XH;"
(lldb) b 0x000000010604f980
Breakpoint 3: address = 0x000000010604f980
(lldb) c
Process 3271 resuming
Process 3271 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x000000010604f980
->  0x10604f980: popq   %rax
    0x10604f981: cmpq   (%rax), %rax
    0x10604f984: xorl   %esi, %esi
    0x10604f986: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8ad0
       rbx = 0x00000000000000c2
       rcx = 0x0000000000000008
       rdx = 0x0000000747bb8af0
       rdi = 0x0000000100803800
       rsi = 0x0000700002e2b5c8
       rbp = 0x0000700002e2b678
       rsp = 0x0000700002e2b628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000104c0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff0261b000
       r12 = 0x0000000000000000
       r13 = 0x000000011e26902b
       r14 = 0x0000700002e2b6a8
       r15 = 0x0000000100803800
       rip = 0x000000010604f980
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) x 0x000000011e26902b
0x11e26902b: c2 2b b6 03 00 c0 00 04 4e b2 04 00 2b b4 01 00  ?+?..?..N?..+?..
0x11e26903b: b6 05 00 2c c3 a7 00 0a 3a 04 2c c3 19 04 bf b1  ?..,ç..:.,?..??
(lldb) p ((oopDesc*)0x0000000747bb8ad0)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb8ad0} - 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"{0x0000000747bb8af8} (e8f7715f 0)

0xc2 表示 monitorenter, 0x2b 表示 aload_1

结合上面的字节码 很容易定位到当前是在执行 monitorenter 

ax 存储的是对象 lockObj 

查看一下 栈帧中的信息, 之所以要贴一下 栈帧信息, 是因为 monitorenter 里面的处理需要处理 栈帧中的一部分数据 

(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8b88
       rbx = 0x00000000000000c2
       rcx = 0x0000000000000008
       rdx = 0x0000000747bb8ba8
       rdi = 0x0000000101800800
       rsi = 0x000070000c6485c8
       rbp = 0x000070000c648678
       rsp = 0x000070000c648628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000104b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff0ae46800
       r12 = 0x0000000000000000
       r13 = 0x000000011c89102b
       r14 = 0x000070000c6486a8
       r15 = 0x0000000101800800
       rip = 0x00000001050cd980
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) x 0x000070000c648628 -c 0x100
0x70000c648628: 88 8b bb 47 07 00 00 00 30 86 64 0c 00 70 00 00  ..?G....0.d..p..
0x70000c648638: 24 10 89 1c 01 00 00 00 a8 86 64 0c 00 70 00 00  $.......?.d..p..
0x70000c648648: 08 11 89 1c 01 00 00 00 00 00 00 00 00 00 00 00  ................
0x70000c648658: 68 86 bb 47 07 00 00 00 90 10 89 1c 01 00 00 00  h.?G............
0x70000c648668: 00 00 00 00 00 00 00 00 a8 86 64 0c 00 70 00 00  ........?.d..p..
0x70000c648678: 10 87 64 0c 00 70 00 00 f1 e9 07 05 01 00 00 00  ..d..p..??......
0x70000c648688: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x70000c648698: 88 8b bb 47 07 00 00 00 88 8b bb 47 07 00 00 00  ..?G......?G....
0x70000c6486a8: 78 8b bb 47 07 00 00 00 a0 1f 00 00 03 00 00 00  x.?G....?.......
0x70000c6486b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x70000c6486c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x70000c6486d8: 00 90 64 0c 00 70 00 00 20 88 64 0c 00 70 00 00  ..d..p.. .d..p..
0x70000c6486e8: 50 8d 64 0c 00 70 00 00 0a 00 00 00 00 70 00 00  P.d..p.......p..
0x70000c6486f8: 90 10 89 1c 01 00 00 00 00 87 0a 05 01 00 00 00  ................
0x70000c648708: a0 8a 64 0c 00 70 00 00 e0 88 64 0c 00 70 00 00  ?.d..p..?.d..p..
0x70000c648718: 1d bb 0e 04 01 00 00 00 01 00 00 00 00 70 00 00  .?...........p..

栈帧信息分析从 rsp 开始
    0x70000c648628 : 0x0000000747bb8b88 : lockObj
    0x70000c648630 : 0x70000c648630 : expression bottom
    0x70000c648638 : 0x011c891024 : byte code pointer
    0x70000c648640 : 0x70000c6486a8 : pointer to locals
    0x70000c648648 : 0x011c891108 : constants pool cache
    0x70000c648650 : 0x0000000000 : method data oop
    0x70000c648658 : 0x0747bb8668 : java mirror
    0x70000c648660 : 0x011c891090 : method oop
    0x70000c648668 : 0x0000000000 : last java stack pointer
    0x70000c648670 : 0x70000c6486a8 : old stack pointer
    0x70000c648678 : 0x70000c648710 : old frame pointer
    0x70000c648680 : 0x010507e9f1 : return address[entry_point's address]
    0x70000c648688 : 0x0000000000 : ex if exists
    0x70000c648690 : 0x0000000000 : cloned
    0x70000c648698 : 0x0000000747bb8b88 : lockObj for monitor enter/exit
    0x70000c6486a0 : 0x0000000747bb8b88 : lockObj
    0x70000c6486a8 : 0x0000000747bb8b78 : args
    0x70000c6486b0 : 0x0300001fa0 : $mxcsr

分配BasicObjectLock

对应 monitorenter 的汇编的模板代码如下 

templateTable_x86.cpp monitorenter 

// Synchronization
//
// Note: monitorenter & exit are symmetric routines; which is reflected
//       in the assembly code structure as well
//
// Stack layout:
//
// [expressions  ] <--- rsp               = expression stack top
// ..
// [expressions  ]
// [monitor entry] <--- monitor block top = expression stack bot
// ..
// [monitor entry]
// [frame data   ] <--- monitor block bot
// ...
// [saved rbp    ] <--- rbp
void TemplateTable::monitorenter() {
  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;

  Label allocated;

  Register rtop = LP64_ONLY(c_rarg3) NOT_LP64(rcx);
  Register rbot = LP64_ONLY(c_rarg2) NOT_LP64(rbx);
  Register rmon = LP64_ONLY(c_rarg1) NOT_LP64(rdx);

  // initialize entry pointer
  __ xorl(rmon, rmon); // points to free slot or NULL

  // find a free slot in the monitor block (result in rmon)
  {
    Label entry, loop, exit;
    __ 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 used
    __ cmpptr(Address(rtop, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD);
    // if not used then remember entry in rmon
    __ cmovptr(Assembler::equal, rmon, rtop);   // cmov => cmovptr
    // check if current entry is for same object
    __ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));
    // if same object then stop searching
    __ jccb(Assembler::equal, exit);
    // 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);
    __ bind(exit);
  }

  __ testptr(rmon, rmon); // check if a slot has been found
  __ jcc(Assembler::notZero, allocated); // if found, continue with that one

  // allocate one if there's no free slot
  {
    Label entry, loop;
    // 1. compute new pointers          // rsp: old expression stack top
    __ movptr(rmon, monitor_block_bot); // rmon: old expression stack bottom
    __ subptr(rsp, entry_size);         // move expression stack top
    __ subptr(rmon, entry_size);        // move expression stack bottom
    __ mov(rtop, rsp);                  // set start value for copy loop
    __ movptr(monitor_block_bot, rmon); // set new monitor block bottom
    __ jmp(entry);
    // 2. move expression stack contents
    __ bind(loop);
    __ movptr(rbot, Address(rtop, entry_size)); // load expression stack
                                                // word from old location
    __ movptr(Address(rtop, 0), rbot);          // and store it at new location
    __ addptr(rtop, wordSize);                  // advance to next word
    __ bind(entry);
    __ cmpptr(rtop, rmon);                      // check if bottom reached
    __ jcc(Assembler::notEqual, loop);          // if not at bottom then
                                                // copy next word
  }

  // call run-time routine
  // rmon: points to monitor entry
  __ bind(allocated);

  // Increment bcp to point to the next bytecode, so exception
  // handling for async. exceptions work correctly.
  // The object has already been poped from the stack, so the
  // expression stack looks correct.
  __ increment(rbcp);

  // store object
  __ movptr(Address(rmon, BasicObjectLock::obj_offset_in_bytes()), rax);
  __ lock_object(rmon);

  // check to make sure this monitor doesn't cause stack overflow after locking
  __ save_bcp();  // in case of exception
  __ generate_stack_overflow_check(0);

  // The bcp has already been incremented. Just need to dispatch to
  // next instruction.
  __ dispatch_next(vtos);
}

monitorenter 里面 lock_object 之前对应的汇编如下 

(lldb) dis -s 0x000000010604f980 -c 100
# 寄存器映射 : rmon = $esi, rtop = $rcx, rbot = $rdx
    // $rax = expressionStack[0], $rsp = $expressionBottom
->  0x10604f980: popq   %rax
    0x10604f981: cmpq   (%rax), %rax
    // $rsi = 0
    0x10604f984: xorl   %esi, %esi
    // $rcx = $rdx = $expressionBottom
    0x10604f986: movq   -0x48(%rbp), %rcx
    0x10604f98a: leaq   -0x48(%rbp), %rdx
    0x10604f98e: jmp    0x10604f9a6

    // BasicLockObject's loop
    0x10604f990: cmpq   $0x0, 0x8(%rcx)
    0x10604f998: cmoveq %rcx, %rsi
    0x10604f99c: cmpq   0x8(%rcx), %rax
    0x10604f9a0: je     0x10604f9ab
    0x10604f9a2: addq   $0x10, %rcx

    0x10604f9a6: cmpq   %rdx, %rcx
    0x10604f9a9: jne    0x10604f990

    // if BasicLockObject choosed, goto doLockBiz
    0x10604f9ab: testq  %rsi, %rsi
    0x10604f9ae: jne    0x10604f9dc

    // ExpressionStack's move
    0x10604f9b4: movq   -0x48(%rbp), %rsi
    0x10604f9b8: subq   $0x10, %rsp
    0x10604f9bc: subq   $0x10, %rsi
    0x10604f9c0: movq   %rsp, %rcx
    0x10604f9c3: movq   %rsi, -0x48(%rbp)
    0x10604f9c7: jmp    0x10604f9d7

    0x10604f9cc: movq   0x10(%rcx), %rdx
    0x10604f9d0: movq   %rdx, (%rcx)
    0x10604f9d3: addq   $0x8, %rcx

    0x10604f9d7: cmpq   %rsi, %rcx
    0x10604f9da: jne    0x10604f9cc
    // after this
    // (lldb) x 0x000070000c648620 -c 0x100
    // 0x70000c648620: 88 8b bb 47 07 00 00 00 88 8b bb 47 07 00 00 00  ..?G......?G....
    // 0x70000c648630: 20 86 64 0c 00 70 00 00 24 10 89 1c 01 00 00 00   .d..p..$.......
    // 0x70000c648640: a8 86 64 0c 00 70 00 00 08 11 89 1c 01 00 00 00  ?.d..p..........
    // 0x70000c648630 : 0x70000c648620 : expression bottom
    // 0x70000c648620 : allocated BasicLockObject

    // doLockBiz
    0x10604f9dc: incq   %r13
    // update BasicLockObject.obj = $lockObj
    0x10604f9df: movq   %rax, 0x8(%rsi)

这部分的代码处理, 主要是需要在 $expresstionBottom 和 表达式栈 之间寻找可用的 BasicObjectLock(obj == null 表示可用) 

如果没有, 则新建一个 BasicObjectLock 放在 $expresstionBottom 和 表达式栈 之间 

在 lock_object 之前有一步处理, 更新 BasicObjectLock.obj = $lockObj 

以上的这部分汇编代码 逻辑上可以参考 上面的代码逻辑, 也可以根据这里的实际情况 走一遍 

也可以 扩展一下 模拟存在 多个 BasicObjectLock 的场景, 尝试一下 

这里执行完之后, $rsi 指向一个 BasicObjectLock, BasicObjectLock.obj 为需要加锁的对象 

关于本地变量表中的对象垃圾回收时间 

曾经在这篇文章中看到 R大 说过 

如果要实现obj1所指向的对象在method返回是理解释放,一种办法是实现Java对象的“栈上分配”(stack allocation)。简单来说就是把对象自身也分配在栈上,那么栈帧释放的时候那个对象也自然就释放掉了。栈上分配需要做“逃逸分析”(escape ****ysis)来判断到底某个对象是否有引用“逃逸”到某个方法之外,如果没有,就意味着该对象与该方法调用的生命周期一致,就可以将对象分配在栈上。
但这样做非常复杂而且实际好处不够大,所以现在主流JVM也无一实现对象的栈上分配。所以这里就不详细说了,在现实生产中您是不会见到这种做法的。

嘿嘿, 但是这里的 BasicObjectLock 应该算是一种狭义上的 栈上分配吧 .. 

lock_object 的业务

interp_ma**_x86.cpp lock_object 

// Lock object
//
// Args:
//      rdx, c_rarg1: BasicObjectLock to be used for locking
//
// Kills:
//      rax, rbx
void InterpreterMacroAssembler::lock_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::monitorenter),
            lock_reg);
  } else {
    Label done;

    const Register swap_reg = rax; // Must use rax for cmpxchg instruction
    const Register tmp_reg = rbx; // Will be passed to biased_locking_enter to avoid a
                                  // problematic case where tmp_reg = no_reg.
    const Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oop

    const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
    const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
    const int mark_offset = lock_offset +
                            BasicLock::displaced_header_offset_in_bytes();

    Label slow_case;

    // Load object pointer into obj_reg
    movptr(obj_reg, Address(lock_reg, obj_offset));

    if (UseBiasedLocking) {
      biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp_reg, false, done, &slow_case);
    }

    // Load immediate 1 into swap_reg %rax
    movl(swap_reg, (int32_t)1);

    // Load (object->mark() | 1) into swap_reg %rax
    orptr(swap_reg, Address(obj_reg, 0));

    // Save (object->mark() | 1) into BasicLock's displaced header
    movptr(Address(lock_reg, mark_offset), swap_reg);

    assert(lock_offset == 0,
           "displaced header must be first word in BasicObjectLock");

    if (os::is_MP()) lock();
    cmpxchgptr(lock_reg, Address(obj_reg, 0));
    if (PrintBiasedLockingStatistics) {
      cond_inc32(Assembler::zero,
                 ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr()));
    }
    jcc(Assembler::zero, done);

    const int zero_bits = LP64_ONLY(7) NOT_LP64(3);

    // Test if the oopMark is an obvious stack pointer, i.e.,
    //  1) (mark & zero_bits) == 0, and
    //  2) rsp <= mark < mark + os::pagesize()
    //
    // These 3 tests can be done by evaluating the following
    // expression: ((mark - rsp) & (zero_bits - os::vm_page_size())),
    // assuming both stack pointer and pagesize have their
    // least significant bits clear.
    // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg
    subptr(swap_reg, rsp);
    andptr(swap_reg, zero_bits - os::vm_page_size());

    // Save the test result, for recursive case, the result is zero
    movptr(Address(lock_reg, mark_offset), swap_reg);

    if (PrintBiasedLockingStatistics) {
      cond_inc32(Assembler::zero,
                 ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr()));
    }
    jcc(Assembler::zero, done);

    bind(slow_case);

    // Call the runtime routine for slow case
    call_VM(noreg,
            CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
            lock_reg);

    bind(done);
  }
}

macroAssembler_x86.cpp biased_locking_enter 

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) {
  assert(UseBiasedLocking, "why call this otherwise?");
  assert(swap_reg == rax, "swap_reg must be rax for cmpxchgq");
  assert(tmp_reg != noreg, "tmp_reg must be supplied");
  assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg);
  assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
  Address mark_addr      (obj_reg, oopDesc::mark_offset_in_bytes());
  NOT_LP64( Address saved_mark_addr(lock_reg, 0); )

  if (PrintBiasedLockingStatistics && counters == NULL) {
    counters = BiasedLocking::counters();
  }
  // Biased locking
  // See whether the lock is currently biased toward our thread and
  // whether the epoch is still valid
  // Note that the runtime guarantees sufficient alignment of JavaThread
  // pointers to allow age to be placed into low bits
  // First check to see whether biasing is even enabled for this object
  Label cas_label;
  int null_check_offset = -1;
  if (!swap_reg_contains_mark) {
    null_check_offset = offset();
    movptr(swap_reg, mark_addr);
  }
  movptr(tmp_reg, swap_reg);
  andptr(tmp_reg, markOopDesc::biased_lock_mask_in_place);
  cmpptr(tmp_reg, markOopDesc::biased_lock_pattern);
  jcc(Assembler::notEqual, cas_label);
  // The bias pattern is present in the object's header. Need to check
  // whether the bias owner and the epoch are both still current.
#ifndef _LP64
  // Note that because there is no current thread register on x86_32 we
  // need to store off the mark word we read out of the object to
  // avoid reloading it and needing to recheck invariants below. This
  // store is unfortunate but it makes the overall code shorter and
  // simpler.
  movptr(saved_mark_addr, swap_reg);
#endif
  if (swap_reg_contains_mark) {
    null_check_offset = offset();
  }
  load_prototype_header(tmp_reg, obj_reg);
#ifdef _LP64
  orptr(tmp_reg, r15_thread);
  xorptr(tmp_reg, swap_reg);
  Register header_reg = tmp_reg;
#else
  xorptr(tmp_reg, swap_reg);
  get_thread(swap_reg);
  xorptr(swap_reg, tmp_reg);
  Register header_reg = swap_reg;
#endif
  andptr(header_reg, ~((int) markOopDesc::age_mask_in_place));
  if (counters != NULL) {
    cond_inc32(Assembler::zero,
               ExternalAddress((address) counters->biased_lock_entry_count_addr()));
  }
  jcc(Assembler::equal, done);

  Label try_revoke_bias;
  Label try_rebias;

  // At this point we know that the header has the bias pattern and
  // that we are not the bias owner in the current epoch. We need to
  // figure out more details about the state of the header in order to
  // know what operations can be legally performed on the object's
  // header.

  // If the low three bits in the xor result aren't clear, that means
  // the prototype header is no longer biased and we have to revoke
  // the bias on this object.
  testptr(header_reg, markOopDesc::biased_lock_mask_in_place);
  jccb(Assembler::notZero, try_revoke_bias);

  // Biasing is still enabled for this data type. See whether the
  // epoch of the current bias is still valid, meaning that the epoch
  // bits of the mark word are equal to the epoch bits of the
  // prototype header. (Note that the prototype header's epoch bits
  // only change at a safepoint.) If not, attempt to rebias the object
  // toward the current thread. Note that we must be absolutely sure
  // that the current epoch is invalid in order to do this because
  // otherwise the manipulations it performs on the mark word are
  // illegal.
  testptr(header_reg, markOopDesc::epoch_mask_in_place);
  jccb(Assembler::notZero, try_rebias);

  // The epoch of the current bias is still valid but we know nothing
  // about the owner; it might be set or it might be clear. Try to
  // acquire the bias of the object using an atomic operation. If this
  // fails we will go in to the runtime to revoke the object's bias.
  // Note that we first construct the presumed unbiased header so we
  // don't accidentally blow away another thread's valid bias.
  NOT_LP64( movptr(swap_reg, saved_mark_addr); )
  andptr(swap_reg,
         markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
#ifdef _LP64
  movptr(tmp_reg, swap_reg);
  orptr(tmp_reg, r15_thread);
#else
  get_thread(tmp_reg);
  orptr(tmp_reg, swap_reg);
#endif
  if (os::is_MP()) {
    lock();
  }
  cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
  // If the biasing toward our thread failed, this means that
  // another thread succeeded in biasing it toward itself and we
  // need to revoke that bias. The revocation will occur in the
  // interpreter runtime in the slow case.
  if (counters != NULL) {
    cond_inc32(Assembler::zero,
               ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
  }
  if (slow_case != NULL) {
    jcc(Assembler::notZero, *slow_case);
  }
  jmp(done);

  bind(try_rebias);
  // At this point we know the epoch has expired, meaning that the
  // current "bias owner", if any, is actually invalid. Under these
  // circumstances _only_, we are allowed to use the current header's
  // value as the comparison value when doing the cas to acquire the
  // bias in the current epoch. In other words, we allow transfer of
  // the bias from one thread to another directly in this situation.
  //
  // FIXME: due to a lack of registers we currently blow away the age
  // bits in this situation. Should attempt to preserve them.
  load_prototype_header(tmp_reg, obj_reg);
#ifdef _LP64
  orptr(tmp_reg, r15_thread);
#else
  get_thread(swap_reg);
  orptr(tmp_reg, swap_reg);
  movptr(swap_reg, saved_mark_addr);
#endif
  if (os::is_MP()) {
    lock();
  }
  cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
  // If the biasing toward our thread failed, then another thread
  // succeeded in biasing it toward itself and we need to revoke that
  // bias. The revocation will occur in the runtime in the slow case.
  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);

  bind(try_revoke_bias);
  // The prototype mark in the klass doesn't have the bias bit set any
  // more, indicating that objects of this data type are not supposed
  // to be biased any more. We are going to try to reset the mark of
  // this object to the prototype value and fall through to the
  // CAS-based locking scheme. Note that if our CAS fails, it means
  // that another thread raced us for the privilege of revoking the
  // bias of this particular object, so it's okay to continue in the
  // normal locking code.
  //
  // FIXME: due to a lack of registers we currently blow away the age
  // bits in this situation. Should attempt to preserve them.
  NOT_LP64( movptr(swap_reg, saved_mark_addr); )
  load_prototype_header(tmp_reg, obj_reg);
  if (os::is_MP()) {
    lock();
  }
  cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
  // Fall through to the normal CAS-based lock, because no matter what
  // the result of the above CAS, some thread must have succeeded in
  // removing the bias bit from the object's header.
  if (counters != NULL) {
    cond_inc32(Assembler::zero,
               ExternalAddress((address) counters->revoked_lock_entry_count_addr()));
  }

  bind(cas_label);

  return null_check_offset;
}

 

lock_object 这部分生成的汇编如下 

(lldb) dis -s 0x000000011652e151 -c 300
    0x11652e151: movq   0x8(%rsi), %rcx

    // biased_locking_enter
    // tmp_reg = rbx, swap_reg = rax, obj_reg = rcx
    // if(!obj.mark().has_bias_pattern()) goto biased_locking_enter_end;
    0x11652e155: movq   (%rcx), %rax
    0x11652e158: movq   %rax, %rbx
    0x11652e15b: andq   $0x7, %rbx
    0x11652e15f: cmpq   $0x5, %rbx
    0x11652e163: jne    0x11652e226

    // $rbx = obj->klass->prototype_header
    // $rbx = &currentThread | $rbx
    0x11652e169: movl   0x8(%rcx), %ebx
    0x11652e16c: shlq   $0x3, %rbx
    0x11652e170: movq   0xb0(%rbx), %rbx
    0x11652e177: orq    %r15, %rbx
    // $rax = obj.mark() 
    0x11652e17a: xorq   %rax, %rbx

    // mask 掉 $rbx 的 age 的几个 bit 
    // 除了 age_bits 其他都相同(重入) goto done;
    // counters != NULL && counters->biased_lock_entry_count_addr ++
    0x11652e17d: andq   $-0x79, %rbx
    0x11652e181: jne    0x11652e190
    0x11652e187: pushfq
    0x11652e188: lock
    0x11652e189: incl   -0xb2934ee(%rip)          ; BiasedLocking::_counters + 5
    0x11652e18f: popfq
    0x11652e190: je     0x11652e4cd

    // if (lockBits != 0) goto try_revoke_bias
    0x11652e196: testq  $0x7, %rbx
    0x11652e19d: jne    0x11652e204

    // if (epoch != 0) goto try_rebias
    0x11652e19f: testq  $0x300, %rbx              ; imm = 0x300
    0x11652e1a6: jne    0x11652e1d4

    // epoch is valid
    // 这里使用的是 $eax(obj.mark), 首先是 mask 掉了 rax 的线程的数据, 然后再 写入 $currentThread 
    0x11652e1a8: andq   $0x37f, %rax              ; imm = 0x37F
    0x11652e1af: movq   %rax, %rbx
    0x11652e1b2: orq    %r15, %rbx
    0x11652e1b5: lock
    0x11652e1b6: cmpxchgq %rbx, (%rcx)
    // counters != NULL && counters->anonymously_biased_lock_entry_count_addr ++
    0x11652e1ba: jne    0x11652e1c9
    0x11652e1c0: pushfq
    0x11652e1c1: lock
    0x11652e1c2: incl   -0xb293523(%rip)          ; BiasedLocking::_counters + 9
    0x11652e1c8: popfq
    0x11652e1c9: jne    0x11652e26d
    0x11652e1cf: jmp    0x11652e4cd

    // try_rebias, age 丢了 ?
    0x11652e1d4: movl   0x8(%rcx), %ebx
    0x11652e1d7: shlq   $0x3, %rbx
    0x11652e1db: movq   0xb0(%rbx), %rbx
    0x11652e1e2: orq    %r15, %rbx
    0x11652e1e5: lock
    0x11652e1e6: cmpxchgq %rbx, (%rcx)
    // counters != NULL && counters->rebiased_lock_entry_count_addr ++
    0x11652e1ea: jne    0x11652e1f9
    0x11652e1f0: pushfq
    0x11652e1f1: lock
    0x11652e1f2: incl   -0xb29354f(%rip)          ; BiasedLocking::_counters + 13
    0x11652e1f8: popfq
    0x11652e1f9: jne    0x11652e26d
    0x11652e1ff: jmp    0x11652e4cd

    // try_revoke_bias
    // obj.set_mark_oop(obj->klass->prototype_header)
    0x11652e204: movl   0x8(%rcx), %ebx
    0x11652e207: shlq   $0x3, %rbx
    0x11652e20b: movq   0xb0(%rbx), %rbx
    0x11652e212: lock
    0x11652e213: cmpxchgq %rbx, (%rcx)
    // counters != NULL && counters->revoked_lock_entry_count_addr ++
    0x11652e217: jne    0x11652e226
    0x11652e21d: pushfq
    0x11652e21e: lock
    0x11652e21f: incl   -0xb293578(%rip)          ; BiasedLocking::_counters + 17
    0x11652e225: popfq


    // cmpxchgptr(lock_reg, Address(obj_reg, 0));
    // 加轻量级锁
    0x11652e226: movl   $0x1, %eax
    0x11652e22b: orq    (%rcx), %rax
    0x11652e22e: movq   %rax, (%rsi)
    0x11652e231: lock
    0x11652e232: cmpxchgq %rsi, (%rcx)
    0x11652e236: jne    0x11652e245
    0x11652e23c: pushfq
    0x11652e23d: lock
    0x11652e23e: incl   -0xb293593(%rip)          ; BiasedLocking::_counters + 21
    0x11652e244: popfq
    0x11652e245: je     0x11652e4cd

    // 轻量级锁重入 
    0x11652e24b: subq   %rsp, %rax
    0x11652e24e: andq   $-0xff9, %rax             ; imm = 0xF007
    0x11652e255: movq   %rax, (%rsi)
    0x11652e258: jne    0x11652e267
    0x11652e25e: pushfq
    0x11652e25f: lock
    0x11652e260: incl   -0xb2935b5(%rip)          ; BiasedLocking::_counters + 21
    0x11652e266: popfq
    0x11652e267: je     0x11652e4cd

    // InterpreterRuntime::monitorenter
    0x11652e26d: callq  0x11652e277
    0x11652e272: jmp    0x11652e4cd
    0x11652e277: leaq   0x8(%rsp), %rax
    0x11652e27c: movq   %r13, -0x40(%rbp)
    0x11652e280: cmpq   $0x0, -0x10(%rbp)
    0x11652e288: je     0x11652e305
    0x11652e28e: movq   %rsp, -0x28(%rsp)
    0x11652e293: subq   $0x80, %rsp
    0x11652e29a: movq   %rax, 0x78(%rsp)
    0x11652e29f: movq   %rcx, 0x70(%rsp)
    0x11652e2a4: movq   %rdx, 0x68(%rsp)
    0x11652e2a9: movq   %rbx, 0x60(%rsp)
    0x11652e2ae: movq   %rbp, 0x50(%rsp)
    0x11652e2b3: movq   %rsi, 0x48(%rsp)
    0x11652e2b8: movq   %rdi, 0x40(%rsp)
    0x11652e2bd: movq   %r8, 0x38(%rsp)
    0x11652e2c2: movq   %r9, 0x30(%rsp)
    0x11652e2c7: movq   %r10, 0x28(%rsp)
    0x11652e2cc: movq   %r11, 0x20(%rsp)
    0x11652e2d1: movq   %r12, 0x18(%rsp)
    0x11652e2d6: movq   %r13, 0x10(%rsp)
    0x11652e2db: movq   %r14, 0x8(%rsp)
    0x11652e2e0: movq   %r15, (%rsp)
    0x11652e2e4: movabsq $0x10b0984ed, %rdi        ; imm = 0x10B0984ED
    0x11652e2ee: movabsq $0x11652e28e, %rsi        ; imm = 0x11652E28E
    0x11652e2f8: movq   %rsp, %rdx
    0x11652e2fb: andq   $-0x10, %rsp
    0x11652e2ff: callq  0x10ab6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x11652e304: hlt
    0x11652e305: pushq  %r10
    0x11652e307: cmpq   -0xb217d1e(%rip), %r12    ; Universe::_narrow_ptrs_base
    0x11652e30e: je     0x11652e38b
    0x11652e314: movq   %rsp, -0x28(%rsp)
    0x11652e319: subq   $0x80, %rsp
    0x11652e320: movq   %rax, 0x78(%rsp)
    0x11652e325: movq   %rcx, 0x70(%rsp)
    0x11652e32a: movq   %rdx, 0x68(%rsp)
    0x11652e32f: movq   %rbx, 0x60(%rsp)
    0x11652e334: movq   %rbp, 0x50(%rsp)
    0x11652e339: movq   %rsi, 0x48(%rsp)
    0x11652e33e: movq   %rdi, 0x40(%rsp)
    0x11652e343: movq   %r8, 0x38(%rsp)
    0x11652e348: movq   %r9, 0x30(%rsp)
    0x11652e34d: movq   %r10, 0x28(%rsp)
    0x11652e352: movq   %r11, 0x20(%rsp)
    0x11652e357: movq   %r12, 0x18(%rsp)
    0x11652e35c: movq   %r13, 0x10(%rsp)
    0x11652e361: movq   %r14, 0x8(%rsp)
    0x11652e366: movq   %r15, (%rsp)
    0x11652e36a: movabsq $0x10b0d4efc, %rdi        ; imm = 0x10B0D4EFC
    0x11652e374: movabsq $0x11652e314, %rsi        ; imm = 0x11652E314
    0x11652e37e: movq   %rsp, %rdx
    0x11652e381: andq   $-0x10, %rsp
    0x11652e385: callq  0x10ab6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x11652e38a: hlt
    0x11652e38b: popq   %r10
    0x11652e38d: movq   %r15, %rdi
    0x11652e390: movq   %rbp, 0x218(%r15)
    0x11652e397: movq   %rax, 0x208(%r15)
    0x11652e39e: testl  $0xf, %esp
    0x11652e3a4: je     0x11652e3bc
    0x11652e3aa: subq   $0x8, %rsp
    0x11652e3ae: callq  0x10a8d2360               ; InterpreterRuntime::monitorenter at interpreterRuntime.cpp:635
    0x11652e3b3: addq   $0x8, %rsp
    0x11652e3b7: jmp    0x11652e3c1
    0x11652e3bc: callq  0x10a8d2360               ; InterpreterRuntime::monitorenter at interpreterRuntime.cpp:635
    0x11652e3c1: pushq  %rax
    0x11652e3c2: pushq  %rdi
    0x11652e3c3: pushq  %rsi
    0x11652e3c4: pushq  %rdx
    0x11652e3c5: pushq  %rcx
    0x11652e3c6: pushq  %r8
    0x11652e3c8: pushq  %r9
    0x11652e3ca: pushq  %r10
    0x11652e3cc: pushq  %r11
    0x11652e3ce: testl  $0xf, %esp
    0x11652e3d4: je     0x11652e3ec
    0x11652e3da: subq   $0x8, %rsp
    0x11652e3de: callq  0x10a003ae0               ; Thread::current at thread.hpp:660
    0x11652e3e3: addq   $0x8, %rsp
    0x11652e3e7: jmp    0x11652e3f1
    0x11652e3ec: callq  0x10a003ae0               ; Thread::current at thread.hpp:660
    0x11652e3f1: popq   %r11
    0x11652e3f3: popq   %r10
    0x11652e3f5: popq   %r9
    0x11652e3f7: popq   %r8
    0x11652e3f9: popq   %rcx
    0x11652e3fa: popq   %rdx
    0x11652e3fb: popq   %rsi
    0x11652e3fc: popq   %rdi
    0x11652e3fd: cmpq   %rax, %r15
    0x11652e400: je     0x11652e47d
    0x11652e406: movq   %rsp, -0x28(%rsp)
    0x11652e40b: subq   $0x80, %rsp
    0x11652e412: movq   %rax, 0x78(%rsp)
    0x11652e417: movq   %rcx, 0x70(%rsp)
    0x11652e41c: movq   %rdx, 0x68(%rsp)
    0x11652e421: movq   %rbx, 0x60(%rsp)
    0x11652e426: movq   %rbp, 0x50(%rsp)
    0x11652e42b: movq   %rsi, 0x48(%rsp)
    0x11652e430: movq   %rdi, 0x40(%rsp)
    0x11652e435: movq   %r8, 0x38(%rsp)
    0x11652e43a: movq   %r9, 0x30(%rsp)
    0x11652e43f: movq   %r10, 0x28(%rsp)
    0x11652e444: movq   %r11, 0x20(%rsp)
    0x11652e449: movq   %r12, 0x18(%rsp)
    0x11652e44e: movq   %r13, 0x10(%rsp)
    0x11652e453: movq   %r14, 0x8(%rsp)
    0x11652e458: movq   %r15, (%rsp)
    0x11652e45c: movabsq $0x10b0d5043, %rdi        ; imm = 0x10B0D5043
    0x11652e466: movabsq $0x11652e406, %rsi        ; imm = 0x11652E406
    0x11652e470: movq   %rsp, %rdx
    0x11652e473: andq   $-0x10, %rsp
    0x11652e477: callq  0x10ab6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:862
    0x11652e47c: hlt
    0x11652e47d: popq   %rax
    0x11652e47e: movabsq $0x0, %r10
    0x11652e488: movq   %r10, 0x208(%r15)
    0x11652e48f: movabsq $0x0, %r10
    0x11652e499: movq   %r10, 0x218(%r15)
    0x11652e4a0: movabsq $0x0, %r10
    0x11652e4aa: movq   %r10, 0x210(%r15)
    0x11652e4b1: cmpq   $0x0, 0x8(%r15)
    0x11652e4b9: je     0x11652e4c4
    0x11652e4bf: jmp    0x1165037a0
    0x11652e4c4: movq   -0x40(%rbp), %r13
    0x11652e4c8: movq   -0x38(%rbp), %r14
    0x11652e4cc: retq
    0x11652e4cd: int3

通过以上的汇编代码块, 可以整理出一些规则 

1. 如果 (!obj.mark().has_bias_pattern()) 对象不支持偏向锁(未启用偏向锁, 类不支持, 或者创建于更新 instanceKlass.prototype_header之前) 则走获取 轻量级锁 的流程

2. 如果 (((obj->klass->prototype_header | &currentThread) ^ (0b101)) & -0x79) 为 0(重入), 直接 done 

3. 如果 "(lockBits != 0)", 走 取消偏向锁, 取消成功 或者 失败, 走获取 轻量级锁的流程 

4. 如果 "(epoch != 0)" 重新获取偏向锁, 获取成功 done, 获取失败 走 InterpreterRuntime::monitorenter 

5. 走 获取偏向锁的流程, cas 更新对象头, 更新成功 done, 更新失败 走 InterpreterRuntime::monitorenter 

6. 如果 没有启用偏向锁 并且 没有只用重量级锁, 或者以上的走 轻量级锁 的部分流程, 尝试获取 轻量级锁, 获取成功, 直接 done, 获取失败 判断是否是 轻量级锁 重入, 如果是 直接 done, 否则 走 InterpreterRuntime::monitorenter 

7. 走  InterpreterRuntime::monitorenter 

像我们这里就比较简单, 直接走的是 5, 更新了 对象头, 并且更新成功  

更新了之后, 输出一下 lockObj 的状态信息, 偏向锁的相关信息就更新到 对象头了 

(lldb) p ((oopDesc*)0x0000000747bb8d18)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb8d18} - 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"{0x0000000747bb8d40} (e8f771a8 0)
(lldb) p ((oopDesc*)0x0000000747bb8d18)->mark()->has_bias_pattern()
(bool) $1 = true
(lldb) p ((oopDesc*)0x0000000747bb8d18)->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  4303366144 (802800 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

添加偏向锁是否丢失了age?

Process 859 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x000000010504f980
->  0x10504f980: popq   %rax
    0x10504f981: cmpq   (%rax), %rax
    0x10504f984: xorl   %esi, %esi
    0x10504f986: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8b88
       rbx = 0x00000000000000c2
       rcx = 0x0000000000000008
       rdx = 0x0000000747bb8ba8
       rdi = 0x0000000100805800
       rsi = 0x0000700007cfc5c8
       rbp = 0x0000700007cfc678
       rsp = 0x0000700007cfc628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff074f5400
       r12 = 0x0000000000000000
       r13 = 0x000000011c87302b
       r14 = 0x0000700007cfc6a8
       r15 = 0x0000000100805800
       rip = 0x000000010504f980
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) p ((oopDesc*)0x0000000747bb8b88)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb8b88} - 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"{0x0000000747bb8bb0} (e8f77176 0)
(lldb) p ((oopDesc*)0x0000000747bb8b88)->age()
(uint) $1 = 0
(lldb) p ((oopDesc*)0x0000000747bb8b88)->incr_age()
(lldb) p ((oopDesc*)0x0000000747bb8b88)->age()
(uint) $2 = 1
(lldb) b 0x10504f9e3
Breakpoint 4: address = 0x000000010504f9e3
(lldb) c
Process 859 resuming
Process 859 stopped
* thread #5, stop reason = breakpoint 4.1
    frame #0: 0x000000010504f9e3
->  0x10504f9e3: movq   0x8(%rsi), %rcx
    0x10504f9e7: movq   (%rcx), %rax
    0x10504f9ea: movq   %rax, %rbx
    0x10504f9ed: andq   $0x7, %rbx
Target 0: (java) stopped.
(lldb) stepi -c 4
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504f9f1
->  0x10504f9f1: cmpq   $0x5, %rbx
    0x10504f9f5: jne    0x10504fa7c
    0x10504f9fb: movl   0x8(%rcx), %ebx
    0x10504f9fe: shlq   $0x3, %rbx
Target 0: (java) stopped.
(lldb) stepi -c 2
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504f9fb
->  0x10504f9fb: movl   0x8(%rcx), %ebx
    0x10504f9fe: shlq   $0x3, %rbx
    0x10504fa02: movq   0xb0(%rbx), %rbx
    0x10504fa09: orq    %r15, %rbx
Target 0: (java) stopped.
(lldb) stepi -c 4
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa0c
->  0x10504fa0c: xorq   %rax, %rbx
    0x10504fa0f: andq   $-0x79, %rbx
    0x10504fa13: je     0x10504fd05
    0x10504fa19: testq  $0x7, %rbx
Target 0: (java) stopped.
(lldb) stepi -c 2
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa13
->  0x10504fa13: je     0x10504fd05
    0x10504fa19: testq  $0x7, %rbx
    0x10504fa20: jne    0x10504fa69
    0x10504fa22: testq  $0x300, %rbx              ; imm = 0x300 
Target 0: (java) stopped.
(lldb) stepi -c 2
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa20
->  0x10504fa20: jne    0x10504fa69
    0x10504fa22: testq  $0x300, %rbx              ; imm = 0x300 
    0x10504fa29: jne    0x10504fa48
    0x10504fa2b: andq   $0x37f, %rax              ; imm = 0x37F 
Target 0: (java) stopped.
(lldb) stepi -c 2
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa29
->  0x10504fa29: jne    0x10504fa48
    0x10504fa2b: andq   $0x37f, %rax              ; imm = 0x37F 
    0x10504fa32: movq   %rax, %rbx
    0x10504fa35: orq    %r15, %rbx
Target 0: (java) stopped.
(lldb) stepi 
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa2b
->  0x10504fa2b: andq   $0x37f, %rax              ; imm = 0x37F 
    0x10504fa32: movq   %rax, %rbx
    0x10504fa35: orq    %r15, %rbx
    0x10504fa38: lock   
Target 0: (java) stopped.
(lldb) stepi -c 5
Process 859 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa43
->  0x10504fa43: jmp    0x10504fd05
    0x10504fa48: movl   0x8(%rcx), %ebx
    0x10504fa4b: shlq   $0x3, %rbx
    0x10504fa4f: movq   0xb0(%rbx), %rbx
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8b88)->age()
(uint) $3 = 1
(lldb) p ((oopDesc*)0x0000000747bb8b88)->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  4303378432 (805800 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

首先是结果 没有, 当时我看 添加偏向锁这段, 我看错了, 看成了 通过 ebx 来 mask 除了线程其他的位, 再设置偏向线程 

但是实际 仔细一看 是使用的 eax, eax 对应的是 obj 原有的 mark 的信息, 因此 age 信息没有丢失 

rebias 是否丢失了age?

Process 845 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x000000010504f980
->  0x10504f980: popq   %rax
    0x10504f981: cmpq   (%rax), %rax
    0x10504f984: xorl   %esi, %esi
    0x10504f986: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8b60
       rbx = 0x00000000000000c2
       rcx = 0x0000000000000008
       rdx = 0x0000000747bb8b80
       rdi = 0x0000000101003800
       rsi = 0x0000700004a525c8
       rbp = 0x0000700004a52678
       rsp = 0x0000700004a52628
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff03a50400
       r12 = 0x0000000000000000
       r13 = 0x000000011cc6b02b
       r14 = 0x0000700004a526a8
       r15 = 0x0000000101003800
       rip = 0x000000010504f980
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) p ((oopDesc*)0x0000000747bb8b60)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb8b60} - 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"{0x0000000747bb8b88} (e8f77171 0)
(lldb) p ((oopDesc*)0x0000000747bb8b60)->age()
(uint) $1 = 0
(lldb) p ((oopDesc*)0x0000000747bb8b60)->incr_age()
(lldb) p ((oopDesc*)0x0000000747bb8b60)->age()
(uint) $2 = 1
(lldb) b 0x10504fa22
Breakpoint 4: address = 0x000000010504fa22
(lldb) c
Process 845 resuming
Process 845 stopped
* thread #5, stop reason = breakpoint 4.1
    frame #0: 0x000000010504fa22
->  0x10504fa22: testq  $0x300, %rbx              ; imm = 0x300 
    0x10504fa29: jne    0x10504fa48
    0x10504fa2b: andq   $0x37f, %rax              ; imm = 0x37F 
    0x10504fa32: movq   %rax, %rbx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x000000000000000d
       rbx = 0x0000000101003800
       rcx = 0x0000000747bb8b60
       rdx = 0x0000700004a52630
       rdi = 0x0000000101003800
       rsi = 0x0000700004a52620
       rbp = 0x0000700004a52678
       rsp = 0x0000700004a52620
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff03a50400
       r12 = 0x0000000000000000
       r13 = 0x000000011cc6b02c
       r14 = 0x0000700004a526a8
       r15 = 0x0000000101003800
       rip = 0x000000010504fa22
    rflags = 0x0000000000000246
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) register write rbx 0x0000000101003b00
(lldb) stepi
Process 845 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa29
->  0x10504fa29: jne    0x10504fa48
    0x10504fa2b: andq   $0x37f, %rax              ; imm = 0x37F 
    0x10504fa32: movq   %rax, %rbx
    0x10504fa35: orq    %r15, %rbx
Target 0: (java) stopped.
(lldb) stepi
Process 845 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa48
->  0x10504fa48: movl   0x8(%rcx), %ebx
    0x10504fa4b: shlq   $0x3, %rbx
    0x10504fa4f: movq   0xb0(%rbx), %rbx
    0x10504fa56: orq    %r15, %rbx
Target 0: (java) stopped.
(lldb) stepi -c 3
Process 845 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa56
->  0x10504fa56: orq    %r15, %rbx
    0x10504fa59: lock   
    0x10504fa5a: cmpxchgq %rbx, (%rcx)
    0x10504fa5e: jne    0x10504faa5
Target 0: (java) stopped.
(lldb) stepi -c 3
Process 845 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010504fa64
->  0x10504fa64: jmp    0x10504fd05
    0x10504fa69: movl   0x8(%rcx), %ebx
    0x10504fa6c: shlq   $0x3, %rbx
    0x10504fa70: movq   0xb0(%rbx), %rbx
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8b60)->age()
(uint) $3 = 0
(lldb) p ((oopDesc*)0x0000000747bb8b60)->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
(lldb) 

呵呵 rebias 这里就是使用的 ebx, 丢失了 age 的相关信息 

进入偏向锁的需求?

1. UseHeavyMonitors 为 false, 从上面的代码可以看出 如果是 UseHeavyMonitors 为true, monitor 只会生成走 InterpreterRuntime::monitorenter 的代码 

2. UseBiasedLocking 为 true, 从上面的代码可以看出, 如果 UseBiasedLocking 为 false, 甚至都不会生成 偏向锁部分的处理的代码 

3. 创建对象的时候 klass->prototype_header() 为 0x05[bias_pattern 允许偏向锁 0x1, 锁标记为为 0x01][可能影响这个, 参数 BiasedLockingStartupDelay]

添加于2020.07.04 - bytecodeInterpreter.cpp 里面的 monitorenter 

呵呵 最近无意间看到了这样的一篇文章  死磕Synchronized底层实现--偏向锁 里面作者介绍的挺好的 

另外还有一个收货就是, bytecodeInterpreter.cpp 里面有 monitorenter 的逻辑代码 

这个看起来更加友好一些 

      CASE(_monitorenter): {
        oop lockee = STACK_OBJECT(-1);
        // derefing's lockee ought to provoke implicit null check
        CHECK_NULL(lockee);
        // find a free monitor or one already allocated for this object
        // if we find a matching object then we need a new monitor
        // since this is recursive enter
        BasicObjectLock* limit = istate->monitor_base();
        BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
        BasicObjectLock* entry = NULL;
        while (most_recent != limit ) {
          if (most_recent->obj() == NULL) entry = most_recent;
          else if (most_recent->obj() == lockee) break;
          most_recent++;
        }
        if (entry != NULL) {
          entry->set_obj(lockee);
          int success = false;
          uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place;

          markOop mark = lockee->mark();
          intptr_t hash = (intptr_t) markOopDesc::no_hash;
          // implies UseBiasedLocking
          if (mark->has_bias_pattern()) {
            uintptr_t thread_ident;
            uintptr_t anticipated_bias_locking_value;
            thread_ident = (uintptr_t)istate->thread();
            anticipated_bias_locking_value =
              (((uintptr_t)lockee->klass()->prototype_header() | thread_ident) ^ (uintptr_t)mark) &
              ~((uintptr_t) markOopDesc::age_mask_in_place);

            if  (anticipated_bias_locking_value == 0) {
              // already biased towards this thread, nothing to do
              if (PrintBiasedLockingStatistics) {
                (* BiasedLocking::biased_lock_entry_count_addr())++;
              }
              success = true;
            }
            else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) {
              // try revoke bias
              markOop header = lockee->klass()->prototype_header();
              if (hash != markOopDesc::no_hash) {
                header = header->copy_set_hash(hash);
              }
              if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) {
                if (PrintBiasedLockingStatistics)
                  (*BiasedLocking::revoked_lock_entry_count_addr())++;
              }
            }
            else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) {
              // try rebias
              markOop new_header = (markOop) ( (intptr_t) lockee->klass()->prototype_header() | thread_ident);
              if (hash != markOopDesc::no_hash) {
                new_header = new_header->copy_set_hash(hash);
              }
              if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) {
                if (PrintBiasedLockingStatistics)
                  (* BiasedLocking::rebiased_lock_entry_count_addr())++;
              }
              else {
                CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
              }
              success = true;
            }
            else {
              // try to bias towards thread in case object is anonymously biased
              markOop header = (markOop) ((uintptr_t) mark & ((uintptr_t)markOopDesc::biased_lock_mask_in_place |
                                                              (uintptr_t)markOopDesc::age_mask_in_place |
                                                              epoch_mask_in_place));
              if (hash != markOopDesc::no_hash) {
                header = header->copy_set_hash(hash);
              }
              markOop new_header = (markOop) ((uintptr_t) header | thread_ident);
              // debugging hint
              DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);)
              if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) {
                if (PrintBiasedLockingStatistics)
                  (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
              }
              else {
                CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
              }
              success = true;
            }
          }

          // traditional lightweight locking
          if (!success) {
            markOop displaced = lockee->mark()->set_unlocked();
            entry->lock()->set_displaced_header(displaced);
            bool call_vm = UseHeavyMonitors;
            if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) {
              // Is it simple recursive case?
              if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
                entry->lock()->set_displaced_header(NULL);
              } else {
                CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
              }
            }
          }
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
        } else {
          istate->set_msg(more_monitors);
          UPDATE_PC_AND_RETURN(0); // Re-execute
        }
      }

参考

Hotspot 三种锁实现总结

标志寄存器

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

为你推荐

随机一门技术分享之Netty

随机一门技术分享之Netty

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

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

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

6
7