1 /* 2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. 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 #include "precompiled.hpp" 25 #include "c1/c1_LIR.hpp" 26 #include "c1/c1_LIRGenerator.hpp" 27 #include "c1/c1_CodeStubs.hpp" 28 #include "gc/z/c1/zBarrierSetC1.hpp" 29 #include "gc/z/zBarrierSet.hpp" 30 #include "gc/z/zBarrierSetAssembler.hpp" 31 #include "gc/z/zThreadLocalData.hpp" 32 #include "utilities/macros.hpp" 33 34 ZLoadBarrierStubC1::ZLoadBarrierStubC1(LIRAccess& access, LIR_Opr ref, address runtime_stub) : 35 _decorators(access.decorators()), 36 _ref_addr(access.resolved_addr()), 37 _ref(ref), 38 _tmp(LIR_OprFact::illegalOpr), 39 _patch_info(access.patch_emit_info()), 40 _runtime_stub(runtime_stub) { 41 42 // Allocate tmp register if needed 43 if (!_ref_addr->is_register()) { 44 assert(_ref_addr->is_address(), "Must be an address"); 45 if (_ref_addr->as_address_ptr()->index()->is_valid() || 46 _ref_addr->as_address_ptr()->disp() != 0) { 47 // Has index or displacement, need tmp register to load address into 48 _tmp = access.gen()->new_pointer_register(); 49 } else { 50 // No index or displacement, address available in base register 51 _ref_addr = _ref_addr->as_address_ptr()->base(); 52 } 53 } 54 55 assert(_ref->is_register(), "Must be a register"); 56 assert(_ref_addr->is_register() != _tmp->is_register(), "Only one should be a register"); 57 } 58 59 DecoratorSet ZLoadBarrierStubC1::decorators() const { 60 return _decorators; 61 } 62 63 LIR_Opr ZLoadBarrierStubC1::ref() const { 64 return _ref; 65 } 66 67 LIR_Opr ZLoadBarrierStubC1::ref_addr() const { 68 return _ref_addr; 69 } 70 71 LIR_Opr ZLoadBarrierStubC1::tmp() const { 72 return _tmp; 73 } 74 75 LIR_PatchCode ZLoadBarrierStubC1::patch_code() const { 76 return (_decorators & C1_NEEDS_PATCHING) != 0 ? lir_patch_normal : lir_patch_none; 77 } 78 79 CodeEmitInfo*& ZLoadBarrierStubC1::patch_info() { 80 return _patch_info; 81 } 82 83 address ZLoadBarrierStubC1::runtime_stub() const { 84 return _runtime_stub; 85 } 86 87 void ZLoadBarrierStubC1::visit(LIR_OpVisitState* visitor) { 88 if (_patch_info != NULL) { 89 visitor->do_slow_case(_patch_info); 90 } else { 91 visitor->do_slow_case(); 92 } 93 94 visitor->do_input(_ref_addr); 95 visitor->do_output(_ref); 96 97 if (_tmp->is_valid()) { 98 visitor->do_temp(_tmp); 99 } 100 } 101 102 void ZLoadBarrierStubC1::emit_code(LIR_Assembler* ce) { 103 ZBarrierSet::assembler()->generate_c1_load_barrier_stub(ce, this); 104 } 105 106 #ifndef PRODUCT 107 void ZLoadBarrierStubC1::print_name(outputStream* out) const { 108 out->print("ZLoadBarrierStubC1"); 109 } 110 #endif // PRODUCT 111 112 class LIR_OpZLoadBarrierTest : public LIR_Op { 113 private: 114 LIR_Opr _opr; 115 116 public: 117 LIR_OpZLoadBarrierTest(LIR_Opr opr) : 118 LIR_Op(), 119 _opr(opr) {} 120 121 virtual void visit(LIR_OpVisitState* state) { 122 state->do_input(_opr); 123 } 124 125 virtual void emit_code(LIR_Assembler* ce) { 126 ZBarrierSet::assembler()->generate_c1_load_barrier_test(ce, _opr); 127 } 128 129 virtual void print_instr(outputStream* out) const { 130 _opr->print(out); 131 out->print(" "); 132 } 133 134 #ifndef PRODUCT 135 virtual const char* name() const { 136 return "lir_z_load_barrier_test"; 137 } 138 #endif // PRODUCT 139 }; 140 141 static bool barrier_needed(LIRAccess& access) { 142 return ZBarrierSet::barrier_needed(access.decorators(), access.type()); 143 } 144 145 ZBarrierSetC1::ZBarrierSetC1() : 146 _load_barrier_on_oop_field_preloaded_runtime_stub(NULL), 147 _load_barrier_on_weak_oop_field_preloaded_runtime_stub(NULL) {} 148 149 address ZBarrierSetC1::load_barrier_on_oop_field_preloaded_runtime_stub(DecoratorSet decorators) const { 150 assert((decorators & ON_PHANTOM_OOP_REF) == 0, "Unsupported decorator"); 151 //assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Unsupported decorator"); 152 153 if ((decorators & ON_WEAK_OOP_REF) != 0) { 154 return _load_barrier_on_weak_oop_field_preloaded_runtime_stub; 155 } else { 156 return _load_barrier_on_oop_field_preloaded_runtime_stub; 157 } 158 } 159 160 #ifdef ASSERT 161 #define __ access.gen()->lir(__FILE__, __LINE__)-> 162 #else 163 #define __ access.gen()->lir()-> 164 #endif 165 166 void ZBarrierSetC1::load_barrier(LIRAccess& access, LIR_Opr result) const { 167 // Fast path 168 __ append(new LIR_OpZLoadBarrierTest(result)); 169 170 // Slow path 171 const address runtime_stub = load_barrier_on_oop_field_preloaded_runtime_stub(access.decorators()); 172 CodeStub* const stub = new ZLoadBarrierStubC1(access, result, runtime_stub); 173 __ branch(lir_cond_notEqual, T_ADDRESS, stub); 174 __ branch_destination(stub->continuation()); 175 } 176 177 #undef __ 178 179 void ZBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { 180 BarrierSetC1::load_at_resolved(access, result); 181 182 if (barrier_needed(access)) { 183 load_barrier(access, result); 184 } 185 } 186 187 static void pre_load_barrier(LIRAccess& access) { 188 DecoratorSet decorators = access.decorators(); 189 190 // Downgrade access to MO_UNORDERED 191 decorators = (decorators & ~MO_DECORATOR_MASK) | MO_UNORDERED; 192 193 // Remove C1_WRITE_ACCESS 194 decorators = (decorators & ~C1_WRITE_ACCESS); 195 196 // Generate synthetic load at 197 access.gen()->access_load_at(decorators, 198 access.type(), 199 access.base().item(), 200 access.offset().opr(), 201 access.gen()->new_register(access.type()), 202 NULL /* patch_emit_info */, 203 NULL /* load_emit_info */); 204 } 205 206 LIR_Opr ZBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { 207 if (barrier_needed(access)) { 208 pre_load_barrier(access); 209 } 210 211 return BarrierSetC1::atomic_xchg_at_resolved(access, value); 212 } 213 214 LIR_Opr ZBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { 215 if (barrier_needed(access)) { 216 pre_load_barrier(access); 217 } 218 219 return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); 220 } 221 222 class ZLoadBarrierRuntimeStubCodeGenClosure : public StubAssemblerCodeGenClosure { 223 private: 224 const DecoratorSet _decorators; 225 226 public: 227 ZLoadBarrierRuntimeStubCodeGenClosure(DecoratorSet decorators) : 228 _decorators(decorators) {} 229 230 virtual OopMapSet* generate_code(StubAssembler* sasm) { 231 ZBarrierSet::assembler()->generate_c1_load_barrier_runtime_stub(sasm, _decorators); 232 return NULL; 233 } 234 }; 235 236 static address generate_c1_runtime_stub(BufferBlob* blob, DecoratorSet decorators, const char* name) { 237 ZLoadBarrierRuntimeStubCodeGenClosure cl(decorators); 238 CodeBlob* const code_blob = Runtime1::generate_blob(blob, -1 /* stub_id */, name, false /* expect_oop_map*/, &cl); 239 return code_blob->code_begin(); 240 } 241 242 void ZBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* blob) { 243 _load_barrier_on_oop_field_preloaded_runtime_stub = 244 generate_c1_runtime_stub(blob, ON_STRONG_OOP_REF, "load_barrier_on_oop_field_preloaded_runtime_stub"); 245 _load_barrier_on_weak_oop_field_preloaded_runtime_stub = 246 generate_c1_runtime_stub(blob, ON_WEAK_OOP_REF, "load_barrier_on_weak_oop_field_preloaded_runtime_stub"); 247 }