1 /* 2 * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. 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 #include "precompiled.hpp" 25 #include "c1/c1_IR.hpp" 26 #include "gc/shared/satbMarkQueue.hpp" 27 #include "gc/shenandoah/brooksPointer.hpp" 28 #include "gc/shenandoah/shenandoahBaseBarrierSetAssembler.hpp" 29 #include "gc/shenandoah/shenandoahHeap.hpp" 30 #include "gc/shenandoah/shenandoahHeapRegion.hpp" 31 #include "gc/shenandoah/shenandoahThreadLocalData.hpp" 32 #include "gc/shenandoah/c1/shenandoahBaseBarrierSetC1.hpp" 33 34 #ifdef ASSERT 35 #define __ gen->lir(__FILE__, __LINE__)-> 36 #else 37 #define __ gen->lir()-> 38 #endif 39 40 void ShenandoahPreBarrierStub::emit_code(LIR_Assembler* ce) { 41 ShenandoahBaseBarrierSetAssembler* bs = (ShenandoahBaseBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 42 bs->gen_pre_barrier_stub(ce, this); 43 } 44 45 void ShenandoahWriteBarrierStub::emit_code(LIR_Assembler* ce) { 46 ShenandoahBaseBarrierSetAssembler* bs = (ShenandoahBaseBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 47 bs->gen_write_barrier_stub(ce, this); 48 } 49 50 void ShenandoahBaseBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) { 51 52 // First we test whether marking is in progress. 53 BasicType flag_type; 54 bool patch = (decorators & C1_NEEDS_PATCHING) != 0; 55 bool do_load = pre_val == LIR_OprFact::illegalOpr; 56 if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { 57 flag_type = T_INT; 58 } else { 59 guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, 60 "Assumption"); 61 // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, 62 // need to use unsigned instructions to use the large offset to load the satb_mark_queue. 63 flag_type = T_BOOLEAN; 64 } 65 LIR_Opr thrd = gen->getThreadPointer(); 66 LIR_Address* mark_active_flag_addr = 67 new LIR_Address(thrd, 68 in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()), 69 flag_type); 70 // Read the marking-in-progress flag. 71 LIR_Opr flag_val = gen->new_register(T_INT); 72 __ load(mark_active_flag_addr, flag_val); 73 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); 74 75 LIR_PatchCode pre_val_patch_code = lir_patch_none; 76 77 CodeStub* slow; 78 79 if (do_load) { 80 assert(pre_val == LIR_OprFact::illegalOpr, "sanity"); 81 assert(addr_opr != LIR_OprFact::illegalOpr, "sanity"); 82 83 if (patch) 84 pre_val_patch_code = lir_patch_normal; 85 86 pre_val = gen->new_register(T_OBJECT); 87 88 if (!addr_opr->is_address()) { 89 assert(addr_opr->is_register(), "must be"); 90 addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT)); 91 } 92 slow = new ShenandoahPreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info ? new CodeEmitInfo(info) : NULL); 93 } else { 94 assert(addr_opr == LIR_OprFact::illegalOpr, "sanity"); 95 assert(pre_val->is_register(), "must be"); 96 assert(pre_val->type() == T_OBJECT, "must be an object"); 97 98 slow = new ShenandoahPreBarrierStub(pre_val); 99 } 100 101 __ branch(lir_cond_notEqual, T_INT, slow); 102 __ branch_destination(slow->continuation()); 103 } 104 105 LIR_Opr ShenandoahBaseBarrierSetC1::read_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { 106 if (UseShenandoahGC && ShenandoahReadBarrier) { 107 return read_barrier_impl(gen, obj, info, need_null_check); 108 } else { 109 return obj; 110 } 111 } 112 113 LIR_Opr ShenandoahBaseBarrierSetC1::read_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { 114 assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier), "Should be enabled"); 115 LabelObj* done = new LabelObj(); 116 LIR_Opr result = gen->new_register(T_OBJECT); 117 __ move(obj, result); 118 if (need_null_check) { 119 __ cmp(lir_cond_equal, result, LIR_OprFact::oopConst(NULL)); 120 __ branch(lir_cond_equal, T_LONG, done->label()); 121 } 122 LIR_Address* brooks_ptr_address = gen->generate_address(result, BrooksPointer::byte_offset(), T_ADDRESS); 123 __ load(brooks_ptr_address, result, info ? new CodeEmitInfo(info) : NULL, lir_patch_none); 124 125 __ branch_destination(done->label()); 126 return result; 127 } 128 129 LIR_Opr ShenandoahBaseBarrierSetC1::write_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { 130 if (UseShenandoahGC && ShenandoahWriteBarrier) { 131 return write_barrier_impl(gen, obj, info, need_null_check); 132 } else { 133 return obj; 134 } 135 } 136 137 LIR_Opr ShenandoahBaseBarrierSetC1::write_barrier_impl(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) { 138 assert(UseShenandoahGC && (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier), "Should be enabled"); 139 140 obj = ensure_in_register(gen, obj); 141 assert(obj->is_register(), "must be a register at this point"); 142 LIR_Opr result = gen->new_register(T_OBJECT); 143 __ move(obj, result); 144 145 LIR_Opr thrd = gen->getThreadPointer(); 146 LIR_Address* active_flag_addr = 147 new LIR_Address(thrd, 148 in_bytes(ShenandoahThreadLocalData::gc_state_offset()), 149 T_BYTE); 150 // Read and check the gc-state-flag. 151 LIR_Opr flag_val = gen->new_register(T_INT); 152 __ load(active_flag_addr, flag_val); 153 LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::HAS_FORWARDED | 154 ShenandoahHeap::EVACUATION | 155 ShenandoahHeap::TRAVERSAL); 156 LIR_Opr mask_reg = gen->new_register(T_INT); 157 __ move(mask, mask_reg); 158 159 if (TwoOperandLIRForm) { 160 __ logical_and(flag_val, mask_reg, flag_val); 161 } else { 162 LIR_Opr masked_flag = gen->new_register(T_INT); 163 __ logical_and(flag_val, mask_reg, masked_flag); 164 flag_val = masked_flag; 165 } 166 __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); 167 168 CodeStub* slow = new ShenandoahWriteBarrierStub(obj, result, info ? new CodeEmitInfo(info) : NULL, need_null_check); 169 __ branch(lir_cond_notEqual, T_INT, slow); 170 __ branch_destination(slow->continuation()); 171 172 return result; 173 } 174 175 LIR_Opr ShenandoahBaseBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr obj) { 176 if (!obj->is_register()) { 177 LIR_Opr obj_reg = gen->new_register(T_OBJECT); 178 if (obj->is_constant()) { 179 __ move(obj, obj_reg); 180 } else { 181 __ leal(obj, obj_reg); 182 } 183 obj = obj_reg; 184 } 185 return obj; 186 } 187 188 LIR_Opr ShenandoahBaseBarrierSetC1::storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators) { 189 bool need_null_check = (decorators & IS_NOT_NULL) == 0; 190 if (ShenandoahStoreValEnqueueBarrier) { 191 obj = write_barrier_impl(gen, obj, info, need_null_check); 192 enqueue_barrier(gen, obj, info, decorators); 193 } 194 if (ShenandoahStoreValReadBarrier) { 195 obj = read_barrier_impl(gen, obj, info, true /*need_null_check*/); 196 } 197 return obj; 198 } 199 200 void ShenandoahBaseBarrierSetC1::enqueue_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators) { 201 if (ShenandoahStoreValEnqueueBarrier) { 202 obj = ensure_in_register(gen, obj); 203 pre_barrier(gen, info, decorators, LIR_OprFact::illegalOpr, obj); 204 } 205 } 206 207 class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { 208 virtual OopMapSet* generate_code(StubAssembler* sasm) { 209 ShenandoahBaseBarrierSetAssembler* bs = (ShenandoahBaseBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); 210 bs->generate_c1_pre_barrier_runtime_stub(sasm); 211 return NULL; 212 } 213 }; 214 215 void ShenandoahBaseBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) { 216 C1ShenandoahPreBarrierCodeGenClosure pre_code_gen_cl; 217 _pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, 218 "shenandoah_pre_barrier_slow", 219 false, &pre_code_gen_cl); 220 }