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 "interpreter/interp_masm.hpp"
29 #include "runtime/jniHandles.hpp"
30 #include "runtime/thread.hpp"
31
32 #define __ masm->
33
load_at(MacroAssembler * masm,DecoratorSet decorators,BasicType type,Register dst,Address src,Register tmp1,Register tmp_thread)34 void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
35 Register dst, Address src, Register tmp1, Register tmp_thread) {
36 bool in_heap = (decorators & IN_HEAP) != 0;
37 bool in_native = (decorators & IN_NATIVE) != 0;
38 bool is_not_null = (decorators & IS_NOT_NULL) != 0;
39 bool atomic = (decorators & MO_RELAXED) != 0;
40
41 switch (type) {
42 case T_OBJECT:
43 case T_ARRAY: {
44 if (in_heap) {
45 #ifdef _LP64
46 if (UseCompressedOops) {
47 __ movl(dst, src);
48 if (is_not_null) {
49 __ decode_heap_oop_not_null(dst);
50 } else {
51 __ decode_heap_oop(dst);
52 }
53 } else
54 #endif
55 {
56 __ movptr(dst, src);
57 }
58 } else {
59 assert(in_native, "why else?");
60 __ movptr(dst, src);
61 }
62 break;
63 }
64 case T_BOOLEAN: __ load_unsigned_byte(dst, src); break;
65 case T_BYTE: __ load_signed_byte(dst, src); break;
66 case T_CHAR: __ load_unsigned_short(dst, src); break;
67 case T_SHORT: __ load_signed_short(dst, src); break;
68 case T_INT: __ movl (dst, src); break;
69 case T_ADDRESS: __ movptr(dst, src); break;
70 case T_FLOAT:
71 assert(dst == noreg, "only to ftos");
72 __ load_float(src);
73 break;
74 case T_DOUBLE:
75 assert(dst == noreg, "only to dtos");
76 __ load_double(src);
77 break;
78 case T_LONG:
79 assert(dst == noreg, "only to ltos");
80 #ifdef _LP64
81 __ movq(rax, src);
82 #else
83 if (atomic) {
84 __ fild_d(src); // Must load atomically
85 __ subptr(rsp,2*wordSize); // Make space for store
86 __ fistp_d(Address(rsp,0));
87 __ pop(rax);
88 __ pop(rdx);
89 } else {
90 __ movl(rax, src);
91 __ movl(rdx, src.plus_disp(wordSize));
92 }
93 #endif
94 break;
95 default: Unimplemented();
96 }
97 }
98
store_at(MacroAssembler * masm,DecoratorSet decorators,BasicType type,Address dst,Register val,Register tmp1,Register tmp2)99 void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
100 Address dst, Register val, Register tmp1, Register tmp2) {
101 bool in_heap = (decorators & IN_HEAP) != 0;
102 bool in_native = (decorators & IN_NATIVE) != 0;
103 bool is_not_null = (decorators & IS_NOT_NULL) != 0;
104 bool atomic = (decorators & MO_RELAXED) != 0;
105
106 switch (type) {
107 case T_OBJECT:
108 case T_ARRAY: {
109 if (in_heap) {
110 if (val == noreg) {
111 assert(!is_not_null, "inconsistent access");
112 #ifdef _LP64
113 if (UseCompressedOops) {
114 __ movl(dst, (int32_t)NULL_WORD);
115 } else {
116 __ movslq(dst, (int32_t)NULL_WORD);
117 }
118 #else
119 __ movl(dst, (int32_t)NULL_WORD);
120 #endif
121 } else {
122 #ifdef _LP64
123 if (UseCompressedOops) {
124 assert(!dst.uses(val), "not enough registers");
125 if (is_not_null) {
126 __ encode_heap_oop_not_null(val);
127 } else {
128 __ encode_heap_oop(val);
129 }
130 __ movl(dst, val);
131 } else
132 #endif
133 {
134 __ movptr(dst, val);
135 }
136 }
137 } else {
138 assert(in_native, "why else?");
139 assert(val != noreg, "not supported");
140 __ movptr(dst, val);
141 }
142 break;
143 }
144 case T_BOOLEAN:
145 __ andl(val, 0x1); // boolean is true if LSB is 1
146 __ movb(dst, val);
147 break;
148 case T_BYTE:
149 __ movb(dst, val);
150 break;
151 case T_SHORT:
152 __ movw(dst, val);
153 break;
154 case T_CHAR:
155 __ movw(dst, val);
156 break;
157 case T_INT:
158 __ movl(dst, val);
159 break;
160 case T_LONG:
161 assert(val == noreg, "only tos");
162 #ifdef _LP64
163 __ movq(dst, rax);
164 #else
165 if (atomic) {
166 __ push(rdx);
167 __ push(rax); // Must update atomically with FIST
168 __ fild_d(Address(rsp,0)); // So load into FPU register
169 __ fistp_d(dst); // and put into memory atomically
170 __ addptr(rsp, 2*wordSize);
171 } else {
172 __ movptr(dst, rax);
173 __ movptr(dst.plus_disp(wordSize), rdx);
174 }
175 #endif
176 break;
177 case T_FLOAT:
178 assert(val == noreg, "only tos");
179 __ store_float(dst);
180 break;
181 case T_DOUBLE:
182 assert(val == noreg, "only tos");
183 __ store_double(dst);
184 break;
185 case T_ADDRESS:
186 __ movptr(dst, val);
187 break;
188 default: Unimplemented();
189 }
190 }
191
192 #ifndef _LP64
obj_equals(MacroAssembler * masm,Address obj1,jobject obj2)193 void BarrierSetAssembler::obj_equals(MacroAssembler* masm,
194 Address obj1, jobject obj2) {
195 __ cmpoop_raw(obj1, obj2);
196 }
197
obj_equals(MacroAssembler * masm,Register obj1,jobject obj2)198 void BarrierSetAssembler::obj_equals(MacroAssembler* masm,
199 Register obj1, jobject obj2) {
200 __ cmpoop_raw(obj1, obj2);
201 }
202 #endif
obj_equals(MacroAssembler * masm,Register obj1,Address obj2)203 void BarrierSetAssembler::obj_equals(MacroAssembler* masm,
204 Register obj1, Address obj2) {
205 __ cmpptr(obj1, obj2);
206 }
207
obj_equals(MacroAssembler * masm,Register obj1,Register obj2)208 void BarrierSetAssembler::obj_equals(MacroAssembler* masm,
209 Register obj1, Register obj2) {
210 __ cmpptr(obj1, obj2);
211 }
212
try_resolve_jobject_in_native(MacroAssembler * masm,Register jni_env,Register obj,Register tmp,Label & slowpath)213 void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
214 Register obj, Register tmp, Label& slowpath) {
215 __ clear_jweak_tag(obj);
216 __ movptr(obj, Address(obj, 0));
217 }
218
tlab_allocate(MacroAssembler * masm,Register thread,Register obj,Register var_size_in_bytes,int con_size_in_bytes,Register t1,Register t2,Label & slow_case)219 void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm,
220 Register thread, Register obj,
221 Register var_size_in_bytes,
222 int con_size_in_bytes,
223 Register t1,
224 Register t2,
225 Label& slow_case) {
226 assert_different_registers(obj, t1, t2);
227 assert_different_registers(obj, var_size_in_bytes, t1);
228 Register end = t2;
229 if (!thread->is_valid()) {
230 #ifdef _LP64
231 thread = r15_thread;
232 #else
233 assert(t1->is_valid(), "need temp reg");
234 thread = t1;
235 __ get_thread(thread);
236 #endif
237 }
238
239 __ verify_tlab();
240
241 __ movptr(obj, Address(thread, JavaThread::tlab_top_offset()));
242 if (var_size_in_bytes == noreg) {
243 __ lea(end, Address(obj, con_size_in_bytes));
244 } else {
245 __ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
246 }
247 __ cmpptr(end, Address(thread, JavaThread::tlab_end_offset()));
248 __ jcc(Assembler::above, slow_case);
249
250 // update the tlab top pointer
251 __ movptr(Address(thread, JavaThread::tlab_top_offset()), end);
252
253 // recover var_size_in_bytes if necessary
254 if (var_size_in_bytes == end) {
255 __ subptr(var_size_in_bytes, obj);
256 }
257 __ verify_tlab();
258 }
259
260 // Defines obj, preserves var_size_in_bytes
eden_allocate(MacroAssembler * masm,Register thread,Register obj,Register var_size_in_bytes,int con_size_in_bytes,Register t1,Label & slow_case)261 void BarrierSetAssembler::eden_allocate(MacroAssembler* masm,
262 Register thread, Register obj,
263 Register var_size_in_bytes,
264 int con_size_in_bytes,
265 Register t1,
266 Label& slow_case) {
267 assert(obj == rax, "obj must be in rax, for cmpxchg");
268 assert_different_registers(obj, var_size_in_bytes, t1);
269 if (!Universe::heap()->supports_inline_contig_alloc()) {
270 __ jmp(slow_case);
271 } else {
272 Register end = t1;
273 Label retry;
274 __ bind(retry);
275 ExternalAddress heap_top((address) Universe::heap()->top_addr());
276 __ movptr(obj, heap_top);
277 if (var_size_in_bytes == noreg) {
278 __ lea(end, Address(obj, con_size_in_bytes));
279 } else {
280 __ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
281 }
282 // if end < obj then we wrapped around => object too long => slow case
283 __ cmpptr(end, obj);
284 __ jcc(Assembler::below, slow_case);
285 __ cmpptr(end, ExternalAddress((address) Universe::heap()->end_addr()));
286 __ jcc(Assembler::above, slow_case);
287 // Compare obj with the top addr, and if still equal, store the new top addr in
288 // end at the address of the top addr pointer. Sets ZF if was equal, and clears
289 // it otherwise. Use lock prefix for atomicity on MPs.
290 __ locked_cmpxchgptr(end, heap_top);
291 __ jcc(Assembler::notEqual, retry);
292 incr_allocated_bytes(masm, thread, var_size_in_bytes, con_size_in_bytes, thread->is_valid() ? noreg : t1);
293 }
294 }
295
incr_allocated_bytes(MacroAssembler * masm,Register thread,Register var_size_in_bytes,int con_size_in_bytes,Register t1)296 void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, Register thread,
297 Register var_size_in_bytes,
298 int con_size_in_bytes,
299 Register t1) {
300 if (!thread->is_valid()) {
301 #ifdef _LP64
302 thread = r15_thread;
303 #else
304 assert(t1->is_valid(), "need temp reg");
305 thread = t1;
306 __ get_thread(thread);
307 #endif
308 }
309
310 #ifdef _LP64
311 if (var_size_in_bytes->is_valid()) {
312 __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
313 } else {
314 __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
315 }
316 #else
317 if (var_size_in_bytes->is_valid()) {
318 __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
319 } else {
320 __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
321 }
322 __ adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0);
323 #endif
324 }
325