Skip to content

runtime interp monitor

ceragon edited this page Jun 12, 2022 · 5 revisions

解释执行的 monitor

结构体

class BasicObjectLock {
    BasicLock _lock;
    // 锁对象的地址
    oop       _obj;
    static int obj_offset_in_bytes()                    {
        return offset_of(BasicObjectLock, _obj);  
    }
};
class BasicLock {
    volatile markOop _displaced_header;
    void         set_displaced_header(markOop header)   { _displaced_header = header; }
};

字节码

monitorEnter

初始情况

索引 名称 介绍
0 save rbp
-9 initial_sp
-9 monitor_block_top

有一个值之后

索引 名称 介绍
0 save rbp
-9 initial_sp
-10 monitor_block_top

有两个不同值之后

索引 名称 介绍
0 save rbp
-9 initial_sp
-11 monitor_block_top
REGISTER_DECLARATION(Register, c_rarg1, rsi);
void TemplateTable::monitorenter() {
    // 调用 monitorEnter 之前需要保证 synchronize 的对象在操作数栈的栈顶,也就是 rax 寄存器
    // 监视的对象不能为空,否则会空指针异常
    __ null_check(rax);
    // rsi 寄存器   
    Register rmon = c_rarg1;
    // 异或  相同为0,则 rmon 最终为0     
    __ xorl(rmon, rmon); // points to free slot or NULL
    {
        // 初始情况下,rtop,rbot 是一个值
        Label entry, loop, exit;
        // rbp 栈帧基址,monitor_block_top 存储在了栈上的偏移 9 的位置
        const Address monitor_block_top(rbp, 
                                        frame::interpreter_frame_monitor_block_top_offset * wordSize);
        // rcx
        Register rtop = c_rarg3;
        
        // 将 monitor_block_top 置入 rcx 中
        __ movptr(rtop, monitor_block_top);
        // 这里存储的是栈帧顶部的地址
        const Address monitor_block_bot(rbp, 
                                        frame::interpreter_frame_initial_sp_offset * wordSize);
        // rdx
        Register rbot = c_rarg2;
        // rbot: monitor_block 的底部
        __ lea(rbot, monitor_block_bot);
        // 跳转到 entry 标签
        __ jmpb(entry);
        
        // loop 开始 ======================
        // loop 标签处
        __ bind(loop);
        // monitor_block_top 存储的是 BasicObjectLock 结构体
        // 查看一下结构体中锁对象的位置是否没被占用
        __ cmpptr(Address(rtop, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD);
        // 比较并移动,如果锁对象的位置没有被占用
        // 将 monitor_block_top 值放入 rmon: rsi 寄存器
        __ cmovptr(Assembler::equal, rmon, rtop);
        // 比较一下 rax 中存储的锁对象地址,和 monitor_block_top 或者说栈上存储的地址是否一样
        __ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));
        // 一样的话跳转到 exit 标签
        __ jccb(Assembler::equal, exit);
        const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
        // 否则 monitor_block_top 地址向上扩展一个 BasicObjectLock 结构体的大小
        // 因为 monitor_block 在栈上是从低向高使用,而不是从高向低
        __ addptr(rtop, entry_size);
        // loop 结束 =============================
        
        __ bind(entry);
        // rbot: monitorBlock 的底部, rtop: monitorBlock的顶部
        // 由于是从低到高遍历,所以遍历到头就可以停止了
        __ cmpptr(rtop, rbot);
        // 没到头就继续循环
        __ jcc(Assembler::notEqual, loop);
        __ bind(exit);
    }
    // 上面的步骤是从 monitor_block 表中找一个空位,
    // 首个对象会直接遇到 rtop == rbot 的情况
    // 判断 rmon 是否为0
    __ testptr(rmon, rmon);
    // 不为 0 就表示找到了空位
    __ jcc(Assembler::notZero, allocated);
    
    {
        // =============== allocate 空间扩展 ================
        Label entry, loop;
        // 1. compute new pointers          // rsp: old expression stack top
        // monitor_block_bot, BasicObjectLock 表的底部
        __ movptr(rmon, monitor_block_bot); // rmon: old expression stack bottom
        // 把 rsp 向下扩展一个 BasicObjectLock 对象的空间
        __ subptr(rsp, entry_size);         // move expression stack top
        // 第一次产生锁的时候,rmon 和 rsp 的值是一致的,BasicObjectLock 表的底部也下移一个对象位置
        __ subptr(rmon, entry_size);        // move expression stack bottom
        // 将栈顶作为 monitor_block 的顶部
        __ 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);
        // 如果是第一次出现锁,则 rtop 和 rmon 一定相同
        __ cmpptr(rtop, rmon);                      // check if bottom reached
        // 不同会循环
        __ jcc(Assembler::notEqual, loop);          // if not at bottom then
    }
    
    __ bind(allocated);
    // 让 rbcp 指向下一个字节码
    __ increment(rbcp);
    // 保存对象到空的位置
    __ movptr(Address(rmon, BasicObjectLock::obj_offset_in_bytes()), rax);
    __ lock_object(rmon);
//    __ save_bcp(); 
    movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), _bcp_register);
    // 检查 stackOverFlow
    __ generate_stack_overflow_check(0);
    // 跳转到下一个字节码
    __ dispatch_next(vtos);
}

lock_object

void InterpreterMacroAssembler::lock_object(Register lock_reg) {
    // lock_reg: rsi 寄存器,且记录的是 BasicObjectLock
    // 默认不启用,否则会直接使用重量级锁
    if (UseHeavyMonitors) {
        call_VM(noreg,
            CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
            lock_reg);
    } else {
        // ================= cmpxchg 进行加锁 ============
        // rcx
        const Register obj_reg = c_rarg3;
        // 让 rcx 记录锁对象的地址
        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);
        }
        const Register swap_reg = rax; // Must use rax for cmpxchg instruction
        // 立即数 1 放到 rax 寄存器上
        movl(swap_reg, (int32_t)1);
        // 每个对象的头 8字节 mark word
        // Load (object->mark() | 1) into swap_reg %rax
        // 说白了将 markWord 的最低位设为1
        // 之所要要将最低位设为1,因为期望的是原本无锁,经过操作之后变为了有锁
        // 无锁状态是 01,若已经加锁,则状态是 00,或者重量级锁 10
        // 因此如果原本就是有锁,那么 cmpxchg 必然失败
        // 只有原本是无锁,且 cmpxchg 操作成功,才说明加锁成功
        orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
        
        // _lock 字段的偏移,默认是0
        const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
        // _displaced_header 字段的偏移,默认是0
        const int mark_offset = lock_offset +
                            BasicLock::displaced_header_offset_in_bytes();
        // 直接先将 markWord 保存到栈上(之前选择好的一个 BasicObjectLock 格子上)
        movptr(Address(lock_reg, mark_offset), swap_reg);
        // 如果是多处理器架构,则增加一个 lock 前缀,
        // 用于保证下一个指令原子化执行
        if (os::is_MP()) lock();
        // 虽然 cmpxchg 是一条指令,但是隐含了两个操作
        // 先从 3缓 读取数据所在的缓存行到 1缓 中
        // 比较读取的数据与 rax 寄存器的值
        // 如果相等,则修改目的地址的值为 lock_reg 的值
        // 以上涉及了对于三缓的两次操作,读和写。
        // 如果不加 lock 前缀,会造成刚读取完值,就被其他核心修改的结果。
        // 此外 lock_reg 是栈上 basicObjectLock 的首地址
        // 下面这个命令的目的就是把锁对象的 mark_word 修改成 basicObjectLock 的首地址
        cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
        // 如果上个步骤修改成功了,则标志寄存器会出现0,
        // 然后就可以跳转到 done 处了
        // 然而这只能保证说设置锁标记成功了,并不代表自己拿到锁了!!!
        jcc(Assembler::zero, done);
        // =======================================
        // ==================== 比较并替换失败 ================
        // swap_reg: 由于 cmpxchg 失败,那么 rax 的值会变成最新的 markWord
        // rsp: 栈指针
        // 将 markWord 与 rsp 相减,乍看会觉得莫名其妙,实则是在判断锁重入!!!
        // 因为 cmpxchg 失败,说明其他线程占有了锁,
        // 如果是占有了锁,那么 markWord 的值会变成占有者线程栈上的 basicObjectLock 的首地址
        // 通过比较当前线程 rsp 指针的值,和 basicObjectLock 的首地址,即可判断是否本线程占有了锁
        subptr(swap_reg, rsp);
        const int zero_bits = 7;
        // 补码的值为: 11111111111111111111000000000111
        // 差值与上页的大小,0 的位直接置为0
        andptr(swap_reg, zero_bits - os::vm_page_size());
        // 将结果保存在栈上
        movptr(Address(lock_reg, mark_offset), swap_reg);
        // 如果 swap_reg 的值是0,就跳转到 done
        // 在轻量级锁生效时,尾数的3位是 000
        // 因为如果要满足为0,一是 swap_reg 和 rsp 的差值在一个页大小的范围内
        // 其次锁标记的状态还必须是轻量级锁,也就是 000
        // 另外这里只是快速判断,如果判断成功,则判断锁重入的效率会很高,
        // 判断失败,则被迫调用 vm 的 monitorEnter
        jcc(Assembler::zero, done);
        // 只有偏向锁用到了这个 label
        bind(slow_case);
        // 调用 vm 的 monitorEnter
        call_VM(noreg,
            CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
            lock_reg);
        
        bind(done);
    }
    
}

call_VM

void MacroAssembler::call_VM(Register oop_result,
                            address entry_point,
                            Register arg_1,
                            bool check_exceptions) {
    // oop_result: null
    // entry_point: monitorenter 的vm调用方法
    // arg_1: basicObjectLock 对象的地址, Register rmon = c_rarg1; 且是 c_rarg1 寄存器
    // check_exceptions: false
    Label C, E;
    // 将当前 jmp(E) 的地址压栈
    // 跳转到 C 执行
    call(C, relocInfo::none);
    jmp(E);

    bind(C);
    pass_arg1(this, arg_1);
    // 执行调用
    call_VM_helper(oop_result, entry_point, 1, check_exceptions);
    ret(0);

    bind(E);
}

static void pass_arg1(MacroAssembler* masm, Register arg) {
    // 根据上下文,arg 是 c_rarg1 寄存器
    if (c_rarg1 != arg ) {
        masm->mov(c_rarg1, arg);
    }
}

call_VM_helper

void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
    // 由于已经将 call_VM 调用之后的返回地址压栈了
    // 所以真实的 rsp 地址应该 + 1
    lea(rax, Address(rsp, wordSize));
    call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions);
}

void MacroAssembler::call_VM_base(Register oop_result,
                                  Register java_thread,
                                  Register last_java_sp,
                                  address  entry_point,
                                  int      number_of_arguments,
                                  bool     check_exceptions) {
    // oop_result: null
    // java_thread: noreg
    // last_java_sp: rax (调用 vm 之前的栈地址)
    // entry_point: monitorenter 的 vm 调用
    // number_of_arguments: 1
    // check_exceptions: false
    if (!java_thread->is_valid()) {
        java_thread = r15_thread;
    }
    // c_rarg0: rdi
    mov(c_rarg0, r15_thread);
    // 修改 java 线程对象的 last_java_sp 和 last_java_fp 两个字段
    set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);
    // 调用 vm 的方法
    MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
    // reset last Java frame
    // Only interpreter should have to clear fp
    reset_last_Java_frame(java_thread, true);
}

void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp) {
    // we must set sp to zero to clear frame
    movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
    if (clear_fp) {
        movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
    }
    movptr(Address(java_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
}

call_VM_leaf_base

void MacroAssembler::call_VM_leaf_base(address entry_point, int num_args) {
    Label L, E;
    // 按理说 rsp 的值是个地址,为啥能和 15 比较大小
    testl(rsp, 15);
    jcc(Assembler::zero, L);
    // 正常流程的话,开辟一个 8 字节的栈空间,用于存储返回地址
    subq(rsp, 8);
    {
        // 调用方法
        call(RuntimeAddress(entry_point));
    }
    // 调用结束恢复栈帧
    addq(rsp, 8);
    jmp(E);
    bind(L);
    {
        call(RuntimeAddress(entry_point));
    }
    bind(E);
}

monitorExit

void TemplateTable::monitorexit() {
    __ null_check(rax);
    {
        Label entry, loop;
        Register rtop = c_rarg1;
        const Address monitor_block_top(
                rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
        __ movptr(rtop, monitor_block_top);
        const Address monitor_block_bot(
                rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
        __ lea(rbot, monitor_block_bot);
        
        __ jmpb(entry);       
        __ bind(loop);
        __ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));
        __ jcc(Assembler::equal, found);
        __ addptr(rtop, entry_size);
        __ bind(entry);
        __ cmpptr(rtop, rbot);
        __ jcc(Assembler::notEqual, loop);
    }
    __ call_VM(noreg, CAST_FROM_FN_PTR(address,
                   InterpreterRuntime::throw_illegal_monitor_state_exception));
    __ should_not_reach_here();
    __ bind(found);
    __ push_ptr(rax);
    __ unlock_object(rtop);
    __ pop_ptr(rax);
}
void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
    if (UseHeavyMonitors) {
        call_VM(noreg,
                CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),
                lock_reg);
    } else {
        Label done;
        save_bcp();
        lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes()));
        movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()));
        movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD);
        if (UseBiasedLocking) {
            biased_locking_exit(obj_reg, header_reg, done);
        }
        movptr(header_reg, Address(swap_reg,
                               BasicLock::displaced_header_offset_in_bytes()));
        testptr(header_reg, header_reg);
        jcc(Assembler::zero, done);
        if (os::is_MP()) lock();
        cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
        jcc(Assembler::zero, done);
        movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), obj_reg);
        call_VM(noreg,
                    CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),
                    lock_reg);
        bind(done);
        restore_bcp();
    }
    
}

VM 调用

数据结构

typedef class oopDesc*                            oop;
class Handle {
    oop* _handle;
    oop     obj() const                            {
        return _handle == NULL ? (oop)NULL : *_handle; 
    }
    oop     non_null_obj() const                   {
        return *_handle;
    }
    
    oop     operator () () const                   {
        return obj(); 
    }
    oop     operator -> () const                   {
        // 被重载之后,实际返回的是 oopDesc 结构体
        // 相当于类型转化
        return non_null_obj(); 
    }
};

markOop  oopDesc::mark()      const {
    // as_oop() 返回对象的首地址
    // mark_offset_in_bytes() markWord 的偏移量
    // 总之就是获取 markWord 的包装类 markOop
    return HeapAccess<MO_VOLATILE>::load_at(as_oop(), mark_offset_in_bytes());
}

inline oop        as_oop() const {
    return const_cast<oopDesc*>(this); 
}
class markOopDesc: public oopDesc {
    uintptr_t value() const { return (uintptr_t) this; }
    enum { age_bits                 = 4,
         lock_bits                = 2,
         biased_lock_bits         = 1,
         max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
         hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
         cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
         epoch_bits               = 2
    };
    enum { lock_shift               = 0,
         biased_lock_shift        = lock_bits,
         age_shift                = lock_bits + biased_lock_bits,
         cms_shift                = age_shift + age_bits,
         hash_shift               = cms_shift + cms_bits,
         epoch_shift              = hash_shift
  };
    enum { 
        // lock_bits: 2
        // lock_mask: 0b11
        lock_mask                = right_n_bits(lock_bits),
        // lock_mask_in_place: 0b11
         lock_mask_in_place       = lock_mask << lock_shift,
         // lock_bits: 2
         // biased_lock_bits: 1
         // biased_lock_mask = 0b111
         biased_lock_mask         = right_n_bits(lock_bits + biased_lock_bits),
         biased_lock_mask_in_place= biased_lock_mask << lock_shift,
         biased_lock_bit_in_place = 1 << biased_lock_shift,
         age_mask                 = right_n_bits(age_bits),
         age_mask_in_place        = age_mask << age_shift,
         epoch_mask               = right_n_bits(epoch_bits),
         epoch_mask_in_place      = epoch_mask << epoch_shift,
         cms_mask                 = right_n_bits(cms_bits),
         cms_mask_in_place        = cms_mask << cms_shift
    };
    enum { locked_value             = 0,
         unlocked_value           = 1,
         monitor_value            = 2,
         marked_value             = 3,
         biased_lock_pattern      = 5
    };
    inline intptr_t mask_bits      (intptr_t  x, intptr_t m) {
        return x & m; 
    }
    bool is_neutral()  const { 
        // biased_lock_mask_in_place: 0b111
        // 判断 markWord 后三位的值是否等于 1
        // 也就是说只要末尾为1,就是中性状态,也就是无锁
        return (mask_bits(value(), biased_lock_mask_in_place) == unlocked_value); 
    }
    bool has_locker() const {
        // lock_mask_in_place: 0b11
        // 判断 markWord 后两位是否等于0
        // 如果相等,则表示轻量级锁加锁成功
        return ((value() & lock_mask_in_place) == locked_value);
    }
    bool has_monitor() const {
        // monitor_value: 0b0010
        // 只要倒数第二位为1,就有 monitor,也就是重量级锁状态
        return ((value() & monitor_value) != 0);
    }
    ObjectMonitor* monitor() const {
        // monitor_value: 0b0010
        // 0 异或任何数都等于它本身
        return (ObjectMonitor*) (value() ^ monitor_value);
    }
    BasicLock* locker() const {
        return (BasicLock*) value();
    }
};

monitorenter

void InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem) {
    // 在栈上分配一个 Handle 对象,持有锁对象的首地址
    Handle h_obj(thread, elem->obj());
    if (UseBiasedLocking) {
        ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
    } else {
        ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
    }
}
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
    markOop mark = obj->mark();
    // 判断 markWord 尾数是否为 1
    if (mark->is_neutral()) {
        // 在栈帧上有个 BasicObjectLock,第一个字段就是 BasicLock
        // 相当于在栈上保存旧的 markWord值
        lock->set_displaced_header(mark);
        // 这里的意思是,尝试将对象头的 markWord 改成 BasicLock 对象的首地址
        if (mark == obj()->cas_set_mark((markOop) lock, mark)) {
            // 如果旧值与mark值相等,则修改成功,同时自己持有了锁
            return;
        }
    } else if (mark->has_locker() &&    
             THREAD->is_lock_owned((address)mark->locker())) {
        // 先判断了是否是轻量级锁
        // 由于轻量级锁状态下,markWord 记录的是持有锁线程栈帧中的 BasicLock 地址
        // 所以判断一下该地址是否在当前线程的栈帧范围内
        // 如果都满足,则锁重入成功
        // 为了保证 markWord 存储的一致性,保存在第一个持有锁的栈帧中即可
        // 当前栈帧已经设置过的 displaced_header 字段就可以置空了
        lock->set_displaced_header(NULL);
        return;
    }
    // 当前是轻量级锁状态,且占有者不是当前线程,那么执行锁膨胀
    // 将当前栈帧上的 displaced_header 置为空,因为没有必要了
    // 重量级锁之后,markWord 会缓存到 monitor 中
    lock->set_displaced_header(markOopDesc::unused_mark());
    ObjectSynchronizer::inflate(THREAD,
                              obj(),
                              inflate_cause_monitor_enter)->enter(THREAD);
}

markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) {
    // as_oop() + mark_offset_in_bytes() 组成了一个地址,也就是对象的头部
    // 如果该位置的值 == old_mark,则修改为 new_mark
    return HeapAccess<>::atomic_cmpxchg_at(new_mark, as_oop(), mark_offset_in_bytes(), old_mark);
}

lock inflate

ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self,
                                                     oop object,
                                                     const InflateCause cause) {
    // 本方法的目的是生成或者返回一个 Monitor 对象
    for (;;) {
        const markOop mark = object->mark();
        // 已经是重量级锁
        if (mark->has_monitor()) {
            // 重量级锁的话,markWord 记录的是 monitor 对象的地址
            ObjectMonitor * inf = mark->monitor();
            return inf;
        }
        // 如果重量级锁膨胀中,那么会直接把 markWord 置为0
        if (mark == markOopDesc::INFLATING()) {
            // TODO
            ReadStableMark(object);
            continue;
        }
        // markWord 末尾是0
        if (mark->has_locker()) {
            // 从线程的 ObjectMonitor 池中获取一个对象
            ObjectMonitor * m = omAlloc(Self);
            // 重置成员变量
            m->Recycle();
            m->_Responsible  = NULL;
            m->_recursions   = 0;
            // 重置自旋次数
            m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;
            // 修改 markword 为膨胀中
            markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
            if (cmp != mark) {
                // 修改失败,释放 m 对象到池中
                omRelease(Self, m, true);
                continue;
            }
            // 修改成功
            // 取出 markWord,注意这个 markWord 实际上是 BasicObjectLock -> BasicLock 的地址
            markOop dmw = mark->displaced_mark_helper();
            // 保存 BasicLock 的地址
            m->set_header(dmw);
            // locker() 其实就是 BasicLock 的地址
            m->set_owner(mark->locker());
            // 将对象保存到 monitor 中
            m->set_object(object);
            // 由于变成了重量级锁,因此 markWord 的值需要变成 monitor 对象的地址
            // 但是不管怎样,m 的地址的末尾必须是 0
            object->release_set_mark(markOopDesc::encode(m));
            // 膨胀次数 +1
            OM_PERFDATA_OP(Inflations, inc());
            return m;
        }
        // 这种情况会出现,是因为已经膨胀成了重量级锁
        // 因此即使锁释放了,下次再获得锁,也会以重量级锁的方式来处理
        // 分配 monitor 和重置变量就不再介绍了
        ObjectMonitor * m = omAlloc(Self);
        m->Recycle();
        m->set_header(mark);
        m->set_owner(NULL);
        m->set_object(object);
        m->_recursions   = 0;
        m->_Responsible  = NULL;
        m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;
        // 比较并替换 markWord 的值
        if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) {
            // 修改失败则他人拿到了锁,需要释放 monitor 对象并重试
            m->set_object(NULL);
            m->set_owner(NULL);
            m->Recycle();
            omRelease(Self, m, true);
            m = NULL;
            continue;
        }
        // 锁膨胀次数 +1
        OM_PERFDATA_OP(Inflations, inc());
        return m;
    }
}


static markOop INFLATING() { return (markOop) 0; }    // inflate-in-progress

ObjectMonitor

class ObjectMonitor {
    void *  volatile _owner;
    // 等待队列
    ObjectWaiter * volatile _cxq;
    // 等待队列中,优先获取到锁的线程
    Thread * volatile _Responsible;
    // TODO: 应该是被唤醒的线程
    Thread * volatile _succ;
};
class Thread: public ThreadShadow {
    // ObjectMonitor 对象池
    ObjectMonitor* omFreeList;
    
    volatile intptr_t _Stalled;
    ParkEvent * _ParkEvent;
};

allocate

ObjectMonitor * volatile ObjectSynchronizer::gFreeList  = NULL; // 全局对象池
ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
    for (;;) {
        ObjectMonitor * m;
        m = Self->omFreeList;
        if (m != NULL) {
            // 有可用对象
            // 已经抢占了 list 的第一个元素,所以要移出队列
            Self->omFreeList = m->FreeNext;
            // 对象池数量 -1
            Self->omFreeCount--;
            // 默认为true,用于支持锁降级
            if (MonitorInUseLists) {
                // 这样占有的锁对象还能关联到对象池
                m->FreeNext = Self->omInUseList;
                // 将 m 放入使用列表中
                Self->omInUseList = m;
                // 使用中的数量 +1
                Self->omInUseCount++;
            } else {
                m->FreeNext = NULL;
            }
            return m;
        }
        // 线程本地的对象池不够用了,看看全局对象池
        // 这里并不是直接从全局的池子里取对象
        // 而是取出多个对象,然后填充到线程的 omFreeList 中
        if (gFreeList != NULL) {
            // 后面就不看了
        }
    }
}

Monitor Enter

void ObjectMonitor::enter(TRAPS) {
    Thread * const Self = THREAD;
    // 比较并修改 monitor 的 owner 字段
    void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
    if (cur == NULL) {
        // cur 是返回的旧值,旧值为空,说明加锁成功
        return;
    }
    // cur 不为空,那么一定指向某个线程的首地址
    if (cur == Self) {
        // 持有锁的线程就是本线程,那么锁重入成功
        _recursions++;
        return;
    }
    // 判断 cur 是否在线程的栈空间内
    // TODO: 不太懂为啥有这个判断
    if (Self->is_lock_owned ((address)cur)) {
        _recursions = 1;
        _owner = Self;
        return;
    }
    // 当前线程缓存 monitor 对象
    Self->_Stalled = intptr_t(this);
    // Knob_SpinEarly 默认是 1
    // TrySpin() 尝试自旋加锁
    if (Knob_SpinEarly && TrySpin (Self) > 0) {
        // 加锁成功了,将取消缓存 monitor 对象
        Self->_Stalled = 0;
        return;
    }
    JavaThread * jt = (JavaThread *) Self;
    Atomic::inc(&_count);
    {
        Self->set_current_pending_monitor(this);
        for (;;) {
            // 正常情况下,EnterI 都会拿到锁再出来
            EnterI(THREAD);
            if (!ExitSuspendEquivalent(jt)) break;
            _recursions = 0;
            exit(false, Self);
        }
        Self->set_current_pending_monitor(NULL);
    }
    Atomic::dec(&_count);
    Self->_Stalled = 0;
    OM_PERFDATA_OP(ContendedLockAttempts, inc());
}

EnterI

void ObjectMonitor::EnterI(TRAPS) {
    Thread * const Self = THREAD;
    // 先尝试加锁
    if (TryLock (Self) > 0) {
        return;
    }
    // 自旋加锁
    if (TrySpin (Self) > 0) {
        return;
    }
    // 被迫进入等待队列
    // 新建一个 Waiter
    ObjectWaiter node(Self);
    // Thread 的一个成员
    Self->_ParkEvent->reset();
    // 重置 waiter
    node._prev   = (ObjectWaiter *) 0xBAD;
    node.TState  = ObjectWaiter::TS_CXQ;
    ObjectWaiter * nxt;
    for (;;) {
        node._next = nxt = _cxq;
        // 尝试将自己放到 _cxq 的位置
        // 成功了就退出循环
        if (Atomic::cmpxchg(&node, &_cxq, nxt) == nxt) break;
        // 有竞争者,失败了再尝试加锁一次
        if (TryLock (Self) > 0) {
            return;
        }
    }
    // nxt 会得到 _cxq 的旧值
    if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
        // 第一次进等待队列,就会出现这个情况
        // 把自己放到 _Responsible 中
        Atomic::replace_if_null(Self, &_Responsible);
    }
    int nWakeups = 0;
    int recheckInterval = 1;
    for (;;) {
        // 又一次尝试加锁
        if (TryLock(Self) > 0) break;
        if ((SyncFlags & 2) && _Responsible == NULL) {
            // 首先说明在上一步中,没有成功把自己设置成 _Responsible
            Atomic::replace_if_null(Self, &_Responsible);
        }
        if (_Responsible == Self || (SyncFlags & 1)) {
            // 只要等待着是自己,那么阻塞吧
            // 超时时间默认1ms
            Self->_ParkEvent->park((jlong) recheckInterval);
            // 需要注意,下一行代码会执行,有两个条件
            // 1: 超时时间到了
            // 2: 被唤醒了
            // 无论什么情况,等待时间加倍
            recheckInterval *= 8;
            // MAX_RECHECK_INTERVAL: 1000
            if (recheckInterval > MAX_RECHECK_INTERVAL) {
                recheckInterval = MAX_RECHECK_INTERVAL;
            }
        } else {
            // 阻塞,直到被唤醒
            Self->_ParkEvent->park();
        }
        // 被唤醒了,加锁试下
        if (TryLock(Self) > 0) break;
        // 没加锁成功,唤醒次数 +1
        ++nWakeups;
        // Knob_SpinAfterFutile: 默认值是1
        // 因此会在进行一次自旋
        if ((Knob_SpinAfterFutile & 1) && TrySpin(Self) > 0) break;
        // Knob_ResetEvent: 默认值是 0
        if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
            Self->_ParkEvent->reset();
            OrderAccess::fence();
        }
        if (_succ == Self) _succ = NULL;
        // 编译器,指令双屏障
        OrderAccess::fence();
    }
    // 由于上面死循环的退出条件只有一个,就是获取到锁
    // 下面的代码就是让自己退出等待队列
    UnlinkAfterAcquire(Self, &node);
    // 如果被唤醒者是自己,置空
    if (_succ == Self) _succ = NULL;
    if (_Responsible == Self) {
        // 如果自己是优先获取锁的,置空
        _Responsible = NULL;
        // 屏障
        OrderAccess::fence();
    }
    if (SyncFlags & 8) {
        OrderAccess::fence();
    }
}

tryLock

int ObjectMonitor::TryLock(Thread * Self) {
    void * own = _owner;
    if (own != NULL) return 0;
    // 比较为空,并进行替换为 Self
    if (Atomic::replace_if_null(Self, &_owner)) {
        // 成功
        return 1;
    }
    // 失败
    return -1;
}

TrySpin

static int Knob_PreSpin             = 10;
int ObjectMonitor::TrySpin(Thread * Self) {
    // 固定次数自旋已经被废弃了 
    int ctr = Knob_FixedSpin;
    if (ctr != 0) {
        while (--ctr >= 0) {
            if (TryLock(Self) > 0) return 1;
            SpinPause();
        }
        return 0;
    }
    // 循环11 次
    for (ctr = Knob_PreSpin + 1; --ctr >= 0;) {
        if (TryLock(Self) > 0) {
            // 加锁成功
            // x 的值是0
            int x = _SpinDuration; 
            // Knob_SpinLimit: 值是0
            if (x < Knob_SpinLimit) {
                if (x < Knob_Poverty) x = Knob_Poverty;
                _SpinDuration = x + Knob_BonusB;
            }
            // 上面没太看懂,只会走到这里
            return 1;
        }
        SpinPause();
    }
    
    // ctr = 0
    ctr = _SpinDuration;
    // Knob_SpinBase 默认值也是0
    if (ctr < Knob_SpinBase) ctr = Knob_SpinBase;
    if (ctr <= 0) return 0;
    // 下面的代码更是看不懂在干嘛
}

Clone this wiki locally