diff options
author | Koichi Sasada <ko1@atdot.net> | 2023-02-02 09:13:19 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-01 16:13:19 -0800 |
commit | 0a82bfe5e18ac86da72c27389db6eb8da156a0b5 (patch) | |
tree | d5cd6e0a79fa3e600b4d96ebbce3e3d957497c25 /vm.c | |
parent | 2675f2c864f462dbdee85d2187e0ac3379106eed (diff) | |
download | ruby-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.c | 23 |
1 files changed, 18 insertions, 5 deletions
@@ -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); } |