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