Skip to content

Commit d8e7ab9

Browse files
authored
YJIT: Split the block on optimized getlocal/setlocal (#13331)
1 parent a21b88a commit d8e7ab9

File tree

2 files changed

+54
-5
lines changed

2 files changed

+54
-5
lines changed

test/-ext-/debug/test_debug.rb

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,58 @@ def test_lazy_block
7575
end
7676
assert_equal true, x, '[Bug #15105]'
7777
end
78+
end
79+
80+
# This is a YJIT test, but we can't test this without a C extension that calls
81+
# rb_debug_inspector_open(), so we're testing it using "-test-/debug" here.
82+
class TestDebugWithYJIT < Test::Unit::TestCase
83+
class LocalSetArray
84+
def to_a
85+
Bug::Debug.inspector.each do |_, binding,|
86+
binding.local_variable_set(:local, :ok) if binding
87+
end
88+
[:ok]
89+
end
90+
end
91+
92+
class DebugArray
93+
def to_a
94+
Bug::Debug.inspector
95+
[:ok]
96+
end
97+
end
98+
99+
def test_yjit_invalidates_getlocal_after_splatarray
100+
val = getlocal_after_splatarray(LocalSetArray.new)
101+
assert_equal [:ok, :ok], val
102+
end
78103

79-
# This is a YJIT test, but we can't test this without a C extension that calls
80-
# rb_debug_inspector_open(), so we're testing it using "-test-/debug" here.
81-
def test_yjit_invalidates_setlocal_after_inspector_call
104+
def test_yjit_invalidates_setlocal_after_splatarray
105+
val = setlocal_after_splatarray(DebugArray.new)
106+
assert_equal [:ok], val
107+
end
108+
109+
def test_yjit_invalidates_setlocal_after_proc_call
82110
val = setlocal_after_proc_call(proc { Bug::Debug.inspector; :ok })
83111
assert_equal :ok, val
84-
end if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
112+
end
85113

86114
private
87115

116+
def getlocal_after_splatarray(array)
117+
local = 1
118+
[*array, local]
119+
end
120+
121+
def setlocal_after_splatarray(array)
122+
local = *array # setlocal followed by splatarray
123+
itself # split a block using a C call
124+
local # getlocal
125+
end
126+
88127
def setlocal_after_proc_call(block)
89128
local = block.call # setlocal followed by OPTIMIZED_METHOD_TYPE_CALL
90129
itself # split a block using a C call
91130
local # getlocal
92131
end
93-
end
132+
end if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?

yjit/src/codegen.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,11 @@ fn gen_getlocal_generic(
24452445
ep_offset: u32,
24462446
level: u32,
24472447
) -> Option<CodegenStatus> {
2448+
// Split the block if we need to invalidate this instruction when EP escapes
2449+
if level == 0 && !jit.escapes_ep() && !jit.at_compile_target() {
2450+
return jit.defer_compilation(asm);
2451+
}
2452+
24482453
let local_opnd = if level == 0 && jit.assume_no_ep_escape(asm) {
24492454
// Load the local using SP register
24502455
asm.local_opnd(ep_offset)
@@ -2535,6 +2540,11 @@ fn gen_setlocal_generic(
25352540
return Some(KeepCompiling);
25362541
}
25372542

2543+
// Split the block if we need to invalidate this instruction when EP escapes
2544+
if level == 0 && !jit.escapes_ep() && !jit.at_compile_target() {
2545+
return jit.defer_compilation(asm);
2546+
}
2547+
25382548
let (flags_opnd, local_opnd) = if level == 0 && jit.assume_no_ep_escape(asm) {
25392549
// Load flags and the local using SP register
25402550
let flags_opnd = asm.ctx.ep_opnd(VM_ENV_DATA_INDEX_FLAGS as i32);

0 commit comments

Comments
 (0)