Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
40930 views
1
/*
2
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*
24
*/
25
26
#include "precompiled.hpp"
27
#include "c1/c1_MacroAssembler.hpp"
28
#include "c1/c1_Runtime1.hpp"
29
#include "gc/shared/barrierSetAssembler.hpp"
30
#include "gc/shared/collectedHeap.hpp"
31
#include "gc/shared/tlab_globals.hpp"
32
#include "interpreter/interpreter.hpp"
33
#include "oops/arrayOop.hpp"
34
#include "oops/markWord.hpp"
35
#include "runtime/basicLock.hpp"
36
#include "runtime/biasedLocking.hpp"
37
#include "runtime/os.hpp"
38
#include "runtime/sharedRuntime.hpp"
39
#include "runtime/stubRoutines.hpp"
40
41
void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
42
FloatRegister f0, FloatRegister f1,
43
Register result)
44
{
45
Label done;
46
if (is_float) {
47
fcmps(f0, f1);
48
} else {
49
fcmpd(f0, f1);
50
}
51
if (unordered_result < 0) {
52
// we want -1 for unordered or less than, 0 for equal and 1 for
53
// greater than.
54
cset(result, NE); // Not equal or unordered
55
cneg(result, result, LT); // Less than or unordered
56
} else {
57
// we want -1 for less than, 0 for equal and 1 for unordered or
58
// greater than.
59
cset(result, NE); // Not equal or unordered
60
cneg(result, result, LO); // Less than
61
}
62
}
63
64
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {
65
const int aligned_mask = BytesPerWord -1;
66
const int hdr_offset = oopDesc::mark_offset_in_bytes();
67
assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
68
Label done;
69
int null_check_offset = -1;
70
71
verify_oop(obj);
72
73
// save object being locked into the BasicObjectLock
74
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
75
76
null_check_offset = offset();
77
78
if (DiagnoseSyncOnValueBasedClasses != 0) {
79
load_klass(hdr, obj);
80
ldrw(hdr, Address(hdr, Klass::access_flags_offset()));
81
tstw(hdr, JVM_ACC_IS_VALUE_BASED_CLASS);
82
br(Assembler::NE, slow_case);
83
}
84
85
if (UseBiasedLocking) {
86
assert(scratch != noreg, "should have scratch register at this point");
87
biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
88
}
89
90
// Load object header
91
ldr(hdr, Address(obj, hdr_offset));
92
// and mark it as unlocked
93
orr(hdr, hdr, markWord::unlocked_value);
94
// save unlocked object header into the displaced header location on the stack
95
str(hdr, Address(disp_hdr, 0));
96
// test if object header is still the same (i.e. unlocked), and if so, store the
97
// displaced header address in the object header - if it is not the same, get the
98
// object header instead
99
lea(rscratch2, Address(obj, hdr_offset));
100
cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/NULL);
101
// if the object header was the same, we're done
102
// if the object header was not the same, it is now in the hdr register
103
// => test if it is a stack pointer into the same stack (recursive locking), i.e.:
104
//
105
// 1) (hdr & aligned_mask) == 0
106
// 2) sp <= hdr
107
// 3) hdr <= sp + page_size
108
//
109
// these 3 tests can be done by evaluating the following expression:
110
//
111
// (hdr - sp) & (aligned_mask - page_size)
112
//
113
// assuming both the stack pointer and page_size have their least
114
// significant 2 bits cleared and page_size is a power of 2
115
mov(rscratch1, sp);
116
sub(hdr, hdr, rscratch1);
117
ands(hdr, hdr, aligned_mask - os::vm_page_size());
118
// for recursive locking, the result is zero => save it in the displaced header
119
// location (NULL in the displaced hdr location indicates recursive locking)
120
str(hdr, Address(disp_hdr, 0));
121
// otherwise we don't care about the result and handle locking via runtime call
122
cbnz(hdr, slow_case);
123
// done
124
bind(done);
125
if (PrintBiasedLockingStatistics) {
126
lea(rscratch2, ExternalAddress((address)BiasedLocking::fast_path_entry_count_addr()));
127
addmw(Address(rscratch2, 0), 1, rscratch1);
128
}
129
return null_check_offset;
130
}
131
132
133
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
134
const int aligned_mask = BytesPerWord -1;
135
const int hdr_offset = oopDesc::mark_offset_in_bytes();
136
assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
137
Label done;
138
139
if (UseBiasedLocking) {
140
// load object
141
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
142
biased_locking_exit(obj, hdr, done);
143
}
144
145
// load displaced header
146
ldr(hdr, Address(disp_hdr, 0));
147
// if the loaded hdr is NULL we had recursive locking
148
// if we had recursive locking, we are done
149
cbz(hdr, done);
150
if (!UseBiasedLocking) {
151
// load object
152
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
153
}
154
verify_oop(obj);
155
// test if object header is pointing to the displaced header, and if so, restore
156
// the displaced header in the object - if the object header is not pointing to
157
// the displaced header, get the object header instead
158
// if the object header was not pointing to the displaced header,
159
// we do unlocking via runtime call
160
if (hdr_offset) {
161
lea(rscratch1, Address(obj, hdr_offset));
162
cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case);
163
} else {
164
cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case);
165
}
166
// done
167
bind(done);
168
}
169
170
171
// Defines obj, preserves var_size_in_bytes
172
void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) {
173
if (UseTLAB) {
174
tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);
175
} else {
176
eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);
177
}
178
}
179
180
void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
181
assert_different_registers(obj, klass, len);
182
if (UseBiasedLocking && !len->is_valid()) {
183
assert_different_registers(obj, klass, len, t1, t2);
184
ldr(t1, Address(klass, Klass::prototype_header_offset()));
185
} else {
186
// This assumes that all prototype bits fit in an int32_t
187
mov(t1, (int32_t)(intptr_t)markWord::prototype().value());
188
}
189
str(t1, Address(obj, oopDesc::mark_offset_in_bytes()));
190
191
if (UseCompressedClassPointers) { // Take care not to kill klass
192
encode_klass_not_null(t1, klass);
193
strw(t1, Address(obj, oopDesc::klass_offset_in_bytes()));
194
} else {
195
str(klass, Address(obj, oopDesc::klass_offset_in_bytes()));
196
}
197
198
if (len->is_valid()) {
199
strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));
200
} else if (UseCompressedClassPointers) {
201
store_klass_gap(obj, zr);
202
}
203
}
204
205
// preserves obj, destroys len_in_bytes
206
void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) {
207
assert(hdr_size_in_bytes >= 0, "header size must be positive or 0");
208
Label done;
209
210
// len_in_bytes is positive and ptr sized
211
subs(len_in_bytes, len_in_bytes, hdr_size_in_bytes);
212
br(Assembler::EQ, done);
213
214
// Preserve obj
215
if (hdr_size_in_bytes)
216
add(obj, obj, hdr_size_in_bytes);
217
zero_memory(obj, len_in_bytes, t1);
218
if (hdr_size_in_bytes)
219
sub(obj, obj, hdr_size_in_bytes);
220
221
bind(done);
222
}
223
224
225
void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) {
226
assert_different_registers(obj, t1, t2); // XXX really?
227
assert(header_size >= 0 && object_size >= header_size, "illegal sizes");
228
229
try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case);
230
231
initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2, UseTLAB);
232
}
233
234
void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, bool is_tlab_allocated) {
235
assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0,
236
"con_size_in_bytes is not multiple of alignment");
237
const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
238
239
initialize_header(obj, klass, noreg, t1, t2);
240
241
if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) {
242
// clear rest of allocated space
243
const Register index = t2;
244
const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)
245
if (var_size_in_bytes != noreg) {
246
mov(index, var_size_in_bytes);
247
initialize_body(obj, index, hdr_size_in_bytes, t1);
248
} else if (con_size_in_bytes <= threshold) {
249
// use explicit null stores
250
int i = hdr_size_in_bytes;
251
if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {
252
str(zr, Address(obj, i));
253
i += BytesPerWord;
254
}
255
for (; i < con_size_in_bytes; i += 2 * BytesPerWord)
256
stp(zr, zr, Address(obj, i));
257
} else if (con_size_in_bytes > hdr_size_in_bytes) {
258
block_comment("zero memory");
259
// use loop to null out the fields
260
261
int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;
262
mov(index, words / 8);
263
264
const int unroll = 8; // Number of str(zr) instructions we'll unroll
265
int remainder = words % unroll;
266
lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));
267
268
Label entry_point, loop;
269
b(entry_point);
270
271
bind(loop);
272
sub(index, index, 1);
273
for (int i = -unroll; i < 0; i++) {
274
if (-i == remainder)
275
bind(entry_point);
276
str(zr, Address(rscratch1, i * wordSize));
277
}
278
if (remainder == 0)
279
bind(entry_point);
280
add(rscratch1, rscratch1, unroll * wordSize);
281
cbnz(index, loop);
282
283
}
284
}
285
286
membar(StoreStore);
287
288
if (CURRENT_ENV->dtrace_alloc_probes()) {
289
assert(obj == r0, "must be");
290
far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
291
}
292
293
verify_oop(obj);
294
}
295
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) {
296
assert_different_registers(obj, len, t1, t2, klass);
297
298
// determine alignment mask
299
assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");
300
301
// check for negative or excessive length
302
mov(rscratch1, (int32_t)max_array_allocation_length);
303
cmp(len, rscratch1);
304
br(Assembler::HS, slow_case);
305
306
const Register arr_size = t2; // okay to be the same
307
// align object end
308
mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);
309
add(arr_size, arr_size, len, ext::uxtw, f);
310
andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask);
311
312
try_allocate(obj, arr_size, 0, t1, t2, slow_case);
313
314
initialize_header(obj, klass, len, t1, t2);
315
316
// clear rest of allocated space
317
const Register len_zero = len;
318
initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);
319
320
membar(StoreStore);
321
322
if (CURRENT_ENV->dtrace_alloc_probes()) {
323
assert(obj == r0, "must be");
324
far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
325
}
326
327
verify_oop(obj);
328
}
329
330
331
void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {
332
verify_oop(receiver);
333
// explicit NULL check not needed since load from [klass_offset] causes a trap
334
// check against inline cache
335
assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check");
336
337
cmp_klass(receiver, iCache, rscratch1);
338
}
339
340
341
void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) {
342
assert(bang_size_in_bytes >= framesize, "stack bang size incorrect");
343
// Make sure there is enough stack space for this method's activation.
344
// Note that we do this before creating a frame.
345
generate_stack_overflow_check(bang_size_in_bytes);
346
MacroAssembler::build_frame(framesize);
347
348
// Insert nmethod entry barrier into frame.
349
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
350
bs->nmethod_entry_barrier(this);
351
}
352
353
void C1_MacroAssembler::remove_frame(int framesize) {
354
MacroAssembler::remove_frame(framesize);
355
}
356
357
358
void C1_MacroAssembler::verified_entry() {
359
// If we have to make this method not-entrant we'll overwrite its
360
// first instruction with a jump. For this action to be legal we
361
// must ensure that this first instruction is a B, BL, NOP, BKPT,
362
// SVC, HVC, or SMC. Make it a NOP.
363
nop();
364
}
365
366
void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) {
367
// rbp, + 0: link
368
// + 1: return address
369
// + 2: argument with offset 0
370
// + 3: argument with offset 1
371
// + 4: ...
372
373
ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord));
374
}
375
376
#ifndef PRODUCT
377
378
void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
379
if (!VerifyOops) return;
380
verify_oop_addr(Address(sp, stack_offset), "oop");
381
}
382
383
void C1_MacroAssembler::verify_not_null_oop(Register r) {
384
if (!VerifyOops) return;
385
Label not_null;
386
cbnz(r, not_null);
387
stop("non-null oop required");
388
bind(not_null);
389
verify_oop(r);
390
}
391
392
void C1_MacroAssembler::invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) {
393
#ifdef ASSERT
394
static int nn;
395
if (inv_r0) mov(r0, 0xDEAD);
396
if (inv_r19) mov(r19, 0xDEAD);
397
if (inv_r2) mov(r2, nn++);
398
if (inv_r3) mov(r3, 0xDEAD);
399
if (inv_r4) mov(r4, 0xDEAD);
400
if (inv_r5) mov(r5, 0xDEAD);
401
#endif
402
}
403
#endif // ifndef PRODUCT
404
405