Ruby 3.5.0dev (2025-11-03 revision 4a3d8346a6d0e068508631541f6bc43e8b154ea1)
load.c (4a3d8346a6d0e068508631541f6bc43e8b154ea1)
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 VALUE
1216run_static_ext_init(VALUE vm_ptr, VALUE feature_value)
1217{
1218 rb_vm_t *vm = (rb_vm_t *)vm_ptr;
1219 const char *feature = RSTRING_PTR(feature_value);
1220 st_data_t key = (st_data_t)feature;
1221 st_data_t init_func;
1222
1223 if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1224 ((void (*)(void))init_func)();
1225 return Qtrue;
1226 }
1227 return Qfalse;
1228}
1229
1230static int
1231no_feature_p(const rb_namespace_t *ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1232{
1233 return 0;
1234}
1235
1236// Documented in doc/globals.md
1237VALUE
1238rb_resolve_feature_path(VALUE klass, VALUE fname)
1239{
1240 VALUE path;
1241 int found;
1242 VALUE sym;
1243 const rb_namespace_t *ns = rb_loading_namespace();
1244
1245 fname = rb_get_path(fname);
1246 path = rb_str_encode_ospath(fname);
1247 found = search_required(ns, path, &path, no_feature_p);
1248
1249 switch (found) {
1250 case 'r':
1251 sym = ID2SYM(rb_intern("rb"));
1252 break;
1253 case 's':
1254 sym = ID2SYM(rb_intern("so"));
1255 break;
1256 default:
1257 return Qnil;
1258 }
1259
1260 return rb_ary_new_from_args(2, sym, path);
1261}
1262
1263static void
1264ext_config_push(rb_thread_t *th, volatile struct rb_ext_config *prev)
1265{
1266 *prev = th->ext_config;
1267 th->ext_config = (struct rb_ext_config){0};
1268}
1269
1270static void
1271ext_config_pop(rb_thread_t *th, volatile struct rb_ext_config *prev)
1272{
1273 th->ext_config = *prev;
1274}
1275
1276void
1278{
1279 GET_THREAD()->ext_config.ractor_safe = flag;
1280}
1281
1282/*
1283 * returns
1284 * 0: if already loaded (false)
1285 * 1: successfully loaded (true)
1286 * <0: not found (LoadError)
1287 * >1: exception
1288 */
1289static int
1290require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1291{
1292 volatile int result = -1;
1293 rb_thread_t *th = rb_ec_thread_ptr(ec);
1294 const rb_namespace_t *ns = rb_loading_namespace();
1295 volatile const struct {
1296 VALUE wrapper, self, errinfo;
1298 const rb_namespace_t *ns;
1299 } saved = {
1300 th->top_wrapper, th->top_self, ec->errinfo,
1301 ec, ns,
1302 };
1303 enum ruby_tag_type state;
1304 char *volatile ftptr = 0;
1305 VALUE path;
1306 volatile VALUE saved_path;
1307 volatile VALUE realpath = 0;
1308 VALUE realpaths = ns->loaded_features_realpaths;
1309 VALUE realpath_map = ns->loaded_features_realpath_map;
1310 volatile bool reset_ext_config = false;
1311 volatile struct rb_ext_config prev_ext_config;
1312
1313 path = rb_str_encode_ospath(fname);
1314 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1315 saved_path = path;
1316
1317 EC_PUSH_TAG(ec);
1318 ec->errinfo = Qnil; /* ensure */
1319 th->top_wrapper = 0;
1320 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1321 VALUE handle;
1322 int found;
1323
1324 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1325 found = search_required(ns, path, &saved_path, rb_feature_p);
1326 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1327 path = saved_path;
1328
1329 if (found) {
1330 if (!path || !(ftptr = load_lock(ns, RSTRING_PTR(path), warn))) {
1331 result = 0;
1332 }
1333 else if (!*ftptr) {
1334 result = TAG_RETURN;
1335 }
1336 else if (found == 's' && RTEST(rb_vm_call_cfunc_in_namespace(Qnil, run_static_ext_init, (VALUE)th->vm, path, path, ns))) {
1337 result = TAG_RETURN;
1338 }
1339 else if (RTEST(rb_hash_aref(realpaths,
1340 realpath = realpath_internal_cached(realpath_map, path)))) {
1341 result = 0;
1342 }
1343 else {
1344 switch (found) {
1345 case 'r':
1346 // iseq_eval_in_namespace will be called with the loading namespace eventually
1347 if (NAMESPACE_OPTIONAL_P(ns)) {
1348 // check with NAMESPACE_OPTIONAL_P (not NAMESPACE_USER_P) for NS1::xxx naming
1349 // it is not expected for the main namespace
1350 load_wrapping(saved.ec, path, ns->ns_object);
1351 }
1352 else {
1353 load_iseq_eval(saved.ec, path);
1354 }
1355 break;
1356
1357 case 's':
1358 reset_ext_config = true;
1359 ext_config_push(th, &prev_ext_config);
1360 handle = rb_vm_call_cfunc_in_namespace(ns->top_self, load_ext, path, fname, path, ns);
1361 rb_hash_aset(ns->ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1362 break;
1363 }
1364 result = TAG_RETURN;
1365 }
1366 }
1367 }
1368 EC_POP_TAG();
1369
1370 ec = saved.ec;
1371 ns = saved.ns;
1372 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1373 th2->top_self = saved.self;
1374 th2->top_wrapper = saved.wrapper;
1375 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1376
1377 path = saved_path;
1378 if (ftptr) load_unlock(ns, RSTRING_PTR(path), !state);
1379
1380 if (state) {
1381 if (state == TAG_FATAL || state == TAG_THROW) {
1382 EC_JUMP_TAG(ec, state);
1383 }
1384 else if (exception) {
1385 /* usually state == TAG_RAISE only, except for
1386 * rb_iseq_load_iseq in load_iseq_eval case */
1387 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1388 if (!NIL_P(exc)) ec->errinfo = exc;
1389 return TAG_RAISE;
1390 }
1391 else if (state == TAG_RETURN) {
1392 return TAG_RAISE;
1393 }
1394 RB_GC_GUARD(fname);
1395 /* never TAG_RETURN */
1396 return state;
1397 }
1398 if (!NIL_P(ec->errinfo)) {
1399 if (!exception) return TAG_RAISE;
1400 rb_exc_raise(ec->errinfo);
1401 }
1402
1403 if (result == TAG_RETURN) {
1404 rb_provide_feature(ns, path);
1405 VALUE real = realpath;
1406 if (real) {
1407 real = rb_fstring(real);
1408 rb_hash_aset(realpaths, real, Qtrue);
1409 }
1410 }
1411 ec->errinfo = saved.errinfo;
1412
1413 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1414
1415 return result;
1416}
1417
1418int
1419rb_require_internal_silent(VALUE fname)
1420{
1421 if (!rb_ractor_main_p()) {
1422 return NUM2INT(rb_ractor_require(fname, true));
1423 }
1424
1425 rb_execution_context_t *ec = GET_EC();
1426 return require_internal(ec, fname, 1, false);
1427}
1428
1429int
1430rb_require_internal(VALUE fname)
1431{
1432 rb_execution_context_t *ec = GET_EC();
1433 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1434}
1435
1436int
1437ruby_require_internal(const char *fname, unsigned int len)
1438{
1439 struct RString fake = {RBASIC_INIT};
1440 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1441 rb_execution_context_t *ec = GET_EC();
1442 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1443 rb_set_errinfo(Qnil);
1444 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1445}
1446
1447VALUE
1449{
1450 return rb_require_string_internal(FilePathValue(fname), false);
1451}
1452
1453static VALUE
1454rb_require_string_internal(VALUE fname, bool resurrect)
1455{
1456 rb_execution_context_t *ec = GET_EC();
1457
1458 // main ractor check
1459 if (!rb_ractor_main_p()) {
1460 if (resurrect) fname = rb_str_resurrect(fname);
1461 return rb_ractor_require(fname, false);
1462 }
1463 else {
1464 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1465
1466 if (result > TAG_RETURN) {
1467 EC_JUMP_TAG(ec, result);
1468 }
1469 if (result < 0) {
1470 if (resurrect) fname = rb_str_resurrect(fname);
1471 load_failed(fname);
1472 }
1473
1474 return RBOOL(result);
1475 }
1476}
1477
1478VALUE
1479rb_require(const char *fname)
1480{
1481 struct RString fake = {RBASIC_INIT};
1482 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1483 return rb_require_string_internal(str, true);
1484}
1485
1486static int
1487register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1488{
1489 const char *name = (char *)*key;
1490 if (existing) {
1491 /* already registered */
1492 rb_warn("%s is already registered", name);
1493 }
1494 else {
1495 *value = (st_data_t)init;
1496 }
1497 return ST_CONTINUE;
1498}
1499
1500// Private API for statically linked extensions.
1501// Used with the ext/Setup file, the --with-setup and
1502// --with-static-linked-ext configuration option, etc.
1503void
1504ruby_init_ext(const char *name, void (*init)(void))
1505{
1506 st_table *inits_table;
1507 rb_vm_t *vm = GET_VM();
1508 const rb_namespace_t *ns = rb_loading_namespace();
1509
1510 if (feature_provided((rb_namespace_t *)ns, name, 0))
1511 return;
1512
1513 inits_table = vm->static_ext_inits;
1514 if (!inits_table) {
1515 inits_table = st_init_strtable();
1516 vm->static_ext_inits = inits_table;
1517 }
1518 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1519}
1520
1521/*
1522 * call-seq:
1523 * mod.autoload(const, filename) -> nil
1524 *
1525 * Registers _filename_ to be loaded (using Kernel::require)
1526 * the first time that _const_ (which may be a String or
1527 * a symbol) is accessed in the namespace of _mod_.
1528 *
1529 * module A
1530 * end
1531 * A.autoload(:B, "b")
1532 * A::B.doit # autoloads "b"
1533 *
1534 * If _const_ in _mod_ is defined as autoload, the file name to be
1535 * loaded is replaced with _filename_. If _const_ is defined but not
1536 * as autoload, does nothing.
1537 *
1538 * Files that are currently being loaded must not be registered for
1539 * autoload.
1540 */
1541
1542static VALUE
1543rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1544{
1545 ID id = rb_to_id(sym);
1546
1547 FilePathValue(file);
1548 rb_autoload_str(mod, id, file);
1549 return Qnil;
1550}
1551
1552/*
1553 * call-seq:
1554 * mod.autoload?(name, inherit=true) -> String or nil
1555 *
1556 * Returns _filename_ to be loaded if _name_ is registered as
1557 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1558 *
1559 * module A
1560 * end
1561 * A.autoload(:B, "b")
1562 * A.autoload?(:B) #=> "b"
1563 *
1564 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1565 *
1566 * class A
1567 * autoload :CONST, "const.rb"
1568 * end
1569 *
1570 * class B < A
1571 * end
1572 *
1573 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1574 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1575 *
1576 */
1577
1578static VALUE
1579rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1580{
1581 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1582 VALUE sym = argv[0];
1583
1584 ID id = rb_check_id(&sym);
1585 if (!id) {
1586 return Qnil;
1587 }
1588 return rb_autoload_at_p(mod, id, recur);
1589}
1590
1591/*
1592 * call-seq:
1593 * autoload(const, filename) -> nil
1594 *
1595 * Registers _filename_ to be loaded (using Kernel::require)
1596 * the first time that _const_ (which may be a String or
1597 * a symbol) is accessed.
1598 *
1599 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1600 *
1601 * If _const_ is defined as autoload, the file name to be loaded is
1602 * replaced with _filename_. If _const_ is defined but not as
1603 * autoload, does nothing.
1604 *
1605 * Files that are currently being loaded must not be registered for
1606 * autoload.
1607 */
1608
1609static VALUE
1610rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1611{
1612 VALUE klass = rb_class_real(rb_vm_cbase());
1613 if (!klass) {
1614 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1615 }
1616 return rb_mod_autoload(klass, sym, file);
1617}
1618
1619/*
1620 * call-seq:
1621 * autoload?(name, inherit=true) -> String or nil
1622 *
1623 * Returns _filename_ to be loaded if _name_ is registered as
1624 * +autoload+ in the current namespace or one of its ancestors.
1625 *
1626 * autoload(:B, "b")
1627 * autoload?(:B) #=> "b"
1628 *
1629 * module C
1630 * autoload(:D, "d")
1631 * autoload?(:D) #=> "d"
1632 * autoload?(:B) #=> nil
1633 * end
1634 *
1635 * class E
1636 * autoload(:F, "f")
1637 * autoload?(:F) #=> "f"
1638 * autoload?(:B) #=> "b"
1639 * end
1640 */
1641
1642static VALUE
1643rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1644{
1645 /* use rb_vm_cbase() as same as rb_f_autoload. */
1646 VALUE klass = rb_vm_cbase();
1647 if (NIL_P(klass)) {
1648 return Qnil;
1649 }
1650 return rb_mod_autoload_p(argc, argv, klass);
1651}
1652
1653void *
1654rb_ext_resolve_symbol(const char* fname, const char* symbol)
1655{
1656 VALUE handle;
1657 VALUE resolved;
1658 VALUE path;
1659 char *ext;
1660 VALUE fname_str = rb_str_new_cstr(fname);
1661 const rb_namespace_t *ns = rb_loading_namespace();
1662
1663 resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1664 if (NIL_P(resolved)) {
1665 ext = strrchr(fname, '.');
1666 if (!ext || !IS_SOEXT(ext)) {
1667 rb_str_cat_cstr(fname_str, ".so");
1668 }
1669 if (rb_feature_p(ns, fname, 0, FALSE, FALSE, 0)) {
1670 return dln_symbol(NULL, symbol);
1671 }
1672 return NULL;
1673 }
1674 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1675 return NULL;
1676 }
1677 path = rb_ary_entry(resolved, 1);
1678 handle = rb_hash_lookup(ns->ruby_dln_libmap, path);
1679 if (NIL_P(handle)) {
1680 return NULL;
1681 }
1682 return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1683}
1684
1685void
1686Init_load(void)
1687{
1688 static const char var_load_path[] = "$:";
1689 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1690
1691 rb_define_hooked_variable(var_load_path, 0, load_path_getter, rb_gvar_readonly_setter);
1692 rb_gvar_namespace_ready(var_load_path);
1693 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1694 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1695
1696 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1697 rb_gvar_namespace_ready("$\"");
1698 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
1699 rb_gvar_namespace_ready("$LOADED_FEATURES");
1700
1701 rb_define_global_function("load", rb_f_load, -1);
1703 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1704 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1705 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1706 rb_define_global_function("autoload", rb_f_autoload, 2);
1707 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1708}
#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:1697
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:3252
#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:1277
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1448
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:1654
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:3791
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1740
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:3147
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1990
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:2008
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:1423
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4261
#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:3272
#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:1142
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:12559
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:1479
#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