Ruby: load.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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