1/*
2 * Copyright (c) 2018, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24#include "precompiled.hpp"
25#include "c1/c1_IR.hpp"
26#include "gc/shared/satbMarkQueue.hpp"
27#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
28#include "gc/shenandoah/shenandoahHeap.hpp"
29#include "gc/shenandoah/shenandoahHeapRegion.hpp"
30#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
31#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
32
33#ifdef ASSERT
34#define __ gen->lir(__FILE__, __LINE__)->
35#else
36#define __ gen->lir()->
37#endif
38
39void ShenandoahPreBarrierStub::emit_code(LIR_Assembler* ce) {
40 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
41 bs->gen_pre_barrier_stub(ce, this);
42}
43
44void ShenandoahLoadReferenceBarrierStub::emit_code(LIR_Assembler* ce) {
45 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
46 bs->gen_load_reference_barrier_stub(ce, this);
47}
48
49void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) {
50 // First we test whether marking is in progress.
51 BasicType flag_type;
52 bool patch = (decorators & C1_NEEDS_PATCHING) != 0;
53 bool do_load = pre_val == LIR_OprFact::illegalOpr;
54 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
55 flag_type = T_INT;
56 } else {
57 guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,
58 "Assumption");
59 // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM,
60 // need to use unsigned instructions to use the large offset to load the satb_mark_queue.
61 flag_type = T_BOOLEAN;
62 }
63 LIR_Opr thrd = gen->getThreadPointer();
64 LIR_Address* mark_active_flag_addr =
65 new LIR_Address(thrd,
66 in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()),
67 flag_type);
68 // Read the marking-in-progress flag.
69 LIR_Opr flag_val = gen->new_register(T_INT);
70 __ load(mark_active_flag_addr, flag_val);
71 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
72
73 LIR_PatchCode pre_val_patch_code = lir_patch_none;
74
75 CodeStub* slow;
76
77 if (do_load) {
78 assert(pre_val == LIR_OprFact::illegalOpr, "sanity");
79 assert(addr_opr != LIR_OprFact::illegalOpr, "sanity");
80
81 if (patch)
82 pre_val_patch_code = lir_patch_normal;
83
84 pre_val = gen->new_register(T_OBJECT);
85
86 if (!addr_opr->is_address()) {
87 assert(addr_opr->is_register(), "must be");
88 addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));
89 }
90 slow = new ShenandoahPreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info ? new CodeEmitInfo(info) : NULL);
91 } else {
92 assert(addr_opr == LIR_OprFact::illegalOpr, "sanity");
93 assert(pre_val->is_register(), "must be");
94 assert(pre_val->type() == T_OBJECT, "must be an object");
95
96 slow = new ShenandoahPreBarrierStub(pre_val);
97 }
98
99 __ branch(lir_cond_notEqual, T_INT, slow);
100 __ branch_destination(slow->continuation());
101}
102
103LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) {
104 if (ShenandoahLoadRefBarrier) {
105 return load_reference_barrier_impl(gen, obj, info, need_null_check);
106 } else {
107 return obj;
108 }
109}
110
111LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) {
112 assert(ShenandoahLoadRefBarrier, "Should be enabled");
113
114 obj = ensure_in_register(gen, obj);
115 assert(obj->is_register(), "must be a register at this point");
116 LIR_Opr result = gen->new_register(T_OBJECT);
117 __ move(obj, result);
118
119 LIR_Opr thrd = gen->getThreadPointer();
120 LIR_Address* active_flag_addr =
121 new LIR_Address(thrd,
122 in_bytes(ShenandoahThreadLocalData::gc_state_offset()),
123 T_BYTE);
124 // Read and check the gc-state-flag.
125 LIR_Opr flag_val = gen->new_register(T_INT);
126 __ load(active_flag_addr, flag_val);
127 LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::HAS_FORWARDED |
128 ShenandoahHeap::EVACUATION |
129 ShenandoahHeap::TRAVERSAL);
130 LIR_Opr mask_reg = gen->new_register(T_INT);
131 __ move(mask, mask_reg);
132
133 if (TwoOperandLIRForm) {
134 __ logical_and(flag_val, mask_reg, flag_val);
135 } else {
136 LIR_Opr masked_flag = gen->new_register(T_INT);
137 __ logical_and(flag_val, mask_reg, masked_flag);
138 flag_val = masked_flag;
139 }
140 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
141
142 CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, result, info ? new CodeEmitInfo(info) : NULL, need_null_check);
143 __ branch(lir_cond_notEqual, T_INT, slow);
144 __ branch_destination(slow->continuation());
145
146 return result;
147}
148
149LIR_Opr ShenandoahBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr obj) {
150 if (!obj->is_register()) {
151 LIR_Opr obj_reg = gen->new_register(T_OBJECT);
152 if (obj->is_constant()) {
153 __ move(obj, obj_reg);
154 } else {
155 __ leal(obj, obj_reg);
156 }
157 obj = obj_reg;
158 }
159 return obj;
160}
161
162LIR_Opr ShenandoahBarrierSetC1::storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators) {
163 if (ShenandoahStoreValEnqueueBarrier) {
164 obj = ensure_in_register(gen, obj);
165 pre_barrier(gen, info, decorators, LIR_OprFact::illegalOpr, obj);
166 }
167 return obj;
168}
169
170void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) {
171 if (access.is_oop()) {
172 if (ShenandoahSATBBarrier) {
173 pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), access.resolved_addr(), LIR_OprFact::illegalOpr /* pre_val */);
174 }
175 value = storeval_barrier(access.gen(), value, access.access_emit_info(), access.decorators());
176 }
177 BarrierSetC1::store_at_resolved(access, value);
178}
179
180void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) {
181 if (!access.is_oop()) {
182 BarrierSetC1::load_at_resolved(access, result);
183 return;
184 }
185
186 LIRGenerator *gen = access.gen();
187
188 if (ShenandoahLoadRefBarrier) {
189 LIR_Opr tmp = gen->new_register(T_OBJECT);
190 BarrierSetC1::load_at_resolved(access, tmp);
191 tmp = load_reference_barrier(access.gen(), tmp, access.access_emit_info(), true);
192 __ move(tmp, result);
193 } else {
194 BarrierSetC1::load_at_resolved(access, result);
195 }
196
197 if (ShenandoahKeepAliveBarrier) {
198 DecoratorSet decorators = access.decorators();
199 bool is_weak = (decorators & ON_WEAK_OOP_REF) != 0;
200 bool is_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
201 bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
202 if (is_weak || is_phantom || is_anonymous) {
203 // Register the value in the referent field with the pre-barrier
204 LabelObj *Lcont_anonymous;
205 if (is_anonymous) {
206 Lcont_anonymous = new LabelObj();
207 generate_referent_check(access, Lcont_anonymous);
208 }
209 pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr /* addr_opr */,
210 result /* pre_val */);
211 if (is_anonymous) {
212 __ branch_destination(Lcont_anonymous->label());
213 }
214 }
215 }
216}
217
218class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure {
219 virtual OopMapSet* generate_code(StubAssembler* sasm) {
220 ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
221 bs->generate_c1_pre_barrier_runtime_stub(sasm);
222 return NULL;
223 }
224};
225
226void ShenandoahBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) {
227 C1ShenandoahPreBarrierCodeGenClosure pre_code_gen_cl;
228 _pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1,
229 "shenandoah_pre_barrier_slow",
230 false, &pre_code_gen_cl);
231}
232