Skip to content

Commit b6fd1ed

Browse files
committed
ZJIT: Avoid emitting WriteBarrier for immediate values
Add a Function::write_barrier helper that checks whether the value is known to be an Immediate before emitting a WriteBarrier instruction. Previously, WriteBarriers with immediate values would only be removed in the fold_constants pass. By not emitting them in the first place, optimization passes that run before fold_constants (such as load/store elimination) can avoid having their cached loads invalidated.
1 parent 6e13d22 commit b6fd1ed

3 files changed

Lines changed: 46 additions & 41 deletions

File tree

‎zjit/src/cruby_methods.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ fn inline_array_aset(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
475475
let index = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: index, right: zero, reason: Box::new(SideExitReason::GuardGreaterEq), state });
476476

477477
let _ = fun.push_insn(block, hir::Insn::ArrayAset { array: recv, index, val });
478-
fun.push_insn(block, hir::Insn::WriteBarrier { recv, val });
478+
fun.write_barrier(block, recv, val);
479479
return Some(val);
480480
}
481481
}
@@ -1006,7 +1006,7 @@ fn inline_struct_initialize(fun: &mut hir::Function, block: hir::BlockId, recv:
10061006
match args.get(index as usize) {
10071007
Some(&val) => {
10081008
fun.push_insn(block, hir::Insn::StoreField { recv, id, offset, val, num_bits });
1009-
fun.push_insn(block, hir::Insn::WriteBarrier { recv, val });
1009+
fun.write_barrier(block, recv, val);
10101010
}
10111011
// nil is an immediate, so the tail needs no write barrier.
10121012
None => {

‎zjit/src/hir.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3274,6 +3274,12 @@ impl Function {
32743274
id
32753275
}
32763276

3277+
pub fn write_barrier(&mut self, block: BlockId, recv: InsnId, val: InsnId) {
3278+
if !self.is_a(val, types::Immediate) {
3279+
self.push_insn(block, Insn::WriteBarrier { recv, val });
3280+
}
3281+
}
3282+
32773283
pub fn prepend_insn(&mut self, block: BlockId, insn: Insn) -> InsnId {
32783284
assert!(!matches!(insn, Insn::Param), "Cannot prepend a Param instruction");
32793285
let id = self.new_insn(insn);
@@ -5282,7 +5288,7 @@ impl Function {
52825288

52835289
let replacement = if let (OptimizedMethodType::StructAset, &[val]) = (opt_type, args.as_slice()) {
52845290
self.push_insn(block, Insn::StoreField { recv: target, id: mid.into(), offset, val, num_bits: types::BasicObject.num_bits() });
5285-
self.push_insn(block, Insn::WriteBarrier { recv, val });
5291+
self.write_barrier(block, recv, val);
52865292
val
52875293
} else { // StructAref
52885294
self.load_field(block, target, mid.into(), offset, types::BasicObject)
@@ -6407,7 +6413,7 @@ impl Function {
64076413
};
64086414

64096415
self.push_insn(block, Insn::StoreField { recv: ivar_storage, id: id.into(), offset, val, num_bits: types::BasicObject.num_bits() });
6410-
self.push_insn(block, Insn::WriteBarrier { recv: ivar_storage, val });
6416+
self.write_barrier(block, ivar_storage, val);
64116417
if spec.next_shape != spec.profiled_type.shape() {
64126418
// Write the new shape ID
64136419
let shape_id = self.push_insn(block, Insn::Const { val: Const::CShape(spec.next_shape) });

‎zjit/src/hir/opt_tests.rs‎

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13285,8 +13285,8 @@ mod hir_opt_tests {
1328513285
v32:CShape = LoadField v30, :shape_id@0x1040
1328613286
v33:CShape[0x1041] = GuardBitEquals v32, CShape(0x1041)
1328713287
StoreField v30, :@foo@0x1042, v17
13288-
v36:CShape[0x1043] = Const CShape(0x1043)
13289-
StoreField v30, :shape_id@0x1040, v36
13288+
v35:CShape[0x1043] = Const CShape(0x1043)
13289+
StoreField v30, :shape_id@0x1040, v35
1329013290
PatchPoint NoEPEscape(test)
1329113291
CheckInterrupts
1329213292
Return v17
@@ -13324,8 +13324,8 @@ mod hir_opt_tests {
1332413324
v32:CShape = LoadField v30, :shape_id@0x1040
1332513325
v33:CShape[0x1041] = GuardBitEquals v32, CShape(0x1041)
1332613326
StoreField v30, :@foo@0x1042, v17
13327-
v36:CShape[0x1043] = Const CShape(0x1043)
13328-
StoreField v30, :shape_id@0x1040, v36
13327+
v35:CShape[0x1043] = Const CShape(0x1043)
13328+
StoreField v30, :shape_id@0x1040, v35
1332913329
PatchPoint NoEPEscape(test)
1333013330
CheckInterrupts
1333113331
Return v17
@@ -13508,9 +13508,9 @@ mod hir_opt_tests {
1350813508
StoreField v50, :a@0x1069, v15
1350913509
StoreField v50, :b@0x106a, v17
1351013510
PatchPoint MethodRedefined(C@0x1008, b@0x106b, cme:0x1070)
13511-
v68:BasicObject = LoadField v50, :b@0x106a
13511+
v66:BasicObject = LoadField v50, :b@0x106a
1351213512
CheckInterrupts
13513-
Return v68
13513+
Return v66
1351413514
");
1351513515
}
1351613516

@@ -14905,9 +14905,9 @@ mod hir_opt_tests {
1490514905
v36:CUInt64 = LoadField v35, :RBASIC_FLAGS@0x1040
1490614906
v37:CUInt64 = GuardNoBitsSet v36, RUBY_FL_FREEZE=CUInt64(2048)
1490714907
v39:CUInt64 = GuardNoBitsSet v37, RUBY_ELTS_SHARED=CUInt64(4096)
14908-
v48:CInt64[1] = Const CInt64(1)
14908+
v47:CInt64[1] = Const CInt64(1)
1490914909
v41:CInt64 = ArrayLength v35
14910-
v42:CInt64[1] = GuardLess v48, v41
14910+
v42:CInt64[1] = GuardLess v47, v41
1491114911
ArrayAset v35, v42, v19
1491214912
PatchPoint NoEPEscape(test)
1491314913
CheckInterrupts
@@ -27559,22 +27559,22 @@ mod hir_opt_tests {
2755927559
v48:CUInt64 = LoadField v47, :RBASIC_FLAGS@0x1040
2756027560
v49:CUInt64 = GuardNoBitsSet v48, RUBY_FL_FREEZE=CUInt64(2048)
2756127561
v51:CUInt64 = GuardNoBitsSet v49, RUBY_ELTS_SHARED=CUInt64(4096)
27562-
v76:CInt64[0] = Const CInt64(0)
27562+
v74:CInt64[0] = Const CInt64(0)
2756327563
v53:CInt64 = ArrayLength v47
27564-
v54:CInt64[0] = GuardLess v76, v53
27564+
v54:CInt64[0] = GuardLess v74, v53
2756527565
ArrayAset v47, v54, v17
2756627566
PatchPoint NoEPEscape(test)
2756727567
v29:Fixnum[1] = Const Value(1)
2756827568
v31:Fixnum[2] = Const Value(2)
2756927569
PatchPoint NoSingletonClass(Array@0x1008)
2757027570
PatchPoint MethodRedefined(Array@0x1008, []=@0x1010, cme:0x1018)
27571-
v64:CUInt64 = LoadField v47, :RBASIC_FLAGS@0x1040
27572-
v65:CUInt64 = GuardNoBitsSet v64, RUBY_FL_FREEZE=CUInt64(2048)
27573-
v67:CUInt64 = GuardNoBitsSet v65, RUBY_ELTS_SHARED=CUInt64(4096)
27574-
v77:CInt64[1] = Const CInt64(1)
27575-
v69:CInt64 = ArrayLength v47
27576-
v70:CInt64[1] = GuardLess v77, v69
27577-
ArrayAset v47, v70, v31
27571+
v63:CUInt64 = LoadField v47, :RBASIC_FLAGS@0x1040
27572+
v64:CUInt64 = GuardNoBitsSet v63, RUBY_FL_FREEZE=CUInt64(2048)
27573+
v66:CUInt64 = GuardNoBitsSet v64, RUBY_ELTS_SHARED=CUInt64(4096)
27574+
v75:CInt64[1] = Const CInt64(1)
27575+
v68:CInt64 = ArrayLength v47
27576+
v69:CInt64[1] = GuardLess v75, v68
27577+
ArrayAset v47, v69, v31
2757827578
PatchPoint NoEPEscape(test)
2757927579
CheckInterrupts
2758027580
Return v31
@@ -27636,29 +27636,29 @@ mod hir_opt_tests {
2763627636
v40:NilClass = Const Value(nil)
2763727637
PatchPoint NoSingletonClass(Array@0x1008)
2763827638
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
27639-
v100:Fixnum = GuardType v16, Fixnum
27640-
v101:CInt64 = UnboxFixnum v100
27641-
v102:CInt64 = ArrayLength v69
27642-
v103:CInt64 = AdjustBounds v101, v102
27643-
v104:BasicObject = ArrayArefChecked v69, v103, v102
27639+
v99:Fixnum = GuardType v16, Fixnum
27640+
v100:CInt64 = UnboxFixnum v99
27641+
v101:CInt64 = ArrayLength v69
27642+
v102:CInt64 = AdjustBounds v100, v101
27643+
v103:BasicObject = ArrayArefChecked v69, v102, v101
2764427644
v50:Fixnum[1] = Const Value(1)
2764527645
PatchPoint MethodRedefined(Integer@0x1040, +@0x1048, cme:0x1050)
27646-
v107:Fixnum = GuardType v104, Fixnum recompile
27647-
v108:Fixnum = FixnumAdd v107, v50
27646+
v106:Fixnum = GuardType v103, Fixnum recompile
27647+
v107:Fixnum = FixnumAdd v106, v50
2764827648
PatchPoint MethodRedefined(Array@0x1008, []=@0x1078, cme:0x1080)
27649-
v114:CUInt64 = LoadField v69, :RBASIC_FLAGS@0x10a8
27650-
v115:CUInt64 = GuardNoBitsSet v114, RUBY_FL_FREEZE=CUInt64(2048)
27651-
v117:CUInt64 = GuardNoBitsSet v115, RUBY_ELTS_SHARED=CUInt64(4096)
27652-
v118:CInt64 = UnboxFixnum v100
27653-
v119:CInt64 = ArrayLength v69
27654-
v120:CInt64 = GuardLess v118, v119
27655-
v121:CInt64 = AdjustBounds v120, v119
27656-
v122:CInt64[0] = Const CInt64(0)
27657-
v123:CInt64 = GuardGreaterEq v121, v122
27658-
ArrayAset v69, v123, v108
27649+
v113:CUInt64 = LoadField v69, :RBASIC_FLAGS@0x10a8
27650+
v114:CUInt64 = GuardNoBitsSet v113, RUBY_FL_FREEZE=CUInt64(2048)
27651+
v116:CUInt64 = GuardNoBitsSet v114, RUBY_ELTS_SHARED=CUInt64(4096)
27652+
v117:CInt64 = UnboxFixnum v99
27653+
v118:CInt64 = ArrayLength v69
27654+
v119:CInt64 = GuardLess v117, v118
27655+
v120:CInt64 = AdjustBounds v119, v118
27656+
v121:CInt64[0] = Const CInt64(0)
27657+
v122:CInt64 = GuardGreaterEq v120, v121
27658+
ArrayAset v69, v122, v107
2765927659
PatchPoint NoEPEscape(test)
2766027660
CheckInterrupts
27661-
Return v108
27661+
Return v107
2766227662
");
2766327663
}
2766427664

@@ -27753,8 +27753,7 @@ mod hir_opt_tests {
2775327753
PatchPoint NoEPEscape(test)
2775427754
v26:Fixnum[2] = Const Value(2)
2775527755
PatchPoint MethodRedefined(S@0x1008, b=@0x1042, cme:0x1048)
27756-
v48:CUInt64 = LoadField v40, :RBASIC_FLAGS@0x1040
27757-
v49:CUInt64 = GuardNoBitsSet v48, RUBY_FL_FREEZE=CUInt64(2048)
27756+
v48:CUInt64 = GuardNoBitsSet v42, RUBY_FL_FREEZE=CUInt64(2048)
2775827757
StoreField v40, :b=@0x1070, v26
2775927758
CheckInterrupts
2776027759
Return v26

0 commit comments

Comments
 (0)