[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / load.c
blob37f7248b7dc2639d54f6a7a93dc1c5afe45c96ab
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;
750 VALUE error = pm_load_parse_file(&result, fname);
752 if (error == Qnil) {
753 iseq = pm_iseq_new_top(&result.node, rb_fstring_lit("<top (required)>"), fname, realpath_internal_cached(realpath_map, fname), NULL);
754 pm_parse_result_free(&result);
756 else {
757 rb_vm_pop_frame(ec);
758 RB_GC_GUARD(v);
759 pm_parse_result_free(&result);
760 rb_exc_raise(error);
763 else {
764 rb_ast_t *ast;
765 VALUE ast_value;
766 VALUE parser = rb_parser_new();
767 rb_parser_set_context(parser, NULL, FALSE);
768 ast_value = rb_parser_load_file(parser, fname);
769 ast = rb_ruby_ast_data_get(ast_value);
771 iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
772 fname, realpath_internal_cached(realpath_map, fname), NULL);
773 rb_ast_dispose(ast);
776 rb_vm_pop_frame(ec);
777 RB_GC_GUARD(v);
779 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
780 rb_iseq_eval(iseq);
783 static inline enum ruby_tag_type
784 load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
786 enum ruby_tag_type state;
787 rb_thread_t *th = rb_ec_thread_ptr(ec);
788 volatile VALUE wrapper = th->top_wrapper;
789 volatile VALUE self = th->top_self;
790 #if !defined __GNUC__
791 rb_thread_t *volatile th0 = th;
792 #endif
794 ec->errinfo = Qnil; /* ensure */
796 /* load in module as toplevel */
797 th->top_self = rb_obj_clone(rb_vm_top_self());
798 th->top_wrapper = load_wrapper;
799 rb_extend_object(th->top_self, th->top_wrapper);
801 EC_PUSH_TAG(ec);
802 state = EC_EXEC_TAG();
803 if (state == TAG_NONE) {
804 load_iseq_eval(ec, fname);
806 EC_POP_TAG();
808 #if !defined __GNUC__
809 th = th0;
810 fname = RB_GC_GUARD(fname);
811 #endif
812 th->top_self = self;
813 th->top_wrapper = wrapper;
814 return state;
817 static inline void
818 raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
820 if (state) {
821 rb_vm_jump_tag_but_local_jump(state);
824 if (!NIL_P(ec->errinfo)) {
825 rb_exc_raise(ec->errinfo);
829 static void
830 rb_load_internal(VALUE fname, VALUE wrap)
832 rb_execution_context_t *ec = GET_EC();
833 enum ruby_tag_type state = TAG_NONE;
834 if (RTEST(wrap)) {
835 if (!RB_TYPE_P(wrap, T_MODULE)) {
836 wrap = rb_module_new();
838 state = load_wrapping(ec, fname, wrap);
840 else {
841 load_iseq_eval(ec, fname);
843 raise_load_if_failed(ec, state);
846 void
847 rb_load(VALUE fname, int wrap)
849 VALUE tmp = rb_find_file(FilePathValue(fname));
850 if (!tmp) load_failed(fname);
851 rb_load_internal(tmp, RBOOL(wrap));
854 void
855 rb_load_protect(VALUE fname, int wrap, int *pstate)
857 enum ruby_tag_type state;
859 EC_PUSH_TAG(GET_EC());
860 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
861 rb_load(fname, wrap);
863 EC_POP_TAG();
865 if (state != TAG_NONE) *pstate = state;
869 * call-seq:
870 * load(filename, wrap=false) -> true
872 * Loads and executes the Ruby program in the file _filename_.
874 * If the filename is an absolute path (e.g. starts with '/'), the file
875 * will be loaded directly using the absolute path.
877 * If the filename is an explicit relative path (e.g. starts with './' or
878 * '../'), the file will be loaded using the relative path from the current
879 * directory.
881 * Otherwise, the file will be searched for in the library
882 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
883 * If the file is found in a directory, it will attempt to load the file
884 * relative to that directory. If the file is not found in any of the
885 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
886 * the relative path from the current directory.
888 * If the file doesn't exist when there is an attempt to load it, a
889 * LoadError will be raised.
891 * If the optional _wrap_ parameter is +true+, the loaded script will
892 * be executed under an anonymous module. If the optional _wrap_ parameter
893 * is a module, the loaded script will be executed under the given module.
894 * In no circumstance will any local variables in the loaded file be
895 * propagated to the loading environment.
898 static VALUE
899 rb_f_load(int argc, VALUE *argv, VALUE _)
901 VALUE fname, wrap, path, orig_fname;
903 rb_scan_args(argc, argv, "11", &fname, &wrap);
905 orig_fname = rb_get_path_check_to_string(fname);
906 fname = rb_str_encode_ospath(orig_fname);
907 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
909 path = rb_find_file(fname);
910 if (!path) {
911 if (!rb_file_load_ok(RSTRING_PTR(fname)))
912 load_failed(orig_fname);
913 path = fname;
915 rb_load_internal(path, wrap);
917 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
919 return Qtrue;
922 static char *
923 load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
925 st_data_t data;
926 st_table *loading_tbl = get_loading_table(vm);
928 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
929 /* partial state */
930 ftptr = ruby_strdup(ftptr);
931 data = (st_data_t)rb_thread_shield_new();
932 st_insert(loading_tbl, (st_data_t)ftptr, data);
933 return (char *)ftptr;
936 if (warn && rb_thread_shield_owned((VALUE)data)) {
937 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
938 rb_backtrace_each(rb_str_append, warning);
939 rb_warning("%"PRIsVALUE, warning);
941 switch (rb_thread_shield_wait((VALUE)data)) {
942 case Qfalse:
943 case Qnil:
944 return 0;
946 return (char *)ftptr;
949 static int
950 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
952 VALUE thread_shield = (VALUE)*value;
953 if (!existing) return ST_STOP;
954 if (done) {
955 rb_thread_shield_destroy(thread_shield);
956 /* Delete the entry even if there are waiting threads, because they
957 * won't load the file and won't delete the entry. */
959 else if (rb_thread_shield_release(thread_shield)) {
960 /* still in-use */
961 return ST_CONTINUE;
963 xfree((char *)*key);
964 return ST_DELETE;
967 static void
968 load_unlock(rb_vm_t *vm, const char *ftptr, int done)
970 if (ftptr) {
971 st_data_t key = (st_data_t)ftptr;
972 st_table *loading_tbl = get_loading_table(vm);
974 st_update(loading_tbl, key, release_thread_shield, done);
978 static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
981 * call-seq:
982 * require(name) -> true or false
984 * Loads the given +name+, returning +true+ if successful and +false+ if the
985 * feature is already loaded.
987 * If the filename neither resolves to an absolute path nor starts with
988 * './' or '../', the file will be searched for in the library
989 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
990 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
992 * If the filename has the extension ".rb", it is loaded as a source file; if
993 * the extension is ".so", ".o", or the default shared library extension on
994 * the current platform, Ruby loads the shared library as a Ruby extension.
995 * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
996 * found. If the file named cannot be found, a LoadError will be raised.
998 * For Ruby extensions the filename given may use ".so" or ".o". For example,
999 * on macOS the socket extension is "socket.bundle" and
1000 * <code>require 'socket.so'</code> will load the socket extension.
1002 * The absolute path of the loaded file is added to
1003 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
1004 * loaded again if its path already appears in <code>$"</code>. For example,
1005 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1006 * again.
1008 * require "my-library.rb"
1009 * require "db-driver"
1011 * Any constants or globals within the loaded source file will be available
1012 * in the calling program's global namespace. However, local variables will
1013 * not be propagated to the loading environment.
1017 VALUE
1018 rb_f_require(VALUE obj, VALUE fname)
1020 return rb_require_string(fname);
1024 * call-seq:
1025 * require_relative(string) -> true or false
1027 * Ruby tries to load the library named _string_ relative to the directory
1028 * containing the requiring file. If the file does not exist a LoadError is
1029 * raised. Returns +true+ if the file was loaded and +false+ if the file was
1030 * already loaded before.
1032 VALUE
1033 rb_f_require_relative(VALUE obj, VALUE fname)
1035 VALUE base = rb_current_realfilepath();
1036 if (NIL_P(base)) {
1037 rb_loaderror("cannot infer basepath");
1039 base = rb_file_dirname(base);
1040 return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1043 typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1045 static int
1046 search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1048 VALUE tmp;
1049 char *ext, *ftptr;
1050 int ft = 0;
1051 const char *loading;
1053 *path = 0;
1054 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
1055 if (ext && !strchr(ext, '/')) {
1056 if (IS_RBEXT(ext)) {
1057 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
1058 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1059 return 'r';
1061 if ((tmp = rb_find_file(fname)) != 0) {
1062 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1063 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
1064 *path = tmp;
1065 return 'r';
1067 return 0;
1069 else if (IS_SOEXT(ext)) {
1070 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1071 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1072 return 's';
1074 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1075 rb_str_cat2(tmp, DLEXT);
1076 OBJ_FREEZE(tmp);
1077 if ((tmp = rb_find_file(tmp)) != 0) {
1078 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1079 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1080 *path = tmp;
1081 return 's';
1084 else if (IS_DLEXT(ext)) {
1085 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1086 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1087 return 's';
1089 if ((tmp = rb_find_file(fname)) != 0) {
1090 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1091 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1092 *path = tmp;
1093 return 's';
1097 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1098 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1099 return 'r';
1101 tmp = fname;
1102 const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1104 // Check if it's a statically linked extension when
1105 // not already a feature and not found as a dynamic library.
1106 if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
1107 VALUE lookup_name = tmp;
1108 // Append ".so" if not already present so for example "etc" can find "etc.so".
1109 // We always register statically linked extensions with a ".so" extension.
1110 // See encinit.c and extinit.c (generated at build-time).
1111 if (!ext) {
1112 lookup_name = rb_str_dup(lookup_name);
1113 rb_str_cat_cstr(lookup_name, ".so");
1115 ftptr = RSTRING_PTR(lookup_name);
1116 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1117 *path = rb_filesystem_str_new_cstr(ftptr);
1118 return 's';
1122 switch (type) {
1123 case 0:
1124 if (ft)
1125 goto feature_present;
1126 ftptr = RSTRING_PTR(tmp);
1127 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1129 default:
1130 if (ft) {
1131 goto feature_present;
1133 /* fall through */
1134 case loadable_ext_rb:
1135 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1136 if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
1137 break;
1138 *path = tmp;
1140 return type > loadable_ext_rb ? 's' : 'r';
1142 feature_present:
1143 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1144 return ft;
1147 static void
1148 load_failed(VALUE fname)
1150 rb_load_fail(fname, "cannot load such file");
1153 static VALUE
1154 load_ext(VALUE path)
1156 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1157 return (VALUE)dln_load(RSTRING_PTR(path));
1160 static bool
1161 run_static_ext_init(rb_vm_t *vm, const char *feature)
1163 st_data_t key = (st_data_t)feature;
1164 st_data_t init_func;
1166 if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1167 ((void (*)(void))init_func)();
1168 return true;
1170 return false;
1173 static int
1174 no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1176 return 0;
1179 // Documented in doc/globals.rdoc
1180 VALUE
1181 rb_resolve_feature_path(VALUE klass, VALUE fname)
1183 VALUE path;
1184 int found;
1185 VALUE sym;
1187 fname = rb_get_path(fname);
1188 path = rb_str_encode_ospath(fname);
1189 found = search_required(GET_VM(), path, &path, no_feature_p);
1191 switch (found) {
1192 case 'r':
1193 sym = ID2SYM(rb_intern("rb"));
1194 break;
1195 case 's':
1196 sym = ID2SYM(rb_intern("so"));
1197 break;
1198 default:
1199 return Qnil;
1202 return rb_ary_new_from_args(2, sym, path);
1205 static void
1206 ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1208 *prev = th->ext_config;
1209 th->ext_config = (struct rb_ext_config){0};
1212 static void
1213 ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1215 th->ext_config = *prev;
1218 void
1219 rb_ext_ractor_safe(bool flag)
1221 GET_THREAD()->ext_config.ractor_safe = flag;
1225 * returns
1226 * 0: if already loaded (false)
1227 * 1: successfully loaded (true)
1228 * <0: not found (LoadError)
1229 * >1: exception
1231 static int
1232 require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1234 volatile int result = -1;
1235 rb_thread_t *th = rb_ec_thread_ptr(ec);
1236 volatile const struct {
1237 VALUE wrapper, self, errinfo;
1238 rb_execution_context_t *ec;
1239 } saved = {
1240 th->top_wrapper, th->top_self, ec->errinfo,
1243 enum ruby_tag_type state;
1244 char *volatile ftptr = 0;
1245 VALUE path;
1246 volatile VALUE saved_path;
1247 volatile VALUE realpath = 0;
1248 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1249 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
1250 volatile bool reset_ext_config = false;
1251 struct rb_ext_config prev_ext_config;
1253 path = rb_str_encode_ospath(fname);
1254 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1255 saved_path = path;
1257 EC_PUSH_TAG(ec);
1258 ec->errinfo = Qnil; /* ensure */
1259 th->top_wrapper = 0;
1260 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1261 VALUE handle;
1262 int found;
1264 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1265 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1266 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1267 path = saved_path;
1269 if (found) {
1270 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1271 result = 0;
1273 else if (!*ftptr) {
1274 result = TAG_RETURN;
1276 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1277 result = TAG_RETURN;
1279 else if (RTEST(rb_hash_aref(realpaths,
1280 realpath = realpath_internal_cached(realpath_map, path)))) {
1281 result = 0;
1283 else {
1284 switch (found) {
1285 case 'r':
1286 load_iseq_eval(ec, path);
1287 break;
1289 case 's':
1290 reset_ext_config = true;
1291 ext_config_push(th, &prev_ext_config);
1292 handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1293 path, VM_BLOCK_HANDLER_NONE, path);
1294 rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1295 break;
1297 result = TAG_RETURN;
1301 EC_POP_TAG();
1303 ec = saved.ec;
1304 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1305 th2->top_self = saved.self;
1306 th2->top_wrapper = saved.wrapper;
1307 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1309 path = saved_path;
1310 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1312 if (state) {
1313 if (state == TAG_FATAL || state == TAG_THROW) {
1314 EC_JUMP_TAG(ec, state);
1316 else if (exception) {
1317 /* usually state == TAG_RAISE only, except for
1318 * rb_iseq_load_iseq in load_iseq_eval case */
1319 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1320 if (!NIL_P(exc)) ec->errinfo = exc;
1321 return TAG_RAISE;
1323 else if (state == TAG_RETURN) {
1324 return TAG_RAISE;
1326 RB_GC_GUARD(fname);
1327 /* never TAG_RETURN */
1328 return state;
1330 if (!NIL_P(ec->errinfo)) {
1331 if (!exception) return TAG_RAISE;
1332 rb_exc_raise(ec->errinfo);
1335 if (result == TAG_RETURN) {
1336 rb_provide_feature(th2->vm, path);
1337 VALUE real = realpath;
1338 if (real) {
1339 real = rb_fstring(real);
1340 rb_hash_aset(realpaths, real, Qtrue);
1343 ec->errinfo = saved.errinfo;
1345 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1347 return result;
1351 rb_require_internal_silent(VALUE fname)
1353 rb_execution_context_t *ec = GET_EC();
1354 return require_internal(ec, fname, 1, false);
1358 rb_require_internal(VALUE fname)
1360 rb_execution_context_t *ec = GET_EC();
1361 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1365 ruby_require_internal(const char *fname, unsigned int len)
1367 struct RString fake;
1368 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1369 rb_execution_context_t *ec = GET_EC();
1370 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1371 rb_set_errinfo(Qnil);
1372 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1375 VALUE
1376 rb_require_string(VALUE fname)
1378 return rb_require_string_internal(FilePathValue(fname), false);
1381 static VALUE
1382 rb_require_string_internal(VALUE fname, bool resurrect)
1384 rb_execution_context_t *ec = GET_EC();
1385 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1387 if (result > TAG_RETURN) {
1388 EC_JUMP_TAG(ec, result);
1390 if (result < 0) {
1391 if (resurrect) fname = rb_str_resurrect(fname);
1392 load_failed(fname);
1395 return RBOOL(result);
1398 VALUE
1399 rb_require(const char *fname)
1401 struct RString fake;
1402 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1403 return rb_require_string_internal(str, true);
1406 static int
1407 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1409 const char *name = (char *)*key;
1410 if (existing) {
1411 /* already registered */
1412 rb_warn("%s is already registered", name);
1414 else {
1415 *value = (st_data_t)init;
1417 return ST_CONTINUE;
1420 // Private API for statically linked extensions.
1421 // Used with the ext/Setup file, the --with-setup and
1422 // --with-static-linked-ext configuration option, etc.
1423 void
1424 ruby_init_ext(const char *name, void (*init)(void))
1426 st_table *inits_table;
1427 rb_vm_t *vm = GET_VM();
1429 if (feature_provided(vm, name, 0))
1430 return;
1432 inits_table = vm->static_ext_inits;
1433 if (!inits_table) {
1434 inits_table = st_init_strtable();
1435 vm->static_ext_inits = inits_table;
1437 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1441 * call-seq:
1442 * mod.autoload(const, filename) -> nil
1444 * Registers _filename_ to be loaded (using Kernel::require)
1445 * the first time that _const_ (which may be a String or
1446 * a symbol) is accessed in the namespace of _mod_.
1448 * module A
1449 * end
1450 * A.autoload(:B, "b")
1451 * A::B.doit # autoloads "b"
1453 * If _const_ in _mod_ is defined as autoload, the file name to be
1454 * loaded is replaced with _filename_. If _const_ is defined but not
1455 * as autoload, does nothing.
1458 static VALUE
1459 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1461 ID id = rb_to_id(sym);
1463 FilePathValue(file);
1464 rb_autoload_str(mod, id, file);
1465 return Qnil;
1469 * call-seq:
1470 * mod.autoload?(name, inherit=true) -> String or nil
1472 * Returns _filename_ to be loaded if _name_ is registered as
1473 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1475 * module A
1476 * end
1477 * A.autoload(:B, "b")
1478 * A.autoload?(:B) #=> "b"
1480 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1482 * class A
1483 * autoload :CONST, "const.rb"
1484 * end
1486 * class B < A
1487 * end
1489 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1490 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1494 static VALUE
1495 rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1497 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1498 VALUE sym = argv[0];
1500 ID id = rb_check_id(&sym);
1501 if (!id) {
1502 return Qnil;
1504 return rb_autoload_at_p(mod, id, recur);
1508 * call-seq:
1509 * autoload(const, filename) -> nil
1511 * Registers _filename_ to be loaded (using Kernel::require)
1512 * the first time that _const_ (which may be a String or
1513 * a symbol) is accessed.
1515 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1517 * If _const_ is defined as autoload, the file name to be loaded is
1518 * replaced with _filename_. If _const_ is defined but not as
1519 * autoload, does nothing.
1522 static VALUE
1523 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1525 VALUE klass = rb_class_real(rb_vm_cbase());
1526 if (!klass) {
1527 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1529 return rb_mod_autoload(klass, sym, file);
1533 * call-seq:
1534 * autoload?(name, inherit=true) -> String or nil
1536 * Returns _filename_ to be loaded if _name_ is registered as
1537 * +autoload+ in the current namespace or one of its ancestors.
1539 * autoload(:B, "b")
1540 * autoload?(:B) #=> "b"
1542 * module C
1543 * autoload(:D, "d")
1544 * autoload?(:D) #=> "d"
1545 * autoload?(:B) #=> nil
1546 * end
1548 * class E
1549 * autoload(:F, "f")
1550 * autoload?(:F) #=> "f"
1551 * autoload?(:B) #=> "b"
1552 * end
1555 static VALUE
1556 rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1558 /* use rb_vm_cbase() as same as rb_f_autoload. */
1559 VALUE klass = rb_vm_cbase();
1560 if (NIL_P(klass)) {
1561 return Qnil;
1563 return rb_mod_autoload_p(argc, argv, klass);
1566 void *
1567 rb_ext_resolve_symbol(const char* fname, const char* symbol)
1569 VALUE handle;
1570 VALUE resolved;
1571 VALUE path;
1572 char *ext;
1573 VALUE fname_str = rb_str_new_cstr(fname);
1575 resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1576 if (NIL_P(resolved)) {
1577 ext = strrchr(fname, '.');
1578 if (!ext || !IS_SOEXT(ext)) {
1579 rb_str_cat_cstr(fname_str, ".so");
1581 if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
1582 return dln_symbol(NULL, symbol);
1584 return NULL;
1586 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1587 return NULL;
1589 path = rb_ary_entry(resolved, 1);
1590 handle = rb_hash_lookup(ruby_dln_libmap, path);
1591 if (NIL_P(handle)) {
1592 return NULL;
1594 return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1597 void
1598 Init_load(void)
1600 rb_vm_t *vm = GET_VM();
1601 static const char var_load_path[] = "$:";
1602 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1604 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1605 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1606 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1607 vm->load_path = rb_ary_new();
1608 vm->expanded_load_path = rb_ary_hidden_new(0);
1609 vm->load_path_snapshot = rb_ary_hidden_new(0);
1610 vm->load_path_check_cache = 0;
1611 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1613 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1614 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1615 vm->loaded_features = rb_ary_new();
1616 vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1617 vm->loaded_features_index = st_init_numtable();
1618 vm->loaded_features_realpaths = rb_hash_new();
1619 rb_obj_hide(vm->loaded_features_realpaths);
1620 vm->loaded_features_realpath_map = rb_hash_new();
1621 rb_obj_hide(vm->loaded_features_realpath_map);
1623 rb_define_global_function("load", rb_f_load, -1);
1624 rb_define_global_function("require", rb_f_require, 1);
1625 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1626 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1627 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1628 rb_define_global_function("autoload", rb_f_autoload, 2);
1629 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1631 ruby_dln_libmap = rb_hash_new_with_size(0);
1632 rb_vm_register_global_object(ruby_dln_libmap);