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);
|