1 /* 2 * Copyright (c) 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 25 #include "precompiled.hpp" 26 #include "gc/shared/barrierSetAssembler.hpp" 27 #include "gc/shared/collectedHeap.hpp" 28 #include "runtime/thread.hpp" 29 30 #define __ masm-> 31 32 void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 33 Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) { 34 bool in_heap = (decorators & IN_HEAP) != 0; 35 bool in_native = (decorators & IN_NATIVE) != 0; 36 switch (type) { 37 case T_OBJECT: 38 case T_ARRAY: { 39 if (in_heap) { 40 { 41 __ ldr(dst, src); 42 } 43 } else { 44 assert(in_native, "why else?"); 45 __ ldr(dst, src); 46 } 47 break; 48 } 49 case T_BOOLEAN: __ ldrb (dst, src); break; 50 case T_BYTE: __ ldrsb (dst, src); break; 51 case T_CHAR: __ ldrh (dst, src); break; 52 case T_SHORT: __ ldrsh (dst, src); break; 53 case T_INT: __ ldr_s32 (dst, src); break; 54 case T_ADDRESS: __ ldr (dst, src); break; 55 case T_LONG: 56 assert(dst == noreg, "only to ltos"); 57 __ add (src.index(), src.index(), src.base()); 58 __ ldmia (src.index(), RegisterSet(R0_tos_lo) | RegisterSet(R1_tos_hi)); 59 break; 60 #ifdef __SOFTFP__ 61 case T_FLOAT: 62 assert(dst == noreg, "only to ftos"); 63 __ ldr (R0_tos, src); 64 break; 65 case T_DOUBLE: 66 assert(dst == noreg, "only to dtos"); 67 __ add (src.index(), src.index(), src.base()); 68 __ ldmia (src.index(), RegisterSet(R0_tos_lo) | RegisterSet(R1_tos_hi)); 69 break; 70 #else 71 case T_FLOAT: 72 assert(dst == noreg, "only to ftos"); 73 __ add(src.index(), src.index(), src.base()); 74 __ ldr_float (S0_tos, src.index()); 75 break; 76 case T_DOUBLE: 77 assert(dst == noreg, "only to dtos"); 78 __ add (src.index(), src.index(), src.base()); 79 __ ldr_double (D0_tos, src.index()); 80 break; 81 #endif 82 default: Unimplemented(); 83 } 84 85 } 86 87 void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, 88 Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null) { 89 bool in_heap = (decorators & IN_HEAP) != 0; 90 bool in_native = (decorators & IN_NATIVE) != 0; 91 switch (type) { 92 case T_OBJECT: 93 case T_ARRAY: { 94 if (in_heap) { 95 { 96 __ str(val, obj); 97 } 98 } else { 99 assert(in_native, "why else?"); 100 __ str(val, obj); 101 } 102 break; 103 } 104 case T_BOOLEAN: 105 __ and_32(val, val, 1); 106 __ strb(val, obj); 107 break; 108 case T_BYTE: __ strb (val, obj); break; 109 case T_CHAR: __ strh (val, obj); break; 110 case T_SHORT: __ strh (val, obj); break; 111 case T_INT: __ str (val, obj); break; 112 case T_ADDRESS: __ str (val, obj); break; 113 case T_LONG: 114 assert(val == noreg, "only tos"); 115 __ add (obj.index(), obj.index(), obj.base()); 116 __ stmia (obj.index(), RegisterSet(R0_tos_lo) | RegisterSet(R1_tos_hi)); 117 break; 118 #ifdef __SOFTFP__ 119 case T_FLOAT: 120 assert(val == noreg, "only tos"); 121 __ str (R0_tos, obj); 122 break; 123 case T_DOUBLE: 124 assert(val == noreg, "only tos"); 125 __ add (obj.index(), obj.index(), obj.base()); 126 __ stmia (obj.index(), RegisterSet(R0_tos_lo) | RegisterSet(R1_tos_hi)); 127 break; 128 #else 129 case T_FLOAT: 130 assert(val == noreg, "only tos"); 131 __ add (obj.index(), obj.index(), obj.base()); 132 __ str_float (S0_tos, obj.index()); 133 break; 134 case T_DOUBLE: 135 assert(val == noreg, "only tos"); 136 __ add (obj.index(), obj.index(), obj.base()); 137 __ str_double (D0_tos, obj.index()); 138 break; 139 #endif 140 default: Unimplemented(); 141 } 142 } 143 144 void BarrierSetAssembler::obj_equals(MacroAssembler* masm, 145 Register obj1, Register obj2) { 146 __ cmp(obj1, obj2); 147 } 148 149 // Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`. 150 void BarrierSetAssembler::eden_allocate(MacroAssembler* masm, Register obj, Register obj_end, Register tmp1, Register tmp2, 151 RegisterOrConstant size_expression, Label& slow_case) { 152 if (!Universe::heap()->supports_inline_contig_alloc()) { 153 __ b(slow_case); 154 return; 155 } 156 157 CollectedHeap* ch = Universe::heap(); 158 159 const Register top_addr = tmp1; 160 const Register heap_end = tmp2; 161 162 if (size_expression.is_register()) { 163 assert_different_registers(obj, obj_end, top_addr, heap_end, size_expression.as_register()); 164 } else { 165 assert_different_registers(obj, obj_end, top_addr, heap_end); 166 } 167 168 bool load_const = VM_Version::supports_movw(); 169 if (load_const) { 170 __ mov_address(top_addr, (address)Universe::heap()->top_addr()); 171 } else { 172 __ ldr(top_addr, Address(Rthread, JavaThread::heap_top_addr_offset())); 173 } 174 // Calculate new heap_top by adding the size of the object 175 Label retry; 176 __ bind(retry); 177 __ ldr(obj, Address(top_addr)); 178 __ ldr(heap_end, Address(top_addr, (intptr_t)ch->end_addr() - (intptr_t)ch->top_addr())); 179 __ add_rc(obj_end, obj, size_expression); 180 // Check if obj_end wrapped around, i.e., obj_end < obj. If yes, jump to the slow case. 181 __ cmp(obj_end, obj); 182 __ b(slow_case, lo); 183 // Update heap_top if allocation succeeded 184 __ cmp(obj_end, heap_end); 185 __ b(slow_case, hi); 186 187 __ atomic_cas_bool(obj, obj_end, top_addr, 0, heap_end/*scratched*/); 188 __ b(retry, ne); 189 190 incr_allocated_bytes(masm, size_expression, tmp1); 191 } 192 193 // Puts address of allocated object into register `obj` and end of allocated object into register `obj_end`. 194 void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, Register obj_end, Register tmp1, 195 RegisterOrConstant size_expression, Label& slow_case) { 196 const Register tlab_end = tmp1; 197 assert_different_registers(obj, obj_end, tlab_end); 198 199 __ ldr(obj, Address(Rthread, JavaThread::tlab_top_offset())); 200 __ ldr(tlab_end, Address(Rthread, JavaThread::tlab_end_offset())); 201 __ add_rc(obj_end, obj, size_expression); 202 __ cmp(obj_end, tlab_end); 203 __ b(slow_case, hi); 204 __ str(obj_end, Address(Rthread, JavaThread::tlab_top_offset())); 205 } 206 207 void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, RegisterOrConstant size_in_bytes, Register tmp) { 208 // Bump total bytes allocated by this thread 209 Label done; 210 211 // Borrow the Rthread for alloc counter 212 Register Ralloc = Rthread; 213 __ add(Ralloc, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); 214 __ ldr(tmp, Address(Ralloc)); 215 __ adds(tmp, tmp, size_in_bytes); 216 __ str(tmp, Address(Ralloc), cc); 217 __ b(done, cc); 218 219 // Increment the high word and store single-copy atomically (that is an unlikely scenario on typical embedded systems as it means >4GB has been allocated) 220 // To do so ldrd/strd instructions used which require an even-odd pair of registers. Such a request could be difficult to satisfy by 221 // allocating those registers on a higher level, therefore the routine is ready to allocate a pair itself. 222 Register low, high; 223 // Select ether R0/R1 or R2/R3 224 225 if (size_in_bytes.is_register() && (size_in_bytes.as_register() == R0 || size_in_bytes.as_register() == R1)) { 226 low = R2; 227 high = R3; 228 } else { 229 low = R0; 230 high = R1; 231 } 232 __ push(RegisterSet(low, high)); 233 234 __ ldrd(low, Address(Ralloc)); 235 __ adds(low, low, size_in_bytes); 236 __ adc(high, high, 0); 237 __ strd(low, Address(Ralloc)); 238 239 __ pop(RegisterSet(low, high)); 240 241 __ bind(done); 242 243 // Unborrow the Rthread 244 __ sub(Rthread, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); 245 }