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#ifndef SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
25#define SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
26
27#include "c1/c1_CodeStubs.hpp"
28#include "gc/shared/c1/barrierSetC1.hpp"
29
30class ShenandoahPreBarrierStub: public CodeStub {
31 friend class ShenandoahBarrierSetC1;
32private:
33 bool _do_load;
34 LIR_Opr _addr;
35 LIR_Opr _pre_val;
36 LIR_PatchCode _patch_code;
37 CodeEmitInfo* _info;
38
39public:
40 // Version that _does_ generate a load of the previous value from addr.
41 // addr (the address of the field to be read) must be a LIR_Address
42 // pre_val (a temporary register) must be a register;
43 ShenandoahPreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
44 _do_load(true), _addr(addr), _pre_val(pre_val),
45 _patch_code(patch_code), _info(info)
46 {
47 assert(_pre_val->is_register(), "should be temporary register");
48 assert(_addr->is_address(), "should be the address of the field");
49 }
50
51 // Version that _does not_ generate load of the previous value; the
52 // previous value is assumed to have already been loaded into pre_val.
53 ShenandoahPreBarrierStub(LIR_Opr pre_val) :
54 _do_load(false), _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val),
55 _patch_code(lir_patch_none), _info(NULL)
56 {
57 assert(_pre_val->is_register(), "should be a register");
58 }
59
60 LIR_Opr addr() const { return _addr; }
61 LIR_Opr pre_val() const { return _pre_val; }
62 LIR_PatchCode patch_code() const { return _patch_code; }
63 CodeEmitInfo* info() const { return _info; }
64 bool do_load() const { return _do_load; }
65
66 virtual void emit_code(LIR_Assembler* e);
67 virtual void visit(LIR_OpVisitState* visitor) {
68 if (_do_load) {
69 // don't pass in the code emit info since it's processed in the fast
70 // path
71 if (_info != NULL)
72 visitor->do_slow_case(_info);
73 else
74 visitor->do_slow_case();
75
76 visitor->do_input(_addr);
77 visitor->do_temp(_pre_val);
78 } else {
79 visitor->do_slow_case();
80 visitor->do_input(_pre_val);
81 }
82 }
83#ifndef PRODUCT
84 virtual void print_name(outputStream* out) const { out->print("ShenandoahPreBarrierStub"); }
85#endif // PRODUCT
86};
87
88class ShenandoahLoadReferenceBarrierStub: public CodeStub {
89 friend class ShenandoahBarrierSetC1;
90private:
91 LIR_Opr _obj;
92 LIR_Opr _result;
93 CodeEmitInfo* _info;
94 bool _needs_null_check;
95
96public:
97 ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr result, CodeEmitInfo* info, bool needs_null_check) :
98 _obj(obj), _result(result), _info(info), _needs_null_check(needs_null_check)
99 {
100 assert(_obj->is_register(), "should be register");
101 assert(_result->is_register(), "should be register");
102 }
103
104 LIR_Opr obj() const { return _obj; }
105 LIR_Opr result() const { return _result; }
106 CodeEmitInfo* info() const { return _info; }
107 bool needs_null_check() const { return _needs_null_check; }
108
109 virtual void emit_code(LIR_Assembler* e);
110 virtual void visit(LIR_OpVisitState* visitor) {
111 visitor->do_slow_case();
112 visitor->do_input(_obj);
113 visitor->do_temp(_result);
114 }
115#ifndef PRODUCT
116 virtual void print_name(outputStream* out) const { out->print("ShenandoahLoadReferenceBarrierStub"); }
117#endif // PRODUCT
118};
119
120class LIR_OpShenandoahCompareAndSwap : public LIR_Op {
121 friend class LIR_OpVisitState;
122
123private:
124 LIR_Opr _addr;
125 LIR_Opr _cmp_value;
126 LIR_Opr _new_value;
127 LIR_Opr _tmp1;
128 LIR_Opr _tmp2;
129
130public:
131 LIR_OpShenandoahCompareAndSwap(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
132 LIR_Opr t1, LIR_Opr t2, LIR_Opr result)
133 : LIR_Op(lir_none, result, NULL) // no info
134 , _addr(addr)
135 , _cmp_value(cmp_value)
136 , _new_value(new_value)
137 , _tmp1(t1)
138 , _tmp2(t2) { }
139
140 LIR_Opr addr() const { return _addr; }
141 LIR_Opr cmp_value() const { return _cmp_value; }
142 LIR_Opr new_value() const { return _new_value; }
143 LIR_Opr tmp1() const { return _tmp1; }
144 LIR_Opr tmp2() const { return _tmp2; }
145
146 virtual void visit(LIR_OpVisitState* state) {
147 assert(_addr->is_valid(), "used");
148 assert(_cmp_value->is_valid(), "used");
149 assert(_new_value->is_valid(), "used");
150 if (_info) state->do_info(_info);
151 state->do_input(_addr);
152 state->do_temp(_addr);
153 state->do_input(_cmp_value);
154 state->do_temp(_cmp_value);
155 state->do_input(_new_value);
156 state->do_temp(_new_value);
157 if (_tmp1->is_valid()) state->do_temp(_tmp1);
158 if (_tmp2->is_valid()) state->do_temp(_tmp2);
159 if (_result->is_valid()) state->do_output(_result);
160 }
161
162 virtual void emit_code(LIR_Assembler* masm);
163
164 virtual void print_instr(outputStream* out) const {
165 addr()->print(out); out->print(" ");
166 cmp_value()->print(out); out->print(" ");
167 new_value()->print(out); out->print(" ");
168 tmp1()->print(out); out->print(" ");
169 tmp2()->print(out); out->print(" ");
170 }
171#ifndef PRODUCT
172 virtual const char* name() const {
173 return "shenandoah_cas_obj";
174 }
175#endif // PRODUCT
176};
177
178class ShenandoahBarrierSetC1 : public BarrierSetC1 {
179private:
180 CodeBlob* _pre_barrier_c1_runtime_code_blob;
181
182 void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val);
183
184 LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check);
185 LIR_Opr storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators);
186
187 LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check);
188
189 LIR_Opr ensure_in_register(LIRGenerator* gen, LIR_Opr obj);
190
191public:
192 CodeBlob* pre_barrier_c1_runtime_code_blob() { return _pre_barrier_c1_runtime_code_blob; }
193
194protected:
195
196 virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
197 virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
198
199 virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
200
201 virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value);
202
203public:
204
205 virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob);
206};
207
208#endif // SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
209