6#include "eval_intern.h"
8#include "internal/box.h"
9#include "internal/dir.h"
10#include "internal/error.h"
11#include "internal/eval.h"
12#include "internal/file.h"
13#include "internal/hash.h"
14#include "internal/load.h"
15#include "internal/ruby_parser.h"
16#include "internal/thread.h"
17#include "internal/variable.h"
19#include "prism_compile.h"
24#include "ractor_core.h"
27#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
28#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
29#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
36static const char *
const loadable_ext[] = {
41static const char *
const ruby_ext[] = {
59rb_construct_expanded_load_path(
rb_box_t *box,
enum expand_type
type,
int *has_relative,
int *has_non_cache,
rb_len_t *maxlen_out)
61 VALUE load_path = box->load_path;
62 VALUE expanded_load_path = box->expanded_load_path;
69 VALUE path, as_str, expanded_path;
70 int is_string, non_cache;
74 non_cache = !is_string ? 1 : 0;
75 as_str = rb_get_path_check_to_string(path);
76 as_cstr = RSTRING_PTR(as_str);
79 if ((
type == EXPAND_RELATIVE &&
80 rb_is_absolute_path(as_cstr)) ||
81 (
type == EXPAND_HOME &&
82 (!as_cstr[0] || as_cstr[0] !=
'~')) ||
83 (
type == EXPAND_NON_CACHE)) {
87 if (
len > maxlen) maxlen =
len;
92 if (!*has_relative && !rb_is_absolute_path(as_cstr))
94 if (!*has_non_cache && non_cache)
99 as_str = rb_get_path_check_convert(as_str);
100 expanded_path = rb_check_realpath(
Qnil, as_str, NULL);
101 if (
NIL_P(expanded_path)) expanded_path = as_str;
103 if (
len > maxlen) maxlen =
len;
107 box->expanded_load_path = ary;
108 snapshot = box->load_path_snapshot;
109 load_path = box->load_path;
110 *maxlen_out = maxlen;
115get_expanded_load_path(
rb_box_t *box)
119 const VALUE load_path_snapshot = box->load_path_snapshot;
120 const VALUE load_path = box->load_path;
125 int has_relative = 0, has_non_cache = 0;
126 rb_construct_expanded_load_path(box, EXPAND_ALL, &has_relative, &has_non_cache, &maxlen);
128 box->load_path_check_cache = rb_dir_getwd_ospath();
130 else if (has_non_cache) {
132 box->load_path_check_cache = non_cache;
135 box->load_path_check_cache = 0;
138 else if ((check_cache = box->load_path_check_cache) == non_cache) {
139 int has_relative = 1, has_non_cache = 1;
141 rb_construct_expanded_load_path(box, EXPAND_NON_CACHE,
142 &has_relative, &has_non_cache, &maxlen);
144 else if (check_cache) {
145 int has_relative = 1, has_non_cache = 1;
146 VALUE cwd = rb_dir_getwd_ospath();
150 box->load_path_check_cache = cwd;
151 rb_construct_expanded_load_path(box, EXPAND_RELATIVE,
152 &has_relative, &has_non_cache, &maxlen);
156 rb_construct_expanded_load_path(box, EXPAND_HOME,
157 &has_relative, &has_non_cache, &maxlen);
161 box->expanded_load_path_maxlen = maxlen;
163 return box->expanded_load_path;
167rb_get_expanded_load_path(
rb_len_t *maxlen)
172 *maxlen = box->expanded_load_path_maxlen;
178load_path_getter(
ID _x,
VALUE * _y)
180 return rb_loading_box()->load_path;
184get_LOADED_FEATURES(
ID _x,
VALUE *_y)
186 return rb_loading_box()->loaded_features;
190reset_loaded_features_snapshot(
const rb_box_t *box)
192 VALUE snapshot = box->loaded_features_snapshot;
193 VALUE loaded_features = box->loaded_features;
198get_loaded_features_index_raw(
const rb_box_t *box)
200 return box->loaded_features_index;
204feature_key(
const char *str,
size_t len)
206 return st_hash(str,
len, 0xfea7009e);
210is_rbext_path(
VALUE feature_path)
214 if (
len <= rbext_len)
return false;
215 return IS_RBEXT(RSTRING_PTR(feature_path) +
len - rbext_len);
218typedef rb_darray(
long) feature_indexes_t;
220struct features_index_add_single_args {
227features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args,
int existing)
229 struct features_index_add_single_args *args = (
struct features_index_add_single_args *)raw_args;
231 VALUE offset = args->offset;
235 VALUE this_feature_index = *value;
238 VALUE loaded_features = box->loaded_features;
241 feature_indexes_t feature_indexes;
242 rb_darray_make(&feature_indexes, 2);
243 int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
244 rb_darray_set(feature_indexes, top^0,
FIX2LONG(this_feature_index));
245 rb_darray_set(feature_indexes, top^1,
FIX2LONG(offset));
251 *value = (st_data_t)feature_indexes;
254 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
258 VALUE loaded_features = box->loaded_features;
259 for (
size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
260 long idx = rb_darray_get(feature_indexes, i);
263 if (!is_rbext_path(this_feature_path)) {
270 rb_darray_append(&feature_indexes,
FIX2LONG(offset));
272 *value = (st_data_t)feature_indexes;
275 long *ptr = rb_darray_data_ptr(feature_indexes);
276 long len = rb_darray_size(feature_indexes);
277 MEMMOVE(ptr + pos + 1, ptr + pos,
long,
len - pos - 1);
290features_index_add_single(
const rb_box_t *box,
const char* str,
size_t len,
VALUE offset,
bool rb)
293 st_data_t short_feature_key;
296 short_feature_key = feature_key(str,
len);
298 features_index = get_loaded_features_index_raw(box);
300 struct features_index_add_single_args args = {
306 st_update(features_index, short_feature_key, features_index_add_single_callback, (st_data_t)&args);
322 const char *feature_str, *feature_end, *ext, *p;
326 feature_end = feature_str + RSTRING_LEN(feature);
328 for (ext = feature_end; ext > feature_str; ext--)
329 if (*ext ==
'.' || *ext ==
'/')
338 p = ext ? ext : feature_end;
341 while (p >= feature_str && *p !=
'/')
346 features_index_add_single(box, p + 1, feature_end - p - 1, offset,
false);
348 features_index_add_single(box, p + 1, ext - p - 1, offset, rb);
351 features_index_add_single(box, feature_str, feature_end - feature_str, offset,
false);
353 features_index_add_single(box, feature_str, ext - feature_str, offset, rb);
358loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
362 rb_darray_free_sized((
void *)obj,
long);
368get_loaded_features_index(
const rb_box_t *box)
371 VALUE features = box->loaded_features;
372 const VALUE snapshot = box->loaded_features_snapshot;
377 st_foreach(box->loaded_features_index, loaded_features_index_clear_i, 0);
379 VALUE realpaths = box->loaded_features_realpaths;
380 VALUE realpath_map = box->loaded_features_realpath_map;
381 VALUE previous_realpath_map = rb_hash_dup(realpath_map);
382 rb_hash_clear(realpaths);
383 rb_hash_clear(realpath_map);
393 as_str = rb_fstring(as_str);
396 features_index_add(box, as_str,
INT2FIX(i));
402 reset_loaded_features_snapshot(box);
404 features = box->loaded_features_snapshot;
406 for (i = 0; i < j; i++) {
408 VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
409 if (
NIL_P(realpath)) {
410 realpath = rb_check_realpath(
Qnil, as_str, NULL);
411 if (
NIL_P(realpath)) realpath = as_str;
412 realpath = rb_fstring(realpath);
414 rb_hash_aset(realpaths, realpath,
Qtrue);
415 rb_hash_aset(realpath_map, as_str, realpath);
418 return box->loaded_features_index;
440 if (vlen <
len+1)
return 0;
441 if (strchr(feature,
'.') && !strncmp(name+(vlen-
len), feature,
len)) {
445 for (e = name + vlen; name != e && *e !=
'.' && *e !=
'/'; --e);
448 strncmp(e-
len, feature,
len))
450 plen = e - name -
len;
452 if (plen > 0 && name[plen-1] !=
'/') {
455 if (
type ==
's' ? !IS_DLEXT(&name[plen+
len]) :
456 type ==
'r' ? !IS_RBEXT(&name[plen+
len]) :
463 if (plen > 0) --plen;
469 if (n != plen)
continue;
470 if (n && strncmp(name, s, n))
continue;
485loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
487 const char *s = (
const char *)v;
489 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
490 fp->type, fp->load_path);
491 if (!p)
return ST_CONTINUE;
503rb_feature_p(
const rb_box_t *box,
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn)
505 VALUE features, this_feature_index =
Qnil, v, p, load_path = 0;
508 st_table *loading_tbl, *features_index;
516 len = strlen(feature) - elen;
517 type = rb ?
'r' :
's';
520 len = strlen(feature);
524 features = box->loaded_features;
525 features_index = get_loaded_features_index(box);
527 key = feature_key(feature, strlen(feature));
554 if (st_lookup(features_index, key, &data) && !
NIL_P(this_feature_index = (
VALUE)data)) {
555 for (
size_t i = 0; ; i++) {
559 index =
FIX2LONG(this_feature_index);
562 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
563 if (i >= rb_darray_size(feature_indexes))
break;
564 index = rb_darray_get(feature_indexes, i);
570 if ((n = RSTRING_LEN(v)) <
len)
continue;
571 if (strncmp(f, feature,
len) != 0) {
572 if (expanded)
continue;
573 if (!load_path) load_path = get_expanded_load_path((
rb_box_t *)box);
574 if (!(p = loaded_feature_path(f, n, feature,
len,
type, load_path)))
577 f += RSTRING_LEN(p) + 1;
579 if (!*(e = f +
len)) {
583 if (*e !=
'.')
continue;
584 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
587 if ((rb || !ext) && (IS_RBEXT(e))) {
593 loading_tbl = box->loading_table;
595 if (!expanded && !rb_is_absolute_path(feature)) {
600 fs.load_path = load_path ? load_path : get_expanded_load_path((
rb_box_t *)box);
602 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
603 if ((f = fs.result) != 0) {
608 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
609 if (fn) *fn = (
const char*)data;
615 static const char so_ext[][4] = {
619 if (ext && *ext)
return 0;
621 buf = RSTRING_PTR(bufstr);
623 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
624 strlcpy(buf +
len, e, DLEXT_MAXLEN + 1);
625 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
626 rb_str_resize(bufstr, 0);
627 if (fn) *fn = (
const char*)data;
628 return i ?
's' :
'r';
631 for (i = 0; i < numberof(so_ext); i++) {
632 strlcpy(buf +
len, so_ext[i], DLEXT_MAXLEN + 1);
633 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
634 rb_str_resize(bufstr, 0);
635 if (fn) *fn = (
const char*)data;
639 rb_str_resize(bufstr, 0);
644 if (!ext)
return 'u';
645 return !IS_RBEXT(ext) ?
's' :
'r';
655feature_provided(
rb_box_t *box,
const char *feature,
const char **loading)
657 const char *ext = strrchr(feature,
'.');
660 if (*feature ==
'.' &&
661 (feature[1] ==
'/' || strncmp(feature+1,
"./", 2) == 0)) {
662 fullpath = rb_file_expand_path_fast(rb_get_path(
rb_str_new2(feature)),
Qnil);
663 feature = RSTRING_PTR(fullpath);
665 if (ext && !strchr(ext,
'/')) {
667 if (rb_feature_p(box, feature, ext, TRUE, FALSE, loading))
return TRUE;
670 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
671 if (rb_feature_p(box, feature, ext, FALSE, FALSE, loading))
return TRUE;
675 if (rb_feature_p(box, feature, 0, TRUE, FALSE, loading))
685 return feature_provided(box, feature, loading);
693 features = box->loaded_features;
696 "$LOADED_FEATURES is frozen; cannot append feature");
698 feature = rb_fstring(feature);
700 get_loaded_features_index(box);
707 reset_loaded_features_snapshot(box);
717 rb_provide_feature(rb_current_box(), rb_fstring_cstr(feature));
720NORETURN(
static void load_failed(
VALUE));
723realpath_internal_cached(
VALUE hash,
VALUE path)
725 VALUE ret = rb_hash_aref(hash, path);
730 VALUE realpath = rb_realpath_internal(
Qnil, path, 1);
731 rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
744load_prism_parse(
VALUE args_ptr)
748 VALUE fname = args->fname;
750 VALUE error = pm_load_parse_file(result, fname, NULL);
757 args->iseq = pm_iseq_new_top(&result->
node, rb_fstring_lit(
"<top (required)>"), fname,
758 realpath_internal_cached(args->realpath_map, fname), NULL, &error_state);
761 rb_jump_tag(error_state);
768load_prism_free_result(
VALUE args_ptr)
771 pm_parse_result_free(&args->result);
778 const rb_box_t *box = rb_loading_box();
779 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
783 VALUE v = rb_vm_push_frame_fname(ec, fname);
785 VALUE realpath_map = box->loaded_features_realpath_map;
787 if (rb_ruby_prism_p()) {
790 .realpath_map = realpath_map,
794 pm_parse_result_init(&args.result);
795 args.result.
node.coverage_enabled = 1;
802 if (args.error !=
Qnil) {
813 VALUE parser = rb_parser_new();
814 rb_parser_set_context(parser, NULL, FALSE);
815 ast_value = rb_parser_load_file(parser, fname);
816 ast = rb_ruby_ast_data_get(ast_value);
818 iseq = rb_iseq_new_top(ast_value, rb_fstring_lit(
"<top (required)>"),
819 fname, realpath_internal_cached(realpath_map, fname), NULL);
826 rb_exec_event_hook_script_compiled(ec, iseq,
Qnil);
828 rb_iseq_eval(iseq, box);
831static inline enum ruby_tag_type
834 enum ruby_tag_type state;
837 volatile VALUE wrapper = th->top_wrapper;
838 volatile VALUE self = th->top_self;
846 if (BOX_OBJ_P(load_wrapper)) {
847 box = rb_get_box_t(load_wrapper);
848 if (!box->top_self) {
851 th->top_self = box->top_self;
856 th->top_wrapper = load_wrapper;
860 state = EC_EXEC_TAG();
861 if (state == TAG_NONE) {
862 load_iseq_eval(ec, fname);
871 th->top_wrapper = wrapper;
879 rb_vm_jump_tag_but_local_jump(state);
882 if (!
NIL_P(ec->errinfo)) {
892 const rb_box_t *box = rb_loading_box();
893 enum ruby_tag_type state = TAG_NONE;
898 state = load_wrapping(ec, fname, wrap);
900 else if (BOX_OPTIONAL_P(box)) {
901 box_value = box->box_object;
902 state = load_wrapping(ec, fname, box_value);
905 load_iseq_eval(ec, fname);
907 raise_load_if_failed(ec, state);
914 if (!tmp) load_failed(fname);
915 rb_load_internal(tmp, RBOOL(wrap));
921 enum ruby_tag_type state;
923 EC_PUSH_TAG(GET_EC());
924 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
929 if (state != TAG_NONE) *pstate = state;
935 VALUE path, orig_fname;
937 orig_fname = rb_get_path_check_to_string(fname);
938 fname = rb_str_encode_ospath(orig_fname);
939 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
941 path = rb_find_file(fname);
943 if (!rb_file_load_ok(RSTRING_PTR(fname)))
944 load_failed(orig_fname);
947 rb_load_internal(path, wrap);
949 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
989 return rb_load_entrypoint(fname, wrap);
993load_lock(
const rb_box_t *box,
const char *ftptr,
bool warn)
996 st_table *loading_tbl = box->loading_table;
998 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
1001 data = (st_data_t)rb_thread_shield_new();
1002 st_insert(loading_tbl, (st_data_t)ftptr, data);
1003 return (
char *)ftptr;
1006 if (warn && rb_thread_shield_owned((
VALUE)data)) {
1007 VALUE warning = rb_warning_string(
"loading in progress, circular require considered harmful - %s", ftptr);
1011 switch (rb_thread_shield_wait((
VALUE)data)) {
1016 return (
char *)ftptr;
1020release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done,
int existing)
1023 if (!existing)
return ST_STOP;
1025 rb_thread_shield_destroy(thread_shield);
1029 else if (rb_thread_shield_release(thread_shield)) {
1033 xfree((
char *)*key);
1038load_unlock(
const rb_box_t *box,
const char *ftptr,
int done)
1041 st_data_t key = (st_data_t)ftptr;
1042 st_table *loading_tbl = box->loading_table;
1044 st_update(loading_tbl, key, release_thread_shield, done);
1048static VALUE rb_require_string_internal(
VALUE fname,
bool resurrect);
1094rb_require_relative_entrypoint(
VALUE fname)
1096 VALUE base = rb_current_realfilepath();
1100 base = rb_file_dirname(base);
1101 return rb_require_string_internal(rb_file_absolute_path(fname, base),
false);
1116 return rb_require_relative_entrypoint(fname);
1120find_ext(
VALUE str,
char **ptr,
const char **end)
1123 *ptr = RSTRING_PTR(str);
1125 return memrchr(*ptr,
'.',
len);
1129ext_equal(
const char *ext,
const char *end,
const char *suffix,
size_t len)
1131 return (
size_t)(end - ext) ==
len && memcmp(ext, suffix,
len) == 0;
1134#define EXT_RB_P(ext, end) ext_equal(ext, end, ".rb", rb_strlen_lit(".rb"))
1135#define EXT_SO_P(ext, end) (ext_equal(ext, end, ".so", rb_strlen_lit(".so")) || \
1136 ext_equal(ext, end, ".o", rb_strlen_lit(".o")))
1137#define EXT_DLEXT_P(ext, end) ext_equal(ext, end, DLEXT, rb_strlen_lit(DLEXT))
1139typedef int (*feature_func)(
const rb_box_t *box,
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn);
1142search_required(
const rb_box_t *box,
VALUE fname,
volatile VALUE *path, feature_func rb_feature_p)
1147 const char *ftend, *loading;
1150 ext = find_ext(fname, &ftptr, &ftend);
1151 if (ext && !memchr(ext,
'/', ftend - ext)) {
1152 if (EXT_RB_P(ext, ftend)) {
1153 if (rb_feature_p(box, ftptr, ext, TRUE, FALSE, &loading)) {
1157 if ((tmp = rb_find_file(fname)) != 0) {
1158 ext = find_ext(tmp, &ftptr, &ftend);
1159 if (!rb_feature_p(box, ftptr, ext, TRUE, TRUE, &loading) || loading)
1165 else if (EXT_SO_P(ext, ftend)) {
1166 if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
1173 if ((tmp = rb_find_file(tmp)) != 0) {
1174 ext = find_ext(tmp, &ftptr, &ftend);
1175 if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
1180 else if (EXT_DLEXT_P(ext, ftend)) {
1181 if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
1185 if ((tmp = rb_find_file(fname)) != 0) {
1186 ext = find_ext(tmp, &ftptr, &ftend);
1187 if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
1193 else if ((ft = rb_feature_p(box, ftptr, 0, FALSE, FALSE, &loading)) ==
'r') {
1198 const unsigned int type = rb_find_file_ext(&tmp, ft ==
's' ? ruby_ext : loadable_ext);
1202 if (!ft &&
type != loadable_ext_rb) {
1204 if (vm->static_ext_inits.num_entries) {
1205 VALUE lookup_name = tmp;
1213 ftptr = RSTRING_PTR(lookup_name);
1214 if (st_lookup(&vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1225 goto feature_present;
1226 ftptr = RSTRING_PTR(tmp);
1227 return rb_feature_p(box, ftptr, 0, FALSE, TRUE, 0);
1231 goto feature_present;
1234 case loadable_ext_rb:
1235 ext = find_ext(tmp, &ftptr, &ftend);
1236 if (rb_feature_p(box, ftptr, ext,
type == loadable_ext_rb, TRUE, &loading) && !loading)
1240 return type > loadable_ext_rb ?
's' :
'r';
1248load_failed(
VALUE fname)
1250 rb_load_fail(fname,
"cannot load such file");
1256 VALUE loaded = path;
1257 const rb_box_t *box = rb_loading_box();
1259 if (BOX_USER_P(box)) {
1260 loaded = rb_box_local_extension(box->box_object, path, &cleanup);
1262 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1263 void *handle = dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
1265 rb_box_cleanup_local_extension(cleanup);
1266 rb_box_defer_unload_local_extension(handle);
1270 return (
VALUE)handle;
1274run_static_ext_init(
VALUE vm_ptr,
VALUE feature_value)
1277 const char *feature = RSTRING_PTR(feature_value);
1278 st_data_t key = (st_data_t)feature;
1279 st_data_t init_func;
1281 if (st_delete(&vm->static_ext_inits, &key, &init_func)) {
1282 ((void (*)(void))init_func)();
1289no_feature_p(
const rb_box_t *box,
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn)
1296rb_resolve_feature_path(
VALUE klass,
VALUE fname)
1301 const rb_box_t *box = rb_loading_box();
1303 fname = rb_get_path(fname);
1304 path = rb_str_encode_ospath(fname);
1305 found = search_required(box, path, &path, no_feature_p);
1309 sym =
ID2SYM(rb_intern(
"rb"));
1312 sym =
ID2SYM(rb_intern(
"so"));
1318 return rb_ary_new_from_args(2, sym, path);
1324 *prev = th->ext_config;
1331 th->ext_config = *prev;
1337 GET_THREAD()->ext_config.ractor_safe = flag;
1350 volatile int result = -1;
1352 const rb_box_t *box = rb_loading_box();
1353 volatile const struct {
1354 VALUE wrapper, self, errinfo;
1358 th->top_wrapper, th->top_self, ec->errinfo,
1361 enum ruby_tag_type state;
1362 char *
volatile ftptr = 0;
1364 volatile VALUE saved_path;
1365 volatile VALUE realpath = 0;
1366 VALUE realpaths = box->loaded_features_realpaths;
1367 VALUE realpath_map = box->loaded_features_realpath_map;
1368 volatile bool reset_ext_config =
false;
1371 path = rb_str_encode_ospath(fname);
1372 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1377 th->top_wrapper = 0;
1378 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1382 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1383 found = search_required(box, path, &saved_path, rb_feature_p);
1384 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1388 if (!path || !(ftptr = load_lock(box, RSTRING_PTR(path), warn))) {
1392 result = TAG_RETURN;
1394 else if (found ==
's' &&
RTEST(rb_vm_call_cfunc_in_box(
Qnil, run_static_ext_init, (
VALUE)th->vm, path, path, box))) {
1395 result = TAG_RETURN;
1397 else if (
RTEST(rb_hash_aref(realpaths,
1398 realpath = realpath_internal_cached(realpath_map, path)))) {
1404 load_iseq_eval(saved.ec, path);
1408 reset_ext_config =
true;
1409 ext_config_push(th, &prev_ext_config);
1410 handle = rb_vm_call_cfunc_in_box(box->top_self, load_ext, path, fname, path, box);
1411 rb_hash_aset(box->ruby_dln_libmap, path, PTR2NUM(handle));
1414 result = TAG_RETURN;
1423 th2->top_self = saved.self;
1424 th2->top_wrapper = saved.wrapper;
1425 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1428 if (ftptr) load_unlock(box, RSTRING_PTR(path), !state);
1431 if (state == TAG_FATAL || state == TAG_THROW) {
1432 EC_JUMP_TAG(ec, state);
1434 else if (exception) {
1437 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state,
Qundef);
1438 if (!
NIL_P(exc)) ec->errinfo = exc;
1441 else if (state == TAG_RETURN) {
1448 if (!
NIL_P(ec->errinfo)) {
1449 if (!exception)
return TAG_RAISE;
1453 if (result == TAG_RETURN) {
1454 rb_provide_feature(box, path);
1455 VALUE real = realpath;
1457 real = rb_fstring(real);
1458 rb_hash_aset(realpaths, real,
Qtrue);
1461 ec->errinfo = saved.errinfo;
1463 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1469rb_require_internal_silent(
VALUE fname)
1471 if (!rb_ractor_main_p()) {
1472 return NUM2INT(rb_ractor_require(fname,
true));
1476 return require_internal(ec, fname, 1,
false);
1480rb_require_internal(
VALUE fname)
1487ruby_require_internal(
const char *fname,
unsigned int len)
1489 struct RString fake = {RBASIC_INIT};
1490 VALUE str = rb_setup_fake_str(&fake, fname,
len, 0);
1493 rb_set_errinfo(
Qnil);
1494 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1500 return rb_require_string_internal(
FilePathValue(fname),
false);
1504rb_require_string_internal(
VALUE fname,
bool resurrect)
1509 if (!rb_ractor_main_p()) {
1511 return rb_ractor_require(fname,
false);
1516 if (result > TAG_RETURN) {
1517 EC_JUMP_TAG(ec, result);
1524 return RBOOL(result);
1531 struct RString fake = {RBASIC_INIT};
1532 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1533 return rb_require_string_internal(str,
true);
1537register_init_ext(st_data_t *key, st_data_t *value, st_data_t init,
int existing)
1539 const char *name = (
char *)*key;
1542 rb_warn(
"%s is already registered", name);
1545 *value = (st_data_t)init;
1554ruby_init_ext(
const char *name,
void (*init)(
void))
1557 const rb_box_t *box = rb_loading_box();
1559 if (feature_provided((
rb_box_t *)box, name, 0))
1562 st_update(&vm->static_ext_inits, (st_data_t)name, register_init_ext, (st_data_t)init);
1592 rb_autoload_str(mod,
id, file);
1624 VALUE base, absolute_path;
1628 base = rb_current_realfilepath();
1630 rb_loaderror(
"cannot infer basepath (autoload_relative called without file context)");
1632 base = rb_file_dirname(base);
1633 absolute_path = rb_file_absolute_path(file, base);
1635 rb_autoload_str(mod,
id, absolute_path);
1666rb_mod_autoload_p(
int argc,
VALUE *argv,
VALUE mod)
1669 VALUE sym = argv[0];
1675 return rb_autoload_at_p(mod,
id, recur);
1701 rb_raise(
rb_eTypeError,
"Can not set autoload on singleton class");
1703 return rb_mod_autoload(klass, sym, file);
1733 rb_raise(
rb_eTypeError,
"Can not set autoload on singleton class");
1735 return rb_mod_autoload_relative(klass, sym, file);
1762rb_f_autoload_p(
int argc,
VALUE *argv,
VALUE obj)
1765 VALUE klass = rb_vm_cbase();
1769 return rb_mod_autoload_p(argc, argv, klass);
1780 const rb_box_t *box = rb_loading_box();
1782 resolved = rb_resolve_feature_path((
VALUE)NULL, fname_str);
1783 if (
NIL_P(resolved)) {
1784 ext = strrchr(fname,
'.');
1785 if (!ext || !IS_SOEXT(ext)) {
1788 if (rb_feature_p(box, fname, 0, FALSE, FALSE, 0)) {
1789 return dln_symbol(NULL, symbol);
1797 handle = rb_hash_lookup(box->ruby_dln_libmap, path);
1798 if (
NIL_P(handle)) {
1801 return dln_symbol(NUM2PTR(handle), symbol);
1807 static const char var_load_path[] =
"$:";
1808 ID id_load_path = rb_intern2(var_load_path,
sizeof(var_load_path)-1);
1811 rb_gvar_box_ready(var_load_path);
1816 rb_gvar_box_ready(
"$\"");
1818 rb_gvar_box_ready(
"$LOADED_FEATURES");
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
VALUE rb_module_new(void)
Creates a new, anonymous module.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define ID2SYM
Old name of RB_ID2SYM.
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
void rb_warning(const char *fmt,...)
Issues a warning.
VALUE rb_cModule
Module class.
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
VALUE rb_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs)
Queries if the passed two arrays share the same backend storage.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Replaces the contents of the former object with the contents of the latter.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_hidden_new(rb_len_t capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
VALUE rb_f_require(VALUE self, VALUE feature)
Identical to rb_require_string(), except it ignores the first argument for no reason.
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
int rb_feature_provided(const char *feature, const char **loading)
Identical to rb_provided(), except it additionally returns the "canonical" name of the loaded feature...
void rb_load_protect(VALUE path, int wrap, int *state)
Identical to rb_load(), except it avoids potential global escapes.
int rb_provided(const char *feature)
Queries if the given feature has already been loaded into the execution context.
void rb_load(VALUE path, int wrap)
Loads and executes the Ruby program in the given file.
void * rb_ext_resolve_symbol(const char *feature, const char *symbol)
Resolves and returns a symbol of a function in the native extension specified by the feature and symb...
VALUE rb_str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
VALUE rb_filesystem_str_new_cstr(const char *ptr)
Identical to rb_filesystem_str_new(), except it assumes the passed pointer is a pointer to a C string...
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
int len
Length of the buffer.
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
pm_scope_node_t node
The resulting scope node that will hold the generated AST.
Internal header for Ruby Box.
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.