1 /*
2 * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
27 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
28 #include "gc/shenandoah/shenandoahForwarding.hpp"
29 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
30 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
31 #include "gc/shenandoah/shenandoahRuntime.hpp"
32 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
33 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
34 #include "interpreter/interpreter.hpp"
35 #include "runtime/javaThread.hpp"
36 #include "runtime/sharedRuntime.hpp"
37 #include "utilities/macros.hpp"
38 #ifdef COMPILER1
39 #include "c1/c1_LIRAssembler.hpp"
40 #include "c1/c1_MacroAssembler.hpp"
41 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
42 #endif
43
44 #define __ masm->
45
46 static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) {
47 if (handle_gpr) {
48 __ push_IU_state();
49 }
50
51 if (handle_fp) {
52 // Some paths can be reached from the c2i adapter with live fp arguments in registers.
53 LP64_ONLY(assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call"));
103 __ movflt(xmm5, Address(rsp, xmm_size * 5));
104 __ movflt(xmm6, Address(rsp, xmm_size * 6));
105 __ movflt(xmm7, Address(rsp, xmm_size * 7));
106 __ addptr(rsp, xmm_size * 8);
107 } else {
108 __ pop_FPU_state();
109 }
110 }
111
112 if (handle_gpr) {
113 __ pop_IU_state();
114 }
115 }
116
117 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
118 Register src, Register dst, Register count) {
119
120 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
121
122 if (is_reference_type(type)) {
123
124 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
125 #ifdef _LP64
126 Register thread = r15_thread;
127 #else
128 Register thread = rax;
129 if (thread == src || thread == dst || thread == count) {
130 thread = rbx;
131 }
132 if (thread == src || thread == dst || thread == count) {
133 thread = rcx;
134 }
135 if (thread == src || thread == dst || thread == count) {
136 thread = rdx;
137 }
138 __ push(thread);
139 __ get_thread(thread);
140 #endif
141 assert_different_registers(src, dst, count, thread);
142
143 Label done;
144 // Short-circuit if count == 0.
145 __ testptr(count, count);
146 __ jcc(Assembler::zero, done);
147
148 // Avoid runtime call when not active.
149 Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
150 int flags;
151 if (ShenandoahSATBBarrier && dest_uninitialized) {
152 flags = ShenandoahHeap::HAS_FORWARDED;
153 } else {
154 flags = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING;
155 }
156 __ testb(gc_state, flags);
157 __ jcc(Assembler::zero, done);
158
159 save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false);
160
161 #ifdef _LP64
162 assert(src == rdi, "expected");
163 assert(dst == rsi, "expected");
164 assert(count == rdx, "expected");
165 if (UseCompressedOops) {
166 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry),
167 src, dst, count);
168 } else
169 #endif
170 {
171 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry),
172 src, dst, count);
173 }
174
175 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false);
176
177 __ bind(done);
178 NOT_LP64(__ pop(thread);)
179 }
180 }
181
182 }
183
184 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
185 Register obj,
186 Register pre_val,
187 Register thread,
188 Register tmp,
189 bool tosca_live,
190 bool expand_call) {
191
192 if (ShenandoahSATBBarrier) {
193 satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call);
194 }
195 }
196
197 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
198 Register obj,
199 Register pre_val,
200 Register thread,
201 Register tmp,
202 bool tosca_live,
203 bool expand_call) {
204 // If expand_call is true then we expand the call_VM_leaf macro
205 // directly to skip generating the check by
206 // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
207
208 #ifdef _LP64
209 assert(thread == r15_thread, "must be");
210 #endif // _LP64
211
212 Label done;
213 Label runtime;
214
215 assert(pre_val != noreg, "check this code");
216
217 if (obj != noreg) {
218 assert_different_registers(obj, pre_val, tmp);
219 assert(pre_val != rax, "check this code");
220 }
221
222 Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()));
223 Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
224 Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
225
226 Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
227 __ testb(gc_state, ShenandoahHeap::MARKING);
228 __ jcc(Assembler::zero, done);
229
230 // Do we need to load the previous value?
231 if (obj != noreg) {
232 __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
233 }
234
235 // Is the previous value null?
236 __ cmpptr(pre_val, NULL_WORD);
237 __ jcc(Assembler::equal, done);
238
239 // Can we store original value in the thread's buffer?
240 // Is index == 0?
241 // (The index field is typed as size_t.)
242
456 __ addptr(rsp, num_saved_regs * wordSize);
457
458 restore_machine_state(masm, /* handle_gpr = */ false, /* handle_fp = */ true);
459
460 __ bind(not_cset);
461
462 if (is_strong) {
463 __ pop(tmp2);
464 __ pop(tmp1);
465 }
466
467 __ bind(heap_stable);
468
469 __ block_comment("} load_reference_barrier");
470
471 #ifndef _LP64
472 __ pop(thread);
473 #endif
474 }
475
476 void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {
477 if (ShenandoahIUBarrier) {
478 iu_barrier_impl(masm, dst, tmp);
479 }
480 }
481
482 void ShenandoahBarrierSetAssembler::iu_barrier_impl(MacroAssembler* masm, Register dst, Register tmp) {
483 assert(ShenandoahIUBarrier, "should be enabled");
484
485 if (dst == noreg) return;
486
487 if (ShenandoahIUBarrier) {
488 save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
489
490 #ifdef _LP64
491 Register thread = r15_thread;
492 #else
493 Register thread = rcx;
494 if (thread == dst || thread == tmp) {
495 thread = rdi;
496 }
497 if (thread == dst || thread == tmp) {
498 thread = rbx;
499 }
500 __ get_thread(thread);
501 #endif
502 assert_different_registers(dst, tmp, thread);
503
504 satb_write_barrier_pre(masm, noreg, dst, thread, tmp, true, false);
505
506 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
507 }
508 }
509
510 //
511 // Arguments:
512 //
513 // Inputs:
514 // src: oop location, might be clobbered
515 // tmp1: scratch register, might not be valid.
516 //
517 // Output:
518 // dst: oop loaded from src location
519 //
520 // Kill:
521 // tmp1 (if it is valid)
522 //
523 void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
524 Register dst, Address src, Register tmp1, Register tmp_thread) {
525 // 1: non-reference load, no additional barrier is needed
526 if (!is_reference_type(type)) {
527 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
528 return;
529 }
573 Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);
574 assert_different_registers(dst, tmp1, tmp_thread);
575 if (!thread->is_valid()) {
576 thread = rdx;
577 }
578 NOT_LP64(__ get_thread(thread));
579 // Generate the SATB pre-barrier code to log the value of
580 // the referent field in an SATB buffer.
581 shenandoah_write_barrier_pre(masm /* masm */,
582 noreg /* obj */,
583 dst /* pre_val */,
584 thread /* thread */,
585 tmp1 /* tmp */,
586 true /* tosca_live */,
587 true /* expand_call */);
588
589 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
590 }
591 }
592
593 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
594 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
595
596 bool on_oop = is_reference_type(type);
597 bool in_heap = (decorators & IN_HEAP) != 0;
598 bool as_normal = (decorators & AS_NORMAL) != 0;
599 if (on_oop && in_heap) {
600 bool needs_pre_barrier = as_normal;
601
602 Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
603 // flatten object address if needed
604 // We do it regardless of precise because we need the registers
605 if (dst.index() == noreg && dst.disp() == 0) {
606 if (dst.base() != tmp1) {
607 __ movptr(tmp1, dst.base());
608 }
609 } else {
610 __ lea(tmp1, dst);
611 }
612
613 assert_different_registers(val, tmp1, tmp2, tmp3, rthread);
614
615 #ifndef _LP64
616 __ get_thread(rthread);
617 InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);
618 imasm->save_bcp();
619 #endif
620
621 if (needs_pre_barrier) {
622 shenandoah_write_barrier_pre(masm /*masm*/,
623 tmp1 /* obj */,
624 tmp2 /* pre_val */,
625 rthread /* thread */,
626 tmp3 /* tmp */,
627 val != noreg /* tosca_live */,
628 false /* expand_call */);
629 }
630 if (val == noreg) {
631 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
632 } else {
633 iu_barrier(masm, val, tmp3);
634 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
635 }
636 NOT_LP64(imasm->restore_bcp());
637 } else {
638 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
639 }
640 }
641
642 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
643 Register obj, Register tmp, Label& slowpath) {
644 Label done;
645 // Resolve jobject
646 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
647
648 // Check for null.
649 __ testptr(obj, obj);
650 __ jcc(Assembler::zero, done);
651
652 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
653 __ testb(gc_state, ShenandoahHeap::EVACUATION);
654 __ jccb(Assembler::notZero, slowpath);
810 // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
811 // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
812
813 if (exchange) {
814 __ bind(L_failure);
815 __ bind(L_success);
816 } else {
817 assert(res != noreg, "need result register");
818
819 Label exit;
820 __ bind(L_failure);
821 __ xorptr(res, res);
822 __ jmpb(exit);
823
824 __ bind(L_success);
825 __ movptr(res, 1);
826 __ bind(exit);
827 }
828 }
829
830 #undef __
831
832 #ifdef COMPILER1
833
834 #define __ ce->masm()->
835
836 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
837 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
838 // At this point we know that marking is in progress.
839 // If do_load() is true then we have to emit the
840 // load of the previous value; otherwise it has already
841 // been loaded into _pre_val.
842
843 __ bind(*stub->entry());
844 assert(stub->pre_val()->is_register(), "Precondition.");
845
846 Register pre_val_reg = stub->pre_val()->as_register();
847
848 if (stub->do_load()) {
849 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/);
|
1 /*
2 * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
28 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
29 #include "gc/shenandoah/shenandoahForwarding.hpp"
30 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
31 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
32 #include "gc/shenandoah/shenandoahRuntime.hpp"
33 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
34 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
35 #include "gc/shenandoah/mode/shenandoahMode.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
46 #define __ masm->
47
48 static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) {
49 if (handle_gpr) {
50 __ push_IU_state();
51 }
52
53 if (handle_fp) {
54 // Some paths can be reached from the c2i adapter with live fp arguments in registers.
55 LP64_ONLY(assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call"));
105 __ movflt(xmm5, Address(rsp, xmm_size * 5));
106 __ movflt(xmm6, Address(rsp, xmm_size * 6));
107 __ movflt(xmm7, Address(rsp, xmm_size * 7));
108 __ addptr(rsp, xmm_size * 8);
109 } else {
110 __ pop_FPU_state();
111 }
112 }
113
114 if (handle_gpr) {
115 __ pop_IU_state();
116 }
117 }
118
119 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
120 Register src, Register dst, Register count) {
121
122 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
123
124 if (is_reference_type(type)) {
125 if (ShenandoahCardBarrier) {
126 bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
127 bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
128 bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops);
129
130 // We need to save the original element count because the array copy stub
131 // will destroy the value and we need it for the card marking barrier.
132 #ifdef _LP64
133 if (!checkcast) {
134 if (!obj_int) {
135 // Save count for barrier
136 __ movptr(r11, count);
137 } else if (disjoint) {
138 // Save dst in r11 in the disjoint case
139 __ movq(r11, dst);
140 }
141 }
142 #else
143 if (disjoint) {
144 __ mov(rdx, dst); // save 'to'
145 }
146 #endif
147 }
148
149 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
150 #ifdef _LP64
151 Register thread = r15_thread;
152 #else
153 Register thread = rax;
154 if (thread == src || thread == dst || thread == count) {
155 thread = rbx;
156 }
157 if (thread == src || thread == dst || thread == count) {
158 thread = rcx;
159 }
160 if (thread == src || thread == dst || thread == count) {
161 thread = rdx;
162 }
163 __ push(thread);
164 __ get_thread(thread);
165 #endif
166 assert_different_registers(src, dst, count, thread);
167
168 Label L_done;
169 // Short-circuit if count == 0.
170 __ testptr(count, count);
171 __ jcc(Assembler::zero, L_done);
172
173 // Avoid runtime call when not active.
174 Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
175 int flags;
176 if (ShenandoahSATBBarrier && dest_uninitialized) {
177 flags = ShenandoahHeap::HAS_FORWARDED;
178 } else {
179 flags = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING;
180 }
181 __ testb(gc_state, flags);
182 __ jcc(Assembler::zero, L_done);
183
184 save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false);
185
186 #ifdef _LP64
187 assert(src == rdi, "expected");
188 assert(dst == rsi, "expected");
189 assert(count == rdx, "expected");
190 if (UseCompressedOops) {
191 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry),
192 src, dst, count);
193 } else
194 #endif
195 {
196 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry),
197 src, dst, count);
198 }
199
200 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false);
201
202 __ bind(L_done);
203 NOT_LP64(__ pop(thread);)
204 }
205 }
206
207 }
208
209 void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
210 Register src, Register dst, Register count) {
211
212 if (ShenandoahCardBarrier && is_reference_type(type)) {
213 bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
214 bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0;
215 bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops);
216 Register tmp = rax;
217
218 #ifdef _LP64
219 if (!checkcast) {
220 if (!obj_int) {
221 // Save count for barrier
222 count = r11;
223 } else if (disjoint) {
224 // Use the saved dst in the disjoint case
225 dst = r11;
226 }
227 } else {
228 tmp = rscratch1;
229 }
230 #else
231 if (disjoint) {
232 __ mov(dst, rdx); // restore 'to'
233 }
234 #endif
235 gen_write_ref_array_post_barrier(masm, decorators, dst, count, tmp);
236 }
237 }
238
239 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
240 Register obj,
241 Register pre_val,
242 Register thread,
243 Register tmp,
244 bool tosca_live,
245 bool expand_call) {
246
247 if (ShenandoahSATBBarrier) {
248 satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call);
249 }
250 }
251
252 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
253 Register obj,
254 Register pre_val,
255 Register thread,
256 Register tmp,
257 bool tosca_live,
258 bool expand_call) {
259 // If expand_call is true then we expand the call_VM_leaf macro
260 // directly to skip generating the check by
261 // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
262
263 #ifdef _LP64
264 assert(thread == r15_thread, "must be");
265 #endif // _LP64
266
267 Label done;
268 Label runtime;
269
270 assert(pre_val != noreg, "check this code");
271
272 if (obj != noreg) {
273 assert_different_registers(obj, pre_val, tmp);
274 assert(pre_val != rax, "check this code");
275 }
276
277 Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
278 Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
279
280 Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
281 __ testb(gc_state, ShenandoahHeap::MARKING);
282 __ jcc(Assembler::zero, done);
283
284 // Do we need to load the previous value?
285 if (obj != noreg) {
286 __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
287 }
288
289 // Is the previous value null?
290 __ cmpptr(pre_val, NULL_WORD);
291 __ jcc(Assembler::equal, done);
292
293 // Can we store original value in the thread's buffer?
294 // Is index == 0?
295 // (The index field is typed as size_t.)
296
510 __ addptr(rsp, num_saved_regs * wordSize);
511
512 restore_machine_state(masm, /* handle_gpr = */ false, /* handle_fp = */ true);
513
514 __ bind(not_cset);
515
516 if (is_strong) {
517 __ pop(tmp2);
518 __ pop(tmp1);
519 }
520
521 __ bind(heap_stable);
522
523 __ block_comment("} load_reference_barrier");
524
525 #ifndef _LP64
526 __ pop(thread);
527 #endif
528 }
529
530 //
531 // Arguments:
532 //
533 // Inputs:
534 // src: oop location, might be clobbered
535 // tmp1: scratch register, might not be valid.
536 //
537 // Output:
538 // dst: oop loaded from src location
539 //
540 // Kill:
541 // tmp1 (if it is valid)
542 //
543 void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
544 Register dst, Address src, Register tmp1, Register tmp_thread) {
545 // 1: non-reference load, no additional barrier is needed
546 if (!is_reference_type(type)) {
547 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
548 return;
549 }
593 Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);
594 assert_different_registers(dst, tmp1, tmp_thread);
595 if (!thread->is_valid()) {
596 thread = rdx;
597 }
598 NOT_LP64(__ get_thread(thread));
599 // Generate the SATB pre-barrier code to log the value of
600 // the referent field in an SATB buffer.
601 shenandoah_write_barrier_pre(masm /* masm */,
602 noreg /* obj */,
603 dst /* pre_val */,
604 thread /* thread */,
605 tmp1 /* tmp */,
606 true /* tosca_live */,
607 true /* expand_call */);
608
609 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
610 }
611 }
612
613 void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) {
614 assert(ShenandoahCardBarrier, "Should have been checked by caller");
615
616 // Does a store check for the oop in register obj. The content of
617 // register obj is destroyed afterwards.
618
619 ShenandoahBarrierSet* ctbs = ShenandoahBarrierSet::barrier_set();
620 CardTable* ct = ctbs->card_table();
621
622 __ shrptr(obj, CardTable::card_shift());
623
624 Address card_addr;
625
626 // The calculation for byte_map_base is as follows:
627 // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
628 // So this essentially converts an address to a displacement and it will
629 // never need to be relocated. On 64-bit however the value may be too
630 // large for a 32-bit displacement.
631 intptr_t byte_map_base = (intptr_t)ct->byte_map_base();
632 if (__ is_simm32(byte_map_base)) {
633 card_addr = Address(noreg, obj, Address::times_1, byte_map_base);
634 } else {
635 // By doing it as an ExternalAddress 'byte_map_base' could be converted to a rip-relative
636 // displacement and done in a single instruction given favorable mapping and a
637 // smarter version of as_Address. However, 'ExternalAddress' generates a relocation
638 // entry and that entry is not properly handled by the relocation code.
639 AddressLiteral cardtable((address)byte_map_base, relocInfo::none);
640 Address index(noreg, obj, Address::times_1);
641 card_addr = __ as_Address(ArrayAddress(cardtable, index), rscratch1);
642 }
643
644 int dirty = CardTable::dirty_card_val();
645 if (UseCondCardMark) {
646 Label L_already_dirty;
647 __ cmpb(card_addr, dirty);
648 __ jccb(Assembler::equal, L_already_dirty);
649 __ movb(card_addr, dirty);
650 __ bind(L_already_dirty);
651 } else {
652 __ movb(card_addr, dirty);
653 }
654 }
655
656 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
657 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
658
659 bool on_oop = is_reference_type(type);
660 bool in_heap = (decorators & IN_HEAP) != 0;
661 bool as_normal = (decorators & AS_NORMAL) != 0;
662 if (on_oop && in_heap) {
663 bool needs_pre_barrier = as_normal;
664
665 Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
666 // flatten object address if needed
667 // We do it regardless of precise because we need the registers
668 if (dst.index() == noreg && dst.disp() == 0) {
669 if (dst.base() != tmp1) {
670 __ movptr(tmp1, dst.base());
671 }
672 } else {
673 __ lea(tmp1, dst);
674 }
675
676 assert_different_registers(val, tmp1, tmp2, tmp3, rthread);
677
678 #ifndef _LP64
679 __ get_thread(rthread);
680 InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);
681 imasm->save_bcp();
682 #endif
683
684 if (needs_pre_barrier) {
685 shenandoah_write_barrier_pre(masm /*masm*/,
686 tmp1 /* obj */,
687 tmp2 /* pre_val */,
688 rthread /* thread */,
689 tmp3 /* tmp */,
690 val != noreg /* tosca_live */,
691 false /* expand_call */);
692 }
693
694 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
695 if (val != noreg) {
696 if (ShenandoahCardBarrier) {
697 store_check(masm, tmp1);
698 }
699 }
700 NOT_LP64(imasm->restore_bcp());
701 } else {
702 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
703 }
704 }
705
706 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
707 Register obj, Register tmp, Label& slowpath) {
708 Label done;
709 // Resolve jobject
710 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
711
712 // Check for null.
713 __ testptr(obj, obj);
714 __ jcc(Assembler::zero, done);
715
716 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
717 __ testb(gc_state, ShenandoahHeap::EVACUATION);
718 __ jccb(Assembler::notZero, slowpath);
874 // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
875 // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
876
877 if (exchange) {
878 __ bind(L_failure);
879 __ bind(L_success);
880 } else {
881 assert(res != noreg, "need result register");
882
883 Label exit;
884 __ bind(L_failure);
885 __ xorptr(res, res);
886 __ jmpb(exit);
887
888 __ bind(L_success);
889 __ movptr(res, 1);
890 __ bind(exit);
891 }
892 }
893
894 #ifdef PRODUCT
895 #define BLOCK_COMMENT(str) /* nothing */
896 #else
897 #define BLOCK_COMMENT(str) __ block_comment(str)
898 #endif
899
900 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
901
902 #define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8)
903
904 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
905 Register addr, Register count,
906 Register tmp) {
907 assert(ShenandoahCardBarrier, "Should have been checked by caller");
908
909 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
910 CardTable* ct = bs->card_table();
911 intptr_t disp = (intptr_t) ct->byte_map_base();
912
913 Label L_loop, L_done;
914 const Register end = count;
915 assert_different_registers(addr, end);
916
917 // Zero count? Nothing to do.
918 __ testl(count, count);
919 __ jccb(Assembler::zero, L_done);
920
921 #ifdef _LP64
922 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size
923 __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
924 __ shrptr(addr, CardTable::card_shift());
925 __ shrptr(end, CardTable::card_shift());
926 __ subptr(end, addr); // end --> cards count
927
928 __ mov64(tmp, disp);
929 __ addptr(addr, tmp);
930
931 __ BIND(L_loop);
932 __ movb(Address(addr, count, Address::times_1), 0);
933 __ decrement(count);
934 __ jccb(Assembler::greaterEqual, L_loop);
935 #else
936 __ lea(end, Address(addr, count, Address::times_ptr, -wordSize));
937 __ shrptr(addr, CardTable::card_shift());
938 __ shrptr(end, CardTable::card_shift());
939 __ subptr(end, addr); // end --> count
940
941 __ BIND(L_loop);
942 Address cardtable(addr, count, Address::times_1, disp);
943 __ movb(cardtable, 0);
944 __ decrement(count);
945 __ jccb(Assembler::greaterEqual, L_loop);
946 #endif
947
948 __ BIND(L_done);
949 }
950
951 #undef __
952
953 #ifdef COMPILER1
954
955 #define __ ce->masm()->
956
957 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
958 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
959 // At this point we know that marking is in progress.
960 // If do_load() is true then we have to emit the
961 // load of the previous value; otherwise it has already
962 // been loaded into _pre_val.
963
964 __ bind(*stub->entry());
965 assert(stub->pre_val()->is_register(), "Precondition.");
966
967 Register pre_val_reg = stub->pre_val()->as_register();
968
969 if (stub->do_load()) {
970 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/);
|