< prev index next >

src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp

Print this page

 82     }
 83     __ pop(saved_regs, sp);
 84 
 85     __ bind(done);
 86   }
 87 }
 88 
 89 void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
 90                                                              Register start, Register count, Register scratch, RegSet saved_regs) {
 91   __ push(saved_regs, sp);
 92   assert_different_registers(start, count, scratch);
 93   assert_different_registers(c_rarg0, count);
 94   __ mov(c_rarg0, start);
 95   __ mov(c_rarg1, count);
 96   __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
 97   __ pop(saved_regs, sp);
 98 }
 99 
100 static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
101                                               const Register thread, const Register value, const Register temp1, const Register temp2) {

102   // Can we store a value in the given thread's buffer?
103   // (The index field is typed as size_t.)
104   __ ldr(temp1, Address(thread, in_bytes(index_offset)));   // temp1 := *(index address)
105   __ cbz(temp1, runtime);                                   // jump to runtime if index == 0 (full buffer)
106   // The buffer is not full, store value into it.
107   __ sub(temp1, temp1, wordSize);                           // temp1 := next index
108   __ str(temp1, Address(thread, in_bytes(index_offset)));   // *(index address) := next index
109   __ ldr(temp2, Address(thread, in_bytes(buffer_offset)));  // temp2 := buffer address
110   __ str(value, Address(temp2, temp1));                     // *(buffer address + next index) := value
111 }
112 
113 static void generate_pre_barrier_fast_path(MacroAssembler* masm,
114                                            const Register thread,
115                                            const Register tmp1) {
116   Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
117   // Is marking active?
118   if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
119     __ ldrw(tmp1, in_progress);
120   } else {
121     assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");

155                                                  bool expand_call) {
156   // If expand_call is true then we expand the call_VM_leaf macro
157   // directly to skip generating the check by
158   // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
159 
160   assert(thread == rthread, "must be");
161 
162   Label done;
163   Label runtime;
164 
165   assert_different_registers(obj, pre_val, tmp1, tmp2);
166   assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
167 
168   generate_pre_barrier_fast_path(masm, thread, tmp1);
169   // If marking is not active (*(mark queue active address) == 0), jump to done
170   __ cbzw(tmp1, done);
171   generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime);
172 
173   __ bind(runtime);
174 
175   __ push_call_clobbered_registers();












176 
177   // Calling the runtime using the regular call_VM_leaf mechanism generates
178   // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
179   // that checks that the *(rfp+frame::interpreter_frame_last_sp) == nullptr.
180   //
181   // If we care generating the pre-barrier without a frame (e.g. in the
182   // intrinsified Reference.get() routine) then rfp might be pointing to
183   // the caller frame and so this check will most likely fail at runtime.
184   //
185   // Expanding the call directly bypasses the generation of the check.
186   // So when we do not have have a full interpreter frame on the stack
187   // expand_call should be passed true.
188 
189   if (expand_call) {
190     assert(pre_val != c_rarg1, "smashed arg");
191     __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
192   } else {
193     __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
194   }
195 
196   __ pop_call_clobbered_registers();
197 
198   __ bind(done);
199 
200 }
201 
202 static void generate_post_barrier_fast_path(MacroAssembler* masm,
203                                             const Register store_addr,
204                                             const Register new_val,
205                                             const Register tmp1,
206                                             const Register tmp2,
207                                             Label& done,
208                                             bool new_val_may_be_null) {
209   // Does store cross heap regions?
210   __ eor(tmp1, store_addr, new_val);                     // tmp1 := store address ^ new value
211   __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);   // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
212   __ cbz(tmp1, done);
213   // Crosses regions, storing null?
214   if (new_val_may_be_null) {
215     __ cbz(new_val, done);
216   }

247                                                   Register store_addr,
248                                                   Register new_val,
249                                                   Register thread,
250                                                   Register tmp1,
251                                                   Register tmp2) {
252   assert(thread == rthread, "must be");
253   assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
254                              rscratch1);
255   assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
256          && tmp2 != noreg, "expecting a register");
257 
258   Label done;
259   Label runtime;
260 
261   generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
262   // If card is young, jump to done
263   __ br(Assembler::EQ, done);
264   generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
265 
266   __ bind(runtime);

267   // save the live input values
268   RegSet saved = RegSet::of(store_addr);
269   __ push(saved, sp);










270   __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
271   __ pop(saved, sp);


272 
273   __ bind(done);
274 }
275 
276 #if defined(COMPILER2)
277 
278 static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
279   SaveLiveRegisters save_registers(masm, stub);
280   if (c_rarg0 != arg) {
281     __ mov(c_rarg0, arg);
282   }
283   __ mov(c_rarg1, rthread);
284   __ mov(rscratch1, runtime_path);
285   __ blr(rscratch1);
286 }
287 
288 void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
289                                                     Register obj,
290                                                     Register pre_val,
291                                                     Register thread,

374   ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
375   if (on_oop && on_reference) {
376     // LR is live.  It must be saved around calls.
377     __ enter(/*strip_ret_addr*/true); // barrier may call runtime
378     // Generate the G1 pre-barrier code to log the value of
379     // the referent field in an SATB buffer.
380     g1_write_barrier_pre(masm /* masm */,
381                          noreg /* obj */,
382                          dst /* pre_val */,
383                          rthread /* thread */,
384                          tmp1 /* tmp1 */,
385                          tmp2 /* tmp2 */,
386                          true /* tosca_live */,
387                          true /* expand_call */);
388     __ leave();
389   }
390 }
391 
392 void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
393                                          Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {










394   // flatten object address if needed
395   if (dst.index() == noreg && dst.offset() == 0) {
396     if (dst.base() != tmp3) {
397       __ mov(tmp3, dst.base());
398     }
399   } else {
400     __ lea(tmp3, dst);
401   }
402 
403   g1_write_barrier_pre(masm,
404                        tmp3 /* obj */,
405                        tmp2 /* pre_val */,
406                        rthread /* thread */,
407                        tmp1  /* tmp1 */,
408                        rscratch2  /* tmp2 */,
409                        val != noreg /* tosca_live */,
410                        false /* expand_call */);


411 
412   if (val == noreg) {
413     BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
414   } else {
415     // G1 barrier needs uncompressed oop for region cross check.
416     Register new_val = val;
417     if (UseCompressedOops) {
418       new_val = rscratch2;
419       __ mov(new_val, val);


420     }

421     BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
422     g1_write_barrier_post(masm,
423                           tmp3 /* store_adr */,
424                           new_val /* new_val */,
425                           rthread /* thread */,
426                           tmp1 /* tmp1 */,
427                           tmp2 /* tmp2 */);


428   }
429 
430 }
431 
432 #ifdef COMPILER1
433 
434 #undef __
435 #define __ ce->masm()->
436 
437 void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
438   G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
439   // At this point we know that marking is in progress.
440   // If do_load() is true then we have to emit the
441   // load of the previous value; otherwise it has already
442   // been loaded into _pre_val.
443 
444   __ bind(*stub->entry());
445 
446   assert(stub->pre_val()->is_register(), "Precondition.");
447 

 82     }
 83     __ pop(saved_regs, sp);
 84 
 85     __ bind(done);
 86   }
 87 }
 88 
 89 void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
 90                                                              Register start, Register count, Register scratch, RegSet saved_regs) {
 91   __ push(saved_regs, sp);
 92   assert_different_registers(start, count, scratch);
 93   assert_different_registers(c_rarg0, count);
 94   __ mov(c_rarg0, start);
 95   __ mov(c_rarg1, count);
 96   __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
 97   __ pop(saved_regs, sp);
 98 }
 99 
100 static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
101                                               const Register thread, const Register value, const Register temp1, const Register temp2) {
102   assert_different_registers(value, temp1, temp2);
103   // Can we store a value in the given thread's buffer?
104   // (The index field is typed as size_t.)
105   __ ldr(temp1, Address(thread, in_bytes(index_offset)));   // temp1 := *(index address)
106   __ cbz(temp1, runtime);                                   // jump to runtime if index == 0 (full buffer)
107   // The buffer is not full, store value into it.
108   __ sub(temp1, temp1, wordSize);                           // temp1 := next index
109   __ str(temp1, Address(thread, in_bytes(index_offset)));   // *(index address) := next index
110   __ ldr(temp2, Address(thread, in_bytes(buffer_offset)));  // temp2 := buffer address
111   __ str(value, Address(temp2, temp1));                     // *(buffer address + next index) := value
112 }
113 
114 static void generate_pre_barrier_fast_path(MacroAssembler* masm,
115                                            const Register thread,
116                                            const Register tmp1) {
117   Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
118   // Is marking active?
119   if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
120     __ ldrw(tmp1, in_progress);
121   } else {
122     assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");

156                                                  bool expand_call) {
157   // If expand_call is true then we expand the call_VM_leaf macro
158   // directly to skip generating the check by
159   // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
160 
161   assert(thread == rthread, "must be");
162 
163   Label done;
164   Label runtime;
165 
166   assert_different_registers(obj, pre_val, tmp1, tmp2);
167   assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
168 
169   generate_pre_barrier_fast_path(masm, thread, tmp1);
170   // If marking is not active (*(mark queue active address) == 0), jump to done
171   __ cbzw(tmp1, done);
172   generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime);
173 
174   __ bind(runtime);
175 
176   // save the live input values
177   RegSet saved = RegSet::of(pre_val);
178   FloatRegSet fsaved;
179 
180   // Barriers might be emitted when converting between (scalarized) calling
181   // conventions for inline types. Save all argument registers before calling
182   // into the runtime.
183 
184   // TODO 8366717 This came with 8284161: Implementation of Virtual Threads (Preview) later in May 2022
185   // Check if it's sufficient
186   //__ push_call_clobbered_registers();
187   assert_different_registers(rscratch1, pre_val); // push_CPU_state trashes rscratch1
188   __ push_CPU_state(true);
189 
190   // Calling the runtime using the regular call_VM_leaf mechanism generates
191   // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
192   // that checks that the *(rfp+frame::interpreter_frame_last_sp) == nullptr.
193   //
194   // If we care generating the pre-barrier without a frame (e.g. in the
195   // intrinsified Reference.get() routine) then rfp might be pointing to
196   // the caller frame and so this check will most likely fail at runtime.
197   //
198   // Expanding the call directly bypasses the generation of the check.
199   // So when we do not have have a full interpreter frame on the stack
200   // expand_call should be passed true.
201 
202   if (expand_call) {
203     assert(pre_val != c_rarg1, "smashed arg");
204     __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
205   } else {
206     __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
207   }
208 
209   __ pop_CPU_state(true);
210 
211   __ bind(done);
212 
213 }
214 
215 static void generate_post_barrier_fast_path(MacroAssembler* masm,
216                                             const Register store_addr,
217                                             const Register new_val,
218                                             const Register tmp1,
219                                             const Register tmp2,
220                                             Label& done,
221                                             bool new_val_may_be_null) {
222   // Does store cross heap regions?
223   __ eor(tmp1, store_addr, new_val);                     // tmp1 := store address ^ new value
224   __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);   // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
225   __ cbz(tmp1, done);
226   // Crosses regions, storing null?
227   if (new_val_may_be_null) {
228     __ cbz(new_val, done);
229   }

260                                                   Register store_addr,
261                                                   Register new_val,
262                                                   Register thread,
263                                                   Register tmp1,
264                                                   Register tmp2) {
265   assert(thread == rthread, "must be");
266   assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
267                              rscratch1);
268   assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
269          && tmp2 != noreg, "expecting a register");
270 
271   Label done;
272   Label runtime;
273 
274   generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
275   // If card is young, jump to done
276   __ br(Assembler::EQ, done);
277   generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
278 
279   __ bind(runtime);
280 
281   // save the live input values
282   RegSet saved = RegSet::of(store_addr);
283   FloatRegSet fsaved;
284 
285   // Barriers might be emitted when converting between (scalarized) calling
286   // conventions for inline types. Save all argument registers before calling
287   // into the runtime.
288   // TODO 8366717 Without this, r11 is corrupted below and it holds the array of pre-allocated value objects in the C2I adapter...
289   // Check if__ push_call_clobbered_registers() is sufficient
290   assert_different_registers(rscratch1, tmp1); // push_CPU_state trashes rscratch1
291   __ enter();
292   __ push_CPU_state(true);
293 
294   __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
295 
296   __ pop_CPU_state(true);
297   __ leave();
298 
299   __ bind(done);
300 }
301 
302 #if defined(COMPILER2)
303 
304 static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
305   SaveLiveRegisters save_registers(masm, stub);
306   if (c_rarg0 != arg) {
307     __ mov(c_rarg0, arg);
308   }
309   __ mov(c_rarg1, rthread);
310   __ mov(rscratch1, runtime_path);
311   __ blr(rscratch1);
312 }
313 
314 void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
315                                                     Register obj,
316                                                     Register pre_val,
317                                                     Register thread,

400   ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
401   if (on_oop && on_reference) {
402     // LR is live.  It must be saved around calls.
403     __ enter(/*strip_ret_addr*/true); // barrier may call runtime
404     // Generate the G1 pre-barrier code to log the value of
405     // the referent field in an SATB buffer.
406     g1_write_barrier_pre(masm /* masm */,
407                          noreg /* obj */,
408                          dst /* pre_val */,
409                          rthread /* thread */,
410                          tmp1 /* tmp1 */,
411                          tmp2 /* tmp2 */,
412                          true /* tosca_live */,
413                          true /* expand_call */);
414     __ leave();
415   }
416 }
417 
418 void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
419                                          Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
420 
421   bool in_heap = (decorators & IN_HEAP) != 0;
422   bool as_normal = (decorators & AS_NORMAL) != 0;
423   bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
424 
425   bool needs_pre_barrier = as_normal && !dest_uninitialized;
426   bool needs_post_barrier = (val != noreg && in_heap);
427 
428   assert_different_registers(val, tmp1, tmp2, tmp3);
429 
430   // flatten object address if needed
431   if (dst.index() == noreg && dst.offset() == 0) {
432     if (dst.base() != tmp3) {
433       __ mov(tmp3, dst.base());
434     }
435   } else {
436     __ lea(tmp3, dst);
437   }
438 
439   if (needs_pre_barrier) {
440     g1_write_barrier_pre(masm,
441                          tmp3 /* obj */,
442                          tmp2 /* pre_val */,
443                          rthread /* thread */,
444                          tmp1  /* tmp1 */,
445                          rscratch2  /* tmp2 */,
446                          val != noreg /* tosca_live */,
447                          false /* expand_call */);
448   }
449 
450   if (val == noreg) {
451     BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
452   } else {
453     // G1 barrier needs uncompressed oop for region cross check.
454     Register new_val = val;
455     if (needs_post_barrier) {
456       if (UseCompressedOops) {
457         new_val = rscratch2;
458         __ mov(new_val, val);
459       }
460     }
461 
462     BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
463     if (needs_post_barrier) {
464       g1_write_barrier_post(masm,
465                             tmp3 /* store_adr */,
466                             new_val /* new_val */,
467                             rthread /* thread */,
468                             tmp1 /* tmp1 */,
469                             tmp2 /* tmp2 */);
470     }
471   }
472 
473 }
474 
475 #ifdef COMPILER1
476 
477 #undef __
478 #define __ ce->masm()->
479 
480 void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
481   G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
482   // At this point we know that marking is in progress.
483   // If do_load() is true then we have to emit the
484   // load of the previous value; otherwise it has already
485   // been loaded into _pre_val.
486 
487   __ bind(*stub->entry());
488 
489   assert(stub->pre_val()->is_register(), "Precondition.");
490 
< prev index next >