1 /*
  2  * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
  4  * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
  5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  6  *
  7  * This code is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU General Public License version 2 only, as
  9  * published by the Free Software Foundation.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  *
 25  */
 26 
 27 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
 28 #include "gc/shenandoah/mode/shenandoahMode.hpp"
 29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
 30 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
 31 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 32 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 33 #include "gc/shenandoah/shenandoahRuntime.hpp"
 34 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
 35 #include "interpreter/interp_masm.hpp"
 36 #include "interpreter/interpreter.hpp"
 37 #include "runtime/javaThread.hpp"
 38 #include "runtime/sharedRuntime.hpp"
 39 #ifdef COMPILER1
 40 #include "c1/c1_LIRAssembler.hpp"
 41 #include "c1/c1_MacroAssembler.hpp"
 42 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
 43 #endif
 44 #ifdef COMPILER2
 45 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
 46 #include "opto/output.hpp"
 47 #endif
 48 
 49 #define __ masm->
 50 
 51 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
 52                                                        Register src, Register dst, Register count, RegSet saved_regs) {
 53   if (is_oop) {
 54     bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
 55     if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
 56 
 57       Label done;
 58 
 59       // Avoid calling runtime if count == 0
 60       __ cbz(count, done);
 61 
 62       // Is GC active?
 63       assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1");
 64       assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2");
 65       Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 66       __ ldrb(rscratch1, gc_state);
 67       if (ShenandoahSATBBarrier && dest_uninitialized) {
 68         __ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
 69       } else {
 70         __ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
 71         __ tst(rscratch1, rscratch2);
 72         __ br(Assembler::EQ, done);
 73       }
 74 
 75       __ push_call_clobbered_registers();
 76       // If arguments are not in proper places, shuffle them.
 77       // Doing this via the stack is the most straight-forward way to avoid
 78       // accidentally smashing any register.
 79       if (c_rarg0 != src || c_rarg1 != dst || c_rarg2 != count) {
 80         __ push(RegSet::of(src), sp);
 81         __ push(RegSet::of(dst), sp);
 82         __ push(RegSet::of(count), sp);
 83         __ pop(RegSet::of(c_rarg2), sp);
 84         __ pop(RegSet::of(c_rarg1), sp);
 85         __ pop(RegSet::of(c_rarg0), sp);
 86       }
 87       address target = nullptr;
 88       if (UseCompressedOops) {
 89         target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop);
 90       } else {
 91         target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop);
 92       }
 93       __ call_VM_leaf(target, 3);
 94       __ pop_call_clobbered_registers();
 95       __ bind(done);
 96     }
 97   }
 98 }
 99 
100 void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
101                                                        Register start, Register count, Register tmp) {
102   if (ShenandoahCardBarrier && is_oop) {
103     gen_write_ref_array_post_barrier(masm, decorators, start, count, tmp);
104   }
105 }
106 
107 void ShenandoahBarrierSetAssembler::satb_barrier(MacroAssembler* masm,
108                                                  Register obj,
109                                                  Register pre_val,
110                                                  Register thread,
111                                                  Register tmp1,
112                                                  Register tmp2) {
113   assert(ShenandoahSATBBarrier, "Should be checked by caller");
114   assert(thread == rthread, "must be");
115 
116   Label done;
117   Label runtime;
118 
119   assert_different_registers(obj, pre_val, tmp1, tmp2);
120   assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
121 
122   Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
123   Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
124 
125   // Is marking active?
126   Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
127   __ ldrb(tmp1, gc_state);
128   __ tbz(tmp1, ShenandoahHeap::MARKING_BITPOS, done);
129 
130   // Do we need to load the previous value?
131   if (obj != noreg) {
132     if (UseCompressedOops) {
133       __ ldrw(pre_val, Address(obj, 0));
134       __ decode_heap_oop(pre_val);
135     } else {
136       __ ldr(pre_val, Address(obj, 0));
137     }
138   }
139 
140   // Is the previous value null?
141   __ cbz(pre_val, done);
142 
143   // Can we store original value in the thread's buffer?
144   // Is index == 0?
145   // (The index field is typed as size_t.)
146 
147   __ ldr(tmp1, index);                      // tmp := *index_adr
148   __ cbz(tmp1, runtime);                    // tmp == 0?
149                                         // If yes, goto runtime
150 
151   __ sub(tmp1, tmp1, wordSize);             // tmp := tmp - wordSize
152   __ str(tmp1, index);                      // *index_adr := tmp
153   __ ldr(tmp2, buffer);
154   __ add(tmp1, tmp1, tmp2);                 // tmp := tmp + *buffer_adr
155 
156   // Record the previous value
157   __ str(pre_val, Address(tmp1, 0));
158   __ b(done);
159 
160   __ bind(runtime);
161 
162   // Slow-path call
163   __ enter(/* strip_ret_addr = */ true);
164   __ push_call_clobbered_registers();
165   if (c_rarg0 != pre_val) {
166     __ mov(c_rarg0, pre_val);
167   }
168   // Calling with super_call_VM_leaf with c_rarg0 bypasses interpreter checks and avoids any moves.
169   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0);
170   __ pop_call_clobbered_registers();
171   __ leave();
172 
173   __ bind(done);
174 }
175 
176 void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, DecoratorSet decorators) {
177   assert(ShenandoahLoadRefBarrier, "Should be enabled");
178   assert(dst != rscratch2, "need rscratch2");
179   assert_different_registers(load_addr.base(), load_addr.index(), rscratch1, rscratch2);
180 
181   bool is_strong  = ShenandoahBarrierSet::is_strong_access(decorators);
182   bool is_weak    = ShenandoahBarrierSet::is_weak_access(decorators);
183   bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);
184   bool is_native  = ShenandoahBarrierSet::is_native_access(decorators);
185   bool is_narrow  = UseCompressedOops && !is_native;
186 
187   Label heap_stable, not_cset;
188   Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
189   __ ldrb(rscratch2, gc_state);
190 
191   // Check for heap stability
192   if (is_strong) {
193     __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);
194   } else {
195     Label lrb;
196     __ tbnz(rscratch2, ShenandoahHeap::WEAK_ROOTS_BITPOS, lrb);
197     __ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);
198     __ bind(lrb);
199   }
200 
201   // use r1 for load address
202   Register result_dst = dst;
203   if (dst == r1) {
204     __ mov(rscratch1, dst);
205     dst = rscratch1;
206   }
207 
208   // Save r0 and r1, unless it is an output register
209   RegSet to_save = RegSet::of(r0, r1) - result_dst;
210   __ push(to_save, sp);
211   __ lea(r1, load_addr);
212   __ mov(r0, dst);
213 
214   // Test for in-cset
215   if (is_strong) {
216     if (AOTCodeCache::is_on_for_dump()) {
217       __ lea(rscratch2, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
218       __ ldr(rscratch2, Address(rscratch2));
219       __ lea(rscratch1, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
220       __ ldrw(rscratch1, Address(rscratch1));
221       __ lsrv(rscratch1, r0, rscratch1);
222     } else {
223       __ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr());
224       __ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint());
225     }
226     __ ldrb(rscratch2, Address(rscratch2, rscratch1));
227     __ tbz(rscratch2, 0, not_cset);
228   }
229 
230   // Slow-path call
231   __ enter(/* strip_ret_addr = */ true);
232   __ push_call_clobbered_registers();
233   address target = nullptr;
234   if (is_strong) {
235     if (is_narrow) {
236       target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow);
237     } else {
238       target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
239     }
240   } else if (is_weak) {
241     if (is_narrow) {
242       target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow);
243     } else {
244       target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
245     }
246   } else {
247     assert(is_phantom, "only remaining strength");
248     assert(!is_narrow, "phantom access cannot be narrow");
249     target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
250   }
251   // Calling with super_call_VM_leaf with c_rarg0/1 bypasses interpreter checks and avoids any moves.
252   __ super_call_VM_leaf(target, c_rarg0, c_rarg1);
253   __ mov(rscratch1, r0);
254   __ pop_call_clobbered_registers();
255   __ mov(r0, rscratch1);
256   __ leave();
257 
258   __ bind(not_cset);
259 
260   __ mov(result_dst, r0);
261   __ pop(to_save, sp);
262 
263   __ bind(heap_stable);
264 }
265 
266 //
267 // Arguments:
268 //
269 // Inputs:
270 //   src:        oop location to load from, might be clobbered
271 //
272 // Output:
273 //   dst:        oop loaded from src location
274 //
275 // Kill:
276 //   rscratch1 (scratch reg)
277 //
278 // Alias:
279 //   dst: rscratch1 (might use rscratch1 as temporary output register to avoid clobbering src)
280 //
281 void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
282                                             Register dst, Address src, Register tmp1, Register tmp2) {
283   // 1: non-reference load, no additional barrier is needed
284   if (!is_reference_type(type)) {
285     BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
286     return;
287   }
288 
289   // 2: load a reference from src location and apply LRB if needed
290   if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) {
291     Register result_dst = dst;
292 
293     // Preserve src location for LRB
294     if (dst == src.base() || dst == src.index()) {
295       dst = rscratch1;
296     }
297     assert_different_registers(dst, src.base(), src.index());
298 
299     BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
300 
301     load_reference_barrier(masm, dst, src, decorators);
302 
303     if (dst != result_dst) {
304       __ mov(result_dst, dst);
305       dst = result_dst;
306     }
307   } else {
308     BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
309   }
310 
311   // 3: apply keep-alive barrier if needed
312   if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
313     satb_barrier(masm /* masm */,
314                  noreg /* obj */,
315                  dst /* pre_val */,
316                  rthread /* thread */,
317                  tmp1 /* tmp1 */,
318                  tmp2 /* tmp2 */);
319   }
320 }
321 
322 void ShenandoahBarrierSetAssembler::card_barrier(MacroAssembler* masm, Register obj) {
323   assert(ShenandoahCardBarrier, "Should have been checked by caller");
324 
325   __ lsr(obj, obj, CardTable::card_shift());
326 
327   assert(CardTable::dirty_card_val() == 0, "must be");
328 
329   Address curr_ct_holder_addr(rthread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
330   __ ldr(rscratch1, curr_ct_holder_addr);
331 
332   if (UseCondCardMark) {
333     Label L_already_dirty;
334     __ ldrb(rscratch2, Address(obj, rscratch1));
335     __ cbz(rscratch2, L_already_dirty);
336     __ strb(zr, Address(obj, rscratch1));
337     __ bind(L_already_dirty);
338   } else {
339     __ strb(zr, Address(obj, rscratch1));
340   }
341 }
342 
343 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
344                                              Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
345   // 1: non-reference types require no barriers
346   if (!is_reference_type(type)) {
347     BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
348     return;
349   }
350 
351   // Flatten object address right away for simplicity: likely needed by barriers
352   if (dst.index() == noreg && dst.offset() == 0) {
353     if (dst.base() != tmp3) {
354       __ mov(tmp3, dst.base());
355     }
356   } else {
357     __ lea(tmp3, dst);
358   }
359 
360   // 2: pre-barrier: SATB needs the previous value
361   if (ShenandoahBarrierSet::need_satb_barrier(decorators, type)) {
362     satb_barrier(masm,
363                  tmp3 /* obj */,
364                  tmp2 /* pre_val */,
365                  rthread /* thread */,
366                  tmp1 /* tmp */,
367                  rscratch1 /* tmp2 */);
368   }
369 
370   // Store!
371   BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
372 
373   // 3: post-barrier: card barrier needs store address
374   bool storing_non_null = (val != noreg);
375   if (ShenandoahBarrierSet::need_card_barrier(decorators, type) && storing_non_null) {
376     card_barrier(masm, tmp3);
377   }
378 }
379 
380 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
381                                                                   Register obj, Register tmp, Label& slowpath) {
382   Label done;
383   // Resolve jobject
384   BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
385 
386   // Check for null.
387   __ cbz(obj, done);
388 
389   assert(obj != rscratch2, "need rscratch2");
390   Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
391   __ lea(rscratch2, gc_state);
392   __ ldrb(rscratch2, Address(rscratch2));
393 
394   // Check for heap in evacuation phase
395   __ tbnz(rscratch2, ShenandoahHeap::EVACUATION_BITPOS, slowpath);
396 
397   __ bind(done);
398 }
399 
400 void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembler* masm, Register weak_handle, Register obj,
401                                                                     Register tmp, Label& slow_path) {
402   assert_different_registers(weak_handle, tmp, noreg);
403   assert_different_registers(obj, tmp, noreg);
404 
405   Label done;
406 
407   // Peek weak handle using the standard implementation.
408   BarrierSetAssembler::try_peek_weak_handle_in_nmethod(masm, weak_handle, obj, tmp, slow_path);
409 
410   // Check if the reference is null, and if it is, take the fast path.
411   __ cbz(obj, done);
412 
413   Address gc_state(rthread, ShenandoahThreadLocalData::gc_state_offset());
414   __ lea(tmp, gc_state);
415   __ ldrb(tmp, __ legitimize_address(gc_state, 1, tmp));
416 
417   // Check if the heap is under weak-reference/roots processing, in
418   // which case we need to take the slow path.
419   __ tbnz(tmp, ShenandoahHeap::WEAK_ROOTS_BITPOS, slow_path);
420   __ bind(done);
421 }
422 
423 void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
424   // Check if the oop is in the right area of memory
425   __ mov(tmp2, (intptr_t) Universe::verify_oop_mask());
426   __ andr(tmp1, obj, tmp2);
427   __ mov(tmp2, (intptr_t) Universe::verify_oop_bits());
428 
429   // Compare tmp1 and tmp2.  We don't use a compare
430   // instruction here because the flags register is live.
431   __ eor(tmp1, tmp1, tmp2);
432   __ cbnz(tmp1, L_error);
433 
434   // This routine is sometimes called before applying GC barriers.
435   // With +COH, loading the klass may end up loading forwarding pointer instead.
436   Label L_skip;
437   if (UseCompactObjectHeaders) {
438     Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
439     __ ldrb(tmp1, gc_state);
440     __ tbnz(tmp1, ShenandoahHeap::HAS_FORWARDED_BITPOS, L_skip);
441   }
442 
443   // Make sure klass is 'reasonable', which is not zero.
444   __ load_narrow_klass(tmp1, obj);
445   __ cbz(tmp1, L_error);
446   __ bind(L_skip);
447 }
448 
449 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
450                                                                      Register start, Register count, Register scratch) {
451   assert(ShenandoahCardBarrier, "Should have been checked by caller");
452 
453   Label L_loop, L_done;
454   const Register end = count;
455 
456   // Zero count? Nothing to do.
457   __ cbz(count, L_done);
458 
459   // end = start + count << LogBytesPerHeapOop
460   // last element address to make inclusive
461   __ lea(end, Address(start, count, Address::lsl(LogBytesPerHeapOop)));
462   __ sub(end, end, BytesPerHeapOop);
463   __ lsr(start, start, CardTable::card_shift());
464   __ lsr(end, end, CardTable::card_shift());
465 
466   // number of bytes to copy
467   __ sub(count, end, start);
468 
469   Address curr_ct_holder_addr(rthread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
470   __ ldr(scratch, curr_ct_holder_addr);
471   __ add(start, start, scratch);
472   __ bind(L_loop);
473   __ strb(zr, Address(start, count));
474   __ subs(count, count, 1);
475   __ br(Assembler::GE, L_loop);
476   __ bind(L_done);
477 }
478 
479 #undef __
480 
481 #ifdef COMPILER1
482 
483 #define __ ce->masm()->
484 
485 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_stub(LIR_Assembler* ce, ShenandoahKeepaliveBarrierStub* stub) {
486   __ bind(*stub->entry());
487 
488   ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
489 
490   Register obj = stub->obj()->as_register();
491 
492   if (stub->do_load()) {
493     ce->mem2reg(stub->addr(), stub->obj(), T_OBJECT, lir_patch_none, nullptr, /* wide = */ false);
494   }
495   __ cbz(obj, *stub->continuation());
496   ce->store_parameter(obj, 0);
497   __ far_call(RuntimeAddress(bs->keepalive_barrier_stub()));
498   __ b(*stub->continuation());
499 }
500 
501 void ShenandoahBarrierSetAssembler::load_reference_barrier_c1_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) {
502   __ bind(*stub->entry());
503 
504   ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
505 
506   Register obj = stub->obj()->as_register();
507   Register addr = stub->addr()->as_pointer_register();
508   Register slow_result = stub->slow_result()->as_register();
509   assert_different_registers(obj, addr, slow_result);
510   assert(slow_result == r0, "C1 must know about our slow call result register");
511 
512   ce->store_parameter(obj, 0);
513   ce->store_parameter(addr, 1);
514   __ far_call(RuntimeAddress(bs->load_reference_barrier_stub(stub->decorators())));
515   if (obj != slow_result) {
516     __ mov(obj, slow_result);
517   }
518 
519   __ b(*stub->continuation());
520 }
521 
522 #undef __
523 
524 #define __ sasm->
525 
526 void ShenandoahBarrierSetAssembler::keepalive_barrier_c1_runtime_stub(StubAssembler* sasm) {
527   __ prologue("shenandoah_keepalive_barrier", false);
528   const Register tmp_obj = r0;
529   const Register tmp1 = r1;
530   const Register tmp2 = r2;
531   __ push(RegSet::of(tmp1, tmp2, tmp_obj), sp);
532   __ load_parameter(0, tmp_obj);
533   satb_barrier(sasm, noreg, tmp_obj, rthread, tmp1, tmp2);
534   __ pop(RegSet::of(tmp1, tmp2, tmp_obj), sp);
535   __ epilogue();
536 }
537 
538 void ShenandoahBarrierSetAssembler::load_reference_barrier_c1_runtime_stub(StubAssembler* sasm, DecoratorSet decorators) {
539   __ prologue("shenandoah_load_reference_barrier", false);
540   const Register tmp_obj = r0;
541   const Register tmp_addr = r1;
542   __ push(RegSet::of(tmp_addr), sp);
543   __ load_parameter(0, tmp_obj);
544   __ load_parameter(1, tmp_addr);
545   load_reference_barrier(sasm, tmp_obj, Address(tmp_addr, 0), decorators);
546   __ pop(RegSet::of(tmp_addr), sp);
547   __ epilogue();
548 }
549 
550 #undef __
551 
552 #endif // COMPILER1
553 
554 #ifdef COMPILER2
555 
556 #undef __
557 #define __ masm->
558 
559 
560 void ShenandoahBarrierSetAssembler::load_c2(const MachNode* node, MacroAssembler* masm, Register dst, Address src, Register tmp1, Register tmp2, bool is_narrow, bool is_acquire) {
561   // Do the actual load. This load is the candidate for implicit null check, and MUST come first.
562   if (is_narrow) {
563     if (is_acquire) {
564       assert(src.getMode() == Address::base_plus_offset && src.offset() == 0,
565           "is_acquire path requires address to be base-only");
566       __ ldarw(dst, src.base());
567     } else {
568       __ ldrw(dst, src);
569     }
570   } else {
571     if (is_acquire) {
572       assert(src.getMode() == Address::base_plus_offset && src.offset() == 0,
573           "is_acquire path requires address to be base-only");
574       __ ldar(dst, src.base());
575     } else {
576       __ ldr(dst, src);
577     }
578   }
579 
580   ShenandoahBarrierStubC2::load_post(masm, node, dst, src, tmp1, tmp2, is_narrow);
581 }
582 
583 void ShenandoahBarrierSetAssembler::store_c2(const MachNode* node, MacroAssembler* masm, Address dst, bool dst_narrow,
584     Register src, bool src_narrow, Register tmp1, Register tmp2, Register tmp3, bool is_volatile) {
585 
586   ShenandoahBarrierStubC2::store_pre(masm, node, dst, tmp1, tmp2, tmp3, dst_narrow);
587 
588   // Do the actual store
589   if (dst_narrow) {
590     if (!src_narrow) {
591       // Need to encode into rscratch, because we cannot clobber src.
592       if ((node->barrier_data() & ShenandoahBitNotNull) == 0) {
593         __ encode_heap_oop(tmp2, src);
594       } else {
595         __ encode_heap_oop_not_null(tmp2, src);
596       }
597       src = tmp2;
598     }
599 
600     if (is_volatile) {
601       assert(dst.getMode() == Address::base_plus_offset && dst.offset() == 0,
602           "is_acquire path requires address to be base-only");
603       __ stlrw(src, dst.base());
604     } else {
605       __ strw(src, dst);
606     }
607   } else {
608     if (is_volatile) {
609       assert(dst.getMode() == Address::base_plus_offset && dst.offset() == 0,
610           "is_acquire path requires address to be base-only");
611       __ stlr(src, dst.base());
612     } else {
613       __ str(src, dst);
614     }
615   }
616 
617   ShenandoahBarrierStubC2::store_post(masm, node, dst, tmp2, tmp3);
618 }
619 
620 void ShenandoahBarrierSetAssembler::compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr,
621     Register oldval, Register newval, Register tmp1, Register tmp2, Register tmp3, bool exchange, bool narrow, bool weak, bool acquire) {
622   Assembler::operand_size op_size = narrow ? Assembler::word : Assembler::xword;
623 
624   ShenandoahBarrierStubC2::load_store_pre(masm, node, addr, tmp1, tmp2, tmp3, narrow);
625 
626   atomic_memory_order order = acquire ? memory_order_seq_cst : memory_order_release;
627 
628   // CAS!
629   if (weak) {
630     __ cmpxchg_weak(addr, oldval, newval, op_size, order, exchange ? res : noreg);
631   } else {
632     __ cmpxchg(addr, oldval, newval, op_size, order, exchange ? res : noreg);
633   }
634 
635   // If we need a boolean result out of CAS, set the flag appropriately and promote the result.
636   if (!exchange) {
637     assert(res != noreg, "need result register");
638     __ cset(res, Assembler::EQ);
639   }
640 
641   ShenandoahBarrierStubC2::load_store_post(masm, node, Address(addr, 0), tmp2, tmp3);
642 }
643 
644 void ShenandoahBarrierSetAssembler::get_and_set_c2(const MachNode* node, MacroAssembler* masm, Register preval,
645     Register newval, Register addr, Register tmp1, Register tmp2, Register tmp3, bool is_acquire) {
646   bool is_narrow = node->bottom_type()->isa_narrowoop();
647 
648   ShenandoahBarrierStubC2::load_store_pre(masm, node, addr, tmp1, tmp2, tmp3, is_narrow);
649 
650   if (is_narrow) {
651     if (is_acquire) {
652       __ atomic_xchgalw(preval, newval, addr);
653     } else {
654       __ atomic_xchgw(preval, newval, addr);
655     }
656   } else {
657     if (is_acquire) {
658       __ atomic_xchgal(preval, newval, addr);
659     } else {
660       __ atomic_xchg(preval, newval, addr);
661     }
662   }
663 
664   ShenandoahBarrierStubC2::load_store_post(masm, node, Address(addr, 0), tmp2, tmp3);
665 }
666 
667 #undef __
668 #define __ masm.
669 
670 void ShenandoahBarrierStubC2::cardtable(MacroAssembler& masm, Address address, Register tmp1, Register tmp2) {
671   assert(CardTable::dirty_card_val() == 0, "must be");
672   Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
673 
674   // tmp1 = card table base (holder)
675   Address curr_ct_holder_addr(rthread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
676   __ ldr(tmp1, curr_ct_holder_addr);
677 
678   // tmp2 = effective address
679   __ lea(tmp2, address);
680 
681   // tmp2 = &card_table[ addr >> CardTable::card_shift() ] ; card index
682   __ add(tmp2, tmp1, tmp2, Assembler::LSR, CardTable::card_shift());
683 
684   if (UseCondCardMark) {
685     Label L_already_dirty;
686     __ ldrb(tmp1, Address(tmp2));
687     __ cbz(tmp1, L_already_dirty);
688     __ strb(zr, Address(tmp2));
689     __ bind(L_already_dirty);
690   } else {
691     __ strb(zr, Address(tmp2));
692   }
693 }
694 
695 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
696   Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
697   PhaseOutput* const output = Compile::current()->output();
698   Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
699 
700   // We piggyback on scratch_emit_size mode to compute the slowpath stub size.
701   // We'll use that information to decide whether we need a far jump to the
702   // stub entry point or not. In scratch_emit_size mode we don't bind entry()
703   // because otherwise it will be rebound when we later emit the instructions
704   // for real.
705   if (_needs_far_jump) {
706     __ ldrb(tmp, gc_state_fast);
707     __ cbz(tmp, *continuation());
708     __ b(output->in_scratch_emit_size() ? *continuation() : *entry());
709   } else {
710     __ ldrb(tmp, gc_state_fast);
711     __ cbnz(tmp, output->in_scratch_emit_size() ? *continuation() : *entry());
712   }
713 
714   // This is were the slowpath stub will return to or the code above will
715   // jump to if the checks are false
716   __ bind(*continuation());
717 }
718 
719 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
720   Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
721   assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
722   PhaseOutput* const output = Compile::current()->output();
723 
724   // We piggyback on scratch_emit_size mode to compute the slowpath stub size.
725   // We'll use that information to decide whether we need a far jump to the
726   // stub entry point or not. In scratch_emit_size mode we don't bind entry()
727   // because otherwise it will be rebound when we later emit the instructions
728   // for real.
729   if (!output->in_scratch_emit_size()) {
730     __ bind(*entry());
731   }
732 
733   // If we need to load ourselves, do it here.
734   if (_do_load) {
735     if (_narrow) {
736       __ ldrw(_obj, _addr);
737     } else {
738       __ ldr(_obj, _addr);
739     }
740   }
741 
742   // If the object is null, there is no point in applying barriers.
743   maybe_far_jump_if_zero(masm, _obj);
744 
745   // We need to make sure that loads done by callers survive across slow-path calls.
746   // For self-loads, we need to care about the case when both KA and LRB are enabled (rare).
747   bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
748   if (!_do_load || needs_both_barriers) {
749     preserve(_obj);
750   }
751 
752   // Go for barriers. Barriers can return straight to continuation, as long
753   // as another barrier is not needed and we can reach the fastpath.
754   if (needs_both_barriers) {
755     // The Load match rule in the .ad file may have legitimized the load
756     // address using a TEMP register and in that case we need to explicitly
757     // preserve them here, because the RA does not consider TEMP as live-in,
758     // and the KA runtime call may clobber them and cause a crash on the
759     // subsequent LRB stub.
760     if (_addr.base() != noreg) {
761       preserve(_addr.base());
762     }
763     if (_addr.index() != noreg) {
764       preserve(_addr.index());
765     }
766     keepalive(masm, nullptr);
767     lrb(masm);
768   } else if (_needs_keep_alive_barrier) {
769     keepalive(masm, continuation());
770   } else if (_needs_load_ref_barrier) {
771     lrb(masm);
772   } else {
773     ShouldNotReachHere();
774   }
775 }
776 
777 void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
778   if (_needs_far_jump) {
779     Label L_short_jump;
780     __ cbnz(reg, L_short_jump);
781     __ b(*continuation());
782     __ bind(L_short_jump);
783   } else {
784     __ cbz(reg, *continuation());
785   }
786 }
787 
788 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
789   Address gcstate(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING)));
790   Address index(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
791   Address buffer(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
792   Label L_through, L_slowpath;
793 
794   // If another barrier is enabled as well, do a runtime check for a specific barrier.
795   if (_needs_load_ref_barrier) {
796     assert(L_done == nullptr, "L_done is always null when _needs_load_ref_barrier is true");
797     __ ldrb(_tmp1, gcstate);
798     __ cbz(_tmp1, L_through);
799   }
800 
801   // Fast-path: put object into buffer.
802   // If buffer is already full, go slow.
803   __ ldr(_tmp1, index);
804   __ cbz(_tmp1, L_slowpath);
805   __ sub(_tmp1, _tmp1, wordSize);
806   __ str(_tmp1, index);
807   __ ldr(_tmp2, buffer);
808 
809   // Store the object in queue.
810   // If object is narrow, we need to decode it before inserting.
811   if (_narrow) {
812     __ add(_tmp2, _tmp2, _tmp1);
813     __ decode_heap_oop_not_null(_tmp1, _obj);
814     __ str(_tmp1, Address(_tmp2));
815   } else {
816     // Buffer is 64-bit address, must be in base register.
817     __ str(_obj, Address(_tmp2, _tmp1));
818   }
819 
820   // Fast-path exits here.
821   if (L_done != nullptr) {
822     __ b(*L_done);
823   } else {
824     __ b(L_through);
825   }
826 
827   // Slow-path: call runtime to handle.
828   __ bind(L_slowpath);
829 
830   {
831     SaveLiveRegisters slr(&masm, this);
832 
833     // Go to runtime and handle the rest there.
834     __ mov(c_rarg0, _obj);
835     __ lea(lr, RuntimeAddress(keepalive_runtime_entry_addr()));
836     __ blr(lr);
837   }
838   if (L_done != nullptr) {
839     __ b(*L_done);
840   } else {
841     __ bind(L_through);
842   }
843 }
844 
845 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
846   Label L_slow;
847 
848   // If another barrier is enabled as well, do a runtime check for a specific barrier.
849   if (_needs_keep_alive_barrier) {
850     char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
851     Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
852     __ ldrb(_tmp1, gc_state_fast);
853     maybe_far_jump_if_zero(masm, _tmp1);
854   }
855 
856   // If weak references are being processed, weak/phantom loads need to go slow,
857   // regardless of their cset status.
858   if (_needs_load_ref_weak_barrier) {
859     Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));
860     __ ldrb(_tmp1, gc_state_fast);
861     __ cbnz(_tmp1, L_slow);
862   }
863 
864   // Cset-check. Fall-through to slow if in collection set.
865   bool is_aot = AOTCodeCache::is_on_for_dump();
866   if (!is_aot) {
867     __ mov(_tmp1, ShenandoahHeap::in_cset_fast_test_addr());
868     if (_narrow) {
869       __ decode_heap_oop_not_null(_tmp2, _obj);
870       __ add(_tmp1, _tmp1, _tmp2, Assembler::LSR, ShenandoahHeapRegion::region_size_bytes_shift_jint());
871     } else {
872       __ add(_tmp1, _tmp1, _obj, Assembler::LSR, ShenandoahHeapRegion::region_size_bytes_shift_jint());
873     }
874   } else {
875     // Generating AOT code, pull the cset bitmap and region shift from AOT table.
876     if (_narrow) {
877       __ decode_heap_oop_not_null(_tmp1, _obj);
878     } else {
879       __ mov(_tmp1, _obj);
880     }
881     __ lea(_tmp2, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
882     __ ldrw(_tmp2, Address(_tmp2));
883     __ lsrv(_tmp2, _tmp1, _tmp2);
884     __ lea(_tmp1, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
885     __ ldr(_tmp1, Address(_tmp1));
886     __ add(_tmp1, _tmp1, _tmp2);
887   }
888   __ ldrb(_tmp1, Address(_tmp1, 0));
889   maybe_far_jump_if_zero(masm, _tmp1);
890 
891   // Slow path
892   __ bind(L_slow);
893 
894   // Obj is the result, need to temporarily stop preserving it.
895   bool is_obj_preserved = is_preserved(_obj);
896   if (is_obj_preserved) {
897     dont_preserve(_obj);
898   }
899   {
900     SaveLiveRegisters slr(&masm, this);
901 
902     // Shuffle in the arguments. The end result should be:
903     //   c_rarg0 <-- obj
904     //   c_rarg1 <-- lea(addr)
905     if (c_rarg0 == _obj) {
906       __ lea(c_rarg1, _addr);
907     } else if (c_rarg1 == _obj) {
908       __ mov(_tmp1, c_rarg1);
909       __ lea(c_rarg1, _addr);
910       __ mov(c_rarg0, _tmp1);
911     } else {
912       assert_different_registers(c_rarg1, _obj);
913       __ lea(c_rarg1, _addr);
914       __ mov(c_rarg0, _obj);
915     }
916 
917     // Go to runtime and handle the rest there.
918     __ lea(lr, RuntimeAddress(lrb_runtime_entry_addr()));
919     __ blr(lr);
920 
921     // Save the result where needed. Narrow entries return narrowOop (32 bits)
922     // and AAPCS does not guarantee the upper 32 bits of x0 are zero.
923     if (_narrow) {
924       __ movw(_obj, r0);
925     } else if (_obj != r0) {
926       __ mov(_obj, r0);
927     }
928   }
929   if (is_obj_preserved) {
930     preserve(_obj);
931   }
932 
933   __ b(*continuation());
934 }
935 
936 int ShenandoahBarrierStubC2::available_gp_registers() {
937   Unimplemented(); // Not used
938   return 0;
939 }
940 
941 bool ShenandoahBarrierStubC2::is_special_register(Register r) {
942   Unimplemented(); // Not used
943   return true;
944 }
945 
946 static ShenandoahBarrierSetC2State* barrier_set_state() {
947   return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state());
948 }
949 
950 static int get_stub_size(ShenandoahBarrierStubC2* stub) {
951   PhaseOutput* const output = Compile::current()->output();
952   assert(output->in_scratch_emit_size(), "only used when in scratch_emit_size.");
953   BufferBlob* const blob = output->scratch_buffer_blob();
954   CodeBuffer cb(blob->content_begin(), (address)output->scratch_locs_memory() - blob->content_begin());
955   MacroAssembler masm(&cb);
956   stub->emit_code(masm);
957   return cb.insts_size();
958 }
959 
960 void ShenandoahBarrierStubC2::post_init() {
961   // If we are in scratch emit mode we assume worst case, and force the use of
962   // far branches.
963   PhaseOutput* const output = Compile::current()->output();
964   ShenandoahBarrierSetC2State* state = barrier_set_state();
965   if (output->in_scratch_emit_size()) {
966     state->inc_stubs_current_total_size(get_stub_size(this));
967     _needs_far_jump = true;
968     return;
969   }
970 
971   // The logic implemented in this stub only uses short jumps (cbz, cbnz) if
972   // the aggregation of all relevant code sections of a method is less than 1MB
973   // - 2KB. We could be more aggressive and try and compute the distance
974   // between the fastpath branch and the stub entry but in practice not many
975   // methods reach the 1MB size.
976   const BufferSizingData* sizing = output->buffer_sizing_data();
977   const int code_size = sizing->_code + state->stubs_current_total_size();
978 
979   // Maximum backward range is 1M. Maximum forward reach is 1M - 4bytes.
980   // Subtract 2K to be ultra conservative.
981   const int cond_branch_max_reach = (int)(1*M - 2*K);
982   _needs_far_jump = code_size >= cond_branch_max_reach;
983 }
984 
985 #endif // COMPILER2