25 */
26
27 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/mode/shenandoahMode.hpp"
29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
31 #include "gc/shenandoah/shenandoahForwarding.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/interp_masm.hpp"
37 #include "interpreter/interpreter.hpp"
38 #include "runtime/javaThread.hpp"
39 #include "runtime/sharedRuntime.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
46 #define __ masm->
47
48 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
49 Register src, Register dst, Register count, RegSet saved_regs) {
50 if (is_oop) {
51 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
52 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
53
54 Label done;
55
56 // Avoid calling runtime if count == 0
57 __ cbz(count, done);
58
59 // Is GC active?
60 assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1");
61 assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2");
62 Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
63 __ ldrb(rscratch1, gc_state);
64 if (ShenandoahSATBBarrier && dest_uninitialized) {
814 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)));
815 } else {
816 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)));
817 }
818 } else {
819 assert(is_phantom, "only remaining strength");
820 assert(is_native, "phantom must only be called off-heap");
821 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)));
822 }
823 __ blr(lr);
824 __ mov(rscratch1, r0);
825 __ pop_call_clobbered_registers();
826 __ mov(r0, rscratch1);
827
828 __ epilogue();
829 }
830
831 #undef __
832
833 #endif // COMPILER1
|
25 */
26
27 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/mode/shenandoahMode.hpp"
29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
31 #include "gc/shenandoah/shenandoahForwarding.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/interp_masm.hpp"
37 #include "interpreter/interpreter.hpp"
38 #include "runtime/javaThread.hpp"
39 #include "runtime/sharedRuntime.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 #include "opto/output.hpp"
48 #endif
49
50 #define __ masm->
51
52 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
53 Register src, Register dst, Register count, RegSet saved_regs) {
54 if (is_oop) {
55 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
56 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
57
58 Label done;
59
60 // Avoid calling runtime if count == 0
61 __ cbz(count, done);
62
63 // Is GC active?
64 assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1");
65 assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2");
66 Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
67 __ ldrb(rscratch1, gc_state);
68 if (ShenandoahSATBBarrier && dest_uninitialized) {
818 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)));
819 } else {
820 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)));
821 }
822 } else {
823 assert(is_phantom, "only remaining strength");
824 assert(is_native, "phantom must only be called off-heap");
825 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)));
826 }
827 __ blr(lr);
828 __ mov(rscratch1, r0);
829 __ pop_call_clobbered_registers();
830 __ mov(r0, rscratch1);
831
832 __ epilogue();
833 }
834
835 #undef __
836
837 #endif // COMPILER1
838
839 #ifdef COMPILER2
840 #undef __
841 #define __ masm.
842
843 int ShenandoahBarrierStubC2::available_gp_registers() {
844 return Register::number_of_registers;
845 }
846
847 bool ShenandoahBarrierStubC2::is_special_register(Register r) {
848 return R18_RESERVED_ONLY(r == r18_tls ||)
849 r == rfp || r == sp || r == lr ||
850 r == rheapbase || r == rthread ||
851 r == rscratch1 || r == rscratch2;
852 }
853
854 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
855 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
856
857 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
858 if (_needs_far_jump) {
859 __ ldrb(rscratch1, gc_state_fast);
860 __ cbz(rscratch1, *continuation());
861 __ b(*entry());
862 } else {
863 __ ldrb(rscratch1, gc_state_fast);
864 __ cbnz(rscratch1, *entry());
865 }
866
867 // This is were the slowpath stub will return to or the code above will
868 // jump to if the checks are false
869 __ bind(*continuation());
870 }
871
872 #undef __
873 #define __ masm->
874
875 void ShenandoahBarrierSetAssembler::compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr,
876 Register oldval, Register newval, Register tmp, bool exchange, bool narrow, bool weak, bool acquire) {
877 Assembler::operand_size op_size = narrow ? Assembler::word : Assembler::xword;
878
879 // Pre-barrier covers several things:
880 // a. Avoids false positives from CAS encountering to-space memory values.
881 // b. Satisfies the need for LRB for the CAE result.
882 // c. Records old value for the sake of SATB.
883 //
884 // (a) and (b) are covered because load barrier does memory location fixup.
885 // (c) is covered by KA on the current memory value.
886 if (ShenandoahBarrierStubC2::needs_slow_barrier(node)) {
887 ShenandoahBarrierStubC2* const stub = ShenandoahBarrierStubC2::create(node, tmp, addr, narrow, /* do_load: */ true);
888 char check = 0;
889 check |= ShenandoahBarrierStubC2::needs_keep_alive_barrier(node) ? ShenandoahHeap::MARKING : 0;
890 check |= ShenandoahBarrierStubC2::needs_load_ref_barrier(node) ? ShenandoahHeap::HAS_FORWARDED : 0;
891 assert(!ShenandoahBarrierStubC2::needs_load_ref_barrier_weak(node), "Not supported for CAS");
892 stub->enter_if_gc_state(*masm, check);
893 }
894
895 // CAS!
896 __ cmpxchg(addr, oldval, newval, op_size, acquire, /* release */ true, weak, exchange ? res : noreg);
897
898 // If we need a boolean result out of CAS, set the flag appropriately and promote the result.
899 if (!exchange) {
900 assert(res != noreg, "need result register");
901 __ cset(res, Assembler::EQ);
902 }
903
904 // Post-barrier deals with card updates.
905 card_barrier_c2(node, masm, Address(addr, 0));
906 }
907
908 void ShenandoahBarrierSetAssembler::get_and_set_c2(const MachNode* node, MacroAssembler* masm, Register preval,
909 Register newval, Register addr, Register tmp, bool is_acquire) {
910 bool is_narrow = node->bottom_type()->isa_narrowoop();
911
912 // Pre-barrier covers several things:
913 // a. Satisfies the need for LRB for the GAS result.
914 // b. Records old value for the sake of SATB.
915 //
916 // (a) is covered because load barrier does memory location fixup.
917 // (b) is covered by KA on the current memory value.
918 if (ShenandoahBarrierStubC2::needs_slow_barrier(node)) {
919 ShenandoahBarrierStubC2* const stub = ShenandoahBarrierStubC2::create(node, tmp, addr, is_narrow, /* do_load: */ true);
920 char check = 0;
921 check |= ShenandoahBarrierStubC2::needs_keep_alive_barrier(node) ? ShenandoahHeap::MARKING : 0;
922 check |= ShenandoahBarrierStubC2::needs_load_ref_barrier(node) ? ShenandoahHeap::HAS_FORWARDED : 0;
923 assert(!ShenandoahBarrierStubC2::needs_load_ref_barrier_weak(node), "Not supported for GAS");
924 stub->enter_if_gc_state(*masm, check);
925 }
926
927 if (is_narrow) {
928 if (is_acquire) {
929 __ atomic_xchgalw(preval, newval, addr);
930 } else {
931 __ atomic_xchgw(preval, newval, addr);
932 }
933 } else {
934 if (is_acquire) {
935 __ atomic_xchgal(preval, newval, addr);
936 } else {
937 __ atomic_xchg(preval, newval, addr);
938 }
939 }
940
941 // Post-barrier deals with card updates.
942 card_barrier_c2(node, masm, Address(addr, 0));
943 }
944
945 void ShenandoahBarrierSetAssembler::store_c2(const MachNode* node, MacroAssembler* masm, Address dst, bool dst_narrow,
946 Register src, bool src_narrow, Register tmp, bool is_volatile) {
947
948 // Pre-barrier: SATB, keep-alive the current memory value.
949 if (ShenandoahBarrierStubC2::needs_slow_barrier(node)) {
950 assert(!ShenandoahBarrierStubC2::needs_load_ref_barrier(node), "Should not be required for stores");
951 ShenandoahBarrierStubC2* const stub = ShenandoahBarrierStubC2::create(node, tmp, dst, dst_narrow, /* do_load: */ true);
952 stub->enter_if_gc_state(*masm, ShenandoahHeap::MARKING);
953 }
954
955 // Do the actual store
956 if (dst_narrow) {
957 if (!src_narrow) {
958 // Need to encode into rscratch, because we cannot clobber src.
959 if (ShenandoahBarrierStubC2::maybe_null(node)) {
960 __ encode_heap_oop(rscratch1, src);
961 } else {
962 __ encode_heap_oop_not_null(rscratch1, src);
963 }
964 src = rscratch1;
965 }
966
967 if (is_volatile) {
968 __ stlrw(src, dst.base());
969 } else {
970 __ strw(src, dst);
971 }
972 } else {
973 if (is_volatile) {
974 __ stlr(src, dst.base());
975 } else {
976 __ str(src, dst);
977 }
978 }
979
980 // Post-barrier: card updates.
981 card_barrier_c2(node, masm, dst);
982 }
983
984 void ShenandoahBarrierSetAssembler::load_c2(const MachNode* node, MacroAssembler* masm, Register dst, Address src, bool is_narrow, bool is_acquire) {
985 // Do the actual load. This load is the candidate for implicit null check, and MUST come first.
986 if (is_narrow) {
987 if (is_acquire) {
988 __ ldarw(dst, src.base());
989 } else {
990 __ ldrw(dst, src);
991 }
992 } else {
993 if (is_acquire) {
994 __ ldar(dst, src.base());
995 } else {
996 __ ldr(dst, src);
997 }
998 }
999
1000 // Post-barrier: LRB / KA / weak-root processing.
1001 if (ShenandoahBarrierStubC2::needs_slow_barrier(node)) {
1002 ShenandoahBarrierStubC2* const stub = ShenandoahBarrierStubC2::create(node, dst, src, is_narrow, /* do_load: */ false);
1003 char check = 0;
1004 check |= ShenandoahBarrierStubC2::needs_keep_alive_barrier(node) ? ShenandoahHeap::MARKING : 0;
1005 check |= ShenandoahBarrierStubC2::needs_load_ref_barrier(node) ? ShenandoahHeap::HAS_FORWARDED : 0;
1006 check |= ShenandoahBarrierStubC2::needs_load_ref_barrier_weak(node) ? ShenandoahHeap::WEAK_ROOTS : 0;
1007 stub->enter_if_gc_state(*masm, check);
1008 }
1009 }
1010
1011 void ShenandoahBarrierSetAssembler::card_barrier_c2(const MachNode* node, MacroAssembler* masm, Address address) {
1012 if (!ShenandoahBarrierStubC2::needs_card_barrier(node)) {
1013 return;
1014 }
1015
1016 assert(CardTable::dirty_card_val() == 0, "must be");
1017 Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
1018
1019 // rscratch1 = card table base (holder)
1020 Address curr_ct_holder_addr(rthread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
1021 __ ldr(rscratch1, curr_ct_holder_addr);
1022
1023 // rscratch2 = effective address
1024 __ lea(rscratch2, address);
1025
1026 // rscratch2 = &card_table[ addr >> CardTable::card_shift() ] ; card index
1027 __ add(rscratch2, rscratch1, rscratch2, Assembler::LSR, CardTable::card_shift());
1028
1029 if (UseCondCardMark) {
1030 Label L_already_dirty;
1031 __ ldrb(rscratch1, Address(rscratch2));
1032 __ cbz(rscratch1, L_already_dirty);
1033 __ strb(zr, Address(rscratch2));
1034 __ bind(L_already_dirty);
1035 } else {
1036 __ strb(zr, Address(rscratch2));
1037 }
1038 }
1039 #undef __
1040 #define __ masm.
1041
1042 void ShenandoahBarrierStubC2::post_init() {
1043 // If we are in scratch emit mode we assume worst case,
1044 // and force the use of trampolines
1045 PhaseOutput* const output = Compile::current()->output();
1046 if (output->in_scratch_emit_size()) {
1047 _needs_far_jump = true;
1048 return;
1049 }
1050
1051 // TODO: how correct is this? factor out this into a method.
1052 const int code_size = output->buffer_sizing_data()->_code +
1053 output->buffer_sizing_data()->_stub +
1054 output->buffer_sizing_data()->_reloc;
1055 _needs_far_jump = code_size >= (int)(1*M);
1056 }
1057
1058 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
1059 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
1060 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
1061
1062 __ bind(*entry());
1063
1064 // If we need to load ourselves, do it here.
1065 if (_do_load) {
1066 if (_narrow) {
1067 __ ldrw(_obj, _addr);
1068 } else {
1069 __ ldr(_obj, _addr);
1070 }
1071 }
1072
1073 // If the object is null, there is no point in applying barriers.
1074 maybe_far_jump_if_zero(masm, _obj, continuation());
1075
1076 // We need to make sure that loads done by callers survive across slow-path calls.
1077 // For self-loads, we need to care about the case when both KA and LRB are enabled (rare).
1078 if (!_do_load || (_needs_keep_alive_barrier && _needs_load_ref_barrier)) {
1079 preserve(_obj);
1080 }
1081
1082 // Go for barriers. Barriers can return straight to continuation, as long
1083 // as another barrier is not needed and we can reach the fastpath.
1084 if (_needs_keep_alive_barrier && _needs_load_ref_barrier) {
1085 keepalive(masm, nullptr);
1086 lrb(masm, continuation());
1087 } else if (_needs_keep_alive_barrier) {
1088 keepalive(masm, continuation());
1089 } else if (_needs_load_ref_barrier) {
1090 lrb(masm, continuation());
1091 } else {
1092 ShouldNotReachHere();
1093 }
1094 }
1095
1096 void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg, Label* L_done) {
1097 if (_needs_far_jump) {
1098 Label L_short_jump;
1099 __ cbnz(reg, L_short_jump);
1100 __ b(*L_done);
1101 __ bind(L_short_jump);
1102 } else {
1103 __ cbz(reg, *L_done);
1104 }
1105 }
1106
1107 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
1108 Address index(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
1109 Address buffer(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
1110
1111 Label L_through, L_slowpath;
1112
1113 Register tmp1 = rscratch1;
1114 Register tmp2 = rscratch2;
1115 assert_different_registers(tmp1, tmp2, _obj, _addr.base(), _addr.index());
1116
1117 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1118 if (_needs_load_ref_barrier) {
1119 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING)));
1120 __ ldrb(tmp1, gc_state_fast);
1121 if (L_done != nullptr) {
1122 maybe_far_jump_if_zero(masm, tmp1, L_done);
1123 } else {
1124 __ cbz(tmp1, L_through);
1125 }
1126 }
1127
1128 // Fast-path: put object into buffer.
1129 // If buffer is already full, go slow.
1130 __ ldr(tmp1, index);
1131 __ cbz(tmp1, L_slowpath);
1132 __ sub(tmp1, tmp1, wordSize);
1133 __ str(tmp1, index);
1134 __ ldr(tmp2, buffer);
1135
1136 // If object is narrow, we need to unpack it before inserting into buffer,
1137 // and pack it back. We can skip the unpack if we know that object is not preserved.
1138 if (_narrow) {
1139 __ decode_heap_oop_not_null(_obj);
1140 }
1141 __ str(_obj, Address(tmp2, tmp1));
1142 if (_narrow && is_preserved(_obj)) {
1143 __ encode_heap_oop_not_null(_obj);
1144 }
1145
1146 // Fast-path exits here.
1147 if (L_done != nullptr) {
1148 __ b(*L_done);
1149 } else {
1150 __ b(L_through);
1151 }
1152
1153 // Slow-path: call runtime to handle.
1154 __ bind(L_slowpath);
1155
1156 // The Load match rule in the .ad file may have legitimized the load address
1157 // using a TEMP register and in that case we need to explicitly preserve them
1158 // here because the RA does not consider TEMP as live-in, of course.
1159 if (_needs_load_ref_barrier) {
1160 preserve(_addr.base());
1161 preserve(_addr.index());
1162 }
1163
1164 {
1165 SaveLiveRegisters slr(&masm, this);
1166
1167 // Go to runtime and handle the rest there.
1168 __ mov(c_rarg0, _obj);
1169 __ mov(lr, keepalive_runtime_entry_addr());
1170 __ blr(lr);
1171 }
1172
1173 if (L_done != nullptr) {
1174 __ b(*L_done);
1175 } else {
1176 __ bind(L_through);
1177 }
1178 }
1179
1180 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm, Label* L_done) {
1181 assert(L_done != nullptr, "Must be set");
1182
1183 Label L_slow;
1184
1185 Register tmp1 = rscratch1;
1186 Register tmp2 = rscratch2;
1187 assert_different_registers(tmp1, tmp2, _obj, _addr.base(), _addr.index());
1188
1189 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1190 if (_needs_keep_alive_barrier) {
1191 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1192 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
1193 __ ldrb(tmp1, gc_state_fast);
1194 maybe_far_jump_if_zero(masm, tmp1, L_done);
1195 }
1196
1197 // If weak references are being processed, weak/phantom loads need to go slow,
1198 // regardless of their cset status.
1199 if (_needs_load_ref_weak_barrier) {
1200 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));
1201 __ ldrb(tmp1, gc_state_fast);
1202 __ cbnz(tmp1, L_slow);
1203 }
1204
1205 // Cset-check. Fall-through to slow if in collection set.
1206 if (_narrow) {
1207 __ decode_heap_oop_not_null(tmp2, _obj);
1208 } else {
1209 tmp2 = _obj;
1210 }
1211 __ mov(tmp1, ShenandoahHeap::in_cset_fast_test_addr());
1212 __ add(tmp1, tmp1, tmp2, Assembler::LSR, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1213 __ ldrb(tmp1, Address(tmp1, 0));
1214 maybe_far_jump_if_zero(masm, tmp1, L_done);
1215
1216 // Slow path
1217 __ bind(L_slow);
1218
1219 // Obj is the result, need to temporarily stop preserving it.
1220 bool is_obj_preserved = is_preserved(_obj);
1221 if (is_obj_preserved) {
1222 dont_preserve(_obj);
1223 }
1224 {
1225 SaveLiveRegisters slr(&masm, this);
1226
1227 // Shuffle in the arguments. The end result should be:
1228 // c_rarg0 <-- obj
1229 // c_rarg1 <-- lea(addr)
1230 if (c_rarg0 == _obj) {
1231 __ lea(c_rarg1, _addr);
1232 } else if (c_rarg1 == _obj) {
1233 // Set up arguments in reverse, and then flip them
1234 __ lea(c_rarg0, _addr);
1235 // flip them
1236 __ mov(tmp1, c_rarg0);
1237 __ mov(c_rarg0, c_rarg1);
1238 __ mov(c_rarg1, tmp1);
1239 } else {
1240 assert_different_registers(c_rarg1, _obj);
1241 __ lea(c_rarg1, _addr);
1242 __ mov(c_rarg0, _obj);
1243 }
1244
1245 // Go to runtime and handle the rest there.
1246 __ mov(lr, lrb_runtime_entry_addr());
1247 __ blr(lr);
1248
1249 // Save the result where needed.
1250 if (_obj != r0) {
1251 __ mov(_obj, r0);
1252 }
1253 }
1254 if (is_obj_preserved) {
1255 preserve(_obj);
1256 }
1257
1258 __ b(*L_done);
1259 }
1260
1261 #undef __
1262 #define __ masm->
1263
1264 #endif // COMPILER2
|