Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
41153 views
1
/*
2
* Copyright (c) 2018, 2021, Red Hat, Inc. 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/shenandoah/shenandoahBarrierSet.hpp"
27
#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
28
#include "gc/shenandoah/shenandoahForwarding.hpp"
29
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
30
#include "gc/shenandoah/shenandoahHeapRegion.hpp"
31
#include "gc/shenandoah/shenandoahRuntime.hpp"
32
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
33
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
34
#include "interpreter/interpreter.hpp"
35
#include "interpreter/interp_masm.hpp"
36
#include "runtime/sharedRuntime.hpp"
37
#include "runtime/thread.hpp"
38
#ifdef COMPILER1
39
#include "c1/c1_LIRAssembler.hpp"
40
#include "c1/c1_MacroAssembler.hpp"
41
#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
42
#endif
43
44
#define __ masm->
45
46
void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
47
Register src, Register dst, Register count, RegSet saved_regs) {
48
if (is_oop) {
49
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
50
if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
51
52
Label done;
53
54
// Avoid calling runtime if count == 0
55
__ cbz(count, done);
56
57
// Is GC active?
58
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
59
__ ldrb(rscratch1, gc_state);
60
if (ShenandoahSATBBarrier && dest_uninitialized) {
61
__ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
62
} else {
63
__ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
64
__ tst(rscratch1, rscratch2);
65
__ br(Assembler::EQ, done);
66
}
67
68
__ push(saved_regs, sp);
69
if (UseCompressedOops) {
70
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);
71
} else {
72
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
73
}
74
__ pop(saved_regs, sp);
75
__ bind(done);
76
}
77
}
78
}
79
80
void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
81
Register obj,
82
Register pre_val,
83
Register thread,
84
Register tmp,
85
bool tosca_live,
86
bool expand_call) {
87
if (ShenandoahSATBBarrier) {
88
satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call);
89
}
90
}
91
92
void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
93
Register obj,
94
Register pre_val,
95
Register thread,
96
Register tmp,
97
bool tosca_live,
98
bool expand_call) {
99
// If expand_call is true then we expand the call_VM_leaf macro
100
// directly to skip generating the check by
101
// InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
102
103
assert(thread == rthread, "must be");
104
105
Label done;
106
Label runtime;
107
108
assert_different_registers(obj, pre_val, tmp, rscratch1);
109
assert(pre_val != noreg && tmp != noreg, "expecting a register");
110
111
Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()));
112
Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
113
Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
114
115
// Is marking active?
116
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
117
__ ldrw(tmp, in_progress);
118
} else {
119
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
120
__ ldrb(tmp, in_progress);
121
}
122
__ cbzw(tmp, done);
123
124
// Do we need to load the previous value?
125
if (obj != noreg) {
126
__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
127
}
128
129
// Is the previous value null?
130
__ cbz(pre_val, done);
131
132
// Can we store original value in the thread's buffer?
133
// Is index == 0?
134
// (The index field is typed as size_t.)
135
136
__ ldr(tmp, index); // tmp := *index_adr
137
__ cbz(tmp, runtime); // tmp == 0?
138
// If yes, goto runtime
139
140
__ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize
141
__ str(tmp, index); // *index_adr := tmp
142
__ ldr(rscratch1, buffer);
143
__ add(tmp, tmp, rscratch1); // tmp := tmp + *buffer_adr
144
145
// Record the previous value
146
__ str(pre_val, Address(tmp, 0));
147
__ b(done);
148
149
__ bind(runtime);
150
// save the live input values
151
RegSet saved = RegSet::of(pre_val);
152
if (tosca_live) saved += RegSet::of(r0);
153
if (obj != noreg) saved += RegSet::of(obj);
154
155
__ push(saved, sp);
156
157
// Calling the runtime using the regular call_VM_leaf mechanism generates
158
// code (generated by InterpreterMacroAssember::call_VM_leaf_base)
159
// that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.
160
//
161
// If we care generating the pre-barrier without a frame (e.g. in the
162
// intrinsified Reference.get() routine) then ebp might be pointing to
163
// the caller frame and so this check will most likely fail at runtime.
164
//
165
// Expanding the call directly bypasses the generation of the check.
166
// So when we do not have have a full interpreter frame on the stack
167
// expand_call should be passed true.
168
169
if (expand_call) {
170
assert(pre_val != c_rarg1, "smashed arg");
171
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
172
} else {
173
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
174
}
175
176
__ pop(saved, sp);
177
178
__ bind(done);
179
}
180
181
void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) {
182
assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");
183
Label is_null;
184
__ cbz(dst, is_null);
185
resolve_forward_pointer_not_null(masm, dst, tmp);
186
__ bind(is_null);
187
}
188
189
// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2, except those explicitely
190
// passed in.
191
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) {
192
assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");
193
// The below loads the mark word, checks if the lowest two bits are
194
// set, and if so, clear the lowest two bits and copy the result
195
// to dst. Otherwise it leaves dst alone.
196
// Implementing this is surprisingly awkward. I do it here by:
197
// - Inverting the mark word
198
// - Test lowest two bits == 0
199
// - If so, set the lowest two bits
200
// - Invert the result back, and copy to dst
201
202
bool borrow_reg = (tmp == noreg);
203
if (borrow_reg) {
204
// No free registers available. Make one useful.
205
tmp = rscratch1;
206
if (tmp == dst) {
207
tmp = rscratch2;
208
}
209
__ push(RegSet::of(tmp), sp);
210
}
211
212
assert_different_registers(tmp, dst);
213
214
Label done;
215
__ ldr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));
216
__ eon(tmp, tmp, zr);
217
__ ands(zr, tmp, markWord::lock_mask_in_place);
218
__ br(Assembler::NE, done);
219
__ orr(tmp, tmp, markWord::marked_value);
220
__ eon(dst, tmp, zr);
221
__ bind(done);
222
223
if (borrow_reg) {
224
__ pop(RegSet::of(tmp), sp);
225
}
226
}
227
228
void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, DecoratorSet decorators) {
229
assert(ShenandoahLoadRefBarrier, "Should be enabled");
230
assert(dst != rscratch2, "need rscratch2");
231
assert_different_registers(load_addr.base(), load_addr.index(), rscratch1, rscratch2);
232
233
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
234
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
235
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
236
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
237
bool is_narrow = UseCompressedOops && !is_native;
238
239
Label heap_stable, not_cset;
240
__ enter();
241
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
242
__ ldrb(rscratch2, gc_state);
243
244
// Check for heap stability
245
if (is_strong) {
246
__ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);
247
} else {
248
Label lrb;
249
__ tbnz(rscratch2, ShenandoahHeap::WEAK_ROOTS_BITPOS, lrb);
250
__ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);
251
__ bind(lrb);
252
}
253
254
// use r1 for load address
255
Register result_dst = dst;
256
if (dst == r1) {
257
__ mov(rscratch1, dst);
258
dst = rscratch1;
259
}
260
261
// Save r0 and r1, unless it is an output register
262
RegSet to_save = RegSet::of(r0, r1) - result_dst;
263
__ push(to_save, sp);
264
__ lea(r1, load_addr);
265
__ mov(r0, dst);
266
267
// Test for in-cset
268
if (is_strong) {
269
__ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr());
270
__ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint());
271
__ ldrb(rscratch2, Address(rscratch2, rscratch1));
272
__ tbz(rscratch2, 0, not_cset);
273
}
274
275
__ push_call_clobbered_registers();
276
if (is_strong) {
277
if (is_narrow) {
278
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow));
279
} else {
280
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));
281
}
282
} else if (is_weak) {
283
if (is_narrow) {
284
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow));
285
} else {
286
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak));
287
}
288
} else {
289
assert(is_phantom, "only remaining strength");
290
assert(!is_narrow, "phantom access cannot be narrow");
291
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));
292
}
293
__ blr(lr);
294
__ mov(rscratch1, r0);
295
__ pop_call_clobbered_registers();
296
__ mov(r0, rscratch1);
297
298
__ bind(not_cset);
299
300
__ mov(result_dst, r0);
301
__ pop(to_save, sp);
302
303
__ bind(heap_stable);
304
__ leave();
305
}
306
307
void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {
308
if (ShenandoahIUBarrier) {
309
__ push_call_clobbered_registers();
310
satb_write_barrier_pre(masm, noreg, dst, rthread, tmp, true, false);
311
__ pop_call_clobbered_registers();
312
}
313
}
314
315
//
316
// Arguments:
317
//
318
// Inputs:
319
// src: oop location to load from, might be clobbered
320
//
321
// Output:
322
// dst: oop loaded from src location
323
//
324
// Kill:
325
// rscratch1 (scratch reg)
326
//
327
// Alias:
328
// dst: rscratch1 (might use rscratch1 as temporary output register to avoid clobbering src)
329
//
330
void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
331
Register dst, Address src, Register tmp1, Register tmp_thread) {
332
// 1: non-reference load, no additional barrier is needed
333
if (!is_reference_type(type)) {
334
BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
335
return;
336
}
337
338
// 2: load a reference from src location and apply LRB if needed
339
if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) {
340
Register result_dst = dst;
341
342
// Preserve src location for LRB
343
if (dst == src.base() || dst == src.index()) {
344
dst = rscratch1;
345
}
346
assert_different_registers(dst, src.base(), src.index());
347
348
BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
349
350
load_reference_barrier(masm, dst, src, decorators);
351
352
if (dst != result_dst) {
353
__ mov(result_dst, dst);
354
dst = result_dst;
355
}
356
} else {
357
BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
358
}
359
360
// 3: apply keep-alive barrier if needed
361
if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
362
__ enter();
363
__ push_call_clobbered_registers();
364
satb_write_barrier_pre(masm /* masm */,
365
noreg /* obj */,
366
dst /* pre_val */,
367
rthread /* thread */,
368
tmp1 /* tmp */,
369
true /* tosca_live */,
370
true /* expand_call */);
371
__ pop_call_clobbered_registers();
372
__ leave();
373
}
374
}
375
376
void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
377
Address dst, Register val, Register tmp1, Register tmp2) {
378
bool on_oop = is_reference_type(type);
379
if (!on_oop) {
380
BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
381
return;
382
}
383
384
// flatten object address if needed
385
if (dst.index() == noreg && dst.offset() == 0) {
386
if (dst.base() != r3) {
387
__ mov(r3, dst.base());
388
}
389
} else {
390
__ lea(r3, dst);
391
}
392
393
shenandoah_write_barrier_pre(masm,
394
r3 /* obj */,
395
tmp2 /* pre_val */,
396
rthread /* thread */,
397
tmp1 /* tmp */,
398
val != noreg /* tosca_live */,
399
false /* expand_call */);
400
401
if (val == noreg) {
402
BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), noreg, noreg, noreg);
403
} else {
404
iu_barrier(masm, val, tmp1);
405
// G1 barrier needs uncompressed oop for region cross check.
406
Register new_val = val;
407
if (UseCompressedOops) {
408
new_val = rscratch2;
409
__ mov(new_val, val);
410
}
411
BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), val, noreg, noreg);
412
}
413
414
}
415
416
void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
417
Register obj, Register tmp, Label& slowpath) {
418
Label done;
419
// Resolve jobject
420
BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
421
422
// Check for null.
423
__ cbz(obj, done);
424
425
assert(obj != rscratch2, "need rscratch2");
426
Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
427
__ lea(rscratch2, gc_state);
428
__ ldrb(rscratch2, Address(rscratch2));
429
430
// Check for heap in evacuation phase
431
__ tbnz(rscratch2, ShenandoahHeap::EVACUATION_BITPOS, slowpath);
432
433
__ bind(done);
434
}
435
436
// Special Shenandoah CAS implementation that handles false negatives due
437
// to concurrent evacuation. The service is more complex than a
438
// traditional CAS operation because the CAS operation is intended to
439
// succeed if the reference at addr exactly matches expected or if the
440
// reference at addr holds a pointer to a from-space object that has
441
// been relocated to the location named by expected. There are two
442
// races that must be addressed:
443
// a) A parallel thread may mutate the contents of addr so that it points
444
// to a different object. In this case, the CAS operation should fail.
445
// b) A parallel thread may heal the contents of addr, replacing a
446
// from-space pointer held in addr with the to-space pointer
447
// representing the new location of the object.
448
// Upon entry to cmpxchg_oop, it is assured that new_val equals NULL
449
// or it refers to an object that is not being evacuated out of
450
// from-space, or it refers to the to-space version of an object that
451
// is being evacuated out of from-space.
452
//
453
// By default the value held in the result register following execution
454
// of the generated code sequence is 0 to indicate failure of CAS,
455
// non-zero to indicate success. If is_cae, the result is the value most
456
// recently fetched from addr rather than a boolean success indicator.
457
//
458
// Clobbers rscratch1, rscratch2
459
void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,
460
Register addr,
461
Register expected,
462
Register new_val,
463
bool acquire, bool release,
464
bool is_cae,
465
Register result) {
466
Register tmp1 = rscratch1;
467
Register tmp2 = rscratch2;
468
bool is_narrow = UseCompressedOops;
469
Assembler::operand_size size = is_narrow ? Assembler::word : Assembler::xword;
470
471
assert_different_registers(addr, expected, tmp1, tmp2);
472
assert_different_registers(addr, new_val, tmp1, tmp2);
473
474
Label step4, done;
475
476
// There are two ways to reach this label. Initial entry into the
477
// cmpxchg_oop code expansion starts at step1 (which is equivalent
478
// to label step4). Additionally, in the rare case that four steps
479
// are required to perform the requested operation, the fourth step
480
// is the same as the first. On a second pass through step 1,
481
// control may flow through step 2 on its way to failure. It will
482
// not flow from step 2 to step 3 since we are assured that the
483
// memory at addr no longer holds a from-space pointer.
484
//
485
// The comments that immediately follow the step4 label apply only
486
// to the case in which control reaches this label by branch from
487
// step 3.
488
489
__ bind (step4);
490
491
// Step 4. CAS has failed because the value most recently fetched
492
// from addr is no longer the from-space pointer held in tmp2. If a
493
// different thread replaced the in-memory value with its equivalent
494
// to-space pointer, then CAS may still be able to succeed. The
495
// value held in the expected register has not changed.
496
//
497
// It is extremely rare we reach this point. For this reason, the
498
// implementation opts for smaller rather than potentially faster
499
// code. Ultimately, smaller code for this rare case most likely
500
// delivers higher overall throughput by enabling improved icache
501
// performance.
502
503
// Step 1. Fast-path.
504
//
505
// Try to CAS with given arguments. If successful, then we are done.
506
//
507
// No label required for step 1.
508
509
__ cmpxchg(addr, expected, new_val, size, acquire, release, false, tmp2);
510
// EQ flag set iff success. tmp2 holds value fetched.
511
512
// If expected equals null but tmp2 does not equal null, the
513
// following branches to done to report failure of CAS. If both
514
// expected and tmp2 equal null, the following branches to done to
515
// report success of CAS. There's no need for a special test of
516
// expected equal to null.
517
518
__ br(Assembler::EQ, done);
519
// if CAS failed, fall through to step 2
520
521
// Step 2. CAS has failed because the value held at addr does not
522
// match expected. This may be a false negative because the value fetched
523
// from addr (now held in tmp2) may be a from-space pointer to the
524
// original copy of same object referenced by to-space pointer expected.
525
//
526
// To resolve this, it suffices to find the forward pointer associated
527
// with fetched value. If this matches expected, retry CAS with new
528
// parameters. If this mismatches, then we have a legitimate
529
// failure, and we're done.
530
//
531
// No need for step2 label.
532
533
// overwrite tmp1 with from-space pointer fetched from memory
534
__ mov(tmp1, tmp2);
535
536
if (is_narrow) {
537
// Decode tmp1 in order to resolve its forward pointer
538
__ decode_heap_oop(tmp1, tmp1);
539
}
540
resolve_forward_pointer(masm, tmp1);
541
// Encode tmp1 to compare against expected.
542
__ encode_heap_oop(tmp1, tmp1);
543
544
// Does forwarded value of fetched from-space pointer match original
545
// value of expected? If tmp1 holds null, this comparison will fail
546
// because we know from step1 that expected is not null. There is
547
// no need for a separate test for tmp1 (the value originally held
548
// in memory) equal to null.
549
__ cmp(tmp1, expected);
550
551
// If not, then the failure was legitimate and we're done.
552
// Branching to done with NE condition denotes failure.
553
__ br(Assembler::NE, done);
554
555
// Fall through to step 3. No need for step3 label.
556
557
// Step 3. We've confirmed that the value originally held in memory
558
// (now held in tmp2) pointed to from-space version of original
559
// expected value. Try the CAS again with the from-space expected
560
// value. If it now succeeds, we're good.
561
//
562
// Note: tmp2 holds encoded from-space pointer that matches to-space
563
// object residing at expected. tmp2 is the new "expected".
564
565
// Note that macro implementation of __cmpxchg cannot use same register
566
// tmp2 for result and expected since it overwrites result before it
567
// compares result with expected.
568
__ cmpxchg(addr, tmp2, new_val, size, acquire, release, false, noreg);
569
// EQ flag set iff success. tmp2 holds value fetched, tmp1 (rscratch1) clobbered.
570
571
// If fetched value did not equal the new expected, this could
572
// still be a false negative because some other thread may have
573
// newly overwritten the memory value with its to-space equivalent.
574
__ br(Assembler::NE, step4);
575
576
if (is_cae) {
577
// We're falling through to done to indicate success. Success
578
// with is_cae is denoted by returning the value of expected as
579
// result.
580
__ mov(tmp2, expected);
581
}
582
583
__ bind(done);
584
// At entry to done, the Z (EQ) flag is on iff if the CAS
585
// operation was successful. Additionally, if is_cae, tmp2 holds
586
// the value most recently fetched from addr. In this case, success
587
// is denoted by tmp2 matching expected.
588
589
if (is_cae) {
590
__ mov(result, tmp2);
591
} else {
592
__ cset(result, Assembler::EQ);
593
}
594
}
595
596
#undef __
597
598
#ifdef COMPILER1
599
600
#define __ ce->masm()->
601
602
void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
603
ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
604
// At this point we know that marking is in progress.
605
// If do_load() is true then we have to emit the
606
// load of the previous value; otherwise it has already
607
// been loaded into _pre_val.
608
609
__ bind(*stub->entry());
610
611
assert(stub->pre_val()->is_register(), "Precondition.");
612
613
Register pre_val_reg = stub->pre_val()->as_register();
614
615
if (stub->do_load()) {
616
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
617
}
618
__ cbz(pre_val_reg, *stub->continuation());
619
ce->store_parameter(stub->pre_val()->as_register(), 0);
620
__ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));
621
__ b(*stub->continuation());
622
}
623
624
void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) {
625
ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
626
__ bind(*stub->entry());
627
628
DecoratorSet decorators = stub->decorators();
629
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
630
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
631
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
632
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
633
634
Register obj = stub->obj()->as_register();
635
Register res = stub->result()->as_register();
636
Register addr = stub->addr()->as_pointer_register();
637
Register tmp1 = stub->tmp1()->as_register();
638
Register tmp2 = stub->tmp2()->as_register();
639
640
assert(res == r0, "result must arrive in r0");
641
642
if (res != obj) {
643
__ mov(res, obj);
644
}
645
646
if (is_strong) {
647
// Check for object in cset.
648
__ mov(tmp2, ShenandoahHeap::in_cset_fast_test_addr());
649
__ lsr(tmp1, res, ShenandoahHeapRegion::region_size_bytes_shift_jint());
650
__ ldrb(tmp2, Address(tmp2, tmp1));
651
__ cbz(tmp2, *stub->continuation());
652
}
653
654
ce->store_parameter(res, 0);
655
ce->store_parameter(addr, 1);
656
if (is_strong) {
657
if (is_native) {
658
__ far_call(RuntimeAddress(bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin()));
659
} else {
660
__ far_call(RuntimeAddress(bs->load_reference_barrier_strong_rt_code_blob()->code_begin()));
661
}
662
} else if (is_weak) {
663
__ far_call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin()));
664
} else {
665
assert(is_phantom, "only remaining strength");
666
__ far_call(RuntimeAddress(bs->load_reference_barrier_phantom_rt_code_blob()->code_begin()));
667
}
668
669
__ b(*stub->continuation());
670
}
671
672
#undef __
673
674
#define __ sasm->
675
676
void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
677
__ prologue("shenandoah_pre_barrier", false);
678
679
// arg0 : previous value of memory
680
681
BarrierSet* bs = BarrierSet::barrier_set();
682
683
const Register pre_val = r0;
684
const Register thread = rthread;
685
const Register tmp = rscratch1;
686
687
Address queue_index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
688
Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
689
690
Label done;
691
Label runtime;
692
693
// Is marking still active?
694
Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
695
__ ldrb(tmp, gc_state);
696
__ tbz(tmp, ShenandoahHeap::MARKING_BITPOS, done);
697
698
// Can we store original value in the thread's buffer?
699
__ ldr(tmp, queue_index);
700
__ cbz(tmp, runtime);
701
702
__ sub(tmp, tmp, wordSize);
703
__ str(tmp, queue_index);
704
__ ldr(rscratch2, buffer);
705
__ add(tmp, tmp, rscratch2);
706
__ load_parameter(0, rscratch2);
707
__ str(rscratch2, Address(tmp, 0));
708
__ b(done);
709
710
__ bind(runtime);
711
__ push_call_clobbered_registers();
712
__ load_parameter(0, pre_val);
713
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
714
__ pop_call_clobbered_registers();
715
__ bind(done);
716
717
__ epilogue();
718
}
719
720
void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, DecoratorSet decorators) {
721
__ prologue("shenandoah_load_reference_barrier", false);
722
// arg0 : object to be resolved
723
724
__ push_call_clobbered_registers();
725
__ load_parameter(0, r0);
726
__ load_parameter(1, r1);
727
728
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
729
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
730
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
731
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
732
if (is_strong) {
733
if (is_native) {
734
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));
735
} else {
736
if (UseCompressedOops) {
737
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow));
738
} else {
739
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));
740
}
741
}
742
} else if (is_weak) {
743
assert(!is_native, "weak must not be called off-heap");
744
if (UseCompressedOops) {
745
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow));
746
} else {
747
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak));
748
}
749
} else {
750
assert(is_phantom, "only remaining strength");
751
assert(is_native, "phantom must only be called off-heap");
752
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));
753
}
754
__ blr(lr);
755
__ mov(rscratch1, r0);
756
__ pop_call_clobbered_registers();
757
__ mov(r0, rscratch1);
758
759
__ epilogue();
760
}
761
762
#undef __
763
764
#endif // COMPILER1
765
766