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