Skip to content

Commit 20c73b1

Browse files
committed
Skip CFUNC frames in the current namespace detection
* The current namespace should be based on the Ruby-level location (file, line no in .rb) and we can get it by LEP(ep) basically (VM_ENV_FLAG_LOCAL flag is set) * But the control frame with VM_FRAME_MAGIC_CFUNC is also a LOCAL frame because it's a visible Ruby-level frame without block handlers * So, for the namespace detection, LEP(ep) is not enough and we need to skip CFUNC frames to fetch the caller of such frames
1 parent a5df24f commit 20c73b1

File tree

2 files changed

+34
-27
lines changed

2 files changed

+34
-27
lines changed

namespace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ rb_namespace_s_current(VALUE recv)
460460
if (!rb_namespace_available())
461461
return Qnil;
462462

463-
ns = rb_vm_caller_namespace(GET_EC());
463+
ns = rb_vm_current_namespace(GET_EC());
464464
VM_ASSERT(ns && ns->ns_object);
465465
return ns->ns_object;
466466
}

vm.c

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,29 @@ rb_vm_search_cf_from_ep(const rb_execution_context_t *ec, const rb_control_frame
9595
}
9696
}
9797

98+
static const VALUE *
99+
VM_EP_RUBY_LEP(const rb_execution_context_t *ec, const rb_control_frame_t *current_cfp)
100+
{
101+
const VALUE *ep = current_cfp->ep;
102+
const rb_control_frame_t *cfp, *checkpoint_cfp = current_cfp;
103+
104+
while (!VM_ENV_LOCAL_P(ep) || VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CFUNC)) {
105+
while (!VM_ENV_LOCAL_P(ep)) {
106+
ep = VM_ENV_PREV_EP(ep);
107+
}
108+
while (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CFUNC)) {
109+
if (!cfp) {
110+
cfp = rb_vm_search_cf_from_ep(ec, checkpoint_cfp, ep);
111+
}
112+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
113+
ep = cfp->ep;
114+
}
115+
checkpoint_cfp = cfp;
116+
cfp = NULL;
117+
}
118+
return ep;
119+
}
120+
98121
const VALUE *
99122
rb_vm_ep_local_ep(const VALUE *ep)
100123
{
@@ -1001,11 +1024,8 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
10011024
VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_SPECVAL], VM_GUARDED_PREV_EP(prev_cfp->ep));
10021025
}
10031026
}
1004-
else if (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_TOP)) {
1005-
// block_handler is always VM_BLOCK_HANDLER_NONE in this case
1006-
}
10071027
else {
1008-
VM_ASSERT(VM_ENV_LOCAL_P(ep) && !VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_TOP));
1028+
VM_ASSERT(VM_ENV_LOCAL_P(ep));
10091029
VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep);
10101030

10111031
if (block_handler != VM_BLOCK_HANDLER_NONE) {
@@ -3017,15 +3037,15 @@ rb_vm_frame_flag_set_ns_require(const rb_execution_context_t *ec)
30173037
}
30183038

30193039
static const rb_namespace_t *
3020-
current_namespace_on_env(const VALUE *ep)
3040+
current_namespace_on_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
30213041
{
30223042
rb_callable_method_entry_t *cme;
30233043
const rb_namespace_t *ns;
3024-
const VALUE *lep = VM_EP_LEP(ep);
3044+
const VALUE *lep = VM_EP_RUBY_LEP(ec, cfp);
30253045
VM_ASSERT(lep);
30263046
VM_ASSERT(rb_namespace_available());
30273047

3028-
if (VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_METHOD) || VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_CFUNC)) {
3048+
if (VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_METHOD)) {
30293049
cme = check_method_entry(lep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
30303050
VM_ASSERT(cme);
30313051
VM_ASSERT(cme->def);
@@ -3053,29 +3073,16 @@ const rb_namespace_t *
30533073
rb_vm_current_namespace(const rb_execution_context_t *ec)
30543074
{
30553075
VM_ASSERT(rb_namespace_available());
3056-
return current_namespace_on_env(ec->cfp->ep);
3057-
}
3058-
3059-
const rb_namespace_t *
3060-
rb_vm_caller_namespace(const rb_execution_context_t *ec)
3061-
{
3062-
const rb_control_frame_t *caller_cfp;
3063-
3064-
VM_ASSERT(rb_namespace_available());
3065-
3066-
// The current control frame is MAGIC_CFUNC to call Namespace.current, but
3067-
// we want to get the current namespace of its caller.
3068-
caller_cfp = vm_get_ruby_level_caller_cfp(ec, ec->cfp);
3069-
return current_namespace_on_env(caller_cfp->ep);
3076+
return current_namespace_on_cfp(ec, ec->cfp);
30703077
}
30713078

30723079
static const rb_control_frame_t *
3073-
find_loader_control_frame(const rb_control_frame_t *cfp, const rb_control_frame_t *end_cfp)
3080+
find_loader_control_frame(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const rb_control_frame_t *end_cfp)
30743081
{
30753082
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
30763083
if (!VM_ENV_FRAME_TYPE_P(cfp->ep, VM_FRAME_MAGIC_CFUNC))
30773084
break;
3078-
if (!NAMESPACE_ROOT_P(current_namespace_on_env(cfp->ep)))
3085+
if (!NAMESPACE_ROOT_P(current_namespace_on_cfp(ec, cfp)))
30793086
break;
30803087
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
30813088
}
@@ -3102,13 +3109,13 @@ rb_vm_loading_namespace(const rb_execution_context_t *ec)
31023109
return rb_get_namespace_t(cfp->self);
31033110
}
31043111
// Kernel#require, #require_relative, #load
3105-
cfp = find_loader_control_frame(cfp, end_cfp);
3106-
return current_namespace_on_env(cfp->ep);
3112+
cfp = find_loader_control_frame(ec, cfp, end_cfp);
3113+
return current_namespace_on_cfp(ec, cfp);
31073114
}
31083115
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
31093116
}
31103117
// no require/load with explicit namespaces.
3111-
return current_namespace_on_env(current_cfp->ep);
3118+
return current_namespace_on_cfp(ec, current_cfp);
31123119
}
31133120

31143121
/* vm */

0 commit comments

Comments
 (0)