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 "asm/macroAssembler.inline.hpp"
28 #include "gc/shared/gc_globals.hpp"
29 #include "gc/shared/gcArguments.hpp"
30 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
31 #include "gc/shenandoah/mode/shenandoahMode.hpp"
32 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
33 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
34 #include "gc/shenandoah/shenandoahHeap.hpp"
35 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
36 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
37 #include "gc/shenandoah/shenandoahRuntime.hpp"
38 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
39 #include "interpreter/interpreter.hpp"
40 #include "macroAssembler_ppc.hpp"
41 #include "runtime/javaThread.hpp"
42 #include "runtime/sharedRuntime.hpp"
43 #include "utilities/globalDefinitions.hpp"
44 #include "vm_version_ppc.hpp"
45 #ifdef COMPILER1
46 #include "c1/c1_LIRAssembler.hpp"
47 #include "c1/c1_MacroAssembler.hpp"
48 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
49 #endif
50 #ifdef COMPILER2
51 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
52 #endif
53
54 #define __ masm->
55
56 void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler *masm,
57 Register base, RegisterOrConstant ind_or_offs,
58 Register tmp1, Register tmp2, Register tmp3,
59 MacroAssembler::PreservationLevel preservation_level,
60 int extra_stack_space) {
61 if (ShenandoahSATBBarrier) {
62 __ block_comment("satb_barrier (shenandoahgc) {");
63 satb_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level, extra_stack_space);
64 __ block_comment("} satb_barrier (shenandoahgc)");
65 }
66 }
67
68 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators,
69 Register base, RegisterOrConstant ind_or_offs,
70 Register dst,
71 Register tmp1, Register tmp2,
696 // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.)
697 __ srdi(addr, addr, CardTable::card_shift());
698 __ srdi(count, count, CardTable::card_shift());
699 __ subf(count, addr, count);
700 __ ld(R0, in_bytes(ShenandoahThreadLocalData::card_table_offset()), R16_thread);
701 __ add(addr, addr, R0);
702 __ addi(count, count, 1);
703 __ li(R0, 0);
704 __ mtctr(count);
705
706 // Byte store loop
707 __ bind(L_store_loop);
708 __ stb(R0, 0, addr);
709 __ addi(addr, addr, 1);
710 __ bdnz(L_store_loop);
711 __ bind(L_skip_loop);
712 }
713
714 #undef __
715
716 #ifdef COMPILER1
717
718 #define __ ce->masm()->
719
720 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
721 __ block_comment("keepalive_barrier_stub (shenandoahgc) {");
722 __ bind(*stub->entry());
723
724 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1();
725
726 Register obj = stub->obj()->as_register();
727
728 // If 'do_load()' returns false, the to-be-stored value is already available in 'obj'
729 if (stub->do_load()) {
730 ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, false);
731 }
732
733 // Fast path: reference is null.
734 __ cmpdi(CR0, obj, 0);
735 __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CR0, Assembler::equal), *stub->continuation());
932 #define __ masm.
933
934 void ShenandoahBarrierStubC2::cardtable(MacroAssembler& masm, Address address, Register tmp1, Register tmp2) {
935 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
936 assert_different_registers(tmp1, tmp2, address.index(), address.base());
937
938 __ ld(tmp1, in_bytes(ShenandoahThreadLocalData::card_table_offset()), R16_thread);
939 if (address.index() == noreg) {
940 __ add_const_optimized(tmp2, address.base(), address.disp(), R0);
941 } else {
942 __ add(tmp2, address.index(), address.base());
943 if (address.disp() != 0) {
944 __ addi(tmp2, tmp2, address.disp());
945 }
946 }
947 __ srdi(tmp2, tmp2, CardTable::card_shift());
948 __ li(R0, CardTable::dirty_card_val());
949 __ stbx(R0, tmp2, tmp1);
950 }
951
952 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
953 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
954
955 __ lbz(tmp, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)), R16_thread);
956 __ cmpdi(CR0, tmp, 0);
957 // Branch to entry if not equal
958 __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CR0, Assembler::equal), *entry());
959 // This is were the slowpath stub will return to
960 __ bind(*continuation());
961 }
962
963 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
964 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
965 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
966
967 __ bind(*entry());
968
969 // If we need to load ourselves, do it here.
970 if (_do_load) {
971 if (_narrow) {
972 __ lwz(_obj, _addr.disp(), _addr.base());
973 } else {
974 __ ld(_obj, _addr.disp(), _addr.base());
975 }
976 }
977
978 // If the object is null, there is no point in applying barriers.
979 maybe_far_jump_if_zero(masm, _obj);
989 // as another barrier is not needed and we can reach the fastpath.
990 if (needs_both_barriers) {
991 keepalive(masm, nullptr);
992 lrb(masm);
993 } else if (_needs_keep_alive_barrier) {
994 keepalive(masm, continuation());
995 } else if (_needs_load_ref_barrier) {
996 lrb(masm);
997 } else {
998 ShouldNotReachHere();
999 }
1000 }
1001
1002 void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
1003 __ cmpdi(CR0, reg, 0);
1004 // Branch to continuation if equal
1005 __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *continuation());
1006 }
1007
1008 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
1009 const int gcstate_offset = in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING));
1010 const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
1011 const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
1012 Label L_through, L_slowpath;
1013
1014 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1015 if (_needs_load_ref_barrier) {
1016 assert(L_done == nullptr, "L_done is always null when _needs_load_ref_barrier is true");
1017 __ lbz(_tmp1, gcstate_offset, R16_thread);
1018 __ cmpdi(CR0, _tmp1, 0);
1019 __ beq(CR0, L_through);
1020 }
1021
1022 // Fast-path: put object into buffer.
1023 // If buffer is already full, go slow.
1024 __ ld(_tmp1, index_offset, R16_thread);
1025 __ cmpdi(CR0, _tmp1, 0);
1026 __ beq(CR0, L_slowpath);
1027 __ addi(_tmp1, _tmp1, -wordSize);
1028 __ std(_tmp1, index_offset, R16_thread);
1029 __ ld(_tmp2, buffer_offset, R16_thread);
1030
1031 // Store the object in queue.
1032 // If object is narrow, we need to decode it before inserting.
1033 if (_narrow) {
1034 __ add(_tmp2, _tmp2, _tmp1);
1035 Register decoded = __ decode_heap_oop_not_null(_tmp1, _obj);
1036 __ stdx(decoded, _tmp2);
1037 } else {
1038 __ stdx(_obj, _tmp2, _tmp1);
1039 }
1048 // Slow-path: call runtime to handle.
1049 __ bind(L_slowpath);
1050
1051 {
1052 SaveLiveRegisters slr(&masm, this);
1053
1054 // Go to runtime and handle the rest there.
1055 __ call_VM_leaf(keepalive_runtime_entry_addr(), _obj);
1056 }
1057
1058 if (L_done != nullptr) {
1059 __ b(*L_done);
1060 } else {
1061 __ bind(L_through);
1062 }
1063 }
1064
1065 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
1066 Label L_slow;
1067
1068 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1069 if (_needs_keep_alive_barrier) {
1070 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1071 __ lbz(_tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)), R16_thread);
1072 maybe_far_jump_if_zero(masm, _tmp1);
1073 }
1074
1075 // If weak references are being processed, weak/phantom loads need to go slow,
1076 // regardless of their cset status.
1077 if (_needs_load_ref_weak_barrier) {
1078 __ lbz(_tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)), R16_thread);
1079 __ cmpdi(CR0, _tmp1, 0);
1080 __ bne(CR0, L_slow);
1081 }
1082
1083 // Cset-check. Fall-through to slow if in collection set.
1084 __ load_const_optimized(_tmp1, ShenandoahHeap::in_cset_fast_test_addr(), _tmp2);
1085 if (_narrow) {
1086 Register decoded = __ decode_heap_oop_not_null(_tmp2, _obj);
1087 __ srdi(_tmp2, decoded, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1088 } else {
1089 __ srdi(_tmp2, _obj, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1090 }
1091 __ lbzx(_tmp2, _tmp2, _tmp1);
1092 maybe_far_jump_if_zero(masm, _tmp2);
1093
1094 // Slow path
1095 __ bind(L_slow);
1096
1097 // Obj is the result, need to temporarily stop preserving it.
1098 bool is_obj_preserved = is_preserved(_obj);
1099 if (is_obj_preserved) {
1100 dont_preserve(_obj);
|
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 "asm/macroAssembler.inline.hpp"
28 #include "gc/shared/gc_globals.hpp"
29 #include "gc/shared/gcArguments.hpp"
30 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
31 #include "gc/shenandoah/mode/shenandoahMode.hpp"
32 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
33 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
34 #include "gc/shenandoah/shenandoahHeap.hpp"
35 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
36 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
37 #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
38 #include "gc/shenandoah/shenandoahRuntime.hpp"
39 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
40 #include "interpreter/interpreter.hpp"
41 #include "macroAssembler_ppc.hpp"
42 #include "nativeInst_ppc.hpp"
43 #include "runtime/icache.hpp"
44 #include "runtime/javaThread.hpp"
45 #include "runtime/sharedRuntime.hpp"
46 #include "utilities/globalDefinitions.hpp"
47 #include "vm_version_ppc.hpp"
48 #ifdef COMPILER1
49 #include "c1/c1_LIRAssembler.hpp"
50 #include "c1/c1_MacroAssembler.hpp"
51 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
52 #endif
53 #ifdef COMPILER2
54 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
55 #include "opto/output.hpp"
56 #endif
57
58 #define __ masm->
59
60 void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler *masm,
61 Register base, RegisterOrConstant ind_or_offs,
62 Register tmp1, Register tmp2, Register tmp3,
63 MacroAssembler::PreservationLevel preservation_level,
64 int extra_stack_space) {
65 if (ShenandoahSATBBarrier) {
66 __ block_comment("satb_barrier (shenandoahgc) {");
67 satb_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level, extra_stack_space);
68 __ block_comment("} satb_barrier (shenandoahgc)");
69 }
70 }
71
72 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators,
73 Register base, RegisterOrConstant ind_or_offs,
74 Register dst,
75 Register tmp1, Register tmp2,
700 // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.)
701 __ srdi(addr, addr, CardTable::card_shift());
702 __ srdi(count, count, CardTable::card_shift());
703 __ subf(count, addr, count);
704 __ ld(R0, in_bytes(ShenandoahThreadLocalData::card_table_offset()), R16_thread);
705 __ add(addr, addr, R0);
706 __ addi(count, count, 1);
707 __ li(R0, 0);
708 __ mtctr(count);
709
710 // Byte store loop
711 __ bind(L_store_loop);
712 __ stb(R0, 0, addr);
713 __ addi(addr, addr, 1);
714 __ bdnz(L_store_loop);
715 __ bind(L_skip_loop);
716 }
717
718 #undef __
719
720 address ShenandoahBarrierSetAssembler::parse_jump_address(address pc) {
721 NativeInstruction* ni = nativeInstruction_at(pc);
722 assert(ni->is_jump(), "Must be");
723 NativeGeneralJump* jmp = nativeGeneralJump_at(pc);
724 return jmp->jump_destination();
725 }
726
727 static uint32_t encode_patchable_nop() {
728 return 0x60000000;
729 }
730
731 void ShenandoahBarrierSetAssembler::insert_patchable_nop(address pc) {
732 *((uint32_t*)pc) = encode_patchable_nop();
733 ICache::invalidate_word(pc);
734 }
735
736 void ShenandoahBarrierSetAssembler::insert_patchable_jump(address pc, address target_pc) {
737 CodeBuffer cb(pc, BytesPerInstWord + 1);
738 MacroAssembler a(&cb);
739 a.b(target_pc);
740 ICache::invalidate_word(pc);
741 }
742
743 bool ShenandoahBarrierSetAssembler::is_patchable_nop(address pc) {
744 return *((uint32_t*)pc) == encode_patchable_nop();
745 }
746
747 bool ShenandoahBarrierSetAssembler::is_patchable_jump(address pc, address target_pc) {
748 NativeInstruction* ni = nativeInstruction_at(pc);
749 return ni->is_jump() && nativeGeneralJump_at(pc)->jump_destination() == target_pc;
750 }
751
752 #ifdef COMPILER1
753
754 #define __ ce->masm()->
755
756 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
757 __ block_comment("keepalive_barrier_stub (shenandoahgc) {");
758 __ bind(*stub->entry());
759
760 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1();
761
762 Register obj = stub->obj()->as_register();
763
764 // If 'do_load()' returns false, the to-be-stored value is already available in 'obj'
765 if (stub->do_load()) {
766 ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, false);
767 }
768
769 // Fast path: reference is null.
770 __ cmpdi(CR0, obj, 0);
771 __ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CR0, Assembler::equal), *stub->continuation());
968 #define __ masm.
969
970 void ShenandoahBarrierStubC2::cardtable(MacroAssembler& masm, Address address, Register tmp1, Register tmp2) {
971 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
972 assert_different_registers(tmp1, tmp2, address.index(), address.base());
973
974 __ ld(tmp1, in_bytes(ShenandoahThreadLocalData::card_table_offset()), R16_thread);
975 if (address.index() == noreg) {
976 __ add_const_optimized(tmp2, address.base(), address.disp(), R0);
977 } else {
978 __ add(tmp2, address.index(), address.base());
979 if (address.disp() != 0) {
980 __ addi(tmp2, tmp2, address.disp());
981 }
982 }
983 __ srdi(tmp2, tmp2, CardTable::card_shift());
984 __ li(R0, CardTable::dirty_card_val());
985 __ stbx(R0, tmp2, tmp1);
986 }
987
988 void ShenandoahBarrierStubC2::patchable_jump(MacroAssembler& masm, const char gc_state, bool jump_when_state, Register tmp1, Register tmp2, Label* L_target) {
989 PhaseOutput* const output = Compile::current()->output();
990 if (output->in_scratch_emit_size()) {
991 // Avoid binding L_target in scratch emits.
992 // We know the patched check is exactly one instruction long.
993 __ nop();
994 return;
995 }
996
997 // Emit the unconditional branch in the first version of the method.
998 // Let the rest of runtime figure out how to manage it.
999 __ relocate(patchable_barrier_Relocation::spec(ShenandoahNMethod::encode_to_reloc(gc_state, jump_when_state)));
1000 __ b(*L_target);
1001 }
1002
1003 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp1, Register tmp2) {
1004 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
1005 patchable_jump_if_gc_state(masm, test_state, tmp1, tmp2, entry());
1006 __ bind(*continuation());
1007 }
1008
1009 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
1010 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
1011 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
1012
1013 __ bind(*entry());
1014
1015 // If we need to load ourselves, do it here.
1016 if (_do_load) {
1017 if (_narrow) {
1018 __ lwz(_obj, _addr.disp(), _addr.base());
1019 } else {
1020 __ ld(_obj, _addr.disp(), _addr.base());
1021 }
1022 }
1023
1024 // If the object is null, there is no point in applying barriers.
1025 maybe_far_jump_if_zero(masm, _obj);
1035 // as another barrier is not needed and we can reach the fastpath.
1036 if (needs_both_barriers) {
1037 keepalive(masm, nullptr);
1038 lrb(masm);
1039 } else if (_needs_keep_alive_barrier) {
1040 keepalive(masm, continuation());
1041 } else if (_needs_load_ref_barrier) {
1042 lrb(masm);
1043 } else {
1044 ShouldNotReachHere();
1045 }
1046 }
1047
1048 void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
1049 __ cmpdi(CR0, reg, 0);
1050 // Branch to continuation if equal
1051 __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *continuation());
1052 }
1053
1054 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
1055 const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset());
1056 const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset());
1057 Label L_through, L_slowpath;
1058
1059 // If another barrier is enabled as well, do a check for a specific barrier.
1060 if (_needs_load_ref_barrier) {
1061 assert(L_done == nullptr, "Should be");
1062 char state_to_check = ShenandoahHeap::MARKING;
1063 patchable_jump_if_not_gc_state(masm, state_to_check, _tmp1, _tmp2, &L_through);
1064 }
1065
1066 // Fast-path: put object into buffer.
1067 // If buffer is already full, go slow.
1068 __ ld(_tmp1, index_offset, R16_thread);
1069 __ cmpdi(CR0, _tmp1, 0);
1070 __ beq(CR0, L_slowpath);
1071 __ addi(_tmp1, _tmp1, -wordSize);
1072 __ std(_tmp1, index_offset, R16_thread);
1073 __ ld(_tmp2, buffer_offset, R16_thread);
1074
1075 // Store the object in queue.
1076 // If object is narrow, we need to decode it before inserting.
1077 if (_narrow) {
1078 __ add(_tmp2, _tmp2, _tmp1);
1079 Register decoded = __ decode_heap_oop_not_null(_tmp1, _obj);
1080 __ stdx(decoded, _tmp2);
1081 } else {
1082 __ stdx(_obj, _tmp2, _tmp1);
1083 }
1092 // Slow-path: call runtime to handle.
1093 __ bind(L_slowpath);
1094
1095 {
1096 SaveLiveRegisters slr(&masm, this);
1097
1098 // Go to runtime and handle the rest there.
1099 __ call_VM_leaf(keepalive_runtime_entry_addr(), _obj);
1100 }
1101
1102 if (L_done != nullptr) {
1103 __ b(*L_done);
1104 } else {
1105 __ bind(L_through);
1106 }
1107 }
1108
1109 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
1110 Label L_slow;
1111
1112 // If another barrier is enabled as well, do a check for a specific barrier.
1113 if (_needs_keep_alive_barrier) {
1114 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1115 patchable_jump_if_not_gc_state(masm, state_to_check, _tmp1, _tmp2, continuation());
1116 }
1117
1118 // If weak references are being processed, weak/phantom loads need to go slow,
1119 // regardless of their cset status.
1120 if (_needs_load_ref_weak_barrier) {
1121 char state_to_check = ShenandoahHeap::WEAK_ROOTS;
1122 patchable_jump_if_gc_state(masm, state_to_check, _tmp1, _tmp2, &L_slow);
1123 }
1124
1125 // Cset-check. Fall-through to slow if in collection set.
1126 __ load_const_optimized(_tmp1, ShenandoahHeap::in_cset_fast_test_addr(), _tmp2);
1127 if (_narrow) {
1128 Register decoded = __ decode_heap_oop_not_null(_tmp2, _obj);
1129 __ srdi(_tmp2, decoded, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1130 } else {
1131 __ srdi(_tmp2, _obj, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1132 }
1133 __ lbzx(_tmp2, _tmp2, _tmp1);
1134 maybe_far_jump_if_zero(masm, _tmp2);
1135
1136 // Slow path
1137 __ bind(L_slow);
1138
1139 // Obj is the result, need to temporarily stop preserving it.
1140 bool is_obj_preserved = is_preserved(_obj);
1141 if (is_obj_preserved) {
1142 dont_preserve(_obj);
|