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