@@ -113,39 +113,62 @@ VM_EP_RUBY_LEP(const rb_execution_context_t *ec, const rb_control_frame_t *curre
113113 // rb_vmdebug_namespace_env_dump_raw() simulates this function
114114 const VALUE * ep = current_cfp -> ep ;
115115 const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME (ec ); /* end of control frame pointer */
116- const rb_control_frame_t * cfp = NULL , * checkpoint_cfp = current_cfp ;
116+ const rb_control_frame_t * cfp = current_cfp ;
117+
118+ if (VM_ENV_FRAME_TYPE_P (ep , VM_FRAME_MAGIC_IFUNC )) {
119+ ep = VM_EP_LEP (current_cfp -> ep );
120+ /**
121+ * Returns CFUNC frame only in this case.
122+ *
123+ * Usually CFUNC frame doesn't represent the current namespace and it should operate
124+ * the caller namespace. See the example:
125+ *
126+ * # in the main namespace
127+ * module Kernel
128+ * def foo = "foo"
129+ * module_function :foo
130+ * end
131+ *
132+ * In the case above, `module_function` is defined in the root namespace.
133+ * If `module_function` worked in the root namespace, `Kernel#foo` is invisible
134+ * from it and it causes NameError: undefined method `foo` for module `Kernel`.
135+ *
136+ * But in cases of IFUNC (blocks written in C), IFUNC doesn't have its own namespace
137+ * and its local env frame will be CFUNC frame.
138+ * For example, `Enumerator#chunk` calls IFUNC blocks, written as `chunk_i` function.
139+ *
140+ * [1].chunk{ it.even? }.each{ ... }
141+ *
142+ * Before calling the Ruby block `{ it.even? }`, `#chunk` calls `chunk_i` as IFUNC
143+ * to iterate the array's members (it's just like `#each`).
144+ * We expect that `chunk_i` works as expected by the implementation of `#chunk`
145+ * without any overwritten definitions from namespaces.
146+ * So the definitions on IFUNC frames should be equal to the caller CFUNC.
147+ */
148+ VM_ASSERT (VM_ENV_FRAME_TYPE_P (ep , VM_FRAME_MAGIC_CFUNC ));
149+ return ep ;
150+ }
117151
118- while (!VM_ENV_LOCAL_P (ep ) || VM_ENV_FRAME_TYPE_P (ep , VM_FRAME_MAGIC_CFUNC )) {
119- while (!VM_ENV_LOCAL_P (ep )) {
120- ep = VM_ENV_PREV_EP (ep );
121- }
122- while (VM_ENV_FLAGS (ep , VM_FRAME_FLAG_CFRAME ) != 0 ) {
123- if (!cfp ) {
124- cfp = rb_vm_search_cf_from_ep (ec , checkpoint_cfp , ep );
125- VM_NAMESPACE_ASSERT (cfp , "Failed to search cfp from ep" );
126- VM_NAMESPACE_ASSERT (cfp -> ep == ep , "Searched cfp's ep is not equal to ep" );
127- }
128- if (!cfp ) {
129- return NULL ;
130- }
131- VM_NAMESPACE_ASSERT (cfp -> ep , "cfp->ep == NULL" );
132- VM_NAMESPACE_ASSERT (cfp -> ep == ep , "cfp->ep != ep" );
152+ while (VM_ENV_FRAME_TYPE_P (ep , VM_FRAME_MAGIC_CFUNC )) {
153+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME (cfp );
133154
134- VM_NAMESPACE_ASSERT (!VM_FRAME_FINISHED_P (cfp ), "CFUNC frame should not FINISHED" );
155+ VM_NAMESPACE_ASSERT (cfp , "CFUNC should have a valid previous control frame" );
156+ VM_NAMESPACE_ASSERT (cfp < eocfp , "CFUNC should have a valid caller frame" );
157+ if (!cfp || cfp >= eocfp ) {
158+ return NULL ;
159+ }
135160
136- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME (cfp );
137- if (cfp >= eocfp ) {
138- return NULL ;
139- }
140- VM_NAMESPACE_ASSERT (cfp , "CFUNC should have a valid previous control frame" );
141- ep = cfp -> ep ;
142- if (!ep ) {
143- return NULL ;
144- }
161+ VM_NAMESPACE_ASSERT (cfp -> ep , "CFUNC should have a valid caller frame with env" );
162+ ep = cfp -> ep ;
163+ if (!ep ) {
164+ return NULL ;
145165 }
146- checkpoint_cfp = cfp ;
147- cfp = NULL ;
148166 }
167+
168+ while (!VM_ENV_LOCAL_P (ep )) {
169+ ep = VM_ENV_PREV_EP (ep );
170+ }
171+
149172 return ep ;
150173}
151174
@@ -3096,7 +3119,7 @@ current_namespace_on_cfp(const rb_execution_context_t *ec, const rb_control_fram
30963119 VM_NAMESPACE_ASSERT (lep , "lep should be valid" );
30973120 VM_NAMESPACE_ASSERT (rb_namespace_available (), "namespace should be available here" );
30983121
3099- if (VM_ENV_FRAME_TYPE_P (lep , VM_FRAME_MAGIC_METHOD )) {
3122+ if (VM_ENV_FRAME_TYPE_P (lep , VM_FRAME_MAGIC_METHOD ) || VM_ENV_FRAME_TYPE_P ( lep , VM_FRAME_MAGIC_CFUNC ) ) {
31003123 cme = check_method_entry (lep [VM_ENV_DATA_INDEX_ME_CREF ], TRUE);
31013124 VM_NAMESPACE_ASSERT (cme , "cme should be valid" );
31023125 VM_NAMESPACE_ASSERT (cme -> def , "cme->def shold be valid" );
0 commit comments