1 /*
2  * Copyright (c) 2018, 2020, 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 
30 class ShenandoahPreBarrierStub: public CodeStub {
31   friend class ShenandoahBarrierSetC1;
32 private:
33   bool _do_load;
34   LIR_Opr _addr;
35   LIR_Opr _pre_val;
36   LIR_PatchCode _patch_code;
37   CodeEmitInfo* _info;
38 
39 public:
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;
ShenandoahPreBarrierStub(LIR_Opr addr,LIR_Opr pre_val,LIR_PatchCode patch_code,CodeEmitInfo * info)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.
ShenandoahPreBarrierStub(LIR_Opr 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 
addr() const60   LIR_Opr addr() const { return _addr; }
pre_val() const61   LIR_Opr pre_val() const { return _pre_val; }
patch_code() const62   LIR_PatchCode patch_code() const { return _patch_code; }
info() const63   CodeEmitInfo* info() const { return _info; }
do_load() const64   bool do_load() const { return _do_load; }
65 
66   virtual void emit_code(LIR_Assembler* e);
visit(LIR_OpVisitState * visitor)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
print_name(outputStream * out) const84   virtual void print_name(outputStream* out) const { out->print("ShenandoahPreBarrierStub"); }
85 #endif // PRODUCT
86 };
87 
88 class ShenandoahLoadReferenceBarrierStub: public CodeStub {
89   friend class ShenandoahBarrierSetC1;
90 private:
91   LIR_Opr _obj;
92   LIR_Opr _addr;
93   LIR_Opr _result;
94   LIR_Opr _tmp1;
95   LIR_Opr _tmp2;
96 
97 public:
ShenandoahLoadReferenceBarrierStub(LIR_Opr obj,LIR_Opr addr,LIR_Opr result,LIR_Opr tmp1,LIR_Opr tmp2)98   ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr addr, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2) :
99     _obj(obj), _addr(addr), _result(result), _tmp1(tmp1), _tmp2(tmp2)
100   {
101     assert(_obj->is_register(), "should be register");
102     assert(_addr->is_register(), "should be register");
103     assert(_result->is_register(), "should be register");
104     assert(_tmp1->is_register(), "should be register");
105     assert(_tmp2->is_register(), "should be register");
106   }
107 
obj() const108   LIR_Opr obj() const { return _obj; }
addr() const109   LIR_Opr addr() const { return _addr; }
result() const110   LIR_Opr result() const { return _result; }
tmp1() const111   LIR_Opr tmp1() const { return _tmp1; }
tmp2() const112   LIR_Opr tmp2() const { return _tmp2; }
113 
114   virtual void emit_code(LIR_Assembler* e);
visit(LIR_OpVisitState * visitor)115   virtual void visit(LIR_OpVisitState* visitor) {
116     visitor->do_slow_case();
117     visitor->do_input(_obj);
118     visitor->do_temp(_obj);
119     visitor->do_input(_addr);
120     visitor->do_temp(_addr);
121     visitor->do_temp(_result);
122     visitor->do_temp(_tmp1);
123     visitor->do_temp(_tmp2);
124   }
125 #ifndef PRODUCT
print_name(outputStream * out) const126   virtual void print_name(outputStream* out) const { out->print("ShenandoahLoadReferenceBarrierStub"); }
127 #endif // PRODUCT
128 };
129 
130 class LIR_OpShenandoahCompareAndSwap : public LIR_Op {
131  friend class LIR_OpVisitState;
132 
133 private:
134   LIR_Opr _addr;
135   LIR_Opr _cmp_value;
136   LIR_Opr _new_value;
137   LIR_Opr _tmp1;
138   LIR_Opr _tmp2;
139 
140 public:
LIR_OpShenandoahCompareAndSwap(LIR_Opr addr,LIR_Opr cmp_value,LIR_Opr new_value,LIR_Opr t1,LIR_Opr t2,LIR_Opr result)141   LIR_OpShenandoahCompareAndSwap(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
142                                  LIR_Opr t1, LIR_Opr t2, LIR_Opr result)
143     : LIR_Op(lir_none, result, NULL)  // no info
144     , _addr(addr)
145     , _cmp_value(cmp_value)
146     , _new_value(new_value)
147     , _tmp1(t1)
148     , _tmp2(t2)                                  { }
149 
addr() const150   LIR_Opr addr()        const                    { return _addr;  }
cmp_value() const151   LIR_Opr cmp_value()   const                    { return _cmp_value; }
new_value() const152   LIR_Opr new_value()   const                    { return _new_value; }
tmp1() const153   LIR_Opr tmp1()        const                    { return _tmp1;      }
tmp2() const154   LIR_Opr tmp2()        const                    { return _tmp2;      }
155 
visit(LIR_OpVisitState * state)156   virtual void visit(LIR_OpVisitState* state) {
157       assert(_addr->is_valid(),      "used");
158       assert(_cmp_value->is_valid(), "used");
159       assert(_new_value->is_valid(), "used");
160       if (_info)                    state->do_info(_info);
161                                     state->do_input(_addr);
162                                     state->do_temp(_addr);
163                                     state->do_input(_cmp_value);
164                                     state->do_temp(_cmp_value);
165                                     state->do_input(_new_value);
166                                     state->do_temp(_new_value);
167       if (_tmp1->is_valid())        state->do_temp(_tmp1);
168       if (_tmp2->is_valid())        state->do_temp(_tmp2);
169       if (_result->is_valid())      state->do_output(_result);
170   }
171 
172   virtual void emit_code(LIR_Assembler* masm);
173 
print_instr(outputStream * out) const174   virtual void print_instr(outputStream* out) const {
175     addr()->print(out);      out->print(" ");
176     cmp_value()->print(out); out->print(" ");
177     new_value()->print(out); out->print(" ");
178     tmp1()->print(out);      out->print(" ");
179     tmp2()->print(out);      out->print(" ");
180   }
181 #ifndef PRODUCT
name() const182   virtual const char* name() const {
183     return "shenandoah_cas_obj";
184   }
185 #endif // PRODUCT
186 };
187 
188 class ShenandoahBarrierSetC1 : public BarrierSetC1 {
189 private:
190   CodeBlob* _pre_barrier_c1_runtime_code_blob;
191   CodeBlob* _load_reference_barrier_rt_code_blob;
192 
193   void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val);
194 
195   LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr);
196   LIR_Opr iu_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators);
197 
198   LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr);
199 
200   LIR_Opr ensure_in_register(LIRGenerator* gen, LIR_Opr obj, BasicType type);
201 
202 public:
203   ShenandoahBarrierSetC1();
204 
pre_barrier_c1_runtime_code_blob()205   CodeBlob* pre_barrier_c1_runtime_code_blob() {
206     assert(_pre_barrier_c1_runtime_code_blob != NULL, "");
207     return _pre_barrier_c1_runtime_code_blob;
208   }
209 
load_reference_barrier_rt_code_blob()210   CodeBlob* load_reference_barrier_rt_code_blob() {
211     assert(_load_reference_barrier_rt_code_blob != NULL, "");
212     return _load_reference_barrier_rt_code_blob;
213   }
214 
215 protected:
216 
217   virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
218   virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register);
219   virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
220 
221   virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
222 
223   virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value);
224 
225 public:
226 
227   virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob);
228 };
229 
230 #endif // SHARE_GC_SHENANDOAH_C1_SHENANDOAHBARRIERSETC1_HPP
231