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) || 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),
167 src, dst, count);
168 } else
169 #endif
170 {
171 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop),
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) {
538 Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);
539 assert_different_registers(dst, tmp1, tmp_thread);
540 if (!thread->is_valid()) {
541 thread = rdx;
542 }
543 NOT_LP64(__ get_thread(thread));
544 // Generate the SATB pre-barrier code to log the value of
545 // the referent field in an SATB buffer.
546 shenandoah_write_barrier_pre(masm /* masm */,
547 noreg /* obj */,
548 dst /* pre_val */,
549 thread /* thread */,
550 tmp1 /* tmp */,
551 true /* tosca_live */,
552 true /* expand_call */);
553
554 restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
555 }
556 }
557
558 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
559 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
560
561 bool on_oop = is_reference_type(type);
562 bool in_heap = (decorators & IN_HEAP) != 0;
563 bool as_normal = (decorators & AS_NORMAL) != 0;
564 if (on_oop && in_heap) {
565 bool needs_pre_barrier = as_normal;
566
567 Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
568 // flatten object address if needed
569 // We do it regardless of precise because we need the registers
570 if (dst.index() == noreg && dst.disp() == 0) {
571 if (dst.base() != tmp1) {
572 __ movptr(tmp1, dst.base());
573 }
574 } else {
575 __ lea(tmp1, dst);
576 }
577
578 assert_different_registers(val, tmp1, tmp2, tmp3, rthread);
579
580 #ifndef _LP64
581 __ get_thread(rthread);
582 InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);
583 imasm->save_bcp();
584 #endif
585
586 if (needs_pre_barrier) {
587 shenandoah_write_barrier_pre(masm /*masm*/,
588 tmp1 /* obj */,
589 tmp2 /* pre_val */,
590 rthread /* thread */,
591 tmp3 /* tmp */,
592 val != noreg /* tosca_live */,
593 false /* expand_call */);
594 }
595 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
596 NOT_LP64(imasm->restore_bcp());
597 } else {
598 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
599 }
600 }
601
602 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
603 Register obj, Register tmp, Label& slowpath) {
604 Label done;
605 // Resolve jobject
606 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
607
608 // Check for null.
609 __ testptr(obj, obj);
610 __ jcc(Assembler::zero, done);
611
612 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
613 __ testb(gc_state, ShenandoahHeap::EVACUATION);
614 __ jccb(Assembler::notZero, slowpath);
615 __ bind(done);
770 // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
771 // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
772
773 if (exchange) {
774 __ bind(L_failure);
775 __ bind(L_success);
776 } else {
777 assert(res != noreg, "need result register");
778
779 Label exit;
780 __ bind(L_failure);
781 __ xorptr(res, res);
782 __ jmpb(exit);
783
784 __ bind(L_success);
785 __ movptr(res, 1);
786 __ bind(exit);
787 }
788 }
789
790 #undef __
791
792 #ifdef COMPILER1
793
794 #define __ ce->masm()->
795
796 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
797 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
798 // At this point we know that marking is in progress.
799 // If do_load() is true then we have to emit the
800 // load of the previous value; otherwise it has already
801 // been loaded into _pre_val.
802
803 __ bind(*stub->entry());
804 assert(stub->pre_val()->is_register(), "Precondition.");
805
806 Register pre_val_reg = stub->pre_val()->as_register();
807
808 if (stub->do_load()) {
809 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),
192 src, dst, count);
193 } else
194 #endif
195 {
196 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop),
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) {
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);
719 __ bind(done);
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*/);
|