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 __ shrptr(obj, CardTable::card_shift());
619
620 // We'll use this register as the TLS base address and also later on
621 // to hold the byte_map_base.
622 Register thread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
623 Register tmp = LP64_ONLY(rscratch1) NOT_LP64(rdx);
624
625 #ifndef _LP64
626 // The next two ifs are just to get temporary registers to use for TLS and card table base.
627 if (thread == obj) {
628 thread = rdx;
629 tmp = rsi;
630 }
631 if (tmp == obj) {
632 tmp = rsi;
633 }
634
635 __ push(thread);
636 __ push(tmp);
637 __ get_thread(thread);
638 #endif
639
640 Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
641 __ movptr(tmp, curr_ct_holder_addr);
642 Address card_addr(tmp, obj, Address::times_1);
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 #ifndef _LP64
656 __ pop(tmp);
657 __ pop(thread);
658 #endif
659 }
660
661 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
662 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
663
664 bool on_oop = is_reference_type(type);
665 bool in_heap = (decorators & IN_HEAP) != 0;
666 bool as_normal = (decorators & AS_NORMAL) != 0;
667 if (on_oop && in_heap) {
668 bool needs_pre_barrier = as_normal;
669
670 Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
671 // flatten object address if needed
672 // We do it regardless of precise because we need the registers
673 if (dst.index() == noreg && dst.disp() == 0) {
674 if (dst.base() != tmp1) {
675 __ movptr(tmp1, dst.base());
676 }
677 } else {
678 __ lea(tmp1, dst);
679 }
680
681 assert_different_registers(val, tmp1, tmp2, tmp3, rthread);
682
683 #ifndef _LP64
684 __ get_thread(rthread);
685 InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);
686 imasm->save_bcp();
687 #endif
688
689 if (needs_pre_barrier) {
690 shenandoah_write_barrier_pre(masm /*masm*/,
691 tmp1 /* obj */,
692 tmp2 /* pre_val */,
693 rthread /* thread */,
694 tmp3 /* tmp */,
695 val != noreg /* tosca_live */,
696 false /* expand_call */);
697 }
698
699 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
700 if (val != noreg) {
701 if (ShenandoahCardBarrier) {
702 store_check(masm, tmp1);
703 }
704 }
705 NOT_LP64(imasm->restore_bcp());
706 } else {
707 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
708 }
709 }
710
711 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
712 Register obj, Register tmp, Label& slowpath) {
713 Label done;
714 // Resolve jobject
715 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
716
717 // Check for null.
718 __ testptr(obj, obj);
719 __ jcc(Assembler::zero, done);
720
721 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
722 __ testb(gc_state, ShenandoahHeap::EVACUATION);
723 __ jccb(Assembler::notZero, slowpath);
879 // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
880 // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
881
882 if (exchange) {
883 __ bind(L_failure);
884 __ bind(L_success);
885 } else {
886 assert(res != noreg, "need result register");
887
888 Label exit;
889 __ bind(L_failure);
890 __ xorptr(res, res);
891 __ jmpb(exit);
892
893 __ bind(L_success);
894 __ movptr(res, 1);
895 __ bind(exit);
896 }
897 }
898
899 #ifdef PRODUCT
900 #define BLOCK_COMMENT(str) /* nothing */
901 #else
902 #define BLOCK_COMMENT(str) __ block_comment(str)
903 #endif
904
905 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
906
907 #define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8)
908
909 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
910 Register addr, Register count,
911 Register tmp) {
912 assert(ShenandoahCardBarrier, "Should have been checked by caller");
913
914 Label L_loop, L_done;
915 const Register end = count;
916 assert_different_registers(addr, end);
917
918 // Zero count? Nothing to do.
919 __ testl(count, count);
920 __ jccb(Assembler::zero, L_done);
921
922 #ifdef _LP64
923 const Register thread = r15_thread;
924 Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
925 __ movptr(tmp, curr_ct_holder_addr);
926
927 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size
928 __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
929 __ shrptr(addr, CardTable::card_shift());
930 __ shrptr(end, CardTable::card_shift());
931 __ subptr(end, addr); // end --> cards count
932
933 __ addptr(addr, tmp);
934
935 __ BIND(L_loop);
936 __ movb(Address(addr, count, Address::times_1), 0);
937 __ decrement(count);
938 __ jccb(Assembler::greaterEqual, L_loop);
939 #else
940 const Register thread = tmp;
941 __ get_thread(thread);
942
943 Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
944 __ movptr(tmp, curr_ct_holder_addr);
945
946 __ lea(end, Address(addr, count, Address::times_ptr, -wordSize));
947 __ shrptr(addr, CardTable::card_shift());
948 __ shrptr(end, CardTable::card_shift());
949 __ subptr(end, addr); // end --> count
950
951 __ addptr(addr, tmp);
952
953 __ BIND(L_loop);
954 Address cardtable(addr, count, Address::times_1, 0);
955 __ movb(cardtable, 0);
956 __ decrement(count);
957 __ jccb(Assembler::greaterEqual, L_loop);
958 #endif
959
960 __ BIND(L_done);
961 }
962
963 #undef __
964
965 #ifdef COMPILER1
966
967 #define __ ce->masm()->
968
969 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
970 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
971 // At this point we know that marking is in progress.
972 // If do_load() is true then we have to emit the
973 // load of the previous value; otherwise it has already
974 // been loaded into _pre_val.
975
976 __ bind(*stub->entry());
977 assert(stub->pre_val()->is_register(), "Precondition.");
978
979 Register pre_val_reg = stub->pre_val()->as_register();
980
981 if (stub->do_load()) {
982 ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/);
|