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
|