Ruby 3.5.0dev (2025-06-27 revision 4965954556b1db71fba6ce090cc217e97641687e)
namespace.c (4965954556b1db71fba6ce090cc217e97641687e)
1/* indent-tabs-mode: nil */
2
3#include "internal.h"
4#include "internal/class.h"
5#include "internal/eval.h"
6#include "internal/error.h"
7#include "internal/file.h"
8#include "internal/gc.h"
9#include "internal/hash.h"
10#include "internal/load.h"
11#include "internal/namespace.h"
12#include "internal/st.h"
13#include "internal/variable.h"
15#include "ruby/util.h"
16#include "vm_core.h"
17
18#include <stdio.h>
19
21VALUE rb_cNamespaceEntry = 0;
23VALUE rb_mNamespaceLoader = 0;
24
25static rb_namespace_t builtin_namespace_data = {
26 .ns_object = Qnil,
27 .ns_id = 0,
28 .is_builtin = true,
29 .is_user = false,
30 .is_optional = false
31};
32static rb_namespace_t * const root_namespace = 0;
33static rb_namespace_t * const builtin_namespace = &builtin_namespace_data;
34static rb_namespace_t * main_namespace = 0;
35static char *tmp_dir;
36static bool tmp_dir_has_dirsep;
37
38#define NAMESPACE_TMP_PREFIX "_ruby_ns_"
39
40#ifndef MAXPATHLEN
41# define MAXPATHLEN 1024
42#endif
43
44#if defined(_WIN32)
45# define DIRSEP "\\"
46#else
47# define DIRSEP "/"
48#endif
49
50bool ruby_namespace_enabled = false; // extern
51bool ruby_namespace_init_done = false; // extern
52
53VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
54static VALUE rb_namespace_inspect(VALUE obj);
55static void namespace_push(rb_thread_t *th, VALUE namespace);
56static VALUE namespace_pop(VALUE th_value);
57
58void
59rb_namespace_init_done(void)
60{
61 ruby_namespace_init_done = true;
62}
63
64void
65rb_namespace_enable_builtin(void)
66{
67 VALUE require_stack = GET_VM()->require_stack;
68 if (require_stack) {
69 rb_ary_push(require_stack, Qnil);
70 }
71}
72
73void
74rb_namespace_disable_builtin(void)
75{
76 VALUE require_stack = GET_VM()->require_stack;
77 if (require_stack) {
78 rb_ary_pop(require_stack);
79 }
80}
81
82void
83rb_namespace_push_loading_namespace(const rb_namespace_t *ns)
84{
85 VALUE require_stack = GET_VM()->require_stack;
86 rb_ary_push(require_stack, ns->ns_object);
87}
88
89void
90rb_namespace_pop_loading_namespace(const rb_namespace_t *ns)
91{
92 VALUE require_stack = GET_VM()->require_stack;
93 long size = RARRAY_LEN(require_stack);
94 if (size == 0)
95 rb_bug("popping on the empty require_stack");
96 VALUE latest = RARRAY_AREF(require_stack, size-1);
97 if (latest != ns->ns_object)
98 rb_bug("Inconsistent loading namespace");
99 rb_ary_pop(require_stack);
100}
101
103rb_root_namespace(void)
104{
105 return root_namespace;
106}
107
108const rb_namespace_t *
109rb_builtin_namespace(void)
110{
111 return (const rb_namespace_t *)builtin_namespace;
112}
113
115rb_main_namespace(void)
116{
117 return main_namespace;
118}
119
120static bool
121namespace_ignore_builtin_primitive_methods_p(const rb_namespace_t *ns, rb_method_definition_t *def)
122{
123 if (!NAMESPACE_BUILTIN_P(ns)) {
124 return false;
125 }
126 /* Primitive methods (just to call C methods) covers/hides the effective
127 namespaces, so ignore the methods' namespaces to expose user code's
128 namespace to the implementation.
129 */
130 if (def->type == VM_METHOD_TYPE_ISEQ) {
131 ID mid = def->original_id;
132 const char *path = RSTRING_PTR(pathobj_path(def->body.iseq.iseqptr->body->location.pathobj));
133 if (strcmp(path, "<internal:kernel>") == 0) {
134 if (mid == rb_intern("class") || mid == rb_intern("clone") ||
135 mid == rb_intern("tag") || mid == rb_intern("then") ||
136 mid == rb_intern("yield_self") || mid == rb_intern("loop") ||
137 mid == rb_intern("Float") || mid == rb_intern("Integer")
138 ) {
139 return true;
140 }
141 }
142 else if (strcmp(path, "<internal:warning>") == 0) {
143 if (mid == rb_intern("warn")) {
144 return true;
145 }
146 }
147 else if (strcmp(path, "<internal:marshal>") == 0) {
148 if (mid == rb_intern("load"))
149 return true;
150 }
151 }
152 return false;
153}
154
155static inline const rb_namespace_t *
156block_proc_namespace(const VALUE procval)
157{
158 rb_proc_t *proc;
159
160 if (procval) {
161 GetProcPtr(procval, proc);
162 return proc->ns;
163 }
164 else {
165 return NULL;
166 }
167}
168
169static const rb_namespace_t *
170current_namespace(bool permit_calling_builtin)
171{
172 /*
173 * TODO: move this code to vm.c or somewhere else
174 * when it's fully updated with VM_FRAME_FLAG_*
175 */
177 const rb_namespace_t *ns;
178 rb_execution_context_t *ec = GET_EC();
179 rb_control_frame_t *cfp = ec->cfp;
180 rb_thread_t *th = rb_ec_thread_ptr(ec);
181 int calling = 1;
182
183 if (!rb_namespace_available())
184 return 0;
185
186 if (th->namespaces && RARRAY_LEN(th->namespaces) > 0) {
187 // temp code to detect the context is in require/load
188 // TODO: this doesn't work well in optional namespaces
189 // calling = 0;
190 }
191 while (calling) {
192 const rb_namespace_t *proc_ns = NULL;
193 VALUE bh;
194 if (VM_FRAME_NS_SWITCH_P(cfp)) {
195 bh = rb_vm_frame_block_handler(cfp);
196 if (bh && vm_block_handler_type(bh) == block_handler_type_proc) {
197 proc_ns = block_proc_namespace(VM_BH_TO_PROC(bh));
198 if (permit_calling_builtin || NAMESPACE_USER_P(proc_ns))
199 return proc_ns;
200 }
201 }
202 cme = rb_vm_frame_method_entry(cfp);
203 if (cme && cme->def) {
204 ns = cme->def->ns;
205 if (ns) {
206 // this method is not a built-in class/module's method
207 // or a built-in primitive (Ruby) method
208 if (!namespace_ignore_builtin_primitive_methods_p(ns, cme->def)) {
209 if (permit_calling_builtin || (proc_ns && NAMESPACE_USER_P(proc_ns)))
210 return ns;
211 }
212 }
213 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
214 }
215 else {
216 calling = 0;
217 }
218 }
219 // not in namespace-marked method calls
220 ns = th->ns;
221 if (ns) {
222 return ns;
223 }
224 if (!main_namespace) {
225 // Namespaces are not ready to be created
226 return root_namespace;
227 }
228 return main_namespace;
229}
230
231const rb_namespace_t *
232rb_current_namespace(void)
233{
234 return current_namespace(true);
235}
236
237const rb_namespace_t *
238rb_loading_namespace(void)
239{
240 VALUE namespace;
241 long len;
242 VALUE require_stack = GET_VM()->require_stack;
243
244 if (!rb_namespace_available())
245 return 0;
246
247 if (!require_stack) {
248 return current_namespace(false);
249 }
250 if ((len = RARRAY_LEN(require_stack)) == 0) {
251 return current_namespace(false);
252 }
253
254 if (!RB_TYPE_P(require_stack, T_ARRAY))
255 rb_bug("require_stack is not an array: %s", rb_type_str(BUILTIN_TYPE(require_stack)));
256
257 namespace = RARRAY_AREF(require_stack, len-1);
258 return rb_get_namespace_t(namespace);
259}
260
261const rb_namespace_t *
262rb_definition_namespace(void)
263{
264 const rb_namespace_t *ns = current_namespace(true);
265 if (NAMESPACE_BUILTIN_P(ns)) {
266 return root_namespace;
267 }
268 return ns;
269}
270
271static long namespace_id_counter = 0;
272
273static long
274namespace_generate_id(void)
275{
276 long id;
277 RB_VM_LOCKING() {
278 id = ++namespace_id_counter;
279 }
280 return id;
281}
282
283static void
284namespace_entry_initialize(rb_namespace_t *ns)
285{
286 rb_vm_t *vm = GET_VM();
287
288 // These will be updated immediately
289 ns->ns_object = 0;
290 ns->ns_id = 0;
291
292 ns->top_self = 0;
293 ns->load_path = rb_ary_dup(vm->load_path);
294 ns->expanded_load_path = rb_ary_dup(vm->expanded_load_path);
295 ns->load_path_snapshot = rb_ary_new();
296 ns->load_path_check_cache = 0;
297 ns->loaded_features = rb_ary_dup(vm->loaded_features);
298 ns->loaded_features_snapshot = rb_ary_new();
299 ns->loaded_features_index = st_init_numtable();
300 ns->loaded_features_realpaths = rb_hash_dup(vm->loaded_features_realpaths);
301 ns->loaded_features_realpath_map = rb_hash_dup(vm->loaded_features_realpath_map);
302 ns->loading_table = st_init_strtable();
303 ns->ruby_dln_libmap = rb_hash_new_with_size(0);
304 ns->gvar_tbl = rb_hash_new_with_size(0);
305
306 ns->is_builtin = false;
307 ns->is_user = true;
308 ns->is_optional = true;
309}
310
311void rb_namespace_gc_update_references(void *ptr)
312{
313 rb_namespace_t *ns = (rb_namespace_t *)ptr;
314 if (!NIL_P(ns->ns_object))
315 ns->ns_object = rb_gc_location(ns->ns_object);
316 ns->top_self = rb_gc_location(ns->top_self);
317 ns->load_path = rb_gc_location(ns->load_path);
318 ns->expanded_load_path = rb_gc_location(ns->expanded_load_path);
319 ns->load_path_snapshot = rb_gc_location(ns->load_path_snapshot);
320 if (ns->load_path_check_cache) {
321 ns->load_path_check_cache = rb_gc_location(ns->load_path_check_cache);
322 }
323 ns->loaded_features = rb_gc_location(ns->loaded_features);
324 ns->loaded_features_snapshot = rb_gc_location(ns->loaded_features_snapshot);
325 ns->loaded_features_realpaths = rb_gc_location(ns->loaded_features_realpaths);
326 ns->loaded_features_realpath_map = rb_gc_location(ns->loaded_features_realpath_map);
327 ns->ruby_dln_libmap = rb_gc_location(ns->ruby_dln_libmap);
328 ns->gvar_tbl = rb_gc_location(ns->gvar_tbl);
329}
330
331void
332rb_namespace_entry_mark(void *ptr)
333{
334 const rb_namespace_t *ns = (rb_namespace_t *)ptr;
335 rb_gc_mark(ns->ns_object);
336 rb_gc_mark(ns->top_self);
337 rb_gc_mark(ns->load_path);
338 rb_gc_mark(ns->expanded_load_path);
339 rb_gc_mark(ns->load_path_snapshot);
340 rb_gc_mark(ns->load_path_check_cache);
341 rb_gc_mark(ns->loaded_features);
342 rb_gc_mark(ns->loaded_features_snapshot);
343 rb_gc_mark(ns->loaded_features_realpaths);
344 rb_gc_mark(ns->loaded_features_realpath_map);
345 if (ns->loading_table) {
346 rb_mark_tbl(ns->loading_table);
347 }
348 rb_gc_mark(ns->ruby_dln_libmap);
349 rb_gc_mark(ns->gvar_tbl);
350}
351
352#define namespace_entry_free RUBY_TYPED_DEFAULT_FREE
353
354static size_t
355namespace_entry_memsize(const void *ptr)
356{
357 return sizeof(rb_namespace_t);
358}
359
360const rb_data_type_t rb_namespace_data_type = {
361 "Namespace::Entry",
362 {
363 rb_namespace_entry_mark,
364 namespace_entry_free,
365 namespace_entry_memsize,
366 rb_namespace_gc_update_references,
367 },
368 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
369};
370
371VALUE
372rb_namespace_entry_alloc(VALUE klass)
373{
374 rb_namespace_t *entry;
375 VALUE obj = TypedData_Make_Struct(klass, rb_namespace_t, &rb_namespace_data_type, entry);
376 namespace_entry_initialize(entry);
377 return obj;
378}
379
380static rb_namespace_t *
381get_namespace_struct_internal(VALUE entry)
382{
383 rb_namespace_t *sval;
384 TypedData_Get_Struct(entry, rb_namespace_t, &rb_namespace_data_type, sval);
385 return sval;
386}
387
389rb_get_namespace_t(VALUE namespace)
390{
391 VALUE entry;
392 ID id_namespace_entry;
393
394 if (!namespace)
395 return root_namespace;
396 if (NIL_P(namespace))
397 return builtin_namespace;
398
399 CONST_ID(id_namespace_entry, "__namespace_entry__");
400 entry = rb_attr_get(namespace, id_namespace_entry);
401 return get_namespace_struct_internal(entry);
402}
403
404VALUE
405rb_get_namespace_object(rb_namespace_t *ns)
406{
407 if (!ns) // root namespace
408 return Qfalse;
409 return ns->ns_object;
410}
411
412static void setup_pushing_loading_namespace(rb_namespace_t *ns);
413
414static VALUE
415namespace_initialize(VALUE namespace)
416{
417 rb_namespace_t *ns;
418 rb_classext_t *object_classext;
419 VALUE entry;
420 ID id_namespace_entry;
421 CONST_ID(id_namespace_entry, "__namespace_entry__");
422
423 if (!rb_namespace_available()) {
424 rb_raise(rb_eRuntimeError, "Namespace is disabled. Set RUBY_NAMESPACE=1 environment variable to use Namespace.");
425 }
426
427 entry = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespaceEntry);
428 ns = get_namespace_struct_internal(entry);
429
430 ns->ns_object = namespace;
431 ns->ns_id = namespace_generate_id();
432 ns->load_path = rb_ary_dup(GET_VM()->load_path);
433 ns->is_user = true;
434 rb_define_singleton_method(ns->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
435
436 // Set the Namespace object unique/consistent from any namespaces to have just single
437 // constant table from any view of every (including main) namespace.
438 // If a code in the namespace adds a constant, the constant will be visible even from root/main.
439 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(namespace, true);
440
441 // Get a clean constant table of Object even by writable one
442 // because ns was just created, so it has not touched any constants yet.
443 object_classext = RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
444 RCLASS_SET_CONST_TBL(namespace, RCLASSEXT_CONST_TBL(object_classext), true);
445
446 rb_ivar_set(namespace, id_namespace_entry, entry);
447
448 setup_pushing_loading_namespace(ns);
449
450 return namespace;
451}
452
453static VALUE
454rb_namespace_s_getenabled(VALUE namespace)
455{
456 return RBOOL(rb_namespace_available());
457}
458
459static VALUE
460rb_namespace_current(VALUE klass)
461{
462 const rb_namespace_t *ns = rb_current_namespace();
463 if (NAMESPACE_USER_P(ns)) {
464 return ns->ns_object;
465 }
466 if (NAMESPACE_BUILTIN_P(ns)) {
467 return Qnil;
468 }
469 return Qfalse;
470}
471
472static VALUE
473rb_namespace_s_is_builtin_p(VALUE namespace, VALUE klass)
474{
475 if (RCLASS_PRIME_CLASSEXT_READABLE_P(klass) && !RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass))
476 return Qtrue;
477 return Qfalse;
478}
479
480static VALUE
481rb_namespace_load_path(VALUE namespace)
482{
483 return rb_get_namespace_t(namespace)->load_path;
484}
485
486#ifdef _WIN32
487UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
488#endif
489
490/* Copied from mjit.c Ruby 3.0.3 */
491static char *
492system_default_tmpdir(void)
493{
494 // c.f. ext/etc/etc.c:etc_systmpdir()
495#ifdef _WIN32
496 WCHAR tmppath[_MAX_PATH];
497 UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
498 if (len) {
499 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
500 char *tmpdir = xmalloc(blen + 1);
501 WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
502 tmpdir[blen] = '\0';
503 return tmpdir;
504 }
505#elif defined _CS_DARWIN_USER_TEMP_DIR
506 char path[MAXPATHLEN];
507 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
508 if (len > 0) {
509 char *tmpdir = xmalloc(len);
510 if (len > sizeof(path)) {
511 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
512 }
513 else {
514 memcpy(tmpdir, path, len);
515 }
516 return tmpdir;
517 }
518#endif
519 return 0;
520}
521
522static int
523check_tmpdir(const char *dir)
524{
525 struct stat st;
526
527 if (!dir) return FALSE;
528 if (stat(dir, &st)) return FALSE;
529#ifndef S_ISDIR
530# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
531#endif
532 if (!S_ISDIR(st.st_mode)) return FALSE;
533#ifndef _WIN32
534# ifndef S_IWOTH
535# define S_IWOTH 002
536# endif
537 if (st.st_mode & S_IWOTH) {
538# ifdef S_ISVTX
539 if (!(st.st_mode & S_ISVTX)) return FALSE;
540# else
541 return FALSE;
542# endif
543 }
544 if (access(dir, W_OK)) return FALSE;
545#endif
546 return TRUE;
547}
548
549static char *
550system_tmpdir(void)
551{
552 char *tmpdir;
553# define RETURN_ENV(name) \
554 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
555 RETURN_ENV("TMPDIR");
556 RETURN_ENV("TMP");
557 tmpdir = system_default_tmpdir();
558 if (check_tmpdir(tmpdir)) return tmpdir;
559 return ruby_strdup("/tmp");
560# undef RETURN_ENV
561}
562
563/* end of copy */
564
565static int
566sprint_ext_filename(char *str, size_t size, long namespace_id, const char *prefix, const char *basename)
567{
568 if (tmp_dir_has_dirsep) {
569 return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), namespace_id, basename);
570 }
571 return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), namespace_id, basename);
572}
573
574#ifdef _WIN32
575static const char *
576copy_ext_file_error(char *message, size_t size)
577{
578 int error = GetLastError();
579 char *p = message;
580 size_t len = snprintf(message, size, "%d: ", error);
581
582#define format_message(sublang) FormatMessage(\
583 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
584 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
585 message + len, size - len, NULL)
586 if (format_message(SUBLANG_ENGLISH_US) == 0)
587 format_message(SUBLANG_DEFAULT);
588 for (p = message + len; *p; p++) {
589 if (*p == '\n' || *p == '\r')
590 *p = ' ';
591 }
592 return message;
593}
594#else
595static const char *
596copy_ext_file_error(char *message, size_t size, int copy_retvalue, char *src_path, char *dst_path)
597{
598 switch (copy_retvalue) {
599 case 1:
600 snprintf(message, size, "can't open the extension path: %s", src_path);
601 case 2:
602 snprintf(message, size, "can't open the file to write: %s", dst_path);
603 case 3:
604 snprintf(message, size, "failed to read the extension path: %s", src_path);
605 case 4:
606 snprintf(message, size, "failed to write the extension path: %s", dst_path);
607 default:
608 rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
609 }
610 return message;
611}
612#endif
613
614static int
615copy_ext_file(char *src_path, char *dst_path)
616{
617#if defined(_WIN32)
618 int rvalue;
619
620 WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
621 WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
622 if (!w_src || !w_dst) {
623 rb_memerror();
624 }
625
626 rvalue = CopyFileW(w_src, w_dst, FALSE) ? 0 : 1;
627 free(w_src);
628 free(w_dst);
629 return rvalue;
630#else
631 FILE *src, *dst;
632 char buffer[1024];
633 size_t read = 0, wrote, written = 0;
634 size_t maxread = sizeof(buffer);
635 int eof = 0;
636 int clean_read = 1;
637 int retvalue = 0;
638
639 src = fopen(src_path, "rb");
640 if (!src) {
641 return 1;
642 }
643 dst = fopen(dst_path, "wb");
644 if (!dst) {
645 return 2;
646 }
647 while (!eof) {
648 if (clean_read) {
649 read = fread(buffer, 1, sizeof(buffer), src);
650 written = 0;
651 }
652 if (read > 0) {
653 wrote = fwrite(buffer+written, 1, read-written, dst);
654 if (wrote < read-written) {
655 if (ferror(dst)) {
656 retvalue = 4;
657 break;
658 }
659 else { // partial write
660 clean_read = 0;
661 written += wrote;
662 }
663 }
664 else { // Wrote the entire buffer to dst, next read is clean one
665 clean_read = 1;
666 }
667 }
668 if (read < maxread) {
669 if (clean_read && feof(src)) {
670 // If it's not clean, buffer should have bytes not written yet.
671 eof = 1;
672 }
673 else if (ferror(src)) {
674 retvalue = 3;
675 // Writes could be partial/dirty, but this load is failure anyway
676 break;
677 }
678 }
679 }
680 fclose(src);
681 fclose(dst);
682 return retvalue;
683#endif
684}
685
686#if defined __CYGWIN__ || defined DOSISH
687#define isdirsep(x) ((x) == '/' || (x) == '\\')
688#else
689#define isdirsep(x) ((x) == '/')
690#endif
691
692#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
693#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
694
695static void
696fname_without_suffix(char *fname, char *rvalue)
697{
698 char *pos;
699 strcpy(rvalue, fname);
700 for (pos = rvalue + strlen(fname); pos > rvalue; pos--) {
701 if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
702 *pos = '\0';
703 return;
704 }
705 }
706}
707
708static void
709escaped_basename(char *path, char *fname, char *rvalue)
710{
711 char *pos, *leaf, *found;
712 leaf = path;
713 // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
714 while ((found = strstr(leaf + 1, fname)) != NULL) {
715 leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
716 }
717 strcpy(rvalue, leaf);
718 for (pos = rvalue; *pos; pos++) {
719 if (isdirsep(*pos)) {
720 *pos = '+';
721 }
722 }
723}
724
725VALUE
726rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path)
727{
728 char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
729 int copy_error, wrote;
730 char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
731 rb_namespace_t *ns = rb_get_namespace_t(namespace);
732
733 fname_without_suffix(fname_ptr, fname2);
734 escaped_basename(src_path, fname2, basename);
735
736 wrote = sprint_ext_filename(ext_path, sizeof(ext_path), ns->ns_id, NAMESPACE_TMP_PREFIX, basename);
737 if (wrote >= (int)sizeof(ext_path)) {
738 rb_bug("Extension file path in namespace was too long");
739 }
740 copy_error = copy_ext_file(src_path, ext_path);
741 if (copy_error) {
742 char message[1024];
743#if defined(_WIN32)
744 copy_ext_file_error(message, sizeof(message));
745#else
746 copy_ext_file_error(message, sizeof(message), copy_error, src_path, ext_path);
747#endif
748 rb_raise(rb_eLoadError, "can't prepare the extension file for namespaces (%s from %s): %s", ext_path, src_path, message);
749 }
750 // TODO: register the path to be clean-uped
751 return rb_str_new_cstr(ext_path);
752}
753
754// TODO: delete it just after dln_load? or delay it?
755// At least for _WIN32, deleting extension files should be delayed until the namespace's destructor.
756// And it requires calling dlclose before deleting it.
757
758static void
759namespace_push(rb_thread_t *th, VALUE namespace)
760{
761 if (RTEST(th->namespaces)) {
762 rb_ary_push(th->namespaces, namespace);
763 }
764 else {
765 th->namespaces = rb_ary_new_from_args(1, namespace);
766 }
767 th->ns = rb_get_namespace_t(namespace);
768}
769
770static VALUE
771namespace_pop(VALUE th_value)
772{
773 VALUE upper_ns;
774 long stack_len;
775 rb_thread_t *th = (rb_thread_t *)th_value;
776 VALUE namespaces = th->namespaces;
777 if (!namespaces) {
778 rb_bug("Too many namespace pops");
779 }
780 rb_ary_pop(namespaces);
781 stack_len = RARRAY_LEN(namespaces);
782 if (stack_len == 0) {
783 th->namespaces = 0;
784 th->ns = main_namespace;
785 }
786 else {
787 upper_ns = RARRAY_AREF(namespaces, stack_len-1);
788 th->ns = rb_get_namespace_t(upper_ns);
789 }
790 return Qnil;
791}
792
793VALUE
794rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg)
795{
796 rb_thread_t *th = GET_THREAD();
797 namespace_push(th, ns ? ns->ns_object : Qnil);
798 return rb_ensure(func, arg, namespace_pop, (VALUE)th);
799}
800
802 rb_thread_t *th;
803 rb_namespace_t *ns;
804};
805
806static VALUE
807namespace_both_pop(VALUE arg)
808{
809 struct namespace_pop2_arg *data = (struct namespace_pop2_arg *)arg;
810 namespace_pop((VALUE) data->th);
811 rb_namespace_pop_loading_namespace(data->ns);
812 return Qnil;
813}
814
815static VALUE
816rb_namespace_load(int argc, VALUE *argv, VALUE namespace)
817{
818 VALUE fname, wrap;
819 rb_thread_t *th = GET_THREAD();
820 rb_namespace_t *ns = rb_get_namespace_t(namespace);
821
822 rb_scan_args(argc, argv, "11", &fname, &wrap);
823
824 VALUE args = rb_ary_new_from_args(2, fname, wrap);
825 namespace_push(th, namespace);
826 rb_namespace_push_loading_namespace(ns);
827 struct namespace_pop2_arg arg = {
828 .th = th,
829 .ns = ns
830 };
831 return rb_ensure(rb_load_entrypoint, args, namespace_both_pop, (VALUE)&arg);
832}
833
834static VALUE
835rb_namespace_require(VALUE namespace, VALUE fname)
836{
837 rb_thread_t *th = GET_THREAD();
838 rb_namespace_t *ns = rb_get_namespace_t(namespace);
839 namespace_push(th, namespace);
840 rb_namespace_push_loading_namespace(ns);
841 struct namespace_pop2_arg arg = {
842 .th = th,
843 .ns = ns
844 };
845 return rb_ensure(rb_require_string, fname, namespace_both_pop, (VALUE)&arg);
846}
847
848static VALUE
849rb_namespace_require_relative(VALUE namespace, VALUE fname)
850{
851 rb_thread_t *th = GET_THREAD();
852 rb_namespace_t *ns = rb_get_namespace_t(namespace);
853 namespace_push(th, namespace);
854 rb_namespace_push_loading_namespace(ns);
855 struct namespace_pop2_arg arg = {
856 .th = th,
857 .ns = ns
858 };
859 return rb_ensure(rb_require_relative_entrypoint, fname, namespace_both_pop, (VALUE)&arg);
860}
861
862static VALUE
863rb_namespace_eval_string(VALUE str)
864{
865 return rb_eval_string(RSTRING_PTR(str));
866}
867
868static VALUE
869rb_namespace_eval(VALUE namespace, VALUE str)
870{
871 rb_thread_t *th = GET_THREAD();
872
873 StringValue(str);
874
875 namespace_push(th, namespace);
876 return rb_ensure(rb_namespace_eval_string, str, namespace_pop, (VALUE)th);
877}
878
879static int namespace_experimental_warned = 0;
880
881void
882rb_initialize_main_namespace(void)
883{
884 rb_namespace_t *ns;
885 rb_vm_t *vm = GET_VM();
886 rb_thread_t *th = GET_THREAD();
887 VALUE main_ns;
888
889 if (!namespace_experimental_warned) {
891 "Namespace is experimental, and the behavior may change in the future!\n"
892 "See doc/namespace.md for known issues, etc.");
893 namespace_experimental_warned = 1;
894 }
895
897 ns = rb_get_namespace_t(main_ns);
898 ns->ns_object = main_ns;
899 ns->ns_id = namespace_generate_id();
900 ns->is_builtin = false;
901 ns->is_user = true;
902 ns->is_optional = false;
903
904 rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
905
906 vm->main_namespace = th->ns = main_namespace = ns;
907}
908
909static VALUE
910rb_namespace_inspect(VALUE obj)
911{
912 rb_namespace_t *ns;
913 VALUE r;
914 if (obj == Qfalse) {
915 r = rb_str_new_cstr("#<Namespace:root>");
916 return r;
917 }
918 ns = rb_get_namespace_t(obj);
919 r = rb_str_new_cstr("#<Namespace:");
920 rb_str_concat(r, rb_funcall(LONG2NUM(ns->ns_id), rb_intern("to_s"), 0));
921 if (NAMESPACE_BUILTIN_P(ns)) {
922 rb_str_cat_cstr(r, ",builtin");
923 }
924 if (NAMESPACE_USER_P(ns)) {
925 rb_str_cat_cstr(r, ",user");
926 }
927 if (NAMESPACE_MAIN_P(ns)) {
928 rb_str_cat_cstr(r, ",main");
929 }
930 else if (NAMESPACE_OPTIONAL_P(ns)) {
931 rb_str_cat_cstr(r, ",optional");
932 }
933 rb_str_cat_cstr(r, ">");
934 return r;
935}
936
938 int argc;
939 VALUE *argv;
940};
941
942static VALUE
943namespace_builtin_refiner_calling_super(VALUE arg)
944{
945 struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
946 return rb_call_super(data->argc, data->argv);
947}
948
949static VALUE
950namespace_builtin_refiner_loading_func_ensure(VALUE _)
951{
952 rb_vm_t *vm = GET_VM();
953 if (!vm->require_stack)
954 rb_bug("require_stack is not ready but the namespace refiner is called");
955 rb_namespace_disable_builtin();
956 return Qnil;
957}
958
959static VALUE
960rb_namespace_builtin_refiner_loading_func(int argc, VALUE *argv, VALUE _self)
961{
962 rb_vm_t *vm = GET_VM();
963 if (!vm->require_stack)
964 rb_bug("require_stack is not ready but the namespace refiner is called");
965 rb_namespace_enable_builtin();
966 // const rb_namespace_t *ns = rb_loading_namespace();
967 // printf("N:current loading ns: %ld\n", ns->ns_id);
968 struct refiner_calling_super_data data = {
969 .argc = argc,
970 .argv = argv
971 };
972 return rb_ensure(namespace_builtin_refiner_calling_super, (VALUE)&data,
973 namespace_builtin_refiner_loading_func_ensure, Qnil);
974}
975
976static void
977setup_builtin_refinement(VALUE mod)
978{
979 struct rb_refinements_data data;
980 rb_refinement_setup(&data, mod, rb_mKernel);
981 rb_define_method(data.refinement, "require", rb_namespace_builtin_refiner_loading_func, -1);
982 rb_define_method(data.refinement, "require_relative", rb_namespace_builtin_refiner_loading_func, -1);
983 rb_define_method(data.refinement, "load", rb_namespace_builtin_refiner_loading_func, -1);
984}
985
986static VALUE
987namespace_user_loading_func_calling_super(VALUE arg)
988{
989 struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
990 return rb_call_super(data->argc, data->argv);
991}
992
993static VALUE
994namespace_user_loading_func_ensure(VALUE arg)
995{
996 rb_namespace_t *ns = (rb_namespace_t *)arg;
997 rb_namespace_pop_loading_namespace(ns);
998 return Qnil;
999}
1000
1001static VALUE
1002rb_namespace_user_loading_func(int argc, VALUE *argv, VALUE _self)
1003{
1004 const rb_namespace_t *ns;
1005 rb_vm_t *vm = GET_VM();
1006 if (!vm->require_stack)
1007 rb_bug("require_stack is not ready but require/load is called in user namespaces");
1008 ns = rb_current_namespace();
1009 VM_ASSERT(rb_namespace_available() || !ns);
1010 rb_namespace_push_loading_namespace(ns);
1011 struct refiner_calling_super_data data = {
1012 .argc = argc,
1013 .argv = argv
1014 };
1015 return rb_ensure(namespace_user_loading_func_calling_super, (VALUE)&data,
1016 namespace_user_loading_func_ensure, (VALUE)ns);
1017}
1018
1019static VALUE
1020setup_pushing_loading_namespace_include(VALUE mod)
1021{
1022 rb_include_module(rb_cObject, mod);
1023 return Qnil;
1024}
1025
1026static void
1027setup_pushing_loading_namespace(rb_namespace_t *ns)
1028{
1029 rb_namespace_exec(ns, setup_pushing_loading_namespace_include, rb_mNamespaceLoader);
1030}
1031
1032static void
1033namespace_define_loader_method(const char *name)
1034{
1035 rb_define_private_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
1036 rb_define_singleton_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
1037}
1038
1039void
1040Init_enable_namespace(void)
1041{
1042 const char *env = getenv("RUBY_NAMESPACE");
1043 if (env && strlen(env) == 1 && env[0] == '1') {
1044 ruby_namespace_enabled = true;
1045 }
1046 else {
1047 ruby_namespace_init_done = true;
1048 }
1049}
1050
1051void
1052Init_Namespace(void)
1053{
1054 tmp_dir = system_tmpdir();
1055 tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
1056
1058 rb_define_method(rb_cNamespace, "initialize", namespace_initialize, 0);
1059
1060 rb_cNamespaceEntry = rb_define_class_under(rb_cNamespace, "Entry", rb_cObject);
1061 rb_define_alloc_func(rb_cNamespaceEntry, rb_namespace_entry_alloc);
1062
1064 if (rb_namespace_available()) {
1065 setup_builtin_refinement(rb_mNamespaceRefiner);
1066 }
1067
1068 rb_mNamespaceLoader = rb_define_module_under(rb_cNamespace, "Loader");
1069 namespace_define_loader_method("require");
1070 namespace_define_loader_method("require_relative");
1071 namespace_define_loader_method("load");
1072
1073 rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0);
1074 rb_define_singleton_method(rb_cNamespace, "current", rb_namespace_current, 0);
1075 rb_define_singleton_method(rb_cNamespace, "is_builtin?", rb_namespace_s_is_builtin_p, 1);
1076
1077 rb_define_method(rb_cNamespace, "load_path", rb_namespace_load_path, 0);
1078 rb_define_method(rb_cNamespace, "load", rb_namespace_load, -1);
1079 rb_define_method(rb_cNamespace, "require", rb_namespace_require, 1);
1080 rb_define_method(rb_cNamespace, "require_relative", rb_namespace_require_relative, 1);
1081 rb_define_method(rb_cNamespace, "eval", rb_namespace_eval, 1);
1082
1083 rb_define_method(rb_cNamespace, "inspect", rb_namespace_inspect, 0);
1084
1085 rb_vm_t *vm = GET_VM();
1086 vm->require_stack = rb_ary_new();
1087}
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Ruby-level global variables / constants, visible from C.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1701
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1484
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1520
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1630
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3138
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
VALUE rb_eLoadError
LoadError exception.
Definition error.c:1448
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
Definition error.h:51
VALUE rb_mKernel
Kernel module.
Definition object.c:61
VALUE rb_cNamespace
Namespace class.
Definition namespace.c:20
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
Definition object.c:2143
VALUE rb_cModule
Module class.
Definition object.c:63
VALUE rb_mNamespaceRefiner
Namespace::Refiner module.
Definition namespace.c:22
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_eval_string(const char *str)
Evaluates the given string.
Definition vm_eval.c:2083
VALUE rb_call_super(int argc, const VALUE *argv)
This resembles ruby's super.
Definition vm_eval.c:362
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1549
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4004
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1656
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2079
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:4042
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
int len
Length of the buffer.
Definition io.h:8
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition util.c:515
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
Definition pid_t.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition method.h:63
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:203
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:136
Internal header for Namespace.
Definition namespace.h:14
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376