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