From 0a82bfe5e18ac86da72c27389db6eb8da156a0b5 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 2 Feb 2023 09:13:19 +0900 Subject: [PATCH] use correct svar (#7225) * use correct svar Without this patch, svar location is used "nearest Ruby frame". It is almost correct but it doesn't correct when the `each` method is written in Ruby. ```ruby class C include Enumerable def each %w(bar baz).each{|e| yield e} end end C.new.grep(/(b.)/){|e| p [$1, e]} ``` This patch fix this issue by traversing ifunc's cfp. Note that if cfp doesn't specify this Thread's cfp stack, reserved svar location (`ec->root_svar`) is used. * make yjit-bindgen --------- Co-authored-by: Takashi Kokubun --- internal/imemo.h | 2 +- proc.c | 2 +- vm.c | 23 ++++++++++++++++++----- yjit/src/cruby_bindings.inc.rs | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/internal/imemo.h b/internal/imemo.h index ef07333a58..8d506dda7d 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -82,7 +82,7 @@ struct vm_ifunc_argc { /*! IFUNC (Internal FUNCtion) */ struct vm_ifunc { VALUE flags; - VALUE reserved; + struct rb_control_frame_struct *owner_cfp; rb_block_call_func_t func; const void *data; struct vm_ifunc_argc argc; diff --git a/proc.c b/proc.c index c31017128e..b4f602a4cb 100644 --- a/proc.c +++ b/proc.c @@ -752,7 +752,7 @@ rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int m } arity.argc.min = min_argc; arity.argc.max = max_argc; - VALUE ret = rb_imemo_new(imemo_ifunc, (VALUE)func, (VALUE)data, arity.packed, 0); + VALUE ret = rb_imemo_new(imemo_ifunc, (VALUE)func, (VALUE)data, arity.packed, (VALUE)GET_EC()->cfp); return (struct vm_ifunc *)ret; } diff --git a/vm.c b/vm.c index d009a5f64a..bca0992155 100644 --- a/vm.c +++ b/vm.c @@ -1621,12 +1621,25 @@ rb_vm_invoke_proc_with_self(rb_execution_context_t *ec, rb_proc_t *proc, VALUE s /* special variable */ static rb_control_frame_t * -vm_normal_frame(const rb_execution_context_t *ec, rb_control_frame_t *cfp) +vm_svar_frame(const rb_execution_context_t *ec, rb_control_frame_t *cfp) { while (cfp->pc == 0) { - cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC) { + struct vm_ifunc *ifunc = (struct vm_ifunc *)cfp->iseq; + rb_control_frame_t *owner_cfp = ifunc->owner_cfp; + if (cfp < owner_cfp) { + cfp = ifunc->owner_cfp; + } + else { + return NULL; + } + } + else { + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } + if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) { - return 0; + return NULL; } } return cfp; @@ -1635,14 +1648,14 @@ vm_normal_frame(const rb_execution_context_t *ec, rb_control_frame_t *cfp) static VALUE vm_cfp_svar_get(const rb_execution_context_t *ec, rb_control_frame_t *cfp, VALUE key) { - cfp = vm_normal_frame(ec, cfp); + cfp = vm_svar_frame(ec, cfp); return lep_svar_get(ec, cfp ? VM_CF_LEP(cfp) : 0, key); } static void vm_cfp_svar_set(const rb_execution_context_t *ec, rb_control_frame_t *cfp, VALUE key, const VALUE val) { - cfp = vm_normal_frame(ec, cfp); + cfp = vm_svar_frame(ec, cfp); lep_svar_set(ec, cfp ? VM_CF_LEP(cfp) : 0, key, val); } diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index ea57ea67fd..128b249e3b 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -570,7 +570,7 @@ pub struct vm_ifunc_argc { #[repr(C)] pub struct vm_ifunc { pub flags: VALUE, - pub reserved: VALUE, + pub owner_cfp: *mut rb_control_frame_struct, pub func: rb_block_call_func_t, pub data: *const ::std::os::raw::c_void, pub argc: vm_ifunc_argc,