Skip to content

Commit 4f47327

Browse files
committed
Update current namespace management by using control frames and lexical contexts
to fix inconsistent and wrong current namespace detections. This includes: * Moving load_path and related things from rb_vm_t to rb_namespace_t to simplify accessing those values via namespace (instead of accessing either vm or ns) * Initializing root_namespace earlier and consolidate builtin_namespace into root_namespace * Adding VM_FRAME_FLAG_NS_REQUIRE for checkpoints to detect a namespace to load/require files * Removing implicit refinements in the root namespace which was used to determine the namespace to be loaded (replaced by VM_FRAME_FLAG_NS_REQUIRE) * Removing namespaces from rb_proc_t because its namespace can be identified by lexical context * Starting to use ep[VM_ENV_DATA_INDEX_SPECVAL] to store the current namespace when the frame type is MAGIC_TOP or MAGIC_CLASS (block handlers don't exist in this case)
1 parent 43392af commit 4f47327

File tree

21 files changed

+487
-812
lines changed

21 files changed

+487
-812
lines changed

builtin.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,8 @@ load_with_builtin_functions(const char *feature_name, const struct rb_builtin_fu
5050
ASSUME(iseq); // otherwise an exception should have raised
5151
vm->builtin_function_table = NULL;
5252

53-
rb_namespace_enable_builtin();
54-
5553
// exec
56-
if (rb_namespace_available() && rb_mNamespaceRefiner) {
57-
rb_iseq_eval_with_refinement(rb_iseq_check(iseq), rb_mNamespaceRefiner);
58-
}
59-
else {
60-
rb_iseq_eval(rb_iseq_check(iseq));
61-
}
62-
63-
rb_namespace_disable_builtin();
54+
rb_iseq_eval(rb_iseq_check(iseq), rb_root_namespace()); // builtin functions are loaded in the root namespace
6455
}
6556

6657
void

class.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool namespaceable)
650650
{
651651
rb_ns_subclasses_t *ns_subclasses;
652652
rb_subclass_anchor_t *anchor;
653-
const rb_namespace_t *ns = rb_definition_namespace();
653+
const rb_namespace_t *ns = rb_current_namespace();
654654

655655
if (!ruby_namespace_init_done) {
656656
namespaceable = true;

eval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ ruby_setup(void)
8080
rb_vm_encoded_insn_data_table_init();
8181
Init_enable_namespace();
8282
Init_vm_objects();
83+
Init_root_namespace();
8384
Init_fstring_table();
8485

8586
EC_PUSH_TAG(GET_EC());

eval_intern.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,10 @@ VALUE rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type state, VALUE val);
296296
rb_cref_t *rb_vm_cref(void);
297297
rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void);
298298
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename);
299-
VALUE rb_vm_call_cfunc2(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE block_handler, VALUE filename);
299+
VALUE rb_vm_call_cfunc_in_namespace(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE filename, const rb_namespace_t *ns);
300+
void rb_vm_frame_flag_set_ns_require(const rb_execution_context_t *ec);
301+
const rb_namespace_t *rb_vm_current_namespace(const rb_execution_context_t *ec);
302+
const rb_namespace_t *rb_vm_loading_namespace(const rb_execution_context_t *ec);
300303
void rb_vm_set_progname(VALUE filename);
301304
VALUE rb_vm_cbase(void);
302305

inits.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ rb_call_inits(void)
5252
CALL(Time);
5353
CALL(Random);
5454
CALL(load);
55+
CALL(Namespace);
5556
CALL(Proc);
5657
CALL(Binding);
5758
CALL(Math);
@@ -78,7 +79,6 @@ rb_call_inits(void)
7879
CALL(Prism);
7980
CALL(unicode_version);
8081
CALL(Set);
81-
CALL(Namespace);
8282

8383
// enable builtin loading
8484
CALL(builtin);

insns.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,12 +803,13 @@ defineclass
803803
(VALUE val)
804804
{
805805
VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
806+
const rb_namespace_t *ns = rb_current_namespace();
806807

807808
rb_iseq_check(class_iseq);
808809

809810
/* enter scope */
810811
vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
811-
GET_BLOCK_HANDLER(),
812+
GC_GUARDED_PTR(ns),
812813
(VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE),
813814
ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(),
814815
ISEQ_BODY(class_iseq)->local_table_size,

internal/class.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,7 @@ RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
390390
static inline rb_classext_t *
391391
RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
392392
{
393-
if (!ns
394-
|| NAMESPACE_BUILTIN_P(ns)
393+
if (NAMESPACE_ROOT_P(ns)
395394
|| RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
396395
return RCLASS_EXT_PRIME(obj);
397396
}
@@ -405,9 +404,9 @@ RCLASS_EXT_READABLE(VALUE obj)
405404
if (RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
406405
return RCLASS_EXT_PRIME(obj);
407406
}
408-
// delay namespace loading to optimize for unmodified classes
407+
// delay determining the current namespace to optimize for unmodified classes
409408
ns = rb_current_namespace();
410-
if (!ns || NAMESPACE_BUILTIN_P(ns)) {
409+
if (NAMESPACE_ROOT_P(ns)) {
411410
return RCLASS_EXT_PRIME(obj);
412411
}
413412
return RCLASS_EXT_READABLE_LOOKUP(obj, ns);
@@ -440,8 +439,7 @@ RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
440439
static inline rb_classext_t *
441440
RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
442441
{
443-
if (!ns
444-
|| NAMESPACE_BUILTIN_P(ns)
442+
if (NAMESPACE_ROOT_P(ns)
445443
|| RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj)) {
446444
return RCLASS_EXT_PRIME(obj);
447445
}
@@ -455,11 +453,9 @@ RCLASS_EXT_WRITABLE(VALUE obj)
455453
if (LIKELY(RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj))) {
456454
return RCLASS_EXT_PRIME(obj);
457455
}
458-
// delay namespace loading to optimize for unmodified classes
456+
// delay determining the current namespace to optimize for unmodified classes
459457
ns = rb_current_namespace();
460-
if (!ns || NAMESPACE_BUILTIN_P(ns)) {
461-
// If no namespace is specified, Ruby VM is in bootstrap
462-
// and the clean class definition is under construction.
458+
if (NAMESPACE_ROOT_P(ns)) {
463459
return RCLASS_EXT_PRIME(obj);
464460
}
465461
return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns);

internal/inits.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ void Init_enable_namespace(void);
3232
void Init_BareVM(void);
3333
void Init_vm_objects(void);
3434

35+
/* namespace.c */
36+
void Init_root_namespace(void);
37+
3538
/* vm_backtrace.c */
3639
void Init_vm_backtrace(void);
3740

internal/namespace.h

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ struct rb_namespace_struct {
3535

3636
VALUE gvar_tbl;
3737

38-
bool is_builtin;
3938
bool is_user;
4039
bool is_optional;
4140
};
4241
typedef struct rb_namespace_struct rb_namespace_t;
4342

44-
#define NAMESPACE_BUILTIN_P(ns) (ns && ns->is_builtin)
43+
#define NAMESPACE_OBJ_P(obj) (CLASS_OF(obj) == rb_cNamespace)
44+
45+
#define NAMESPACE_ROOT_P(ns) (ns && !ns->is_user)
4546
#define NAMESPACE_USER_P(ns) (ns && ns->is_user)
4647
#define NAMESPACE_OPTIONAL_P(ns) (ns && ns->is_optional)
4748
#define NAMESPACE_MAIN_P(ns) (ns && ns->is_user && !ns->is_optional)
@@ -60,24 +61,16 @@ rb_namespace_available(void)
6061
return ruby_namespace_enabled;
6162
}
6263

63-
void rb_namespace_enable_builtin(void);
64-
void rb_namespace_disable_builtin(void);
65-
void rb_namespace_push_loading_namespace(const rb_namespace_t *);
66-
void rb_namespace_pop_loading_namespace(const rb_namespace_t *);
67-
rb_namespace_t * rb_root_namespace(void);
68-
const rb_namespace_t *rb_builtin_namespace(void);
69-
rb_namespace_t * rb_main_namespace(void);
70-
const rb_namespace_t * rb_definition_namespace(void);
71-
const rb_namespace_t * rb_loading_namespace(void);
64+
const rb_namespace_t * rb_root_namespace(void);
65+
const rb_namespace_t * rb_main_namespace(void);
7266
const rb_namespace_t * rb_current_namespace(void);
73-
VALUE rb_current_namespace_details(VALUE);
67+
const rb_namespace_t * rb_loading_namespace(void);
7468

7569
void rb_namespace_entry_mark(void *);
70+
void rb_namespace_gc_update_references(void *ptr);
7671

7772
rb_namespace_t * rb_get_namespace_t(VALUE ns);
7873
VALUE rb_get_namespace_object(rb_namespace_t *ns);
79-
typedef VALUE namespace_exec_func(VALUE arg);
80-
VALUE rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg);
8174

8275
VALUE rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path);
8376

iseq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1966,7 +1966,7 @@ iseqw_eval(VALUE self)
19661966
if (0 == ISEQ_BODY(iseq)->iseq_size) {
19671967
rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
19681968
}
1969-
return rb_iseq_eval(iseq);
1969+
return rb_iseq_eval(iseq, rb_current_namespace());
19701970
}
19711971

19721972
/*

0 commit comments

Comments
 (0)