Ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e0ba6b95ab71a441357ed5484e33498)
load.c
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/file.h"
11#include "internal/load.h"
12#include "internal/parse.h"
13#include "internal/thread.h"
14#include "internal/variable.h"
15#include "iseq.h"
16#include "probes.h"
17#include "ruby/encoding.h"
18#include "ruby/util.h"
19
20static VALUE ruby_dln_librefs;
21
22#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
23#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
24#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
25
26static const char *const loadable_ext[] = {
27 ".rb", DLEXT,
28 0
29};
30
31static const char *const ruby_ext[] = {
32 ".rb",
33 0
34};
35
36enum expand_type {
37 EXPAND_ALL,
38 EXPAND_RELATIVE,
39 EXPAND_HOME,
40 EXPAND_NON_CACHE
41};
42
43/* Construct expanded load path and store it to cache.
44 We rebuild load path partially if the cache is invalid.
45 We don't cache non string object and expand it every time. We ensure that
46 string objects in $LOAD_PATH are frozen.
47 */
48static void
49rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache)
50{
51 VALUE load_path = vm->load_path;
52 VALUE expanded_load_path = vm->expanded_load_path;
53 VALUE ary;
54 long i;
55
56 ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
57 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
58 VALUE path, as_str, expanded_path;
59 int is_string, non_cache;
60 char *as_cstr;
61 as_str = path = RARRAY_AREF(load_path, i);
62 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
63 non_cache = !is_string ? 1 : 0;
64 as_str = rb_get_path_check_to_string(path);
65 as_cstr = RSTRING_PTR(as_str);
66
67 if (!non_cache) {
68 if ((type == EXPAND_RELATIVE &&
69 rb_is_absolute_path(as_cstr)) ||
70 (type == EXPAND_HOME &&
71 (!as_cstr[0] || as_cstr[0] != '~')) ||
72 (type == EXPAND_NON_CACHE)) {
73 /* Use cached expanded path. */
74 rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
75 continue;
76 }
77 }
78 if (!*has_relative && !rb_is_absolute_path(as_cstr))
79 *has_relative = 1;
80 if (!*has_non_cache && non_cache)
81 *has_non_cache = 1;
82 /* Freeze only string object. We expand other objects every time. */
83 if (is_string)
84 rb_str_freeze(path);
85 as_str = rb_get_path_check_convert(as_str);
86 expanded_path = rb_check_realpath(Qnil, as_str, NULL);
87 if (NIL_P(expanded_path)) expanded_path = as_str;
88 rb_ary_push(ary, rb_fstring(expanded_path));
89 }
90 rb_obj_freeze(ary);
91 vm->expanded_load_path = ary;
92 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
93}
94
95static VALUE
96get_expanded_load_path(rb_vm_t *vm)
97{
98 const VALUE non_cache = Qtrue;
99
100 if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
101 /* The load path was modified. Rebuild the expanded load path. */
102 int has_relative = 0, has_non_cache = 0;
103 rb_construct_expanded_load_path(vm, EXPAND_ALL, &has_relative, &has_non_cache);
104 if (has_relative) {
105 vm->load_path_check_cache = rb_dir_getwd_ospath();
106 }
107 else if (has_non_cache) {
108 /* Non string object. */
109 vm->load_path_check_cache = non_cache;
110 }
111 else {
112 vm->load_path_check_cache = 0;
113 }
114 }
115 else if (vm->load_path_check_cache == non_cache) {
116 int has_relative = 1, has_non_cache = 1;
117 /* Expand only non-cacheable objects. */
118 rb_construct_expanded_load_path(vm, EXPAND_NON_CACHE,
119 &has_relative, &has_non_cache);
120 }
121 else if (vm->load_path_check_cache) {
122 int has_relative = 1, has_non_cache = 1;
123 VALUE cwd = rb_dir_getwd_ospath();
124 if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
125 /* Current working directory or filesystem encoding was changed.
126 Expand relative load path and non-cacheable objects again. */
127 vm->load_path_check_cache = cwd;
128 rb_construct_expanded_load_path(vm, EXPAND_RELATIVE,
129 &has_relative, &has_non_cache);
130 }
131 else {
132 /* Expand only tilde (User HOME) and non-cacheable objects. */
133 rb_construct_expanded_load_path(vm, EXPAND_HOME,
134 &has_relative, &has_non_cache);
135 }
136 }
137 return vm->expanded_load_path;
138}
139
140VALUE
141rb_get_expanded_load_path(void)
142{
143 return get_expanded_load_path(GET_VM());
144}
145
146static VALUE
147load_path_getter(ID id, VALUE * p)
148{
149 rb_vm_t *vm = (void *)p;
150 return vm->load_path;
151}
152
153static VALUE
154get_loaded_features(rb_vm_t *vm)
155{
156 return vm->loaded_features;
157}
158
159static VALUE
160get_loaded_features_realpaths(rb_vm_t *vm)
161{
162 return vm->loaded_features_realpaths;
163}
164
165static VALUE
166get_LOADED_FEATURES(ID _x, VALUE *_y)
167{
168 return get_loaded_features(GET_VM());
169}
170
171static void
172reset_loaded_features_snapshot(rb_vm_t *vm)
173{
174 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
175}
176
177static struct st_table *
178get_loaded_features_index_raw(rb_vm_t *vm)
179{
180 return vm->loaded_features_index;
181}
182
183static st_table *
184get_loading_table(rb_vm_t *vm)
185{
186 return vm->loading_table;
187}
188
189static st_data_t
190feature_key(const char *str, size_t len)
191{
192 return st_hash(str, len, 0xfea7009e);
193}
194
195static bool
196is_rbext_path(VALUE feature_path)
197{
198 long len = RSTRING_LEN(feature_path);
199 long rbext_len = rb_strlen_lit(".rb");
200 if (len <= rbext_len) return false;
201 return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
202}
203
204static void
205features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb)
206{
207 struct st_table *features_index;
208 VALUE this_feature_index = Qnil;
209 st_data_t short_feature_key;
210 st_data_t data;
211
212 Check_Type(offset, T_FIXNUM);
213 short_feature_key = feature_key(str, len);
214
215 features_index = get_loaded_features_index_raw(vm);
216 if (!st_lookup(features_index, short_feature_key, &data) ||
217 NIL_P(this_feature_index = (VALUE)data)) {
218 st_insert(features_index, short_feature_key, (st_data_t)offset);
219 }
220 else if (FIXNUM_P(this_feature_index)) {
221 VALUE loaded_features = get_loaded_features(vm);
222 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
223 VALUE feature_indexes[2];
224 int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
225 feature_indexes[top^0] = this_feature_index;
226 feature_indexes[top^1] = offset;
227 this_feature_index = (VALUE)xcalloc(1, sizeof(struct RArray));
228 RBASIC(this_feature_index)->flags = T_ARRAY; /* fake VALUE, do not mark/sweep */
229 rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes));
230 st_insert(features_index, short_feature_key, (st_data_t)this_feature_index);
231 }
232 else {
233 long pos = -1;
234
235 Check_Type(this_feature_index, T_ARRAY);
236 if (rb) {
237 VALUE loaded_features = get_loaded_features(vm);
238 for (long i = 0; i < RARRAY_LEN(this_feature_index); ++i) {
239 VALUE idx = RARRAY_AREF(this_feature_index, i);
240 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(idx));
241 Check_Type(this_feature_path, T_STRING);
242 if (!is_rbext_path(this_feature_path)) {
243 /* as this_feature_index is a fake VALUE, `push` (which
244 * doesn't wb_unprotect like as rb_ary_splice) first,
245 * then rotate partially. */
246 pos = i;
247 break;
248 }
249 }
250 }
251 rb_ary_push(this_feature_index, offset);
252 if (pos >= 0) {
253 VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(this_feature_index);
254 long len = RARRAY_LEN(this_feature_index);
255 MEMMOVE(ptr + pos, ptr + pos + 1, VALUE, len - pos - 1);
256 ptr[pos] = offset;
257 }
258 }
259}
260
261/* Add to the loaded-features index all the required entries for
262 `feature`, located at `offset` in $LOADED_FEATURES. We add an
263 index entry at each string `short_feature` for which
264 feature == "#{prefix}#{short_feature}#{ext}"
265 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
266 or ends in '/'. This maintains the invariant that `rb_feature_p()`
267 relies on for its fast lookup.
268*/
269static void
270features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
271{
272 const char *feature_str, *feature_end, *ext, *p;
273 bool rb = false;
274
275 feature_str = StringValuePtr(feature);
276 feature_end = feature_str + RSTRING_LEN(feature);
277
278 for (ext = feature_end; ext > feature_str; ext--)
279 if (*ext == '.' || *ext == '/')
280 break;
281 if (*ext != '.')
282 ext = NULL;
283 else
284 rb = IS_RBEXT(ext);
285 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
286 at the end of `feature`, or is NULL if there is no such string. */
287
288 p = ext ? ext : feature_end;
289 while (1) {
290 p--;
291 while (p >= feature_str && *p != '/')
292 p--;
293 if (p < feature_str)
294 break;
295 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
296 features_index_add_single(vm, p + 1, feature_end - p - 1, offset, false);
297 if (ext) {
298 features_index_add_single(vm, p + 1, ext - p - 1, offset, rb);
299 }
300 }
301 features_index_add_single(vm, feature_str, feature_end - feature_str, offset, false);
302 if (ext) {
303 features_index_add_single(vm, feature_str, ext - feature_str, offset, rb);
304 }
305}
306
307static int
308loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
309{
310 VALUE obj = (VALUE)val;
311 if (!SPECIAL_CONST_P(obj)) {
312 rb_ary_free(obj);
313 ruby_sized_xfree((void *)obj, sizeof(struct RArray));
314 }
315 return ST_DELETE;
316}
317
318static st_table *
319get_loaded_features_index(rb_vm_t *vm)
320{
321 VALUE features;
322 int i;
323
324 if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
325 /* The sharing was broken; something (other than us in rb_provide_feature())
326 modified loaded_features. Rebuild the index. */
327 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
328
329 VALUE realpaths = vm->loaded_features_realpaths;
330 rb_hash_clear(realpaths);
331 features = vm->loaded_features;
332 for (i = 0; i < RARRAY_LEN(features); i++) {
333 VALUE entry, as_str;
334 as_str = entry = rb_ary_entry(features, i);
335 StringValue(as_str);
336 as_str = rb_fstring(rb_str_freeze(as_str));
337 if (as_str != entry)
338 rb_ary_store(features, i, as_str);
339 features_index_add(vm, as_str, INT2FIX(i));
340 }
341 reset_loaded_features_snapshot(vm);
342
343 features = rb_ary_dup(vm->loaded_features_snapshot);
344 long j = RARRAY_LEN(features);
345 for (i = 0; i < j; i++) {
346 VALUE as_str = rb_ary_entry(features, i);
347 VALUE realpath = rb_check_realpath(Qnil, as_str, NULL);
348 if (NIL_P(realpath)) realpath = as_str;
349 rb_hash_aset(realpaths, rb_fstring(realpath), Qtrue);
350 }
351 }
352 return vm->loaded_features_index;
353}
354
355/* This searches `load_path` for a value such that
356 name == "#{load_path[i]}/#{feature}"
357 if `feature` is a suffix of `name`, or otherwise
358 name == "#{load_path[i]}/#{feature}#{ext}"
359 for an acceptable string `ext`. It returns
360 `load_path[i].to_str` if found, else 0.
361
362 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
363 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
364 or have any value matching `%r{^\.[^./]*$}`.
365*/
366static VALUE
367loaded_feature_path(const char *name, long vlen, const char *feature, long len,
368 int type, VALUE load_path)
369{
370 long i;
371 long plen;
372 const char *e;
373
374 if (vlen < len+1) return 0;
375 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
376 plen = vlen - len;
377 }
378 else {
379 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
380 if (*e != '.' ||
381 e-name < len ||
382 strncmp(e-len, feature, len))
383 return 0;
384 plen = e - name - len;
385 }
386 if (plen > 0 && name[plen-1] != '/') {
387 return 0;
388 }
389 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
390 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
391 0) {
392 return 0;
393 }
394 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
395 (possibly empty) and prefix is some string of length plen. */
396
397 if (plen > 0) --plen; /* exclude '.' */
398 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
399 VALUE p = RARRAY_AREF(load_path, i);
400 const char *s = StringValuePtr(p);
401 long n = RSTRING_LEN(p);
402
403 if (n != plen) continue;
404 if (n && strncmp(name, s, n)) continue;
405 return p;
406 }
407 return 0;
408}
409
411 const char *name;
412 long len;
413 int type;
414 VALUE load_path;
415 const char *result;
416};
417
418static int
419loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
420{
421 const char *s = (const char *)v;
422 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
423 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
424 fp->type, fp->load_path);
425 if (!p) return ST_CONTINUE;
426 fp->result = s;
427 return ST_STOP;
428}
429
430static int
431rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
432{
433 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
434 const char *f, *e;
435 long i, len, elen, n;
436 st_table *loading_tbl, *features_index;
437 st_data_t data;
438 st_data_t key;
439 int type;
440
441 if (fn) *fn = 0;
442 if (ext) {
443 elen = strlen(ext);
444 len = strlen(feature) - elen;
445 type = rb ? 'r' : 's';
446 }
447 else {
448 len = strlen(feature);
449 elen = 0;
450 type = 0;
451 }
452 features = get_loaded_features(vm);
453 features_index = get_loaded_features_index(vm);
454
455 key = feature_key(feature, strlen(feature));
456 /* We search `features` for an entry such that either
457 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
458 for some j, or
459 "#{features[i]}" == "#{feature}#{e}"
460 Here `e` is an "allowed" extension -- either empty or one
461 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
462 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
463 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
464
465 If `expanded`, then only the latter form (without load_path[j])
466 is accepted. Otherwise either form is accepted, *unless* `ext`
467 is false and an otherwise-matching entry of the first form is
468 preceded by an entry of the form
469 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
470 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
471 After a "distractor" entry of this form, only entries of the
472 form "#{feature}#{e}" are accepted.
473
474 In `rb_provide_feature()` and `get_loaded_features_index()` we
475 maintain an invariant that the array `this_feature_index` will
476 point to every entry in `features` which has the form
477 "#{prefix}#{feature}#{e}"
478 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
479 or ends in '/'. This includes both match forms above, as well
480 as any distractors, so we may ignore all other entries in `features`.
481 */
482 if (st_lookup(features_index, key, &data) && !NIL_P(this_feature_index = (VALUE)data)) {
483 for (i = 0; ; i++) {
484 VALUE entry;
485 long index;
486 if (RB_TYPE_P(this_feature_index, T_ARRAY)) {
487 if (i >= RARRAY_LEN(this_feature_index)) break;
488 entry = RARRAY_AREF(this_feature_index, i);
489 }
490 else {
491 if (i > 0) break;
492 entry = this_feature_index;
493 }
494 index = FIX2LONG(entry);
495
496 v = RARRAY_AREF(features, index);
497 f = StringValuePtr(v);
498 if ((n = RSTRING_LEN(v)) < len) continue;
499 if (strncmp(f, feature, len) != 0) {
500 if (expanded) continue;
501 if (!load_path) load_path = get_expanded_load_path(vm);
502 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
503 continue;
504 expanded = 1;
505 f += RSTRING_LEN(p) + 1;
506 }
507 if (!*(e = f + len)) {
508 if (ext) continue;
509 return 'u';
510 }
511 if (*e != '.') continue;
512 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
513 return 's';
514 }
515 if ((rb || !ext) && (IS_RBEXT(e))) {
516 return 'r';
517 }
518 }
519 }
520
521 loading_tbl = get_loading_table(vm);
522 f = 0;
523 if (!expanded) {
524 struct loaded_feature_searching fs;
525 fs.name = feature;
526 fs.len = len;
527 fs.type = type;
528 fs.load_path = load_path ? load_path : get_expanded_load_path(vm);
529 fs.result = 0;
530 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
531 if ((f = fs.result) != 0) {
532 if (fn) *fn = f;
533 goto loading;
534 }
535 }
536 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
537 if (fn) *fn = (const char*)data;
538 goto loading;
539 }
540 else {
541 VALUE bufstr;
542 char *buf;
543 static const char so_ext[][4] = {
544 ".so", ".o",
545 };
546
547 if (ext && *ext) return 0;
548 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
549 buf = RSTRING_PTR(bufstr);
550 MEMCPY(buf, feature, char, len);
551 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
552 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
553 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
554 rb_str_resize(bufstr, 0);
555 if (fn) *fn = (const char*)data;
556 return i ? 's' : 'r';
557 }
558 }
559 for (i = 0; i < numberof(so_ext); i++) {
560 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
561 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
562 rb_str_resize(bufstr, 0);
563 if (fn) *fn = (const char*)data;
564 return 's';
565 }
566 }
567 rb_str_resize(bufstr, 0);
568 }
569 return 0;
570
571 loading:
572 if (!ext) return 'u';
573 return !IS_RBEXT(ext) ? 's' : 'r';
574}
575
576int
577rb_provided(const char *feature)
578{
579 return rb_feature_provided(feature, 0);
580}
581
582static int
583feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
584{
585 const char *ext = strrchr(feature, '.');
586 VALUE fullpath = 0;
587
588 if (*feature == '.' &&
589 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
590 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
591 feature = RSTRING_PTR(fullpath);
592 }
593 if (ext && !strchr(ext, '/')) {
594 if (IS_RBEXT(ext)) {
595 if (rb_feature_p(vm, feature, ext, TRUE, FALSE, loading)) return TRUE;
596 return FALSE;
597 }
598 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
599 if (rb_feature_p(vm, feature, ext, FALSE, FALSE, loading)) return TRUE;
600 return FALSE;
601 }
602 }
603 if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
604 return TRUE;
605 RB_GC_GUARD(fullpath);
606 return FALSE;
607}
608
609int
610rb_feature_provided(const char *feature, const char **loading)
611{
612 return feature_provided(GET_VM(), feature, loading);
613}
614
615static void
616rb_provide_feature(rb_vm_t *vm, VALUE feature)
617{
618 VALUE features;
619
620 features = get_loaded_features(vm);
621 if (OBJ_FROZEN(features)) {
622 rb_raise(rb_eRuntimeError,
623 "$LOADED_FEATURES is frozen; cannot append feature");
624 }
625 rb_str_freeze(feature);
626
627 get_loaded_features_index(vm);
628 // If loaded_features and loaded_features_snapshot share the same backing
629 // array, pushing into it would cause the whole array to be copied.
630 // To avoid this we first clear loaded_features_snapshot.
631 rb_ary_clear(vm->loaded_features_snapshot);
632 rb_ary_push(features, rb_fstring(feature));
633 features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
634 reset_loaded_features_snapshot(vm);
635}
636
637void
638rb_provide(const char *feature)
639{
640 rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
641}
642
643NORETURN(static void load_failed(VALUE));
644
645static inline void
646load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
647{
648 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
649
650 if (!iseq) {
651 rb_ast_t *ast;
652 VALUE parser = rb_parser_new();
653 rb_parser_set_context(parser, NULL, FALSE);
654 ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
655 iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
656 fname, rb_realpath_internal(Qnil, fname, 1), NULL);
657 rb_ast_dispose(ast);
658 }
659 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
660 rb_iseq_eval(iseq);
661}
662
663static inline enum ruby_tag_type
664load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
665{
666 enum ruby_tag_type state;
667 rb_thread_t *th = rb_ec_thread_ptr(ec);
668 volatile VALUE wrapper = th->top_wrapper;
669 volatile VALUE self = th->top_self;
670#if !defined __GNUC__
671 rb_thread_t *volatile th0 = th;
672#endif
673
674 ec->errinfo = Qnil; /* ensure */
675
676 /* load in module as toplevel */
677 th->top_self = rb_obj_clone(rb_vm_top_self());
678 th->top_wrapper = load_wrapper;
679 rb_extend_object(th->top_self, th->top_wrapper);
680
681 EC_PUSH_TAG(ec);
682 state = EC_EXEC_TAG();
683 if (state == TAG_NONE) {
684 load_iseq_eval(ec, fname);
685 }
686 EC_POP_TAG();
687
688#if !defined __GNUC__
689 th = th0;
690 fname = RB_GC_GUARD(fname);
691#endif
692 th->top_self = self;
693 th->top_wrapper = wrapper;
694 return state;
695}
696
697static inline void
698raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
699{
700 if (state) {
701 rb_vm_jump_tag_but_local_jump(state);
702 }
703
704 if (!NIL_P(ec->errinfo)) {
705 rb_exc_raise(ec->errinfo);
706 }
707}
708
709static void
710rb_load_internal(VALUE fname, VALUE wrap)
711{
712 rb_execution_context_t *ec = GET_EC();
713 enum ruby_tag_type state = TAG_NONE;
714 if (RTEST(wrap)) {
715 if (!RB_TYPE_P(wrap, T_MODULE)) {
716 wrap = rb_module_new();
717 }
718 state = load_wrapping(ec, fname, wrap);
719 }
720 else {
721 load_iseq_eval(ec, fname);
722 }
723 raise_load_if_failed(ec, state);
724}
725
726void
727rb_load(VALUE fname, int wrap)
728{
729 VALUE tmp = rb_find_file(FilePathValue(fname));
730 if (!tmp) load_failed(fname);
731 rb_load_internal(tmp, RBOOL(wrap));
732}
733
734void
735rb_load_protect(VALUE fname, int wrap, int *pstate)
736{
737 enum ruby_tag_type state;
738
739 EC_PUSH_TAG(GET_EC());
740 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
741 rb_load(fname, wrap);
742 }
743 EC_POP_TAG();
744
745 if (state != TAG_NONE) *pstate = state;
746}
747
748/*
749 * call-seq:
750 * load(filename, wrap=false) -> true
751 *
752 * Loads and executes the Ruby program in the file _filename_.
753 *
754 * If the filename is an absolute path (e.g. starts with '/'), the file
755 * will be loaded directly using the absolute path.
756 *
757 * If the filename is an explicit relative path (e.g. starts with './' or
758 * '../'), the file will be loaded using the relative path from the current
759 * directory.
760 *
761 * Otherwise, the file will be searched for in the library
762 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
763 * If the file is found in a directory, it will attempt to load the file
764 * relative to that directory. If the file is not found in any of the
765 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
766 * the relative path from the current directory.
767 *
768 * If the file doesn't exist when there is an attempt to load it, a
769 * LoadError will be raised.
770 *
771 * If the optional _wrap_ parameter is +true+, the loaded script will
772 * be executed under an anonymous module, protecting the calling
773 * program's global namespace. If the optional _wrap_ parameter is a
774 * module, the loaded script will be executed under the given module.
775 * In no circumstance will any local variables in the loaded file be
776 * propagated to the loading environment.
777 */
778
779static VALUE
780rb_f_load(int argc, VALUE *argv, VALUE _)
781{
782 VALUE fname, wrap, path, orig_fname;
783
784 rb_scan_args(argc, argv, "11", &fname, &wrap);
785
786 orig_fname = rb_get_path_check_to_string(fname);
787 fname = rb_str_encode_ospath(orig_fname);
788 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
789
790 path = rb_find_file(fname);
791 if (!path) {
792 if (!rb_file_load_ok(RSTRING_PTR(fname)))
793 load_failed(orig_fname);
794 path = fname;
795 }
796 rb_load_internal(path, wrap);
797
798 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
799
800 return Qtrue;
801}
802
803static char *
804load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
805{
806 st_data_t data;
807 st_table *loading_tbl = get_loading_table(vm);
808
809 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
810 /* partial state */
811 ftptr = ruby_strdup(ftptr);
812 data = (st_data_t)rb_thread_shield_new();
813 st_insert(loading_tbl, (st_data_t)ftptr, data);
814 return (char *)ftptr;
815 }
816 else if (imemo_type_p(data, imemo_memo)) {
817 struct MEMO *memo = MEMO_CAST(data);
818 void (*init)(void) = memo->u3.func;
819 data = (st_data_t)rb_thread_shield_new();
820 st_insert(loading_tbl, (st_data_t)ftptr, data);
821 (*init)();
822 return (char *)"";
823 }
824 if (warn) {
825 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
826 rb_backtrace_each(rb_str_append, warning);
827 rb_warning("%"PRIsVALUE, warning);
828 }
829 switch (rb_thread_shield_wait((VALUE)data)) {
830 case Qfalse:
831 case Qnil:
832 return 0;
833 }
834 return (char *)ftptr;
835}
836
837static int
838release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
839{
840 VALUE thread_shield = (VALUE)*value;
841 if (!existing) return ST_STOP;
842 if (done) {
843 rb_thread_shield_destroy(thread_shield);
844 /* Delete the entry even if there are waiting threads, because they
845 * won't load the file and won't delete the entry. */
846 }
847 else if (rb_thread_shield_release(thread_shield)) {
848 /* still in-use */
849 return ST_CONTINUE;
850 }
851 xfree((char *)*key);
852 return ST_DELETE;
853}
854
855static void
856load_unlock(rb_vm_t *vm, const char *ftptr, int done)
857{
858 if (ftptr) {
859 st_data_t key = (st_data_t)ftptr;
860 st_table *loading_tbl = get_loading_table(vm);
861
862 st_update(loading_tbl, key, release_thread_shield, done);
863 }
864}
865
866
867/*
868 * call-seq:
869 * require(name) -> true or false
870 *
871 * Loads the given +name+, returning +true+ if successful and +false+ if the
872 * feature is already loaded.
873 *
874 * If the filename neither resolves to an absolute path nor starts with
875 * './' or '../', the file will be searched for in the library
876 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
877 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
878 *
879 * If the filename has the extension ".rb", it is loaded as a source file; if
880 * the extension is ".so", ".o", or ".dll", or the default shared library
881 * extension on the current platform, Ruby loads the shared library as a
882 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
883 * to the name until found. If the file named cannot be found, a LoadError
884 * will be raised.
885 *
886 * For Ruby extensions the filename given may use any shared library
887 * extension. For example, on Linux the socket extension is "socket.so" and
888 * <code>require 'socket.dll'</code> will load the socket extension.
889 *
890 * The absolute path of the loaded file is added to
891 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
892 * loaded again if its path already appears in <code>$"</code>. For example,
893 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
894 * again.
895 *
896 * require "my-library.rb"
897 * require "db-driver"
898 *
899 * Any constants or globals within the loaded source file will be available
900 * in the calling program's global namespace. However, local variables will
901 * not be propagated to the loading environment.
902 *
903 */
904
905VALUE
906rb_f_require(VALUE obj, VALUE fname)
907{
908 return rb_require_string(fname);
909}
910
911/*
912 * call-seq:
913 * require_relative(string) -> true or false
914 *
915 * Ruby tries to load the library named _string_ relative to the requiring
916 * file's path. If the file's path cannot be determined a LoadError is raised.
917 * If a file is loaded +true+ is returned and false otherwise.
918 */
919VALUE
920rb_f_require_relative(VALUE obj, VALUE fname)
921{
922 VALUE base = rb_current_realfilepath();
923 if (NIL_P(base)) {
924 rb_loaderror("cannot infer basepath");
925 }
926 base = rb_file_dirname(base);
927 return rb_require_string(rb_file_absolute_path(fname, base));
928}
929
930typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
931
932static int
933search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
934{
935 VALUE tmp;
936 char *ext, *ftptr;
937 int type, ft = 0;
938 const char *loading;
939
940 *path = 0;
941 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
942 if (ext && !strchr(ext, '/')) {
943 if (IS_RBEXT(ext)) {
944 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
945 if (loading) *path = rb_filesystem_str_new_cstr(loading);
946 return 'r';
947 }
948 if ((tmp = rb_find_file(fname)) != 0) {
949 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
950 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
951 *path = tmp;
952 return 'r';
953 }
954 return 0;
955 }
956 else if (IS_SOEXT(ext)) {
957 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
958 if (loading) *path = rb_filesystem_str_new_cstr(loading);
959 return 's';
960 }
961 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
962 rb_str_cat2(tmp, DLEXT);
963 OBJ_FREEZE(tmp);
964 if ((tmp = rb_find_file(tmp)) != 0) {
965 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
966 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
967 *path = tmp;
968 return 's';
969 }
970 }
971 else if (IS_DLEXT(ext)) {
972 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
973 if (loading) *path = rb_filesystem_str_new_cstr(loading);
974 return 's';
975 }
976 if ((tmp = rb_find_file(fname)) != 0) {
977 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
978 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
979 *path = tmp;
980 return 's';
981 }
982 }
983 }
984 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
985 if (loading) *path = rb_filesystem_str_new_cstr(loading);
986 return 'r';
987 }
988 tmp = fname;
989 type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
990 switch (type) {
991 case 0:
992 if (ft)
993 goto statically_linked;
994 ftptr = RSTRING_PTR(tmp);
995 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
996
997 default:
998 if (ft) {
999 goto statically_linked;
1000 }
1001 /* fall through */
1002 case 1:
1003 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1004 if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
1005 break;
1006 *path = tmp;
1007 }
1008 return type ? 's' : 'r';
1009
1010 statically_linked:
1011 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1012 return ft;
1013}
1014
1015static void
1016load_failed(VALUE fname)
1017{
1018 rb_load_fail(fname, "cannot load such file");
1019}
1020
1021static VALUE
1022load_ext(VALUE path)
1023{
1024 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1025 return (VALUE)dln_load(RSTRING_PTR(path));
1026}
1027
1028static int
1029no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1030{
1031 return 0;
1032}
1033
1034// Documented in doc/globals.rdoc
1035VALUE
1036rb_resolve_feature_path(VALUE klass, VALUE fname)
1037{
1038 VALUE path;
1039 int found;
1040 VALUE sym;
1041
1042 fname = rb_get_path(fname);
1043 path = rb_str_encode_ospath(fname);
1044 found = search_required(GET_VM(), path, &path, no_feature_p);
1045
1046 switch (found) {
1047 case 'r':
1048 sym = ID2SYM(rb_intern("rb"));
1049 break;
1050 case 's':
1051 sym = ID2SYM(rb_intern("so"));
1052 break;
1053 default:
1054 return Qnil;
1055 }
1056
1057 return rb_ary_new_from_args(2, sym, path);
1058}
1059
1060static void
1061ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1062{
1063 *prev = th->ext_config;
1064 th->ext_config = (struct rb_ext_config){0};
1065}
1066
1067static void
1068ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1069{
1070 th->ext_config = *prev;
1071}
1072
1073void
1075{
1076 GET_THREAD()->ext_config.ractor_safe = flag;
1077}
1078
1079/*
1080 * returns
1081 * 0: if already loaded (false)
1082 * 1: successfully loaded (true)
1083 * <0: not found (LoadError)
1084 * >1: exception
1085 */
1086static int
1087require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1088{
1089 volatile int result = -1;
1090 rb_thread_t *th = rb_ec_thread_ptr(ec);
1091 volatile const struct {
1092 VALUE wrapper, self, errinfo;
1093 } saved = {
1094 th->top_wrapper, th->top_self, ec->errinfo,
1095 };
1096 enum ruby_tag_type state;
1097 char *volatile ftptr = 0;
1098 VALUE path;
1099 volatile VALUE saved_path;
1100 volatile VALUE realpath = 0;
1101 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1102 volatile bool reset_ext_config = false;
1103 struct rb_ext_config prev_ext_config;
1104
1105 fname = rb_get_path(fname);
1106 path = rb_str_encode_ospath(fname);
1107 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1108 saved_path = path;
1109
1110 EC_PUSH_TAG(ec);
1111 ec->errinfo = Qnil; /* ensure */
1112 th->top_wrapper = 0;
1113 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1114 long handle;
1115 int found;
1116
1117 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1118 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1119 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1120 path = saved_path;
1121
1122 if (found) {
1123 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1124 result = 0;
1125 }
1126 else if (!*ftptr) {
1127 result = TAG_RETURN;
1128 }
1129 else if (RTEST(rb_hash_aref(realpaths,
1130 realpath = rb_realpath_internal(Qnil, path, 1)))) {
1131 result = 0;
1132 }
1133 else {
1134 switch (found) {
1135 case 'r':
1136 load_iseq_eval(ec, path);
1137 break;
1138
1139 case 's':
1140 reset_ext_config = true;
1141 ext_config_push(th, &prev_ext_config);
1142 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1143 path, VM_BLOCK_HANDLER_NONE, path);
1144 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1145 break;
1146 }
1147 result = TAG_RETURN;
1148 }
1149 }
1150 }
1151 EC_POP_TAG();
1152
1153 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1154 th2->top_self = saved.self;
1155 th2->top_wrapper = saved.wrapper;
1156 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1157
1158 path = saved_path;
1159 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1160
1161 if (state) {
1162 if (state == TAG_FATAL || state == TAG_THROW) {
1163 EC_JUMP_TAG(ec, state);
1164 }
1165 else if (exception) {
1166 /* usually state == TAG_RAISE only, except for
1167 * rb_iseq_load_iseq in load_iseq_eval case */
1168 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1169 if (!NIL_P(exc)) ec->errinfo = exc;
1170 return TAG_RAISE;
1171 }
1172 else if (state == TAG_RETURN) {
1173 return TAG_RAISE;
1174 }
1175 RB_GC_GUARD(fname);
1176 /* never TAG_RETURN */
1177 return state;
1178 }
1179 if (!NIL_P(ec->errinfo)) {
1180 if (!exception) return TAG_RAISE;
1181 rb_exc_raise(ec->errinfo);
1182 }
1183
1184 if (result == TAG_RETURN) {
1185 rb_provide_feature(th2->vm, path);
1186 VALUE real = realpath;
1187 if (real) {
1188 rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
1189 }
1190 }
1191 ec->errinfo = saved.errinfo;
1192
1193 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1194
1195 return result;
1196}
1197
1198int
1199rb_require_internal_silent(VALUE fname)
1200{
1201 rb_execution_context_t *ec = GET_EC();
1202 return require_internal(ec, fname, 1, false);
1203}
1204
1205int
1206rb_require_internal(VALUE fname)
1207{
1208 rb_execution_context_t *ec = GET_EC();
1209 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1210}
1211
1212int
1213ruby_require_internal(const char *fname, unsigned int len)
1214{
1215 struct RString fake;
1216 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1217 rb_execution_context_t *ec = GET_EC();
1218 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1220 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1221}
1222
1223VALUE
1225{
1226 rb_execution_context_t *ec = GET_EC();
1227 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1228
1229 if (result > TAG_RETURN) {
1230 EC_JUMP_TAG(ec, result);
1231 }
1232 if (result < 0) {
1233 load_failed(fname);
1234 }
1235
1236 return RBOOL(result);
1237}
1238
1239VALUE
1240rb_require(const char *fname)
1241{
1242 return rb_require_string(rb_str_new_cstr(fname));
1243}
1244
1245static int
1246register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1247{
1248 const char *name = (char *)*key;
1249 if (existing) {
1250 /* already registered */
1251 rb_warn("%s is already registered", name);
1252 }
1253 else {
1254 *value = (st_data_t)MEMO_NEW(0, 0, init);
1255 *key = (st_data_t)ruby_strdup(name);
1256 }
1257 return ST_CONTINUE;
1258}
1259
1260RUBY_FUNC_EXPORTED void
1261ruby_init_ext(const char *name, void (*init)(void))
1262{
1263 rb_vm_t *vm = GET_VM();
1264 st_table *loading_tbl = get_loading_table(vm);
1265
1266 if (feature_provided(vm, name, 0))
1267 return;
1268 st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
1269}
1270
1271/*
1272 * call-seq:
1273 * mod.autoload(module, filename) -> nil
1274 *
1275 * Registers _filename_ to be loaded (using Kernel::require)
1276 * the first time that _module_ (which may be a String or
1277 * a symbol) is accessed in the namespace of _mod_.
1278 *
1279 * module A
1280 * end
1281 * A.autoload(:B, "b")
1282 * A::B.doit # autoloads "b"
1283 */
1284
1285static VALUE
1286rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1287{
1288 ID id = rb_to_id(sym);
1289
1290 FilePathValue(file);
1291 rb_autoload_str(mod, id, file);
1292 return Qnil;
1293}
1294
1295/*
1296 * call-seq:
1297 * mod.autoload?(name, inherit=true) -> String or nil
1298 *
1299 * Returns _filename_ to be loaded if _name_ is registered as
1300 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1301 *
1302 * module A
1303 * end
1304 * A.autoload(:B, "b")
1305 * A.autoload?(:B) #=> "b"
1306 *
1307 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1308 *
1309 * class A
1310 * autoload :CONST, "const.rb"
1311 * end
1312 *
1313 * class B < A
1314 * end
1315 *
1316 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1317 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1318 *
1319 */
1320
1321static VALUE
1322rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1323{
1324 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1325 VALUE sym = argv[0];
1326
1327 ID id = rb_check_id(&sym);
1328 if (!id) {
1329 return Qnil;
1330 }
1331 return rb_autoload_at_p(mod, id, recur);
1332}
1333
1334/*
1335 * call-seq:
1336 * autoload(module, filename) -> nil
1337 *
1338 * Registers _filename_ to be loaded (using Kernel::require)
1339 * the first time that _module_ (which may be a String or
1340 * a symbol) is accessed.
1341 *
1342 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1343 */
1344
1345static VALUE
1346rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1347{
1348 VALUE klass = rb_class_real(rb_vm_cbase());
1349 if (!klass) {
1350 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1351 }
1352 return rb_mod_autoload(klass, sym, file);
1353}
1354
1355/*
1356 * call-seq:
1357 * autoload?(name, inherit=true) -> String or nil
1358 *
1359 * Returns _filename_ to be loaded if _name_ is registered as
1360 * +autoload+.
1361 *
1362 * autoload(:B, "b")
1363 * autoload?(:B) #=> "b"
1364 */
1365
1366static VALUE
1367rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1368{
1369 /* use rb_vm_cbase() as same as rb_f_autoload. */
1370 VALUE klass = rb_vm_cbase();
1371 if (NIL_P(klass)) {
1372 return Qnil;
1373 }
1374 return rb_mod_autoload_p(argc, argv, klass);
1375}
1376
1377void
1378Init_load(void)
1379{
1380 rb_vm_t *vm = GET_VM();
1381 static const char var_load_path[] = "$:";
1382 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1383
1384 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1385 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1386 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1387 vm->load_path = rb_ary_new();
1388 vm->expanded_load_path = rb_ary_tmp_new(0);
1389 vm->load_path_snapshot = rb_ary_tmp_new(0);
1390 vm->load_path_check_cache = 0;
1391 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1392
1393 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1394 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1395 vm->loaded_features = rb_ary_new();
1396 vm->loaded_features_snapshot = rb_ary_tmp_new(0);
1397 vm->loaded_features_index = st_init_numtable();
1398 vm->loaded_features_realpaths = rb_hash_new();
1399 rb_obj_hide(vm->loaded_features_realpaths);
1400
1401 rb_define_global_function("load", rb_f_load, -1);
1403 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1404 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1405 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1406 rb_define_global_function("autoload", rb_f_autoload, 2);
1407 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1408
1409 ruby_dln_librefs = rb_ary_tmp_new(0);
1410 rb_gc_register_mark_object(ruby_dln_librefs);
1411}
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition: eval.c:1579
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:2406
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:1914
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2110
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition: string.h:1738
#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:145
#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:143
#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 LONG2NUM
Old name of RB_LONG2NUM.
Definition: long.h:50
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define xcalloc
Old name of ruby_xcalloc.
Definition: xmalloc.h:55
#define FIXNUM_P
Old name of RB_FIXNUM_P.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3021
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:671
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1760
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition: error.h:459
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition: error.c:418
void rb_warning(const char *fmt,...)
Issues a warning.
Definition: error.c:449
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition: object.c:178
Encoding relates APIs.
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8686
VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs)
Queries if the passed two arrays share the same backend storage.
Definition: array.c:688
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
Definition: array.c:2663
void rb_ary_free(VALUE ary)
Destroys the given array for no reason.
Definition: array.c:865
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
Definition: array.c:1321
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Replaces the contents of the former object with the contents of the latter.
Definition: array.c:4415
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:750
VALUE rb_ary_tmp_new(long capa)
Allocates a "temporary" array.
Definition: array.c:847
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
Definition: array.c:4465
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1308
VALUE rb_ary_new_from_args(long n,...)
Constructs an array from the passed objects.
Definition: array.c:756
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1679
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
Definition: array.c:1148
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition: error.h:294
VALUE rb_find_file(VALUE path)
Identical to rb_find_file_ext(), except it takes a feature name and is extension at once,...
Definition: file.c:6505
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
Definition: file.c:251
int rb_is_absolute_path(const char *path)
Queries if the given path is an absolute path.
Definition: file.c:6270
int rb_find_file_ext(VALUE *feature, const char *const *exts)
Resolves a feature's path.
Definition: file.c:6446
VALUE rb_file_dirname(VALUE fname)
Strips a file path's last component (and trailing separators if any).
Definition: file.c:4785
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
Maps a relative path to its absolute representation.
Definition: file.c:4172
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
Definition: hash.c:2082
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2903
VALUE rb_hash_clear(VALUE hash)
Swipes everything out of the passed hash table.
Definition: hash.c:2829
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1529
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition: load.c:638
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:906
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition: load.c:1074
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition: load.c:1224
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:610
void rb_load_protect(VALUE path, int wrap, int *state)
Identical to rb_load(), except it avoids potential global escapes.
Definition: load.c:735
int rb_provided(const char *feature)
Queries if the given feature has already been loaded into the execution context.
Definition: load.c:577
void rb_load(VALUE path, int wrap)
Loads and executes the Ruby program in the given file.
Definition: load.c:727
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:3317
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition: string.c:1540
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:2821
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
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:1269
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition: string.c:3628
#define rb_strlen_lit(str)
Length of a string literal.
Definition: string.h:1756
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition: string.c:2963
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:952
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3056
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition: variable.c:843
ID rb_intern2(const char *name, long len)
Identical to rb_intern(), except it additionally takes the length of the string.
Definition: symbol.c:775
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition: symbol.h:276
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition: symbol.c:1066
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition: symbol.c:782
ID rb_to_id(VALUE str)
Identical to rb_intern(), except it takes an instance of rb_cString.
Definition: string.c:11892
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition: variable.h:135
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
Definition: variable.c:594
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Identical to rb_define_virtual_variable(), but can also specify a storage.
Definition: variable.c:563
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:536
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:366
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition: memory.h:378
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition: cxxanyargs.hpp:432
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:68
#define RARRAY_CONST_PTR_TRANSIENT
Just another name of rb_array_const_ptr_transient.
Definition: rarray.h:70
#define RARRAY_AREF(a, i)
Definition: rarray.h:588
#define RBASIC(obj)
Convenient casting macro.
Definition: rbasic.h:40
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:72
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition: rstring.h:82
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
VALUE rb_get_path(VALUE obj)
Converts an object to a path.
Definition: file.c:245
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition: load.c:1240
#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 array.
Ruby's String.
long len
Length of the string, not including terminating NUL character.
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:432
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:375