< prev index next >

src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp

Print this page




   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "precompiled.hpp"
  25 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
  26 #include "gc/shenandoah/shenandoahForwarding.hpp"
  27 #include "gc/shenandoah/shenandoahHeap.hpp"
  28 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  29 #include "gc/shenandoah/shenandoahHeuristics.hpp"
  30 #include "gc/shenandoah/shenandoahRuntime.hpp"
  31 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  32 #include "interpreter/interpreter.hpp"
  33 #include "interpreter/interp_masm.hpp"
  34 #include "runtime/sharedRuntime.hpp"
  35 #include "runtime/thread.hpp"
  36 #include "utilities/macros.hpp"
  37 #ifdef COMPILER1
  38 #include "c1/c1_LIRAssembler.hpp"
  39 #include "c1/c1_MacroAssembler.hpp"
  40 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
  41 #endif
  42 
  43 #define __ masm->
  44 
  45 address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL;
  46 


 296 #endif
 297     __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), 2);
 298   } else {
 299     __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread);
 300   }
 301 
 302   NOT_LP64( __ pop(thread); )
 303 
 304   // save the live input values
 305   if (pre_val != rax)
 306     __ pop(pre_val);
 307 
 308   if (obj != noreg && obj != rax)
 309     __ pop(obj);
 310 
 311   if(tosca_live) __ pop(rax);
 312 
 313   __ bind(done);
 314 }
 315 
 316 void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) {
 317   assert(ShenandoahCASBarrier, "should be enabled");
 318   Label is_null;
 319   __ testptr(dst, dst);
 320   __ jcc(Assembler::zero, is_null);
 321   resolve_forward_pointer_not_null(masm, dst);
 322   __ bind(is_null);
 323 }
 324 
 325 void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) {
 326   assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled");
 327   __ movptr(dst, Address(dst, ShenandoahForwarding::byte_offset()));
















 328 }
 329 
 330 
 331 void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst) {
 332   assert(ShenandoahLoadRefBarrier, "Should be enabled");
 333 #ifdef _LP64
 334   Label done;
 335 
 336   Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 337   __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL);
 338   __ jccb(Assembler::zero, done);
 339 
 340   // Heap is unstable, need to perform the resolve even if LRB is inactive
 341   resolve_forward_pointer_not_null(masm, dst);
 342 
 343   __ testb(gc_state, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL);
 344   __ jccb(Assembler::zero, done);
 345 
 346    if (dst != rax) {
 347      __ xchgptr(dst, rax); // Move obj into rax and save rax into obj.
 348    }
 349 
 350    __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb())));
 351 
 352    if (dst != rax) {
 353      __ xchgptr(rax, dst); // Swap back obj with rax.
 354    }
 355 
 356   __ bind(done);
 357 #else
 358   Unimplemented();
 359 #endif
 360 }
 361 
 362 void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) {
 363   if (ShenandoahStoreValEnqueueBarrier) {


 458       shenandoah_write_barrier_pre(masm /*masm*/,
 459                                    tmp1 /* obj */,
 460                                    tmp2 /* pre_val */,
 461                                    rthread /* thread */,
 462                                    tmp3  /* tmp */,
 463                                    val != noreg /* tosca_live */,
 464                                    false /* expand_call */);
 465     }
 466     if (val == noreg) {
 467       BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
 468     } else {
 469       storeval_barrier(masm, val, tmp3);
 470       BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
 471     }
 472     NOT_LP64(imasm->restore_bcp());
 473   } else {
 474     BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
 475   }
 476 }
 477 
 478 void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm,
 479                                                   Register thread, Register obj,
 480                                                   Register var_size_in_bytes,
 481                                                   int con_size_in_bytes,
 482                                                   Register t1, Register t2,
 483                                                   Label& slow_case) {
 484   assert_different_registers(obj, t1, t2);
 485   assert_different_registers(obj, var_size_in_bytes, t1);
 486   Register end = t2;
 487   if (!thread->is_valid()) {
 488 #ifdef _LP64
 489     thread = r15_thread;
 490 #else
 491     assert(t1->is_valid(), "need temp reg");
 492     thread = t1;
 493     __ get_thread(thread);
 494 #endif
 495   }
 496 
 497   __ verify_tlab();
 498 
 499   __ movptr(obj, Address(thread, JavaThread::tlab_top_offset()));
 500   if (var_size_in_bytes == noreg) {
 501     __ lea(end, Address(obj, con_size_in_bytes + ShenandoahForwarding::byte_size()));
 502   } else {
 503     __ addptr(var_size_in_bytes, ShenandoahForwarding::byte_size());
 504     __ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
 505   }
 506   __ cmpptr(end, Address(thread, JavaThread::tlab_end_offset()));
 507   __ jcc(Assembler::above, slow_case);
 508 
 509   // update the tlab top pointer
 510   __ movptr(Address(thread, JavaThread::tlab_top_offset()), end);
 511 
 512   // Initialize brooks pointer
 513 #ifdef _LP64
 514   __ incrementq(obj, ShenandoahForwarding::byte_size());
 515 #else
 516   __ incrementl(obj, ShenandoahForwarding::byte_size());
 517 #endif
 518   __ movptr(Address(obj, ShenandoahForwarding::byte_offset()), obj);
 519 
 520   // recover var_size_in_bytes if necessary
 521   if (var_size_in_bytes == end) {
 522     __ subptr(var_size_in_bytes, obj);
 523   }
 524   __ verify_tlab();
 525 }
 526 
 527 // Special Shenandoah CAS implementation that handles false negatives
 528 // due to concurrent evacuation.
 529 #ifndef _LP64
 530 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,
 531                                                 Register res, Address addr, Register oldval, Register newval,
 532                                                 bool exchange, Register tmp1, Register tmp2) {
 533   // Shenandoah has no 32-bit version for this.
 534   Unimplemented();
 535 }
 536 #else
 537 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,
 538                                                 Register res, Address addr, Register oldval, Register newval,
 539                                                 bool exchange, Register tmp1, Register tmp2) {
 540   assert(ShenandoahCASBarrier, "Should only be used when CAS barrier is enabled");
 541   assert(oldval == rax, "must be in rax for implicit use in cmpxchg");
 542 
 543   Label retry, done;
 544 
 545   // Remember oldval for retry logic below
 546   if (UseCompressedOops) {
 547     __ movl(tmp1, oldval);
 548   } else {
 549     __ movptr(tmp1, oldval);
 550   }
 551 
 552   // Step 1. Try to CAS with given arguments. If successful, then we are done,
 553   // and can safely return.
 554   if (os::is_MP()) __ lock();
 555   if (UseCompressedOops) {
 556     __ cmpxchgl(newval, addr);
 557   } else {
 558     __ cmpxchgptr(newval, addr);
 559   }
 560   __ jcc(Assembler::equal, done, true);
 561 
 562   // Step 2. CAS had failed. This may be a false negative.
 563   //
 564   // The trouble comes when we compare the to-space pointer with the from-space
 565   // pointer to the same object. To resolve this, it will suffice to resolve both
 566   // oldval and the value from memory -- this will give both to-space pointers.
 567   // If they mismatch, then it was a legitimate failure.
 568   //
 569   if (UseCompressedOops) {
 570     __ decode_heap_oop(tmp1);
 571   }
 572   resolve_forward_pointer(masm, tmp1);
 573 
 574   if (UseCompressedOops) {
 575     __ movl(tmp2, oldval);
 576     __ decode_heap_oop(tmp2);
 577   } else {
 578     __ movptr(tmp2, oldval);
 579   }
 580   resolve_forward_pointer(masm, tmp2);
 581 
 582   __ cmpptr(tmp1, tmp2);
 583   __ jcc(Assembler::notEqual, done, true);
 584 
 585   // Step 3. Try to CAS again with resolved to-space pointers.
 586   //
 587   // Corner case: it may happen that somebody stored the from-space pointer
 588   // to memory while we were preparing for retry. Therefore, we can fail again
 589   // on retry, and so need to do this in loop, always resolving the failure
 590   // witness.
 591   __ bind(retry);
 592   if (os::is_MP()) __ lock();
 593   if (UseCompressedOops) {
 594     __ cmpxchgl(newval, addr);
 595   } else {
 596     __ cmpxchgptr(newval, addr);
 597   }
 598   __ jcc(Assembler::equal, done, true);
 599 
 600   if (UseCompressedOops) {
 601     __ movl(tmp2, oldval);
 602     __ decode_heap_oop(tmp2);
 603   } else {
 604     __ movptr(tmp2, oldval);
 605   }
 606   resolve_forward_pointer(masm, tmp2);
 607 
 608   __ cmpptr(tmp1, tmp2);
 609   __ jcc(Assembler::equal, retry, true);
 610 
 611   // Step 4. If we need a boolean result out of CAS, check the flag again,
 612   // and promote the result. Note that we handle the flag from both the CAS
 613   // itself and from the retry loop.
 614   __ bind(done);
 615   if (!exchange) {
 616     assert(res != NULL, "need result register");
 617     __ setb(Assembler::equal, res);
 618     __ movzbl(res, res);
 619   }
 620 }
 621 #endif // LP64
 622 
 623 void ShenandoahBarrierSetAssembler::save_vector_registers(MacroAssembler* masm) {
 624   int num_xmm_regs = LP64_ONLY(16) NOT_LP64(8);
 625   if (UseAVX > 2) {
 626     num_xmm_regs = LP64_ONLY(32) NOT_LP64(8);


 834   __ epilogue();
 835 }
 836 
 837 #undef __
 838 
 839 #endif // COMPILER1
 840 
 841 address ShenandoahBarrierSetAssembler::shenandoah_lrb() {
 842   assert(_shenandoah_lrb != NULL, "need load reference barrier stub");
 843   return _shenandoah_lrb;
 844 }
 845 
 846 #define __ cgen->assembler()->
 847 
 848 address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) {
 849   __ align(CodeEntryAlignment);
 850   StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb");
 851   address start = __ pc();
 852 
 853 #ifdef _LP64
 854   Label not_done;
 855 
 856   // We use RDI, which also serves as argument register for slow call.
 857   // RAX always holds the src object ptr, except after the slow call and
 858   // the cmpxchg, then it holds the result.
 859   // R8 and RCX are used as temporary registers.
 860   __ push(rdi);
 861   __ push(r8);
 862 
 863   // Check for object beeing in the collection set.
 864   // TODO: Can we use only 1 register here?
 865   // The source object arrives here in rax.
 866   // live: rax
 867   // live: rdi
 868   __ mov(rdi, rax);
 869   __ shrptr(rdi, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 870   // live: r8
 871   __ movptr(r8, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
 872   __ movbool(r8, Address(r8, rdi, Address::times_1));
 873   // unlive: rdi
 874   __ testbool(r8);
 875   // unlive: r8
 876   __ jccb(Assembler::notZero, not_done);


















 877 
 878   __ pop(r8);
 879   __ pop(rdi);
 880   __ ret(0);
 881 
 882   __ bind(not_done);
 883 
 884   __ push(rcx);
 885   __ push(rdx);
 886   __ push(rdi);
 887   __ push(rsi);
 888   __ push(r8);
 889   __ push(r9);
 890   __ push(r10);
 891   __ push(r11);
 892   __ push(r12);
 893   __ push(r13);
 894   __ push(r14);
 895   __ push(r15);
 896   save_vector_registers(cgen->assembler());
 897   __ movptr(rdi, rax);
 898   __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), rdi);
 899   restore_vector_registers(cgen->assembler());
 900   __ pop(r15);
 901   __ pop(r14);
 902   __ pop(r13);




   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "precompiled.hpp"
  25 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"

  26 #include "gc/shenandoah/shenandoahHeap.hpp"
  27 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  28 #include "gc/shenandoah/shenandoahHeuristics.hpp"
  29 #include "gc/shenandoah/shenandoahRuntime.hpp"
  30 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  31 #include "interpreter/interpreter.hpp"
  32 #include "interpreter/interp_masm.hpp"
  33 #include "runtime/sharedRuntime.hpp"
  34 #include "runtime/thread.hpp"
  35 #include "utilities/macros.hpp"
  36 #ifdef COMPILER1
  37 #include "c1/c1_LIRAssembler.hpp"
  38 #include "c1/c1_MacroAssembler.hpp"
  39 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
  40 #endif
  41 
  42 #define __ masm->
  43 
  44 address ShenandoahBarrierSetAssembler::_shenandoah_lrb = NULL;
  45 


 295 #endif
 296     __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), 2);
 297   } else {
 298     __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread);
 299   }
 300 
 301   NOT_LP64( __ pop(thread); )
 302 
 303   // save the live input values
 304   if (pre_val != rax)
 305     __ pop(pre_val);
 306 
 307   if (obj != noreg && obj != rax)
 308     __ pop(obj);
 309 
 310   if(tosca_live) __ pop(rax);
 311 
 312   __ bind(done);
 313 }
 314 
 315 void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) {
 316   assert(ShenandoahCASBarrier, "should be enabled");
 317   Label is_null;
 318   __ testptr(dst, dst);
 319   __ jcc(Assembler::zero, is_null);
 320   resolve_forward_pointer_not_null(masm, dst, tmp);
 321   __ bind(is_null);
 322 }
 323 
 324 void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) {
 325   assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled");
 326   // The below loads the mark word, checks if the lowest two bits are
 327   // set, and if so, clear the lowest two bits and copy the result
 328   // to dst. Otherwise it leaves dst alone.
 329   // Implementing this is surprisingly awkward. I do it here by:
 330   // - Inverting the mark word
 331   // - Test lowest two bits == 0
 332   // - If so, set the lowest two bits
 333   // - Invert the result back, and copy to dst
 334   Label done;
 335   __ movptr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));
 336   __ notptr(tmp);
 337   __ testb(tmp, markOopDesc::marked_value);
 338   __ jccb(Assembler::notZero, done);
 339   __ orptr(tmp, markOopDesc::marked_value);
 340   __ notptr(tmp);
 341   __ mov(dst, tmp);
 342   __ bind(done);
 343 }
 344 
 345 
 346 void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst) {
 347   assert(ShenandoahLoadRefBarrier, "Should be enabled");
 348 #ifdef _LP64
 349   Label done;
 350 
 351   Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 352   __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);






 353   __ jccb(Assembler::zero, done);
 354 
 355    if (dst != rax) {
 356      __ xchgptr(dst, rax); // Move obj into rax and save rax into obj.
 357    }
 358 
 359    __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahBarrierSetAssembler::shenandoah_lrb())));
 360 
 361    if (dst != rax) {
 362      __ xchgptr(rax, dst); // Swap back obj with rax.
 363    }
 364 
 365   __ bind(done);
 366 #else
 367   Unimplemented();
 368 #endif
 369 }
 370 
 371 void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) {
 372   if (ShenandoahStoreValEnqueueBarrier) {


 467       shenandoah_write_barrier_pre(masm /*masm*/,
 468                                    tmp1 /* obj */,
 469                                    tmp2 /* pre_val */,
 470                                    rthread /* thread */,
 471                                    tmp3  /* tmp */,
 472                                    val != noreg /* tosca_live */,
 473                                    false /* expand_call */);
 474     }
 475     if (val == noreg) {
 476       BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
 477     } else {
 478       storeval_barrier(masm, val, tmp3);
 479       BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
 480     }
 481     NOT_LP64(imasm->restore_bcp());
 482   } else {
 483     BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
 484   }
 485 }
 486 

















































 487 // Special Shenandoah CAS implementation that handles false negatives
 488 // due to concurrent evacuation.
 489 #ifndef _LP64
 490 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,
 491                                                 Register res, Address addr, Register oldval, Register newval,
 492                                                 bool exchange, Register tmp1, Register tmp2) {
 493   // Shenandoah has no 32-bit version for this.
 494   Unimplemented();
 495 }
 496 #else
 497 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,
 498                                                 Register res, Address addr, Register oldval, Register newval,
 499                                                 bool exchange, Register tmp1, Register tmp2, Register tmp3) {
 500   assert(ShenandoahCASBarrier, "Should only be used when CAS barrier is enabled");
 501   assert(oldval == rax, "must be in rax for implicit use in cmpxchg");
 502 
 503   Label retry, done;
 504 
 505   // Remember oldval for retry logic below
 506   if (UseCompressedOops) {
 507     __ movl(tmp1, oldval);
 508   } else {
 509     __ movptr(tmp1, oldval);
 510   }
 511 
 512   // Step 1. Try to CAS with given arguments. If successful, then we are done,
 513   // and can safely return.
 514   if (os::is_MP()) __ lock();
 515   if (UseCompressedOops) {
 516     __ cmpxchgl(newval, addr);
 517   } else {
 518     __ cmpxchgptr(newval, addr);
 519   }
 520   __ jcc(Assembler::equal, done, true);
 521 
 522   // Step 2. CAS had failed. This may be a false negative.
 523   //
 524   // The trouble comes when we compare the to-space pointer with the from-space
 525   // pointer to the same object. To resolve this, it will suffice to resolve both
 526   // oldval and the value from memory -- this will give both to-space pointers.
 527   // If they mismatch, then it was a legitimate failure.
 528   //
 529   if (UseCompressedOops) {
 530     __ decode_heap_oop(tmp1);
 531   }
 532   resolve_forward_pointer(masm, tmp1, tmp3);
 533 
 534   if (UseCompressedOops) {
 535     __ movl(tmp2, oldval);
 536     __ decode_heap_oop(tmp2);
 537   } else {
 538     __ movptr(tmp2, oldval);
 539   }
 540   resolve_forward_pointer(masm, tmp2, tmp3);
 541 
 542   __ cmpptr(tmp1, tmp2);
 543   __ jcc(Assembler::notEqual, done, true);
 544 
 545   // Step 3. Try to CAS again with resolved to-space pointers.
 546   //
 547   // Corner case: it may happen that somebody stored the from-space pointer
 548   // to memory while we were preparing for retry. Therefore, we can fail again
 549   // on retry, and so need to do this in loop, always resolving the failure
 550   // witness.
 551   __ bind(retry);
 552   if (os::is_MP()) __ lock();
 553   if (UseCompressedOops) {
 554     __ cmpxchgl(newval, addr);
 555   } else {
 556     __ cmpxchgptr(newval, addr);
 557   }
 558   __ jcc(Assembler::equal, done, true);
 559 
 560   if (UseCompressedOops) {
 561     __ movl(tmp2, oldval);
 562     __ decode_heap_oop(tmp2);
 563   } else {
 564     __ movptr(tmp2, oldval);
 565   }
 566   resolve_forward_pointer(masm, tmp2, tmp3);
 567 
 568   __ cmpptr(tmp1, tmp2);
 569   __ jcc(Assembler::equal, retry, true);
 570 
 571   // Step 4. If we need a boolean result out of CAS, check the flag again,
 572   // and promote the result. Note that we handle the flag from both the CAS
 573   // itself and from the retry loop.
 574   __ bind(done);
 575   if (!exchange) {
 576     assert(res != NULL, "need result register");
 577     __ setb(Assembler::equal, res);
 578     __ movzbl(res, res);
 579   }
 580 }
 581 #endif // LP64
 582 
 583 void ShenandoahBarrierSetAssembler::save_vector_registers(MacroAssembler* masm) {
 584   int num_xmm_regs = LP64_ONLY(16) NOT_LP64(8);
 585   if (UseAVX > 2) {
 586     num_xmm_regs = LP64_ONLY(32) NOT_LP64(8);


 794   __ epilogue();
 795 }
 796 
 797 #undef __
 798 
 799 #endif // COMPILER1
 800 
 801 address ShenandoahBarrierSetAssembler::shenandoah_lrb() {
 802   assert(_shenandoah_lrb != NULL, "need load reference barrier stub");
 803   return _shenandoah_lrb;
 804 }
 805 
 806 #define __ cgen->assembler()->
 807 
 808 address ShenandoahBarrierSetAssembler::generate_shenandoah_lrb(StubCodeGenerator* cgen) {
 809   __ align(CodeEntryAlignment);
 810   StubCodeMark mark(cgen, "StubRoutines", "shenandoah_lrb");
 811   address start = __ pc();
 812 
 813 #ifdef _LP64
 814   Label resolve_oop, slow_path;
 815 
 816   // We use RDI, which also serves as argument register for slow call.
 817   // RAX always holds the src object ptr, except after the slow call and
 818   // the cmpxchg, then it holds the result.
 819   // R8 and RCX are used as temporary registers.
 820   __ push(rdi);
 821   __ push(r8);
 822 
 823   // Check for object beeing in the collection set.
 824   // TODO: Can we use only 1 register here?
 825   // The source object arrives here in rax.
 826   // live: rax
 827   // live: rdi
 828   __ mov(rdi, rax);
 829   __ shrptr(rdi, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 830   // live: r8
 831   __ movptr(r8, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
 832   __ movbool(r8, Address(r8, rdi, Address::times_1));
 833   // unlive: rdi
 834   __ testbool(r8);
 835   // unlive: r8
 836   __ jccb(Assembler::notZero, resolve_oop);
 837 
 838   __ pop(r8);
 839   __ pop(rdi);
 840   __ ret(0);
 841 
 842   __ bind(resolve_oop);
 843 
 844   __ movptr(r8, Address(rax, oopDesc::mark_offset_in_bytes()));
 845   // Test if both lowest bits are set. We trick it by negating the bits
 846   // then test for both bits clear.
 847   __ notptr(r8);
 848   __ testb(r8, markOopDesc::marked_value);
 849   __ jccb(Assembler::notZero, slow_path);
 850   // Clear both lower bits. It's still inverted, so set them, and then invert back.
 851   __ orptr(r8, markOopDesc::marked_value);
 852   __ notptr(r8);
 853   // At this point, r8 contains the decoded forwarding pointer.
 854   __ mov(rax, r8);
 855 
 856   __ pop(r8);
 857   __ pop(rdi);
 858   __ ret(0);
 859 
 860   __ bind(slow_path);
 861 
 862   __ push(rcx);
 863   __ push(rdx);
 864   __ push(rdi);
 865   __ push(rsi);
 866   __ push(r8);
 867   __ push(r9);
 868   __ push(r10);
 869   __ push(r11);
 870   __ push(r12);
 871   __ push(r13);
 872   __ push(r14);
 873   __ push(r15);
 874   save_vector_registers(cgen->assembler());
 875   __ movptr(rdi, rax);
 876   __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), rdi);
 877   restore_vector_registers(cgen->assembler());
 878   __ pop(r15);
 879   __ pop(r14);
 880   __ pop(r13);


< prev index next >