[ruby/digest] [DOC] Update document to use `rb_digest_make_metadata`
[ruby.git] / load.c
blob89e9ea8f99caf82c10eddf17ea05c09b042408a6
1 /*
2 * load methods from eval.c
3 */
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/hash.h"
12 #include "internal/load.h"
13 #include "internal/ruby_parser.h"
14 #include "internal/thread.h"
15 #include "internal/variable.h"
16 #include "iseq.h"
17 #include "probes.h"
18 #include "darray.h"
19 #include "ruby/encoding.h"
20 #include "ruby/util.h"
22 static VALUE ruby_dln_libmap;
24 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
25 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
26 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
28 #if SIZEOF_VALUE <= SIZEOF_LONG
29 # define SVALUE2NUM(x) LONG2NUM((long)(x))
30 # define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
31 #elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
32 # define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
33 # define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
34 #else
35 # error Need integer for VALUE
36 #endif
38 enum {
39 loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
40 1) /* offset by rb_find_file_ext() */
43 static const char *const loadable_ext[] = {
44 ".rb", DLEXT,
48 static const char *const ruby_ext[] = {
49 ".rb",
53 enum expand_type {
54 EXPAND_ALL,
55 EXPAND_RELATIVE,
56 EXPAND_HOME,
57 EXPAND_NON_CACHE
60 /* Construct expanded load path and store it to cache.
61 We rebuild load path partially if the cache is invalid.
62 We don't cache non string object and expand it every time. We ensure that
63 string objects in $LOAD_PATH are frozen.
65 static void
66 rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache)
68 VALUE load_path = vm->load_path;
69 VALUE expanded_load_path = vm->expanded_load_path;
70 VALUE ary;
71 long i;
73 ary = rb_ary_hidden_new(RARRAY_LEN(load_path));
74 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
75 VALUE path, as_str, expanded_path;
76 int is_string, non_cache;
77 char *as_cstr;
78 as_str = path = RARRAY_AREF(load_path, i);
79 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
80 non_cache = !is_string ? 1 : 0;
81 as_str = rb_get_path_check_to_string(path);
82 as_cstr = RSTRING_PTR(as_str);
84 if (!non_cache) {
85 if ((type == EXPAND_RELATIVE &&
86 rb_is_absolute_path(as_cstr)) ||
87 (type == EXPAND_HOME &&
88 (!as_cstr[0] || as_cstr[0] != '~')) ||
89 (type == EXPAND_NON_CACHE)) {
90 /* Use cached expanded path. */
91 rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
92 continue;
95 if (!*has_relative && !rb_is_absolute_path(as_cstr))
96 *has_relative = 1;
97 if (!*has_non_cache && non_cache)
98 *has_non_cache = 1;
99 /* Freeze only string object. We expand other objects every time. */
100 if (is_string)
101 rb_str_freeze(path);
102 as_str = rb_get_path_check_convert(as_str);
103 expanded_path = rb_check_realpath(Qnil, as_str, NULL);
104 if (NIL_P(expanded_path)) expanded_path = as_str;
105 rb_ary_push(ary, rb_fstring(expanded_path));
107 rb_obj_freeze(ary);
108 vm->expanded_load_path = ary;
109 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
112 static VALUE
113 get_expanded_load_path(rb_vm_t *vm)
115 const VALUE non_cache = Qtrue;
117 if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
118 /* The load path was modified. Rebuild the expanded load path. */
119 int has_relative = 0, has_non_cache = 0;
120 rb_construct_expanded_load_path(vm, EXPAND_ALL, &has_relative, &has_non_cache);
121 if (has_relative) {
122 vm->load_path_check_cache = rb_dir_getwd_ospath();
124 else if (has_non_cache) {
125 /* Non string object. */
126 vm->load_path_check_cache = non_cache;
128 else {
129 vm->load_path_check_cache = 0;
132 else if (vm->load_path_check_cache == non_cache) {
133 int has_relative = 1, has_non_cache = 1;
134 /* Expand only non-cacheable objects. */
135 rb_construct_expanded_load_path(vm, EXPAND_NON_CACHE,
136 &has_relative, &has_non_cache);
138 else if (vm->load_path_check_cache) {
139 int has_relative = 1, has_non_cache = 1;
140 VALUE cwd = rb_dir_getwd_ospath();
141 if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
142 /* Current working directory or filesystem encoding was changed.
143 Expand relative load path and non-cacheable objects again. */
144 vm->load_path_check_cache = cwd;
145 rb_construct_expanded_load_path(vm, EXPAND_RELATIVE,
146 &has_relative, &has_non_cache);
148 else {
149 /* Expand only tilde (User HOME) and non-cacheable objects. */
150 rb_construct_expanded_load_path(vm, EXPAND_HOME,
151 &has_relative, &has_non_cache);
154 return vm->expanded_load_path;
157 VALUE
158 rb_get_expanded_load_path(void)
160 return get_expanded_load_path(GET_VM());
163 static VALUE
164 load_path_getter(ID id, VALUE * p)
166 rb_vm_t *vm = (void *)p;
167 return vm->load_path;
170 static VALUE
171 get_loaded_features(rb_vm_t *vm)
173 return vm->loaded_features;
176 static VALUE
177 get_loaded_features_realpaths(rb_vm_t *vm)
179 return vm->loaded_features_realpaths;
182 static VALUE
183 get_loaded_features_realpath_map(rb_vm_t *vm)
185 return vm->loaded_features_realpath_map;
188 static VALUE
189 get_LOADED_FEATURES(ID _x, VALUE *_y)
191 return get_loaded_features(GET_VM());
194 static void
195 reset_loaded_features_snapshot(rb_vm_t *vm)
197 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
200 static struct st_table *
201 get_loaded_features_index_raw(rb_vm_t *vm)
203 return vm->loaded_features_index;
206 static st_table *
207 get_loading_table(rb_vm_t *vm)
209 return vm->loading_table;
212 static st_data_t
213 feature_key(const char *str, size_t len)
215 return st_hash(str, len, 0xfea7009e);
218 static bool
219 is_rbext_path(VALUE feature_path)
221 long len = RSTRING_LEN(feature_path);
222 long rbext_len = rb_strlen_lit(".rb");
223 if (len <= rbext_len) return false;
224 return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
227 typedef rb_darray(long) feature_indexes_t;
229 struct features_index_add_single_args {
230 rb_vm_t *vm;
231 VALUE offset;
232 bool rb;
235 static int
236 features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
238 struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
239 rb_vm_t *vm = args->vm;
240 VALUE offset = args->offset;
241 bool rb = args->rb;
243 if (existing) {
244 VALUE this_feature_index = *value;
246 if (FIXNUM_P(this_feature_index)) {
247 VALUE loaded_features = get_loaded_features(vm);
248 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
250 feature_indexes_t feature_indexes;
251 rb_darray_make(&feature_indexes, 2);
252 int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
253 rb_darray_set(feature_indexes, top^0, FIX2LONG(this_feature_index));
254 rb_darray_set(feature_indexes, top^1, FIX2LONG(offset));
256 RUBY_ASSERT(rb_darray_size(feature_indexes) == 2);
257 // assert feature_indexes does not look like a special const
258 RUBY_ASSERT(!SPECIAL_CONST_P((VALUE)feature_indexes));
260 *value = (st_data_t)feature_indexes;
262 else {
263 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
264 long pos = -1;
266 if (rb) {
267 VALUE loaded_features = get_loaded_features(vm);
268 for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
269 long idx = rb_darray_get(feature_indexes, i);
270 VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
271 Check_Type(this_feature_path, T_STRING);
272 if (!is_rbext_path(this_feature_path)) {
273 pos = i;
274 break;
279 rb_darray_append(&feature_indexes, FIX2LONG(offset));
280 /* darray may realloc which will change the pointer */
281 *value = (st_data_t)feature_indexes;
283 if (pos >= 0) {
284 long *ptr = rb_darray_data_ptr(feature_indexes);
285 long len = rb_darray_size(feature_indexes);
286 MEMMOVE(ptr + pos, ptr + pos + 1, long, len - pos - 1);
287 ptr[pos] = FIX2LONG(offset);
291 else {
292 *value = offset;
295 return ST_CONTINUE;
298 static void
299 features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb)
301 struct st_table *features_index;
302 st_data_t short_feature_key;
304 Check_Type(offset, T_FIXNUM);
305 short_feature_key = feature_key(str, len);
307 features_index = get_loaded_features_index_raw(vm);
309 struct features_index_add_single_args args = {
310 .vm = vm,
311 .offset = offset,
312 .rb = rb,
315 st_update(features_index, short_feature_key, features_index_add_single_callback, (st_data_t)&args);
318 /* Add to the loaded-features index all the required entries for
319 `feature`, located at `offset` in $LOADED_FEATURES. We add an
320 index entry at each string `short_feature` for which
321 feature == "#{prefix}#{short_feature}#{ext}"
322 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
323 or ends in '/'. This maintains the invariant that `rb_feature_p()`
324 relies on for its fast lookup.
326 static void
327 features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
329 const char *feature_str, *feature_end, *ext, *p;
330 bool rb = false;
332 feature_str = StringValuePtr(feature);
333 feature_end = feature_str + RSTRING_LEN(feature);
335 for (ext = feature_end; ext > feature_str; ext--)
336 if (*ext == '.' || *ext == '/')
337 break;
338 if (*ext != '.')
339 ext = NULL;
340 else
341 rb = IS_RBEXT(ext);
342 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
343 at the end of `feature`, or is NULL if there is no such string. */
345 p = ext ? ext : feature_end;
346 while (1) {
347 p--;
348 while (p >= feature_str && *p != '/')
349 p--;
350 if (p < feature_str)
351 break;
352 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
353 features_index_add_single(vm, p + 1, feature_end - p - 1, offset, false);
354 if (ext) {
355 features_index_add_single(vm, p + 1, ext - p - 1, offset, rb);
358 features_index_add_single(vm, feature_str, feature_end - feature_str, offset, false);
359 if (ext) {
360 features_index_add_single(vm, feature_str, ext - feature_str, offset, rb);
364 static int
365 loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
367 VALUE obj = (VALUE)val;
368 if (!SPECIAL_CONST_P(obj)) {
369 rb_darray_free((void *)obj);
371 return ST_DELETE;
374 void
375 rb_free_loaded_features_index(rb_vm_t *vm)
377 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
378 st_free_table(vm->loaded_features_index);
381 static st_table *
382 get_loaded_features_index(rb_vm_t *vm)
384 VALUE features;
385 int i;
387 if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
388 /* The sharing was broken; something (other than us in rb_provide_feature())
389 modified loaded_features. Rebuild the index. */
390 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
392 VALUE realpaths = vm->loaded_features_realpaths;
393 VALUE realpath_map = vm->loaded_features_realpath_map;
394 VALUE previous_realpath_map = rb_hash_dup(realpath_map);
395 rb_hash_clear(realpaths);
396 rb_hash_clear(realpath_map);
397 features = vm->loaded_features;
398 for (i = 0; i < RARRAY_LEN(features); i++) {
399 VALUE entry, as_str;
400 as_str = entry = rb_ary_entry(features, i);
401 StringValue(as_str);
402 as_str = rb_fstring(as_str);
403 if (as_str != entry)
404 rb_ary_store(features, i, as_str);
405 features_index_add(vm, as_str, INT2FIX(i));
407 reset_loaded_features_snapshot(vm);
409 features = rb_ary_dup(vm->loaded_features_snapshot);
410 long j = RARRAY_LEN(features);
411 for (i = 0; i < j; i++) {
412 VALUE as_str = rb_ary_entry(features, i);
413 VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
414 if (NIL_P(realpath)) {
415 realpath = rb_check_realpath(Qnil, as_str, NULL);
416 if (NIL_P(realpath)) realpath = as_str;
417 realpath = rb_fstring(realpath);
419 rb_hash_aset(realpaths, realpath, Qtrue);
420 rb_hash_aset(realpath_map, as_str, realpath);
423 return vm->loaded_features_index;
426 /* This searches `load_path` for a value such that
427 name == "#{load_path[i]}/#{feature}"
428 if `feature` is a suffix of `name`, or otherwise
429 name == "#{load_path[i]}/#{feature}#{ext}"
430 for an acceptable string `ext`. It returns
431 `load_path[i].to_str` if found, else 0.
433 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
434 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
435 or have any value matching `%r{^\.[^./]*$}`.
437 static VALUE
438 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
439 int type, VALUE load_path)
441 long i;
442 long plen;
443 const char *e;
445 if (vlen < len+1) return 0;
446 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
447 plen = vlen - len;
449 else {
450 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
451 if (*e != '.' ||
452 e-name < len ||
453 strncmp(e-len, feature, len))
454 return 0;
455 plen = e - name - len;
457 if (plen > 0 && name[plen-1] != '/') {
458 return 0;
460 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
461 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
462 0) {
463 return 0;
465 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
466 (possibly empty) and prefix is some string of length plen. */
468 if (plen > 0) --plen; /* exclude '.' */
469 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
470 VALUE p = RARRAY_AREF(load_path, i);
471 const char *s = StringValuePtr(p);
472 long n = RSTRING_LEN(p);
474 if (n != plen) continue;
475 if (n && strncmp(name, s, n)) continue;
476 return p;
478 return 0;
481 struct loaded_feature_searching {
482 const char *name;
483 long len;
484 int type;
485 VALUE load_path;
486 const char *result;
489 static int
490 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
492 const char *s = (const char *)v;
493 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
494 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
495 fp->type, fp->load_path);
496 if (!p) return ST_CONTINUE;
497 fp->result = s;
498 return ST_STOP;
502 * Returns the type of already provided feature.
503 * 'r': ruby script (".rb")
504 * 's': shared object (".so"/"."DLEXT)
505 * 'u': unsuffixed
507 static int
508 rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
510 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
511 const char *f, *e;
512 long i, len, elen, n;
513 st_table *loading_tbl, *features_index;
514 st_data_t data;
515 st_data_t key;
516 int type;
518 if (fn) *fn = 0;
519 if (ext) {
520 elen = strlen(ext);
521 len = strlen(feature) - elen;
522 type = rb ? 'r' : 's';
524 else {
525 len = strlen(feature);
526 elen = 0;
527 type = 0;
529 features = get_loaded_features(vm);
530 features_index = get_loaded_features_index(vm);
532 key = feature_key(feature, strlen(feature));
533 /* We search `features` for an entry such that either
534 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
535 for some j, or
536 "#{features[i]}" == "#{feature}#{e}"
537 Here `e` is an "allowed" extension -- either empty or one
538 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
539 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
540 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
542 If `expanded`, then only the latter form (without load_path[j])
543 is accepted. Otherwise either form is accepted, *unless* `ext`
544 is false and an otherwise-matching entry of the first form is
545 preceded by an entry of the form
546 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
547 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
548 After a "distractor" entry of this form, only entries of the
549 form "#{feature}#{e}" are accepted.
551 In `rb_provide_feature()` and `get_loaded_features_index()` we
552 maintain an invariant that the array `this_feature_index` will
553 point to every entry in `features` which has the form
554 "#{prefix}#{feature}#{e}"
555 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
556 or ends in '/'. This includes both match forms above, as well
557 as any distractors, so we may ignore all other entries in `features`.
559 if (st_lookup(features_index, key, &data) && !NIL_P(this_feature_index = (VALUE)data)) {
560 for (size_t i = 0; ; i++) {
561 long index;
562 if (FIXNUM_P(this_feature_index)) {
563 if (i > 0) break;
564 index = FIX2LONG(this_feature_index);
566 else {
567 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
568 if (i >= rb_darray_size(feature_indexes)) break;
569 index = rb_darray_get(feature_indexes, i);
572 v = RARRAY_AREF(features, index);
573 f = StringValuePtr(v);
574 if ((n = RSTRING_LEN(v)) < len) continue;
575 if (strncmp(f, feature, len) != 0) {
576 if (expanded) continue;
577 if (!load_path) load_path = get_expanded_load_path(vm);
578 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
579 continue;
580 expanded = 1;
581 f += RSTRING_LEN(p) + 1;
583 if (!*(e = f + len)) {
584 if (ext) continue;
585 return 'u';
587 if (*e != '.') continue;
588 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
589 return 's';
591 if ((rb || !ext) && (IS_RBEXT(e))) {
592 return 'r';
597 loading_tbl = get_loading_table(vm);
598 f = 0;
599 if (!expanded) {
600 struct loaded_feature_searching fs;
601 fs.name = feature;
602 fs.len = len;
603 fs.type = type;
604 fs.load_path = load_path ? load_path : get_expanded_load_path(vm);
605 fs.result = 0;
606 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
607 if ((f = fs.result) != 0) {
608 if (fn) *fn = f;
609 goto loading;
612 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
613 if (fn) *fn = (const char*)data;
614 goto loading;
616 else {
617 VALUE bufstr;
618 char *buf;
619 static const char so_ext[][4] = {
620 ".so", ".o",
623 if (ext && *ext) return 0;
624 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
625 buf = RSTRING_PTR(bufstr);
626 MEMCPY(buf, feature, char, len);
627 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
628 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
629 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
630 rb_str_resize(bufstr, 0);
631 if (fn) *fn = (const char*)data;
632 return i ? 's' : 'r';
635 for (i = 0; i < numberof(so_ext); i++) {
636 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
637 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
638 rb_str_resize(bufstr, 0);
639 if (fn) *fn = (const char*)data;
640 return 's';
643 rb_str_resize(bufstr, 0);
645 return 0;
647 loading:
648 if (!ext) return 'u';
649 return !IS_RBEXT(ext) ? 's' : 'r';
653 rb_provided(const char *feature)
655 return rb_feature_provided(feature, 0);
658 static int
659 feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
661 const char *ext = strrchr(feature, '.');
662 VALUE fullpath = 0;
664 if (*feature == '.' &&
665 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
666 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
667 feature = RSTRING_PTR(fullpath);
669 if (ext && !strchr(ext, '/')) {
670 if (IS_RBEXT(ext)) {
671 if (rb_feature_p(vm, feature, ext, TRUE, FALSE, loading)) return TRUE;
672 return FALSE;
674 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
675 if (rb_feature_p(vm, feature, ext, FALSE, FALSE, loading)) return TRUE;
676 return FALSE;
679 if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
680 return TRUE;
681 RB_GC_GUARD(fullpath);
682 return FALSE;
686 rb_feature_provided(const char *feature, const char **loading)
688 return feature_provided(GET_VM(), feature, loading);
691 static void
692 rb_provide_feature(rb_vm_t *vm, VALUE feature)
694 VALUE features;
696 features = get_loaded_features(vm);
697 if (OBJ_FROZEN(features)) {
698 rb_raise(rb_eRuntimeError,
699 "$LOADED_FEATURES is frozen; cannot append feature");
701 feature = rb_fstring(feature);
703 get_loaded_features_index(vm);
704 // If loaded_features and loaded_features_snapshot share the same backing
705 // array, pushing into it would cause the whole array to be copied.
706 // To avoid this we first clear loaded_features_snapshot.
707 rb_ary_clear(vm->loaded_features_snapshot);
708 rb_ary_push(features, feature);
709 features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
710 reset_loaded_features_snapshot(vm);
713 void
714 rb_provide(const char *feature)
716 rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
719 NORETURN(static void load_failed(VALUE));
721 static inline VALUE
722 realpath_internal_cached(VALUE hash, VALUE path)
724 VALUE ret = rb_hash_aref(hash, path);
725 if(RTEST(ret)) {
726 return ret;
729 VALUE realpath = rb_realpath_internal(Qnil, path, 1);
730 rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
731 return realpath;
734 static inline void
735 load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
737 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
739 if (!iseq) {
740 rb_execution_context_t *ec = GET_EC();
741 VALUE v = rb_vm_push_frame_fname(ec, fname);
743 rb_thread_t *th = rb_ec_thread_ptr(ec);
744 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
746 if (*rb_ruby_prism_ptr()) {
747 pm_parse_result_t result = { 0 };
748 result.options.line = 1;
749 result.node.coverage_enabled = 1;
751 VALUE error = pm_load_parse_file(&result, fname);
753 if (error == Qnil) {
754 iseq = pm_iseq_new_top(&result.node, rb_fstring_lit("<top (required)>"), fname, realpath_internal_cached(realpath_map, fname), NULL);
755 pm_parse_result_free(&result);
757 else {
758 rb_vm_pop_frame(ec);
759 RB_GC_GUARD(v);
760 pm_parse_result_free(&result);
761 rb_exc_raise(error);
764 else {
765 rb_ast_t *ast;
766 VALUE ast_value;
767 VALUE parser = rb_parser_new();
768 rb_parser_set_context(parser, NULL, FALSE);
769 ast_value = rb_parser_load_file(parser, fname);
770 ast = rb_ruby_ast_data_get(ast_value);
772 iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
773 fname, realpath_internal_cached(realpath_map, fname), NULL);
774 rb_ast_dispose(ast);
777 rb_vm_pop_frame(ec);
778 RB_GC_GUARD(v);
780 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
781 rb_iseq_eval(iseq);
784 static inline enum ruby_tag_type
785 load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
787 enum ruby_tag_type state;
788 rb_thread_t *th = rb_ec_thread_ptr(ec);
789 volatile VALUE wrapper = th->top_wrapper;
790 volatile VALUE self = th->top_self;
791 #if !defined __GNUC__
792 rb_thread_t *volatile th0 = th;
793 #endif
795 ec->errinfo = Qnil; /* ensure */
797 /* load in module as toplevel */
798 th->top_self = rb_obj_clone(rb_vm_top_self());
799 th->top_wrapper = load_wrapper;
800 rb_extend_object(th->top_self, th->top_wrapper);
802 EC_PUSH_TAG(ec);
803 state = EC_EXEC_TAG();
804 if (state == TAG_NONE) {
805 load_iseq_eval(ec, fname);
807 EC_POP_TAG();
809 #if !defined __GNUC__
810 th = th0;
811 fname = RB_GC_GUARD(fname);
812 #endif
813 th->top_self = self;
814 th->top_wrapper = wrapper;
815 return state;
818 static inline void
819 raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
821 if (state) {
822 rb_vm_jump_tag_but_local_jump(state);
825 if (!NIL_P(ec->errinfo)) {
826 rb_exc_raise(ec->errinfo);
830 static void
831 rb_load_internal(VALUE fname, VALUE wrap)
833 rb_execution_context_t *ec = GET_EC();
834 enum ruby_tag_type state = TAG_NONE;
835 if (RTEST(wrap)) {
836 if (!RB_TYPE_P(wrap, T_MODULE)) {
837 wrap = rb_module_new();
839 state = load_wrapping(ec, fname, wrap);
841 else {
842 load_iseq_eval(ec, fname);
844 raise_load_if_failed(ec, state);
847 void
848 rb_load(VALUE fname, int wrap)
850 VALUE tmp = rb_find_file(FilePathValue(fname));
851 if (!tmp) load_failed(fname);
852 rb_load_internal(tmp, RBOOL(wrap));
855 void
856 rb_load_protect(VALUE fname, int wrap, int *pstate)
858 enum ruby_tag_type state;
860 EC_PUSH_TAG(GET_EC());
861 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
862 rb_load(fname, wrap);
864 EC_POP_TAG();
866 if (state != TAG_NONE) *pstate = state;
870 * call-seq:
871 * load(filename, wrap=false) -> true
873 * Loads and executes the Ruby program in the file _filename_.
875 * If the filename is an absolute path (e.g. starts with '/'), the file
876 * will be loaded directly using the absolute path.
878 * If the filename is an explicit relative path (e.g. starts with './' or
879 * '../'), the file will be loaded using the relative path from the current
880 * directory.
882 * Otherwise, the file will be searched for in the library
883 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
884 * If the file is found in a directory, it will attempt to load the file
885 * relative to that directory. If the file is not found in any of the
886 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
887 * the relative path from the current directory.
889 * If the file doesn't exist when there is an attempt to load it, a
890 * LoadError will be raised.
892 * If the optional _wrap_ parameter is +true+, the loaded script will
893 * be executed under an anonymous module. If the optional _wrap_ parameter
894 * is a module, the loaded script will be executed under the given module.
895 * In no circumstance will any local variables in the loaded file be
896 * propagated to the loading environment.
899 static VALUE
900 rb_f_load(int argc, VALUE *argv, VALUE _)
902 VALUE fname, wrap, path, orig_fname;
904 rb_scan_args(argc, argv, "11", &fname, &wrap);
906 orig_fname = rb_get_path_check_to_string(fname);
907 fname = rb_str_encode_ospath(orig_fname);
908 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
910 path = rb_find_file(fname);
911 if (!path) {
912 if (!rb_file_load_ok(RSTRING_PTR(fname)))
913 load_failed(orig_fname);
914 path = fname;
916 rb_load_internal(path, wrap);
918 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
920 return Qtrue;
923 static char *
924 load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
926 st_data_t data;
927 st_table *loading_tbl = get_loading_table(vm);
929 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
930 /* partial state */
931 ftptr = ruby_strdup(ftptr);
932 data = (st_data_t)rb_thread_shield_new();
933 st_insert(loading_tbl, (st_data_t)ftptr, data);
934 return (char *)ftptr;
937 if (warn && rb_thread_shield_owned((VALUE)data)) {
938 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
939 rb_backtrace_each(rb_str_append, warning);
940 rb_warning("%"PRIsVALUE, warning);
942 switch (rb_thread_shield_wait((VALUE)data)) {
943 case Qfalse:
944 case Qnil:
945 return 0;
947 return (char *)ftptr;
950 static int
951 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
953 VALUE thread_shield = (VALUE)*value;
954 if (!existing) return ST_STOP;
955 if (done) {
956 rb_thread_shield_destroy(thread_shield);
957 /* Delete the entry even if there are waiting threads, because they
958 * won't load the file and won't delete the entry. */
960 else if (rb_thread_shield_release(thread_shield)) {
961 /* still in-use */
962 return ST_CONTINUE;
964 xfree((char *)*key);
965 return ST_DELETE;
968 static void
969 load_unlock(rb_vm_t *vm, const char *ftptr, int done)
971 if (ftptr) {
972 st_data_t key = (st_data_t)ftptr;
973 st_table *loading_tbl = get_loading_table(vm);
975 st_update(loading_tbl, key, release_thread_shield, done);
979 static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
982 * call-seq:
983 * require(name) -> true or false
985 * Loads the given +name+, returning +true+ if successful and +false+ if the
986 * feature is already loaded.
988 * If the filename neither resolves to an absolute path nor starts with
989 * './' or '../', the file will be searched for in the library
990 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
991 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
993 * If the filename has the extension ".rb", it is loaded as a source file; if
994 * the extension is ".so", ".o", or the default shared library extension on
995 * the current platform, Ruby loads the shared library as a Ruby extension.
996 * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
997 * found. If the file named cannot be found, a LoadError will be raised.
999 * For Ruby extensions the filename given may use ".so" or ".o". For example,
1000 * on macOS the socket extension is "socket.bundle" and
1001 * <code>require 'socket.so'</code> will load the socket extension.
1003 * The absolute path of the loaded file is added to
1004 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
1005 * loaded again if its path already appears in <code>$"</code>. For example,
1006 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1007 * again.
1009 * require "my-library.rb"
1010 * require "db-driver"
1012 * Any constants or globals within the loaded source file will be available
1013 * in the calling program's global namespace. However, local variables will
1014 * not be propagated to the loading environment.
1018 VALUE
1019 rb_f_require(VALUE obj, VALUE fname)
1021 return rb_require_string(fname);
1025 * call-seq:
1026 * require_relative(string) -> true or false
1028 * Ruby tries to load the library named _string_ relative to the directory
1029 * containing the requiring file. If the file does not exist a LoadError is
1030 * raised. Returns +true+ if the file was loaded and +false+ if the file was
1031 * already loaded before.
1033 VALUE
1034 rb_f_require_relative(VALUE obj, VALUE fname)
1036 VALUE base = rb_current_realfilepath();
1037 if (NIL_P(base)) {
1038 rb_loaderror("cannot infer basepath");
1040 base = rb_file_dirname(base);
1041 return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1044 typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1046 static int
1047 search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1049 VALUE tmp;
1050 char *ext, *ftptr;
1051 int ft = 0;
1052 const char *loading;
1054 *path = 0;
1055 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
1056 if (ext && !strchr(ext, '/')) {
1057 if (IS_RBEXT(ext)) {
1058 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
1059 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1060 return 'r';
1062 if ((tmp = rb_find_file(fname)) != 0) {
1063 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1064 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
1065 *path = tmp;
1066 return 'r';
1068 return 0;
1070 else if (IS_SOEXT(ext)) {
1071 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1072 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1073 return 's';
1075 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1076 rb_str_cat2(tmp, DLEXT);
1077 OBJ_FREEZE(tmp);
1078 if ((tmp = rb_find_file(tmp)) != 0) {
1079 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1080 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1081 *path = tmp;
1082 return 's';
1085 else if (IS_DLEXT(ext)) {
1086 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1087 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1088 return 's';
1090 if ((tmp = rb_find_file(fname)) != 0) {
1091 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1092 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1093 *path = tmp;
1094 return 's';
1098 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1099 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1100 return 'r';
1102 tmp = fname;
1103 const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1105 // Check if it's a statically linked extension when
1106 // not already a feature and not found as a dynamic library.
1107 if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
1108 VALUE lookup_name = tmp;
1109 // Append ".so" if not already present so for example "etc" can find "etc.so".
1110 // We always register statically linked extensions with a ".so" extension.
1111 // See encinit.c and extinit.c (generated at build-time).
1112 if (!ext) {
1113 lookup_name = rb_str_dup(lookup_name);
1114 rb_str_cat_cstr(lookup_name, ".so");
1116 ftptr = RSTRING_PTR(lookup_name);
1117 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1118 *path = rb_filesystem_str_new_cstr(ftptr);
1119 return 's';
1123 switch (type) {
1124 case 0:
1125 if (ft)
1126 goto feature_present;
1127 ftptr = RSTRING_PTR(tmp);
1128 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1130 default:
1131 if (ft) {
1132 goto feature_present;
1134 /* fall through */
1135 case loadable_ext_rb:
1136 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1137 if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
1138 break;
1139 *path = tmp;
1141 return type > loadable_ext_rb ? 's' : 'r';
1143 feature_present:
1144 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1145 return ft;
1148 static void
1149 load_failed(VALUE fname)
1151 rb_load_fail(fname, "cannot load such file");
1154 static VALUE
1155 load_ext(VALUE path)
1157 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1158 return (VALUE)dln_load(RSTRING_PTR(path));
1161 static bool
1162 run_static_ext_init(rb_vm_t *vm, const char *feature)
1164 st_data_t key = (st_data_t)feature;
1165 st_data_t init_func;
1167 if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1168 ((void (*)(void))init_func)();
1169 return true;
1171 return false;
1174 static int
1175 no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1177 return 0;
1180 // Documented in doc/globals.rdoc
1181 VALUE
1182 rb_resolve_feature_path(VALUE klass, VALUE fname)
1184 VALUE path;
1185 int found;
1186 VALUE sym;
1188 fname = rb_get_path(fname);
1189 path = rb_str_encode_ospath(fname);
1190 found = search_required(GET_VM(), path, &path, no_feature_p);
1192 switch (found) {
1193 case 'r':
1194 sym = ID2SYM(rb_intern("rb"));
1195 break;
1196 case 's':
1197 sym = ID2SYM(rb_intern("so"));
1198 break;
1199 default:
1200 return Qnil;
1203 return rb_ary_new_from_args(2, sym, path);
1206 static void
1207 ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1209 *prev = th->ext_config;
1210 th->ext_config = (struct rb_ext_config){0};
1213 static void
1214 ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1216 th->ext_config = *prev;
1219 void
1220 rb_ext_ractor_safe(bool flag)
1222 GET_THREAD()->ext_config.ractor_safe = flag;
1226 * returns
1227 * 0: if already loaded (false)
1228 * 1: successfully loaded (true)
1229 * <0: not found (LoadError)
1230 * >1: exception
1232 static int
1233 require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1235 volatile int result = -1;
1236 rb_thread_t *th = rb_ec_thread_ptr(ec);
1237 volatile const struct {
1238 VALUE wrapper, self, errinfo;
1239 rb_execution_context_t *ec;
1240 } saved = {
1241 th->top_wrapper, th->top_self, ec->errinfo,
1244 enum ruby_tag_type state;
1245 char *volatile ftptr = 0;
1246 VALUE path;
1247 volatile VALUE saved_path;
1248 volatile VALUE realpath = 0;
1249 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1250 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
1251 volatile bool reset_ext_config = false;
1252 struct rb_ext_config prev_ext_config;
1254 path = rb_str_encode_ospath(fname);
1255 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1256 saved_path = path;
1258 EC_PUSH_TAG(ec);
1259 ec->errinfo = Qnil; /* ensure */
1260 th->top_wrapper = 0;
1261 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1262 VALUE handle;
1263 int found;
1265 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1266 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1267 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1268 path = saved_path;
1270 if (found) {
1271 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1272 result = 0;
1274 else if (!*ftptr) {
1275 result = TAG_RETURN;
1277 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1278 result = TAG_RETURN;
1280 else if (RTEST(rb_hash_aref(realpaths,
1281 realpath = realpath_internal_cached(realpath_map, path)))) {
1282 result = 0;
1284 else {
1285 switch (found) {
1286 case 'r':
1287 load_iseq_eval(saved.ec, path);
1288 break;
1290 case 's':
1291 reset_ext_config = true;
1292 ext_config_push(th, &prev_ext_config);
1293 handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1294 path, VM_BLOCK_HANDLER_NONE, path);
1295 rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1296 break;
1298 result = TAG_RETURN;
1302 EC_POP_TAG();
1304 ec = saved.ec;
1305 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1306 th2->top_self = saved.self;
1307 th2->top_wrapper = saved.wrapper;
1308 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1310 path = saved_path;
1311 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1313 if (state) {
1314 if (state == TAG_FATAL || state == TAG_THROW) {
1315 EC_JUMP_TAG(ec, state);
1317 else if (exception) {
1318 /* usually state == TAG_RAISE only, except for
1319 * rb_iseq_load_iseq in load_iseq_eval case */
1320 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1321 if (!NIL_P(exc)) ec->errinfo = exc;
1322 return TAG_RAISE;
1324 else if (state == TAG_RETURN) {
1325 return TAG_RAISE;
1327 RB_GC_GUARD(fname);
1328 /* never TAG_RETURN */
1329 return state;
1331 if (!NIL_P(ec->errinfo)) {
1332 if (!exception) return TAG_RAISE;
1333 rb_exc_raise(ec->errinfo);
1336 if (result == TAG_RETURN) {
1337 rb_provide_feature(th2->vm, path);
1338 VALUE real = realpath;
1339 if (real) {
1340 real = rb_fstring(real);
1341 rb_hash_aset(realpaths, real, Qtrue);
1344 ec->errinfo = saved.errinfo;
1346 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1348 return result;
1352 rb_require_internal_silent(VALUE fname)
1354 rb_execution_context_t *ec = GET_EC();
1355 return require_internal(ec, fname, 1, false);
1359 rb_require_internal(VALUE fname)
1361 rb_execution_context_t *ec = GET_EC();
1362 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1366 ruby_require_internal(const char *fname, unsigned int len)
1368 struct RString fake;
1369 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1370 rb_execution_context_t *ec = GET_EC();
1371 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1372 rb_set_errinfo(Qnil);
1373 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1376 VALUE
1377 rb_require_string(VALUE fname)
1379 return rb_require_string_internal(FilePathValue(fname), false);
1382 static VALUE
1383 rb_require_string_internal(VALUE fname, bool resurrect)
1385 rb_execution_context_t *ec = GET_EC();
1386 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1388 if (result > TAG_RETURN) {
1389 EC_JUMP_TAG(ec, result);
1391 if (result < 0) {
1392 if (resurrect) fname = rb_str_resurrect(fname);
1393 load_failed(fname);
1396 return RBOOL(result);
1399 VALUE
1400 rb_require(const char *fname)
1402 struct RString fake;
1403 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1404 return rb_require_string_internal(str, true);
1407 static int
1408 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1410 const char *name = (char *)*key;
1411 if (existing) {
1412 /* already registered */
1413 rb_warn("%s is already registered", name);
1415 else {
1416 *value = (st_data_t)init;
1418 return ST_CONTINUE;
1421 // Private API for statically linked extensions.
1422 // Used with the ext/Setup file, the --with-setup and
1423 // --with-static-linked-ext configuration option, etc.
1424 void
1425 ruby_init_ext(const char *name, void (*init)(void))
1427 st_table *inits_table;
1428 rb_vm_t *vm = GET_VM();
1430 if (feature_provided(vm, name, 0))
1431 return;
1433 inits_table = vm->static_ext_inits;
1434 if (!inits_table) {
1435 inits_table = st_init_strtable();
1436 vm->static_ext_inits = inits_table;
1438 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1442 * call-seq:
1443 * mod.autoload(const, filename) -> nil
1445 * Registers _filename_ to be loaded (using Kernel::require)
1446 * the first time that _const_ (which may be a String or
1447 * a symbol) is accessed in the namespace of _mod_.
1449 * module A
1450 * end
1451 * A.autoload(:B, "b")
1452 * A::B.doit # autoloads "b"
1454 * If _const_ in _mod_ is defined as autoload, the file name to be
1455 * loaded is replaced with _filename_. If _const_ is defined but not
1456 * as autoload, does nothing.
1459 static VALUE
1460 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1462 ID id = rb_to_id(sym);
1464 FilePathValue(file);
1465 rb_autoload_str(mod, id, file);
1466 return Qnil;
1470 * call-seq:
1471 * mod.autoload?(name, inherit=true) -> String or nil
1473 * Returns _filename_ to be loaded if _name_ is registered as
1474 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1476 * module A
1477 * end
1478 * A.autoload(:B, "b")
1479 * A.autoload?(:B) #=> "b"
1481 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1483 * class A
1484 * autoload :CONST, "const.rb"
1485 * end
1487 * class B < A
1488 * end
1490 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1491 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1495 static VALUE
1496 rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1498 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1499 VALUE sym = argv[0];
1501 ID id = rb_check_id(&sym);
1502 if (!id) {
1503 return Qnil;
1505 return rb_autoload_at_p(mod, id, recur);
1509 * call-seq:
1510 * autoload(const, filename) -> nil
1512 * Registers _filename_ to be loaded (using Kernel::require)
1513 * the first time that _const_ (which may be a String or
1514 * a symbol) is accessed.
1516 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1518 * If _const_ is defined as autoload, the file name to be loaded is
1519 * replaced with _filename_. If _const_ is defined but not as
1520 * autoload, does nothing.
1523 static VALUE
1524 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1526 VALUE klass = rb_class_real(rb_vm_cbase());
1527 if (!klass) {
1528 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1530 return rb_mod_autoload(klass, sym, file);
1534 * call-seq:
1535 * autoload?(name, inherit=true) -> String or nil
1537 * Returns _filename_ to be loaded if _name_ is registered as
1538 * +autoload+ in the current namespace or one of its ancestors.
1540 * autoload(:B, "b")
1541 * autoload?(:B) #=> "b"
1543 * module C
1544 * autoload(:D, "d")
1545 * autoload?(:D) #=> "d"
1546 * autoload?(:B) #=> nil
1547 * end
1549 * class E
1550 * autoload(:F, "f")
1551 * autoload?(:F) #=> "f"
1552 * autoload?(:B) #=> "b"
1553 * end
1556 static VALUE
1557 rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1559 /* use rb_vm_cbase() as same as rb_f_autoload. */
1560 VALUE klass = rb_vm_cbase();
1561 if (NIL_P(klass)) {
1562 return Qnil;
1564 return rb_mod_autoload_p(argc, argv, klass);
1567 void *
1568 rb_ext_resolve_symbol(const char* fname, const char* symbol)
1570 VALUE handle;
1571 VALUE resolved;
1572 VALUE path;
1573 char *ext;
1574 VALUE fname_str = rb_str_new_cstr(fname);
1576 resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1577 if (NIL_P(resolved)) {
1578 ext = strrchr(fname, '.');
1579 if (!ext || !IS_SOEXT(ext)) {
1580 rb_str_cat_cstr(fname_str, ".so");
1582 if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
1583 return dln_symbol(NULL, symbol);
1585 return NULL;
1587 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1588 return NULL;
1590 path = rb_ary_entry(resolved, 1);
1591 handle = rb_hash_lookup(ruby_dln_libmap, path);
1592 if (NIL_P(handle)) {
1593 return NULL;
1595 return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1598 void
1599 Init_load(void)
1601 rb_vm_t *vm = GET_VM();
1602 static const char var_load_path[] = "$:";
1603 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1605 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1606 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1607 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1608 vm->load_path = rb_ary_new();
1609 vm->expanded_load_path = rb_ary_hidden_new(0);
1610 vm->load_path_snapshot = rb_ary_hidden_new(0);
1611 vm->load_path_check_cache = 0;
1612 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1614 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1615 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1616 vm->loaded_features = rb_ary_new();
1617 vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1618 vm->loaded_features_index = st_init_numtable();
1619 vm->loaded_features_realpaths = rb_hash_new();
1620 rb_obj_hide(vm->loaded_features_realpaths);
1621 vm->loaded_features_realpath_map = rb_hash_new();
1622 rb_obj_hide(vm->loaded_features_realpath_map);
1624 rb_define_global_function("load", rb_f_load, -1);
1625 rb_define_global_function("require", rb_f_require, 1);
1626 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1627 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1628 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1629 rb_define_global_function("autoload", rb_f_autoload, 2);
1630 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1632 ruby_dln_libmap = rb_hash_new_with_size(0);
1633 rb_vm_register_global_object(ruby_dln_libmap);