Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
66646 views
1
/*
2
* Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
3
* Copyright (c) 2012, 2021 SAP SE. 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 "gc/shared/gcArguments.hpp"
27
#include "gc/shared/gc_globals.hpp"
28
#include "macroAssembler_ppc.hpp"
29
#include "precompiled.hpp"
30
#include "asm/macroAssembler.inline.hpp"
31
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
32
#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
33
#include "gc/shenandoah/shenandoahForwarding.hpp"
34
#include "gc/shenandoah/shenandoahHeap.hpp"
35
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
36
#include "gc/shenandoah/shenandoahHeapRegion.hpp"
37
#include "gc/shenandoah/shenandoahRuntime.hpp"
38
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
39
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
40
#include "interpreter/interpreter.hpp"
41
#include "runtime/sharedRuntime.hpp"
42
#include "runtime/thread.hpp"
43
#include "utilities/globalDefinitions.hpp"
44
#include "vm_version_ppc.hpp"
45
46
#ifdef COMPILER1
47
48
#include "c1/c1_LIRAssembler.hpp"
49
#include "c1/c1_MacroAssembler.hpp"
50
#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
51
52
#endif
53
54
#define __ masm->
55
56
void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm,
57
Register base, RegisterOrConstant ind_or_offs,
58
Register tmp1, Register tmp2, Register tmp3,
59
MacroAssembler::PreservationLevel preservation_level) {
60
if (ShenandoahSATBBarrier) {
61
__ block_comment("satb_write_barrier (shenandoahgc) {");
62
satb_write_barrier_impl(masm, 0, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level);
63
__ block_comment("} satb_write_barrier (shenandoahgc)");
64
}
65
}
66
67
void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler *masm,
68
Register val,
69
Register tmp1, Register tmp2,
70
MacroAssembler::PreservationLevel preservation_level,
71
DecoratorSet decorators) {
72
// IU barriers are also employed to avoid resurrection of weak references,
73
// even if Shenandoah does not operate in incremental update mode.
74
if (ShenandoahIUBarrier || ShenandoahSATBBarrier) {
75
__ block_comment("iu_barrier (shenandoahgc) {");
76
satb_write_barrier_impl(masm, decorators, noreg, noreg, val, tmp1, tmp2, preservation_level);
77
__ block_comment("} iu_barrier (shenandoahgc)");
78
}
79
}
80
81
void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators,
82
Register base, RegisterOrConstant ind_or_offs,
83
Register dst,
84
Register tmp1, Register tmp2,
85
MacroAssembler::PreservationLevel preservation_level) {
86
if (ShenandoahLoadRefBarrier) {
87
__ block_comment("load_reference_barrier (shenandoahgc) {");
88
load_reference_barrier_impl(masm, decorators, base, ind_or_offs, dst, tmp1, tmp2, preservation_level);
89
__ block_comment("} load_reference_barrier (shenandoahgc)");
90
}
91
}
92
93
void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, DecoratorSet decorators, BasicType type,
94
Register src, Register dst, Register count,
95
Register preserve1, Register preserve2) {
96
__ block_comment("arraycopy_prologue (shenandoahgc) {");
97
98
Register R11_tmp = R11_scratch1;
99
100
assert_different_registers(src, dst, count, R11_tmp, noreg);
101
if (preserve1 != noreg) {
102
// Technically not required, but likely to indicate an error.
103
assert_different_registers(preserve1, preserve2);
104
}
105
106
/* ==== Check whether barrier is required (optimizations) ==== */
107
// Fast path: Component type of array is not a reference type.
108
if (!is_reference_type(type)) {
109
return;
110
}
111
112
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
113
114
// Fast path: No barrier required if for every barrier type, it is either disabled or would not store
115
// any useful information.
116
if ((!ShenandoahSATBBarrier || dest_uninitialized) && !ShenandoahIUBarrier && !ShenandoahLoadRefBarrier) {
117
return;
118
}
119
120
Label skip_prologue;
121
122
// Fast path: Array is of length zero.
123
__ cmpdi(CCR0, count, 0);
124
__ beq(CCR0, skip_prologue);
125
126
/* ==== Check whether barrier is required (gc state) ==== */
127
__ lbz(R11_tmp, in_bytes(ShenandoahThreadLocalData::gc_state_offset()),
128
R16_thread);
129
130
// The set of garbage collection states requiring barriers depends on the available barrier types and the
131
// type of the reference in question.
132
// For instance, satb barriers may be skipped if it is certain that the overridden values are not relevant
133
// for the garbage collector.
134
const int required_states = ShenandoahSATBBarrier && dest_uninitialized
135
? ShenandoahHeap::HAS_FORWARDED
136
: ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING;
137
138
__ andi_(R11_tmp, R11_tmp, required_states);
139
__ beq(CCR0, skip_prologue);
140
141
/* ==== Invoke runtime ==== */
142
// Save to-be-preserved registers.
143
int highest_preserve_register_index = 0;
144
{
145
if (preserve1 != noreg && preserve1->is_volatile()) {
146
__ std(preserve1, -BytesPerWord * ++highest_preserve_register_index, R1_SP);
147
}
148
if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) {
149
__ std(preserve2, -BytesPerWord * ++highest_preserve_register_index, R1_SP);
150
}
151
152
__ std(src, -BytesPerWord * ++highest_preserve_register_index, R1_SP);
153
__ std(dst, -BytesPerWord * ++highest_preserve_register_index, R1_SP);
154
__ std(count, -BytesPerWord * ++highest_preserve_register_index, R1_SP);
155
156
__ save_LR_CR(R11_tmp);
157
__ push_frame_reg_args(-BytesPerWord * highest_preserve_register_index,
158
R11_tmp);
159
}
160
161
// Invoke runtime.
162
address jrt_address = NULL;
163
if (UseCompressedOops) {
164
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry);
165
} else {
166
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry);
167
}
168
assert(jrt_address != nullptr, "jrt routine cannot be found");
169
170
__ call_VM_leaf(jrt_address, src, dst, count);
171
172
// Restore to-be-preserved registers.
173
{
174
__ pop_frame();
175
__ restore_LR_CR(R11_tmp);
176
177
__ ld(count, -BytesPerWord * highest_preserve_register_index--, R1_SP);
178
__ ld(dst, -BytesPerWord * highest_preserve_register_index--, R1_SP);
179
__ ld(src, -BytesPerWord * highest_preserve_register_index--, R1_SP);
180
181
if (preserve2 != noreg && preserve2 != preserve1 && preserve2->is_volatile()) {
182
__ ld(preserve2, -BytesPerWord * highest_preserve_register_index--, R1_SP);
183
}
184
if (preserve1 != noreg && preserve1->is_volatile()) {
185
__ ld(preserve1, -BytesPerWord * highest_preserve_register_index--, R1_SP);
186
}
187
}
188
189
__ bind(skip_prologue);
190
__ block_comment("} arraycopy_prologue (shenandoahgc)");
191
}
192
193
// The to-be-enqueued value can either be determined
194
// - dynamically by passing the reference's address information (load mode) or
195
// - statically by passing a register the value is stored in (preloaded mode)
196
// - for performance optimizations in cases where the previous value is known (currently not implemented) and
197
// - for incremental-update barriers.
198
//
199
// decorators: The previous value's decorator set.
200
// In "load mode", the value must equal '0'.
201
// base: Base register of the reference's address (load mode).
202
// In "preloaded mode", the register must equal 'noreg'.
203
// ind_or_offs: Index or offset of the reference's address (load mode).
204
// If 'base' equals 'noreg' (preloaded mode), the passed value is ignored.
205
// pre_val: Register holding the to-be-stored value (preloaded mode).
206
// In "load mode", this register acts as a temporary register and must
207
// thus not be 'noreg'. In "preloaded mode", its content will be sustained.
208
// tmp1/tmp2: Temporary registers, one of which must be non-volatile in "preloaded mode".
209
void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm, DecoratorSet decorators,
210
Register base, RegisterOrConstant ind_or_offs,
211
Register pre_val,
212
Register tmp1, Register tmp2,
213
MacroAssembler::PreservationLevel preservation_level) {
214
assert_different_registers(tmp1, tmp2, pre_val, noreg);
215
216
Label skip_barrier;
217
218
/* ==== Determine necessary runtime invocation preservation measures ==== */
219
const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR;
220
const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS;
221
const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS;
222
223
// Check whether marking is active.
224
__ lbz(tmp1, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread);
225
226
__ andi_(tmp1, tmp1, ShenandoahHeap::MARKING);
227
__ beq(CCR0, skip_barrier);
228
229
/* ==== Determine the reference's previous value ==== */
230
bool preloaded_mode = base == noreg;
231
Register pre_val_save = noreg;
232
233
if (preloaded_mode) {
234
// Previous value has been passed to the method, so it must not be determined manually.
235
// In case 'pre_val' is a volatile register, it must be saved across the C-call
236
// as callers may depend on its value.
237
// Unless the general purposes registers are saved anyway, one of the temporary registers
238
// (i.e., 'tmp1' and 'tmp2') is used to the preserve 'pre_val'.
239
if (!preserve_gp_registers && pre_val->is_volatile()) {
240
pre_val_save = !tmp1->is_volatile() ? tmp1 : tmp2;
241
assert(!pre_val_save->is_volatile(), "at least one of the temporary registers must be non-volatile");
242
}
243
244
if ((decorators & IS_NOT_NULL) != 0) {
245
#ifdef ASSERT
246
__ cmpdi(CCR0, pre_val, 0);
247
__ asm_assert_ne("null oop is not allowed");
248
#endif // ASSERT
249
} else {
250
__ cmpdi(CCR0, pre_val, 0);
251
__ beq(CCR0, skip_barrier);
252
}
253
} else {
254
// Load from the reference address to determine the reference's current value (before the store is being performed).
255
// Contrary to the given value in "preloaded mode", it is not necessary to preserve it.
256
assert(decorators == 0, "decorator set must be empty");
257
assert(base != noreg, "base must be a register");
258
assert(!ind_or_offs.is_register() || ind_or_offs.as_register() != noreg, "ind_or_offs must be a register");
259
if (UseCompressedOops) {
260
__ lwz(pre_val, ind_or_offs, base);
261
} else {
262
__ ld(pre_val, ind_or_offs, base);
263
}
264
265
__ cmpdi(CCR0, pre_val, 0);
266
__ beq(CCR0, skip_barrier);
267
268
if (UseCompressedOops) {
269
__ decode_heap_oop_not_null(pre_val);
270
}
271
}
272
273
/* ==== Try to enqueue the to-be-stored value directly into thread's local SATB mark queue ==== */
274
{
275
Label runtime;
276
Register Rbuffer = tmp1, Rindex = tmp2;
277
278
// Check whether the queue has enough capacity to store another oop.
279
// If not, jump to the runtime to commit the buffer and to allocate a new one.
280
// (The buffer's index corresponds to the amount of remaining free space.)
281
__ ld(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
282
__ cmpdi(CCR0, Rindex, 0);
283
__ beq(CCR0, runtime); // If index == 0 (buffer is full), goto runtime.
284
285
// Capacity suffices. Decrement the queue's size by the size of one oop.
286
// (The buffer is filled contrary to the heap's growing direction, i.e., it is filled downwards.)
287
__ addi(Rindex, Rindex, -wordSize);
288
__ std(Rindex, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
289
290
// Enqueue the previous value and skip the invocation of the runtime.
291
__ ld(Rbuffer, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread);
292
__ stdx(pre_val, Rbuffer, Rindex);
293
__ b(skip_barrier);
294
295
__ bind(runtime);
296
}
297
298
/* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */
299
// Save to-be-preserved registers.
300
int nbytes_save = 0;
301
302
if (needs_frame) {
303
if (preserve_gp_registers) {
304
nbytes_save = (preserve_fp_registers
305
? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs
306
: MacroAssembler::num_volatile_gp_regs) * BytesPerWord;
307
__ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers);
308
}
309
310
__ save_LR_CR(tmp1);
311
__ push_frame_reg_args(nbytes_save, tmp2);
312
}
313
314
if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) {
315
assert(pre_val_save != noreg, "nv_save must not be noreg");
316
317
// 'pre_val' register must be saved manually unless general-purpose are preserved in general.
318
__ mr(pre_val_save, pre_val);
319
}
320
321
// Invoke runtime.
322
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, R16_thread);
323
324
// Restore to-be-preserved registers.
325
if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) {
326
__ mr(pre_val, pre_val_save);
327
}
328
329
if (needs_frame) {
330
__ pop_frame();
331
__ restore_LR_CR(tmp1);
332
333
if (preserve_gp_registers) {
334
__ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers);
335
}
336
}
337
338
__ bind(skip_barrier);
339
}
340
341
void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler *masm, Register dst, Register tmp) {
342
__ block_comment("resolve_forward_pointer_not_null (shenandoahgc) {");
343
344
Register tmp1 = tmp,
345
R0_tmp2 = R0;
346
assert_different_registers(dst, tmp1, R0_tmp2, noreg);
347
348
// If the object has been evacuated, the mark word layout is as follows:
349
// | forwarding pointer (62-bit) | '11' (2-bit) |
350
351
// The invariant that stack/thread pointers have the lowest two bits cleared permits retrieving
352
// the forwarding pointer solely by inversing the lowest two bits.
353
// This invariant follows inevitably from hotspot's minimal alignment.
354
assert(markWord::marked_value <= (unsigned long) MinObjAlignmentInBytes,
355
"marked value must not be higher than hotspot's minimal alignment");
356
357
Label done;
358
359
// Load the object's mark word.
360
__ ld(tmp1, oopDesc::mark_offset_in_bytes(), dst);
361
362
// Load the bit mask for the lock bits.
363
__ li(R0_tmp2, markWord::lock_mask_in_place);
364
365
// Check whether all bits matching the bit mask are set.
366
// If that is the case, the object has been evacuated and the most significant bits form the forward pointer.
367
__ andc_(R0_tmp2, R0_tmp2, tmp1);
368
369
assert(markWord::lock_mask_in_place == markWord::marked_value,
370
"marked value must equal the value obtained when all lock bits are being set");
371
if (VM_Version::has_isel()) {
372
__ xori(tmp1, tmp1, markWord::lock_mask_in_place);
373
__ isel(dst, CCR0, Assembler::equal, false, tmp1);
374
} else {
375
__ bne(CCR0, done);
376
__ xori(dst, tmp1, markWord::lock_mask_in_place);
377
}
378
379
__ bind(done);
380
__ block_comment("} resolve_forward_pointer_not_null (shenandoahgc)");
381
}
382
383
// base: Base register of the reference's address.
384
// ind_or_offs: Index or offset of the reference's address (load mode).
385
// dst: Reference's address. In case the object has been evacuated, this is the to-space version
386
// of that object.
387
void ShenandoahBarrierSetAssembler::load_reference_barrier_impl(
388
MacroAssembler *masm, DecoratorSet decorators,
389
Register base, RegisterOrConstant ind_or_offs,
390
Register dst,
391
Register tmp1, Register tmp2,
392
MacroAssembler::PreservationLevel preservation_level) {
393
if (ind_or_offs.is_register()) {
394
assert_different_registers(tmp1, tmp2, base, ind_or_offs.as_register(), dst, noreg);
395
} else {
396
assert_different_registers(tmp1, tmp2, base, dst, noreg);
397
}
398
399
Label skip_barrier;
400
401
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
402
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
403
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
404
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
405
bool is_narrow = UseCompressedOops && !is_native;
406
407
/* ==== Check whether heap is stable ==== */
408
__ lbz(tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread);
409
410
if (is_strong) {
411
// For strong references, the heap is considered stable if "has forwarded" is not active.
412
__ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION);
413
__ beq(CCR0, skip_barrier);
414
#ifdef ASSERT
415
// "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set.
416
__ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED);
417
__ asm_assert_ne("'has forwarded' is missing");
418
#endif // ASSERT
419
} else {
420
// For all non-strong references, the heap is considered stable if not any of "has forwarded",
421
// "root set processing", and "weak reference processing" is active.
422
// The additional phase conditions are in place to avoid the resurrection of weak references (see JDK-8266440).
423
Label skip_fastpath;
424
__ andi_(tmp1, tmp2, ShenandoahHeap::WEAK_ROOTS);
425
__ bne(CCR0, skip_fastpath);
426
427
__ andi_(tmp1, tmp2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION);
428
__ beq(CCR0, skip_barrier);
429
#ifdef ASSERT
430
// "evacuation" -> (implies) "has forwarded". If we reach this code, "has forwarded" must thus be set.
431
__ andi_(tmp1, tmp1, ShenandoahHeap::HAS_FORWARDED);
432
__ asm_assert_ne("'has forwarded' is missing");
433
#endif // ASSERT
434
435
__ bind(skip_fastpath);
436
}
437
438
/* ==== Check whether region is in collection set ==== */
439
if (is_strong) {
440
// Shenandoah stores metadata on regions in a continuous area of memory in which a single byte corresponds to
441
// an entire region of the shenandoah heap. At present, only the least significant bit is of significance
442
// and indicates whether the region is part of the collection set.
443
//
444
// All regions are of the same size and are always aligned by a power of two.
445
// Any address can thus be shifted by a fixed number of bits to retrieve the address prefix shared by
446
// all objects within that region (region identification bits).
447
//
448
// | unused bits | region identification bits | object identification bits |
449
// (Region size depends on a couple of criteria, such as page size, user-provided arguments and the max heap size.
450
// The number of object identification bits can thus not be determined at compile time.)
451
//
452
// ------------------------------------------------------- <--- cs (collection set) base address
453
// | lost space due to heap space base address -> 'ShenandoahHeap::in_cset_fast_test_addr()'
454
// | (region identification bits contain heap base offset)
455
// |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift)
456
// | collection set in the proper -> shift: 'region_size_bytes_shift_jint()'
457
// |
458
// |------------------------------------------------------ <--- cs base address + (heap_base >> region size shift)
459
// + number of regions
460
__ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1);
461
__ srdi(tmp1, dst, ShenandoahHeapRegion::region_size_bytes_shift_jint());
462
__ lbzx(tmp2, tmp1, tmp2);
463
__ andi_(tmp2, tmp2, 1);
464
__ beq(CCR0, skip_barrier);
465
}
466
467
/* ==== Invoke runtime ==== */
468
// Save to-be-preserved registers.
469
int nbytes_save = 0;
470
471
const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR;
472
const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS;
473
const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS;
474
475
if (needs_frame) {
476
if (preserve_gp_registers) {
477
nbytes_save = (preserve_fp_registers
478
? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs
479
: MacroAssembler::num_volatile_gp_regs) * BytesPerWord;
480
__ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers);
481
}
482
483
__ save_LR_CR(tmp1);
484
__ push_frame_reg_args(nbytes_save, tmp1);
485
}
486
487
// Calculate the reference's absolute address.
488
__ add(R4_ARG2, ind_or_offs, base);
489
490
// Invoke runtime.
491
address jrt_address = nullptr;
492
493
if (is_strong) {
494
if (is_narrow) {
495
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow);
496
} else {
497
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
498
}
499
} else if (is_weak) {
500
if (is_narrow) {
501
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow);
502
} else {
503
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
504
}
505
} else {
506
assert(is_phantom, "only remaining strength");
507
assert(!is_narrow, "phantom access cannot be narrow");
508
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
509
}
510
assert(jrt_address != nullptr, "jrt routine cannot be found");
511
512
__ call_VM_leaf(jrt_address, dst /* reference */, R4_ARG2 /* reference address */);
513
514
// Restore to-be-preserved registers.
515
if (preserve_gp_registers) {
516
__ mr(R0, R3_RET);
517
} else {
518
__ mr_if_needed(dst, R3_RET);
519
}
520
521
if (needs_frame) {
522
__ pop_frame();
523
__ restore_LR_CR(tmp1);
524
525
if (preserve_gp_registers) {
526
__ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers);
527
__ mr(dst, R0);
528
}
529
}
530
531
__ bind(skip_barrier);
532
}
533
534
// base: Base register of the reference's address.
535
// ind_or_offs: Index or offset of the reference's address.
536
// L_handle_null: An optional label that will be jumped to if the reference is null.
537
void ShenandoahBarrierSetAssembler::load_at(
538
MacroAssembler *masm, DecoratorSet decorators, BasicType type,
539
Register base, RegisterOrConstant ind_or_offs, Register dst,
540
Register tmp1, Register tmp2,
541
MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null) {
542
// Register must not clash, except 'base' and 'dst'.
543
if (ind_or_offs.is_register()) {
544
if (base != noreg) {
545
assert_different_registers(tmp1, tmp2, base, ind_or_offs.register_or_noreg(), R0, noreg);
546
}
547
assert_different_registers(tmp1, tmp2, dst, ind_or_offs.register_or_noreg(), R0, noreg);
548
} else {
549
if (base == noreg) {
550
assert_different_registers(tmp1, tmp2, base, R0, noreg);
551
}
552
assert_different_registers(tmp1, tmp2, dst, R0, noreg);
553
}
554
555
/* ==== Apply load barrier, if required ==== */
556
if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) {
557
assert(is_reference_type(type), "need_load_reference_barrier must check whether type is a reference type");
558
559
// If 'dst' clashes with either 'base' or 'ind_or_offs', use an intermediate result register
560
// to keep the values of those alive until the load reference barrier is applied.
561
Register intermediate_dst = (dst == base || (ind_or_offs.is_register() && dst == ind_or_offs.as_register()))
562
? tmp2
563
: dst;
564
565
BarrierSetAssembler::load_at(masm, decorators, type,
566
base, ind_or_offs,
567
intermediate_dst,
568
tmp1, noreg,
569
preservation_level, L_handle_null);
570
571
load_reference_barrier(masm, decorators,
572
base, ind_or_offs,
573
intermediate_dst,
574
tmp1, R0,
575
preservation_level);
576
577
__ mr_if_needed(dst, intermediate_dst);
578
} else {
579
BarrierSetAssembler::load_at(masm, decorators, type,
580
base, ind_or_offs,
581
dst,
582
tmp1, tmp2,
583
preservation_level, L_handle_null);
584
}
585
586
/* ==== Apply keep-alive barrier, if required (e.g., to inhibit weak reference resurrection) ==== */
587
if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
588
iu_barrier(masm, dst, tmp1, tmp2, preservation_level);
589
}
590
}
591
592
// base: Base register of the reference's address.
593
// ind_or_offs: Index or offset of the reference's address.
594
// val: To-be-stored value/reference's new value.
595
void ShenandoahBarrierSetAssembler::store_at(MacroAssembler *masm, DecoratorSet decorators, BasicType type,
596
Register base, RegisterOrConstant ind_or_offs, Register val,
597
Register tmp1, Register tmp2, Register tmp3,
598
MacroAssembler::PreservationLevel preservation_level) {
599
if (is_reference_type(type)) {
600
if (ShenandoahSATBBarrier) {
601
satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level);
602
}
603
604
if (ShenandoahIUBarrier && val != noreg) {
605
iu_barrier(masm, val, tmp1, tmp2, preservation_level, decorators);
606
}
607
}
608
609
BarrierSetAssembler::store_at(masm, decorators, type,
610
base, ind_or_offs,
611
val,
612
tmp1, tmp2, tmp3,
613
preservation_level);
614
}
615
616
void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler *masm,
617
Register dst, Register jni_env, Register obj,
618
Register tmp, Label &slowpath) {
619
__ block_comment("try_resolve_jobject_in_native (shenandoahgc) {");
620
621
assert_different_registers(jni_env, obj, tmp);
622
623
Label done;
624
625
// Fast path: Reference is null (JNI tags are zero for null pointers).
626
__ cmpdi(CCR0, obj, 0);
627
__ beq(CCR0, done);
628
629
// Resolve jobject using standard implementation.
630
BarrierSetAssembler::try_resolve_jobject_in_native(masm, dst, jni_env, obj, tmp, slowpath);
631
632
// Check whether heap is stable.
633
__ lbz(tmp,
634
in_bytes(ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset()),
635
jni_env);
636
637
__ andi_(tmp, tmp, ShenandoahHeap::EVACUATION | ShenandoahHeap::HAS_FORWARDED);
638
__ bne(CCR0, slowpath);
639
640
__ bind(done);
641
__ block_comment("} try_resolve_jobject_in_native (shenandoahgc)");
642
}
643
644
// Special shenandoah CAS implementation that handles false negatives due
645
// to concurrent evacuation. That is, the CAS operation is intended to succeed in
646
// the following scenarios (success criteria):
647
// s1) The reference pointer ('base_addr') equals the expected ('expected') pointer.
648
// s2) The reference pointer refers to the from-space version of an already-evacuated
649
// object, whereas the expected pointer refers to the to-space version of the same object.
650
// Situations in which the reference pointer refers to the to-space version of an object
651
// and the expected pointer refers to the from-space version of the same object can not occur due to
652
// shenandoah's strong to-space invariant. This also implies that the reference stored in 'new_val'
653
// can not refer to the from-space version of an already-evacuated object.
654
//
655
// To guarantee correct behavior in concurrent environments, two races must be addressed:
656
// r1) A concurrent thread may heal the reference pointer (i.e., it is no longer referring to the
657
// from-space version but to the to-space version of the object in question).
658
// In this case, the CAS operation should succeed.
659
// r2) A concurrent thread may mutate the reference (i.e., the reference pointer refers to an entirely different object).
660
// In this case, the CAS operation should fail.
661
//
662
// By default, the value held in the 'result' register is zero to indicate failure of CAS,
663
// non-zero to indicate success. If 'is_cae' is set, the result is the most recently fetched
664
// value from 'base_addr' rather than a boolean success indicator.
665
void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register base_addr,
666
Register expected, Register new_val, Register tmp1, Register tmp2,
667
bool is_cae, Register result) {
668
__ block_comment("cmpxchg_oop (shenandoahgc) {");
669
670
assert_different_registers(base_addr, new_val, tmp1, tmp2, result, R0);
671
assert_different_registers(base_addr, expected, tmp1, tmp2, result, R0);
672
673
// Potential clash of 'success_flag' and 'tmp' is being accounted for.
674
Register success_flag = is_cae ? noreg : result,
675
current_value = is_cae ? result : tmp1,
676
tmp = is_cae ? tmp1 : result,
677
initial_value = tmp2;
678
679
Label done, step_four;
680
681
__ bind(step_four);
682
683
/* ==== Step 1 ("Standard" CAS) ==== */
684
// Fast path: The values stored in 'expected' and 'base_addr' are equal.
685
// Given that 'expected' must refer to the to-space object of an evacuated object (strong to-space invariant),
686
// no special processing is required.
687
if (UseCompressedOops) {
688
__ cmpxchgw(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone,
689
false, success_flag, true);
690
} else {
691
__ cmpxchgd(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone,
692
false, success_flag, NULL, true);
693
}
694
695
// Skip the rest of the barrier if the CAS operation succeeds immediately.
696
// If it does not, the value stored at the address is either the from-space pointer of the
697
// referenced object (success criteria s2)) or simply another object.
698
__ beq(CCR0, done);
699
700
/* ==== Step 2 (Null check) ==== */
701
// The success criteria s2) cannot be matched with a null pointer
702
// (null pointers cannot be subject to concurrent evacuation). The failure of the CAS operation is thus legitimate.
703
__ cmpdi(CCR0, current_value, 0);
704
__ beq(CCR0, done);
705
706
/* ==== Step 3 (reference pointer refers to from-space version; success criteria s2)) ==== */
707
// To check whether the reference pointer refers to the from-space version, the forward
708
// pointer of the object referred to by the reference is resolved and compared against the expected pointer.
709
// If this check succeed, another CAS operation is issued with the from-space pointer being the expected pointer.
710
//
711
// Save the potential from-space pointer.
712
__ mr(initial_value, current_value);
713
714
// Resolve forward pointer.
715
if (UseCompressedOops) { __ decode_heap_oop_not_null(current_value); }
716
resolve_forward_pointer_not_null(masm, current_value, tmp);
717
if (UseCompressedOops) { __ encode_heap_oop_not_null(current_value); }
718
719
if (!is_cae) {
720
// 'success_flag' was overwritten by call to 'resovle_forward_pointer_not_null'.
721
// Load zero into register for the potential failure case.
722
__ li(success_flag, 0);
723
}
724
__ cmpd(CCR0, current_value, expected);
725
__ bne(CCR0, done);
726
727
// Discard fetched value as it might be a reference to the from-space version of an object.
728
if (UseCompressedOops) {
729
__ cmpxchgw(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone,
730
false, success_flag);
731
} else {
732
__ cmpxchgd(CCR0, R0, initial_value, new_val, base_addr, MacroAssembler::MemBarNone,
733
false, success_flag);
734
}
735
736
/* ==== Step 4 (Retry CAS with to-space pointer (success criteria s2) under race r1)) ==== */
737
// The reference pointer could have been healed whilst the previous CAS operation was being performed.
738
// Another CAS operation must thus be issued with the to-space pointer being the expected pointer.
739
// If that CAS operation fails as well, race r2) must have occurred, indicating that
740
// the operation failure is legitimate.
741
//
742
// To keep the code's size small and thus improving cache (icache) performance, this highly
743
// unlikely case should be handled by the smallest possible code. Instead of emitting a third,
744
// explicit CAS operation, the code jumps back and reuses the first CAS operation (step 1)
745
// (passed arguments are identical).
746
//
747
// A failure of the CAS operation in step 1 would imply that the overall CAS operation is supposed
748
// to fail. Jumping back to step 1 requires, however, that step 2 and step 3 are re-executed as well.
749
// It is thus important to ensure that a re-execution of those steps does not put program correctness
750
// at risk:
751
// - Step 2: Either terminates in failure (desired result) or falls through to step 3.
752
// - Step 3: Terminates if the comparison between the forwarded, fetched pointer and the expected value
753
// fails. Unless the reference has been updated in the meanwhile once again, this is
754
// guaranteed to be the case.
755
// In case of a concurrent update, the CAS would be retried again. This is legitimate
756
// in terms of program correctness (even though it is not desired).
757
__ bne(CCR0, step_four);
758
759
__ bind(done);
760
__ block_comment("} cmpxchg_oop (shenandoahgc)");
761
}
762
763
#undef __
764
765
#ifdef COMPILER1
766
767
#define __ ce->masm()->
768
769
void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler *ce, ShenandoahPreBarrierStub *stub) {
770
__ block_comment("gen_pre_barrier_stub (shenandoahgc) {");
771
772
ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1();
773
__ bind(*stub->entry());
774
775
// GC status has already been verified by 'ShenandoahBarrierSetC1::pre_barrier'.
776
// This stub is the slowpath of that function.
777
778
assert(stub->pre_val()->is_register(), "pre_val must be a register");
779
Register pre_val = stub->pre_val()->as_register();
780
781
// If 'do_load()' returns false, the to-be-stored value is already available in 'stub->pre_val()'
782
// ("preloaded mode" of the store barrier).
783
if (stub->do_load()) {
784
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false, false /*unaligned*/);
785
}
786
787
// Fast path: Reference is null.
788
__ cmpdi(CCR0, pre_val, 0);
789
__ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation());
790
791
// Argument passing via the stack.
792
__ std(pre_val, -8, R1_SP);
793
794
__ load_const_optimized(R0, bs->pre_barrier_c1_runtime_code_blob()->code_begin());
795
__ call_stub(R0);
796
797
__ b(*stub->continuation());
798
__ block_comment("} gen_pre_barrier_stub (shenandoahgc)");
799
}
800
801
void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler *ce,
802
ShenandoahLoadReferenceBarrierStub *stub) {
803
__ block_comment("gen_load_reference_barrier_stub (shenandoahgc) {");
804
805
ShenandoahBarrierSetC1 *bs = (ShenandoahBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1();
806
__ bind(*stub->entry());
807
808
Register obj = stub->obj()->as_register();
809
Register res = stub->result()->as_register();
810
Register addr = stub->addr()->as_pointer_register();
811
Register tmp1 = stub->tmp1()->as_register();
812
Register tmp2 = stub->tmp2()->as_register();
813
assert_different_registers(addr, res, tmp1, tmp2);
814
815
#ifdef ASSERT
816
// Ensure that 'res' is 'R3_ARG1' and contains the same value as 'obj' to reduce the number of required
817
// copy instructions.
818
assert(R3_RET == res, "res must be r3");
819
__ cmpd(CCR0, res, obj);
820
__ asm_assert_eq("result register must contain the reference stored in obj");
821
#endif
822
823
DecoratorSet decorators = stub->decorators();
824
825
/* ==== Check whether region is in collection set ==== */
826
// GC status (unstable) has already been verified by 'ShenandoahBarrierSetC1::load_reference_barrier_impl'.
827
// This stub is the slowpath of that function.
828
829
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
830
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
831
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
832
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
833
834
if (is_strong) {
835
// Check whether object is in collection set.
836
__ load_const_optimized(tmp2, ShenandoahHeap::in_cset_fast_test_addr(), tmp1);
837
__ srdi(tmp1, obj, ShenandoahHeapRegion::region_size_bytes_shift_jint());
838
__ lbzx(tmp2, tmp1, tmp2);
839
840
__ andi_(tmp2, tmp2, 1);
841
__ bc_far_optimized(Assembler::bcondCRbiIs1_bhintNoHint, __ bi0(CCR0, Assembler::equal), *stub->continuation());
842
}
843
844
address blob_addr = nullptr;
845
846
if (is_strong) {
847
if (is_native) {
848
blob_addr = bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin();
849
} else {
850
blob_addr = bs->load_reference_barrier_strong_rt_code_blob()->code_begin();
851
}
852
} else if (is_weak) {
853
blob_addr = bs->load_reference_barrier_weak_rt_code_blob()->code_begin();
854
} else {
855
assert(is_phantom, "only remaining strength");
856
blob_addr = bs->load_reference_barrier_phantom_rt_code_blob()->code_begin();
857
}
858
859
assert(blob_addr != nullptr, "code blob cannot be found");
860
861
// Argument passing via the stack. 'obj' is passed implicitly (as asserted above).
862
__ std(addr, -8, R1_SP);
863
864
__ load_const_optimized(tmp1, blob_addr, tmp2);
865
__ call_stub(tmp1);
866
867
// 'res' is 'R3_RET'. The result is thus already in the correct register.
868
869
__ b(*stub->continuation());
870
__ block_comment("} gen_load_reference_barrier_stub (shenandoahgc)");
871
}
872
873
#undef __
874
875
#define __ sasm->
876
877
void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler *sasm) {
878
__ block_comment("generate_c1_pre_barrier_runtime_stub (shenandoahgc) {");
879
880
Label runtime, skip_barrier;
881
BarrierSet *bs = BarrierSet::barrier_set();
882
883
// Argument passing via the stack.
884
const int caller_stack_slots = 3;
885
886
Register R0_pre_val = R0;
887
__ ld(R0, -8, R1_SP);
888
Register R11_tmp1 = R11_scratch1;
889
__ std(R11_tmp1, -16, R1_SP);
890
Register R12_tmp2 = R12_scratch2;
891
__ std(R12_tmp2, -24, R1_SP);
892
893
/* ==== Check whether marking is active ==== */
894
// Even though gc status was checked in 'ShenandoahBarrierSetAssembler::gen_pre_barrier_stub',
895
// another check is required as a safepoint might have been reached in the meantime (JDK-8140588).
896
__ lbz(R12_tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), R16_thread);
897
898
__ andi_(R12_tmp2, R12_tmp2, ShenandoahHeap::MARKING);
899
__ beq(CCR0, skip_barrier);
900
901
/* ==== Add previous value directly to thread-local SATB mark queue ==== */
902
// Check queue's capacity. Jump to runtime if no free slot is available.
903
__ ld(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
904
__ cmpdi(CCR0, R12_tmp2, 0);
905
__ beq(CCR0, runtime);
906
907
// Capacity suffices. Decrement the queue's size by one slot (size of one oop).
908
__ addi(R12_tmp2, R12_tmp2, -wordSize);
909
__ std(R12_tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
910
911
// Enqueue the previous value and skip the runtime invocation.
912
__ ld(R11_tmp1, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread);
913
__ stdx(R0_pre_val, R11_tmp1, R12_tmp2);
914
__ b(skip_barrier);
915
916
__ bind(runtime);
917
918
/* ==== Invoke runtime to commit SATB mark queue to gc and allocate a new buffer ==== */
919
// Save to-be-preserved registers.
920
const int nbytes_save = (MacroAssembler::num_volatile_regs + caller_stack_slots) * BytesPerWord;
921
__ save_volatile_gprs(R1_SP, -nbytes_save);
922
__ save_LR_CR(R11_tmp1);
923
__ push_frame_reg_args(nbytes_save, R11_tmp1);
924
925
// Invoke runtime.
926
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), R0_pre_val, R16_thread);
927
928
// Restore to-be-preserved registers.
929
__ pop_frame();
930
__ restore_LR_CR(R11_tmp1);
931
__ restore_volatile_gprs(R1_SP, -nbytes_save);
932
933
__ bind(skip_barrier);
934
935
// Restore spilled registers.
936
__ ld(R11_tmp1, -16, R1_SP);
937
__ ld(R12_tmp2, -24, R1_SP);
938
939
__ blr();
940
__ block_comment("} generate_c1_pre_barrier_runtime_stub (shenandoahgc)");
941
}
942
943
void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler *sasm,
944
DecoratorSet decorators) {
945
__ block_comment("generate_c1_load_reference_barrier_runtime_stub (shenandoahgc) {");
946
947
// Argument passing via the stack.
948
const int caller_stack_slots = 1;
949
950
// Save to-be-preserved registers.
951
const int nbytes_save = (MacroAssembler::num_volatile_regs - 1 // 'R3_ARG1' is skipped
952
+ caller_stack_slots) * BytesPerWord;
953
__ save_volatile_gprs(R1_SP, -nbytes_save, true, false);
954
955
// Load arguments from stack.
956
// No load required, as assured by assertions in 'ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub'.
957
Register R3_obj = R3_ARG1;
958
Register R4_load_addr = R4_ARG2;
959
__ ld(R4_load_addr, -8, R1_SP);
960
961
Register R11_tmp = R11_scratch1;
962
963
/* ==== Invoke runtime ==== */
964
bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);
965
bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);
966
bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
967
bool is_native = ShenandoahBarrierSet::is_native_access(decorators);
968
969
address jrt_address = NULL;
970
971
if (is_strong) {
972
if (is_native) {
973
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
974
} else {
975
if (UseCompressedOops) {
976
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow);
977
} else {
978
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
979
}
980
}
981
} else if (is_weak) {
982
assert(!is_native, "weak load reference barrier must not be called off-heap");
983
if (UseCompressedOops) {
984
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow);
985
} else {
986
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
987
}
988
} else {
989
assert(is_phantom, "reference type must be phantom");
990
assert(is_native, "phantom load reference barrier must be called off-heap");
991
jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
992
}
993
assert(jrt_address != NULL, "load reference barrier runtime routine cannot be found");
994
995
__ save_LR_CR(R11_tmp);
996
__ push_frame_reg_args(nbytes_save, R11_tmp);
997
998
// Invoke runtime. Arguments are already stored in the corresponding registers.
999
__ call_VM_leaf(jrt_address, R3_obj, R4_load_addr);
1000
1001
// Restore to-be-preserved registers.
1002
__ pop_frame();
1003
__ restore_LR_CR(R11_tmp);
1004
__ restore_volatile_gprs(R1_SP, -nbytes_save, true, false); // Skip 'R3_RET' register.
1005
1006
__ blr();
1007
__ block_comment("} generate_c1_load_reference_barrier_runtime_stub (shenandoahgc)");
1008
}
1009
1010
#undef __
1011
1012
#endif // COMPILER1
1013
1014