summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <rubybugs@bernsteinbear.com>2025-10-27 18:53:28 -0400
committerGitHub <noreply@github.com>2025-10-27 22:53:28 +0000
commit8d45e1f34e9a169987587d99a837b4ee035d7000 (patch)
tree081f85ca1c075bfef97ad775c333b9af17413480
parentd97fb3b424cebb812012a4e8a497a88510be9b72 (diff)
ZJIT: Fix internal compiler error looking up profiles for trace_getinstancevariable (#14969)
We treat getinstancevariable differently from other opcodes: it does not look at the stack for its self operand, but instead looks at `cfp->self`. In some cases, we might see the `trace_` variant in the front-end, so make sure we treat that the same. Example repro: ``` def test @foo end 28.times do test end trace = TracePoint.trace(:call) do |tp| puts tp.method_id end trace.enable do 30.times do test end end ```
-rw-r--r--zjit/src/hir.rs29
1 files changed, 28 insertions, 1 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 61014d5fd4..e948ee4452 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -4021,7 +4021,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
.try_into()
.unwrap();
- if opcode == YARVINSN_getinstancevariable {
+ // If TracePoint has been enabled after we have collected profiles, we'll see
+ // trace_getinstancevariable in the ISEQ. We have to treat it like getinstancevariable
+ // for profiling purposes: there is no operand on the stack to look up; we have
+ // profiled cfp->self.
+ if opcode == YARVINSN_getinstancevariable || opcode == YARVINSN_trace_getinstancevariable {
profiles.profile_self(&exit_state, self_param);
} else {
profiles.profile_stack(&exit_state);
@@ -7409,6 +7413,29 @@ mod tests {
}
#[test]
+ fn test_trace_getinstancevariable() {
+ eval("
+ def test = @foo
+ test
+ trace = TracePoint.trace(:call) { |tp| }
+ trace.enable { test }
+ ");
+ assert_contains_opcode("test", YARVINSN_trace_getinstancevariable);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@<compiled>:2:
+ bb0():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb2(v1)
+ bb1(v4:BasicObject):
+ EntryPoint JIT(0)
+ Jump bb2(v4)
+ bb2(v6:BasicObject):
+ SideExit UnhandledYARVInsn(trace_getinstancevariable)
+ ");
+ }
+
+ #[test]
fn test_setinstancevariable() {
eval("
def test = @foo = 1