Ruby 3.2.2p53 (2023-03-30 revision e51014f9c05aa65cbf203442d37fef7c12390015)
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
854 if (warn && rb_thread_shield_owned((VALUE)data)) {
855 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
856 rb_backtrace_each(rb_str_append, warning);
857 rb_warning("%"PRIsVALUE, warning);
858 }
859 switch (rb_thread_shield_wait((VALUE)data)) {
860 case Qfalse:
861 case Qnil:
862 return 0;
863 }
864 return (char *)ftptr;
865}
866
867static int
868release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
869{
870 VALUE thread_shield = (VALUE)*value;
871 if (!existing) return ST_STOP;
872 if (done) {
873 rb_thread_shield_destroy(thread_shield);
874 /* Delete the entry even if there are waiting threads, because they
875 * won't load the file and won't delete the entry. */
876 }
877 else if (rb_thread_shield_release(thread_shield)) {
878 /* still in-use */
879 return ST_CONTINUE;
880 }
881 xfree((char *)*key);
882 return ST_DELETE;
883}
884
885static void
886load_unlock(rb_vm_t *vm, const char *ftptr, int done)
887{
888 if (ftptr) {
889 st_data_t key = (st_data_t)ftptr;
890 st_table *loading_tbl = get_loading_table(vm);
891
892 st_update(loading_tbl, key, release_thread_shield, done);
893 }
894}
895
896
897/*
898 * call-seq:
899 * require(name) -> true or false
900 *
901 * Loads the given +name+, returning +true+ if successful and +false+ if the
902 * feature is already loaded.
903 *
904 * If the filename neither resolves to an absolute path nor starts with
905 * './' or '../', the file will be searched for in the library
906 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
907 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
908 *
909 * If the filename has the extension ".rb", it is loaded as a source file; if
910 * the extension is ".so", ".o", or ".dll", or the default shared library
911 * extension on the current platform, Ruby loads the shared library as a
912 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
913 * to the name until found. If the file named cannot be found, a LoadError
914 * will be raised.
915 *
916 * For Ruby extensions the filename given may use any shared library
917 * extension. For example, on Linux the socket extension is "socket.so" and
918 * <code>require 'socket.dll'</code> will load the socket extension.
919 *
920 * The absolute path of the loaded file is added to
921 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
922 * loaded again if its path already appears in <code>$"</code>. For example,
923 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
924 * again.
925 *
926 * require "my-library.rb"
927 * require "db-driver"
928 *
929 * Any constants or globals within the loaded source file will be available
930 * in the calling program's global namespace. However, local variables will
931 * not be propagated to the loading environment.
932 *
933 */
934
935VALUE
937{
938 return rb_require_string(fname);
939}
940
941/*
942 * call-seq:
943 * require_relative(string) -> true or false
944 *
945 * Ruby tries to load the library named _string_ relative to the directory
946 * containing the requiring file. If the file does not exist a LoadError is
947 * raised. Returns +true+ if the file was loaded and +false+ if the file was
948 * already loaded before.
949 */
950VALUE
951rb_f_require_relative(VALUE obj, VALUE fname)
952{
953 VALUE base = rb_current_realfilepath();
954 if (NIL_P(base)) {
955 rb_loaderror("cannot infer basepath");
956 }
957 base = rb_file_dirname(base);
958 return rb_require_string(rb_file_absolute_path(fname, base));
959}
960
961typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
962
963static int
964search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
965{
966 VALUE tmp;
967 char *ext, *ftptr;
968 int type, ft = 0;
969 const char *loading;
970
971 *path = 0;
972 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
973 if (ext && !strchr(ext, '/')) {
974 if (IS_RBEXT(ext)) {
975 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
976 if (loading) *path = rb_filesystem_str_new_cstr(loading);
977 return 'r';
978 }
979 if ((tmp = rb_find_file(fname)) != 0) {
980 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
981 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
982 *path = tmp;
983 return 'r';
984 }
985 return 0;
986 }
987 else if (IS_SOEXT(ext)) {
988 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
989 if (loading) *path = rb_filesystem_str_new_cstr(loading);
990 return 's';
991 }
992 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
993 rb_str_cat2(tmp, DLEXT);
994 OBJ_FREEZE(tmp);
995 if ((tmp = rb_find_file(tmp)) != 0) {
996 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
997 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
998 *path = tmp;
999 return 's';
1000 }
1001 }
1002 else if (IS_DLEXT(ext)) {
1003 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1004 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1005 return 's';
1006 }
1007 if ((tmp = rb_find_file(fname)) != 0) {
1008 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1009 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1010 *path = tmp;
1011 return 's';
1012 }
1013 }
1014 }
1015 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1016 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1017 return 'r';
1018 }
1019 tmp = fname;
1020 type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1021#if EXTSTATIC
1022 if (!ft && type != 1) { // not already a feature and not found as a dynamic library
1023 VALUE lookup_name = tmp;
1024 // Append ".so" if not already present so for example "etc" can find "etc.so".
1025 // We always register statically linked extensions with a ".so" extension.
1026 // See encinit.c and extinit.c (generated at build-time).
1027 if (!ext) {
1028 lookup_name = rb_str_dup(lookup_name);
1029 rb_str_cat_cstr(lookup_name, ".so");
1030 }
1031 ftptr = RSTRING_PTR(lookup_name);
1032 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1033 *path = rb_filesystem_str_new_cstr(ftptr);
1034 return 's';
1035 }
1036 }
1037#endif
1038 switch (type) {
1039 case 0:
1040 if (ft)
1041 goto feature_present;
1042 ftptr = RSTRING_PTR(tmp);
1043 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1044
1045 default:
1046 if (ft) {
1047 goto feature_present;
1048 }
1049 /* fall through */
1050 case 1:
1051 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1052 if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
1053 break;
1054 *path = tmp;
1055 }
1056 return type ? 's' : 'r';
1057
1058 feature_present:
1059 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1060 return ft;
1061}
1062
1063static void
1064load_failed(VALUE fname)
1065{
1066 rb_load_fail(fname, "cannot load such file");
1067}
1068
1069static VALUE
1070load_ext(VALUE path)
1071{
1072 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1073 return (VALUE)dln_load(RSTRING_PTR(path));
1074}
1075
1076#if EXTSTATIC
1077static bool
1078run_static_ext_init(rb_vm_t *vm, const char *feature)
1079{
1080 st_data_t key = (st_data_t)feature;
1081 st_data_t init_func;
1082 if (st_delete(vm->static_ext_inits, &key, &init_func)) {
1083 ((void (*)(void))init_func)();
1084 return true;
1085 }
1086 return false;
1087}
1088#endif
1089
1090static int
1091no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1092{
1093 return 0;
1094}
1095
1096// Documented in doc/globals.rdoc
1097VALUE
1098rb_resolve_feature_path(VALUE klass, VALUE fname)
1099{
1100 VALUE path;
1101 int found;
1102 VALUE sym;
1103
1104 fname = rb_get_path(fname);
1105 path = rb_str_encode_ospath(fname);
1106 found = search_required(GET_VM(), path, &path, no_feature_p);
1107
1108 switch (found) {
1109 case 'r':
1110 sym = ID2SYM(rb_intern("rb"));
1111 break;
1112 case 's':
1113 sym = ID2SYM(rb_intern("so"));
1114 break;
1115 default:
1116 return Qnil;
1117 }
1118
1119 return rb_ary_new_from_args(2, sym, path);
1120}
1121
1122static void
1123ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1124{
1125 *prev = th->ext_config;
1126 th->ext_config = (struct rb_ext_config){0};
1127}
1128
1129static void
1130ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1131{
1132 th->ext_config = *prev;
1133}
1134
1135void
1137{
1138 GET_THREAD()->ext_config.ractor_safe = flag;
1139}
1140
1141/*
1142 * returns
1143 * 0: if already loaded (false)
1144 * 1: successfully loaded (true)
1145 * <0: not found (LoadError)
1146 * >1: exception
1147 */
1148static int
1149require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1150{
1151 volatile int result = -1;
1152 rb_thread_t *th = rb_ec_thread_ptr(ec);
1153 volatile const struct {
1154 VALUE wrapper, self, errinfo;
1155 } saved = {
1156 th->top_wrapper, th->top_self, ec->errinfo,
1157 };
1158 enum ruby_tag_type state;
1159 char *volatile ftptr = 0;
1160 VALUE path;
1161 volatile VALUE saved_path;
1162 volatile VALUE realpath = 0;
1163 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1164 volatile bool reset_ext_config = false;
1165 struct rb_ext_config prev_ext_config;
1166
1167 fname = rb_get_path(fname);
1168 path = rb_str_encode_ospath(fname);
1169 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1170 saved_path = path;
1171
1172 EC_PUSH_TAG(ec);
1173 ec->errinfo = Qnil; /* ensure */
1174 th->top_wrapper = 0;
1175 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1176 long handle;
1177 int found;
1178
1179 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1180 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1181 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1182 path = saved_path;
1183
1184 if (found) {
1185 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1186 result = 0;
1187 }
1188 else if (!*ftptr) {
1189 result = TAG_RETURN;
1190 }
1191#if EXTSTATIC
1192 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1193 result = TAG_RETURN;
1194 }
1195#endif
1196 else if (RTEST(rb_hash_aref(realpaths,
1197 realpath = rb_realpath_internal(Qnil, path, 1)))) {
1198 result = 0;
1199 }
1200 else {
1201 switch (found) {
1202 case 'r':
1203 load_iseq_eval(ec, path);
1204 break;
1205
1206 case 's':
1207 reset_ext_config = true;
1208 ext_config_push(th, &prev_ext_config);
1209 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1210 path, VM_BLOCK_HANDLER_NONE, path);
1211 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1212 break;
1213 }
1214 result = TAG_RETURN;
1215 }
1216 }
1217 }
1218 EC_POP_TAG();
1219
1220 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1221 th2->top_self = saved.self;
1222 th2->top_wrapper = saved.wrapper;
1223 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1224
1225 path = saved_path;
1226 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1227
1228 if (state) {
1229 if (state == TAG_FATAL || state == TAG_THROW) {
1230 EC_JUMP_TAG(ec, state);
1231 }
1232 else if (exception) {
1233 /* usually state == TAG_RAISE only, except for
1234 * rb_iseq_load_iseq in load_iseq_eval case */
1235 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1236 if (!NIL_P(exc)) ec->errinfo = exc;
1237 return TAG_RAISE;
1238 }
1239 else if (state == TAG_RETURN) {
1240 return TAG_RAISE;
1241 }
1242 RB_GC_GUARD(fname);
1243 /* never TAG_RETURN */
1244 return state;
1245 }
1246 if (!NIL_P(ec->errinfo)) {
1247 if (!exception) return TAG_RAISE;
1248 rb_exc_raise(ec->errinfo);
1249 }
1250
1251 if (result == TAG_RETURN) {
1252 rb_provide_feature(th2->vm, path);
1253 VALUE real = realpath;
1254 if (real) {
1255 rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
1256 }
1257 }
1258 ec->errinfo = saved.errinfo;
1259
1260 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1261
1262 return result;
1263}
1264
1265int
1266rb_require_internal_silent(VALUE fname)
1267{
1268 rb_execution_context_t *ec = GET_EC();
1269 return require_internal(ec, fname, 1, false);
1270}
1271
1272int
1273rb_require_internal(VALUE fname)
1274{
1275 rb_execution_context_t *ec = GET_EC();
1276 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1277}
1278
1279int
1280ruby_require_internal(const char *fname, unsigned int len)
1281{
1282 struct RString fake;
1283 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1284 rb_execution_context_t *ec = GET_EC();
1285 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1287 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1288}
1289
1290VALUE
1292{
1293 rb_execution_context_t *ec = GET_EC();
1294 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1295
1296 if (result > TAG_RETURN) {
1297 EC_JUMP_TAG(ec, result);
1298 }
1299 if (result < 0) {
1300 load_failed(fname);
1301 }
1302
1303 return RBOOL(result);
1304}
1305
1306VALUE
1307rb_require(const char *fname)
1308{
1309 return rb_require_string(rb_str_new_cstr(fname));
1310}
1311
1312#if EXTSTATIC
1313static int
1314register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1315{
1316 const char *name = (char *)*key;
1317 if (existing) {
1318 /* already registered */
1319 rb_warn("%s is already registered", name);
1320 }
1321 else {
1322 *value = (st_data_t)init;
1323 }
1324 return ST_CONTINUE;
1325}
1326
1327void
1328ruby_init_ext(const char *name, void (*init)(void))
1329{
1330 rb_vm_t *vm = GET_VM();
1331 st_table *inits_table = vm->static_ext_inits;
1332
1333 if (feature_provided(vm, name, 0))
1334 return;
1335 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1336}
1337#endif
1338
1339/*
1340 * call-seq:
1341 * mod.autoload(const, filename) -> nil
1342 *
1343 * Registers _filename_ to be loaded (using Kernel::require)
1344 * the first time that _const_ (which may be a String or
1345 * a symbol) is accessed in the namespace of _mod_.
1346 *
1347 * module A
1348 * end
1349 * A.autoload(:B, "b")
1350 * A::B.doit # autoloads "b"
1351 *
1352 * If _const_ in _mod_ is defined as autoload, the file name to be
1353 * loaded is replaced with _filename_. If _const_ is defined but not
1354 * as autoload, does nothing.
1355 */
1356
1357static VALUE
1358rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1359{
1360 ID id = rb_to_id(sym);
1361
1362 FilePathValue(file);
1363 rb_autoload_str(mod, id, file);
1364 return Qnil;
1365}
1366
1367/*
1368 * call-seq:
1369 * mod.autoload?(name, inherit=true) -> String or nil
1370 *
1371 * Returns _filename_ to be loaded if _name_ is registered as
1372 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1373 *
1374 * module A
1375 * end
1376 * A.autoload(:B, "b")
1377 * A.autoload?(:B) #=> "b"
1378 *
1379 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1380 *
1381 * class A
1382 * autoload :CONST, "const.rb"
1383 * end
1384 *
1385 * class B < A
1386 * end
1387 *
1388 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1389 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1390 *
1391 */
1392
1393static VALUE
1394rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1395{
1396 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1397 VALUE sym = argv[0];
1398
1399 ID id = rb_check_id(&sym);
1400 if (!id) {
1401 return Qnil;
1402 }
1403 return rb_autoload_at_p(mod, id, recur);
1404}
1405
1406/*
1407 * call-seq:
1408 * autoload(const, filename) -> nil
1409 *
1410 * Registers _filename_ to be loaded (using Kernel::require)
1411 * the first time that _const_ (which may be a String or
1412 * a symbol) is accessed.
1413 *
1414 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1415 *
1416 * If _const_ is defined as autoload, the file name to be loaded is
1417 * replaced with _filename_. If _const_ is defined but not as
1418 * autoload, does nothing.
1419 */
1420
1421static VALUE
1422rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1423{
1424 VALUE klass = rb_class_real(rb_vm_cbase());
1425 if (!klass) {
1426 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1427 }
1428 return rb_mod_autoload(klass, sym, file);
1429}
1430
1431/*
1432 * call-seq:
1433 * autoload?(name, inherit=true) -> String or nil
1434 *
1435 * Returns _filename_ to be loaded if _name_ is registered as
1436 * +autoload+.
1437 *
1438 * autoload(:B, "b")
1439 * autoload?(:B) #=> "b"
1440 */
1441
1442static VALUE
1443rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1444{
1445 /* use rb_vm_cbase() as same as rb_f_autoload. */
1446 VALUE klass = rb_vm_cbase();
1447 if (NIL_P(klass)) {
1448 return Qnil;
1449 }
1450 return rb_mod_autoload_p(argc, argv, klass);
1451}
1452
1453void
1454Init_load(void)
1455{
1456 rb_vm_t *vm = GET_VM();
1457 static const char var_load_path[] = "$:";
1458 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1459
1460 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1461 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1462 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1463 vm->load_path = rb_ary_new();
1464 vm->expanded_load_path = rb_ary_hidden_new(0);
1465 vm->load_path_snapshot = rb_ary_hidden_new(0);
1466 vm->load_path_check_cache = 0;
1467 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1468
1469 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1470 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1471 vm->loaded_features = rb_ary_new();
1472 vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1473 vm->loaded_features_index = st_init_numtable();
1474 vm->loaded_features_realpaths = rb_hash_new();
1475 rb_obj_hide(vm->loaded_features_realpaths);
1476
1477 rb_define_global_function("load", rb_f_load, -1);
1478 rb_define_global_function("require", rb_f_require, 1);
1479 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1480 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1481 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1482 rb_define_global_function("autoload", rb_f_autoload, 2);
1483 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1484
1485 ruby_dln_librefs = rb_ary_hidden_new(0);
1486 rb_gc_register_mark_object(ruby_dln_librefs);
1487}
#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:936
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1136
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1291
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:3324
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:2826
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:3650
#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:2942
#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:3037
#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:859
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:11850
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:1307
#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