14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26
27 #include "code/aotCodeCache.hpp"
28 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
29 #include "gc/shenandoah/mode/shenandoahMode.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
31 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
32 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
33 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
34 #include "gc/shenandoah/shenandoahRuntime.hpp"
35 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
36 #include "interpreter/interpreter.hpp"
37 #include "runtime/javaThread.hpp"
38 #include "runtime/sharedRuntime.hpp"
39 #include "utilities/macros.hpp"
40 #ifdef COMPILER1
41 #include "c1/c1_LIRAssembler.hpp"
42 #include "c1/c1_MacroAssembler.hpp"
43 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
44 #endif
45 #ifdef COMPILER2
46 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
47 #endif
48
49 #define __ masm->
50
51 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
52 Register src, Register dst, Register count) {
53
54 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
55
56 if (is_reference_type(type)) {
57 if (ShenandoahCardBarrier) {
58 bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
59 bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
60 bool obj_int = (type == T_OBJECT) && UseCompressedOops;
61
62 // We need to save the original element count because the array copy stub
63 // will destroy the value and we need it for the card marking barrier.
64 if (!checkcast) {
65 if (!obj_int) {
66 // Save count for barrier
573 __ movptr(tmp, curr_ct_holder_addr);
574
575 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size
576 __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
577 __ shrptr(addr, CardTable::card_shift());
578 __ shrptr(end, CardTable::card_shift());
579 __ subptr(end, addr); // end --> cards count
580
581 __ addptr(addr, tmp);
582
583 __ BIND(L_loop);
584 __ movb(Address(addr, count, Address::times_1), 0);
585 __ decrement(count);
586 __ jccb(Assembler::greaterEqual, L_loop);
587
588 __ BIND(L_done);
589 }
590
591 #undef __
592
593 #ifdef COMPILER1
594
595 #define __ ce->masm()->
596
597 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
598 __ bind(*stub->entry());
599
600 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
601
602 Register obj = stub->obj()->as_register();
603
604 if (stub->do_load()) {
605 ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, /* wide = */ false);
606 }
607 __ cmpptr(obj, NULL_WORD);
608 __ jcc(Assembler::equal, *stub->continuation());
609
610 ce->store_parameter(obj, 0);
611 __ call(RuntimeAddress(bs->keepalive_barrier_stub()));
612 __ jmp(*stub->continuation());
761
762 __ lea(tmp1, addr);
763 __ shrptr(tmp1, CardTable::card_shift());
764 __ addptr(tmp1, Address(r15_thread, in_bytes(ShenandoahThreadLocalData::card_table_offset())));
765 Address card_address(tmp1, 0);
766
767 assert(CardTable::dirty_card_val() == 0, "Encoding assumption");
768 Label L_done;
769 if (UseCondCardMark) {
770 __ cmpb(card_address, 0);
771 __ jccb(Assembler::equal, L_done);
772 }
773 if (UseCompressedOops && CompressedOops::base() == nullptr) {
774 __ movb(card_address, r12);
775 } else {
776 __ movb(card_address, 0);
777 }
778 __ bind(L_done);
779 }
780
781 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
782 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
783
784 Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
785 __ cmpb(gc_state_fast, 0);
786 __ jcc(Assembler::notEqual, *entry());
787 __ bind(*continuation());
788 }
789
790 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
791 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
792 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
793
794 // On x86, there is a significant penalty with unaligned branch target, for example
795 // when the target instruction straggles the fetch line. It makes (performance) sense
796 // to spend some code size to align the target better.
797 __ align(16);
798 __ bind(*entry());
799
800 // If we need to load ourselves, do it here.
801 if (_do_load) {
802 if (_narrow) {
803 __ movl(_obj, _addr);
804 } else {
805 __ movq(_obj, _addr);
806 }
807 }
808
809 // If the object is null, there is no point in applying barriers.
814 bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
815 if (!_do_load || needs_both_barriers) {
816 preserve(_obj);
817 }
818
819 // Go for barriers. Barriers can return straight to continuation, as long
820 // as another barrier is not needed.
821 if (needs_both_barriers) {
822 keepalive(masm, nullptr);
823 lrb(masm);
824 } else if (_needs_keep_alive_barrier) {
825 keepalive(masm, continuation());
826 } else if (_needs_load_ref_barrier) {
827 lrb(masm);
828 } else {
829 ShouldNotReachHere();
830 }
831 }
832
833 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
834 Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING)));
835 Address index(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
836 Address buffer(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
837
838 Label L_through, L_pop_and_slow;
839
840 // If another barrier is enabled as well, do a runtime check for a specific barrier.
841 if (_needs_load_ref_barrier) {
842 assert(L_done == nullptr, "L_done is always null when _needs_load_ref_barrier is true");
843 __ cmpb(gc_state_fast, 0);
844 __ jcc(Assembler::equal, L_through);
845 }
846
847 // Need temp to work, allocate one now.
848 bool tmp_live;
849 Register tmp = select_temp_register(tmp_live);
850 if (tmp_live) {
851 __ push(tmp);
852 }
853
854 // Fast-path: put object into buffer.
855 // If buffer is already full, go slow.
856 __ movptr(tmp, index);
857 __ subptr(tmp, wordSize);
858 // VerifyOops adds code for decoded oop and needs long jump here
859 __ jcc(Assembler::below, L_pop_and_slow);
860 __ movptr(index, tmp);
861 __ addptr(tmp, buffer);
862
863 // Store the object in queue.
864 // If object is narrow, we need to decode it before inserting.
894 // Shuffle in the arguments. The end result should be:
895 // c_rarg0 <-- obj
896 if (c_rarg0 != _obj) {
897 __ mov(c_rarg0, _obj);
898 }
899
900 // Go to runtime and handle the rest there.
901 // Use rax as scratch, as it will be saved if live.
902 __ call(RuntimeAddress(keepalive_runtime_entry_addr()), rax);
903 }
904 if (L_done != nullptr) {
905 __ jmp(*L_done);
906 } else {
907 __ bind(L_through);
908 }
909 }
910
911 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
912 Label L_pop_and_slow, L_slow;
913
914 // If another barrier is enabled as well, do a runtime check for a specific barrier.
915 if (_needs_keep_alive_barrier) {
916 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
917 Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
918 __ cmpb(gc_state_fast, 0);
919 __ jcc(Assembler::equal, *continuation());
920 }
921
922 // If weak references are being processed, weak/phantom loads need to go slow,
923 // regardless of their cset status.
924 if (_needs_load_ref_weak_barrier) {
925 Address gc_state_fast(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));
926 __ cmpb(gc_state_fast, 0);
927 __ jccb(Assembler::notEqual, L_slow);
928 }
929
930 bool is_aot = AOTCodeCache::is_on_for_dump();
931
932 // Need temp to work, allocate one now.
933 bool tmp_live;
934 Register tmp = select_temp_register(tmp_live, /* skip_reg1 = */ is_aot ? rcx : noreg);
935 if (tmp_live) {
936 __ push(tmp);
937 }
938
939 // Compute the cset bitmap index
940 if (_narrow) {
941 __ decode_heap_oop_not_null(tmp, _obj);
942 } else {
943 __ movptr(tmp, _obj);
944 }
945
946 Address cset_addr_arg;
947 intptr_t cset_addr = reinterpret_cast<intptr_t>(ShenandoahHeap::in_cset_fast_test_addr());
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26
27 #include "code/aotCodeCache.hpp"
28 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
29 #include "gc/shenandoah/mode/shenandoahMode.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
31 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
32 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
33 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
34 #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
35 #include "gc/shenandoah/shenandoahRuntime.hpp"
36 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
37 #include "interpreter/interpreter.hpp"
38 #include "nativeInst_x86.hpp"
39 #include "runtime/javaThread.hpp"
40 #include "runtime/sharedRuntime.hpp"
41 #include "utilities/macros.hpp"
42 #ifdef COMPILER1
43 #include "c1/c1_LIRAssembler.hpp"
44 #include "c1/c1_MacroAssembler.hpp"
45 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
46 #endif
47 #ifdef COMPILER2
48 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
49 #include "opto/output.hpp"
50 #endif
51
52 #define __ masm->
53
54 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
55 Register src, Register dst, Register count) {
56
57 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
58
59 if (is_reference_type(type)) {
60 if (ShenandoahCardBarrier) {
61 bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
62 bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
63 bool obj_int = (type == T_OBJECT) && UseCompressedOops;
64
65 // We need to save the original element count because the array copy stub
66 // will destroy the value and we need it for the card marking barrier.
67 if (!checkcast) {
68 if (!obj_int) {
69 // Save count for barrier
576 __ movptr(tmp, curr_ct_holder_addr);
577
578 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size
579 __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
580 __ shrptr(addr, CardTable::card_shift());
581 __ shrptr(end, CardTable::card_shift());
582 __ subptr(end, addr); // end --> cards count
583
584 __ addptr(addr, tmp);
585
586 __ BIND(L_loop);
587 __ movb(Address(addr, count, Address::times_1), 0);
588 __ decrement(count);
589 __ jccb(Assembler::greaterEqual, L_loop);
590
591 __ BIND(L_done);
592 }
593
594 #undef __
595
596 address ShenandoahBarrierSetAssembler::parse_jump_address(address pc) {
597 NativeInstruction* ni = nativeInstruction_at(pc);
598 assert(ni->is_jump(), "Must be a jump");
599 NativeJump* jmp = nativeJump_at(pc);
600 return jmp->jump_destination();
601 }
602
603 void ShenandoahBarrierSetAssembler::insert_patchable_nop(address pc) {
604 *(pc + 0) = 0x0F;
605 *(pc + 1) = 0x1F;
606 *(pc + 2) = 0x44;
607 *(pc + 3) = 0x00;
608 *(pc + 4) = 0x00;
609 // No invalidation is needed: relies on reader-side cross-modify-fence.
610 }
611
612 bool ShenandoahBarrierSetAssembler::is_patchable_nop(address pc) {
613 if (*(pc + 0) != 0x0F) return false;
614 if (*(pc + 1) != 0x1F) return false;
615 if (*(pc + 2) != 0x44) return false;
616 if (*(pc + 3) != 0x00) return false;
617 if (*(pc + 4) != 0x00) return false;
618 return true;
619 }
620
621 void ShenandoahBarrierSetAssembler::insert_patchable_jump(address pc, address target_pc) {
622 int32_t disp = checked_cast<int32_t>((intptr_t)target_pc - ((intptr_t)pc + 5));
623
624 *(pc + 0) = 0xE9;
625 *(pc + 1) = (disp >> 0) & 0xFF;
626 *(pc + 2) = (disp >> 8) & 0xFF;
627 *(pc + 3) = (disp >> 16) & 0xFF;
628 *(pc + 4) = (disp >> 24) & 0xFF;
629 // No invalidation is needed: relies on reader-side cross-modify-fence.
630 }
631
632 bool ShenandoahBarrierSetAssembler::is_patchable_jump(address pc, address target_pc) {
633 int32_t disp = checked_cast<int32_t>((intptr_t)target_pc - ((intptr_t)pc + 5));
634
635 if (*(pc + 0) != 0xE9) return false;
636 if (*(pc + 1) != ((disp >> 0) & 0xFF)) return false;
637 if (*(pc + 2) != ((disp >> 8) & 0xFF)) return false;
638 if (*(pc + 3) != ((disp >> 16) & 0xFF)) return false;
639 if (*(pc + 4) != ((disp >> 24) & 0xFF)) return false;
640 return true;
641 }
642
643 #ifdef COMPILER1
644
645 #define __ ce->masm()->
646
647 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
648 __ bind(*stub->entry());
649
650 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
651
652 Register obj = stub->obj()->as_register();
653
654 if (stub->do_load()) {
655 ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, /* wide = */ false);
656 }
657 __ cmpptr(obj, NULL_WORD);
658 __ jcc(Assembler::equal, *stub->continuation());
659
660 ce->store_parameter(obj, 0);
661 __ call(RuntimeAddress(bs->keepalive_barrier_stub()));
662 __ jmp(*stub->continuation());
811
812 __ lea(tmp1, addr);
813 __ shrptr(tmp1, CardTable::card_shift());
814 __ addptr(tmp1, Address(r15_thread, in_bytes(ShenandoahThreadLocalData::card_table_offset())));
815 Address card_address(tmp1, 0);
816
817 assert(CardTable::dirty_card_val() == 0, "Encoding assumption");
818 Label L_done;
819 if (UseCondCardMark) {
820 __ cmpb(card_address, 0);
821 __ jccb(Assembler::equal, L_done);
822 }
823 if (UseCompressedOops && CompressedOops::base() == nullptr) {
824 __ movb(card_address, r12);
825 } else {
826 __ movb(card_address, 0);
827 }
828 __ bind(L_done);
829 }
830
831 void ShenandoahBarrierStubC2::patchable_jump(MacroAssembler& masm, const char gc_state, bool jump_when_state, Register tmp1, Register tmp2, Label* L_target) {
832 #ifdef ASSERT
833 Label L_fake_entry, L_good;
834 Address gc_state_addr(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
835
836 // Emit the secondary jump and use it to cross-check against the actual GC state.
837 // This also checks that all interesting GC state transitions are done non-racily
838 // from the perspective of the thread executing the nmethod.
839 __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
840 __ jmp(L_fake_entry, /* maybe_short = */ false);
841
842 // Currently hot-patched to NOP.
843 __ testb(gc_state_addr, gc_state);
844 __ jccb(jump_when_state ? Assembler::zero : Assembler::notZero, L_good);
845 __ hlt();
846
847 // Currently hot-patched to JUMP.
848 __ bind(L_fake_entry);
849 __ testb(gc_state_addr, gc_state);
850 __ jccb(jump_when_state ? Assembler::notZero : Assembler::zero, L_good);
851 __ hlt();
852
853 __ bind(L_good);
854 #endif
855
856 PhaseOutput* const output = Compile::current()->output();
857 if (!output->in_scratch_emit_size()) {
858 // Emit the unconditional branch in the first version of the method.
859 // Let the rest of runtime figure out how to manage it.
860 __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
861 __ jmp(*L_target, /* maybe_short = */ false);
862 } else {
863 // Avoid binding L_target in scratch emits.
864 // We know the patchable check is exactly 5 bytes long.
865 __ nop(5);
866 }
867 }
868
869 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp1, Register tmp2) {
870 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
871 patchable_jump_if_gc_state(masm, test_state, tmp1, tmp2, entry());
872 __ bind(*continuation());
873 }
874
875
876 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
877 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
878 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
879
880 // On x86, there is a significant penalty with unaligned branch target, for example
881 // when the target instruction straggles the fetch line. It makes (performance) sense
882 // to spend some code size to align the target better.
883 __ align(16);
884 __ bind(*entry());
885
886 // If we need to load ourselves, do it here.
887 if (_do_load) {
888 if (_narrow) {
889 __ movl(_obj, _addr);
890 } else {
891 __ movq(_obj, _addr);
892 }
893 }
894
895 // If the object is null, there is no point in applying barriers.
900 bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
901 if (!_do_load || needs_both_barriers) {
902 preserve(_obj);
903 }
904
905 // Go for barriers. Barriers can return straight to continuation, as long
906 // as another barrier is not needed.
907 if (needs_both_barriers) {
908 keepalive(masm, nullptr);
909 lrb(masm);
910 } else if (_needs_keep_alive_barrier) {
911 keepalive(masm, continuation());
912 } else if (_needs_load_ref_barrier) {
913 lrb(masm);
914 } else {
915 ShouldNotReachHere();
916 }
917 }
918
919 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
920 Address index(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
921 Address buffer(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
922
923 Label L_through, L_pop_and_slow;
924
925 // If another barrier is enabled as well, do a check for a specific barrier.
926 if (_needs_load_ref_barrier) {
927 assert(L_done == nullptr, "Should be");
928 char state_to_check = ShenandoahHeap::MARKING;
929 patchable_jump_if_not_gc_state(masm, state_to_check, noreg, noreg, &L_through);
930 }
931
932 // Need temp to work, allocate one now.
933 bool tmp_live;
934 Register tmp = select_temp_register(tmp_live);
935 if (tmp_live) {
936 __ push(tmp);
937 }
938
939 // Fast-path: put object into buffer.
940 // If buffer is already full, go slow.
941 __ movptr(tmp, index);
942 __ subptr(tmp, wordSize);
943 // VerifyOops adds code for decoded oop and needs long jump here
944 __ jcc(Assembler::below, L_pop_and_slow);
945 __ movptr(index, tmp);
946 __ addptr(tmp, buffer);
947
948 // Store the object in queue.
949 // If object is narrow, we need to decode it before inserting.
979 // Shuffle in the arguments. The end result should be:
980 // c_rarg0 <-- obj
981 if (c_rarg0 != _obj) {
982 __ mov(c_rarg0, _obj);
983 }
984
985 // Go to runtime and handle the rest there.
986 // Use rax as scratch, as it will be saved if live.
987 __ call(RuntimeAddress(keepalive_runtime_entry_addr()), rax);
988 }
989 if (L_done != nullptr) {
990 __ jmp(*L_done);
991 } else {
992 __ bind(L_through);
993 }
994 }
995
996 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
997 Label L_pop_and_slow, L_slow;
998
999 // If another barrier is enabled as well, do a check for a specific barrier.
1000 if (_needs_keep_alive_barrier) {
1001 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1002 patchable_jump_if_not_gc_state(masm, state_to_check, noreg, noreg, continuation());
1003 }
1004
1005 // If weak references are being processed, weak/phantom loads need to go slow,
1006 // regardless of their cset status.
1007 if (_needs_load_ref_weak_barrier) {
1008 char state_to_check = ShenandoahHeap::WEAK_ROOTS;
1009 patchable_jump_if_gc_state(masm, state_to_check, noreg, noreg, &L_slow);
1010 }
1011
1012 bool is_aot = AOTCodeCache::is_on_for_dump();
1013
1014 // Need temp to work, allocate one now.
1015 bool tmp_live;
1016 Register tmp = select_temp_register(tmp_live, /* skip_reg1 = */ is_aot ? rcx : noreg);
1017 if (tmp_live) {
1018 __ push(tmp);
1019 }
1020
1021 // Compute the cset bitmap index
1022 if (_narrow) {
1023 __ decode_heap_oop_not_null(tmp, _obj);
1024 } else {
1025 __ movptr(tmp, _obj);
1026 }
1027
1028 Address cset_addr_arg;
1029 intptr_t cset_addr = reinterpret_cast<intptr_t>(ShenandoahHeap::in_cset_fast_test_addr());
|