Skip to content

Commit 64f5a81

Browse files
committed
ZJIT: Check if BOP is redefined before rewriting
Fix Shopify#592
1 parent 616df50 commit 64f5a81

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

zjit/src/hir.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,11 @@ impl Function {
13821382
}
13831383

13841384
fn try_rewrite_fixnum_op(&mut self, block: BlockId, orig_insn_id: InsnId, f: &dyn Fn(InsnId, InsnId) -> Insn, bop: u32, left: InsnId, right: InsnId, state: InsnId) {
1385+
if !unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, INTEGER_REDEFINED_OP_FLAG) } {
1386+
// If the basic operation is already redefined, we cannot optimize it.
1387+
self.push_insn_id(block, orig_insn_id);
1388+
return;
1389+
}
13851390
if self.arguments_likely_fixnums(left, right, state) {
13861391
if bop == BOP_NEQ {
13871392
// For opt_neq, the interpreter checks that both neq and eq are unchanged.
@@ -1399,6 +1404,11 @@ impl Function {
13991404
}
14001405

14011406
fn rewrite_if_frozen(&mut self, block: BlockId, orig_insn_id: InsnId, self_val: InsnId, klass: u32, bop: u32, state: InsnId) {
1407+
if !unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } {
1408+
// If the basic operation is already redefined, we cannot optimize it.
1409+
self.push_insn_id(block, orig_insn_id);
1410+
return;
1411+
}
14021412
let self_type = self.type_of(self_val);
14031413
if let Some(obj) = self_type.ruby_object() {
14041414
if obj.is_frozen() {
@@ -1431,6 +1441,11 @@ impl Function {
14311441
}
14321442

14331443
fn try_rewrite_aref(&mut self, block: BlockId, orig_insn_id: InsnId, self_val: InsnId, idx_val: InsnId, state: InsnId) {
1444+
if !unsafe { rb_BASIC_OP_UNREDEFINED_P(BOP_AREF, ARRAY_REDEFINED_OP_FLAG) } {
1445+
// If the basic operation is already redefined, we cannot optimize it.
1446+
self.push_insn_id(block, orig_insn_id);
1447+
return;
1448+
}
14341449
let self_type = self.type_of(self_val);
14351450
let idx_type = self.type_of(idx_val);
14361451
if self_type.is_subtype(types::ArrayExact) {
@@ -2667,6 +2682,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
26672682
break; // End the block
26682683
},
26692684
};
2685+
if !unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG) } {
2686+
// If the basic operation is already redefined, we cannot optimize it.
2687+
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::PatchPoint(Invariant::BOPRedefined { klass: ARRAY_REDEFINED_OP_FLAG, bop }) });
2688+
break; // End the block
2689+
}
26702690
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass: ARRAY_REDEFINED_OP_FLAG, bop }, state: exit_id });
26712691
state.stack_push(fun.push_insn(block, insn));
26722692
}
@@ -5590,6 +5610,25 @@ mod opt_tests {
55905610
"#]]);
55915611
}
55925612

5613+
#[test]
5614+
fn test_dont_optimize_fixnum_add_if_redefined() {
5615+
eval("
5616+
class Integer
5617+
def +(other)
5618+
100
5619+
end
5620+
end
5621+
def test(a, b) = a + b
5622+
test(1,2); test(3,4)
5623+
");
5624+
assert_optimized_method_hir("test", expect![[r#"
5625+
fn test@<compiled>:7:
5626+
bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
5627+
v5:BasicObject = SendWithoutBlock v1, :+, v2
5628+
Return v5
5629+
"#]]);
5630+
}
5631+
55935632
#[test]
55945633
fn test_optimize_send_into_fixnum_add_both_profiled() {
55955634
eval("
@@ -6628,6 +6667,23 @@ mod opt_tests {
66286667
"#]]);
66296668
}
66306669

6670+
#[test]
6671+
fn test_dont_optimize_hash_freeze_if_redefined() {
6672+
eval("
6673+
class Hash
6674+
def freeze; end
6675+
end
6676+
def test = {}.freeze
6677+
");
6678+
assert_optimized_method_hir("test", expect![[r#"
6679+
fn test@<compiled>:5:
6680+
bb0(v0:BasicObject):
6681+
v3:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
6682+
v4:BasicObject = SendWithoutBlock v3, :freeze
6683+
Return v4
6684+
"#]]);
6685+
}
6686+
66316687
#[test]
66326688
fn test_elide_freeze_with_refrozen_hash() {
66336689
eval("
@@ -6973,6 +7029,44 @@ mod opt_tests {
69737029
"#]]);
69747030
}
69757031

7032+
#[test]
7033+
fn test_dont_optimize_array_aref_if_redefined() {
7034+
eval(r##"
7035+
class Array
7036+
def [](index); end
7037+
end
7038+
def test = [4,5,6].freeze[10]
7039+
"##);
7040+
assert_optimized_method_hir("test", expect![[r#"
7041+
fn test@<compiled>:5:
7042+
bb0(v0:BasicObject):
7043+
v3:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
7044+
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE)
7045+
v5:Fixnum[10] = Const Value(10)
7046+
v7:BasicObject = SendWithoutBlock v3, :[], v5
7047+
Return v7
7048+
"#]]);
7049+
}
7050+
7051+
#[test]
7052+
fn test_dont_optimize_array_max_if_redefined() {
7053+
eval(r##"
7054+
class Array
7055+
def max = 10
7056+
end
7057+
def test = [4,5,6].max
7058+
"##);
7059+
assert_optimized_method_hir("test", expect![[r#"
7060+
fn test@<compiled>:5:
7061+
bb0(v0:BasicObject):
7062+
v2:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
7063+
v4:ArrayExact = ArrayDup v2
7064+
PatchPoint MethodRedefined(Array@0x1008, max@0x1010)
7065+
v9:BasicObject = SendWithoutBlockDirect v4, :max (0x1018)
7066+
Return v9
7067+
"#]]);
7068+
}
7069+
69767070
#[test]
69777071
fn test_set_type_from_constant() {
69787072
eval("

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy