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 #include "precompiled.hpp" 25 #include "c1/c1_MacroAssembler.hpp" 26 #include "c1/c1_LIRAssembler.hpp" 27 #include "macroAssembler_aarch64.hpp" 28 #include "shenandoahBarrierSetAssembler_aarch64.hpp" 29 #include "gc_implementation/shenandoah/shenandoahBarrierSet.hpp" 30 #include "gc_implementation/shenandoah/shenandoahBarrierSetC1.hpp" 31 #include "gc_implementation/shenandoah/shenandoahForwarding.hpp" 32 #include "gc_implementation/shenandoah/shenandoahHeap.hpp" 33 #include "gc_implementation/shenandoah/shenandoahRuntime.hpp" 34 #include "runtime/stubCodeGenerator.hpp" 35 #include "runtime/thread.hpp" 36 37 ShenandoahBarrierSetAssembler* ShenandoahBarrierSetAssembler::bsasm() { 38 return ShenandoahBarrierSet::barrier_set()->bsasm(); 39 } 40 41 #define __ masm-> 42 43 void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) { 44 assert(ShenandoahCASBarrier, "should be enabled"); 45 Label is_null; 46 __ cbz(dst, is_null); 47 resolve_forward_pointer_not_null(masm, dst, tmp); 48 __ bind(is_null); 49 } 50 51 // IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2, except those explicitely 52 // passed in. 53 void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) { 54 assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled"); 55 // The below loads the mark word, checks if the lowest two bits are 56 // set, and if so, clear the lowest two bits and copy the result 57 // to dst. Otherwise it leaves dst alone. 58 // Implementing this is surprisingly awkward. I do it here by: 59 // - Inverting the mark word 60 // - Test lowest two bits == 0 61 // - If so, set the lowest two bits 62 // - Invert the result back, and copy to dst 63 64 bool borrow_reg = (tmp == noreg); 65 if (borrow_reg) { 66 // No free registers available. Make one useful. 67 tmp = rscratch1; 68 __ push(RegSet::of(tmp), sp); 69 } 70 71 Label done; 72 __ ldr(tmp, Address(dst, oopDesc::mark_offset_in_bytes())); 73 __ eon(tmp, tmp, zr); 74 __ ands(zr, tmp, markOopDesc::lock_mask_in_place); 75 __ br(Assembler::NE, done); 76 __ orr(tmp, tmp, markOopDesc::marked_value); 77 __ eon(dst, tmp, zr); 78 __ bind(done); 79 80 if (borrow_reg) { 81 __ pop(RegSet::of(tmp), sp); 82 } 83 } 84 85 void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst) { 86 assert(ShenandoahLoadRefBarrier, "Should be enabled"); 87 assert(dst != rscratch2, "need rscratch2"); 88 89 Label done; 90 __ enter(); 91 Address gc_state(rthread, in_bytes(JavaThread::gc_state_offset())); 92 __ ldrb(rscratch2, gc_state); 93 94 // Check for heap stability 95 __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, done); 96 97 RegSet to_save = RegSet::of(r0); 98 if (dst != r0) { 99 __ push(to_save, sp); 100 __ mov(r0, dst); 101 } 102 103 __ push_call_clobbered_registers(); 104 __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_interpreter), r0); 105 __ mov(rscratch1, r0); 106 __ pop_call_clobbered_registers(); 107 __ mov(r0, rscratch1); 108 109 if (dst != r0) { 110 __ mov(dst, r0); 111 __ pop(to_save, sp); 112 } 113 114 __ bind(done); 115 __ leave(); 116 } 117 118 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst) { 119 if (ShenandoahLoadRefBarrier) { 120 Label is_null; 121 __ cbz(dst, is_null); 122 load_reference_barrier_not_null(masm, dst); 123 __ bind(is_null); 124 } 125 } 126 127 void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, 128 bool acquire, bool release, bool weak, bool is_cae, 129 Register result) { 130 131 Register tmp1 = rscratch1; 132 Register tmp2 = rscratch2; 133 bool is_narrow = UseCompressedOops; 134 Assembler::operand_size size = is_narrow ? Assembler::word : Assembler::xword; 135 136 assert_different_registers(addr, expected, new_val, tmp1, tmp2); 137 138 Label retry, done, fail; 139 140 // CAS, using LL/SC pair. 141 __ bind(retry); 142 __ load_exclusive(tmp1, addr, size, acquire); 143 if (is_narrow) { 144 __ cmpw(tmp1, expected); 145 } else { 146 __ cmp(tmp1, expected); 147 } 148 __ br(Assembler::NE, fail); 149 __ store_exclusive(tmp2, new_val, addr, size, release); 150 if (weak) { 151 __ cmpw(tmp2, 0u); // If the store fails, return NE to our caller 152 } else { 153 __ cbnzw(tmp2, retry); 154 } 155 __ b(done); 156 157 __ bind(fail); 158 // Check if rb(expected)==rb(tmp1) 159 // Shuffle registers so that we have memory value ready for next expected. 160 __ mov(tmp2, expected); 161 __ mov(expected, tmp1); 162 if (is_narrow) { 163 __ decode_heap_oop(tmp1, tmp1); 164 __ decode_heap_oop(tmp2, tmp2); 165 } 166 resolve_forward_pointer(masm, tmp1); 167 resolve_forward_pointer(masm, tmp2); 168 __ cmp(tmp1, tmp2); 169 // Retry with expected now being the value we just loaded from addr. 170 __ br(Assembler::EQ, retry); 171 if (is_cae && is_narrow) { 172 // For cmp-and-exchange and narrow oops, we need to restore 173 // the compressed old-value. We moved it to 'expected' a few lines up. 174 __ mov(result, expected); 175 } 176 __ bind(done); 177 178 if (is_cae) { 179 __ mov(result, tmp1); 180 } else { 181 __ cset(result, Assembler::EQ); 182 } 183 } 184 185 #undef __ 186 187 #ifdef COMPILER1 188 189 #define __ ce->masm()-> 190 191 void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) { 192 193 Register obj = stub->obj()->as_register(); 194 Register res = stub->result()->as_register(); 195 196 Label done; 197 198 __ bind(*stub->entry()); 199 200 if (res != obj) { 201 __ mov(res, obj); 202 } 203 // Check for null. 204 if (stub->needs_null_check()) { 205 __ cbz(res, done); 206 } 207 208 load_reference_barrier_not_null(ce->masm(), res); 209 210 __ bind(done); 211 __ b(*stub->continuation()); 212 } 213 214 #undef __ 215 216 #endif // COMPILER1