1 /*
2 * Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
27 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
28 #include "gc/shenandoah/shenandoahForwarding.hpp"
29 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
30 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
31 #include "gc/shenandoah/shenandoahRuntime.hpp"
32 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
33 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
34 #include "interpreter/interpreter.hpp"
35 #include "interpreter/interp_masm.hpp"
36 #include "runtime/javaThread.hpp"
37 #include "runtime/sharedRuntime.hpp"
38 #ifdef COMPILER1
39 #include "c1/c1_LIRAssembler.hpp"
40 #include "c1/c1_MacroAssembler.hpp"
41 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
42 #endif
43
44 #define __ masm->
45
46 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
47 Register src, Register dst, Register count, RegSet saved_regs) {
48 if (is_oop) {
49 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
50 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
51
52 Label done;
53
60 if (ShenandoahSATBBarrier && dest_uninitialized) {
61 __ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
62 } else {
63 __ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
64 __ tst(rscratch1, rscratch2);
65 __ br(Assembler::EQ, done);
66 }
67
68 __ push(saved_regs, sp);
69 if (UseCompressedOops) {
70 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);
71 } else {
72 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
73 }
74 __ pop(saved_regs, sp);
75 __ bind(done);
76 }
77 }
78 }
79
80 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
81 Register obj,
82 Register pre_val,
83 Register thread,
84 Register tmp,
85 bool tosca_live,
86 bool expand_call) {
87 if (ShenandoahSATBBarrier) {
88 satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, rscratch1, tosca_live, expand_call);
89 }
90 }
91
92 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
93 Register obj,
94 Register pre_val,
95 Register thread,
96 Register tmp1,
97 Register tmp2,
98 bool tosca_live,
99 bool expand_call) {
358 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
359 }
360
361 // 3: apply keep-alive barrier if needed
362 if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
363 __ enter(/*strip_ret_addr*/true);
364 __ push_call_clobbered_registers();
365 satb_write_barrier_pre(masm /* masm */,
366 noreg /* obj */,
367 dst /* pre_val */,
368 rthread /* thread */,
369 tmp1 /* tmp1 */,
370 tmp2 /* tmp2 */,
371 true /* tosca_live */,
372 true /* expand_call */);
373 __ pop_call_clobbered_registers();
374 __ leave();
375 }
376 }
377
378 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
379 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
380 bool on_oop = is_reference_type(type);
381 if (!on_oop) {
382 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
383 return;
384 }
385
386 // flatten object address if needed
387 if (dst.index() == noreg && dst.offset() == 0) {
388 if (dst.base() != tmp3) {
389 __ mov(tmp3, dst.base());
390 }
391 } else {
392 __ lea(tmp3, dst);
393 }
394
395 shenandoah_write_barrier_pre(masm,
396 tmp3 /* obj */,
397 tmp2 /* pre_val */,
398 rthread /* thread */,
399 tmp1 /* tmp */,
400 val != noreg /* tosca_live */,
401 false /* expand_call */);
402
403 if (val == noreg) {
404 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
405 } else {
406 iu_barrier(masm, val, tmp1);
407 // G1 barrier needs uncompressed oop for region cross check.
408 Register new_val = val;
409 if (UseCompressedOops) {
410 new_val = rscratch2;
411 __ mov(new_val, val);
412 }
413 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
414 }
415
416 }
417
418 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
419 Register obj, Register tmp, Label& slowpath) {
420 Label done;
421 // Resolve jobject
422 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
423
424 // Check for null.
425 __ cbz(obj, done);
426
427 assert(obj != rscratch2, "need rscratch2");
428 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
429 __ lea(rscratch2, gc_state);
430 __ ldrb(rscratch2, Address(rscratch2));
431
432 // Check for heap in evacuation phase
433 __ tbnz(rscratch2, ShenandoahHeap::EVACUATION_BITPOS, slowpath);
578 if (is_cae) {
579 // We're falling through to done to indicate success. Success
580 // with is_cae is denoted by returning the value of expected as
581 // result.
582 __ mov(tmp2, expected);
583 }
584
585 __ bind(done);
586 // At entry to done, the Z (EQ) flag is on iff if the CAS
587 // operation was successful. Additionally, if is_cae, tmp2 holds
588 // the value most recently fetched from addr. In this case, success
589 // is denoted by tmp2 matching expected.
590
591 if (is_cae) {
592 __ mov(result, tmp2);
593 } else {
594 __ cset(result, Assembler::EQ);
595 }
596 }
597
598 #undef __
599
600 #ifdef COMPILER1
601
602 #define __ ce->masm()->
603
604 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
605 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
606 // At this point we know that marking is in progress.
607 // If do_load() is true then we have to emit the
608 // load of the previous value; otherwise it has already
609 // been loaded into _pre_val.
610
611 __ bind(*stub->entry());
612
613 assert(stub->pre_val()->is_register(), "Precondition.");
614
615 Register pre_val_reg = stub->pre_val()->as_register();
616
617 if (stub->do_load()) {
|
1 /*
2 * Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. 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 "precompiled.hpp"
27 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
28 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
29 #include "gc/shenandoah/shenandoahForwarding.hpp"
30 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
31 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
32 #include "gc/shenandoah/shenandoahRuntime.hpp"
33 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
34 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
35 #include "gc/shenandoah/mode/shenandoahMode.hpp"
36 #include "interpreter/interpreter.hpp"
37 #include "interpreter/interp_masm.hpp"
38 #include "runtime/javaThread.hpp"
39 #include "runtime/sharedRuntime.hpp"
40 #ifdef COMPILER1
41 #include "c1/c1_LIRAssembler.hpp"
42 #include "c1/c1_MacroAssembler.hpp"
43 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
44 #endif
45
46 #define __ masm->
47
48 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
49 Register src, Register dst, Register count, RegSet saved_regs) {
50 if (is_oop) {
51 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
52 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
53
54 Label done;
55
62 if (ShenandoahSATBBarrier && dest_uninitialized) {
63 __ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
64 } else {
65 __ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
66 __ tst(rscratch1, rscratch2);
67 __ br(Assembler::EQ, done);
68 }
69
70 __ push(saved_regs, sp);
71 if (UseCompressedOops) {
72 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);
73 } else {
74 __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
75 }
76 __ pop(saved_regs, sp);
77 __ bind(done);
78 }
79 }
80 }
81
82 void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
83 Register start, Register count, Register tmp, RegSet saved_regs) {
84 if (ShenandoahCardBarrier && is_oop) {
85 gen_write_ref_array_post_barrier(masm, decorators, start, count, tmp, saved_regs);
86 }
87 }
88
89 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
90 Register obj,
91 Register pre_val,
92 Register thread,
93 Register tmp,
94 bool tosca_live,
95 bool expand_call) {
96 if (ShenandoahSATBBarrier) {
97 satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, rscratch1, tosca_live, expand_call);
98 }
99 }
100
101 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
102 Register obj,
103 Register pre_val,
104 Register thread,
105 Register tmp1,
106 Register tmp2,
107 bool tosca_live,
108 bool expand_call) {
367 BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2);
368 }
369
370 // 3: apply keep-alive barrier if needed
371 if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
372 __ enter(/*strip_ret_addr*/true);
373 __ push_call_clobbered_registers();
374 satb_write_barrier_pre(masm /* masm */,
375 noreg /* obj */,
376 dst /* pre_val */,
377 rthread /* thread */,
378 tmp1 /* tmp1 */,
379 tmp2 /* tmp2 */,
380 true /* tosca_live */,
381 true /* expand_call */);
382 __ pop_call_clobbered_registers();
383 __ leave();
384 }
385 }
386
387 void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj) {
388 assert(ShenandoahCardBarrier, "Should have been checked by caller");
389
390 __ lsr(obj, obj, CardTable::card_shift());
391
392 assert(CardTable::dirty_card_val() == 0, "must be");
393
394 __ load_byte_map_base(rscratch1);
395
396 if (UseCondCardMark) {
397 Label L_already_dirty;
398 __ ldrb(rscratch2, Address(obj, rscratch1));
399 __ cbz(rscratch2, L_already_dirty);
400 __ strb(zr, Address(obj, rscratch1));
401 __ bind(L_already_dirty);
402 } else {
403 __ strb(zr, Address(obj, rscratch1));
404 }
405 }
406
407 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
408 Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
409 bool on_oop = is_reference_type(type);
410 if (!on_oop) {
411 BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
412 return;
413 }
414
415 // flatten object address if needed
416 if (dst.index() == noreg && dst.offset() == 0) {
417 if (dst.base() != tmp3) {
418 __ mov(tmp3, dst.base());
419 }
420 } else {
421 __ lea(tmp3, dst);
422 }
423
424 shenandoah_write_barrier_pre(masm,
425 tmp3 /* obj */,
426 tmp2 /* pre_val */,
427 rthread /* thread */,
428 tmp1 /* tmp */,
429 val != noreg /* tosca_live */,
430 false /* expand_call */);
431
432 if (val == noreg) {
433 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
434 } else {
435 iu_barrier(masm, val, tmp1);
436 // G1 barrier needs uncompressed oop for region cross check.
437 Register new_val = val;
438 if (UseCompressedOops) {
439 new_val = rscratch2;
440 __ mov(new_val, val);
441 }
442 BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), val, noreg, noreg, noreg);
443 if (ShenandoahCardBarrier) {
444 store_check(masm, tmp3);
445 }
446 }
447
448 }
449
450 void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
451 Register obj, Register tmp, Label& slowpath) {
452 Label done;
453 // Resolve jobject
454 BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);
455
456 // Check for null.
457 __ cbz(obj, done);
458
459 assert(obj != rscratch2, "need rscratch2");
460 Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());
461 __ lea(rscratch2, gc_state);
462 __ ldrb(rscratch2, Address(rscratch2));
463
464 // Check for heap in evacuation phase
465 __ tbnz(rscratch2, ShenandoahHeap::EVACUATION_BITPOS, slowpath);
610 if (is_cae) {
611 // We're falling through to done to indicate success. Success
612 // with is_cae is denoted by returning the value of expected as
613 // result.
614 __ mov(tmp2, expected);
615 }
616
617 __ bind(done);
618 // At entry to done, the Z (EQ) flag is on iff if the CAS
619 // operation was successful. Additionally, if is_cae, tmp2 holds
620 // the value most recently fetched from addr. In this case, success
621 // is denoted by tmp2 matching expected.
622
623 if (is_cae) {
624 __ mov(result, tmp2);
625 } else {
626 __ cset(result, Assembler::EQ);
627 }
628 }
629
630 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
631 Register start, Register count, Register scratch, RegSet saved_regs) {
632 assert(ShenandoahCardBarrier, "Should have been checked by caller");
633
634 Label L_loop, L_done;
635 const Register end = count;
636
637 // Zero count? Nothing to do.
638 __ cbz(count, L_done);
639
640 // end = start + count << LogBytesPerHeapOop
641 // last element address to make inclusive
642 __ lea(end, Address(start, count, Address::lsl(LogBytesPerHeapOop)));
643 __ sub(end, end, BytesPerHeapOop);
644 __ lsr(start, start, CardTable::card_shift());
645 __ lsr(end, end, CardTable::card_shift());
646
647 // number of bytes to copy
648 __ sub(count, end, start);
649
650 __ load_byte_map_base(scratch);
651 __ add(start, start, scratch);
652 __ bind(L_loop);
653 __ strb(zr, Address(start, count));
654 __ subs(count, count, 1);
655 __ br(Assembler::GE, L_loop);
656 __ bind(L_done);
657 }
658
659 #undef __
660
661 #ifdef COMPILER1
662
663 #define __ ce->masm()->
664
665 void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {
666 ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
667 // At this point we know that marking is in progress.
668 // If do_load() is true then we have to emit the
669 // load of the previous value; otherwise it has already
670 // been loaded into _pre_val.
671
672 __ bind(*stub->entry());
673
674 assert(stub->pre_val()->is_register(), "Precondition.");
675
676 Register pre_val_reg = stub->pre_val()->as_register();
677
678 if (stub->do_load()) {
|