summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2023-02-02 09:13:19 +0900
committerGitHub <noreply@github.com>2023-02-01 16:13:19 -0800
commit0a82bfe5e18ac86da72c27389db6eb8da156a0b5 (patch)
treed5cd6e0a79fa3e600b4d96ebbce3e3d957497c25 /vm.c
parent2675f2c864f462dbdee85d2187e0ac3379106eed (diff)
downloadruby-0a82bfe5e18ac86da72c27389db6eb8da156a0b5.tar.gz
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 <takashikkbn@gmail.com>
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c23
1 files changed, 18 insertions, 5 deletions
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);
}