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 }
610
611 bool ShenandoahBarrierSetAssembler::is_patchable_nop(address pc) {
612 if (*(pc + 0) != 0x0F) return false;
613 if (*(pc + 1) != 0x1F) return false;
614 if (*(pc + 2) != 0x44) return false;
615 if (*(pc + 3) != 0x00) return false;
616 if (*(pc + 4) != 0x00) return false;
617 return true;
618 }
619
620 void ShenandoahBarrierSetAssembler::insert_patchable_jump(address pc, address target_pc) {
621 int32_t disp = checked_cast<int32_t>((intptr_t)target_pc - ((intptr_t)pc + 5));
622
623 *(pc + 0) = 0xE9;
624 *(pc + 1) = (disp >> 0) & 0xFF;
625 *(pc + 2) = (disp >> 8) & 0xFF;
626 *(pc + 3) = (disp >> 16) & 0xFF;
627 *(pc + 4) = (disp >> 24) & 0xFF;
628 }
629
630 bool ShenandoahBarrierSetAssembler::is_patchable_jump(address pc, address target_pc) {
631 int32_t disp = checked_cast<int32_t>((intptr_t)target_pc - ((intptr_t)pc + 5));
632
633 if (*(pc + 0) != 0xE9) return false;
634 if (*(pc + 1) != ((disp >> 0) & 0xFF)) return false;
635 if (*(pc + 2) != ((disp >> 8) & 0xFF)) return false;
636 if (*(pc + 3) != ((disp >> 16) & 0xFF)) return false;
637 if (*(pc + 4) != ((disp >> 24) & 0xFF)) return false;
638 return true;
639 }
640
641 #ifdef COMPILER1
642
643 #define __ ce->masm()->
644
645 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
646 __ bind(*stub->entry());
647
648 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
649
650 Register obj = stub->obj()->as_register();
651
652 if (stub->do_load()) {
653 ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, /* wide = */ false);
654 }
655 __ cmpptr(obj, NULL_WORD);
656 __ jcc(Assembler::equal, *stub->continuation());
657
658 ce->store_parameter(obj, 0);
659 __ call(RuntimeAddress(bs->keepalive_barrier_stub()));
660 __ jmp(*stub->continuation());
809
810 __ lea(tmp1, addr);
811 __ shrptr(tmp1, CardTable::card_shift());
812 __ addptr(tmp1, Address(r15_thread, in_bytes(ShenandoahThreadLocalData::card_table_offset())));
813 Address card_address(tmp1, 0);
814
815 assert(CardTable::dirty_card_val() == 0, "Encoding assumption");
816 Label L_done;
817 if (UseCondCardMark) {
818 __ cmpb(card_address, 0);
819 __ jccb(Assembler::equal, L_done);
820 }
821 if (UseCompressedOops && CompressedOops::base() == nullptr) {
822 __ movb(card_address, r12);
823 } else {
824 __ movb(card_address, 0);
825 }
826 __ bind(L_done);
827 }
828
829 void ShenandoahBarrierStubC2::patchable_jump(MacroAssembler& masm, const char gc_state, bool jump_when_state, Register tmp1, Register tmp2, Label* L_target) {
830 #ifdef ASSERT
831 Label L_fake_entry, L_good;
832 Address gc_state_addr(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
833
834 // Emit the secondary jump and use it to cross-check against the actual GC state.
835 // This also checks that all interesting GC state transitions are done non-racily
836 // from the perspective of the thread executing the nmethod.
837 __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
838 __ jmp(L_fake_entry, /* maybe_short = */ false);
839
840 // Currently hot-patched to NOP.
841 __ testb(gc_state_addr, gc_state);
842 __ jccb(jump_when_state ? Assembler::zero : Assembler::notZero, L_good);
843 __ hlt();
844
845 // Currently hot-patched to JUMP.
846 __ bind(L_fake_entry);
847 __ testb(gc_state_addr, gc_state);
848 __ jccb(jump_when_state ? Assembler::notZero : Assembler::zero, L_good);
849 __ hlt();
850
851 __ bind(L_good);
852 #endif
853
854 PhaseOutput* const output = Compile::current()->output();
855 if (!output->in_scratch_emit_size()) {
856 // Emit the unconditional branch in the first version of the method.
857 // Let the rest of runtime figure out how to manage it.
858 __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
859 __ jmp(*L_target, /* maybe_short = */ false);
860 } else {
861 // Avoid binding L_target in scratch emits.
862 // We know the patchable check is exactly 5 bytes long.
863 __ nop(5);
864 }
865 }
866
867 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp1, Register tmp2) {
868 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
869 patchable_jump_if_gc_state(masm, test_state, tmp1, tmp2, entry());
870 __ bind(*continuation());
871 }
872
873
874 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
875 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
876 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
877
878 // On x86, there is a significant penalty with unaligned branch target, for example
879 // when the target instruction straggles the fetch line. It makes (performance) sense
880 // to spend some code size to align the target better.
881 __ align(16);
882 __ bind(*entry());
883
884 // If we need to load ourselves, do it here.
885 if (_do_load) {
886 if (_narrow) {
887 __ movl(_obj, _addr);
888 } else {
889 __ movq(_obj, _addr);
890 }
891 }
892
893 // If the object is null, there is no point in applying barriers.
898 bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
899 if (!_do_load || needs_both_barriers) {
900 preserve(_obj);
901 }
902
903 // Go for barriers. Barriers can return straight to continuation, as long
904 // as another barrier is not needed.
905 if (needs_both_barriers) {
906 keepalive(masm, nullptr);
907 lrb(masm);
908 } else if (_needs_keep_alive_barrier) {
909 keepalive(masm, continuation());
910 } else if (_needs_load_ref_barrier) {
911 lrb(masm);
912 } else {
913 ShouldNotReachHere();
914 }
915 }
916
917 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
918 Address index(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
919 Address buffer(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
920
921 Label L_through, L_pop_and_slow;
922
923 // If another barrier is enabled as well, do a check for a specific barrier.
924 if (_needs_load_ref_barrier) {
925 assert(L_done == nullptr, "Should be");
926 char state_to_check = ShenandoahHeap::MARKING;
927 patchable_jump_if_not_gc_state(masm, state_to_check, noreg, noreg, &L_through);
928 }
929
930 // Need temp to work, allocate one now.
931 bool tmp_live;
932 Register tmp = select_temp_register(tmp_live);
933 if (tmp_live) {
934 __ push(tmp);
935 }
936
937 // Fast-path: put object into buffer.
938 // If buffer is already full, go slow.
939 __ movptr(tmp, index);
940 __ subptr(tmp, wordSize);
941 // VerifyOops adds code for decoded oop and needs long jump here
942 __ jcc(Assembler::below, L_pop_and_slow);
943 __ movptr(index, tmp);
944 __ addptr(tmp, buffer);
945
946 // Store the object in queue.
947 // If object is narrow, we need to decode it before inserting.
977 // Shuffle in the arguments. The end result should be:
978 // c_rarg0 <-- obj
979 if (c_rarg0 != _obj) {
980 __ mov(c_rarg0, _obj);
981 }
982
983 // Go to runtime and handle the rest there.
984 // Use rax as scratch, as it will be saved if live.
985 __ call(RuntimeAddress(keepalive_runtime_entry_addr()), rax);
986 }
987 if (L_done != nullptr) {
988 __ jmp(*L_done);
989 } else {
990 __ bind(L_through);
991 }
992 }
993
994 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
995 Label L_pop_and_slow, L_slow;
996
997 // If another barrier is enabled as well, do a check for a specific barrier.
998 if (_needs_keep_alive_barrier) {
999 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1000 patchable_jump_if_not_gc_state(masm, state_to_check, noreg, noreg, continuation());
1001 }
1002
1003 // If weak references are being processed, weak/phantom loads need to go slow,
1004 // regardless of their cset status.
1005 if (_needs_load_ref_weak_barrier) {
1006 char state_to_check = ShenandoahHeap::WEAK_ROOTS;
1007 patchable_jump_if_gc_state(masm, state_to_check, noreg, noreg, &L_slow);
1008 }
1009
1010 bool is_aot = AOTCodeCache::is_on_for_dump();
1011
1012 // Need temp to work, allocate one now.
1013 bool tmp_live;
1014 Register tmp = select_temp_register(tmp_live, /* skip_reg1 = */ is_aot ? rcx : noreg);
1015 if (tmp_live) {
1016 __ push(tmp);
1017 }
1018
1019 // Compute the cset bitmap index
1020 if (_narrow) {
1021 __ decode_heap_oop_not_null(tmp, _obj);
1022 } else {
1023 __ movptr(tmp, _obj);
1024 }
1025
1026 Address cset_addr_arg;
1027 intptr_t cset_addr = reinterpret_cast<intptr_t>(ShenandoahHeap::in_cset_fast_test_addr());
|