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