646 // This is convenient but results a ST-before-CAS penalty. The following CAS suffers
647 // additional latency as we have another ST in the store buffer that must drain.
648
649 // avoid ST-before-CAS
650 // register juggle because we need tmpReg for cmpxchgptr below
651 movptr(scrReg, boxReg);
652 movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
653
654 // Optimistic form: consider XORL tmpReg,tmpReg
655 movptr(tmpReg, NULL_WORD);
656
657 // Appears unlocked - try to swing _owner from null to non-null.
658 // Ideally, I'd manifest "Self" with get_thread and then attempt
659 // to CAS the register containing Self into m->Owner.
660 // But we don't have enough registers, so instead we can either try to CAS
661 // rsp or the address of the box (in scr) into &m->owner. If the CAS succeeds
662 // we later store "Self" into m->Owner. Transiently storing a stack address
663 // (rsp or the address of the box) into m->owner is harmless.
664 // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
665 lock();
666 cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
667 movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3
668 // If we weren't able to swing _owner from null to the BasicLock
669 // then take the slow path.
670 jccb (Assembler::notZero, NO_COUNT);
671 // update _owner from BasicLock to thread
672 get_thread (scrReg); // beware: clobbers ICCs
673 movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg);
674 xorptr(boxReg, boxReg); // set icc.ZFlag = 1 to indicate success
675
676 // If the CAS fails we can either retry or pass control to the slow path.
677 // We use the latter tactic.
678 // Pass the CAS result in the icc.ZFlag into DONE_LABEL
679 // If the CAS was successful ...
680 // Self has acquired the lock
681 // Invariant: m->_recursions should already be 0, so we don't need to explicitly set it.
682 // Intentional fall-through into DONE_LABEL ...
683 #else // _LP64
684 // It's inflated and we use scrReg for ObjectMonitor* in this section.
685 movq(scrReg, tmpReg);
686 xorq(tmpReg, tmpReg);
687 lock();
688 cmpxchgptr(thread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
689 // Unconditionally set box->_displaced_header = markWord::unused_mark().
690 // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
691 movptr(Address(boxReg, 0), checked_cast<int32_t>(markWord::unused_mark().value()));
692 // Propagate ICC.ZF from CAS above into DONE_LABEL.
693 jccb(Assembler::equal, COUNT); // CAS above succeeded; propagate ZF = 1 (success)
694
|
646 // This is convenient but results a ST-before-CAS penalty. The following CAS suffers
647 // additional latency as we have another ST in the store buffer that must drain.
648
649 // avoid ST-before-CAS
650 // register juggle because we need tmpReg for cmpxchgptr below
651 movptr(scrReg, boxReg);
652 movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
653
654 // Optimistic form: consider XORL tmpReg,tmpReg
655 movptr(tmpReg, NULL_WORD);
656
657 // Appears unlocked - try to swing _owner from null to non-null.
658 // Ideally, I'd manifest "Self" with get_thread and then attempt
659 // to CAS the register containing Self into m->Owner.
660 // But we don't have enough registers, so instead we can either try to CAS
661 // rsp or the address of the box (in scr) into &m->owner. If the CAS succeeds
662 // we later store "Self" into m->Owner. Transiently storing a stack address
663 // (rsp or the address of the box) into m->owner is harmless.
664 // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
665 lock();
666 cmpxchgptr(thread, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
667 movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3
668
669 // If the CAS fails we can either retry or pass control to the slow path.
670 // We use the latter tactic.
671 // Pass the CAS result in the icc.ZFlag into DONE_LABEL
672 // If the CAS was successful ...
673 // Self has acquired the lock
674 // Invariant: m->_recursions should already be 0, so we don't need to explicitly set it.
675 // Intentional fall-through into DONE_LABEL ...
676 #else // _LP64
677 // It's inflated and we use scrReg for ObjectMonitor* in this section.
678 movq(scrReg, tmpReg);
679 xorq(tmpReg, tmpReg);
680 lock();
681 cmpxchgptr(thread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
682 // Unconditionally set box->_displaced_header = markWord::unused_mark().
683 // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
684 movptr(Address(boxReg, 0), checked_cast<int32_t>(markWord::unused_mark().value()));
685 // Propagate ICC.ZF from CAS above into DONE_LABEL.
686 jccb(Assembler::equal, COUNT); // CAS above succeeded; propagate ZF = 1 (success)
687
|