Skip to content

Commit 9516e6d

Browse files
committed
8231087: Shenandoah: Self-fixing load reference barriers for C1/C2
Reviewed-by: shade
1 parent 9510e7f commit 9516e6d

14 files changed

+227
-92
lines changed

src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt
9999
__ xchg(access.resolved_addr(), value_opr, result, tmp);
100100

101101
if (access.is_oop()) {
102-
result = load_reference_barrier(access.gen(), result);
102+
result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0));
103103
LIR_Opr tmp = gen->new_register(type);
104104
__ move(result, tmp);
105105
result = tmp;

src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble
501501

502502
Register obj = stub->obj()->as_register();
503503
Register res = stub->result()->as_register();
504+
Register addr = stub->addr()->as_register_lo();
504505
Register tmp1 = stub->tmp1()->as_register();
505506
Register tmp2 = stub->tmp2()->as_register();
506507

@@ -533,6 +534,7 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble
533534

534535
__ bind(slow_path);
535536
ce->store_parameter(res, 0);
537+
ce->store_parameter(addr, 1);
536538
__ far_call(RuntimeAddress(bs->load_reference_barrier_rt_code_blob()->code_begin()));
537539

538540
__ b(*stub->continuation());
@@ -594,7 +596,12 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s
594596

595597
__ push_call_clobbered_registers();
596598
__ load_parameter(0, r0);
597-
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier));
599+
__ load_parameter(1, r1);
600+
if (UseCompressedOops) {
601+
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_fixup_narrow));
602+
} else {
603+
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_fixup));
604+
}
598605
__ blr(lr);
599606
__ mov(rscratch1, r0);
600607
__ pop_call_clobbered_registers();

src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt
110110
__ xchg(access.resolved_addr(), result, result, LIR_OprFact::illegalOpr);
111111

112112
if (access.is_oop()) {
113-
result = load_reference_barrier(access.gen(), result);
113+
result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0));
114114
LIR_Opr tmp = gen->new_register(type);
115115
__ move(result, tmp);
116116
result = tmp;

src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,10 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble
715715

716716
Register obj = stub->obj()->as_register();
717717
Register res = stub->result()->as_register();
718+
Register addr = stub->addr()->as_register();
718719
Register tmp1 = stub->tmp1()->as_register();
719720
Register tmp2 = stub->tmp2()->as_register();
721+
assert_different_registers(obj, res, addr, tmp1, tmp2);
720722

721723
Label slow_path;
722724

@@ -745,29 +747,9 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble
745747
#endif
746748
__ jcc(Assembler::zero, *stub->continuation());
747749

748-
// Test if object is resolved.
749-
__ movptr(tmp1, Address(res, oopDesc::mark_offset_in_bytes()));
750-
// Test if both lowest bits are set. We trick it by negating the bits
751-
// then test for both bits clear.
752-
__ notptr(tmp1);
753-
#ifdef _LP64
754-
__ testb(tmp1, markWord::marked_value);
755-
#else
756-
// On x86_32, C1 register allocator can give us the register without 8-bit support.
757-
// Do the full-register access and test to avoid compilation failures.
758-
__ testptr(tmp1, markWord::marked_value);
759-
#endif
760-
__ jccb(Assembler::notZero, slow_path);
761-
// Clear both lower bits. It's still inverted, so set them, and then invert back.
762-
__ orptr(tmp1, markWord::marked_value);
763-
__ notptr(tmp1);
764-
// At this point, tmp1 contains the decoded forwarding pointer.
765-
__ mov(res, tmp1);
766-
767-
__ jmp(*stub->continuation());
768-
769750
__ bind(slow_path);
770751
ce->store_parameter(res, 0);
752+
ce->store_parameter(addr, 1);
771753
__ call(RuntimeAddress(bs->load_reference_barrier_rt_code_blob()->code_begin()));
772754

773755
__ jmp(*stub->continuation());
@@ -838,8 +820,21 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s
838820
// arg0 : object to be resolved
839821

840822
__ save_live_registers_no_oop_map(true);
841-
__ load_parameter(0, LP64_ONLY(c_rarg0) NOT_LP64(rax));
842-
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), LP64_ONLY(c_rarg0) NOT_LP64(rax));
823+
824+
#ifdef _LP64
825+
__ load_parameter(0, c_rarg0);
826+
__ load_parameter(1, c_rarg1);
827+
if (UseCompressedOops) {
828+
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_fixup_narrow), c_rarg0, c_rarg1);
829+
} else {
830+
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_fixup), c_rarg0, c_rarg1);
831+
}
832+
#else
833+
__ load_parameter(0, rax);
834+
__ load_parameter(1, rbx);
835+
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_fixup), rax, rbx);
836+
#endif
837+
843838
__ restore_live_registers_except_rax(true);
844839

845840
__ epilogue();

src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,21 @@ void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info,
105105
__ branch_destination(slow->continuation());
106106
}
107107

108-
LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj) {
108+
LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr) {
109109
if (ShenandoahLoadRefBarrier) {
110-
return load_reference_barrier_impl(gen, obj);
110+
return load_reference_barrier_impl(gen, obj, addr);
111111
} else {
112112
return obj;
113113
}
114114
}
115115

116-
LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj) {
116+
LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr) {
117117
assert(ShenandoahLoadRefBarrier, "Should be enabled");
118118

119119
obj = ensure_in_register(gen, obj);
120120
assert(obj->is_register(), "must be a register at this point");
121+
addr = ensure_in_register(gen, addr);
122+
assert(addr->is_register(), "must be a register at this point");
121123
LIR_Opr result = gen->result_register_for(obj->value_type());
122124
__ move(obj, result);
123125
LIR_Opr tmp1 = gen->new_register(T_OBJECT);
@@ -146,7 +148,7 @@ LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, L
146148
}
147149
__ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
148150

149-
CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, result, tmp1, tmp2);
151+
CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, addr, result, tmp1, tmp2);
150152
__ branch(lir_cond_notEqual, T_INT, slow);
151153
__ branch_destination(slow->continuation());
152154

@@ -155,10 +157,18 @@ LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, L
155157

156158
LIR_Opr ShenandoahBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr obj) {
157159
if (!obj->is_register()) {
158-
LIR_Opr obj_reg = gen->new_register(T_OBJECT);
160+
LIR_Opr obj_reg;
159161
if (obj->is_constant()) {
162+
obj_reg = gen->new_register(T_OBJECT);
160163
__ move(obj, obj_reg);
161164
} else {
165+
#ifdef AARCH64
166+
// AArch64 expects double-size register.
167+
obj_reg = gen->new_pointer_register();
168+
#else
169+
// x86 expects single-size register.
170+
obj_reg = gen->new_register(T_OBJECT);
171+
#endif
162172
__ leal(obj, obj_reg);
163173
}
164174
obj = obj_reg;
@@ -184,6 +194,14 @@ void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value)
184194
BarrierSetC1::store_at_resolved(access, value);
185195
}
186196

197+
LIR_Opr ShenandoahBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) {
198+
// We must resolve in register when patching. This is to avoid
199+
// having a patch area in the load barrier stub, since the call
200+
// into the runtime to patch will not have the proper oop map.
201+
const bool patch_before_barrier = access.is_oop() && (access.decorators() & C1_NEEDS_PATCHING) != 0;
202+
return BarrierSetC1::resolve_address(access, resolve_in_register || patch_before_barrier);
203+
}
204+
187205
void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) {
188206
if (!access.is_oop()) {
189207
BarrierSetC1::load_at_resolved(access, result);
@@ -210,7 +228,7 @@ void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result)
210228
if (ShenandoahLoadRefBarrier) {
211229
LIR_Opr tmp = gen->new_register(T_OBJECT);
212230
BarrierSetC1::load_at_resolved(access, tmp);
213-
tmp = load_reference_barrier(access.gen(), tmp);
231+
tmp = load_reference_barrier(access.gen(), tmp, access.resolved_addr());
214232
__ move(tmp, result);
215233
} else {
216234
BarrierSetC1::load_at_resolved(access, result);

src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,24 @@ class ShenandoahLoadReferenceBarrierStub: public CodeStub {
8989
friend class ShenandoahBarrierSetC1;
9090
private:
9191
LIR_Opr _obj;
92+
LIR_Opr _addr;
9293
LIR_Opr _result;
9394
LIR_Opr _tmp1;
9495
LIR_Opr _tmp2;
9596

9697
public:
97-
ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2) :
98-
_obj(obj), _result(result), _tmp1(tmp1), _tmp2(tmp2)
98+
ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr addr, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2) :
99+
_obj(obj), _addr(addr), _result(result), _tmp1(tmp1), _tmp2(tmp2)
99100
{
100101
assert(_obj->is_register(), "should be register");
102+
assert(_addr->is_register(), "should be register");
101103
assert(_result->is_register(), "should be register");
102104
assert(_tmp1->is_register(), "should be register");
103105
assert(_tmp2->is_register(), "should be register");
104106
}
105107

106108
LIR_Opr obj() const { return _obj; }
109+
LIR_Opr addr() const { return _addr; }
107110
LIR_Opr result() const { return _result; }
108111
LIR_Opr tmp1() const { return _tmp1; }
109112
LIR_Opr tmp2() const { return _tmp2; }
@@ -112,6 +115,9 @@ class ShenandoahLoadReferenceBarrierStub: public CodeStub {
112115
virtual void visit(LIR_OpVisitState* visitor) {
113116
visitor->do_slow_case();
114117
visitor->do_input(_obj);
118+
visitor->do_temp(_obj);
119+
visitor->do_input(_addr);
120+
visitor->do_temp(_addr);
115121
visitor->do_temp(_result);
116122
visitor->do_temp(_tmp1);
117123
visitor->do_temp(_tmp2);
@@ -186,10 +192,10 @@ class ShenandoahBarrierSetC1 : public BarrierSetC1 {
186192

187193
void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val);
188194

189-
LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj);
195+
LIR_Opr load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr);
190196
LIR_Opr storeval_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators);
191197

192-
LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj);
198+
LIR_Opr load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr);
193199

194200
LIR_Opr ensure_in_register(LIRGenerator* gen, LIR_Opr obj);
195201

@@ -209,6 +215,7 @@ class ShenandoahBarrierSetC1 : public BarrierSetC1 {
209215
protected:
210216

211217
virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
218+
virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register);
212219
virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
213220

214221
virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);

src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,11 @@ const TypeFunc* ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type() {
475475
}
476476

477477
const TypeFunc* ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type() {
478-
const Type **fields = TypeTuple::fields(1);
478+
const Type **fields = TypeTuple::fields(2);
479479
fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
480-
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
480+
fields[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // original load address
481+
482+
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields);
481483

482484
// create result type (range)
483485
fields = TypeTuple::fields(1);

0 commit comments

Comments
 (0)