Skip to content

Commit 48128b8

Browse files
authored
Refactor barrier implementations (#332)
We recently added another write barrier, the `SATBBarrier`. Being another barrier based on the per-object unlog bit, it shares much code with the `ObjectBarrier`. We refactor the write barriers to improve code sharing and clean up unused code. We introduce abstract base classes `MMTkUnlogBitBarrierSetRuntime`, `MMTkUnlogBitBarrierSetAssembler`, `MMTkUnlogBitBarrierSetC1` and `MMTkUnlogBitBarrierSetC2`, which both `ObjectBarrier` and `SATBBarrier` derive from. Those base classes include common parts related to unlog bit handling, including the fast paths for checking if the unlog bit is set, and also the generic implementation for both the pre and the post barriers if applicable. Runtime: - Extracted a method for testing if the unlog bit is set for a given object. Assembler: - Extracted a method for emitting the unlog bit checking fast path. - Extracted a method for generating both the pre and the post write barriers. - Simplified the fast path to use fewer instructions and fewer scratch registers. - Worked around an issue where the `tmp1` and `tmp2` temporary registers passed in from `BarrierSetAssembler::store_at` may overlap with `dst.base()` and `dst_index()`, respectively. - See https://bugs.openjdk.org/browse/JDK-8301371 C1: - Changed "runtime stubs" to be one per runtime function, not one per pre/post/refload barrier. Those "runtime stubs" are now assembled by `MMTkBarrierSetAssembler` instead of by `MMTkObjectBarrierSetAssembler` or `MMTkSATBBarrierSetAssembler`. The intention is that all barriers can call those functions. - Extracted a method for emitting the unlog bit checking fast path. - Extracted a method for emitting both the pre and the post write barriers and their slow-path code stub. - We no longer pass the `slot` and `new_val` to the runtime function in the slow path. Object-logging barriers only needs the `obj` argument for scanning its fields. - For this reason, we moved the C1 CodeStub for the pre/post barrier slow paths down from `mmtkBarrierSetC1.hpp` to `mmtkUnlogBitBarrier.hpp` (and unified the pre/post stub implementation) because it no longer needs the `slot` or `new_val` args, and is now specific to unlog bit barriers. If we introduce field-logging barriers, we will implement a different stub. - The C1 SATBBarrier no longer needs code patching. The code patching was intended for barriers that load from the field in the fast path using LIR instructions, such as G1's SATB barrier. Our object-logging barrier scans the fields in runtime functions (`mmtk_object_reference_write_pre`), not using LIR instructions. C2: - Extracted a method for emitting the unlog bit checking fast path. - Extracted a method for emitting both the pre and the post write barriers. - We no longer pass the `slot` and `new_val` to the runtime function in the slow path. Misc: - Removed the `#define private public` hack as we no longer need it. - Removed unused macros, dead code and irrelevant comments. - Changed the macro `SOFT_REFERENCE_LOAD_BARRIER` to a run-time flag `mmtk_enable_reference_load_barrier` settable by environment variable.
1 parent e350a01 commit 48128b8

16 files changed

+641
-782
lines changed

mmtk/Cargo.lock

Lines changed: 99 additions & 109 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mmtk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ probe = "0.5"
3636
# - change branch
3737
# - change repo name
3838
# But other changes including adding/removing whitespaces in commented lines may break the CI.
39-
mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "a4dd70cb70a116a32b1bbb20501c48f77f49181b" }
39+
mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "e25ad8bb969f5d650de3f1946582075923bafcc9" }
4040
# Uncomment the following to build locally
4141
# mmtk = { path = "../repos/mmtk-core" }
4242

openjdk/barriers/mmtkObjectBarrier.cpp

Lines changed: 12 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
#include "mmtkObjectBarrier.hpp"
33
#include "runtime/interfaceSupport.inline.hpp"
44

5+
//////////////////// Runtime ////////////////////
6+
57
void MMTkObjectBarrierSetRuntime::object_probable_write(oop new_obj) const {
68
if (mmtk_enable_barrier_fastpath) {
79
// Do fast-path check before entering mmtk rust code, to improve mutator performance.
810
// This is identical to calling `mmtk_object_probable_write` directly without a fast-path.
9-
intptr_t addr = (intptr_t) (void*) new_obj;
10-
uint8_t* meta_addr = (uint8_t*) (SIDE_METADATA_BASE_ADDRESS + (addr >> 6));
11-
intptr_t shift = (addr >> 3) & 0b111;
12-
uint8_t byte_val = *meta_addr;
13-
if (((byte_val >> shift) & 1) == 1) {
11+
if (is_unlog_bit_set(new_obj)) {
1412
// Only promoted objects will reach here.
1513
// The duplicated unlog bit check inside slow-path still remains correct.
1614
mmtk_object_probable_write((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, (void*) new_obj);
@@ -23,70 +21,21 @@ void MMTkObjectBarrierSetRuntime::object_probable_write(oop new_obj) const {
2321

2422
void MMTkObjectBarrierSetRuntime::object_reference_write_post(oop src, oop* slot, oop target) const {
2523
if (mmtk_enable_barrier_fastpath) {
26-
intptr_t addr = (intptr_t) (void*) src;
27-
uint8_t* meta_addr = (uint8_t*) (SIDE_METADATA_BASE_ADDRESS + (addr >> 6));
28-
intptr_t shift = (addr >> 3) & 0b111;
29-
uint8_t byte_val = *meta_addr;
30-
if (((byte_val >> shift) & 1) == 1) {
31-
// MMTkObjectBarrierSetRuntime::object_reference_write_pre_slow()((void*) src);
24+
if (is_unlog_bit_set(src)) {
3225
object_reference_write_slow_call((void*) src, (void*) slot, (void*) target);
3326
}
3427
} else {
3528
object_reference_write_post_call((void*) src, (void*) slot, (void*) target);
3629
}
3730
}
3831

32+
//////////////////// Assembler ////////////////////
33+
3934
#define __ masm->
4035

4136
void MMTkObjectBarrierSetAssembler::object_reference_write_post(MacroAssembler* masm, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, bool compensate_val_reg) const {
4237
if (can_remove_barrier(decorators, val, /* skip_const_null */ true)) return;
43-
44-
bool is_not_null = (decorators & IS_NOT_NULL) != 0;
45-
46-
Label done;
47-
Register obj = dst.base();
48-
if (mmtk_enable_barrier_fastpath) {
49-
Register tmp3 = rscratch1;
50-
Register tmp4 = rscratch2;
51-
assert_different_registers(obj, tmp2, tmp3);
52-
assert_different_registers(tmp4, rcx);
53-
54-
// tmp2 = load-byte (SIDE_METADATA_BASE_ADDRESS + (obj >> 6));
55-
__ movptr(tmp3, obj);
56-
__ shrptr(tmp3, 6);
57-
__ movptr(tmp2, SIDE_METADATA_BASE_ADDRESS);
58-
__ movb(tmp2, Address(tmp2, tmp3));
59-
// tmp3 = (obj >> 3) & 7
60-
__ movptr(tmp3, obj);
61-
__ shrptr(tmp3, 3);
62-
__ andptr(tmp3, 7);
63-
// tmp2 = tmp2 >> tmp3
64-
__ movptr(tmp4, rcx);
65-
__ movl(rcx, tmp3);
66-
__ shrptr(tmp2);
67-
__ movptr(rcx, tmp4);
68-
// if ((tmp2 & 1) == 1) goto slowpath;
69-
__ andptr(tmp2, 1);
70-
__ cmpptr(tmp2, 1);
71-
__ jcc(Assembler::notEqual, done);
72-
}
73-
74-
__ movptr(c_rarg0, obj);
75-
__ xorptr(c_rarg1, c_rarg1);
76-
// Note: If `compensate_val_reg == true && UseCompressedOops === true`, the `val` register will be
77-
// holding a compressed pointer to the target object. If the write barrier needs to know the
78-
// target, we will need to decompress it before passing it to the barrier slow path. However,
79-
// since we know the semantics of `mmtk::plan::barriers::ObjectBarrier`, i.e. it logs the object
80-
// without looking at the `slot` or the `target` parameter at all, we simply pass nullptr to both
81-
// parameters.
82-
__ xorptr(c_rarg2, c_rarg2);
83-
84-
if (mmtk_enable_barrier_fastpath) {
85-
__ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_slow_call), 3);
86-
__ bind(done);
87-
} else {
88-
__ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_post_call), 3);
89-
}
38+
object_reference_write_pre_or_post(masm, decorators, dst, val, /* pre = */ false);
9039
}
9140

9241
void MMTkObjectBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) {
@@ -135,56 +84,7 @@ void MMTkObjectBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec
13584

13685
#undef __
13786

138-
#define __ sasm->
139-
140-
void MMTkObjectBarrierSetAssembler::generate_c1_post_write_barrier_runtime_stub(StubAssembler* sasm) const {
141-
__ prologue("mmtk_object_barrier", false);
142-
143-
Label done, runtime;
144-
145-
__ push(c_rarg0);
146-
__ push(c_rarg1);
147-
__ push(c_rarg2);
148-
__ push(rax);
149-
150-
__ load_parameter(0, c_rarg0);
151-
__ load_parameter(1, c_rarg1);
152-
__ load_parameter(2, c_rarg2);
153-
154-
__ bind(runtime);
155-
156-
__ save_live_registers_no_oop_map(true);
157-
158-
if (mmtk_enable_barrier_fastpath) {
159-
__ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_slow_call), 3);
160-
} else {
161-
__ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_post_call), 3);
162-
}
163-
164-
__ restore_live_registers(true);
165-
166-
__ bind(done);
167-
__ pop(rax);
168-
__ pop(c_rarg2);
169-
__ pop(c_rarg1);
170-
__ pop(c_rarg0);
171-
172-
__ epilogue();
173-
}
174-
175-
#undef __
176-
#define __ ce->masm()->
177-
178-
void MMTkObjectBarrierSetAssembler::generate_c1_post_write_barrier_stub(LIR_Assembler* ce, MMTkC1PostBarrierStub* stub) const {
179-
MMTkBarrierSetC1* bs = (MMTkBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1();
180-
__ bind(*stub->entry());
181-
ce->store_parameter(stub->src->as_pointer_register(), 0);
182-
ce->store_parameter(stub->slot->as_pointer_register(), 1);
183-
ce->store_parameter(stub->new_val->as_pointer_register(), 2);
184-
__ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
185-
__ jmp(*stub->continuation());
186-
}
187-
#undef __
87+
//////////////////// C1 ////////////////////
18888

18989
#ifdef ASSERT
19090
#define __ gen->lir(__FILE__, __LINE__)->
@@ -193,100 +93,21 @@ void MMTkObjectBarrierSetAssembler::generate_c1_post_write_barrier_stub(LIR_Asse
19393
#endif
19494

19595
void MMTkObjectBarrierSetC1::object_reference_write_post(LIRAccess& access, LIR_Opr src, LIR_Opr slot, LIR_Opr new_val) const {
196-
LIRGenerator* gen = access.gen();
197-
DecoratorSet decorators = access.decorators();
198-
if ((decorators & IN_HEAP) == 0) return;
199-
if (!src->is_register()) {
200-
LIR_Opr reg = gen->new_pointer_register();
201-
if (src->is_constant()) {
202-
__ move(src, reg);
203-
} else {
204-
__ leal(src, reg);
205-
}
206-
src = reg;
207-
}
208-
assert(src->is_register(), "must be a register at this point");
209-
if (!slot->is_register()) {
210-
LIR_Opr reg = gen->new_pointer_register();
211-
if (slot->is_constant()) {
212-
__ move(slot, reg);
213-
} else {
214-
__ leal(slot, reg);
215-
}
216-
slot = reg;
217-
}
218-
assert(slot->is_register(), "must be a register at this point");
219-
if (!new_val->is_register()) {
220-
LIR_Opr new_val_reg = gen->new_register(T_OBJECT);
221-
if (new_val->is_constant()) {
222-
__ move(new_val, new_val_reg);
223-
} else {
224-
__ leal(new_val, new_val_reg);
225-
}
226-
new_val = new_val_reg;
227-
}
228-
assert(new_val->is_register(), "must be a register at this point");
229-
CodeStub* slow = new MMTkC1PostBarrierStub(src, slot, new_val);
230-
231-
if (mmtk_enable_barrier_fastpath) {
232-
LIR_Opr addr = src;
233-
// uint8_t* meta_addr = (uint8_t*) (SIDE_METADATA_BASE_ADDRESS + (addr >> 6));
234-
LIR_Opr offset = gen->new_pointer_register();
235-
__ move(addr, offset);
236-
__ unsigned_shift_right(offset, 6, offset);
237-
LIR_Opr base = gen->new_pointer_register();
238-
__ move(LIR_OprFact::longConst(SIDE_METADATA_BASE_ADDRESS), base);
239-
LIR_Address* meta_addr = new LIR_Address(base, offset, T_BYTE);
240-
// uint8_t byte_val = *meta_addr;
241-
LIR_Opr byte_val = gen->new_register(T_INT);
242-
__ move(meta_addr, byte_val);
243-
// intptr_t shift = (addr >> 3) & 0b111;
244-
LIR_Opr shift = gen->new_register(T_INT);
245-
__ move(addr, shift);
246-
__ unsigned_shift_right(shift, 3, shift);
247-
__ logical_and(shift, LIR_OprFact::intConst(0b111), shift);
248-
// if (((byte_val >> shift) & 1) == 1) slow;
249-
LIR_Opr result = byte_val;
250-
__ unsigned_shift_right(result, shift, result, LIR_OprFact::illegalOpr);
251-
__ logical_and(result, LIR_OprFact::intConst(1), result);
252-
__ cmp(lir_cond_equal, result, LIR_OprFact::intConst(1));
253-
__ branch(lir_cond_equal, T_BYTE, slow);
254-
} else {
255-
__ jump(slow);
256-
}
257-
258-
__ branch_destination(slow->continuation());
96+
object_reference_write_pre_or_post(access, src, /* pre = */ false);
25997
}
26098

26199
#undef __
262100

101+
//////////////////// C2 ////////////////////
102+
263103
#define __ ideal.
264104

265105
void MMTkObjectBarrierSetC2::object_reference_write_post(GraphKit* kit, Node* src, Node* slot, Node* val) const {
266106
if (can_remove_barrier(kit, &kit->gvn(), src, slot, val, /* skip_const_null */ true)) return;
267107

268108
MMTkIdealKit ideal(kit, true);
269109

270-
if (mmtk_enable_barrier_fastpath) {
271-
Node* no_base = __ top();
272-
float unlikely = PROB_UNLIKELY(0.999);
273-
274-
Node* zero = __ ConI(0);
275-
Node* addr = __ CastPX(__ ctrl(), src);
276-
Node* meta_addr = __ AddP(no_base, __ ConP(SIDE_METADATA_BASE_ADDRESS), __ URShiftX(addr, __ ConI(6)));
277-
Node* byte = __ load(__ ctrl(), meta_addr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw);
278-
Node* shift = __ URShiftX(addr, __ ConI(3));
279-
shift = __ AndI(__ ConvL2I(shift), __ ConI(7));
280-
Node* result = __ AndI(__ URShiftI(byte, shift), __ ConI(1));
281-
282-
__ if_then(result, BoolTest::ne, zero, unlikely); {
283-
const TypeFunc* tf = __ func_type(TypeOopPtr::BOTTOM, TypeOopPtr::BOTTOM, TypeOopPtr::BOTTOM);
284-
Node* x = __ make_leaf_call(tf, FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_slow_call), "mmtk_barrier_call", src, slot, val);
285-
} __ end_if();
286-
} else {
287-
const TypeFunc* tf = __ func_type(TypeOopPtr::BOTTOM, TypeOopPtr::BOTTOM, TypeOopPtr::BOTTOM);
288-
Node* x = __ make_leaf_call(tf, FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_post_call), "mmtk_barrier_call", src, slot, val);
289-
}
110+
object_reference_write_pre_or_post(ideal, src, /* pre = */ false);
290111

291112
kit->final_sync(ideal); // Final sync IdealKit and GraphKit.
292113
}

openjdk/barriers/mmtkObjectBarrier.hpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@
66
#include "../mmtkBarrierSetAssembler_x86.hpp"
77
#include "../mmtkBarrierSetC1.hpp"
88
#include "../mmtkBarrierSetC2.hpp"
9+
#include "mmtkUnlogBitBarrier.hpp"
910
#include "c1/c1_LIRAssembler.hpp"
1011
#include "c1/c1_MacroAssembler.hpp"
1112
#include "gc/shared/barrierSet.hpp"
1213
#include "opto/callnode.hpp"
1314
#include "opto/idealKit.hpp"
1415

15-
#define SIDE_METADATA_WORST_CASE_RATIO_LOG 1
16-
#define LOG_BYTES_IN_CHUNK 22
17-
#define CHUNK_MASK ((1L << LOG_BYTES_IN_CHUNK) - 1)
16+
/// This file supports the `ObjectBarrier` in MMTk core,
17+
/// i.e. the barrier that remembers the object when it is first modified.
18+
/// Despite the name, `ObjectBarrier` is not the only barrier that uses the object-grained unlogging bit.
19+
/// `SATBBarrier` also uses the object-grained unlog bit.
20+
/// We keep the name in sync with the MMTk core.
1821

19-
const intptr_t SIDE_METADATA_BASE_ADDRESS = (intptr_t) GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS;
22+
//////////////////// Runtime ////////////////////
2023

21-
class MMTkObjectBarrierSetRuntime: public MMTkBarrierSetRuntime {
24+
class MMTkObjectBarrierSetRuntime: public MMTkUnlogBitBarrierSetRuntime {
2225
public:
2326
// Interfaces called by `MMTkBarrierSet::AccessBarrier`
2427
virtual void object_reference_write_post(oop src, oop* slot, oop target) const override;
@@ -28,18 +31,19 @@ class MMTkObjectBarrierSetRuntime: public MMTkBarrierSetRuntime {
2831
virtual void object_probable_write(oop new_obj) const override;
2932
};
3033

31-
class MMTkObjectBarrierSetAssembler: public MMTkBarrierSetAssembler {
34+
//////////////////// Assembler ////////////////////
35+
36+
class MMTkObjectBarrierSetAssembler: public MMTkUnlogBitBarrierSetAssembler {
3237
protected:
3338
virtual void object_reference_write_post(MacroAssembler* masm, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, bool compensate_val_reg) const override;
34-
/// Generate C1 write barrier slow-call assembly code
35-
virtual void generate_c1_post_write_barrier_runtime_stub(StubAssembler* sasm) const override;
3639
public:
37-
virtual void generate_c1_post_write_barrier_stub(LIR_Assembler* ce, MMTkC1PostBarrierStub* stub) const override;
3840
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) override;
3941
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) override;
4042
};
4143

42-
class MMTkObjectBarrierSetC1: public MMTkBarrierSetC1 {
44+
//////////////////// C1 ////////////////////
45+
46+
class MMTkObjectBarrierSetC1: public MMTkUnlogBitBarrierSetC1 {
4347
protected:
4448
virtual void object_reference_write_post(LIRAccess& access, LIR_Opr src, LIR_Opr slot, LIR_Opr new_val) const override;
4549

@@ -48,11 +52,15 @@ class MMTkObjectBarrierSetC1: public MMTkBarrierSetC1 {
4852
}
4953
};
5054

51-
class MMTkObjectBarrierSetC2: public MMTkBarrierSetC2 {
55+
//////////////////// C2 ////////////////////
56+
57+
class MMTkObjectBarrierSetC2: public MMTkUnlogBitBarrierSetC2 {
5258
protected:
5359
virtual void object_reference_write_post(GraphKit* kit, Node* src, Node* slot, Node* val) const override;
5460
};
5561

62+
//////////////////// Impl ////////////////////
63+
5664
struct MMTkObjectBarrier: MMTkBarrierImpl<
5765
MMTkObjectBarrierSetRuntime,
5866
MMTkObjectBarrierSetAssembler,

0 commit comments

Comments
 (0)