< prev index next >

src/cpu/x86/vm/macroAssembler_x86.cpp

Print this page
rev 12152 : [mq]: verification.patch

*** 43,52 **** --- 43,54 ---- #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" + #include "gc/shenandoah/shenandoahHeap.inline.hpp" + #include "gc/shenandoah/shenandoahHeapRegion.hpp" #endif // INCLUDE_ALL_GCS #include "crc32c.h" #ifdef COMPILER2 #include "opto/intrinsicnode.hpp" #endif
*** 1104,1113 **** --- 1106,1117 ---- 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); ) + shenandoah_store_addr_check(obj_reg); + if (PrintBiasedLockingStatistics && counters == NULL) { counters = BiasedLocking::counters(); } // Biased locking // See whether the lock is currently biased toward our thread and
*** 1167,1177 **** // 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 --- 1171,1181 ---- // 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_if_possible(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
*** 1179,1189 **** // 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. --- 1183,1193 ---- // 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_if_possible(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.
*** 1288,1297 **** --- 1292,1302 ---- // Note: we do not have to check the thread ID for two reasons. // First, the interpreter checks for IllegalMonitorStateException at // a higher level. Second, if the bias was revoked while we held the // lock, the object could not be rebiased toward another thread, so // the bias bit would be clear. + shenandoah_store_addr_check(obj_reg); // Access mark word movptr(temp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); andptr(temp_reg, markOopDesc::biased_lock_mask_in_place); cmpptr(temp_reg, markOopDesc::biased_lock_pattern); jcc(Assembler::equal, done); }
*** 1480,1489 **** --- 1485,1495 ---- if (RTMRetryCount > 0) { movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort bind(L_rtm_retry); } + shenandoah_store_addr_check(objReg); // Access mark word movptr(tmpReg, Address(objReg, 0)); testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased jcc(Assembler::notZero, IsInflated); if (PrintPreciseRTMLockingStatistics || profile_rtm) {
*** 1556,1565 **** --- 1562,1572 ---- assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); atomic_incptr(ExternalAddress((address)rtm_counters->total_count_addr()), scrReg); bind(L_noincrement); } xbegin(L_on_abort); + shenandoah_store_addr_check(objReg); // Access mark word movptr(tmpReg, Address(objReg, 0)); movptr(tmpReg, Address(tmpReg, owner_offset)); testptr(tmpReg, tmpReg); jcc(Assembler::zero, DONE_LABEL); if (UseRTMXendForLockBusy) {
*** 1702,1711 **** --- 1709,1720 ---- assert(cx1Reg == noreg, ""); assert(cx2Reg == noreg, ""); assert_different_registers(objReg, boxReg, tmpReg, scrReg); } + shenandoah_store_addr_check(objReg); // Access mark word + if (counters != NULL) { atomic_incl(ExternalAddress((address)counters->total_entry_count_addr()), scrReg); } if (EmitSync & 1) { // set box->dhw = markOopDesc::unused_mark()
*** 1751,1761 **** } #endif // INCLUDE_RTM_OPT movptr(tmpReg, Address(objReg, 0)); // [FETCH] testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased ! jccb(Assembler::notZero, IsInflated); // Attempt stack-locking ... orptr (tmpReg, markOopDesc::unlocked_value); movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS if (os::is_MP()) { --- 1760,1770 ---- } #endif // INCLUDE_RTM_OPT movptr(tmpReg, Address(objReg, 0)); // [FETCH] testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased ! jccb_if_possible(Assembler::notZero, IsInflated); // Attempt stack-locking ... orptr (tmpReg, markOopDesc::unlocked_value); movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS if (os::is_MP()) {
*** 1828,1838 **** } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines // Test-And-CAS instead of CAS movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? ! jccb (Assembler::notZero, DONE_LABEL); } // Appears unlocked - try to swing _owner from null to non-null. // Ideally, I'd manifest "Self" with get_thread and then attempt // to CAS the register containing Self into m->Owner. --- 1837,1847 ---- } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines // Test-And-CAS instead of CAS movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? ! jccb_if_possible(Assembler::notZero, DONE_LABEL); } // Appears unlocked - try to swing _owner from null to non-null. // Ideally, I'd manifest "Self" with get_thread and then attempt // to CAS the register containing Self into m->Owner.
*** 1846,1856 **** } cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3 // If we weren't able to swing _owner from NULL to the BasicLock // then take the slow path. ! jccb (Assembler::notZero, DONE_LABEL); // update _owner from BasicLock to thread get_thread (scrReg); // beware: clobbers ICCs movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg); xorptr(boxReg, boxReg); // set icc.ZFlag = 1 to indicate success --- 1855,1865 ---- } cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3 // If we weren't able to swing _owner from NULL to the BasicLock // then take the slow path. ! jccb_if_possible(Assembler::notZero, DONE_LABEL); // update _owner from BasicLock to thread get_thread (scrReg); // beware: clobbers ICCs movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg); xorptr(boxReg, boxReg); // set icc.ZFlag = 1 to indicate success
*** 1876,1886 **** xorptr (tmpReg, tmpReg); } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? ! jccb (Assembler::notZero, DONE_LABEL); } // Appears unlocked - try to swing _owner from null to non-null. // Use either "Self" (in scr) or rsp as thread identity in _owner. // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand. --- 1885,1895 ---- xorptr (tmpReg, tmpReg); } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? ! jccb_if_possible(Assembler::notZero, DONE_LABEL); } // Appears unlocked - try to swing _owner from null to non-null. // Use either "Self" (in scr) or rsp as thread identity in _owner. // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
*** 1964,1973 **** --- 1973,1984 ---- void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) { assert(boxReg == rax, ""); assert_different_registers(objReg, boxReg, tmpReg); + shenandoah_store_addr_check(objReg); // Access mark word + if (EmitSync & 4) { // Disable - inhibit all inlining. Force control through the slow-path cmpptr (rsp, 0); } else { Label DONE_LABEL, Stacked, CheckSucc;
*** 2005,2015 **** int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner); movptr(boxReg, Address(tmpReg, owner_offset)); testptr(boxReg, boxReg); jccb(Assembler::notZero, L_regular_inflated_unlock); xend(); ! jmpb(DONE_LABEL); bind(L_regular_inflated_unlock); } #endif // Despite our balanced locking property we still check that m->_owner == Self --- 2016,2026 ---- int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner); movptr(boxReg, Address(tmpReg, owner_offset)); testptr(boxReg, boxReg); jccb(Assembler::notZero, L_regular_inflated_unlock); xend(); ! jmpb_if_possible(DONE_LABEL); bind(L_regular_inflated_unlock); } #endif // Despite our balanced locking property we still check that m->_owner == Self
*** 2049,2069 **** if ((EmitSync & 65536) == 0 && (EmitSync & 256)) { // Attempt to reduce branch density - AMD's branch predictor. orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); ! jccb (Assembler::notZero, DONE_LABEL); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); ! jmpb (DONE_LABEL); } else { orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); ! jccb (Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); jccb (Assembler::notZero, CheckSucc); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); ! jmpb (DONE_LABEL); } // The Following code fragment (EmitSync & 65536) improves the performance of // contended applications and contended synchronization microbenchmarks. // Unfortunately the emission of the code - even though not executed - causes regressions --- 2060,2080 ---- if ((EmitSync & 65536) == 0 && (EmitSync & 256)) { // Attempt to reduce branch density - AMD's branch predictor. orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); ! jccb_if_possible(Assembler::notZero, DONE_LABEL); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); ! jmpb_if_possible(DONE_LABEL); } else { orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); ! jccb_if_possible(Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); jccb (Assembler::notZero, CheckSucc); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); ! jmpb_if_possible(DONE_LABEL); } // The Following code fragment (EmitSync & 65536) improves the performance of // contended applications and contended synchronization microbenchmarks. // Unfortunately the emission of the code - even though not executed - causes regressions
*** 2129,2143 **** movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), boxReg); // Intentional fall-through into LGoSlowPath ... bind (LGoSlowPath); orptr(boxReg, 1); // set ICC.ZF=0 to indicate failure ! jmpb (DONE_LABEL); bind (LSuccess); xorptr(boxReg, boxReg); // set ICC.ZF=1 to indicate success ! jmpb (DONE_LABEL); } bind (Stacked); // It's not inflated and it's not recursively stack-locked and it's not biased. // It must be stack-locked. --- 2140,2154 ---- movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), boxReg); // Intentional fall-through into LGoSlowPath ... bind (LGoSlowPath); orptr(boxReg, 1); // set ICC.ZF=0 to indicate failure ! jmpb_if_possible(DONE_LABEL); bind (LSuccess); xorptr(boxReg, boxReg); // set ICC.ZF=1 to indicate success ! jmpb_if_possible(DONE_LABEL); } bind (Stacked); // It's not inflated and it's not recursively stack-locked and it's not biased. // It must be stack-locked.
*** 2171,2186 **** xorptr(boxReg, r15_thread); } else { xorptr(boxReg, boxReg); } orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); ! jccb (Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); jccb (Assembler::notZero, CheckSucc); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); ! jmpb (DONE_LABEL); if ((EmitSync & 65536) == 0) { // Try to avoid passing control into the slow_path ... Label LSuccess, LGoSlowPath ; bind (CheckSucc); --- 2182,2197 ---- xorptr(boxReg, r15_thread); } else { xorptr(boxReg, boxReg); } orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); ! jccb_if_possible(Assembler::notZero, DONE_LABEL); movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); jccb (Assembler::notZero, CheckSucc); movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); ! jmpb_if_possible(DONE_LABEL); if ((EmitSync & 65536) == 0) { // Try to avoid passing control into the slow_path ... Label LSuccess, LGoSlowPath ; bind (CheckSucc);
*** 2233,2247 **** jccb (Assembler::notEqual, LSuccess); // Intentional fall-through into slow-path bind (LGoSlowPath); orl (boxReg, 1); // set ICC.ZF=0 to indicate failure ! jmpb (DONE_LABEL); bind (LSuccess); testl (boxReg, 0); // set ICC.ZF=1 to indicate success ! jmpb (DONE_LABEL); } bind (Stacked); movptr(tmpReg, Address (boxReg, 0)); // re-fetch if (os::is_MP()) { lock(); } --- 2244,2258 ---- jccb (Assembler::notEqual, LSuccess); // Intentional fall-through into slow-path bind (LGoSlowPath); orl (boxReg, 1); // set ICC.ZF=0 to indicate failure ! jmpb_if_possible(DONE_LABEL); bind (LSuccess); testl (boxReg, 0); // set ICC.ZF=1 to indicate success ! jmpb_if_possible (DONE_LABEL); } bind (Stacked); movptr(tmpReg, Address (boxReg, 0)); // re-fetch if (os::is_MP()) { lock(); }
*** 6075,6084 **** --- 6086,6255 ---- call(rax); // Caller pops the arguments (oop, message) and restores rax, r10 BLOCK_COMMENT("} verify_oop"); } + void MacroAssembler::in_heap_check(Register raddr, Label& done) { + ShenandoahHeap *h = (ShenandoahHeap *)Universe::heap(); + + HeapWord* first_region_bottom = h->first_region_bottom(); + HeapWord* last_region_end = first_region_bottom + (ShenandoahHeapRegion::RegionSizeBytes / HeapWordSize) * h->max_regions(); + + cmpptr(raddr, (intptr_t) first_region_bottom); + jcc(Assembler::less, done); + cmpptr(raddr, (intptr_t) first_region_bottom); + jcc(Assembler::greaterEqual, done); + + } + + void MacroAssembler::shenandoah_cset_check(Register raddr, Register tmp1, Register tmp2, Label& done) { + // Test that oop is not in to-space. + movptr(tmp1, raddr); + shrptr(tmp1, ShenandoahHeapRegion::RegionSizeShift); + movptr(tmp2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr()); + movbool(tmp2, Address(tmp2, tmp1, Address::times_1)); + testbool(tmp2); + jcc(Assembler::zero, done); + + // Check for cancelled GC. + movptr(tmp2, (intptr_t) ShenandoahHeap::cancelled_concgc_addr()); + movbool(tmp2, Address(tmp2, 0)); + testbool(tmp2); + jcc(Assembler::notZero, done); + + } + + void MacroAssembler::_shenandoah_store_addr_check(Address addr, const char* msg, const char* file, int line) { + _shenandoah_store_addr_check(addr.base(), msg, file, line); + } + + void MacroAssembler::_shenandoah_store_addr_check(Register dst, const char* msg, const char* file, int line) { + if (! UseShenandoahGC && ! ShenandoahStoreCheck) return; + if (dst == rsp) return; // Stack-based target + + Register raddr = r9; + Register tmp1 = r10; + Register tmp2 = r11; + + Label done; + + pushf(); + push(raddr); + push(tmp1); + push(tmp2); + + movptr(raddr, dst); + + // Check null. + testptr(raddr, raddr); + jcc(Assembler::zero, done); + + in_heap_check(raddr, done); + shenandoah_cset_check(raddr, tmp1, tmp2, done); + + // Fail. + pop(tmp2); + pop(tmp1); + pop(raddr); + popf(); + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("shenandoah_store_check: %s in file: %s line: %i", msg, file, line); + b = code_string(ss.as_string()); + } + stop(b); + + bind(done); + + pop(tmp2); + pop(tmp1); + pop(raddr); + popf(); + } + + void MacroAssembler::_shenandoah_store_check(Register dst, Register value, const char* msg, const char* file, int line) { + if (! UseShenandoahGC && ! ShenandoahStoreCheck) return; + if (dst == rsp) return; // Stack-based target + + Register raddr = r8; + Register rval = r9; + Register tmp1 = r10; + Register tmp2 = r11; + + // Push tmp regs and flags. + pushf(); + push(raddr); + push(rval); + push(tmp1); + push(tmp2); + + movptr(raddr, dst); + movptr(rval, value); + + Label done; + + // If not in-heap target, skip check. + in_heap_check(raddr, done); + + // Test that target oop is not in to-space. + shenandoah_cset_check(raddr, tmp1, tmp2, done); + + // Do value-check only when concurrent mark is in progress. + movptr(tmp1, (intptr_t) ShenandoahHeap::concurrent_mark_in_progress_addr()); + movbool(tmp1, Address(tmp1, 0)); + testbool(tmp1); + jcc(Assembler::zero, done); + + // Null-check value. + testptr(rval, rval); + jcc(Assembler::zero, done); + + // Test that value oop is not in to-space. + shenandoah_cset_check(rval, tmp1, tmp2, done); + + // Failure. + // Pop tmp regs and flags. + pop(tmp2); + pop(tmp1); + pop(rval); + pop(raddr); + popf(); + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("shenandoah_store_check: %s in file: %s line: %i", msg, file, line); + b = code_string(ss.as_string()); + } + stop(b); + + bind(done); + + // Pop tmp regs and flags. + pop(tmp2); + pop(tmp1); + pop(rval); + pop(raddr); + popf(); + } + + void MacroAssembler::_shenandoah_store_check(Address addr, Register value, const char* msg, const char* file, int line) { + _shenandoah_store_check(addr.base(), value, msg, file, line); + } + + void MacroAssembler::_shenandoah_lock_check(Register dst, const char* msg, const char* file, int line) { + #ifdef ASSERT + if (! UseShenandoahGC && ! ShenandoahStoreCheck) return; + + push(r8); + movptr(r8, Address(dst, BasicObjectLock::obj_offset_in_bytes())); + _shenandoah_store_addr_check(r8, msg, file, line); + pop(r8); + #endif + } RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) { intptr_t value = *delayed_value_addr;
< prev index next >