Ruby 4.1.0dev (2026-10-14 revision b709bdb3e37451bb1103b50fb280968dbf038103)
load.c (b709bdb3e37451bb1103b50fb280968dbf038103)
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/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"
18#include "iseq.h"
19#include "prism_compile.h"
20#include "probes.h"
21#include "darray.h"
22#include "ruby/encoding.h"
23#include "ruby/util.h"
24#include "ractor_core.h"
25#include "vm_core.h"
26
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)
30
31enum {
32 loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
33 1) /* offset by rb_find_file_ext() */
34};
35
36static const char *const loadable_ext[] = {
37 ".rb", DLEXT,
38 0
39};
40
41static const char *const ruby_ext[] = {
42 ".rb",
43 0
44};
45
46enum expand_type {
47 EXPAND_ALL,
48 EXPAND_RELATIVE,
49 EXPAND_HOME,
50 EXPAND_NON_CACHE
51};
52
53/* Construct expanded load path and store it to cache.
54 We rebuild load path partially if the cache is invalid.
55 We don't cache non string object and expand it every time. We ensure that
56 string objects in $LOAD_PATH are frozen.
57 */
58static void
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)
60{
61 VALUE load_path = box->load_path;
62 VALUE expanded_load_path = box->expanded_load_path;
63 VALUE snapshot;
64 VALUE ary;
65 rb_len_t i, maxlen = 0;
66
67 ary = rb_ary_hidden_new(RARRAY_LEN(load_path));
68 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
69 VALUE path, as_str, expanded_path;
70 int is_string, non_cache;
71 char *as_cstr;
72 as_str = path = RARRAY_AREF(load_path, i);
73 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
74 non_cache = !is_string ? 1 : 0;
75 as_str = rb_get_path_check_to_string(path);
76 as_cstr = RSTRING_PTR(as_str);
77
78 if (!non_cache) {
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)) {
84 /* Use cached expanded path. */
85 expanded_path = RARRAY_AREF(expanded_load_path, i);
86 rb_len_t len = RSTRING_LEN(expanded_path);
87 if (len > maxlen) maxlen = len;
88 rb_ary_push(ary, expanded_path);
89 continue;
90 }
91 }
92 if (!*has_relative && !rb_is_absolute_path(as_cstr))
93 *has_relative = 1;
94 if (!*has_non_cache && non_cache)
95 *has_non_cache = 1;
96 /* Freeze only string object. We expand other objects every time. */
97 if (is_string)
98 rb_str_freeze(path);
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;
102 rb_len_t len = RSTRING_LEN(expanded_path);
103 if (len > maxlen) maxlen = len;
104 rb_ary_push(ary, rb_fstring(expanded_path));
105 }
106 rb_ary_freeze(ary);
107 box->expanded_load_path = ary;
108 snapshot = box->load_path_snapshot;
109 load_path = box->load_path;
110 *maxlen_out = maxlen;
111 rb_ary_replace(snapshot, load_path);
112}
113
114static VALUE
115get_expanded_load_path(rb_box_t *box)
116{
117 VALUE check_cache;
118 const VALUE non_cache = Qtrue;
119 const VALUE load_path_snapshot = box->load_path_snapshot;
120 const VALUE load_path = box->load_path;
121 rb_len_t maxlen = 0;
122
123 if (!rb_ary_shared_with_p(load_path_snapshot, load_path)) {
124 /* The load path was modified. Rebuild the expanded 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);
127 if (has_relative) {
128 box->load_path_check_cache = rb_dir_getwd_ospath();
129 }
130 else if (has_non_cache) {
131 /* Non string object. */
132 box->load_path_check_cache = non_cache;
133 }
134 else {
135 box->load_path_check_cache = 0;
136 }
137 }
138 else if ((check_cache = box->load_path_check_cache) == non_cache) {
139 int has_relative = 1, has_non_cache = 1;
140 /* Expand only non-cacheable objects. */
141 rb_construct_expanded_load_path(box, EXPAND_NON_CACHE,
142 &has_relative, &has_non_cache, &maxlen);
143 }
144 else if (check_cache) {
145 int has_relative = 1, has_non_cache = 1;
146 VALUE cwd = rb_dir_getwd_ospath();
147 if (!rb_str_equal(check_cache, cwd)) {
148 /* Current working directory or filesystem encoding was changed.
149 Expand relative load path and non-cacheable objects again. */
150 box->load_path_check_cache = cwd;
151 rb_construct_expanded_load_path(box, EXPAND_RELATIVE,
152 &has_relative, &has_non_cache, &maxlen);
153 }
154 else {
155 /* Expand only tilde (User HOME) and non-cacheable objects. */
156 rb_construct_expanded_load_path(box, EXPAND_HOME,
157 &has_relative, &has_non_cache, &maxlen);
158 }
159 }
160 if (maxlen) {
161 box->expanded_load_path_maxlen = maxlen;
162 }
163 return box->expanded_load_path;
164}
165
166VALUE
167rb_get_expanded_load_path(rb_len_t *maxlen)
168{
169 rb_box_t *box = (rb_box_t *)rb_loading_box();
170 VALUE load_path = get_expanded_load_path((rb_box_t *)box);
171 if (maxlen) {
172 *maxlen = box->expanded_load_path_maxlen;
173 }
174 return load_path;
175}
176
177static VALUE
178load_path_getter(ID _x, VALUE * _y)
179{
180 return rb_loading_box()->load_path;
181}
182
183static VALUE
184get_LOADED_FEATURES(ID _x, VALUE *_y)
185{
186 return rb_loading_box()->loaded_features;
187}
188
189static void
190reset_loaded_features_snapshot(const rb_box_t *box)
191{
192 VALUE snapshot = box->loaded_features_snapshot;
193 VALUE loaded_features = box->loaded_features;
194 rb_ary_replace(snapshot, loaded_features);
195}
196
197static struct st_table *
198get_loaded_features_index_raw(const rb_box_t *box)
199{
200 return box->loaded_features_index;
201}
202
203static st_data_t
204feature_key(const char *str, size_t len)
205{
206 return st_hash(str, len, 0xfea7009e);
207}
208
209static bool
210is_rbext_path(VALUE feature_path)
211{
212 rb_len_t len = RSTRING_LEN(feature_path);
213 rb_len_t rbext_len = rb_strlen_lit(".rb");
214 if (len <= rbext_len) return false;
215 return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
216}
217
218typedef rb_darray(long) feature_indexes_t;
219
220struct features_index_add_single_args {
221 const rb_box_t *box;
222 VALUE offset;
223 bool rb;
224};
225
226static int
227features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
228{
229 struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
230 const rb_box_t *box = args->box;
231 VALUE offset = args->offset;
232 bool rb = args->rb;
233
234 if (existing) {
235 VALUE this_feature_index = *value;
236
237 if (FIXNUM_P(this_feature_index)) {
238 VALUE loaded_features = box->loaded_features;
239 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
240
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));
246
247 RUBY_ASSERT(rb_darray_size(feature_indexes) == 2);
248 // assert feature_indexes does not look like a special const
249 RUBY_ASSERT(!SPECIAL_CONST_P((VALUE)feature_indexes));
250
251 *value = (st_data_t)feature_indexes;
252 }
253 else {
254 feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
255 long pos = -1;
256
257 if (rb) {
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);
261 VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
262 Check_Type(this_feature_path, T_STRING);
263 if (!is_rbext_path(this_feature_path)) {
264 pos = i;
265 break;
266 }
267 }
268 }
269
270 rb_darray_append(&feature_indexes, FIX2LONG(offset));
271 /* darray may realloc which will change the pointer */
272 *value = (st_data_t)feature_indexes;
273
274 if (pos >= 0) {
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);
278 ptr[pos] = FIX2LONG(offset);
279 }
280 }
281 }
282 else {
283 *value = offset;
284 }
285
286 return ST_CONTINUE;
287}
288
289static void
290features_index_add_single(const rb_box_t *box, const char* str, size_t len, VALUE offset, bool rb)
291{
292 struct st_table *features_index;
293 st_data_t short_feature_key;
294
295 Check_Type(offset, T_FIXNUM);
296 short_feature_key = feature_key(str, len);
297
298 features_index = get_loaded_features_index_raw(box);
299
300 struct features_index_add_single_args args = {
301 .box = box,
302 .offset = offset,
303 .rb = rb,
304 };
305
306 st_update(features_index, short_feature_key, features_index_add_single_callback, (st_data_t)&args);
307}
308
309/* Add to the loaded-features index all the required entries for
310 `feature`, located at `offset` in $LOADED_FEATURES. We add an
311 index entry at each string `short_feature` for which
312 feature == "#{prefix}#{short_feature}#{ext}"
313 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
314 or ends in '/'. This maintains the invariant that `rb_feature_p()`
315 relies on for its fast lookup.
316*/
317static void
318features_index_add(const rb_box_t *box, VALUE feature, VALUE offset)
319{
320 RUBY_ASSERT(rb_ractor_main_p());
321
322 const char *feature_str, *feature_end, *ext, *p;
323 bool rb = false;
324
325 feature_str = StringValuePtr(feature);
326 feature_end = feature_str + RSTRING_LEN(feature);
327
328 for (ext = feature_end; ext > feature_str; ext--)
329 if (*ext == '.' || *ext == '/')
330 break;
331 if (*ext != '.')
332 ext = NULL;
333 else
334 rb = IS_RBEXT(ext);
335 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
336 at the end of `feature`, or is NULL if there is no such string. */
337
338 p = ext ? ext : feature_end;
339 while (1) {
340 p--;
341 while (p >= feature_str && *p != '/')
342 p--;
343 if (p < feature_str)
344 break;
345 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
346 features_index_add_single(box, p + 1, feature_end - p - 1, offset, false);
347 if (ext) {
348 features_index_add_single(box, p + 1, ext - p - 1, offset, rb);
349 }
350 }
351 features_index_add_single(box, feature_str, feature_end - feature_str, offset, false);
352 if (ext) {
353 features_index_add_single(box, feature_str, ext - feature_str, offset, rb);
354 }
355}
356
357static int
358loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
359{
360 VALUE obj = (VALUE)val;
361 if (!SPECIAL_CONST_P(obj)) {
362 rb_darray_free_sized((void *)obj, long);
363 }
364 return ST_DELETE;
365}
366
367static st_table *
368get_loaded_features_index(const rb_box_t *box)
369{
370 int i;
371 VALUE features = box->loaded_features;
372 const VALUE snapshot = box->loaded_features_snapshot;
373
374 if (!rb_ary_shared_with_p(snapshot, features)) {
375 /* The sharing was broken; something (other than us in rb_provide_feature())
376 modified loaded_features. Rebuild the index. */
377 st_foreach(box->loaded_features_index, loaded_features_index_clear_i, 0);
378
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);
384
385 /* We have to make a copy of features here because the StringValue call
386 * below could call a Ruby method, which could modify $LOADED_FEATURES
387 * and cause it to be corrupt. */
388 features = rb_ary_resurrect(features);
389 for (i = 0; i < RARRAY_LEN(features); i++) {
390 VALUE entry, as_str;
391 as_str = entry = rb_ary_entry(features, i);
392 StringValue(as_str);
393 as_str = rb_fstring(as_str);
394 if (as_str != entry)
395 rb_ary_store(features, i, as_str);
396 features_index_add(box, as_str, INT2FIX(i));
397 }
398 /* The user modified $LOADED_FEATURES, so we should restore the changes. */
399 if (!rb_ary_shared_with_p(features, box->loaded_features)) {
400 rb_ary_replace(box->loaded_features, features);
401 }
402 reset_loaded_features_snapshot(box);
403
404 features = box->loaded_features_snapshot;
405 rb_len_t j = RARRAY_LEN(features);
406 for (i = 0; i < j; i++) {
407 VALUE as_str = rb_ary_entry(features, 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);
413 }
414 rb_hash_aset(realpaths, realpath, Qtrue);
415 rb_hash_aset(realpath_map, as_str, realpath);
416 }
417 }
418 return box->loaded_features_index;
419}
420
421/* This searches `load_path` for a value such that
422 name == "#{load_path[i]}/#{feature}"
423 if `feature` is a suffix of `name`, or otherwise
424 name == "#{load_path[i]}/#{feature}#{ext}"
425 for an acceptable string `ext`. It returns
426 `load_path[i].to_str` if found, else 0.
427
428 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
429 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
430 or have any value matching `%r{^\.[^./]*$}`.
431*/
432static VALUE
433loaded_feature_path(const char *name, rb_len_t vlen, const char *feature, rb_len_t len,
434 int type, VALUE load_path)
435{
436 rb_len_t i;
437 rb_len_t plen;
438 const char *e;
439
440 if (vlen < len+1) return 0;
441 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
442 plen = vlen - len;
443 }
444 else {
445 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
446 if (*e != '.' ||
447 e-name < len ||
448 strncmp(e-len, feature, len))
449 return 0;
450 plen = e - name - len;
451 }
452 if (plen > 0 && name[plen-1] != '/') {
453 return 0;
454 }
455 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
456 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
457 0) {
458 return 0;
459 }
460 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
461 (possibly empty) and prefix is some string of length plen. */
462
463 if (plen > 0) --plen; /* exclude '.' */
464 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
465 VALUE p = RARRAY_AREF(load_path, i);
466 const char *s = StringValuePtr(p);
467 rb_len_t n = RSTRING_LEN(p);
468
469 if (n != plen) continue;
470 if (n && strncmp(name, s, n)) continue;
471 return p;
472 }
473 return 0;
474}
475
477 const char *name;
479 int type;
480 VALUE load_path;
481 const char *result;
482};
483
484static int
485loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
486{
487 const char *s = (const char *)v;
488 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
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;
492 fp->result = s;
493 return ST_STOP;
494}
495
496/*
497 * Returns the type of already provided feature.
498 * 'r': ruby script (".rb")
499 * 's': shared object (".so"/"."DLEXT)
500 * 'u': unsuffixed
501 */
502static int
503rb_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
504{
505 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
506 const char *f, *e;
507 rb_len_t i, len, elen, n;
508 st_table *loading_tbl, *features_index;
509 st_data_t data;
510 st_data_t key;
511 int type;
512
513 if (fn) *fn = 0;
514 if (ext) {
515 elen = strlen(ext);
516 len = strlen(feature) - elen;
517 type = rb ? 'r' : 's';
518 }
519 else {
520 len = strlen(feature);
521 elen = 0;
522 type = 0;
523 }
524 features = box->loaded_features;
525 features_index = get_loaded_features_index(box);
526
527 key = feature_key(feature, strlen(feature));
528 /* We search `features` for an entry such that either
529 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
530 for some j, or
531 "#{features[i]}" == "#{feature}#{e}"
532 Here `e` is an "allowed" extension -- either empty or one
533 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
534 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
535 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
536
537 If `expanded`, then only the latter form (without load_path[j])
538 is accepted. Otherwise either form is accepted, *unless* `ext`
539 is false and an otherwise-matching entry of the first form is
540 preceded by an entry of the form
541 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
542 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
543 After a "distractor" entry of this form, only entries of the
544 form "#{feature}#{e}" are accepted.
545
546 In `rb_provide_feature()` and `get_loaded_features_index()` we
547 maintain an invariant that the array `this_feature_index` will
548 point to every entry in `features` which has the form
549 "#{prefix}#{feature}#{e}"
550 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
551 or ends in '/'. This includes both match forms above, as well
552 as any distractors, so we may ignore all other entries in `features`.
553 */
554 if (st_lookup(features_index, key, &data) && !NIL_P(this_feature_index = (VALUE)data)) {
555 for (size_t i = 0; ; i++) {
556 long index;
557 if (FIXNUM_P(this_feature_index)) {
558 if (i > 0) break;
559 index = FIX2LONG(this_feature_index);
560 }
561 else {
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);
565 }
566
567 if (index >= RARRAY_LEN(features)) continue;
568 v = RARRAY_AREF(features, index);
569 f = StringValuePtr(v);
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)))
575 continue;
576 expanded = 1;
577 f += RSTRING_LEN(p) + 1;
578 }
579 if (!*(e = f + len)) {
580 if (ext) continue;
581 return 'u';
582 }
583 if (*e != '.') continue;
584 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
585 return 's';
586 }
587 if ((rb || !ext) && (IS_RBEXT(e))) {
588 return 'r';
589 }
590 }
591 }
592
593 loading_tbl = box->loading_table;
594 f = 0;
595 if (!expanded && !rb_is_absolute_path(feature)) {
596 struct loaded_feature_searching fs;
597 fs.name = feature;
598 fs.len = len;
599 fs.type = type;
600 fs.load_path = load_path ? load_path : get_expanded_load_path((rb_box_t *)box);
601 fs.result = 0;
602 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
603 if ((f = fs.result) != 0) {
604 if (fn) *fn = f;
605 goto loading;
606 }
607 }
608 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
609 if (fn) *fn = (const char*)data;
610 goto loading;
611 }
612 else {
613 VALUE bufstr;
614 char *buf;
615 static const char so_ext[][4] = {
616 ".so", ".o",
617 };
618
619 if (ext && *ext) return 0;
620 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
621 buf = RSTRING_PTR(bufstr);
622 MEMCPY(buf, feature, char, len);
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';
629 }
630 }
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;
636 return 's';
637 }
638 }
639 rb_str_resize(bufstr, 0);
640 }
641 return 0;
642
643 loading:
644 if (!ext) return 'u';
645 return !IS_RBEXT(ext) ? 's' : 'r';
646}
647
648int
649rb_provided(const char *feature)
650{
651 return rb_feature_provided(feature, 0);
652}
653
654static int
655feature_provided(rb_box_t *box, const char *feature, const char **loading)
656{
657 const char *ext = strrchr(feature, '.');
658 VALUE fullpath = 0;
659
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);
664 }
665 if (ext && !strchr(ext, '/')) {
666 if (IS_RBEXT(ext)) {
667 if (rb_feature_p(box, feature, ext, TRUE, FALSE, loading)) return TRUE;
668 return FALSE;
669 }
670 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
671 if (rb_feature_p(box, feature, ext, FALSE, FALSE, loading)) return TRUE;
672 return FALSE;
673 }
674 }
675 if (rb_feature_p(box, feature, 0, TRUE, FALSE, loading))
676 return TRUE;
677 RB_GC_GUARD(fullpath);
678 return FALSE;
679}
680
681int
682rb_feature_provided(const char *feature, const char **loading)
683{
684 rb_box_t *box = (rb_box_t *)rb_current_box();
685 return feature_provided(box, feature, loading);
686}
687
688static void
689rb_provide_feature(const rb_box_t *box, VALUE feature)
690{
691 VALUE features;
692
693 features = box->loaded_features;
694 if (OBJ_FROZEN(features)) {
695 rb_raise(rb_eRuntimeError,
696 "$LOADED_FEATURES is frozen; cannot append feature");
697 }
698 feature = rb_fstring(feature);
699
700 get_loaded_features_index(box);
701 // If loaded_features and loaded_features_snapshot share the same backing
702 // array, pushing into it would cause the whole array to be copied.
703 // To avoid this we first clear loaded_features_snapshot.
704 rb_ary_clear(box->loaded_features_snapshot);
705 rb_ary_push(features, feature);
706 features_index_add(box, feature, INT2FIX(RARRAY_LEN(features)-1));
707 reset_loaded_features_snapshot(box);
708}
709
710void
711rb_provide(const char *feature)
712{
713 /*
714 * rb_provide() must use rb_current_box to store provided features
715 * in the current box's loaded_features, etc.
716 */
717 rb_provide_feature(rb_current_box(), rb_fstring_cstr(feature));
718}
719
720NORETURN(static void load_failed(VALUE));
721
722static inline VALUE
723realpath_internal_cached(VALUE hash, VALUE path)
724{
725 VALUE ret = rb_hash_aref(hash, path);
726 if(RTEST(ret)) {
727 return ret;
728 }
729
730 VALUE realpath = rb_realpath_internal(Qnil, path, 1);
731 rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
732 return realpath;
733}
734
736 pm_parse_result_t result;
737 VALUE fname;
738 VALUE realpath_map;
739 const rb_iseq_t *iseq;
740 VALUE error;
741};
742
743static VALUE
744load_prism_parse(VALUE args_ptr)
745{
746 struct load_prism_args *args = (struct load_prism_args *)args_ptr;
747 pm_parse_result_t *result = &args->result;
748 VALUE fname = args->fname;
749
750 VALUE error = pm_load_parse_file(result, fname, NULL);
751 if (error != Qnil) {
752 args->error = error;
753 return Qnil;
754 }
755
756 int error_state;
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);
759 if (error_state) {
760 RUBY_ASSERT(args->iseq == NULL);
761 rb_jump_tag(error_state);
762 }
763
764 return Qnil;
765}
766
767static VALUE
768load_prism_free_result(VALUE args_ptr)
769{
770 struct load_prism_args *args = (struct load_prism_args *)args_ptr;
771 pm_parse_result_free(&args->result);
772 return Qnil;
773}
774
775static inline void
776load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
777{
778 const rb_box_t *box = rb_loading_box();
779 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
780
781 if (!iseq) {
782 rb_execution_context_t *ec = GET_EC();
783 VALUE v = rb_vm_push_frame_fname(ec, fname);
784
785 VALUE realpath_map = box->loaded_features_realpath_map;
786
787 if (rb_ruby_prism_p()) {
788 struct load_prism_args args = {
789 .fname = fname,
790 .realpath_map = realpath_map,
791 .iseq = NULL,
792 .error = Qnil,
793 };
794 pm_parse_result_init(&args.result);
795 args.result.node.coverage_enabled = 1;
796
797 /* The parse result must be freed even if parsing or compiling
798 * raises (e.g. an asynchronously raised IOError while reading a
799 * pipe), so wrap it in rb_ensure. */
800 rb_ensure(load_prism_parse, (VALUE)&args, load_prism_free_result, (VALUE)&args);
801
802 if (args.error != Qnil) {
803 rb_vm_pop_frame(ec);
804 RB_GC_GUARD(v);
805 rb_exc_raise(args.error);
806 }
807
808 iseq = args.iseq;
809 }
810 else {
811 rb_ast_t *ast;
812 VALUE ast_value;
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);
817
818 iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
819 fname, realpath_internal_cached(realpath_map, fname), NULL);
820 rb_ast_dispose(ast);
821 }
822
823 rb_vm_pop_frame(ec);
824 RB_GC_GUARD(v);
825 }
826 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
827
828 rb_iseq_eval(iseq, box);
829}
830
831static inline enum ruby_tag_type
832load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
833{
834 enum ruby_tag_type state;
835 rb_box_t *box;
836 rb_thread_t *th = rb_ec_thread_ptr(ec);
837 volatile VALUE wrapper = th->top_wrapper;
838 volatile VALUE self = th->top_self;
839#if !defined __GNUC__
840 rb_thread_t *volatile th0 = th;
841#endif
842
843 ec->errinfo = Qnil; /* ensure */
844
845 /* load in module as toplevel */
846 if (BOX_OBJ_P(load_wrapper)) {
847 box = rb_get_box_t(load_wrapper);
848 if (!box->top_self) {
849 box->top_self = rb_obj_clone(rb_vm_top_self());
850 }
851 th->top_self = box->top_self;
852 }
853 else {
854 th->top_self = rb_obj_clone(rb_vm_top_self());
855 }
856 th->top_wrapper = load_wrapper;
857 rb_extend_object(th->top_self, th->top_wrapper);
858
859 EC_PUSH_TAG(ec);
860 state = EC_EXEC_TAG();
861 if (state == TAG_NONE) {
862 load_iseq_eval(ec, fname);
863 }
864 EC_POP_TAG();
865
866#if !defined __GNUC__
867 th = th0;
868 fname = RB_GC_GUARD(fname);
869#endif
870 th->top_self = self;
871 th->top_wrapper = wrapper;
872 return state;
873}
874
875static inline void
876raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
877{
878 if (state) {
879 rb_vm_jump_tag_but_local_jump(state);
880 }
881
882 if (!NIL_P(ec->errinfo)) {
883 rb_exc_raise(ec->errinfo);
884 }
885}
886
887static void
888rb_load_internal(VALUE fname, VALUE wrap)
889{
890 VALUE box_value;
891 rb_execution_context_t *ec = GET_EC();
892 const rb_box_t *box = rb_loading_box();
893 enum ruby_tag_type state = TAG_NONE;
894 if (RTEST(wrap)) {
895 if (!RB_TYPE_P(wrap, T_MODULE)) {
896 wrap = rb_module_new();
897 }
898 state = load_wrapping(ec, fname, wrap);
899 }
900 else if (BOX_OPTIONAL_P(box)) {
901 box_value = box->box_object;
902 state = load_wrapping(ec, fname, box_value);
903 }
904 else {
905 load_iseq_eval(ec, fname);
906 }
907 raise_load_if_failed(ec, state);
908}
909
910void
911rb_load(VALUE fname, int wrap)
912{
913 VALUE tmp = rb_find_file(FilePathValue(fname));
914 if (!tmp) load_failed(fname);
915 rb_load_internal(tmp, RBOOL(wrap));
916}
917
918void
919rb_load_protect(VALUE fname, int wrap, int *pstate)
920{
921 enum ruby_tag_type state;
922
923 EC_PUSH_TAG(GET_EC());
924 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
925 rb_load(fname, wrap);
926 }
927 EC_POP_TAG();
928
929 if (state != TAG_NONE) *pstate = state;
930}
931
932VALUE
933rb_load_entrypoint(VALUE fname, VALUE wrap)
934{
935 VALUE path, orig_fname;
936
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));
940
941 path = rb_find_file(fname);
942 if (!path) {
943 if (!rb_file_load_ok(RSTRING_PTR(fname)))
944 load_failed(orig_fname);
945 path = fname;
946 }
947 rb_load_internal(path, wrap);
948
949 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
950
951 return Qtrue;
952}
953
954/*
955 * call-seq:
956 * load(filename, wrap=false) -> true
957 *
958 * Loads and executes the Ruby program in the file _filename_.
959 *
960 * If the filename is an absolute path (e.g. starts with '/'), the file
961 * will be loaded directly using the absolute path.
962 *
963 * If the filename is an explicit relative path (e.g. starts with './' or
964 * '../'), the file will be loaded using the relative path from the current
965 * directory.
966 *
967 * Otherwise, the file will be searched for in the library
968 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
969 * If the file is found in a directory, it will attempt to load the file
970 * relative to that directory. If the file is not found in any of the
971 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
972 * the relative path from the current directory.
973 *
974 * If the file doesn't exist when there is an attempt to load it, a
975 * LoadError will be raised.
976 *
977 * If the optional _wrap_ parameter is +true+, the loaded script will
978 * be executed under an anonymous module. If the optional _wrap_ parameter
979 * is a module, the loaded script will be executed under the given module.
980 * In no circumstance will any local variables in the loaded file be
981 * propagated to the loading environment.
982 */
983
984static VALUE
985rb_f_load(int argc, VALUE *argv, VALUE _)
986{
987 VALUE fname, wrap;
988 rb_scan_args(argc, argv, "11", &fname, &wrap);
989 return rb_load_entrypoint(fname, wrap);
990}
991
992static char *
993load_lock(const rb_box_t *box, const char *ftptr, bool warn)
994{
995 st_data_t data;
996 st_table *loading_tbl = box->loading_table;
997
998 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
999 /* partial state */
1000 ftptr = ruby_strdup(ftptr);
1001 data = (st_data_t)rb_thread_shield_new();
1002 st_insert(loading_tbl, (st_data_t)ftptr, data);
1003 return (char *)ftptr;
1004 }
1005
1006 if (warn && rb_thread_shield_owned((VALUE)data)) {
1007 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
1008 rb_backtrace_each(rb_str_append, warning);
1009 rb_warning("%"PRIsVALUE, warning);
1010 }
1011 switch (rb_thread_shield_wait((VALUE)data)) {
1012 case Qfalse:
1013 case Qnil:
1014 return 0;
1015 }
1016 return (char *)ftptr;
1017}
1018
1019static int
1020release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
1021{
1022 VALUE thread_shield = (VALUE)*value;
1023 if (!existing) return ST_STOP;
1024 if (done) {
1025 rb_thread_shield_destroy(thread_shield);
1026 /* Delete the entry even if there are waiting threads, because they
1027 * won't load the file and won't delete the entry. */
1028 }
1029 else if (rb_thread_shield_release(thread_shield)) {
1030 /* still in-use */
1031 return ST_CONTINUE;
1032 }
1033 xfree((char *)*key);
1034 return ST_DELETE;
1035}
1036
1037static void
1038load_unlock(const rb_box_t *box, const char *ftptr, int done)
1039{
1040 if (ftptr) {
1041 st_data_t key = (st_data_t)ftptr;
1042 st_table *loading_tbl = box->loading_table;
1043
1044 st_update(loading_tbl, key, release_thread_shield, done);
1045 }
1046}
1047
1048static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
1049
1050/*
1051 * call-seq:
1052 * require(name) -> true or false
1053 *
1054 * Loads the given +name+, returning +true+ if successful and +false+ if the
1055 * feature is already loaded.
1056 *
1057 * If the filename neither resolves to an absolute path nor starts with
1058 * './' or '../', the file will be searched for in the library
1059 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
1060 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
1061 *
1062 * If the filename has the extension ".rb", it is loaded as a source file; if
1063 * the extension is ".so", ".o", or the default shared library extension on
1064 * the current platform, Ruby loads the shared library as a Ruby extension.
1065 * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
1066 * found. If the file named cannot be found, a LoadError will be raised.
1067 *
1068 * For Ruby extensions the filename given may use ".so" or ".o". For example,
1069 * on macOS the socket extension is "socket.bundle" and
1070 * <code>require 'socket.so'</code> will load the socket extension.
1071 *
1072 * The absolute path of the loaded file is added to
1073 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
1074 * loaded again if its path already appears in <code>$"</code>. For example,
1075 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1076 * again.
1077 *
1078 * require "my-library.rb"
1079 * require "db-driver"
1080 *
1081 * Any constants or globals within the loaded source file will be available
1082 * in the calling program's global namespace. However, local variables will
1083 * not be propagated to the loading environment.
1084 *
1085 */
1086
1087VALUE
1089{
1090 return rb_require_string(fname);
1091}
1092
1093VALUE
1094rb_require_relative_entrypoint(VALUE fname)
1095{
1096 VALUE base = rb_current_realfilepath();
1097 if (NIL_P(base)) {
1098 rb_loaderror("cannot infer basepath");
1099 }
1100 base = rb_file_dirname(base);
1101 return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1102}
1103
1104/*
1105 * call-seq:
1106 * require_relative(string) -> true or false
1107 *
1108 * Ruby tries to load the library named _string_ relative to the directory
1109 * containing the requiring file. If the file does not exist a LoadError is
1110 * raised. Returns +true+ if the file was loaded and +false+ if the file was
1111 * already loaded before.
1112 */
1113static VALUE
1114rb_f_require_relative(VALUE obj, VALUE fname)
1115{
1116 return rb_require_relative_entrypoint(fname);
1117}
1118
1119static char *
1120find_ext(VALUE str, char **ptr, const char **end)
1121{
1122 rb_len_t len = RSTRING_LEN(str);
1123 *ptr = RSTRING_PTR(str);
1124 *end = *ptr + len;
1125 return memrchr(*ptr, '.', len);
1126}
1127
1128static bool
1129ext_equal(const char *ext, const char *end, const char *suffix, size_t len)
1130{
1131 return (size_t)(end - ext) == len && memcmp(ext, suffix, len) == 0;
1132}
1133
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))
1138
1139typedef int (*feature_func)(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1140
1141static int
1142search_required(const rb_box_t *box, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1143{
1144 VALUE tmp;
1145 char *ext, *ftptr;
1146 int ft = 0;
1147 const char *ftend, *loading;
1148
1149 *path = 0;
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)) {
1154 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1155 return 'r';
1156 }
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)
1160 *path = tmp;
1161 return 'r';
1162 }
1163 return 0;
1164 }
1165 else if (EXT_SO_P(ext, ftend)) {
1166 if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
1167 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1168 return 's';
1169 }
1170 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1171 rb_str_cat2(tmp, DLEXT);
1172 OBJ_FREEZE(tmp);
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)
1176 *path = tmp;
1177 return 's';
1178 }
1179 }
1180 else if (EXT_DLEXT_P(ext, ftend)) {
1181 if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
1182 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1183 return 's';
1184 }
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)
1188 *path = tmp;
1189 return 's';
1190 }
1191 }
1192 }
1193 else if ((ft = rb_feature_p(box, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1194 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1195 return 'r';
1196 }
1197 tmp = fname;
1198 const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1199
1200 // Check if it's a statically linked extension when
1201 // not already a feature and not found as a dynamic library.
1202 if (!ft && type != loadable_ext_rb) {
1203 rb_vm_t *vm = GET_VM();
1204 if (vm->static_ext_inits.num_entries) {
1205 VALUE lookup_name = tmp;
1206 // Append ".so" if not already present so for example "etc" can find "etc.so".
1207 // We always register statically linked extensions with a ".so" extension.
1208 // See encinit.c and extinit.c (generated at build-time).
1209 if (!ext) {
1210 lookup_name = rb_str_dup(lookup_name);
1211 rb_str_cat_cstr(lookup_name, ".so");
1212 }
1213 ftptr = RSTRING_PTR(lookup_name);
1214 if (st_lookup(&vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1215 *path = rb_filesystem_str_new_cstr(ftptr);
1216 RB_GC_GUARD(lookup_name);
1217 return 's';
1218 }
1219 }
1220 }
1221
1222 switch (type) {
1223 case 0:
1224 if (ft)
1225 goto feature_present;
1226 ftptr = RSTRING_PTR(tmp);
1227 return rb_feature_p(box, ftptr, 0, FALSE, TRUE, 0);
1228
1229 default:
1230 if (ft) {
1231 goto feature_present;
1232 }
1233 /* fall through */
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)
1237 break;
1238 *path = tmp;
1239 }
1240 return type > loadable_ext_rb ? 's' : 'r';
1241
1242 feature_present:
1243 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1244 return ft;
1245}
1246
1247static void
1248load_failed(VALUE fname)
1249{
1250 rb_load_fail(fname, "cannot load such file");
1251}
1252
1253static VALUE
1254load_ext(VALUE path, VALUE fname)
1255{
1256 VALUE loaded = path;
1257 const rb_box_t *box = rb_loading_box();
1258 VALUE cleanup = 0;
1259 if (BOX_USER_P(box)) {
1260 loaded = rb_box_local_extension(box->box_object, path, &cleanup);
1261 }
1262 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1263 void *handle = dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
1264 if (cleanup) {
1265 rb_box_cleanup_local_extension(cleanup);
1266 rb_box_defer_unload_local_extension(handle);
1267 }
1268 RB_GC_GUARD(loaded);
1269 RB_GC_GUARD(fname);
1270 return (VALUE)handle;
1271}
1272
1273static VALUE
1274run_static_ext_init(VALUE vm_ptr, VALUE feature_value)
1275{
1276 rb_vm_t *vm = (rb_vm_t *)vm_ptr;
1277 const char *feature = RSTRING_PTR(feature_value);
1278 st_data_t key = (st_data_t)feature;
1279 st_data_t init_func;
1280
1281 if (st_delete(&vm->static_ext_inits, &key, &init_func)) {
1282 ((void (*)(void))init_func)();
1283 return Qtrue;
1284 }
1285 return Qfalse;
1286}
1287
1288static int
1289no_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1290{
1291 return 0;
1292}
1293
1294// Documented in doc/language/globals.md
1295VALUE
1296rb_resolve_feature_path(VALUE klass, VALUE fname)
1297{
1298 VALUE path;
1299 int found;
1300 VALUE sym;
1301 const rb_box_t *box = rb_loading_box();
1302
1303 fname = rb_get_path(fname);
1304 path = rb_str_encode_ospath(fname);
1305 found = search_required(box, path, &path, no_feature_p);
1306
1307 switch (found) {
1308 case 'r':
1309 sym = ID2SYM(rb_intern("rb"));
1310 break;
1311 case 's':
1312 sym = ID2SYM(rb_intern("so"));
1313 break;
1314 default:
1315 return Qnil;
1316 }
1317
1318 return rb_ary_new_from_args(2, sym, path);
1319}
1320
1321static void
1322ext_config_push(rb_thread_t *th, volatile struct rb_ext_config *prev)
1323{
1324 *prev = th->ext_config;
1325 th->ext_config = (struct rb_ext_config){0};
1326}
1327
1328static void
1329ext_config_pop(rb_thread_t *th, volatile struct rb_ext_config *prev)
1330{
1331 th->ext_config = *prev;
1332}
1333
1334void
1336{
1337 GET_THREAD()->ext_config.ractor_safe = flag;
1338}
1339
1340/*
1341 * returns
1342 * 0: if already loaded (false)
1343 * 1: successfully loaded (true)
1344 * <0: not found (LoadError)
1345 * >1: exception
1346 */
1347static int
1348require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1349{
1350 volatile int result = -1;
1351 rb_thread_t *th = rb_ec_thread_ptr(ec);
1352 const rb_box_t *box = rb_loading_box();
1353 volatile const struct {
1354 VALUE wrapper, self, errinfo;
1356 const rb_box_t *box;
1357 } saved = {
1358 th->top_wrapper, th->top_self, ec->errinfo,
1359 ec, box,
1360 };
1361 enum ruby_tag_type state;
1362 char *volatile ftptr = 0;
1363 VALUE path;
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;
1369 volatile struct rb_ext_config prev_ext_config;
1370
1371 path = rb_str_encode_ospath(fname);
1372 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1373 saved_path = path;
1374
1375 EC_PUSH_TAG(ec);
1376 ec->errinfo = Qnil; /* ensure */
1377 th->top_wrapper = 0;
1378 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1379 VALUE handle;
1380 int found;
1381
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));
1385 path = saved_path;
1386
1387 if (found) {
1388 if (!path || !(ftptr = load_lock(box, RSTRING_PTR(path), warn))) {
1389 result = 0;
1390 }
1391 else if (!*ftptr) {
1392 result = TAG_RETURN;
1393 }
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;
1396 }
1397 else if (RTEST(rb_hash_aref(realpaths,
1398 realpath = realpath_internal_cached(realpath_map, path)))) {
1399 result = 0;
1400 }
1401 else {
1402 switch (found) {
1403 case 'r':
1404 load_iseq_eval(saved.ec, path);
1405 break;
1406
1407 case 's':
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));
1412 break;
1413 }
1414 result = TAG_RETURN;
1415 }
1416 }
1417 }
1418 EC_POP_TAG();
1419
1420 ec = saved.ec;
1421 box = saved.box;
1422 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1423 th2->top_self = saved.self;
1424 th2->top_wrapper = saved.wrapper;
1425 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1426
1427 path = saved_path;
1428 if (ftptr) load_unlock(box, RSTRING_PTR(path), !state);
1429
1430 if (state) {
1431 if (state == TAG_FATAL || state == TAG_THROW) {
1432 EC_JUMP_TAG(ec, state);
1433 }
1434 else if (exception) {
1435 /* usually state == TAG_RAISE only, except for
1436 * rb_iseq_load_iseq in load_iseq_eval case */
1437 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1438 if (!NIL_P(exc)) ec->errinfo = exc;
1439 return TAG_RAISE;
1440 }
1441 else if (state == TAG_RETURN) {
1442 return TAG_RAISE;
1443 }
1444 RB_GC_GUARD(fname);
1445 /* never TAG_RETURN */
1446 return state;
1447 }
1448 if (!NIL_P(ec->errinfo)) {
1449 if (!exception) return TAG_RAISE;
1450 rb_exc_raise(ec->errinfo);
1451 }
1452
1453 if (result == TAG_RETURN) {
1454 rb_provide_feature(box, path);
1455 VALUE real = realpath;
1456 if (real) {
1457 real = rb_fstring(real);
1458 rb_hash_aset(realpaths, real, Qtrue);
1459 }
1460 }
1461 ec->errinfo = saved.errinfo;
1462
1463 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1464
1465 return result;
1466}
1467
1468int
1469rb_require_internal_silent(VALUE fname)
1470{
1471 if (!rb_ractor_main_p()) {
1472 return NUM2INT(rb_ractor_require(fname, true));
1473 }
1474
1475 rb_execution_context_t *ec = GET_EC();
1476 return require_internal(ec, fname, 1, false);
1477}
1478
1479int
1480rb_require_internal(VALUE fname)
1481{
1482 rb_execution_context_t *ec = GET_EC();
1483 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1484}
1485
1486int
1487ruby_require_internal(const char *fname, unsigned int len)
1488{
1489 struct RString fake = {RBASIC_INIT};
1490 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1491 rb_execution_context_t *ec = GET_EC();
1492 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1493 rb_set_errinfo(Qnil);
1494 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1495}
1496
1497VALUE
1499{
1500 return rb_require_string_internal(FilePathValue(fname), false);
1501}
1502
1503static VALUE
1504rb_require_string_internal(VALUE fname, bool resurrect)
1505{
1506 rb_execution_context_t *ec = GET_EC();
1507
1508 // main ractor check
1509 if (!rb_ractor_main_p()) {
1510 if (resurrect) fname = rb_str_resurrect(fname);
1511 return rb_ractor_require(fname, false);
1512 }
1513 else {
1514 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1515
1516 if (result > TAG_RETURN) {
1517 EC_JUMP_TAG(ec, result);
1518 }
1519 if (result < 0) {
1520 if (resurrect) fname = rb_str_resurrect(fname);
1521 load_failed(fname);
1522 }
1523
1524 return RBOOL(result);
1525 }
1526}
1527
1528VALUE
1529rb_require(const char *fname)
1530{
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);
1534}
1535
1536static int
1537register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1538{
1539 const char *name = (char *)*key;
1540 if (existing) {
1541 /* already registered */
1542 rb_warn("%s is already registered", name);
1543 }
1544 else {
1545 *value = (st_data_t)init;
1546 }
1547 return ST_CONTINUE;
1548}
1549
1550// Private API for statically linked extensions.
1551// Used with the ext/Setup file, the --with-setup and
1552// --with-static-linked-ext configuration option, etc.
1553void
1554ruby_init_ext(const char *name, void (*init)(void))
1555{
1556 rb_vm_t *vm = GET_VM();
1557 const rb_box_t *box = rb_loading_box();
1558
1559 if (feature_provided((rb_box_t *)box, name, 0))
1560 return;
1561
1562 st_update(&vm->static_ext_inits, (st_data_t)name, register_init_ext, (st_data_t)init);
1563}
1564
1565/*
1566 * call-seq:
1567 * mod.autoload(const, filename) -> nil
1568 *
1569 * Registers _filename_ to be loaded (using Kernel::require)
1570 * the first time that _const_ (which may be a String or
1571 * a symbol) is accessed in the namespace of _mod_.
1572 *
1573 * module A
1574 * end
1575 * A.autoload(:B, "b")
1576 * A::B.doit # autoloads "b"
1577 *
1578 * If _const_ in _mod_ is defined as autoload, the file name to be
1579 * loaded is replaced with _filename_. If _const_ is defined but not
1580 * as autoload, does nothing.
1581 *
1582 * Files that are currently being loaded must not be registered for
1583 * autoload.
1584 */
1585
1586static VALUE
1587rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1588{
1589 ID id = rb_to_id(sym);
1590
1591 FilePathValue(file);
1592 rb_autoload_str(mod, id, file);
1593 return Qnil;
1594}
1595
1596/*
1597 * call-seq:
1598 * mod.autoload_relative(const, filename) -> nil
1599 *
1600 * Registers _filename_ to be loaded (using Kernel::require)
1601 * the first time that _const_ (which may be a String or
1602 * a symbol) is accessed in the namespace of _mod_. The _filename_
1603 * is interpreted as relative to the directory of the file where
1604 * autoload_relative is called.
1605 *
1606 * module A
1607 * end
1608 * A.autoload_relative(:B, "b.rb")
1609 *
1610 * If _const_ in _mod_ is defined as autoload, the file name to be
1611 * loaded is replaced with _filename_. If _const_ is defined but not
1612 * as autoload, does nothing.
1613 *
1614 * The relative path is converted to an absolute path, which is what
1615 * will be returned by Module#autoload? for the constant.
1616 *
1617 * Raises LoadError if called without file context (e.g., from eval).
1618 */
1619
1620static VALUE
1621rb_mod_autoload_relative(VALUE mod, VALUE sym, VALUE file)
1622{
1623 ID id = rb_to_id(sym);
1624 VALUE base, absolute_path;
1625
1626 FilePathValue(file);
1627
1628 base = rb_current_realfilepath();
1629 if (NIL_P(base)) {
1630 rb_loaderror("cannot infer basepath (autoload_relative called without file context)");
1631 }
1632 base = rb_file_dirname(base);
1633 absolute_path = rb_file_absolute_path(file, base);
1634
1635 rb_autoload_str(mod, id, absolute_path);
1636 return Qnil;
1637}
1638
1639/*
1640 * call-seq:
1641 * mod.autoload?(name, inherit=true) -> String or nil
1642 *
1643 * Returns _filename_ to be loaded if _name_ is registered as
1644 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1645 *
1646 * module A
1647 * end
1648 * A.autoload(:B, "b")
1649 * A.autoload?(:B) #=> "b"
1650 *
1651 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1652 *
1653 * class A
1654 * autoload :CONST, "const.rb"
1655 * end
1656 *
1657 * class B < A
1658 * end
1659 *
1660 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1661 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1662 *
1663 */
1664
1665static VALUE
1666rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1667{
1668 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1669 VALUE sym = argv[0];
1670
1671 ID id = rb_check_id(&sym);
1672 if (!id) {
1673 return Qnil;
1674 }
1675 return rb_autoload_at_p(mod, id, recur);
1676}
1677
1678/*
1679 * call-seq:
1680 * autoload(const, filename) -> nil
1681 *
1682 * Registers _filename_ to be loaded (using Kernel::require)
1683 * the first time that _const_ (which may be a String or
1684 * a symbol) is accessed.
1685 *
1686 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1687 *
1688 * If _const_ is defined as autoload, the file name to be loaded is
1689 * replaced with _filename_. If _const_ is defined but not as
1690 * autoload, does nothing.
1691 *
1692 * Files that are currently being loaded must not be registered for
1693 * autoload.
1694 */
1695
1696static VALUE
1697rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1698{
1699 VALUE klass = rb_class_real(rb_vm_cbase());
1700 if (!klass) {
1701 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1702 }
1703 return rb_mod_autoload(klass, sym, file);
1704}
1705
1706/*
1707 * call-seq:
1708 * autoload_relative(const, filename) -> nil
1709 *
1710 * Registers _filename_ to be loaded (using Kernel::require)
1711 * the first time that _const_ (which may be a String or
1712 * a symbol) is accessed. The _filename_ is interpreted as
1713 * relative to the directory of the file where autoload_relative
1714 * is called.
1715 *
1716 * autoload_relative(:MyModule, "my_module.rb")
1717 *
1718 * If _const_ is defined as autoload, the file name to be loaded is
1719 * replaced with _filename_. If _const_ is defined but not as
1720 * autoload, does nothing.
1721 *
1722 * The relative path is converted to an absolute path, which is what
1723 * will be returned by Kernel#autoload? for the constant.
1724 *
1725 * Raises LoadError if called without file context (e.g., from eval).
1726 */
1727
1728static VALUE
1729rb_f_autoload_relative(VALUE obj, VALUE sym, VALUE file)
1730{
1731 VALUE klass = rb_class_real(rb_vm_cbase());
1732 if (!klass) {
1733 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1734 }
1735 return rb_mod_autoload_relative(klass, sym, file);
1736}
1737
1738/*
1739 * call-seq:
1740 * autoload?(name, inherit=true) -> String or nil
1741 *
1742 * Returns _filename_ to be loaded if _name_ is registered as
1743 * +autoload+ in the current namespace or one of its ancestors.
1744 *
1745 * autoload(:B, "b")
1746 * autoload?(:B) #=> "b"
1747 *
1748 * module C
1749 * autoload(:D, "d")
1750 * autoload?(:D) #=> "d"
1751 * autoload?(:B) #=> nil
1752 * end
1753 *
1754 * class E
1755 * autoload(:F, "f")
1756 * autoload?(:F) #=> "f"
1757 * autoload?(:B) #=> "b"
1758 * end
1759 */
1760
1761static VALUE
1762rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1763{
1764 /* use rb_vm_cbase() as same as rb_f_autoload. */
1765 VALUE klass = rb_vm_cbase();
1766 if (NIL_P(klass)) {
1767 return Qnil;
1768 }
1769 return rb_mod_autoload_p(argc, argv, klass);
1770}
1771
1772void *
1773rb_ext_resolve_symbol(const char* fname, const char* symbol)
1774{
1775 VALUE handle;
1776 VALUE resolved;
1777 VALUE path;
1778 const char *ext;
1779 VALUE fname_str = rb_str_new_cstr(fname);
1780 const rb_box_t *box = rb_loading_box();
1781
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)) {
1786 rb_str_cat_cstr(fname_str, ".so");
1787 }
1788 if (rb_feature_p(box, fname, 0, FALSE, FALSE, 0)) {
1789 return dln_symbol(NULL, symbol);
1790 }
1791 return NULL;
1792 }
1793 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1794 return NULL;
1795 }
1796 path = rb_ary_entry(resolved, 1);
1797 handle = rb_hash_lookup(box->ruby_dln_libmap, path);
1798 if (NIL_P(handle)) {
1799 return NULL;
1800 }
1801 return dln_symbol(NUM2PTR(handle), symbol);
1802}
1803
1804void
1805Init_load(void)
1806{
1807 static const char var_load_path[] = "$:";
1808 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1809
1810 rb_define_hooked_variable(var_load_path, 0, load_path_getter, rb_gvar_readonly_setter);
1811 rb_gvar_box_ready(var_load_path);
1812 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1813 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1814
1815 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1816 rb_gvar_box_ready("$\"");
1817 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
1818 rb_gvar_box_ready("$LOADED_FEATURES");
1819
1820 rb_define_global_function("load", rb_f_load, -1);
1822 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1823 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1824 rb_define_method(rb_cModule, "autoload_relative", rb_mod_autoload_relative, 2);
1825 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1826 rb_define_global_function("autoload", rb_f_autoload, 2);
1827 rb_define_global_function("autoload_relative", rb_f_autoload_relative, 2);
1828 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1829}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#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.
Definition eval.c:1940
VALUE rb_module_new(void)
Creates a new, anonymous module.
Definition class.c:1662
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:3385
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#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:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#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:131
#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 Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#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 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.
Definition eval.c:678
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
Definition error.c:3975
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:495
VALUE rb_cModule
Module class.
Definition object.c:61
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:225
VALUE rb_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
Definition object.c:501
Encoding relates APIs.
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.
Definition error.h:284
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:711
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:1088
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1335
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1498
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:682
void rb_load_protect(VALUE path, int wrap, int *state)
Identical to rb_load(), except it avoids potential global escapes.
Definition load.c:919
int rb_provided(const char *feature)
Queries if the given feature has already been loaded into the execution context.
Definition load.c:649
void rb_load(VALUE path, int wrap)
Loads and executes the Ruby program in the given file.
Definition load.c:911
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...
Definition load.c:1773
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...
Definition string.c:3270
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:3917
VALUE rb_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
Definition string.c:1797
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2038
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...
Definition string.c:2056
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:1466
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4386
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1717
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3395
#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.
Definition string.h:1681
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1539
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition variable.c:1230
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1289
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...
Definition string.c:14141
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
int len
Length of the buffer.
Definition io.h:8
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:511
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
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.
Definition rarray.h:50
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1529
#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 String.
Definition rstring.h:196
pm_scope_node_t node
The resulting scope node that will hold the generated AST.
Internal header for Ruby Box.
Definition box.h:14
Definition st.h:79
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:131
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:425
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:376