* 2022-01-18 [ci skip]
[ruby-80x24.org.git] / load.c
bloba2b9da48fb28484a57195f6b01b4e62c3a463fde
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/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"
20 static VALUE ruby_dln_librefs;
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)
26 static const char *const loadable_ext[] = {
27 ".rb", DLEXT,
31 static const char *const ruby_ext[] = {
32 ".rb",
36 enum expand_type {
37 EXPAND_ALL,
38 EXPAND_RELATIVE,
39 EXPAND_HOME,
40 EXPAND_NON_CACHE
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.
48 static void
49 rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache)
51 VALUE load_path = vm->load_path;
52 VALUE expanded_load_path = vm->expanded_load_path;
53 VALUE ary;
54 long i;
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);
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;
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));
90 rb_obj_freeze(ary);
91 vm->expanded_load_path = ary;
92 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
95 static VALUE
96 get_expanded_load_path(rb_vm_t *vm)
98 const VALUE non_cache = Qtrue;
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();
107 else if (has_non_cache) {
108 /* Non string object. */
109 vm->load_path_check_cache = non_cache;
111 else {
112 vm->load_path_check_cache = 0;
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);
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);
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);
137 return vm->expanded_load_path;
140 VALUE
141 rb_get_expanded_load_path(void)
143 return get_expanded_load_path(GET_VM());
146 static VALUE
147 load_path_getter(ID id, VALUE * p)
149 rb_vm_t *vm = (void *)p;
150 return vm->load_path;
153 static VALUE
154 get_loaded_features(rb_vm_t *vm)
156 return vm->loaded_features;
159 static VALUE
160 get_loaded_features_realpaths(rb_vm_t *vm)
162 return vm->loaded_features_realpaths;
165 static VALUE
166 get_LOADED_FEATURES(ID _x, VALUE *_y)
168 return get_loaded_features(GET_VM());
171 static void
172 reset_loaded_features_snapshot(rb_vm_t *vm)
174 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
177 static struct st_table *
178 get_loaded_features_index_raw(rb_vm_t *vm)
180 return vm->loaded_features_index;
183 static st_table *
184 get_loading_table(rb_vm_t *vm)
186 return vm->loading_table;
189 static st_data_t
190 feature_key(const char *str, size_t len)
192 return st_hash(str, len, 0xfea7009e);
195 static bool
196 is_rbext_path(VALUE feature_path)
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);
204 static void
205 features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb)
207 struct st_table *features_index;
208 VALUE this_feature_index = Qnil;
209 st_data_t short_feature_key;
210 st_data_t data;
212 Check_Type(offset, T_FIXNUM);
213 short_feature_key = feature_key(str, len);
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);
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);
232 else {
233 long pos = -1;
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;
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;
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.
269 static void
270 features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
272 const char *feature_str, *feature_end, *ext, *p;
273 bool rb = false;
275 feature_str = StringValuePtr(feature);
276 feature_end = feature_str + RSTRING_LEN(feature);
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. */
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);
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);
307 static int
308 loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
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));
315 return ST_DELETE;
318 static st_table *
319 get_loaded_features_index(rb_vm_t *vm)
321 VALUE features;
322 int i;
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);
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));
341 reset_loaded_features_snapshot(vm);
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);
352 return vm->loaded_features_index;
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.
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{^\.[^./]*$}`.
366 static VALUE
367 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
368 int type, VALUE load_path)
370 long i;
371 long plen;
372 const char *e;
374 if (vlen < len+1) return 0;
375 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
376 plen = vlen - len;
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;
386 if (plen > 0 && name[plen-1] != '/') {
387 return 0;
389 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
390 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
391 0) {
392 return 0;
394 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
395 (possibly empty) and prefix is some string of length plen. */
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);
403 if (n != plen) continue;
404 if (n && strncmp(name, s, n)) continue;
405 return p;
407 return 0;
410 struct loaded_feature_searching {
411 const char *name;
412 long len;
413 int type;
414 VALUE load_path;
415 const char *result;
418 static int
419 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
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;
430 static int
431 rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
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;
441 if (fn) *fn = 0;
442 if (ext) {
443 elen = strlen(ext);
444 len = strlen(feature) - elen;
445 type = rb ? 'r' : 's';
447 else {
448 len = strlen(feature);
449 elen = 0;
450 type = 0;
452 features = get_loaded_features(vm);
453 features_index = get_loaded_features_index(vm);
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)`.
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.
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`.
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);
490 else {
491 if (i > 0) break;
492 entry = this_feature_index;
494 index = FIX2LONG(entry);
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;
507 if (!*(e = f + len)) {
508 if (ext) continue;
509 return 'u';
511 if (*e != '.') continue;
512 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
513 return 's';
515 if ((rb || !ext) && (IS_RBEXT(e))) {
516 return 'r';
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;
536 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
537 if (fn) *fn = (const char*)data;
538 goto loading;
540 else {
541 VALUE bufstr;
542 char *buf;
543 static const char so_ext[][4] = {
544 ".so", ".o",
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';
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';
567 rb_str_resize(bufstr, 0);
569 return 0;
571 loading:
572 if (!ext) return 'u';
573 return !IS_RBEXT(ext) ? 's' : 'r';
577 rb_provided(const char *feature)
579 return rb_feature_provided(feature, 0);
582 static int
583 feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
585 const char *ext = strrchr(feature, '.');
586 VALUE fullpath = 0;
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);
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;
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;
603 if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
604 return TRUE;
605 RB_GC_GUARD(fullpath);
606 return FALSE;
610 rb_feature_provided(const char *feature, const char **loading)
612 return feature_provided(GET_VM(), feature, loading);
615 static void
616 rb_provide_feature(rb_vm_t *vm, VALUE feature)
618 VALUE features;
620 features = get_loaded_features(vm);
621 if (OBJ_FROZEN(features)) {
622 rb_raise(rb_eRuntimeError,
623 "$LOADED_FEATURES is frozen; cannot append feature");
625 rb_str_freeze(feature);
627 get_loaded_features_index(vm);
628 rb_ary_push(features, rb_fstring(feature));
629 features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
630 reset_loaded_features_snapshot(vm);
633 void
634 rb_provide(const char *feature)
636 rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
639 NORETURN(static void load_failed(VALUE));
641 static inline void
642 load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
644 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
646 if (!iseq) {
647 rb_ast_t *ast;
648 VALUE parser = rb_parser_new();
649 rb_parser_set_context(parser, NULL, FALSE);
650 ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
651 iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
652 fname, rb_realpath_internal(Qnil, fname, 1), NULL);
653 rb_ast_dispose(ast);
655 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
656 rb_iseq_eval(iseq);
659 static inline enum ruby_tag_type
660 load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
662 enum ruby_tag_type state;
663 rb_thread_t *th = rb_ec_thread_ptr(ec);
664 volatile VALUE wrapper = th->top_wrapper;
665 volatile VALUE self = th->top_self;
666 #if !defined __GNUC__
667 rb_thread_t *volatile th0 = th;
668 #endif
670 ec->errinfo = Qnil; /* ensure */
672 /* load in module as toplevel */
673 th->top_self = rb_obj_clone(rb_vm_top_self());
674 th->top_wrapper = load_wrapper;
675 rb_extend_object(th->top_self, th->top_wrapper);
677 EC_PUSH_TAG(ec);
678 state = EC_EXEC_TAG();
679 if (state == TAG_NONE) {
680 load_iseq_eval(ec, fname);
682 EC_POP_TAG();
684 #if !defined __GNUC__
685 th = th0;
686 fname = RB_GC_GUARD(fname);
687 #endif
688 th->top_self = self;
689 th->top_wrapper = wrapper;
690 return state;
693 static inline void
694 raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
696 if (state) {
697 rb_vm_jump_tag_but_local_jump(state);
700 if (!NIL_P(ec->errinfo)) {
701 rb_exc_raise(ec->errinfo);
705 static void
706 rb_load_internal(VALUE fname, VALUE wrap)
708 rb_execution_context_t *ec = GET_EC();
709 enum ruby_tag_type state = TAG_NONE;
710 if (RTEST(wrap)) {
711 if (!RB_TYPE_P(wrap, T_MODULE)) {
712 wrap = rb_module_new();
714 state = load_wrapping(ec, fname, wrap);
716 else {
717 load_iseq_eval(ec, fname);
719 raise_load_if_failed(ec, state);
722 void
723 rb_load(VALUE fname, int wrap)
725 VALUE tmp = rb_find_file(FilePathValue(fname));
726 if (!tmp) load_failed(fname);
727 rb_load_internal(tmp, RBOOL(wrap));
730 void
731 rb_load_protect(VALUE fname, int wrap, int *pstate)
733 enum ruby_tag_type state;
735 EC_PUSH_TAG(GET_EC());
736 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
737 rb_load(fname, wrap);
739 EC_POP_TAG();
741 if (state != TAG_NONE) *pstate = state;
745 * call-seq:
746 * load(filename, wrap=false) -> true
748 * Loads and executes the Ruby program in the file _filename_.
750 * If the filename is an absolute path (e.g. starts with '/'), the file
751 * will be loaded directly using the absolute path.
753 * If the filename is an explicit relative path (e.g. starts with './' or
754 * '../'), the file will be loaded using the relative path from the current
755 * directory.
757 * Otherwise, the file will be searched for in the library
758 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
759 * If the file is found in a directory, it will attempt to load the file
760 * relative to that directory. If the file is not found in any of the
761 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
762 * the relative path from the current directory.
764 * If the file doesn't exist when there is an attempt to load it, a
765 * LoadError will be raised.
767 * If the optional _wrap_ parameter is +true+, the loaded script will
768 * be executed under an anonymous module, protecting the calling
769 * program's global namespace. If the optional _wrap_ parameter is a
770 * module, the loaded script will be executed under the given module.
771 * In no circumstance will any local variables in the loaded file be
772 * propagated to the loading environment.
775 static VALUE
776 rb_f_load(int argc, VALUE *argv, VALUE _)
778 VALUE fname, wrap, path, orig_fname;
780 rb_scan_args(argc, argv, "11", &fname, &wrap);
782 orig_fname = rb_get_path_check_to_string(fname);
783 fname = rb_str_encode_ospath(orig_fname);
784 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
786 path = rb_find_file(fname);
787 if (!path) {
788 if (!rb_file_load_ok(RSTRING_PTR(fname)))
789 load_failed(orig_fname);
790 path = fname;
792 rb_load_internal(path, wrap);
794 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
796 return Qtrue;
799 static char *
800 load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
802 st_data_t data;
803 st_table *loading_tbl = get_loading_table(vm);
805 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
806 /* partial state */
807 ftptr = ruby_strdup(ftptr);
808 data = (st_data_t)rb_thread_shield_new();
809 st_insert(loading_tbl, (st_data_t)ftptr, data);
810 return (char *)ftptr;
812 else if (imemo_type_p(data, imemo_memo)) {
813 struct MEMO *memo = MEMO_CAST(data);
814 void (*init)(void) = memo->u3.func;
815 data = (st_data_t)rb_thread_shield_new();
816 st_insert(loading_tbl, (st_data_t)ftptr, data);
817 (*init)();
818 return (char *)"";
820 if (warn) {
821 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
822 rb_backtrace_each(rb_str_append, warning);
823 rb_warning("%"PRIsVALUE, warning);
825 switch (rb_thread_shield_wait((VALUE)data)) {
826 case Qfalse:
827 case Qnil:
828 return 0;
830 return (char *)ftptr;
833 static int
834 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
836 VALUE thread_shield = (VALUE)*value;
837 if (!existing) return ST_STOP;
838 if (done) {
839 rb_thread_shield_destroy(thread_shield);
840 /* Delete the entry even if there are waiting threads, because they
841 * won't load the file and won't delete the entry. */
843 else if (rb_thread_shield_release(thread_shield)) {
844 /* still in-use */
845 return ST_CONTINUE;
847 xfree((char *)*key);
848 return ST_DELETE;
851 static void
852 load_unlock(rb_vm_t *vm, const char *ftptr, int done)
854 if (ftptr) {
855 st_data_t key = (st_data_t)ftptr;
856 st_table *loading_tbl = get_loading_table(vm);
858 st_update(loading_tbl, key, release_thread_shield, done);
864 * call-seq:
865 * require(name) -> true or false
867 * Loads the given +name+, returning +true+ if successful and +false+ if the
868 * feature is already loaded.
870 * If the filename neither resolves to an absolute path nor starts with
871 * './' or '../', the file will be searched for in the library
872 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
873 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
875 * If the filename has the extension ".rb", it is loaded as a source file; if
876 * the extension is ".so", ".o", or ".dll", or the default shared library
877 * extension on the current platform, Ruby loads the shared library as a
878 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
879 * to the name until found. If the file named cannot be found, a LoadError
880 * will be raised.
882 * For Ruby extensions the filename given may use any shared library
883 * extension. For example, on Linux the socket extension is "socket.so" and
884 * <code>require 'socket.dll'</code> will load the socket extension.
886 * The absolute path of the loaded file is added to
887 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
888 * loaded again if its path already appears in <code>$"</code>. For example,
889 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
890 * again.
892 * require "my-library.rb"
893 * require "db-driver"
895 * Any constants or globals within the loaded source file will be available
896 * in the calling program's global namespace. However, local variables will
897 * not be propagated to the loading environment.
901 VALUE
902 rb_f_require(VALUE obj, VALUE fname)
904 return rb_require_string(fname);
908 * call-seq:
909 * require_relative(string) -> true or false
911 * Ruby tries to load the library named _string_ relative to the requiring
912 * file's path. If the file's path cannot be determined a LoadError is raised.
913 * If a file is loaded +true+ is returned and false otherwise.
915 VALUE
916 rb_f_require_relative(VALUE obj, VALUE fname)
918 VALUE base = rb_current_realfilepath();
919 if (NIL_P(base)) {
920 rb_loaderror("cannot infer basepath");
922 base = rb_file_dirname(base);
923 return rb_require_string(rb_file_absolute_path(fname, base));
926 typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
928 static int
929 search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
931 VALUE tmp;
932 char *ext, *ftptr;
933 int type, ft = 0;
934 const char *loading;
936 *path = 0;
937 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
938 if (ext && !strchr(ext, '/')) {
939 if (IS_RBEXT(ext)) {
940 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
941 if (loading) *path = rb_filesystem_str_new_cstr(loading);
942 return 'r';
944 if ((tmp = rb_find_file(fname)) != 0) {
945 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
946 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
947 *path = tmp;
948 return 'r';
950 return 0;
952 else if (IS_SOEXT(ext)) {
953 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
954 if (loading) *path = rb_filesystem_str_new_cstr(loading);
955 return 's';
957 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
958 rb_str_cat2(tmp, DLEXT);
959 OBJ_FREEZE(tmp);
960 if ((tmp = rb_find_file(tmp)) != 0) {
961 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
962 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
963 *path = tmp;
964 return 's';
967 else if (IS_DLEXT(ext)) {
968 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
969 if (loading) *path = rb_filesystem_str_new_cstr(loading);
970 return 's';
972 if ((tmp = rb_find_file(fname)) != 0) {
973 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
974 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
975 *path = tmp;
976 return 's';
980 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
981 if (loading) *path = rb_filesystem_str_new_cstr(loading);
982 return 'r';
984 tmp = fname;
985 type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
986 switch (type) {
987 case 0:
988 if (ft)
989 goto statically_linked;
990 ftptr = RSTRING_PTR(tmp);
991 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
993 default:
994 if (ft) {
995 goto statically_linked;
997 /* fall through */
998 case 1:
999 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1000 if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
1001 break;
1002 *path = tmp;
1004 return type ? 's' : 'r';
1006 statically_linked:
1007 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1008 return ft;
1011 static void
1012 load_failed(VALUE fname)
1014 rb_load_fail(fname, "cannot load such file");
1017 static VALUE
1018 load_ext(VALUE path)
1020 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1021 return (VALUE)dln_load(RSTRING_PTR(path));
1024 static int
1025 no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1027 return 0;
1030 // Documented in doc/globals.rdoc
1031 VALUE
1032 rb_resolve_feature_path(VALUE klass, VALUE fname)
1034 VALUE path;
1035 int found;
1036 VALUE sym;
1038 fname = rb_get_path(fname);
1039 path = rb_str_encode_ospath(fname);
1040 found = search_required(GET_VM(), path, &path, no_feature_p);
1042 switch (found) {
1043 case 'r':
1044 sym = ID2SYM(rb_intern("rb"));
1045 break;
1046 case 's':
1047 sym = ID2SYM(rb_intern("so"));
1048 break;
1049 default:
1050 return Qnil;
1053 return rb_ary_new_from_args(2, sym, path);
1056 static void
1057 ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1059 *prev = th->ext_config;
1060 th->ext_config = (struct rb_ext_config){0};
1063 static void
1064 ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1066 th->ext_config = *prev;
1069 void
1070 rb_ext_ractor_safe(bool flag)
1072 GET_THREAD()->ext_config.ractor_safe = flag;
1076 * returns
1077 * 0: if already loaded (false)
1078 * 1: successfully loaded (true)
1079 * <0: not found (LoadError)
1080 * >1: exception
1082 static int
1083 require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1085 volatile int result = -1;
1086 rb_thread_t *th = rb_ec_thread_ptr(ec);
1087 volatile const struct {
1088 VALUE wrapper, self, errinfo;
1089 } saved = {
1090 th->top_wrapper, th->top_self, ec->errinfo,
1092 enum ruby_tag_type state;
1093 char *volatile ftptr = 0;
1094 VALUE path;
1095 volatile VALUE saved_path;
1096 volatile VALUE realpath = 0;
1097 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1098 volatile bool reset_ext_config = false;
1099 struct rb_ext_config prev_ext_config;
1101 fname = rb_get_path(fname);
1102 path = rb_str_encode_ospath(fname);
1103 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1104 saved_path = path;
1106 EC_PUSH_TAG(ec);
1107 ec->errinfo = Qnil; /* ensure */
1108 th->top_wrapper = 0;
1109 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1110 long handle;
1111 int found;
1113 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1114 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1115 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1116 path = saved_path;
1118 if (found) {
1119 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1120 result = 0;
1122 else if (!*ftptr) {
1123 result = TAG_RETURN;
1125 else if (RTEST(rb_hash_aref(realpaths,
1126 realpath = rb_realpath_internal(Qnil, path, 1)))) {
1127 result = 0;
1129 else {
1130 switch (found) {
1131 case 'r':
1132 load_iseq_eval(ec, path);
1133 break;
1135 case 's':
1136 reset_ext_config = true;
1137 ext_config_push(th, &prev_ext_config);
1138 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1139 path, VM_BLOCK_HANDLER_NONE, path);
1140 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1141 break;
1143 result = TAG_RETURN;
1147 EC_POP_TAG();
1149 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1150 th2->top_self = saved.self;
1151 th2->top_wrapper = saved.wrapper;
1152 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1154 path = saved_path;
1155 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1157 if (state) {
1158 if (state == TAG_FATAL) {
1159 EC_JUMP_TAG(ec, state);
1161 else if (exception) {
1162 /* usually state == TAG_RAISE only, except for
1163 * rb_iseq_load_iseq in load_iseq_eval case */
1164 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1165 if (!NIL_P(exc)) ec->errinfo = exc;
1166 return TAG_RAISE;
1168 else if (state == TAG_RETURN) {
1169 return TAG_RAISE;
1171 RB_GC_GUARD(fname);
1172 /* never TAG_RETURN */
1173 return state;
1175 if (!NIL_P(ec->errinfo)) {
1176 if (!exception) return TAG_RAISE;
1177 rb_exc_raise(ec->errinfo);
1180 if (result == TAG_RETURN) {
1181 rb_provide_feature(th2->vm, path);
1182 VALUE real = realpath;
1183 if (real) {
1184 rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
1187 ec->errinfo = saved.errinfo;
1189 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1191 return result;
1195 rb_require_internal_silent(VALUE fname)
1197 rb_execution_context_t *ec = GET_EC();
1198 return require_internal(ec, fname, 1, false);
1202 rb_require_internal(VALUE fname)
1204 rb_execution_context_t *ec = GET_EC();
1205 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1209 ruby_require_internal(const char *fname, unsigned int len)
1211 struct RString fake;
1212 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1213 rb_execution_context_t *ec = GET_EC();
1214 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1215 rb_set_errinfo(Qnil);
1216 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1219 VALUE
1220 rb_require_string(VALUE fname)
1222 rb_execution_context_t *ec = GET_EC();
1223 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1225 if (result > TAG_RETURN) {
1226 EC_JUMP_TAG(ec, result);
1228 if (result < 0) {
1229 load_failed(fname);
1232 return RBOOL(result);
1235 VALUE
1236 rb_require(const char *fname)
1238 return rb_require_string(rb_str_new_cstr(fname));
1241 static int
1242 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1244 const char *name = (char *)*key;
1245 if (existing) {
1246 /* already registered */
1247 rb_warn("%s is already registered", name);
1249 else {
1250 *value = (st_data_t)MEMO_NEW(0, 0, init);
1251 *key = (st_data_t)ruby_strdup(name);
1253 return ST_CONTINUE;
1256 RUBY_FUNC_EXPORTED void
1257 ruby_init_ext(const char *name, void (*init)(void))
1259 rb_vm_t *vm = GET_VM();
1260 st_table *loading_tbl = get_loading_table(vm);
1262 if (feature_provided(vm, name, 0))
1263 return;
1264 st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
1268 * call-seq:
1269 * mod.autoload(module, filename) -> nil
1271 * Registers _filename_ to be loaded (using Kernel::require)
1272 * the first time that _module_ (which may be a String or
1273 * a symbol) is accessed in the namespace of _mod_.
1275 * module A
1276 * end
1277 * A.autoload(:B, "b")
1278 * A::B.doit # autoloads "b"
1281 static VALUE
1282 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1284 ID id = rb_to_id(sym);
1286 FilePathValue(file);
1287 rb_autoload_str(mod, id, file);
1288 return Qnil;
1292 * call-seq:
1293 * mod.autoload?(name, inherit=true) -> String or nil
1295 * Returns _filename_ to be loaded if _name_ is registered as
1296 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1298 * module A
1299 * end
1300 * A.autoload(:B, "b")
1301 * A.autoload?(:B) #=> "b"
1303 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1305 * class A
1306 * autoload :CONST, "const.rb"
1307 * end
1309 * class B < A
1310 * end
1312 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1313 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1317 static VALUE
1318 rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1320 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1321 VALUE sym = argv[0];
1323 ID id = rb_check_id(&sym);
1324 if (!id) {
1325 return Qnil;
1327 return rb_autoload_at_p(mod, id, recur);
1331 * call-seq:
1332 * autoload(module, filename) -> nil
1334 * Registers _filename_ to be loaded (using Kernel::require)
1335 * the first time that _module_ (which may be a String or
1336 * a symbol) is accessed.
1338 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1341 static VALUE
1342 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1344 VALUE klass = rb_class_real(rb_vm_cbase());
1345 if (!klass) {
1346 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1348 return rb_mod_autoload(klass, sym, file);
1352 * call-seq:
1353 * autoload?(name, inherit=true) -> String or nil
1355 * Returns _filename_ to be loaded if _name_ is registered as
1356 * +autoload+.
1358 * autoload(:B, "b")
1359 * autoload?(:B) #=> "b"
1362 static VALUE
1363 rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1365 /* use rb_vm_cbase() as same as rb_f_autoload. */
1366 VALUE klass = rb_vm_cbase();
1367 if (NIL_P(klass)) {
1368 return Qnil;
1370 return rb_mod_autoload_p(argc, argv, klass);
1373 void
1374 Init_load(void)
1376 rb_vm_t *vm = GET_VM();
1377 static const char var_load_path[] = "$:";
1378 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1380 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1381 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1382 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1383 vm->load_path = rb_ary_new();
1384 vm->expanded_load_path = rb_ary_tmp_new(0);
1385 vm->load_path_snapshot = rb_ary_tmp_new(0);
1386 vm->load_path_check_cache = 0;
1387 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1389 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1390 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1391 vm->loaded_features = rb_ary_new();
1392 vm->loaded_features_snapshot = rb_ary_tmp_new(0);
1393 vm->loaded_features_index = st_init_numtable();
1394 vm->loaded_features_realpaths = rb_hash_new();
1395 rb_obj_hide(vm->loaded_features_realpaths);
1397 rb_define_global_function("load", rb_f_load, -1);
1398 rb_define_global_function("require", rb_f_require, 1);
1399 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1400 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1401 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1402 rb_define_global_function("autoload", rb_f_autoload, 2);
1403 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1405 ruby_dln_librefs = rb_ary_tmp_new(0);
1406 rb_gc_register_mark_object(ruby_dln_librefs);