Ruby 3.2.3p157 (2024-01-18 revision 52bb2ac0a6971d0391efa2275f7a66bff319087c)
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#if EXTSTATIC
1037 if (!ft && type != 1) { // not already a feature and not found as a dynamic library
1038 VALUE lookup_name = tmp;
1039 // Append ".so" if not already present so for example "etc" can find "etc.so".
1040 // We always register statically linked extensions with a ".so" extension.
1041 // See encinit.c and extinit.c (generated at build-time).
1042 if (!ext) {
1043 lookup_name = rb_str_dup(lookup_name);
1044 rb_str_cat_cstr(lookup_name, ".so");
1045 }
1046 ftptr = RSTRING_PTR(lookup_name);
1047 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1048 *path = rb_filesystem_str_new_cstr(ftptr);
1049 return 's';
1050 }
1051 }
1052#endif
1053 switch (type) {
1054 case 0:
1055 if (ft)
1056 goto feature_present;
1057 ftptr = RSTRING_PTR(tmp);
1058 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1059
1060 default:
1061 if (ft) {
1062 goto feature_present;
1063 }
1064 /* fall through */
1065 case 1:
1066 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1067 if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
1068 break;
1069 *path = tmp;
1070 }
1071 return type ? 's' : 'r';
1072
1073 feature_present:
1074 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1075 return ft;
1076}
1077
1078static void
1079load_failed(VALUE fname)
1080{
1081 rb_load_fail(fname, "cannot load such file");
1082}
1083
1084static VALUE
1085load_ext(VALUE path)
1086{
1087 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1088 return (VALUE)dln_load(RSTRING_PTR(path));
1089}
1090
1091#if EXTSTATIC
1092static bool
1093run_static_ext_init(rb_vm_t *vm, const char *feature)
1094{
1095 st_data_t key = (st_data_t)feature;
1096 st_data_t init_func;
1097 if (st_delete(vm->static_ext_inits, &key, &init_func)) {
1098 ((void (*)(void))init_func)();
1099 return true;
1100 }
1101 return false;
1102}
1103#endif
1104
1105static int
1106no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1107{
1108 return 0;
1109}
1110
1111// Documented in doc/globals.rdoc
1112VALUE
1113rb_resolve_feature_path(VALUE klass, VALUE fname)
1114{
1115 VALUE path;
1116 int found;
1117 VALUE sym;
1118
1119 fname = rb_get_path(fname);
1120 path = rb_str_encode_ospath(fname);
1121 found = search_required(GET_VM(), path, &path, no_feature_p);
1122
1123 switch (found) {
1124 case 'r':
1125 sym = ID2SYM(rb_intern("rb"));
1126 break;
1127 case 's':
1128 sym = ID2SYM(rb_intern("so"));
1129 break;
1130 default:
1131 return Qnil;
1132 }
1133
1134 return rb_ary_new_from_args(2, sym, path);
1135}
1136
1137static void
1138ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1139{
1140 *prev = th->ext_config;
1141 th->ext_config = (struct rb_ext_config){0};
1142}
1143
1144static void
1145ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1146{
1147 th->ext_config = *prev;
1148}
1149
1150void
1152{
1153 GET_THREAD()->ext_config.ractor_safe = flag;
1154}
1155
1156/*
1157 * returns
1158 * 0: if already loaded (false)
1159 * 1: successfully loaded (true)
1160 * <0: not found (LoadError)
1161 * >1: exception
1162 */
1163static int
1164require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1165{
1166 volatile int result = -1;
1167 rb_thread_t *th = rb_ec_thread_ptr(ec);
1168 volatile const struct {
1169 VALUE wrapper, self, errinfo;
1170 } saved = {
1171 th->top_wrapper, th->top_self, ec->errinfo,
1172 };
1173 enum ruby_tag_type state;
1174 char *volatile ftptr = 0;
1175 VALUE path;
1176 volatile VALUE saved_path;
1177 volatile VALUE realpath = 0;
1178 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1179 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
1180 volatile bool reset_ext_config = false;
1181 struct rb_ext_config prev_ext_config;
1182
1183 path = rb_str_encode_ospath(fname);
1184 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1185 saved_path = path;
1186
1187 EC_PUSH_TAG(ec);
1188 ec->errinfo = Qnil; /* ensure */
1189 th->top_wrapper = 0;
1190 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1191 long handle;
1192 int found;
1193
1194 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1195 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1196 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1197 path = saved_path;
1198
1199 if (found) {
1200 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1201 result = 0;
1202 }
1203 else if (!*ftptr) {
1204 result = TAG_RETURN;
1205 }
1206#if EXTSTATIC
1207 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1208 result = TAG_RETURN;
1209 }
1210#endif
1211 else if (RTEST(rb_hash_aref(realpaths,
1212 realpath = rb_realpath_internal(Qnil, path, 1)))) {
1213 result = 0;
1214 }
1215 else {
1216 switch (found) {
1217 case 'r':
1218 load_iseq_eval(ec, path);
1219 break;
1220
1221 case 's':
1222 reset_ext_config = true;
1223 ext_config_push(th, &prev_ext_config);
1224 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1225 path, VM_BLOCK_HANDLER_NONE, path);
1226 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1227 break;
1228 }
1229 result = TAG_RETURN;
1230 }
1231 }
1232 }
1233 EC_POP_TAG();
1234
1235 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1236 th2->top_self = saved.self;
1237 th2->top_wrapper = saved.wrapper;
1238 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1239
1240 path = saved_path;
1241 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1242
1243 if (state) {
1244 if (state == TAG_FATAL || state == TAG_THROW) {
1245 EC_JUMP_TAG(ec, state);
1246 }
1247 else if (exception) {
1248 /* usually state == TAG_RAISE only, except for
1249 * rb_iseq_load_iseq in load_iseq_eval case */
1250 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1251 if (!NIL_P(exc)) ec->errinfo = exc;
1252 return TAG_RAISE;
1253 }
1254 else if (state == TAG_RETURN) {
1255 return TAG_RAISE;
1256 }
1257 RB_GC_GUARD(fname);
1258 /* never TAG_RETURN */
1259 return state;
1260 }
1261 if (!NIL_P(ec->errinfo)) {
1262 if (!exception) return TAG_RAISE;
1263 rb_exc_raise(ec->errinfo);
1264 }
1265
1266 if (result == TAG_RETURN) {
1267 rb_provide_feature(th2->vm, path);
1268 VALUE real = realpath;
1269 if (real) {
1270 real = rb_fstring(real);
1271 rb_hash_aset(realpaths, real, Qtrue);
1272 rb_hash_aset(realpath_map, path, real);
1273 }
1274 }
1275 ec->errinfo = saved.errinfo;
1276
1277 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1278
1279 return result;
1280}
1281
1282int
1283rb_require_internal_silent(VALUE fname)
1284{
1285 rb_execution_context_t *ec = GET_EC();
1286 return require_internal(ec, fname, 1, false);
1287}
1288
1289int
1290rb_require_internal(VALUE fname)
1291{
1292 rb_execution_context_t *ec = GET_EC();
1293 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1294}
1295
1296int
1297ruby_require_internal(const char *fname, unsigned int len)
1298{
1299 struct RString fake;
1300 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1301 rb_execution_context_t *ec = GET_EC();
1302 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1304 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1305}
1306
1307VALUE
1309{
1310 return rb_require_string_internal(FilePathValue(fname));
1311}
1312
1313static VALUE
1314rb_require_string_internal(VALUE fname)
1315{
1316 rb_execution_context_t *ec = GET_EC();
1317 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1318
1319 if (result > TAG_RETURN) {
1320 EC_JUMP_TAG(ec, result);
1321 }
1322 if (result < 0) {
1323 load_failed(fname);
1324 }
1325
1326 return RBOOL(result);
1327}
1328
1329VALUE
1330rb_require(const char *fname)
1331{
1332 struct RString fake;
1333 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1334 return rb_require_string_internal(str);
1335}
1336
1337#if EXTSTATIC
1338static int
1339register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1340{
1341 const char *name = (char *)*key;
1342 if (existing) {
1343 /* already registered */
1344 rb_warn("%s is already registered", name);
1345 }
1346 else {
1347 *value = (st_data_t)init;
1348 }
1349 return ST_CONTINUE;
1350}
1351
1352void
1353ruby_init_ext(const char *name, void (*init)(void))
1354{
1355 rb_vm_t *vm = GET_VM();
1356 st_table *inits_table = vm->static_ext_inits;
1357
1358 if (feature_provided(vm, name, 0))
1359 return;
1360 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1361}
1362#endif
1363
1364/*
1365 * call-seq:
1366 * mod.autoload(const, filename) -> nil
1367 *
1368 * Registers _filename_ to be loaded (using Kernel::require)
1369 * the first time that _const_ (which may be a String or
1370 * a symbol) is accessed in the namespace of _mod_.
1371 *
1372 * module A
1373 * end
1374 * A.autoload(:B, "b")
1375 * A::B.doit # autoloads "b"
1376 *
1377 * If _const_ in _mod_ is defined as autoload, the file name to be
1378 * loaded is replaced with _filename_. If _const_ is defined but not
1379 * as autoload, does nothing.
1380 */
1381
1382static VALUE
1383rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1384{
1385 ID id = rb_to_id(sym);
1386
1387 FilePathValue(file);
1388 rb_autoload_str(mod, id, file);
1389 return Qnil;
1390}
1391
1392/*
1393 * call-seq:
1394 * mod.autoload?(name, inherit=true) -> String or nil
1395 *
1396 * Returns _filename_ to be loaded if _name_ is registered as
1397 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1398 *
1399 * module A
1400 * end
1401 * A.autoload(:B, "b")
1402 * A.autoload?(:B) #=> "b"
1403 *
1404 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1405 *
1406 * class A
1407 * autoload :CONST, "const.rb"
1408 * end
1409 *
1410 * class B < A
1411 * end
1412 *
1413 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1414 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1415 *
1416 */
1417
1418static VALUE
1419rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1420{
1421 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1422 VALUE sym = argv[0];
1423
1424 ID id = rb_check_id(&sym);
1425 if (!id) {
1426 return Qnil;
1427 }
1428 return rb_autoload_at_p(mod, id, recur);
1429}
1430
1431/*
1432 * call-seq:
1433 * autoload(const, filename) -> nil
1434 *
1435 * Registers _filename_ to be loaded (using Kernel::require)
1436 * the first time that _const_ (which may be a String or
1437 * a symbol) is accessed.
1438 *
1439 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1440 *
1441 * If _const_ is defined as autoload, the file name to be loaded is
1442 * replaced with _filename_. If _const_ is defined but not as
1443 * autoload, does nothing.
1444 */
1445
1446static VALUE
1447rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1448{
1449 VALUE klass = rb_class_real(rb_vm_cbase());
1450 if (!klass) {
1451 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1452 }
1453 return rb_mod_autoload(klass, sym, file);
1454}
1455
1456/*
1457 * call-seq:
1458 * autoload?(name, inherit=true) -> String or nil
1459 *
1460 * Returns _filename_ to be loaded if _name_ is registered as
1461 * +autoload+.
1462 *
1463 * autoload(:B, "b")
1464 * autoload?(:B) #=> "b"
1465 */
1466
1467static VALUE
1468rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1469{
1470 /* use rb_vm_cbase() as same as rb_f_autoload. */
1471 VALUE klass = rb_vm_cbase();
1472 if (NIL_P(klass)) {
1473 return Qnil;
1474 }
1475 return rb_mod_autoload_p(argc, argv, klass);
1476}
1477
1478void
1479Init_load(void)
1480{
1481 rb_vm_t *vm = GET_VM();
1482 static const char var_load_path[] = "$:";
1483 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1484
1485 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1486 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1487 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1488 vm->load_path = rb_ary_new();
1489 vm->expanded_load_path = rb_ary_hidden_new(0);
1490 vm->load_path_snapshot = rb_ary_hidden_new(0);
1491 vm->load_path_check_cache = 0;
1492 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1493
1494 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1495 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1496 vm->loaded_features = rb_ary_new();
1497 vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1498 vm->loaded_features_index = st_init_numtable();
1499 vm->loaded_features_realpaths = rb_hash_new();
1500 rb_obj_hide(vm->loaded_features_realpaths);
1501 vm->loaded_features_realpath_map = rb_hash_new();
1502 rb_obj_hide(vm->loaded_features_realpath_map);
1503
1504 rb_define_global_function("load", rb_f_load, -1);
1506 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1507 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1508 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1509 rb_define_global_function("autoload", rb_f_autoload, 2);
1510 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1511
1512 ruby_dln_librefs = rb_ary_hidden_new(0);
1513 rb_gc_register_mark_object(ruby_dln_librefs);
1514}
#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:1151
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1308
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:3679
#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:782
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:1084
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:789
ID rb_to_id(VALUE str)
Identical to rb_intern(), except it takes an instance of rb_cString.
Definition string.c:11908
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:1330
#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