Ruby 3.5.0dev (2025-10-09 revision 960c28a4f84e8982fba61702a2ac7a89643ac4f6)
load.c (960c28a4f84e8982fba61702a2ac7a89643ac4f6)
1/*
2 * load methods from eval.c
3 */
4
5#include "dln.h"
6#include "eval_intern.h"
7#include "internal.h"
8#include "internal/dir.h"
9#include "internal/error.h"
10#include "internal/eval.h"
11#include "internal/file.h"
12#include "internal/hash.h"
13#include "internal/load.h"
14#include "internal/namespace.h"
15#include "internal/ruby_parser.h"
16#include "internal/thread.h"
17#include "internal/variable.h"
18#include "iseq.h"
19#include "probes.h"
20#include "darray.h"
21#include "ruby/encoding.h"
22#include "ruby/util.h"
23#include "ractor_core.h"
24#include "vm_core.h"
25
26#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
27#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
28#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
29
30#if SIZEOF_VALUE <= SIZEOF_LONG
31# define SVALUE2NUM(x) LONG2NUM((long)(x))
32# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
33#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
34# define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
35# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
36#else
37# error Need integer for VALUE
38#endif
39
40enum {
41 loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
42 1) /* offset by rb_find_file_ext() */
43};
44
45static const char *const loadable_ext[] = {
46 ".rb", DLEXT,
47 0
48};
49
50static const char *const ruby_ext[] = {
51 ".rb",
52 0
53};
54
55enum expand_type {
56 EXPAND_ALL,
57 EXPAND_RELATIVE,
58 EXPAND_HOME,
59 EXPAND_NON_CACHE
60};
61
62/* Construct expanded load path and store it to cache.
63 We rebuild load path partially if the cache is invalid.
64 We don't cache non string object and expand it every time. We ensure that
65 string objects in $LOAD_PATH are frozen.
66 */
67static void
68rb_construct_expanded_load_path(rb_namespace_t *ns, enum expand_type type, int *has_relative, int *has_non_cache)
69{
70 VALUE load_path = ns->load_path;
71 VALUE expanded_load_path = ns->expanded_load_path;
72 VALUE snapshot;
73 VALUE ary;
74 long i;
75
76 ary = rb_ary_hidden_new(RARRAY_LEN(load_path));
77 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
78 VALUE path, as_str, expanded_path;
79 int is_string, non_cache;
80 char *as_cstr;
81 as_str = path = RARRAY_AREF(load_path, i);
82 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
83 non_cache = !is_string ? 1 : 0;
84 as_str = rb_get_path_check_to_string(path);
85 as_cstr = RSTRING_PTR(as_str);
86
87 if (!non_cache) {
88 if ((type == EXPAND_RELATIVE &&
89 rb_is_absolute_path(as_cstr)) ||
90 (type == EXPAND_HOME &&
91 (!as_cstr[0] || as_cstr[0] != '~')) ||
92 (type == EXPAND_NON_CACHE)) {
93 /* Use cached expanded path. */
94 rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
95 continue;
96 }
97 }
98 if (!*has_relative && !rb_is_absolute_path(as_cstr))
99 *has_relative = 1;
100 if (!*has_non_cache && non_cache)
101 *has_non_cache = 1;
102 /* Freeze only string object. We expand other objects every time. */
103 if (is_string)
104 rb_str_freeze(path);
105 as_str = rb_get_path_check_convert(as_str);
106 expanded_path = rb_check_realpath(Qnil, as_str, NULL);
107 if (NIL_P(expanded_path)) expanded_path = as_str;
108 rb_ary_push(ary, rb_fstring(expanded_path));
109 }
110 rb_ary_freeze(ary);
111 ns->expanded_load_path = ary;
112 snapshot = ns->load_path_snapshot;
113 load_path = ns->load_path;
114 rb_ary_replace(snapshot, load_path);
115}
116
117static VALUE
118get_expanded_load_path(rb_namespace_t *ns)
119{
120 VALUE check_cache;
121 const VALUE non_cache = Qtrue;
122 const VALUE load_path_snapshot = ns->load_path_snapshot;
123 const VALUE load_path = ns->load_path;
124
125 if (!rb_ary_shared_with_p(load_path_snapshot, load_path)) {
126 /* The load path was modified. Rebuild the expanded load path. */
127 int has_relative = 0, has_non_cache = 0;
128 rb_construct_expanded_load_path(ns, EXPAND_ALL, &has_relative, &has_non_cache);
129 if (has_relative) {
130 ns->load_path_check_cache = rb_dir_getwd_ospath();
131 }
132 else if (has_non_cache) {
133 /* Non string object. */
134 ns->load_path_check_cache = non_cache;
135 }
136 else {
137 ns->load_path_check_cache = 0;
138 }
139 }
140 else if ((check_cache = ns->load_path_check_cache) == non_cache) {
141 int has_relative = 1, has_non_cache = 1;
142 /* Expand only non-cacheable objects. */
143 rb_construct_expanded_load_path(ns, EXPAND_NON_CACHE,
144 &has_relative, &has_non_cache);
145 }
146 else if (check_cache) {
147 int has_relative = 1, has_non_cache = 1;
148 VALUE cwd = rb_dir_getwd_ospath();
149 if (!rb_str_equal(check_cache, cwd)) {
150 /* Current working directory or filesystem encoding was changed.
151 Expand relative load path and non-cacheable objects again. */
152 ns->load_path_check_cache = cwd;
153 rb_construct_expanded_load_path(ns, EXPAND_RELATIVE,
154 &has_relative, &has_non_cache);
155 }
156 else {
157 /* Expand only tilde (User HOME) and non-cacheable objects. */
158 rb_construct_expanded_load_path(ns, EXPAND_HOME,
159 &has_relative, &has_non_cache);
160 }
161 }
162 return ns->expanded_load_path;
163}
164
165VALUE
166rb_get_expanded_load_path(void)
167{
168 return get_expanded_load_path((rb_namespace_t *)rb_loading_namespace());
169}
170
171static VALUE
172load_path_getter(ID _x, VALUE * _y)
173{
174 return rb_loading_namespace()->load_path;
175}
176
177static VALUE
178get_LOADED_FEATURES(ID _x, VALUE *_y)
179{
180 return rb_loading_namespace()->loaded_features;
181}
182
183static void
184reset_loaded_features_snapshot(const rb_namespace_t *ns)
185{
186 VALUE snapshot = ns->loaded_features_snapshot;
187 VALUE loaded_features = ns->loaded_features;
188 rb_ary_replace(snapshot, loaded_features);
189}
190
191static struct st_table *
192get_loaded_features_index_raw(const rb_namespace_t *ns)
193{
194 return ns->loaded_features_index;
195}
196
197static st_data_t
198feature_key(const char *str, size_t len)
199{
200 return st_hash(str, len, 0xfea7009e);
201}
202
203static bool
204is_rbext_path(VALUE feature_path)
205{
206 long len = RSTRING_LEN(feature_path);
207 long rbext_len = rb_strlen_lit(".rb");
208 if (len <= rbext_len) return false;
209 return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
210}
211
212typedef rb_darray(long) feature_indexes_t;
213
214struct features_index_add_single_args {
215 const rb_namespace_t *ns;
216 VALUE offset;
217 bool rb;
218};
219
220static int
221features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
222{
223 struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
224 const rb_namespace_t *ns = args->ns;
225 VALUE offset = args->offset;
226 bool rb = args->rb;
227
228 if (existing) {
229 VALUE this_feature_index = *value;
230
231 if (FIXNUM_P(this_feature_index)) {
232 VALUE loaded_features = ns->loaded_features;
233 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
234
235 feature_indexes_t feature_indexes;
236 rb_darray_make(&feature_indexes, 2);
237 int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
238 rb_darray_set(feature_indexes, top^0, FIX2LONG(this_feature_index));
239 rb_darray_set(feature_indexes, top^1, FIX2LONG(offset));
240
241 RUBY_ASSERT(rb_darray_size(feature_indexes) == 2);
242 // assert feature_indexes does not look like a special const
243 RUBY_ASSERT(!SPECIAL_CONST_P((VALUE)feature_indexes));
244
245 *value = (st_data_t)feature_indexes;
246 }
247 else {
248 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
249 long pos = -1;
250
251 if (rb) {
252 VALUE loaded_features = ns->loaded_features;
253 for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
254 long idx = rb_darray_get(feature_indexes, i);
255 VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
256 Check_Type(this_feature_path, T_STRING);
257 if (!is_rbext_path(this_feature_path)) {
258 pos = i;
259 break;
260 }
261 }
262 }
263
264 rb_darray_append(&feature_indexes, FIX2LONG(offset));
265 /* darray may realloc which will change the pointer */
266 *value = (st_data_t)feature_indexes;
267
268 if (pos >= 0) {
269 long *ptr = rb_darray_data_ptr(feature_indexes);
270 long len = rb_darray_size(feature_indexes);
271 MEMMOVE(ptr + pos + 1, ptr + pos, long, len - pos - 1);
272 ptr[pos] = FIX2LONG(offset);
273 }
274 }
275 }
276 else {
277 *value = offset;
278 }
279
280 return ST_CONTINUE;
281}
282
283static void
284features_index_add_single(const rb_namespace_t *ns, const char* str, size_t len, VALUE offset, bool rb)
285{
286 struct st_table *features_index;
287 st_data_t short_feature_key;
288
289 Check_Type(offset, T_FIXNUM);
290 short_feature_key = feature_key(str, len);
291
292 features_index = get_loaded_features_index_raw(ns);
293
294 struct features_index_add_single_args args = {
295 .ns = ns,
296 .offset = offset,
297 .rb = rb,
298 };
299
300 st_update(features_index, short_feature_key, features_index_add_single_callback, (st_data_t)&args);
301}
302
303/* Add to the loaded-features index all the required entries for
304 `feature`, located at `offset` in $LOADED_FEATURES. We add an
305 index entry at each string `short_feature` for which
306 feature == "#{prefix}#{short_feature}#{ext}"
307 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
308 or ends in '/'. This maintains the invariant that `rb_feature_p()`
309 relies on for its fast lookup.
310*/
311static void
312features_index_add(const rb_namespace_t *ns, VALUE feature, VALUE offset)
313{
314 RUBY_ASSERT(rb_ractor_main_p());
315
316 const char *feature_str, *feature_end, *ext, *p;
317 bool rb = false;
318
319 feature_str = StringValuePtr(feature);
320 feature_end = feature_str + RSTRING_LEN(feature);
321
322 for (ext = feature_end; ext > feature_str; ext--)
323 if (*ext == '.' || *ext == '/')
324 break;
325 if (*ext != '.')
326 ext = NULL;
327 else
328 rb = IS_RBEXT(ext);
329 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
330 at the end of `feature`, or is NULL if there is no such string. */
331
332 p = ext ? ext : feature_end;
333 while (1) {
334 p--;
335 while (p >= feature_str && *p != '/')
336 p--;
337 if (p < feature_str)
338 break;
339 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
340 features_index_add_single(ns, p + 1, feature_end - p - 1, offset, false);
341 if (ext) {
342 features_index_add_single(ns, p + 1, ext - p - 1, offset, rb);
343 }
344 }
345 features_index_add_single(ns, feature_str, feature_end - feature_str, offset, false);
346 if (ext) {
347 features_index_add_single(ns, feature_str, ext - feature_str, offset, rb);
348 }
349}
350
351static int
352loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
353{
354 VALUE obj = (VALUE)val;
355 if (!SPECIAL_CONST_P(obj)) {
356 rb_darray_free((void *)obj);
357 }
358 return ST_DELETE;
359}
360
361static st_table *
362get_loaded_features_index(const rb_namespace_t *ns)
363{
364 int i;
365 VALUE features = ns->loaded_features;
366 const VALUE snapshot = ns->loaded_features_snapshot;
367
368 if (!rb_ary_shared_with_p(snapshot, features)) {
369 /* The sharing was broken; something (other than us in rb_provide_feature())
370 modified loaded_features. Rebuild the index. */
371 st_foreach(ns->loaded_features_index, loaded_features_index_clear_i, 0);
372
373 VALUE realpaths = ns->loaded_features_realpaths;
374 VALUE realpath_map = ns->loaded_features_realpath_map;
375 VALUE previous_realpath_map = rb_hash_dup(realpath_map);
376 rb_hash_clear(realpaths);
377 rb_hash_clear(realpath_map);
378
379 /* We have to make a copy of features here because the StringValue call
380 * below could call a Ruby method, which could modify $LOADED_FEATURES
381 * and cause it to be corrupt. */
382 features = rb_ary_resurrect(features);
383 for (i = 0; i < RARRAY_LEN(features); i++) {
384 VALUE entry, as_str;
385 as_str = entry = rb_ary_entry(features, i);
386 StringValue(as_str);
387 as_str = rb_fstring(as_str);
388 if (as_str != entry)
389 rb_ary_store(features, i, as_str);
390 features_index_add(ns, as_str, INT2FIX(i));
391 }
392 /* The user modified $LOADED_FEATURES, so we should restore the changes. */
393 if (!rb_ary_shared_with_p(features, ns->loaded_features)) {
394 rb_ary_replace(ns->loaded_features, features);
395 }
396 reset_loaded_features_snapshot(ns);
397
398 features = ns->loaded_features_snapshot;
399 long j = RARRAY_LEN(features);
400 for (i = 0; i < j; i++) {
401 VALUE as_str = rb_ary_entry(features, i);
402 VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
403 if (NIL_P(realpath)) {
404 realpath = rb_check_realpath(Qnil, as_str, NULL);
405 if (NIL_P(realpath)) realpath = as_str;
406 realpath = rb_fstring(realpath);
407 }
408 rb_hash_aset(realpaths, realpath, Qtrue);
409 rb_hash_aset(realpath_map, as_str, realpath);
410 }
411 }
412 return ns->loaded_features_index;
413}
414
415/* This searches `load_path` for a value such that
416 name == "#{load_path[i]}/#{feature}"
417 if `feature` is a suffix of `name`, or otherwise
418 name == "#{load_path[i]}/#{feature}#{ext}"
419 for an acceptable string `ext`. It returns
420 `load_path[i].to_str` if found, else 0.
421
422 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
423 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
424 or have any value matching `%r{^\.[^./]*$}`.
425*/
426static VALUE
427loaded_feature_path(const char *name, long vlen, const char *feature, long len,
428 int type, VALUE load_path)
429{
430 long i;
431 long plen;
432 const char *e;
433
434 if (vlen < len+1) return 0;
435 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
436 plen = vlen - len;
437 }
438 else {
439 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
440 if (*e != '.' ||
441 e-name < len ||
442 strncmp(e-len, feature, len))
443 return 0;
444 plen = e - name - len;
445 }
446 if (plen > 0 && name[plen-1] != '/') {
447 return 0;
448 }
449 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
450 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
451 0) {
452 return 0;
453 }
454 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
455 (possibly empty) and prefix is some string of length plen. */
456
457 if (plen > 0) --plen; /* exclude '.' */
458 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
459 VALUE p = RARRAY_AREF(load_path, i);
460 const char *s = StringValuePtr(p);
461 long n = RSTRING_LEN(p);
462
463 if (n != plen) continue;
464 if (n && strncmp(name, s, n)) continue;
465 return p;
466 }
467 return 0;
468}
469
471 const char *name;
472 long len;
473 int type;
474 VALUE load_path;
475 const char *result;
476};
477
478static int
479loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
480{
481 const char *s = (const char *)v;
482 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
483 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
484 fp->type, fp->load_path);
485 if (!p) return ST_CONTINUE;
486 fp->result = s;
487 return ST_STOP;
488}
489
490/*
491 * Returns the type of already provided feature.
492 * 'r': ruby script (".rb")
493 * 's': shared object (".so"/"."DLEXT)
494 * 'u': unsuffixed
495 */
496static int
497rb_feature_p(const rb_namespace_t *ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
498{
499 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
500 const char *f, *e;
501 long i, len, elen, n;
502 st_table *loading_tbl, *features_index;
503 st_data_t data;
504 st_data_t key;
505 int type;
506
507 if (fn) *fn = 0;
508 if (ext) {
509 elen = strlen(ext);
510 len = strlen(feature) - elen;
511 type = rb ? 'r' : 's';
512 }
513 else {
514 len = strlen(feature);
515 elen = 0;
516 type = 0;
517 }
518 features = ns->loaded_features;
519 features_index = get_loaded_features_index(ns);
520
521 key = feature_key(feature, strlen(feature));
522 /* We search `features` for an entry such that either
523 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
524 for some j, or
525 "#{features[i]}" == "#{feature}#{e}"
526 Here `e` is an "allowed" extension -- either empty or one
527 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
528 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
529 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
530
531 If `expanded`, then only the latter form (without load_path[j])
532 is accepted. Otherwise either form is accepted, *unless* `ext`
533 is false and an otherwise-matching entry of the first form is
534 preceded by an entry of the form
535 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
536 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
537 After a "distractor" entry of this form, only entries of the
538 form "#{feature}#{e}" are accepted.
539
540 In `rb_provide_feature()` and `get_loaded_features_index()` we
541 maintain an invariant that the array `this_feature_index` will
542 point to every entry in `features` which has the form
543 "#{prefix}#{feature}#{e}"
544 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
545 or ends in '/'. This includes both match forms above, as well
546 as any distractors, so we may ignore all other entries in `features`.
547 */
548 if (st_lookup(features_index, key, &data) && !NIL_P(this_feature_index = (VALUE)data)) {
549 for (size_t i = 0; ; i++) {
550 long index;
551 if (FIXNUM_P(this_feature_index)) {
552 if (i > 0) break;
553 index = FIX2LONG(this_feature_index);
554 }
555 else {
556 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
557 if (i >= rb_darray_size(feature_indexes)) break;
558 index = rb_darray_get(feature_indexes, i);
559 }
560
561 if (index >= RARRAY_LEN(features)) continue;
562 v = RARRAY_AREF(features, index);
563 f = StringValuePtr(v);
564 if ((n = RSTRING_LEN(v)) < len) continue;
565 if (strncmp(f, feature, len) != 0) {
566 if (expanded) continue;
567 if (!load_path) load_path = get_expanded_load_path((rb_namespace_t *)ns);
568 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
569 continue;
570 expanded = 1;
571 f += RSTRING_LEN(p) + 1;
572 }
573 if (!*(e = f + len)) {
574 if (ext) continue;
575 return 'u';
576 }
577 if (*e != '.') continue;
578 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
579 return 's';
580 }
581 if ((rb || !ext) && (IS_RBEXT(e))) {
582 return 'r';
583 }
584 }
585 }
586
587 loading_tbl = ns->loading_table;
588 f = 0;
589 if (!expanded && !rb_is_absolute_path(feature)) {
590 struct loaded_feature_searching fs;
591 fs.name = feature;
592 fs.len = len;
593 fs.type = type;
594 fs.load_path = load_path ? load_path : get_expanded_load_path((rb_namespace_t *)ns);
595 fs.result = 0;
596 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
597 if ((f = fs.result) != 0) {
598 if (fn) *fn = f;
599 goto loading;
600 }
601 }
602 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
603 if (fn) *fn = (const char*)data;
604 goto loading;
605 }
606 else {
607 VALUE bufstr;
608 char *buf;
609 static const char so_ext[][4] = {
610 ".so", ".o",
611 };
612
613 if (ext && *ext) return 0;
614 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
615 buf = RSTRING_PTR(bufstr);
616 MEMCPY(buf, feature, char, len);
617 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
618 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
619 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
620 rb_str_resize(bufstr, 0);
621 if (fn) *fn = (const char*)data;
622 return i ? 's' : 'r';
623 }
624 }
625 for (i = 0; i < numberof(so_ext); i++) {
626 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
627 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
628 rb_str_resize(bufstr, 0);
629 if (fn) *fn = (const char*)data;
630 return 's';
631 }
632 }
633 rb_str_resize(bufstr, 0);
634 }
635 return 0;
636
637 loading:
638 if (!ext) return 'u';
639 return !IS_RBEXT(ext) ? 's' : 'r';
640}
641
642int
643rb_provided(const char *feature)
644{
645 return rb_feature_provided(feature, 0);
646}
647
648static int
649feature_provided(rb_namespace_t *ns, const char *feature, const char **loading)
650{
651 const char *ext = strrchr(feature, '.');
652 VALUE fullpath = 0;
653
654 if (*feature == '.' &&
655 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
656 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
657 feature = RSTRING_PTR(fullpath);
658 }
659 if (ext && !strchr(ext, '/')) {
660 if (IS_RBEXT(ext)) {
661 if (rb_feature_p(ns, feature, ext, TRUE, FALSE, loading)) return TRUE;
662 return FALSE;
663 }
664 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
665 if (rb_feature_p(ns, feature, ext, FALSE, FALSE, loading)) return TRUE;
666 return FALSE;
667 }
668 }
669 if (rb_feature_p(ns, feature, 0, TRUE, FALSE, loading))
670 return TRUE;
671 RB_GC_GUARD(fullpath);
672 return FALSE;
673}
674
675int
676rb_feature_provided(const char *feature, const char **loading)
677{
678 rb_namespace_t *ns = (rb_namespace_t *)rb_current_namespace();
679 return feature_provided(ns, feature, loading);
680}
681
682static void
683rb_provide_feature(const rb_namespace_t *ns, VALUE feature)
684{
685 VALUE features;
686
687 features = ns->loaded_features;
688 if (OBJ_FROZEN(features)) {
689 rb_raise(rb_eRuntimeError,
690 "$LOADED_FEATURES is frozen; cannot append feature");
691 }
692 feature = rb_fstring(feature);
693
694 get_loaded_features_index(ns);
695 // If loaded_features and loaded_features_snapshot share the same backing
696 // array, pushing into it would cause the whole array to be copied.
697 // To avoid this we first clear loaded_features_snapshot.
698 rb_ary_clear(ns->loaded_features_snapshot);
699 rb_ary_push(features, feature);
700 features_index_add(ns, feature, INT2FIX(RARRAY_LEN(features)-1));
701 reset_loaded_features_snapshot(ns);
702}
703
704void
705rb_provide(const char *feature)
706{
707 /*
708 * rb_provide() must use rb_current_namespace to store provided features
709 * in the current namespace's loaded_features, etc.
710 */
711 rb_provide_feature(rb_current_namespace(), rb_fstring_cstr(feature));
712}
713
714NORETURN(static void load_failed(VALUE));
715
716static inline VALUE
717realpath_internal_cached(VALUE hash, VALUE path)
718{
719 VALUE ret = rb_hash_aref(hash, path);
720 if(RTEST(ret)) {
721 return ret;
722 }
723
724 VALUE realpath = rb_realpath_internal(Qnil, path, 1);
725 rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
726 return realpath;
727}
728
729static inline void
730load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
731{
732 const rb_namespace_t *ns = rb_loading_namespace();
733 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
734
735 if (!iseq) {
736 rb_execution_context_t *ec = GET_EC();
737 VALUE v = rb_vm_push_frame_fname(ec, fname);
738
739 VALUE realpath_map = ns->loaded_features_realpath_map;
740
741 if (rb_ruby_prism_p()) {
742 pm_parse_result_t result = { 0 };
743 result.options.line = 1;
744 result.node.coverage_enabled = 1;
745
746 VALUE error = pm_load_parse_file(&result, fname, NULL);
747
748 if (error == Qnil) {
749 int error_state;
750 iseq = pm_iseq_new_top(&result.node, rb_fstring_lit("<top (required)>"), fname, realpath_internal_cached(realpath_map, fname), NULL, &error_state);
751
752 pm_parse_result_free(&result);
753
754 if (error_state) {
755 RUBY_ASSERT(iseq == NULL);
756 rb_jump_tag(error_state);
757 }
758 }
759 else {
760 rb_vm_pop_frame(ec);
761 RB_GC_GUARD(v);
762 pm_parse_result_free(&result);
763 rb_exc_raise(error);
764 }
765 }
766 else {
767 rb_ast_t *ast;
768 VALUE ast_value;
769 VALUE parser = rb_parser_new();
770 rb_parser_set_context(parser, NULL, FALSE);
771 ast_value = rb_parser_load_file(parser, fname);
772 ast = rb_ruby_ast_data_get(ast_value);
773
774 iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
775 fname, realpath_internal_cached(realpath_map, fname), NULL);
776 rb_ast_dispose(ast);
777 }
778
779 rb_vm_pop_frame(ec);
780 RB_GC_GUARD(v);
781 }
782 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
783
784 rb_iseq_eval(iseq, ns);
785}
786
787static inline enum ruby_tag_type
788load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
789{
790 enum ruby_tag_type state;
791 rb_namespace_t *ns;
792 rb_thread_t *th = rb_ec_thread_ptr(ec);
793 volatile VALUE wrapper = th->top_wrapper;
794 volatile VALUE self = th->top_self;
795#if !defined __GNUC__
796 rb_thread_t *volatile th0 = th;
797#endif
798
799 ec->errinfo = Qnil; /* ensure */
800
801 /* load in module as toplevel */
802 if (NAMESPACE_OBJ_P(load_wrapper)) {
803 ns = rb_get_namespace_t(load_wrapper);
804 if (!ns->top_self) {
805 ns->top_self = rb_obj_clone(rb_vm_top_self());
806 }
807 th->top_self = ns->top_self;
808 }
809 else {
810 th->top_self = rb_obj_clone(rb_vm_top_self());
811 }
812 th->top_wrapper = load_wrapper;
813 rb_extend_object(th->top_self, th->top_wrapper);
814
815 EC_PUSH_TAG(ec);
816 state = EC_EXEC_TAG();
817 if (state == TAG_NONE) {
818 load_iseq_eval(ec, fname);
819 }
820 EC_POP_TAG();
821
822#if !defined __GNUC__
823 th = th0;
824 fname = RB_GC_GUARD(fname);
825#endif
826 th->top_self = self;
827 th->top_wrapper = wrapper;
828 return state;
829}
830
831static inline void
832raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
833{
834 if (state) {
835 rb_vm_jump_tag_but_local_jump(state);
836 }
837
838 if (!NIL_P(ec->errinfo)) {
839 rb_exc_raise(ec->errinfo);
840 }
841}
842
843static void
844rb_load_internal(VALUE fname, VALUE wrap)
845{
846 VALUE namespace;
847 rb_execution_context_t *ec = GET_EC();
848 const rb_namespace_t *ns = rb_loading_namespace();
849 enum ruby_tag_type state = TAG_NONE;
850 if (RTEST(wrap)) {
851 if (!RB_TYPE_P(wrap, T_MODULE)) {
852 wrap = rb_module_new();
853 }
854 state = load_wrapping(ec, fname, wrap);
855 }
856 else if (NAMESPACE_OPTIONAL_P(ns)) {
857 namespace = ns->ns_object;
858 state = load_wrapping(ec, fname, namespace);
859 }
860 else {
861 load_iseq_eval(ec, fname);
862 }
863 raise_load_if_failed(ec, state);
864}
865
866void
867rb_load(VALUE fname, int wrap)
868{
869 VALUE tmp = rb_find_file(FilePathValue(fname));
870 if (!tmp) load_failed(fname);
871 rb_load_internal(tmp, RBOOL(wrap));
872}
873
874void
875rb_load_protect(VALUE fname, int wrap, int *pstate)
876{
877 enum ruby_tag_type state;
878
879 EC_PUSH_TAG(GET_EC());
880 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
881 rb_load(fname, wrap);
882 }
883 EC_POP_TAG();
884
885 if (state != TAG_NONE) *pstate = state;
886}
887
888static VALUE
889load_entrypoint_internal(VALUE fname, VALUE wrap)
890{
891 VALUE path, orig_fname;
892
893 orig_fname = rb_get_path_check_to_string(fname);
894 fname = rb_str_encode_ospath(orig_fname);
895 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
896
897 path = rb_find_file(fname);
898 if (!path) {
899 if (!rb_file_load_ok(RSTRING_PTR(fname)))
900 load_failed(orig_fname);
901 path = fname;
902 }
903 rb_load_internal(path, wrap);
904
905 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
906
907 return Qtrue;
908}
909
910VALUE
911rb_load_entrypoint(VALUE args)
912{
913 VALUE fname, wrap;
914 if (RARRAY_LEN(args) != 2) {
915 rb_bug("invalid arguments: %ld", RARRAY_LEN(args));
916 }
917 fname = rb_ary_entry(args, 0);
918 wrap = rb_ary_entry(args, 1);
919 return load_entrypoint_internal(fname, wrap);
920}
921
922/*
923 * call-seq:
924 * load(filename, wrap=false) -> true
925 *
926 * Loads and executes the Ruby program in the file _filename_.
927 *
928 * If the filename is an absolute path (e.g. starts with '/'), the file
929 * will be loaded directly using the absolute path.
930 *
931 * If the filename is an explicit relative path (e.g. starts with './' or
932 * '../'), the file will be loaded using the relative path from the current
933 * directory.
934 *
935 * Otherwise, the file will be searched for in the library
936 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
937 * If the file is found in a directory, it will attempt to load the file
938 * relative to that directory. If the file is not found in any of the
939 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
940 * the relative path from the current directory.
941 *
942 * If the file doesn't exist when there is an attempt to load it, a
943 * LoadError will be raised.
944 *
945 * If the optional _wrap_ parameter is +true+, the loaded script will
946 * be executed under an anonymous module. If the optional _wrap_ parameter
947 * is a module, the loaded script will be executed under the given module.
948 * In no circumstance will any local variables in the loaded file be
949 * propagated to the loading environment.
950 */
951
952static VALUE
953rb_f_load(int argc, VALUE *argv, VALUE _)
954{
955 VALUE fname, wrap;
956 rb_scan_args(argc, argv, "11", &fname, &wrap);
957 return load_entrypoint_internal(fname, wrap);
958}
959
960static char *
961load_lock(const rb_namespace_t *ns, const char *ftptr, bool warn)
962{
963 st_data_t data;
964 st_table *loading_tbl = ns->loading_table;
965
966 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
967 /* partial state */
968 ftptr = ruby_strdup(ftptr);
969 data = (st_data_t)rb_thread_shield_new();
970 st_insert(loading_tbl, (st_data_t)ftptr, data);
971 return (char *)ftptr;
972 }
973
974 if (warn && rb_thread_shield_owned((VALUE)data)) {
975 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
976 rb_backtrace_each(rb_str_append, warning);
977 rb_warning("%"PRIsVALUE, warning);
978 }
979 switch (rb_thread_shield_wait((VALUE)data)) {
980 case Qfalse:
981 case Qnil:
982 return 0;
983 }
984 return (char *)ftptr;
985}
986
987static int
988release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
989{
990 VALUE thread_shield = (VALUE)*value;
991 if (!existing) return ST_STOP;
992 if (done) {
993 rb_thread_shield_destroy(thread_shield);
994 /* Delete the entry even if there are waiting threads, because they
995 * won't load the file and won't delete the entry. */
996 }
997 else if (rb_thread_shield_release(thread_shield)) {
998 /* still in-use */
999 return ST_CONTINUE;
1000 }
1001 xfree((char *)*key);
1002 return ST_DELETE;
1003}
1004
1005static void
1006load_unlock(const rb_namespace_t *ns, const char *ftptr, int done)
1007{
1008 if (ftptr) {
1009 st_data_t key = (st_data_t)ftptr;
1010 st_table *loading_tbl = ns->loading_table;
1011
1012 st_update(loading_tbl, key, release_thread_shield, done);
1013 }
1014}
1015
1016static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
1017
1018/*
1019 * call-seq:
1020 * require(name) -> true or false
1021 *
1022 * Loads the given +name+, returning +true+ if successful and +false+ if the
1023 * feature is already loaded.
1024 *
1025 * If the filename neither resolves to an absolute path nor starts with
1026 * './' or '../', the file will be searched for in the library
1027 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
1028 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
1029 *
1030 * If the filename has the extension ".rb", it is loaded as a source file; if
1031 * the extension is ".so", ".o", or the default shared library extension on
1032 * the current platform, Ruby loads the shared library as a Ruby extension.
1033 * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
1034 * found. If the file named cannot be found, a LoadError will be raised.
1035 *
1036 * For Ruby extensions the filename given may use ".so" or ".o". For example,
1037 * on macOS the socket extension is "socket.bundle" and
1038 * <code>require 'socket.so'</code> will load the socket extension.
1039 *
1040 * The absolute path of the loaded file is added to
1041 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
1042 * loaded again if its path already appears in <code>$"</code>. For example,
1043 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1044 * again.
1045 *
1046 * require "my-library.rb"
1047 * require "db-driver"
1048 *
1049 * Any constants or globals within the loaded source file will be available
1050 * in the calling program's global namespace. However, local variables will
1051 * not be propagated to the loading environment.
1052 *
1053 */
1054
1055VALUE
1057{
1058 // const rb_namespace_t *ns = rb_loading_namespace();
1059 // printf("F:current loading ns: %ld\n", ns->ns_id);
1060 return rb_require_string(fname);
1061}
1062
1063VALUE
1064rb_require_relative_entrypoint(VALUE fname)
1065{
1066 VALUE base = rb_current_realfilepath();
1067 if (NIL_P(base)) {
1068 rb_loaderror("cannot infer basepath");
1069 }
1070 base = rb_file_dirname(base);
1071 return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1072}
1073
1074/*
1075 * call-seq:
1076 * require_relative(string) -> true or false
1077 *
1078 * Ruby tries to load the library named _string_ relative to the directory
1079 * containing the requiring file. If the file does not exist a LoadError is
1080 * raised. Returns +true+ if the file was loaded and +false+ if the file was
1081 * already loaded before.
1082 */
1083VALUE
1084rb_f_require_relative(VALUE obj, VALUE fname)
1085{
1086 return rb_require_relative_entrypoint(fname);
1087}
1088
1089typedef int (*feature_func)(const rb_namespace_t *ns, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1090
1091static int
1092search_required(const rb_namespace_t *ns, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1093{
1094 VALUE tmp;
1095 char *ext, *ftptr;
1096 int ft = 0;
1097 const char *loading;
1098
1099 *path = 0;
1100 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
1101 if (ext && !strchr(ext, '/')) {
1102 if (IS_RBEXT(ext)) {
1103 if (rb_feature_p(ns, ftptr, ext, TRUE, FALSE, &loading)) {
1104 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1105 return 'r';
1106 }
1107 if ((tmp = rb_find_file(fname)) != 0) {
1108 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1109 if (!rb_feature_p(ns, ftptr, ext, TRUE, TRUE, &loading) || loading)
1110 *path = tmp;
1111 return 'r';
1112 }
1113 return 0;
1114 }
1115 else if (IS_SOEXT(ext)) {
1116 if (rb_feature_p(ns, ftptr, ext, FALSE, FALSE, &loading)) {
1117 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1118 return 's';
1119 }
1120 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1121 rb_str_cat2(tmp, DLEXT);
1122 OBJ_FREEZE(tmp);
1123 if ((tmp = rb_find_file(tmp)) != 0) {
1124 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1125 if (!rb_feature_p(ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
1126 *path = tmp;
1127 return 's';
1128 }
1129 }
1130 else if (IS_DLEXT(ext)) {
1131 if (rb_feature_p(ns, ftptr, ext, FALSE, FALSE, &loading)) {
1132 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1133 return 's';
1134 }
1135 if ((tmp = rb_find_file(fname)) != 0) {
1136 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1137 if (!rb_feature_p(ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
1138 *path = tmp;
1139 return 's';
1140 }
1141 }
1142 }
1143 else if ((ft = rb_feature_p(ns, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1144 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1145 return 'r';
1146 }
1147 tmp = fname;
1148 const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1149
1150 // Check if it's a statically linked extension when
1151 // not already a feature and not found as a dynamic library.
1152 if (!ft && type != loadable_ext_rb) {
1153 rb_vm_t *vm = GET_VM();
1154 if (vm->static_ext_inits) {
1155 VALUE lookup_name = tmp;
1156 // Append ".so" if not already present so for example "etc" can find "etc.so".
1157 // We always register statically linked extensions with a ".so" extension.
1158 // See encinit.c and extinit.c (generated at build-time).
1159 if (!ext) {
1160 lookup_name = rb_str_dup(lookup_name);
1161 rb_str_cat_cstr(lookup_name, ".so");
1162 }
1163 ftptr = RSTRING_PTR(lookup_name);
1164 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1165 *path = rb_filesystem_str_new_cstr(ftptr);
1166 RB_GC_GUARD(lookup_name);
1167 return 's';
1168 }
1169 }
1170 }
1171
1172 switch (type) {
1173 case 0:
1174 if (ft)
1175 goto feature_present;
1176 ftptr = RSTRING_PTR(tmp);
1177 return rb_feature_p(ns, ftptr, 0, FALSE, TRUE, 0);
1178
1179 default:
1180 if (ft) {
1181 goto feature_present;
1182 }
1183 /* fall through */
1184 case loadable_ext_rb:
1185 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1186 if (rb_feature_p(ns, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
1187 break;
1188 *path = tmp;
1189 }
1190 return type > loadable_ext_rb ? 's' : 'r';
1191
1192 feature_present:
1193 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1194 return ft;
1195}
1196
1197static void
1198load_failed(VALUE fname)
1199{
1200 rb_load_fail(fname, "cannot load such file");
1201}
1202
1203static VALUE
1204load_ext(VALUE path, VALUE fname)
1205{
1206 VALUE loaded = path;
1207 const rb_namespace_t *ns = rb_loading_namespace();
1208 if (NAMESPACE_USER_P(ns)) {
1209 loaded = rb_namespace_local_extension(ns->ns_object, fname, path);
1210 }
1211 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1212 return (VALUE)dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
1213}
1214
1215static bool
1216run_static_ext_init(rb_vm_t *vm, const char *feature)
1217{
1218 st_data_t key = (st_data_t)feature;
1219 st_data_t init_func;
1220
1221 if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1222 ((void (*)(void))init_func)();
1223 return true;
1224 }
1225 return false;
1226}
1227
1228static int
1229no_feature_p(const rb_namespace_t *ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1230{
1231 return 0;
1232}
1233
1234// Documented in doc/globals.md
1235VALUE
1236rb_resolve_feature_path(VALUE klass, VALUE fname)
1237{
1238 VALUE path;
1239 int found;
1240 VALUE sym;
1241 const rb_namespace_t *ns = rb_loading_namespace();
1242
1243 fname = rb_get_path(fname);
1244 path = rb_str_encode_ospath(fname);
1245 found = search_required(ns, path, &path, no_feature_p);
1246
1247 switch (found) {
1248 case 'r':
1249 sym = ID2SYM(rb_intern("rb"));
1250 break;
1251 case 's':
1252 sym = ID2SYM(rb_intern("so"));
1253 break;
1254 default:
1255 return Qnil;
1256 }
1257
1258 return rb_ary_new_from_args(2, sym, path);
1259}
1260
1261static void
1262ext_config_push(rb_thread_t *th, volatile struct rb_ext_config *prev)
1263{
1264 *prev = th->ext_config;
1265 th->ext_config = (struct rb_ext_config){0};
1266}
1267
1268static void
1269ext_config_pop(rb_thread_t *th, volatile struct rb_ext_config *prev)
1270{
1271 th->ext_config = *prev;
1272}
1273
1274void
1276{
1277 GET_THREAD()->ext_config.ractor_safe = flag;
1278}
1279
1280/*
1281 * returns
1282 * 0: if already loaded (false)
1283 * 1: successfully loaded (true)
1284 * <0: not found (LoadError)
1285 * >1: exception
1286 */
1287static int
1288require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1289{
1290 volatile int result = -1;
1291 rb_thread_t *th = rb_ec_thread_ptr(ec);
1292 const rb_namespace_t *ns = rb_loading_namespace();
1293 volatile const struct {
1294 VALUE wrapper, self, errinfo;
1296 const rb_namespace_t *ns;
1297 } saved = {
1298 th->top_wrapper, th->top_self, ec->errinfo,
1299 ec, ns,
1300 };
1301 enum ruby_tag_type state;
1302 char *volatile ftptr = 0;
1303 VALUE path;
1304 volatile VALUE saved_path;
1305 volatile VALUE realpath = 0;
1306 VALUE realpaths = ns->loaded_features_realpaths;
1307 VALUE realpath_map = ns->loaded_features_realpath_map;
1308 volatile bool reset_ext_config = false;
1309 volatile struct rb_ext_config prev_ext_config;
1310
1311 path = rb_str_encode_ospath(fname);
1312 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1313 saved_path = path;
1314
1315 EC_PUSH_TAG(ec);
1316 ec->errinfo = Qnil; /* ensure */
1317 th->top_wrapper = 0;
1318 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1319 VALUE handle;
1320 int found;
1321
1322 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1323 found = search_required(ns, path, &saved_path, rb_feature_p);
1324 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1325 path = saved_path;
1326
1327 if (found) {
1328 if (!path || !(ftptr = load_lock(ns, RSTRING_PTR(path), warn))) {
1329 result = 0;
1330 }
1331 else if (!*ftptr) {
1332 result = TAG_RETURN;
1333 }
1334 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1335 result = TAG_RETURN;
1336 }
1337 else if (RTEST(rb_hash_aref(realpaths,
1338 realpath = realpath_internal_cached(realpath_map, path)))) {
1339 result = 0;
1340 }
1341 else {
1342 switch (found) {
1343 case 'r':
1344 // iseq_eval_in_namespace will be called with the loading namespace eventually
1345 if (NAMESPACE_OPTIONAL_P(ns)) {
1346 // check with NAMESPACE_OPTIONAL_P (not NAMESPACE_USER_P) for NS1::xxx naming
1347 // it is not expected for the main namespace
1348 load_wrapping(saved.ec, path, ns->ns_object);
1349 }
1350 else {
1351 load_iseq_eval(saved.ec, path);
1352 }
1353 break;
1354
1355 case 's':
1356 reset_ext_config = true;
1357 ext_config_push(th, &prev_ext_config);
1358 handle = rb_vm_call_cfunc_in_namespace(ns->top_self, load_ext, path, fname, path, ns);
1359 rb_hash_aset(ns->ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1360 break;
1361 }
1362 result = TAG_RETURN;
1363 }
1364 }
1365 }
1366 EC_POP_TAG();
1367
1368 ec = saved.ec;
1369 ns = saved.ns;
1370 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1371 th2->top_self = saved.self;
1372 th2->top_wrapper = saved.wrapper;
1373 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1374
1375 path = saved_path;
1376 if (ftptr) load_unlock(ns, RSTRING_PTR(path), !state);
1377
1378 if (state) {
1379 if (state == TAG_FATAL || state == TAG_THROW) {
1380 EC_JUMP_TAG(ec, state);
1381 }
1382 else if (exception) {
1383 /* usually state == TAG_RAISE only, except for
1384 * rb_iseq_load_iseq in load_iseq_eval case */
1385 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1386 if (!NIL_P(exc)) ec->errinfo = exc;
1387 return TAG_RAISE;
1388 }
1389 else if (state == TAG_RETURN) {
1390 return TAG_RAISE;
1391 }
1392 RB_GC_GUARD(fname);
1393 /* never TAG_RETURN */
1394 return state;
1395 }
1396 if (!NIL_P(ec->errinfo)) {
1397 if (!exception) return TAG_RAISE;
1398 rb_exc_raise(ec->errinfo);
1399 }
1400
1401 if (result == TAG_RETURN) {
1402 rb_provide_feature(ns, path);
1403 VALUE real = realpath;
1404 if (real) {
1405 real = rb_fstring(real);
1406 rb_hash_aset(realpaths, real, Qtrue);
1407 }
1408 }
1409 ec->errinfo = saved.errinfo;
1410
1411 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1412
1413 return result;
1414}
1415
1416int
1417rb_require_internal_silent(VALUE fname)
1418{
1419 if (!rb_ractor_main_p()) {
1420 return NUM2INT(rb_ractor_require(fname, true));
1421 }
1422
1423 rb_execution_context_t *ec = GET_EC();
1424 return require_internal(ec, fname, 1, false);
1425}
1426
1427int
1428rb_require_internal(VALUE fname)
1429{
1430 rb_execution_context_t *ec = GET_EC();
1431 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1432}
1433
1434int
1435ruby_require_internal(const char *fname, unsigned int len)
1436{
1437 struct RString fake = {RBASIC_INIT};
1438 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1439 rb_execution_context_t *ec = GET_EC();
1440 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1441 rb_set_errinfo(Qnil);
1442 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1443}
1444
1445VALUE
1447{
1448 return rb_require_string_internal(FilePathValue(fname), false);
1449}
1450
1451static VALUE
1452rb_require_string_internal(VALUE fname, bool resurrect)
1453{
1454 rb_execution_context_t *ec = GET_EC();
1455
1456 // main ractor check
1457 if (!rb_ractor_main_p()) {
1458 if (resurrect) fname = rb_str_resurrect(fname);
1459 return rb_ractor_require(fname, false);
1460 }
1461 else {
1462 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1463
1464 if (result > TAG_RETURN) {
1465 EC_JUMP_TAG(ec, result);
1466 }
1467 if (result < 0) {
1468 if (resurrect) fname = rb_str_resurrect(fname);
1469 load_failed(fname);
1470 }
1471
1472 return RBOOL(result);
1473 }
1474}
1475
1476VALUE
1477rb_require(const char *fname)
1478{
1479 struct RString fake = {RBASIC_INIT};
1480 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1481 return rb_require_string_internal(str, true);
1482}
1483
1484static int
1485register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1486{
1487 const char *name = (char *)*key;
1488 if (existing) {
1489 /* already registered */
1490 rb_warn("%s is already registered", name);
1491 }
1492 else {
1493 *value = (st_data_t)init;
1494 }
1495 return ST_CONTINUE;
1496}
1497
1498// Private API for statically linked extensions.
1499// Used with the ext/Setup file, the --with-setup and
1500// --with-static-linked-ext configuration option, etc.
1501void
1502ruby_init_ext(const char *name, void (*init)(void))
1503{
1504 st_table *inits_table;
1505 rb_vm_t *vm = GET_VM();
1506 const rb_namespace_t *ns = rb_loading_namespace();
1507
1508 if (feature_provided((rb_namespace_t *)ns, name, 0))
1509 return;
1510
1511 inits_table = vm->static_ext_inits;
1512 if (!inits_table) {
1513 inits_table = st_init_strtable();
1514 vm->static_ext_inits = inits_table;
1515 }
1516 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1517}
1518
1519/*
1520 * call-seq:
1521 * mod.autoload(const, filename) -> nil
1522 *
1523 * Registers _filename_ to be loaded (using Kernel::require)
1524 * the first time that _const_ (which may be a String or
1525 * a symbol) is accessed in the namespace of _mod_.
1526 *
1527 * module A
1528 * end
1529 * A.autoload(:B, "b")
1530 * A::B.doit # autoloads "b"
1531 *
1532 * If _const_ in _mod_ is defined as autoload, the file name to be
1533 * loaded is replaced with _filename_. If _const_ is defined but not
1534 * as autoload, does nothing.
1535 *
1536 * Files that are currently being loaded must not be registered for
1537 * autoload.
1538 */
1539
1540static VALUE
1541rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1542{
1543 ID id = rb_to_id(sym);
1544
1545 FilePathValue(file);
1546 rb_autoload_str(mod, id, file);
1547 return Qnil;
1548}
1549
1550/*
1551 * call-seq:
1552 * mod.autoload?(name, inherit=true) -> String or nil
1553 *
1554 * Returns _filename_ to be loaded if _name_ is registered as
1555 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1556 *
1557 * module A
1558 * end
1559 * A.autoload(:B, "b")
1560 * A.autoload?(:B) #=> "b"
1561 *
1562 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1563 *
1564 * class A
1565 * autoload :CONST, "const.rb"
1566 * end
1567 *
1568 * class B < A
1569 * end
1570 *
1571 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1572 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1573 *
1574 */
1575
1576static VALUE
1577rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1578{
1579 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1580 VALUE sym = argv[0];
1581
1582 ID id = rb_check_id(&sym);
1583 if (!id) {
1584 return Qnil;
1585 }
1586 return rb_autoload_at_p(mod, id, recur);
1587}
1588
1589/*
1590 * call-seq:
1591 * autoload(const, filename) -> nil
1592 *
1593 * Registers _filename_ to be loaded (using Kernel::require)
1594 * the first time that _const_ (which may be a String or
1595 * a symbol) is accessed.
1596 *
1597 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1598 *
1599 * If _const_ is defined as autoload, the file name to be loaded is
1600 * replaced with _filename_. If _const_ is defined but not as
1601 * autoload, does nothing.
1602 *
1603 * Files that are currently being loaded must not be registered for
1604 * autoload.
1605 */
1606
1607static VALUE
1608rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1609{
1610 VALUE klass = rb_class_real(rb_vm_cbase());
1611 if (!klass) {
1612 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1613 }
1614 return rb_mod_autoload(klass, sym, file);
1615}
1616
1617/*
1618 * call-seq:
1619 * autoload?(name, inherit=true) -> String or nil
1620 *
1621 * Returns _filename_ to be loaded if _name_ is registered as
1622 * +autoload+ in the current namespace or one of its ancestors.
1623 *
1624 * autoload(:B, "b")
1625 * autoload?(:B) #=> "b"
1626 *
1627 * module C
1628 * autoload(:D, "d")
1629 * autoload?(:D) #=> "d"
1630 * autoload?(:B) #=> nil
1631 * end
1632 *
1633 * class E
1634 * autoload(:F, "f")
1635 * autoload?(:F) #=> "f"
1636 * autoload?(:B) #=> "b"
1637 * end
1638 */
1639
1640static VALUE
1641rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1642{
1643 /* use rb_vm_cbase() as same as rb_f_autoload. */
1644 VALUE klass = rb_vm_cbase();
1645 if (NIL_P(klass)) {
1646 return Qnil;
1647 }
1648 return rb_mod_autoload_p(argc, argv, klass);
1649}
1650
1651void *
1652rb_ext_resolve_symbol(const char* fname, const char* symbol)
1653{
1654 VALUE handle;
1655 VALUE resolved;
1656 VALUE path;
1657 char *ext;
1658 VALUE fname_str = rb_str_new_cstr(fname);
1659 const rb_namespace_t *ns = rb_loading_namespace();
1660
1661 resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1662 if (NIL_P(resolved)) {
1663 ext = strrchr(fname, '.');
1664 if (!ext || !IS_SOEXT(ext)) {
1665 rb_str_cat_cstr(fname_str, ".so");
1666 }
1667 if (rb_feature_p(ns, fname, 0, FALSE, FALSE, 0)) {
1668 return dln_symbol(NULL, symbol);
1669 }
1670 return NULL;
1671 }
1672 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1673 return NULL;
1674 }
1675 path = rb_ary_entry(resolved, 1);
1676 handle = rb_hash_lookup(ns->ruby_dln_libmap, path);
1677 if (NIL_P(handle)) {
1678 return NULL;
1679 }
1680 return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1681}
1682
1683void
1684Init_load(void)
1685{
1686 static const char var_load_path[] = "$:";
1687 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1688
1689 rb_define_hooked_variable(var_load_path, 0, load_path_getter, rb_gvar_readonly_setter);
1690 rb_gvar_namespace_ready(var_load_path);
1691 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1692 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1693
1694 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1695 rb_gvar_namespace_ready("$\"");
1696 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
1697 rb_gvar_namespace_ready("$LOADED_FEATURES");
1698
1699 rb_define_global_function("load", rb_f_load, -1);
1701 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1702 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1703 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1704 rb_define_global_function("autoload", rb_f_autoload, 2);
1705 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1706}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition eval.c:1878
VALUE rb_module_new(void)
Creates a new, anonymous module.
Definition class.c:1583
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 rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:683
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
Definition error.c:3815
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:497
VALUE rb_cModule
Module class.
Definition object.c:62
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:256
VALUE rb_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
Definition object.c:528
Encoding relates APIs.
VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs)
Queries if the passed two arrays share the same backend storage.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Replaces the contents of the former object with the contents of the latter.
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:705
VALUE rb_f_require(VALUE self, VALUE feature)
Identical to rb_require_string(), except it ignores the first argument for no reason.
Definition load.c:1056
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1275
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1446
int rb_feature_provided(const char *feature, const char **loading)
Identical to rb_provided(), except it additionally returns the "canonical" name of the loaded feature...
Definition load.c:676
void rb_load_protect(VALUE path, int wrap, int *state)
Identical to rb_load(), except it avoids potential global escapes.
Definition load.c:875
int rb_provided(const char *feature)
Queries if the given feature has already been loaded into the execution context.
Definition load.c:643
void rb_load(VALUE path, int wrap)
Loads and executes the Ruby program in the given file.
Definition load.c:867
void * rb_ext_resolve_symbol(const char *feature, const char *symbol)
Resolves and returns a symbol of a function in the native extension specified by the feature and symb...
Definition load.c:1652
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3772
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1721
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:3128
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1971
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:1989
VALUE rb_filesystem_str_new_cstr(const char *ptr)
Identical to rb_filesystem_str_new(), except it assumes the passed pointer is a pointer to a C string...
Definition string.c:1414
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4242
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1691
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3253
#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
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition variable.c:1141
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1133
ID rb_to_id(VALUE str)
Definition string.c:12705
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
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 MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
#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 StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1477
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#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
Ruby's String.
Definition rstring.h:196
int32_t line
The line within the file that the parse starts on.
Definition options.h:124
pm_scope_node_t node
The resulting scope node that will hold the generated AST.
pm_options_t options
The options that will be passed to the parser.
Internal header for Namespace.
Definition namespace.h:14
Definition st.h:79
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
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 void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
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