1 /*
2 * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
3 * Copyright (c) 2025, Oracle and/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 #ifndef SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
27 #define SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
28
29 #include "c1/c1_CodeStubs.hpp"
30 #include "gc/shared/c1/barrierSetC1.hpp"
31
32 class ShenandoahPreBarrierStub: public CodeStub {
33 friend class ShenandoahBarrierSetC1;
34 private:
35 bool _do_load;
36 LIR_Opr _addr;
37 LIR_Opr _pre_val;
38 LIR_PatchCode _patch_code;
39 CodeEmitInfo* _info;
40
41 public:
42 // Version that _does_ generate a load of the previous value from addr.
43 // addr (the address of the field to be read) must be a LIR_Address
44 // pre_val (a temporary register) must be a register;
45 ShenandoahPreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
46 _do_load(true), _addr(addr), _pre_val(pre_val),
47 _patch_code(patch_code), _info(info)
48 {
49 assert(_pre_val->is_register(), "should be temporary register");
50 assert(_addr->is_address(), "should be the address of the field");
51 FrameMap* f = Compilation::current()->frame_map();
52 f->update_reserved_argument_area_size(2 * BytesPerWord);
53 }
54
55 // Version that _does not_ generate load of the previous value; the
56 // previous value is assumed to have already been loaded into pre_val.
57 ShenandoahPreBarrierStub(LIR_Opr pre_val) :
58 _do_load(false), _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val),
59 _patch_code(lir_patch_none), _info(nullptr)
60 {
61 assert(_pre_val->is_register(), "should be a register");
62 }
63
64 LIR_Opr addr() const { return _addr; }
65 LIR_Opr pre_val() const { return _pre_val; }
66 LIR_PatchCode patch_code() const { return _patch_code; }
67 CodeEmitInfo* info() const { return _info; }
68 bool do_load() const { return _do_load; }
69
70 virtual void emit_code(LIR_Assembler* e);
71 virtual void visit(LIR_OpVisitState* visitor) {
72 if (_do_load) {
73 // don't pass in the code emit info since it's processed in the fast
74 // path
75 if (_info != nullptr)
76 visitor->do_slow_case(_info);
77 else
78 visitor->do_slow_case();
79
80 visitor->do_input(_addr);
81 visitor->do_temp(_pre_val);
82 } else {
83 visitor->do_slow_case();
84 visitor->do_input(_pre_val);
85 }
86 }
87 #ifndef PRODUCT
88 virtual void print_name(outputStream* out) const { out->print("ShenandoahPreBarrierStub"); }
89 #endif // PRODUCT
90 };
91
92 class ShenandoahLoadReferenceBarrierStub: public CodeStub {
93 friend class ShenandoahBarrierSetC1;
94 private:
95 LIR_Opr _obj;
96 LIR_Opr _addr;
97 LIR_Opr _result;
98 LIR_Opr _tmp1;
99 LIR_Opr _tmp2;
100 DecoratorSet _decorators;
101 public:
102 ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr addr, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2, DecoratorSet decorators) :
103 _obj(obj), _addr(addr), _result(result), _tmp1(tmp1), _tmp2(tmp2), _decorators(decorators)
104 {
105 assert(_obj->is_register(), "should be register");
106 assert(_addr->is_register(), "should be register");
107 assert(_result->is_register(), "should be register");
108 assert(_tmp1->is_register(), "should be register");
109 assert(_tmp2->is_register(), "should be register");
110
111 FrameMap* f = Compilation::current()->frame_map();
112 f->update_reserved_argument_area_size(2 * BytesPerWord);
113 }
114
115 LIR_Opr obj() const { return _obj; }
116 LIR_Opr addr() const { return _addr; }
117 LIR_Opr result() const { return _result; }
118 LIR_Opr tmp1() const { return _tmp1; }
119 LIR_Opr tmp2() const { return _tmp2; }
120 DecoratorSet decorators() const { return _decorators; }
121
122 virtual void emit_code(LIR_Assembler* e);
123 virtual void visit(LIR_OpVisitState* visitor) {
124 visitor->do_slow_case();
125 visitor->do_input(_obj);
126 visitor->do_temp(_obj);
127 visitor->do_input(_addr);
128 visitor->do_temp(_addr);
129 visitor->do_temp(_result);
130 visitor->do_temp(_tmp1);
131 visitor->do_temp(_tmp2);
132 }
133 #ifndef PRODUCT
134 virtual void print_name(outputStream* out) const { out->print("ShenandoahLoadReferenceBarrierStub"); }
135 #endif // PRODUCT
136 };
137
138 class LIR_OpShenandoahCompareAndSwap : public LIR_Op {
139 friend class LIR_OpVisitState;
140
141 private:
142 LIR_Opr _addr;
143 LIR_Opr _cmp_value;
144 LIR_Opr _new_value;
145 LIR_Opr _tmp1;
146 LIR_Opr _tmp2;
147
148 public:
149 LIR_OpShenandoahCompareAndSwap(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
150 LIR_Opr t1, LIR_Opr t2, LIR_Opr result)
151 : LIR_Op(lir_none, result, nullptr) // no info
152 , _addr(addr)
153 , _cmp_value(cmp_value)
154 , _new_value(new_value)
155 , _tmp1(t1)
156 , _tmp2(t2) { }
157
158 LIR_Opr addr() const { return _addr; }
159 LIR_Opr cmp_value() const { return _cmp_value; }
160 LIR_Opr new_value() const { return _new_value; }
161 LIR_Opr tmp1() const { return _tmp1; }
162 LIR_Opr tmp2() const { return _tmp2; }
163
164 virtual void visit(LIR_OpVisitState* state) {
165 if (_info) state->do_info(_info);
166 assert(_addr->is_valid(), "used"); state->do_input(_addr);
167 state->do_temp(_addr);
168 assert(_cmp_value->is_valid(), "used"); state->do_input(_cmp_value);
169 state->do_temp(_cmp_value);
170 assert(_new_value->is_valid(), "used"); state->do_input(_new_value);
171 state->do_temp(_new_value);
172 if (_tmp1->is_valid()) state->do_temp(_tmp1);
173 if (_tmp2->is_valid()) state->do_temp(_tmp2);
174 if (_result->is_valid()) state->do_output(_result);
175 }
176
177 virtual void emit_code(LIR_Assembler* masm);
178
179 virtual void print_instr(outputStream* out) const {
180 addr()->print(out); out->print(" ");
181 cmp_value()->print(out); out->print(" ");
182 new_value()->print(out); out->print(" ");
183 tmp1()->print(out); out->print(" ");
184 tmp2()->print(out); out->print(" ");
185 }
186 #ifndef PRODUCT
187 virtual const char* name() const {
188 return "shenandoah_cas_obj";
189 }
190 #endif // PRODUCT
191 };
192
193 class AOTCodeAddressTable;
194
195 class ShenandoahBarrierSetC1 : public BarrierSetC1 {
196 friend class AOTCodeAddressTable;
197 private:
198 CodeBlob* _pre_barrier_c1_runtime_code_blob;
199 CodeBlob* _load_reference_barrier_strong_rt_code_blob;
200 CodeBlob* _load_reference_barrier_strong_native_rt_code_blob;
201 CodeBlob* _load_reference_barrier_weak_rt_code_blob;
202 CodeBlob* _load_reference_barrier_phantom_rt_code_blob;
203
204 void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val);
205
206 LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators);
207
208 LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators);
209
210 LIR_Opr ensure_in_register(LIRGenerator* gen, LIR_Opr obj, BasicType type);
211
212 public:
213 ShenandoahBarrierSetC1();
214
215 CodeBlob* pre_barrier_c1_runtime_code_blob() {
216 assert(_pre_barrier_c1_runtime_code_blob != nullptr, "");
217 return _pre_barrier_c1_runtime_code_blob;
218 }
219
220 CodeBlob* load_reference_barrier_strong_rt_code_blob() {
221 assert(_load_reference_barrier_strong_rt_code_blob != nullptr, "");
222 return _load_reference_barrier_strong_rt_code_blob;
223 }
224
225 CodeBlob* load_reference_barrier_strong_native_rt_code_blob() {
226 assert(_load_reference_barrier_strong_native_rt_code_blob != nullptr, "");
227 return _load_reference_barrier_strong_native_rt_code_blob;
228 }
229
230 CodeBlob* load_reference_barrier_weak_rt_code_blob() {
231 assert(_load_reference_barrier_weak_rt_code_blob != nullptr, "");
232 return _load_reference_barrier_weak_rt_code_blob;
233 }
234
235 CodeBlob* load_reference_barrier_phantom_rt_code_blob() {
236 assert(_load_reference_barrier_phantom_rt_code_blob != nullptr, "");
237 return _load_reference_barrier_phantom_rt_code_blob;
238 }
239
240 protected:
241
242 virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
243 virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register);
244 virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
245
246 virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
247
248 virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value);
249
250 void post_barrier(LIRAccess& access, LIR_Opr addr, LIR_Opr new_val);
251
252 public:
253
254 virtual bool generate_c1_runtime_stubs(BufferBlob* buffer_blob);
255 };
256
257 #endif // SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP