Ruby 3.5.0dev (2025-10-06 revision 704677257ecb01c7ee10aa0dfc55ca1d4fc4636d)
namespace.c (704677257ecb01c7ee10aa0dfc55ca1d4fc4636d)
1/* indent-tabs-mode: nil */
2
3#include "eval_intern.h"
4#include "internal.h"
5#include "internal/class.h"
6#include "internal/eval.h"
7#include "internal/error.h"
8#include "internal/file.h"
9#include "internal/gc.h"
10#include "internal/hash.h"
11#include "internal/load.h"
12#include "internal/namespace.h"
13#include "internal/st.h"
14#include "internal/variable.h"
15#include "iseq.h"
17#include "ruby/util.h"
18#include "vm_core.h"
19
20#include <stdio.h>
21
23VALUE rb_cNamespaceEntry = 0;
24VALUE rb_mNamespaceLoader = 0;
25
26static rb_namespace_t root_namespace_data = {
27 /* Initialize values lazily in Init_namespace() */
28 (VALUE)NULL, 0,
29 (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL,
30 (struct st_table *)NULL, (struct st_table *)NULL, (VALUE)NULL, (VALUE)NULL,
31 false, false
32};
33
34static rb_namespace_t * root_namespace = &root_namespace_data;
35static rb_namespace_t * main_namespace = 0;
36static char *tmp_dir;
37static bool tmp_dir_has_dirsep;
38
39#define NAMESPACE_TMP_PREFIX "_ruby_ns_"
40
41#ifndef MAXPATHLEN
42# define MAXPATHLEN 1024
43#endif
44
45#if defined(_WIN32)
46# define DIRSEP "\\"
47#else
48# define DIRSEP "/"
49#endif
50
51bool ruby_namespace_enabled = false; // extern
52bool ruby_namespace_init_done = false; // extern
53
54VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
55static VALUE rb_namespace_inspect(VALUE obj);
56
57void
58rb_namespace_init_done(void)
59{
60 ruby_namespace_init_done = true;
61}
62
63const rb_namespace_t *
64rb_root_namespace(void)
65{
66 return root_namespace;
67}
68
69const rb_namespace_t *
70rb_main_namespace(void)
71{
72 return main_namespace;
73}
74
75const rb_namespace_t *
76rb_current_namespace(void)
77{
78 /*
79 * If RUBY_NAMESPACE is not set, the root namespace is the only available one.
80 *
81 * Until the main_namespace is not initialized, the root namespace is
82 * the only valid namespace.
83 * This early return is to avoid accessing EC before its setup.
84 */
85 if (!main_namespace)
86 return root_namespace;
87
88 return rb_vm_current_namespace(GET_EC());
89}
90
91const rb_namespace_t *
92rb_loading_namespace(void)
93{
94 if (!main_namespace)
95 return root_namespace;
96
97 return rb_vm_loading_namespace(GET_EC());
98}
99
100static long namespace_id_counter = 0;
101
102static long
103namespace_generate_id(void)
104{
105 long id;
106 RB_VM_LOCKING() {
107 id = ++namespace_id_counter;
108 }
109 return id;
110}
111
112static void
113namespace_entry_initialize(rb_namespace_t *ns)
114{
115 const rb_namespace_t *root = rb_root_namespace();
116
117 // These will be updated immediately
118 ns->ns_object = 0;
119 ns->ns_id = 0;
120
121 ns->top_self = rb_obj_alloc(rb_cObject);
122 // TODO:
123 // rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
124 // rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");
125 ns->load_path = rb_ary_dup(root->load_path);
126 ns->expanded_load_path = rb_ary_dup(root->expanded_load_path);
127 ns->load_path_snapshot = rb_ary_new();
128 ns->load_path_check_cache = 0;
129 ns->loaded_features = rb_ary_dup(root->loaded_features);
130 ns->loaded_features_snapshot = rb_ary_new();
131 ns->loaded_features_index = st_init_numtable();
132 ns->loaded_features_realpaths = rb_hash_dup(root->loaded_features_realpaths);
133 ns->loaded_features_realpath_map = rb_hash_dup(root->loaded_features_realpath_map);
134 ns->loading_table = st_init_strtable();
135 ns->ruby_dln_libmap = rb_hash_new_with_size(0);
136 ns->gvar_tbl = rb_hash_new_with_size(0);
137
138 ns->is_user = true;
139 ns->is_optional = true;
140}
141
142void
143rb_namespace_gc_update_references(void *ptr)
144{
145 rb_namespace_t *ns = (rb_namespace_t *)ptr;
146 if (!ns) return;
147
148 if (ns->ns_object)
149 ns->ns_object = rb_gc_location(ns->ns_object);
150 if (ns->top_self)
151 ns->top_self = rb_gc_location(ns->top_self);
152 ns->load_path = rb_gc_location(ns->load_path);
153 ns->expanded_load_path = rb_gc_location(ns->expanded_load_path);
154 ns->load_path_snapshot = rb_gc_location(ns->load_path_snapshot);
155 if (ns->load_path_check_cache) {
156 ns->load_path_check_cache = rb_gc_location(ns->load_path_check_cache);
157 }
158 ns->loaded_features = rb_gc_location(ns->loaded_features);
159 ns->loaded_features_snapshot = rb_gc_location(ns->loaded_features_snapshot);
160 ns->loaded_features_realpaths = rb_gc_location(ns->loaded_features_realpaths);
161 ns->loaded_features_realpath_map = rb_gc_location(ns->loaded_features_realpath_map);
162 ns->ruby_dln_libmap = rb_gc_location(ns->ruby_dln_libmap);
163 ns->gvar_tbl = rb_gc_location(ns->gvar_tbl);
164}
165
166void
167rb_namespace_entry_mark(void *ptr)
168{
169 const rb_namespace_t *ns = (rb_namespace_t *)ptr;
170 if (!ns) return;
171
172 rb_gc_mark(ns->ns_object);
173 rb_gc_mark(ns->top_self);
174 rb_gc_mark(ns->load_path);
175 rb_gc_mark(ns->expanded_load_path);
176 rb_gc_mark(ns->load_path_snapshot);
177 rb_gc_mark(ns->load_path_check_cache);
178 rb_gc_mark(ns->loaded_features);
179 rb_gc_mark(ns->loaded_features_snapshot);
180 rb_gc_mark(ns->loaded_features_realpaths);
181 rb_gc_mark(ns->loaded_features_realpath_map);
182 if (ns->loading_table) {
183 rb_mark_tbl(ns->loading_table);
184 }
185 rb_gc_mark(ns->ruby_dln_libmap);
186 rb_gc_mark(ns->gvar_tbl);
187}
188
189static int
190free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
191{
192 xfree((char *)key);
193 return ST_DELETE;
194}
195
196static void
197namespace_entry_free(void *ptr)
198{
199 rb_namespace_t *ns = (rb_namespace_t *)ptr;
200 if (ns->loading_table) {
201 st_foreach(ns->loading_table, free_loading_table_entry, 0);
202 st_free_table(ns->loading_table);
203 ns->loading_table = 0;
204 }
205}
206
207static size_t
208namespace_entry_memsize(const void *ptr)
209{
210 const rb_namespace_t *ns = (const rb_namespace_t *)ptr;
211 return sizeof(rb_namespace_t) + \
212 rb_st_memsize(ns->loaded_features_index) + \
213 rb_st_memsize(ns->loading_table);
214}
215
216const rb_data_type_t rb_namespace_data_type = {
217 "Namespace::Entry",
218 {
219 rb_namespace_entry_mark,
220 namespace_entry_free,
221 namespace_entry_memsize,
222 rb_namespace_gc_update_references,
223 },
224 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
225};
226
227VALUE
228rb_namespace_entry_alloc(VALUE klass)
229{
230 rb_namespace_t *entry;
231 VALUE obj = TypedData_Make_Struct(klass, rb_namespace_t, &rb_namespace_data_type, entry);
232 namespace_entry_initialize(entry);
233 return obj;
234}
235
236static rb_namespace_t *
237get_namespace_struct_internal(VALUE entry)
238{
239 rb_namespace_t *sval;
240 TypedData_Get_Struct(entry, rb_namespace_t, &rb_namespace_data_type, sval);
241 return sval;
242}
243
245rb_get_namespace_t(VALUE namespace)
246{
247 VALUE entry;
248 ID id_namespace_entry;
249
250 VM_ASSERT(namespace);
251
252 if (NIL_P(namespace))
253 return root_namespace;
254
255 VM_ASSERT(NAMESPACE_OBJ_P(namespace));
256
257 CONST_ID(id_namespace_entry, "__namespace_entry__");
258 entry = rb_attr_get(namespace, id_namespace_entry);
259 return get_namespace_struct_internal(entry);
260}
261
262VALUE
263rb_get_namespace_object(rb_namespace_t *ns)
264{
265 VM_ASSERT(ns && ns->ns_object);
266 return ns->ns_object;
267}
268
269/*
270 * call-seq:
271 * Namespace.new -> new_namespace
272 *
273 * Returns a new Namespace object.
274 */
275static VALUE
276namespace_initialize(VALUE namespace)
277{
278 rb_namespace_t *ns;
279 rb_classext_t *object_classext;
280 VALUE entry;
281 ID id_namespace_entry;
282 CONST_ID(id_namespace_entry, "__namespace_entry__");
283
284 if (!rb_namespace_available()) {
285 rb_raise(rb_eRuntimeError, "Namespace is disabled. Set RUBY_NAMESPACE=1 environment variable to use Namespace.");
286 }
287
288 entry = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespaceEntry);
289 ns = get_namespace_struct_internal(entry);
290
291 ns->ns_object = namespace;
292 ns->ns_id = namespace_generate_id();
293 rb_define_singleton_method(ns->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
294
295 // Set the Namespace object unique/consistent from any namespaces to have just single
296 // constant table from any view of every (including main) namespace.
297 // If a code in the namespace adds a constant, the constant will be visible even from root/main.
298 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(namespace, true);
299
300 // Get a clean constant table of Object even by writable one
301 // because ns was just created, so it has not touched any constants yet.
302 object_classext = RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
303 RCLASS_SET_CONST_TBL(namespace, RCLASSEXT_CONST_TBL(object_classext), true);
304
305 rb_ivar_set(namespace, id_namespace_entry, entry);
306
307 return namespace;
308}
309
310/*
311 * call-seq:
312 * Namespace.enabled? -> true or false
313 *
314 * Returns +true+ if namespace is enabled.
315 */
316static VALUE
317rb_namespace_s_getenabled(VALUE recv)
318{
319 return RBOOL(rb_namespace_available());
320}
321
322/*
323 * call-seq:
324 * Namespace.current -> namespace, nil or false
325 *
326 * Returns the current namespace.
327 * Returns +nil+ if it is the built-in namespace.
328 * Returns +false+ if namespace is not enabled.
329 */
330static VALUE
331rb_namespace_s_current(VALUE recv)
332{
333 const rb_namespace_t *ns;
334
335 if (!rb_namespace_available())
336 return Qnil;
337
338 ns = rb_vm_current_namespace(GET_EC());
339 VM_ASSERT(ns && ns->ns_object);
340 return ns->ns_object;
341}
342
343/*
344 * call-seq:
345 * Namespace.is_builtin?(klass) -> true or false
346 *
347 * Returns +true+ if +klass+ is only in a user namespace.
348 */
349static VALUE
350rb_namespace_s_is_builtin_p(VALUE recv, VALUE klass)
351{
352 if (RCLASS_PRIME_CLASSEXT_READABLE_P(klass) && !RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass))
353 return Qtrue;
354 return Qfalse;
355}
356
357/*
358 * call-seq:
359 * load_path -> array
360 *
361 * Returns namespace local load path.
362 */
363static VALUE
364rb_namespace_load_path(VALUE namespace)
365{
366 VM_ASSERT(NAMESPACE_OBJ_P(namespace));
367 return rb_get_namespace_t(namespace)->load_path;
368}
369
370#ifdef _WIN32
371UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
372#endif
373
374/* Copied from mjit.c Ruby 3.0.3 */
375static char *
376system_default_tmpdir(void)
377{
378 // c.f. ext/etc/etc.c:etc_systmpdir()
379#ifdef _WIN32
380 WCHAR tmppath[_MAX_PATH];
381 UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
382 if (len) {
383 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
384 char *tmpdir = xmalloc(blen + 1);
385 WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
386 tmpdir[blen] = '\0';
387 return tmpdir;
388 }
389#elif defined _CS_DARWIN_USER_TEMP_DIR
390 char path[MAXPATHLEN];
391 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
392 if (len > 0) {
393 char *tmpdir = xmalloc(len);
394 if (len > sizeof(path)) {
395 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
396 }
397 else {
398 memcpy(tmpdir, path, len);
399 }
400 return tmpdir;
401 }
402#endif
403 return 0;
404}
405
406static int
407check_tmpdir(const char *dir)
408{
409 struct stat st;
410
411 if (!dir) return FALSE;
412 if (stat(dir, &st)) return FALSE;
413#ifndef S_ISDIR
414# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
415#endif
416 if (!S_ISDIR(st.st_mode)) return FALSE;
417#ifndef _WIN32
418# ifndef S_IWOTH
419# define S_IWOTH 002
420# endif
421 if (st.st_mode & S_IWOTH) {
422# ifdef S_ISVTX
423 if (!(st.st_mode & S_ISVTX)) return FALSE;
424# else
425 return FALSE;
426# endif
427 }
428 if (access(dir, W_OK)) return FALSE;
429#endif
430 return TRUE;
431}
432
433static char *
434system_tmpdir(void)
435{
436 char *tmpdir;
437# define RETURN_ENV(name) \
438 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
439 RETURN_ENV("TMPDIR");
440 RETURN_ENV("TMP");
441 tmpdir = system_default_tmpdir();
442 if (check_tmpdir(tmpdir)) return tmpdir;
443 return ruby_strdup("/tmp");
444# undef RETURN_ENV
445}
446
447/* end of copy */
448
449static int
450sprint_ext_filename(char *str, size_t size, long namespace_id, const char *prefix, const char *basename)
451{
452 if (tmp_dir_has_dirsep) {
453 return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), namespace_id, basename);
454 }
455 return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), namespace_id, basename);
456}
457
458#ifdef _WIN32
459static const char *
460copy_ext_file_error(char *message, size_t size)
461{
462 int error = GetLastError();
463 char *p = message;
464 size_t len = snprintf(message, size, "%d: ", error);
465
466#define format_message(sublang) FormatMessage(\
467 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
468 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
469 message + len, size - len, NULL)
470 if (format_message(SUBLANG_ENGLISH_US) == 0)
471 format_message(SUBLANG_DEFAULT);
472 for (p = message + len; *p; p++) {
473 if (*p == '\n' || *p == '\r')
474 *p = ' ';
475 }
476 return message;
477}
478#else
479static const char *
480copy_ext_file_error(char *message, size_t size, int copy_retvalue, char *src_path, char *dst_path)
481{
482 switch (copy_retvalue) {
483 case 1:
484 snprintf(message, size, "can't open the extension path: %s", src_path);
485 case 2:
486 snprintf(message, size, "can't open the file to write: %s", dst_path);
487 case 3:
488 snprintf(message, size, "failed to read the extension path: %s", src_path);
489 case 4:
490 snprintf(message, size, "failed to write the extension path: %s", dst_path);
491 default:
492 rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
493 }
494 return message;
495}
496#endif
497
498static int
499copy_ext_file(char *src_path, char *dst_path)
500{
501#if defined(_WIN32)
502 int rvalue;
503
504 WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
505 WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
506 if (!w_src || !w_dst) {
507 rb_memerror();
508 }
509
510 rvalue = CopyFileW(w_src, w_dst, FALSE) ? 0 : 1;
511 free(w_src);
512 free(w_dst);
513 return rvalue;
514#else
515 FILE *src, *dst;
516 char buffer[1024];
517 size_t read = 0, wrote, written = 0;
518 size_t maxread = sizeof(buffer);
519 int eof = 0;
520 int clean_read = 1;
521 int retvalue = 0;
522
523 src = fopen(src_path, "rb");
524 if (!src) {
525 return 1;
526 }
527 dst = fopen(dst_path, "wb");
528 if (!dst) {
529 return 2;
530 }
531 while (!eof) {
532 if (clean_read) {
533 read = fread(buffer, 1, sizeof(buffer), src);
534 written = 0;
535 }
536 if (read > 0) {
537 wrote = fwrite(buffer+written, 1, read-written, dst);
538 if (wrote < read-written) {
539 if (ferror(dst)) {
540 retvalue = 4;
541 break;
542 }
543 else { // partial write
544 clean_read = 0;
545 written += wrote;
546 }
547 }
548 else { // Wrote the entire buffer to dst, next read is clean one
549 clean_read = 1;
550 }
551 }
552 if (read < maxread) {
553 if (clean_read && feof(src)) {
554 // If it's not clean, buffer should have bytes not written yet.
555 eof = 1;
556 }
557 else if (ferror(src)) {
558 retvalue = 3;
559 // Writes could be partial/dirty, but this load is failure anyway
560 break;
561 }
562 }
563 }
564 fclose(src);
565 fclose(dst);
566 return retvalue;
567#endif
568}
569
570#if defined __CYGWIN__ || defined DOSISH
571#define isdirsep(x) ((x) == '/' || (x) == '\\')
572#else
573#define isdirsep(x) ((x) == '/')
574#endif
575
576#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
577#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
578
579static void
580fname_without_suffix(const char *fname, char *rvalue, size_t rsize)
581{
582 size_t len = strlen(fname);
583 const char *pos;
584 for (pos = fname + len; pos > fname; pos--) {
585 if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
586 len = pos - fname;
587 break;
588 }
589 if (fname + len - pos > DLEXT_MAXLEN) break;
590 }
591 if (len > rsize - 1) len = rsize - 1;
592 memcpy(rvalue, fname, len);
593 rvalue[len] = '\0';
594}
595
596static void
597escaped_basename(const char *path, const char *fname, char *rvalue, size_t rsize)
598{
599 char *pos;
600 const char *leaf = path, *found;
601 // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
602 while ((found = strstr(leaf + 1, fname)) != NULL) {
603 leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
604 }
605 strlcpy(rvalue, leaf, rsize);
606 for (pos = rvalue; *pos; pos++) {
607 if (isdirsep(*pos)) {
608 *pos = '+';
609 }
610 }
611}
612
613VALUE
614rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path)
615{
616 char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
617 int copy_error, wrote;
618 char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
619 rb_namespace_t *ns = rb_get_namespace_t(namespace);
620
621 fname_without_suffix(fname_ptr, fname2, sizeof(fname2));
622 escaped_basename(src_path, fname2, basename, sizeof(basename));
623
624 wrote = sprint_ext_filename(ext_path, sizeof(ext_path), ns->ns_id, NAMESPACE_TMP_PREFIX, basename);
625 if (wrote >= (int)sizeof(ext_path)) {
626 rb_bug("Extension file path in namespace was too long");
627 }
628 copy_error = copy_ext_file(src_path, ext_path);
629 if (copy_error) {
630 char message[1024];
631#if defined(_WIN32)
632 copy_ext_file_error(message, sizeof(message));
633#else
634 copy_ext_file_error(message, sizeof(message), copy_error, src_path, ext_path);
635#endif
636 rb_raise(rb_eLoadError, "can't prepare the extension file for namespaces (%s from %s): %s", ext_path, src_path, message);
637 }
638 // TODO: register the path to be clean-uped
639 return rb_str_new_cstr(ext_path);
640}
641
642// TODO: delete it just after dln_load? or delay it?
643// At least for _WIN32, deleting extension files should be delayed until the namespace's destructor.
644// And it requires calling dlclose before deleting it.
645
646static VALUE
647rb_namespace_load(int argc, VALUE *argv, VALUE namespace)
648{
649 VALUE fname, wrap;
650 rb_scan_args(argc, argv, "11", &fname, &wrap);
651
652 rb_vm_frame_flag_set_ns_require(GET_EC());
653
654 VALUE args = rb_ary_new_from_args(2, fname, wrap);
655 return rb_load_entrypoint(args);
656}
657
658static VALUE
659rb_namespace_require(VALUE namespace, VALUE fname)
660{
661 rb_vm_frame_flag_set_ns_require(GET_EC());
662
663 return rb_require_string(fname);
664}
665
666static VALUE
667rb_namespace_require_relative(VALUE namespace, VALUE fname)
668{
669 rb_vm_frame_flag_set_ns_require(GET_EC());
670
671 return rb_require_relative_entrypoint(fname);
672}
673
674static void
675initialize_root_namespace(void)
676{
677 VALUE root_namespace, entry;
678 ID id_namespace_entry;
679 rb_vm_t *vm = GET_VM();
680 rb_namespace_t *root = (rb_namespace_t *)rb_root_namespace();
681
682 root->load_path = rb_ary_new();
683 root->expanded_load_path = rb_ary_hidden_new(0);
684 root->load_path_snapshot = rb_ary_hidden_new(0);
685 root->load_path_check_cache = 0;
686 rb_define_singleton_method(root->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
687
688 root->loaded_features = rb_ary_new();
689 root->loaded_features_snapshot = rb_ary_hidden_new(0);
690 root->loaded_features_index = st_init_numtable();
691 root->loaded_features_realpaths = rb_hash_new();
692 rb_obj_hide(root->loaded_features_realpaths);
693 root->loaded_features_realpath_map = rb_hash_new();
694 rb_obj_hide(root->loaded_features_realpath_map);
695
696 root->ruby_dln_libmap = rb_hash_new_with_size(0);
697 root->gvar_tbl = rb_hash_new_with_size(0);
698
699 vm->root_namespace = root;
700
701 if (rb_namespace_available()) {
702 CONST_ID(id_namespace_entry, "__namespace_entry__");
703
704 root_namespace = rb_obj_alloc(rb_cNamespace);
705 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(root_namespace, true);
706 RCLASS_SET_CONST_TBL(root_namespace, RCLASSEXT_CONST_TBL(RCLASS_EXT_PRIME(rb_cObject)), true);
707
708 root->ns_id = namespace_generate_id();
709 root->ns_object = root_namespace;
710
711 entry = TypedData_Wrap_Struct(rb_cNamespaceEntry, &rb_namespace_data_type, root);
712 rb_ivar_set(root_namespace, id_namespace_entry, entry);
713 }
714 else {
715 root->ns_id = 1;
716 root->ns_object = Qnil;
717 }
718}
719
720static VALUE
721rb_namespace_eval(VALUE namespace, VALUE str)
722{
723 const rb_iseq_t *iseq;
724 const rb_namespace_t *ns;
725
726 StringValue(str);
727
728 iseq = rb_iseq_compile_iseq(str, rb_str_new_cstr("eval"));
729 VM_ASSERT(iseq);
730
731 ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
732
733 return rb_iseq_eval(iseq, ns);
734}
735
736static int namespace_experimental_warned = 0;
737
738void
739rb_initialize_main_namespace(void)
740{
741 rb_namespace_t *ns;
742 VALUE main_ns;
743 rb_vm_t *vm = GET_VM();
744
745 VM_ASSERT(rb_namespace_available());
746
747 if (!namespace_experimental_warned) {
749 "Namespace is experimental, and the behavior may change in the future!\n"
750 "See doc/namespace.md for known issues, etc.");
751 namespace_experimental_warned = 1;
752 }
753
754 main_ns = rb_class_new_instance(0, NULL, rb_cNamespace);
755 VM_ASSERT(NAMESPACE_OBJ_P(main_ns));
756 ns = rb_get_namespace_t(main_ns);
757 ns->ns_object = main_ns;
758 ns->ns_id = namespace_generate_id();
759 ns->is_user = true;
760 ns->is_optional = false;
761
762 rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
763
764 vm->main_namespace = main_namespace = ns;
765}
766
767static VALUE
768rb_namespace_inspect(VALUE obj)
769{
770 rb_namespace_t *ns;
771 VALUE r;
772 if (obj == Qfalse) {
773 r = rb_str_new_cstr("#<Namespace:root>");
774 return r;
775 }
776 ns = rb_get_namespace_t(obj);
777 r = rb_str_new_cstr("#<Namespace:");
778 rb_str_concat(r, rb_funcall(LONG2NUM(ns->ns_id), rb_intern("to_s"), 0));
779 if (NAMESPACE_ROOT_P(ns)) {
780 rb_str_cat_cstr(r, ",root");
781 }
782 if (NAMESPACE_USER_P(ns)) {
783 rb_str_cat_cstr(r, ",user");
784 }
785 if (NAMESPACE_MAIN_P(ns)) {
786 rb_str_cat_cstr(r, ",main");
787 }
788 else if (NAMESPACE_OPTIONAL_P(ns)) {
789 rb_str_cat_cstr(r, ",optional");
790 }
791 rb_str_cat_cstr(r, ">");
792 return r;
793}
794
795static VALUE
796rb_namespace_loading_func(int argc, VALUE *argv, VALUE _self)
797{
798 rb_vm_frame_flag_set_ns_require(GET_EC());
799 return rb_call_super(argc, argv);
800}
801
802static void
803namespace_define_loader_method(const char *name)
804{
805 rb_define_private_method(rb_mNamespaceLoader, name, rb_namespace_loading_func, -1);
806 rb_define_singleton_method(rb_mNamespaceLoader, name, rb_namespace_loading_func, -1);
807}
808
809void
810Init_root_namespace(void)
811{
812 root_namespace->loading_table = st_init_strtable();
813}
814
815void
816Init_enable_namespace(void)
817{
818 const char *env = getenv("RUBY_NAMESPACE");
819 if (env && strlen(env) == 1 && env[0] == '1') {
820 ruby_namespace_enabled = true;
821 }
822 else {
823 ruby_namespace_init_done = true;
824 }
825}
826
827#ifdef RUBY_DEBUG
828
829/* :nodoc: */
830static VALUE
831rb_namespace_s_root(VALUE recv)
832{
833 return root_namespace->ns_object;
834}
835
836/* :nodoc: */
837static VALUE
838rb_namespace_s_main(VALUE recv)
839{
840 return main_namespace->ns_object;
841}
842
843static const char *
844classname(VALUE klass)
845{
846 VALUE p = RCLASS_CLASSPATH(klass);
847 if (RTEST(p))
848 return RSTRING_PTR(p);
849 if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS))
850 return RSTRING_PTR(rb_inspect(klass));
851 return "NonClassValue";
852}
853
854static enum rb_id_table_iterator_result
855dump_classext_methods_i(ID mid, VALUE _val, void *data)
856{
857 VALUE ary = (VALUE)data;
858 rb_ary_push(ary, rb_id2str(mid));
859 return ID_TABLE_CONTINUE;
860}
861
862static enum rb_id_table_iterator_result
863dump_classext_constants_i(ID mid, VALUE _val, void *data)
864{
865 VALUE ary = (VALUE)data;
866 rb_ary_push(ary, rb_id2str(mid));
867 return ID_TABLE_CONTINUE;
868}
869
870static void
871dump_classext_i(rb_classext_t *ext, bool is_prime, VALUE _ns, void *data)
872{
873 char buf[4096];
874 struct rb_id_table *tbl;
875 VALUE ary, res = (VALUE)data;
876
877 snprintf(buf, 4096, "Namespace %ld:%s classext %p\n",
878 RCLASSEXT_NS(ext)->ns_id, is_prime ? " prime" : "", (void *)ext);
879 rb_str_cat_cstr(res, buf);
880
881 snprintf(buf, 2048, " Super: %s\n", classname(RCLASSEXT_SUPER(ext)));
882 rb_str_cat_cstr(res, buf);
883
884 tbl = RCLASSEXT_M_TBL(ext);
885 if (tbl) {
886 ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
887 rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (void *)ary);
888 rb_ary_sort_bang(ary);
889 snprintf(buf, 4096, " Methods(%ld): ", RARRAY_LEN(ary));
890 rb_str_cat_cstr(res, buf);
892 rb_str_cat_cstr(res, "\n");
893 }
894 else {
895 rb_str_cat_cstr(res, " Methods(0): .\n");
896 }
897
898 tbl = RCLASSEXT_CONST_TBL(ext);
899 if (tbl) {
900 ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
901 rb_id_table_foreach(tbl, dump_classext_constants_i, (void *)ary);
902 rb_ary_sort_bang(ary);
903 snprintf(buf, 4096, " Constants(%ld): ", RARRAY_LEN(ary));
904 rb_str_cat_cstr(res, buf);
906 rb_str_cat_cstr(res, "\n");
907 }
908 else {
909 rb_str_cat_cstr(res, " Constants(0): .\n");
910 }
911}
912
913/* :nodoc: */
914static VALUE
915rb_f_dump_classext(VALUE recv, VALUE klass)
916{
917 /*
918 * The desired output String value is:
919 * Class: 0x88800932 (String) [singleton]
920 * Prime classext namespace(2,main), readable(t), writable(f)
921 * Non-prime classexts: 3
922 * Namespace 2: prime classext 0x88800933
923 * Super: Object
924 * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
925 * Constants(12): FOO, Bar, ...
926 * Namespace 5: classext 0x88800934
927 * Super: Object
928 * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
929 * Constants(12): FOO, Bar, ...
930 */
931 char buf[2048];
932 VALUE res;
933 const rb_classext_t *ext;
934 const rb_namespace_t *ns;
935 st_table *classext_tbl;
936
937 if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE))) {
938 snprintf(buf, 2048, "Non-class/module value: %p (%s)\n", (void *)klass, rb_type_str(BUILTIN_TYPE(klass)));
939 return rb_str_new_cstr(buf);
940 }
941
942 if (RB_TYPE_P(klass, T_CLASS)) {
943 snprintf(buf, 2048, "Class: %p (%s)%s\n",
944 (void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ? " [singleton]" : "");
945 }
946 else {
947 snprintf(buf, 2048, "Module: %p (%s)\n", (void *)klass, classname(klass));
948 }
949 res = rb_str_new_cstr(buf);
950
951 ext = RCLASS_EXT_PRIME(klass);
952 ns = RCLASSEXT_NS(ext);
953 snprintf(buf, 2048, "Prime classext namespace(%ld,%s), readable(%s), writable(%s)\n",
954 ns->ns_id,
955 NAMESPACE_ROOT_P(ns) ? "root" : (NAMESPACE_MAIN_P(ns) ? "main" : "optional"),
956 RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ? "t" : "f",
957 RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ? "t" : "f");
958 rb_str_cat_cstr(res, buf);
959
960 classext_tbl = RCLASS_CLASSEXT_TBL(klass);
961 if (!classext_tbl) {
962 rb_str_cat_cstr(res, "Non-prime classexts: 0\n");
963 }
964 else {
965 snprintf(buf, 2048, "Non-prime classexts: %zu\n", st_table_size(classext_tbl));
966 rb_str_cat_cstr(res, buf);
967 }
968
969 rb_class_classext_foreach(klass, dump_classext_i, (void *)res);
970
971 return res;
972}
973
974#endif /* RUBY_DEBUG */
975
976/*
977 * Document-class: Namespace
978 *
979 * Namespace is designed to provide separated spaces in a Ruby
980 * process, to isolate applications and libraries.
981 * See {Namespace}[rdoc-ref:namespace.md].
982 */
983void
984Init_Namespace(void)
985{
986 tmp_dir = system_tmpdir();
987 tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
988
990 rb_define_method(rb_cNamespace, "initialize", namespace_initialize, 0);
991
992 /* :nodoc: */
993 rb_cNamespaceEntry = rb_define_class_under(rb_cNamespace, "Entry", rb_cObject);
994 rb_define_alloc_func(rb_cNamespaceEntry, rb_namespace_entry_alloc);
995
996 initialize_root_namespace();
997
998 /* :nodoc: */
999 rb_mNamespaceLoader = rb_define_module_under(rb_cNamespace, "Loader");
1000 namespace_define_loader_method("require");
1001 namespace_define_loader_method("require_relative");
1002 namespace_define_loader_method("load");
1003
1004 if (rb_namespace_available()) {
1005 rb_include_module(rb_cObject, rb_mNamespaceLoader);
1006
1007#ifdef RUBY_DEBUG
1008 rb_define_singleton_method(rb_cNamespace, "root", rb_namespace_s_root, 0);
1009 rb_define_singleton_method(rb_cNamespace, "main", rb_namespace_s_main, 0);
1010 rb_define_global_function("dump_classext", rb_f_dump_classext, 1);
1011#endif
1012 }
1013
1014 rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0);
1015 rb_define_singleton_method(rb_cNamespace, "current", rb_namespace_s_current, 0);
1016 rb_define_singleton_method(rb_cNamespace, "is_builtin?", rb_namespace_s_is_builtin_p, 1);
1017
1018 rb_define_method(rb_cNamespace, "load_path", rb_namespace_load_path, 0);
1019 rb_define_method(rb_cNamespace, "load", rb_namespace_load, -1);
1020 rb_define_method(rb_cNamespace, "require", rb_namespace_require, 1);
1021 rb_define_method(rb_cNamespace, "require_relative", rb_namespace_require_relative, 1);
1022 rb_define_method(rb_cNamespace, "eval", rb_namespace_eval, 1);
1023
1024 rb_define_method(rb_cNamespace, "inspect", rb_namespace_inspect, 0);
1025}
#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.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
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:3143
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
#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 NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#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_cNamespace
Namespace class.
Definition namespace.c:22
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2164
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2205
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
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:2182
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
VALUE rb_cModule
Module class.
Definition object.c:62
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
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_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_sort_bang(VALUE ary)
Destructively sorts the passed array in-place, according to each elements' <=> result.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1446
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:4009
#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:1655
#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:1513
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:1985
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:3878
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
#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 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:521
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:456
#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:503
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
Internal header for Namespace.
Definition namespace.h:14
Definition st.h:79
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