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