Ruby: variable.c Source File

Ruby 4.0.6p0 (2026-07-14 revision 03b6d3f8898a28604fe6cb00eae3226b821168f4)

variable.c
1/**********************************************************************
2
3 variable.c -
4
5 $Author$
6 created at: Tue Apr 19 23:55:15 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15#include <stddef.h>
16#include "ruby/internal/stdbool.h"
17#include "ccan/list/list.h"
18#include "constant.h"
19#include "debug_counter.h"
20#include "id.h"
21#include "id_table.h"
22#include "internal.h"
23#include "internal/box.h"
24#include "internal/class.h"
25#include "internal/compilers.h"
26#include "internal/error.h"
27#include "internal/eval.h"
28#include "internal/hash.h"
29#include "internal/object.h"
30#include "internal/gc.h"
31#include "internal/re.h"
32#include "internal/struct.h"
33#include "internal/symbol.h"
34#include "internal/thread.h"
35#include "internal/variable.h"
36#include "ruby/encoding.h"
37#include "ruby/st.h"
38#include "ruby/util.h"
39#include "shape.h"
40#include "symbol.h"
41#include "variable.h"
42#include "vm_core.h"
43#include "ractor_core.h"
44#include "vm_sync.h"
45
46 RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
47#define GET_GLOBAL_CVAR_STATE() (ruby_vm_global_cvar_state)
48
49typedef void rb_gvar_compact_t(void *var);
50
51static struct rb_id_table *rb_global_tbl;
52static ID autoload;
53
54// This hash table maps file paths to loadable features. We use this to track
55// autoload state until it's no longer needed.
56// feature (file path) => struct autoload_data
57static VALUE autoload_features;
58
59// This mutex is used to protect autoloading state. We use a global mutex which
60// is held until a per-feature mutex can be created. This ensures there are no
61// race conditions relating to autoload state.
62static VALUE autoload_mutex;
63
64static void check_before_mod_set(VALUE, ID, VALUE, const char *);
65static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
66static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in);
67static st_table *generic_fields_tbl_;
68
69typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg);
70static void rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only);
71
72void
73Init_var_tables(void)
74{
75 rb_global_tbl = rb_id_table_create(0);
76 generic_fields_tbl_ = st_init_numtable();
77 autoload = rb_intern_const("__autoload__");
78
79 autoload_mutex = rb_mutex_new();
80 rb_obj_hide(autoload_mutex);
81 rb_vm_register_global_object(autoload_mutex);
82
83 autoload_features = rb_ident_hash_new();
84 rb_obj_hide(autoload_features);
85 rb_vm_register_global_object(autoload_features);
86}
87
88static inline bool
89rb_namespace_p(VALUE obj)
90{
91 if (RB_SPECIAL_CONST_P(obj)) return false;
92 switch (RB_BUILTIN_TYPE(obj)) {
93 case T_MODULE: case T_CLASS: return true;
94 default: break;
95 }
96 return false;
97}
98
109static VALUE
110classname(VALUE klass, bool *permanent)
111{
112 *permanent = false;
113
114 VALUE classpath = RCLASS_CLASSPATH(klass);
115 if (classpath == 0) return Qnil;
116
117 *permanent = RCLASS_PERMANENT_CLASSPATH_P(klass);
118
119 return classpath;
120}
121
122 VALUE
123rb_mod_name0(VALUE klass, bool *permanent)
124{
125 return classname(klass, permanent);
126}
127
128/*
129 * call-seq:
130 * mod.name -> string or nil
131 *
132 * Returns the name of the module <i>mod</i>. Returns +nil+ for anonymous modules.
133 */
134
135 VALUE
136rb_mod_name(VALUE mod)
137{
138 // YJIT needs this function to not allocate.
139 bool permanent;
140 return classname(mod, &permanent);
141}
142
143// Similar to logic in rb_mod_const_get().
144static bool
145is_constant_path(VALUE name)
146{
147 const char *path = RSTRING_PTR(name);
148 const char *pend = RSTRING_END(name);
149 rb_encoding *enc = rb_enc_get(name);
150
151 const char *p = path;
152
153 if (p >= pend || !*p) {
154 return false;
155 }
156
157 while (p < pend) {
158 if (p + 2 <= pend && p[0] == ':' && p[1] == ':') {
159 p += 2;
160 }
161
162 const char *pbeg = p;
163 while (p < pend && *p != ':') p++;
164
165 if (pbeg == p) return false;
166
167 if (rb_enc_symname_type(pbeg, p - pbeg, enc, 0) != ID_CONST) {
168 return false;
169 }
170 }
171
172 return true;
173}
174
175 struct sub_temporary_name_args {
176 VALUE names;
177 ID last;
178};
179
180static VALUE build_const_path(VALUE head, ID tail);
181static void set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name);
182
183static VALUE
184set_sub_temporary_name_recursive(VALUE mod, VALUE data, int recursive)
185{
186 if (recursive) return Qfalse;
187
188 struct sub_temporary_name_args *args = (void *)data;
189 VALUE name = 0;
190 if (args->names) {
191 name = build_const_path(rb_ary_last(0, 0, args->names), args->last);
192 }
193 set_sub_temporary_name_foreach(mod, args, name);
194 return Qtrue;
195}
196
197static VALUE
198set_sub_temporary_name_topmost(VALUE mod, VALUE data, int recursive)
199{
200 if (recursive) return Qfalse;
201
202 struct sub_temporary_name_args *args = (void *)data;
203 VALUE name = args->names;
204 if (name) {
205 args->names = rb_ary_hidden_new(0);
206 }
207 set_sub_temporary_name_foreach(mod, args, name);
208 return Qtrue;
209}
210
211static enum rb_id_table_iterator_result
212set_sub_temporary_name_i(ID id, VALUE val, void *data)
213{
214 val = ((rb_const_entry_t *)val)->value;
215 if (rb_namespace_p(val) && !RCLASS_PERMANENT_CLASSPATH_P(val)) {
216 VALUE arg = (VALUE)data;
217 struct sub_temporary_name_args *args = data;
218 args->last = id;
219 rb_exec_recursive_paired(set_sub_temporary_name_recursive, val, arg, arg);
220 }
221 return ID_TABLE_CONTINUE;
222}
223
224static void
225set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name)
226{
227 RCLASS_WRITE_CLASSPATH(mod, name, FALSE);
228 struct rb_id_table *tbl = RCLASS_CONST_TBL(mod);
229 if (!tbl) return;
230 if (!name) {
231 rb_id_table_foreach(tbl, set_sub_temporary_name_i, args);
232 }
233 else {
234 long names_len = RARRAY_LEN(args->names); // paranoiac check?
235 rb_ary_push(args->names, name);
236 rb_id_table_foreach(tbl, set_sub_temporary_name_i, args);
237 rb_ary_set_len(args->names, names_len);
238 }
239}
240
241static void
242set_sub_temporary_name(VALUE mod, VALUE name)
243{
244 struct sub_temporary_name_args args = {name};
245 VALUE arg = (VALUE)&args;
246 rb_exec_recursive_paired(set_sub_temporary_name_topmost, mod, arg, arg);
247}
248
249/*
250 * call-seq:
251 * mod.set_temporary_name(string) -> self
252 * mod.set_temporary_name(nil) -> self
253 *
254 * Sets the temporary name of the module. This name is reflected in
255 * introspection of the module and the values that are related to it, such
256 * as instances, constants, and methods.
257 *
258 * The name should be +nil+ or a non-empty string that is not a valid constant
259 * path (to avoid confusing between permanent and temporary names).
260 *
261 * The method can be useful to distinguish dynamically generated classes and
262 * modules without assigning them to constants.
263 *
264 * If the module is given a permanent name by assigning it to a constant,
265 * the temporary name is discarded. A temporary name can't be assigned to
266 * modules that have a permanent name.
267 *
268 * If the given name is +nil+, the module becomes anonymous again.
269 *
270 * Example:
271 *
272 * m = Module.new # => #<Module:0x0000000102c68f38>
273 * m.name #=> nil
274 *
275 * m.set_temporary_name("fake_name") # => fake_name
276 * m.name #=> "fake_name"
277 *
278 * m.set_temporary_name(nil) # => #<Module:0x0000000102c68f38>
279 * m.name #=> nil
280 *
281 * c = Class.new
282 * c.set_temporary_name("MyClass(with description)") # => MyClass(with description)
283 *
284 * c.new # => #<MyClass(with description):0x0....>
285 *
286 * c::M = m
287 * c::M.name #=> "MyClass(with description)::M"
288 *
289 * # Assigning to a constant replaces the name with a permanent one
290 * C = c
291 *
292 * C.name #=> "C"
293 * C::M.name #=> "C::M"
294 * c.new # => #<C:0x0....>
295 */
296
297 VALUE
298rb_mod_set_temporary_name(VALUE mod, VALUE name)
299{
300 // We don't allow setting the name if the classpath is already permanent:
301 if (RCLASS_PERMANENT_CLASSPATH_P(mod)) {
302 rb_raise(rb_eRuntimeError, "can't change permanent name");
303 }
304
305 if (NIL_P(name)) {
306 // Set the temporary classpath to NULL (anonymous):
307 RB_VM_LOCKING() {
308 set_sub_temporary_name(mod, 0);
309 }
310 }
311 else {
312 // Ensure the name is a string:
313 StringValue(name);
314
315 if (RSTRING_LEN(name) == 0) {
316 rb_raise(rb_eArgError, "empty class/module name");
317 }
318
319 if (is_constant_path(name)) {
320 rb_raise(rb_eArgError, "the temporary name must not be a constant path to avoid confusion");
321 }
322
323 name = rb_str_new_frozen(name);
324 RB_OBJ_SET_SHAREABLE(name);
325
326 // Set the temporary classpath to the given name:
327 RB_VM_LOCKING() {
328 set_sub_temporary_name(mod, name);
329 }
330 }
331
332 return mod;
333}
334
335static VALUE
336make_temporary_path(VALUE obj, VALUE klass)
337{
338 VALUE path;
339 switch (klass) {
340 case Qnil:
341 path = rb_sprintf("#<Class:%p>", (void*)obj);
342 break;
343 case Qfalse:
344 path = rb_sprintf("#<Module:%p>", (void*)obj);
345 break;
346 default:
347 path = rb_sprintf("#<%"PRIsVALUE":%p>", klass, (void*)obj);
348 break;
349 }
350 OBJ_FREEZE(path);
351 return path;
352}
353
354typedef VALUE (*fallback_func)(VALUE obj, VALUE name);
355
356static VALUE
357rb_tmp_class_path(VALUE klass, bool *permanent, fallback_func fallback)
358{
359 VALUE path = classname(klass, permanent);
360
361 if (!NIL_P(path)) {
362 return path;
363 }
364
365 if (RB_TYPE_P(klass, T_MODULE)) {
366 if (rb_obj_class(klass) == rb_cModule) {
367 path = Qfalse;
368 }
369 else {
370 bool perm;
371 path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, fallback);
372 }
373 }
374
375 *permanent = false;
376 return fallback(klass, path);
377}
378
379 VALUE
380rb_class_path(VALUE klass)
381{
382 bool permanent;
383 VALUE path = rb_tmp_class_path(klass, &permanent, make_temporary_path);
384 if (!NIL_P(path)) path = rb_str_dup(path);
385 return path;
386}
387
388 VALUE
389rb_class_path_cached(VALUE klass)
390{
391 return rb_mod_name(klass);
392}
393
394static VALUE
395no_fallback(VALUE obj, VALUE name)
396{
397 return name;
398}
399
400 VALUE
401rb_search_class_path(VALUE klass)
402{
403 bool permanent;
404 return rb_tmp_class_path(klass, &permanent, no_fallback);
405}
406
407static VALUE
408build_const_pathname(VALUE head, VALUE tail)
409{
410 VALUE path = rb_str_dup(head);
411 rb_str_cat2(path, "::");
412 rb_str_append(path, tail);
413 return rb_fstring(path);
414}
415
416static VALUE
417build_const_path(VALUE head, ID tail)
418{
419 return build_const_pathname(head, rb_id2str(tail));
420}
421
422void
423rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
424{
425 bool permanent = true;
426
427 VALUE str;
428 if (under == rb_cObject) {
429 str = rb_str_new_frozen(name);
430 }
431 else {
432 str = rb_tmp_class_path(under, &permanent, make_temporary_path);
433 str = build_const_pathname(str, name);
434 }
435
436 RB_OBJ_SET_SHAREABLE(str);
437 RCLASS_SET_CLASSPATH(klass, str, permanent);
438}
439
440void
441rb_set_class_path(VALUE klass, VALUE under, const char *name)
442{
443 VALUE str = rb_str_new2(name);
444 OBJ_FREEZE(str);
445 rb_set_class_path_string(klass, under, str);
446}
447
448 VALUE
449rb_path_to_class(VALUE pathname)
450{
451 rb_encoding *enc = rb_enc_get(pathname);
452 const char *pbeg, *pend, *p, *path = RSTRING_PTR(pathname);
453 ID id;
454 VALUE c = rb_cObject;
455
456 if (!rb_enc_asciicompat(enc)) {
457 rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
458 }
459 pbeg = p = path;
460 pend = path + RSTRING_LEN(pathname);
461 if (path == pend || path[0] == '#') {
462 rb_raise(rb_eArgError, "can't retrieve anonymous class %"PRIsVALUE,
463 QUOTE(pathname));
464 }
465 while (p < pend) {
466 while (p < pend && *p != ':') p++;
467 id = rb_check_id_cstr(pbeg, p-pbeg, enc);
468 if (p < pend && p[0] == ':') {
469 if ((size_t)(pend - p) < 2 || p[1] != ':') goto undefined_class;
470 p += 2;
471 pbeg = p;
472 }
473 if (!id) {
474 goto undefined_class;
475 }
476 c = rb_const_search(c, id, TRUE, FALSE, FALSE, NULL);
477 if (UNDEF_P(c)) goto undefined_class;
478 if (!rb_namespace_p(c)) {
479 rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
480 pathname);
481 }
482 }
483 RB_GC_GUARD(pathname);
484
485 return c;
486
487 undefined_class:
488 rb_raise(rb_eArgError, "undefined class/module % "PRIsVALUE,
489 rb_str_subseq(pathname, 0, p-path));
490 UNREACHABLE_RETURN(Qundef);
491}
492
493 VALUE
494rb_path2class(const char *path)
495{
496 return rb_path_to_class(rb_str_new_cstr(path));
497}
498
499 VALUE
500rb_class_name(VALUE klass)
501{
502 return rb_class_path(rb_class_real(klass));
503}
504
505const char *
506rb_class2name(VALUE klass)
507{
508 bool permanent;
509 VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, make_temporary_path);
510 if (NIL_P(path)) return NULL;
511 return RSTRING_PTR(path);
512}
513
514const char *
515rb_obj_classname(VALUE obj)
516{
517 return rb_class2name(CLASS_OF(obj));
518}
519
520 struct trace_var {
521 int removed;
522 void (*func)(VALUE arg, VALUE val);
523 VALUE data;
524 struct trace_var *next;
525};
526
527 struct rb_global_variable {
528 int counter;
529 int block_trace;
530 VALUE *data;
531 rb_gvar_getter_t *getter;
532 rb_gvar_setter_t *setter;
533 rb_gvar_marker_t *marker;
534 rb_gvar_compact_t *compactor;
535 struct trace_var *trace;
536 bool box_ready;
537 bool box_dynamic;
538};
539
540 struct rb_global_entry {
541 struct rb_global_variable *var;
542 ID id;
543 bool ractor_local;
544};
545
546static void
547free_global_variable(struct rb_global_variable *var)
548{
549 RUBY_ASSERT(var->counter == 0);
550
551 struct trace_var *trace = var->trace;
552 while (trace) {
553 struct trace_var *next = trace->next;
554 xfree(trace);
555 trace = next;
556 }
557 xfree(var);
558}
559
560static enum rb_id_table_iterator_result
561free_global_entry_i(VALUE val, void *arg)
562{
563 struct rb_global_entry *entry = (struct rb_global_entry *)val;
564 entry->var->counter--;
565 if (entry->var->counter == 0) {
566 free_global_variable(entry->var);
567 }
568 ruby_xfree(entry);
569 return ID_TABLE_DELETE;
570}
571
572void
573rb_free_rb_global_tbl(void)
574{
575 rb_id_table_foreach_values(rb_global_tbl, free_global_entry_i, 0);
576 rb_id_table_free(rb_global_tbl);
577}
578
579void
580rb_free_generic_fields_tbl_(void)
581{
582 st_free_table(generic_fields_tbl_);
583}
584
585static struct rb_global_entry*
586rb_find_global_entry(ID id)
587{
588 struct rb_global_entry *entry;
589 VALUE data;
590
591 RB_VM_LOCKING() {
592 if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
593 entry = NULL;
594 }
595 else {
596 entry = (struct rb_global_entry *)data;
597 RUBY_ASSERT(entry != NULL);
598 }
599 }
600
601 if (UNLIKELY(!rb_ractor_main_p()) && (!entry || !entry->ractor_local)) {
602 rb_raise(rb_eRactorIsolationError, "can not access global variable %s from non-main Ractor", rb_id2name(id));
603 }
604
605 return entry;
606}
607
608void
609rb_gvar_ractor_local(const char *name)
610{
611 struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
612 entry->ractor_local = true;
613}
614
615void
616rb_gvar_box_ready(const char *name)
617{
618 struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
619 entry->var->box_ready = true;
620}
621
622void
623rb_gvar_box_dynamic(const char *name)
624{
625 struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
626 entry->var->box_dynamic = true;
627}
628
629static void
630rb_gvar_undef_compactor(void *var)
631{
632}
633
634static struct rb_global_entry*
635 rb_global_entry(ID id)
636{
637 struct rb_global_entry *entry;
638 RB_VM_LOCKING() {
639 entry = rb_find_global_entry(id);
640 if (!entry) {
641 struct rb_global_variable *var;
642 entry = ALLOC(struct rb_global_entry);
643 var = ALLOC(struct rb_global_variable);
644 entry->id = id;
645 entry->var = var;
646 entry->ractor_local = false;
647 var->counter = 1;
648 var->data = 0;
649 var->getter = rb_gvar_undef_getter;
650 var->setter = rb_gvar_undef_setter;
651 var->marker = rb_gvar_undef_marker;
652 var->compactor = rb_gvar_undef_compactor;
653
654 var->block_trace = 0;
655 var->trace = 0;
656 var->box_ready = false;
657 var->box_dynamic = false;
658 rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
659 }
660 }
661 return entry;
662}
663
664 VALUE
665 rb_gvar_undef_getter(ID id, VALUE *_)
666{
667 rb_warning("global variable '%"PRIsVALUE"' not initialized", QUOTE_ID(id));
668
669 return Qnil;
670}
671
672static void
673rb_gvar_val_compactor(void *_var)
674{
675 struct rb_global_variable *var = (struct rb_global_variable *)_var;
676
677 VALUE obj = (VALUE)var->data;
678
679 if (obj) {
680 VALUE new = rb_gc_location(obj);
681 if (new != obj) {
682 var->data = (void*)new;
683 }
684 }
685}
686
687void
688 rb_gvar_undef_setter(VALUE val, ID id, VALUE *_)
689{
690 struct rb_global_variable *var = rb_global_entry(id)->var;
691 var->getter = rb_gvar_val_getter;
692 var->setter = rb_gvar_val_setter;
693 var->marker = rb_gvar_val_marker;
694 var->compactor = rb_gvar_val_compactor;
695
696 var->data = (void*)val;
697}
698
699void
700 rb_gvar_undef_marker(VALUE *var)
701{
702}
703
704 VALUE
705 rb_gvar_val_getter(ID id, VALUE *data)
706{
707 return (VALUE)data;
708}
709
710void
711 rb_gvar_val_setter(VALUE val, ID id, VALUE *_)
712{
713 struct rb_global_variable *var = rb_global_entry(id)->var;
714 var->data = (void*)val;
715}
716
717void
718 rb_gvar_val_marker(VALUE *var)
719{
720 VALUE data = (VALUE)var;
721 if (data) rb_gc_mark_movable(data);
722}
723
724 VALUE
725 rb_gvar_var_getter(ID id, VALUE *var)
726{
727 if (!var) return Qnil;
728 return *var;
729}
730
731void
732 rb_gvar_var_setter(VALUE val, ID id, VALUE *data)
733{
734 *data = val;
735}
736
737void
738 rb_gvar_var_marker(VALUE *var)
739{
740 if (var) rb_gc_mark_maybe(*var);
741}
742
743void
744 rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_)
745{
746 rb_name_error(id, "%"PRIsVALUE" is a read-only variable", QUOTE_ID(id));
747}
748
749static enum rb_id_table_iterator_result
750mark_global_entry(VALUE v, void *ignored)
751{
752 struct rb_global_entry *entry = (struct rb_global_entry *)v;
753 struct trace_var *trace;
754 struct rb_global_variable *var = entry->var;
755
756 (*var->marker)(var->data);
757 trace = var->trace;
758 while (trace) {
759 if (trace->data) rb_gc_mark_maybe(trace->data);
760 trace = trace->next;
761 }
762 return ID_TABLE_CONTINUE;
763}
764
765#define gc_mark_table(task) \
766 if (rb_global_tbl) { rb_id_table_foreach_values(rb_global_tbl, task##_global_entry, 0); }
767
768void
769rb_gc_mark_global_tbl(void)
770{
771 gc_mark_table(mark);
772}
773
774static enum rb_id_table_iterator_result
775update_global_entry(VALUE v, void *ignored)
776{
777 struct rb_global_entry *entry = (struct rb_global_entry *)v;
778 struct rb_global_variable *var = entry->var;
779
780 (*var->compactor)(var);
781 return ID_TABLE_CONTINUE;
782}
783
784void
785rb_gc_update_global_tbl(void)
786{
787 gc_mark_table(update);
788}
789
790static ID
791global_id(const char *name)
792{
793 ID id;
794
795 if (name[0] == '$') id = rb_intern(name);
796 else {
797 size_t len = strlen(name);
798 VALUE vbuf = 0;
799 char *buf = ALLOCV_N(char, vbuf, len+1);
800 buf[0] = '$';
801 memcpy(buf+1, name, len);
802 id = rb_intern2(buf, len+1);
803 ALLOCV_END(vbuf);
804 }
805 return id;
806}
807
808static ID
809find_global_id(const char *name)
810{
811 ID id;
812 size_t len = strlen(name);
813
814 if (name[0] == '$') {
815 id = rb_check_id_cstr(name, len, NULL);
816 }
817 else {
818 VALUE vbuf = 0;
819 char *buf = ALLOCV_N(char, vbuf, len+1);
820 buf[0] = '$';
821 memcpy(buf+1, name, len);
822 id = rb_check_id_cstr(buf, len+1, NULL);
823 ALLOCV_END(vbuf);
824 }
825
826 return id;
827}
828
829void
830 rb_define_hooked_variable(
831 const char *name,
832 VALUE *var,
833 rb_gvar_getter_t *getter,
834 rb_gvar_setter_t *setter)
835{
836 volatile VALUE tmp = var ? *var : Qnil;
837 ID id = global_id(name);
838 struct rb_global_variable *gvar = rb_global_entry(id)->var;
839
840 gvar->data = (void*)var;
841 gvar->getter = getter ? (rb_gvar_getter_t *)getter : rb_gvar_var_getter;
842 gvar->setter = setter ? (rb_gvar_setter_t *)setter : rb_gvar_var_setter;
843 gvar->marker = rb_gvar_var_marker;
844
845 RB_GC_GUARD(tmp);
846}
847
848void
849rb_define_variable(const char *name, VALUE *var)
850{
851 rb_define_hooked_variable(name, var, 0, 0);
852}
853
854void
855rb_define_readonly_variable(const char *name, const VALUE *var)
856{
857 rb_define_hooked_variable(name, (VALUE *)var, 0, rb_gvar_readonly_setter);
858}
859
860void
861 rb_define_virtual_variable(
862 const char *name,
863 rb_gvar_getter_t *getter,
864 rb_gvar_setter_t *setter)
865{
866 if (!getter) getter = rb_gvar_val_getter;
867 if (!setter) setter = rb_gvar_readonly_setter;
868 rb_define_hooked_variable(name, 0, getter, setter);
869}
870
871static void
872rb_trace_eval(VALUE cmd, VALUE val)
873{
874 rb_eval_cmd_call_kw(cmd, 1, &val, RB_NO_KEYWORDS);
875}
876
877 VALUE
878rb_f_trace_var(int argc, const VALUE *argv)
879{
880 VALUE var, cmd;
881 struct rb_global_entry *entry;
882 struct trace_var *trace;
883
884 if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
885 cmd = rb_block_proc();
886 }
887 if (NIL_P(cmd)) {
888 return rb_f_untrace_var(argc, argv);
889 }
890 entry = rb_global_entry(rb_to_id(var));
891 trace = ALLOC(struct trace_var);
892 trace->next = entry->var->trace;
893 trace->func = rb_trace_eval;
894 trace->data = cmd;
895 trace->removed = 0;
896 entry->var->trace = trace;
897
898 return Qnil;
899}
900
901static void
902remove_trace(struct rb_global_variable *var)
903{
904 struct trace_var *trace = var->trace;
905 struct trace_var t;
906 struct trace_var *next;
907
908 t.next = trace;
909 trace = &t;
910 while (trace->next) {
911 next = trace->next;
912 if (next->removed) {
913 trace->next = next->next;
914 xfree(next);
915 }
916 else {
917 trace = next;
918 }
919 }
920 var->trace = t.next;
921}
922
923 VALUE
924rb_f_untrace_var(int argc, const VALUE *argv)
925{
926 VALUE var, cmd;
927 ID id;
928 struct rb_global_entry *entry;
929 struct trace_var *trace;
930
931 rb_scan_args(argc, argv, "11", &var, &cmd);
932 id = rb_check_id(&var);
933 if (!id) {
934 rb_name_error_str(var, "undefined global variable %"PRIsVALUE"", QUOTE(var));
935 }
936 if ((entry = rb_find_global_entry(id)) == NULL) {
937 rb_name_error(id, "undefined global variable %"PRIsVALUE"", QUOTE_ID(id));
938 }
939
940 trace = entry->var->trace;
941 if (NIL_P(cmd)) {
942 VALUE ary = rb_ary_new();
943
944 while (trace) {
945 struct trace_var *next = trace->next;
946 rb_ary_push(ary, (VALUE)trace->data);
947 trace->removed = 1;
948 trace = next;
949 }
950
951 if (!entry->var->block_trace) remove_trace(entry->var);
952 return ary;
953 }
954 else {
955 while (trace) {
956 if (trace->data == cmd) {
957 trace->removed = 1;
958 if (!entry->var->block_trace) remove_trace(entry->var);
959 return rb_ary_new3(1, cmd);
960 }
961 trace = trace->next;
962 }
963 }
964 return Qnil;
965}
966
967 struct trace_data {
968 struct trace_var *trace;
969 VALUE val;
970};
971
972static VALUE
973trace_ev(VALUE v)
974{
975 struct trace_data *data = (void *)v;
976 struct trace_var *trace = data->trace;
977
978 while (trace) {
979 (*trace->func)(trace->data, data->val);
980 trace = trace->next;
981 }
982
983 return Qnil;
984}
985
986static VALUE
987trace_en(VALUE v)
988{
989 struct rb_global_variable *var = (void *)v;
990 var->block_trace = 0;
991 remove_trace(var);
992 return Qnil; /* not reached */
993}
994
995static VALUE
996rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val)
997{
998 struct trace_data trace;
999 struct rb_global_variable *var = entry->var;
1000
1001 (*var->setter)(val, entry->id, var->data);
1002
1003 if (var->trace && !var->block_trace) {
1004 var->block_trace = 1;
1005 trace.trace = var->trace;
1006 trace.val = val;
1007 rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
1008 }
1009 return val;
1010}
1011
1012static inline bool
1013gvar_use_box_tbl(const rb_box_t *box, const struct rb_global_entry *entry)
1014{
1015 return BOX_USER_P(box) &&
1016 !entry->var->box_dynamic &&
1017 (!entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter);
1018}
1019
1020 VALUE
1021rb_gvar_set(ID id, VALUE val)
1022{
1023 VALUE retval;
1024 struct rb_global_entry *entry;
1025 const rb_box_t *box = rb_current_box();
1026 bool use_box_tbl = false;
1027
1028 RB_VM_LOCKING() {
1029 entry = rb_global_entry(id);
1030
1031 if (gvar_use_box_tbl(box, entry)) {
1032 use_box_tbl = true;
1033 rb_hash_aset(box->gvar_tbl, rb_id2sym(entry->id), val);
1034 retval = val;
1035 // TODO: think about trace
1036 }
1037 }
1038
1039 if (!use_box_tbl) {
1040 retval = rb_gvar_set_entry(entry, val);
1041 }
1042 return retval;
1043}
1044
1045 VALUE
1046rb_gv_set(const char *name, VALUE val)
1047{
1048 return rb_gvar_set(global_id(name), val);
1049}
1050
1051 VALUE
1052rb_gvar_get(ID id)
1053{
1054 VALUE retval, gvars, key;
1055 const rb_box_t *box = rb_current_box();
1056 bool use_box_tbl = false;
1057 struct rb_global_entry *entry;
1058 struct rb_global_variable *var;
1059 // TODO: use lock-free rb_id_table when it's available for use (doesn't yet exist)
1060 RB_VM_LOCKING() {
1061 entry = rb_global_entry(id);
1062 var = entry->var;
1063
1064 if (gvar_use_box_tbl(box, entry)) {
1065 use_box_tbl = true;
1066 gvars = box->gvar_tbl;
1067 key = rb_id2sym(entry->id);
1068 if (RTEST(rb_hash_has_key(gvars, key))) { // this gvar is already cached
1069 retval = rb_hash_aref(gvars, key);
1070 }
1071 else {
1072 RB_VM_UNLOCK();
1073 {
1074 retval = (*var->getter)(entry->id, var->data);
1075 if (rb_obj_respond_to(retval, rb_intern("clone"), 1)) {
1076 retval = rb_funcall(retval, rb_intern("clone"), 0);
1077 }
1078 }
1079 RB_VM_LOCK();
1080 rb_hash_aset(gvars, key, retval);
1081 }
1082 }
1083 }
1084 if (!use_box_tbl) {
1085 retval = (*var->getter)(entry->id, var->data);
1086 }
1087 return retval;
1088}
1089
1090 VALUE
1091rb_gv_get(const char *name)
1092{
1093 ID id = find_global_id(name);
1094
1095 if (!id) {
1096 rb_warning("global variable '%s' not initialized", name);
1097 return Qnil;
1098 }
1099
1100 return rb_gvar_get(id);
1101}
1102
1103 VALUE
1104rb_gvar_defined(ID id)
1105{
1106 struct rb_global_entry *entry = rb_global_entry(id);
1107 return RBOOL(entry->var->getter != rb_gvar_undef_getter);
1108}
1109
1110 rb_gvar_getter_t *
1111rb_gvar_getter_function_of(ID id)
1112{
1113 const struct rb_global_entry *entry = rb_global_entry(id);
1114 return entry->var->getter;
1115}
1116
1117 rb_gvar_setter_t *
1118rb_gvar_setter_function_of(ID id)
1119{
1120 const struct rb_global_entry *entry = rb_global_entry(id);
1121 return entry->var->setter;
1122}
1123
1124static enum rb_id_table_iterator_result
1125gvar_i(ID key, VALUE val, void *a)
1126{
1127 VALUE ary = (VALUE)a;
1128 rb_ary_push(ary, ID2SYM(key));
1129 return ID_TABLE_CONTINUE;
1130}
1131
1132 VALUE
1133rb_f_global_variables(void)
1134{
1135 VALUE ary = rb_ary_new();
1136 VALUE sym, backref = rb_backref_get();
1137
1138 if (!rb_ractor_main_p()) {
1139 rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
1140 }
1141 /* gvar access (get/set) in boxes creates gvar entries globally */
1142
1143 rb_id_table_foreach(rb_global_tbl, gvar_i, (void *)ary);
1144 if (!NIL_P(backref)) {
1145 char buf[2];
1146 int i, nmatch = rb_match_count(backref);
1147 buf[0] = '$';
1148 for (i = 1; i <= nmatch; ++i) {
1149 if (!RTEST(rb_reg_nth_defined(i, backref))) continue;
1150 if (i < 10) {
1151 /* probably reused, make static ID */
1152 buf[1] = (char)(i + '0');
1153 sym = ID2SYM(rb_intern2(buf, 2));
1154 }
1155 else {
1156 /* dynamic symbol */
1157 sym = rb_str_intern(rb_sprintf("$%d", i));
1158 }
1159 rb_ary_push(ary, sym);
1160 }
1161 }
1162 return ary;
1163}
1164
1165void
1166rb_alias_variable(ID name1, ID name2)
1167{
1168 struct rb_global_entry *entry1 = NULL, *entry2;
1169 VALUE data1;
1170 struct rb_id_table *gtbl = rb_global_tbl;
1171
1172 if (!rb_ractor_main_p()) {
1173 rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
1174 }
1175
1176 RB_VM_LOCKING() {
1177 entry2 = rb_global_entry(name2);
1178 if (!rb_id_table_lookup(gtbl, name1, &data1)) {
1179 entry1 = ZALLOC(struct rb_global_entry);
1180 entry1->id = name1;
1181 rb_id_table_insert(gtbl, name1, (VALUE)entry1);
1182 }
1183 else if ((entry1 = (struct rb_global_entry *)data1)->var != entry2->var) {
1184 struct rb_global_variable *var = entry1->var;
1185 if (var->block_trace) {
1186 RB_VM_UNLOCK();
1187 rb_raise(rb_eRuntimeError, "can't alias in tracer");
1188 }
1189 var->counter--;
1190 if (var->counter == 0) {
1191 free_global_variable(var);
1192 }
1193 }
1194 if (entry1->var != entry2->var) {
1195 entry2->var->counter++;
1196 entry1->var = entry2->var;
1197 }
1198 }
1199}
1200
1201static void
1202IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
1203{
1204 if (UNLIKELY(!rb_ractor_main_p())) {
1205 if (rb_is_instance_id(id)) { // check only normal ivars
1206 rb_raise(rb_eRactorIsolationError, "can not set instance variables of classes/modules by non-main Ractors");
1207 }
1208 }
1209}
1210
1211static void
1212CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(VALUE klass, ID id)
1213{
1214 if (UNLIKELY(!rb_ractor_main_p())) {
1215 rb_raise(rb_eRactorIsolationError, "can not access class variables from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")", rb_id2str(id), klass);
1216 }
1217}
1218
1219static inline void
1220ivar_ractor_check(VALUE obj, ID id)
1221{
1222 if (LIKELY(rb_is_instance_id(id)) /* not internal ID */ &&
1223 !RB_OBJ_FROZEN_RAW(obj) &&
1224 UNLIKELY(!rb_ractor_main_p()) &&
1225 UNLIKELY(rb_ractor_shareable_p(obj))) {
1226
1227 rb_raise(rb_eRactorIsolationError, "can not access instance variables of shareable objects from non-main Ractors");
1228 }
1229}
1230
1231static inline struct st_table *
1232generic_fields_tbl_no_ractor_check(void)
1233{
1234 ASSERT_vm_locking();
1235
1236 return generic_fields_tbl_;
1237}
1238
1239struct st_table *
1240rb_generic_fields_tbl_get(void)
1241{
1242 return generic_fields_tbl_;
1243}
1244
1245void
1246rb_mark_generic_ivar(VALUE obj)
1247{
1248 VALUE data;
1249 // Bypass ASSERT_vm_locking() check because marking may happen concurrently with mmtk
1250 if (st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&data)) {
1251 rb_gc_mark_movable(data);
1252 }
1253}
1254
1255 VALUE
1256rb_obj_fields_generic_uncached(VALUE obj)
1257{
1258 VALUE fields_obj = 0;
1259 RB_VM_LOCKING() {
1260 if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) {
1261 rb_bug("Object is missing entry in generic_fields_tbl");
1262 }
1263 }
1264 return fields_obj;
1265}
1266
1267 VALUE
1268rb_obj_fields(VALUE obj, ID field_name)
1269{
1270 RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO));
1271 ivar_ractor_check(obj, field_name);
1272
1273 VALUE fields_obj = 0;
1274 if (rb_shape_obj_has_fields(obj)) {
1275 switch (BUILTIN_TYPE(obj)) {
1276 case T_DATA:
1277 if (LIKELY(RTYPEDDATA_P(obj))) {
1278 fields_obj = RTYPEDDATA(obj)->fields_obj;
1279 break;
1280 }
1281 goto generic_fields;
1282 case T_STRUCT:
1283 if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
1284 fields_obj = RSTRUCT_FIELDS_OBJ(obj);
1285 break;
1286 }
1287 goto generic_fields;
1288 default:
1289 generic_fields:
1290 {
1291 rb_execution_context_t *ec = GET_EC();
1292 if (ec->gen_fields_cache.obj == obj && !UNDEF_P(ec->gen_fields_cache.fields_obj) && rb_imemo_fields_owner(ec->gen_fields_cache.fields_obj) == obj) {
1293 fields_obj = ec->gen_fields_cache.fields_obj;
1294 RUBY_ASSERT(fields_obj == rb_obj_fields_generic_uncached(obj));
1295 }
1296 else {
1297 fields_obj = rb_obj_fields_generic_uncached(obj);
1298 ec->gen_fields_cache.fields_obj = fields_obj;
1299 ec->gen_fields_cache.obj = obj;
1300 }
1301 }
1302 }
1303 }
1304 return fields_obj;
1305}
1306
1307void
1308rb_free_generic_ivar(VALUE obj)
1309{
1310 if (rb_obj_gen_fields_p(obj)) {
1311 st_data_t key = (st_data_t)obj, value;
1312 switch (BUILTIN_TYPE(obj)) {
1313 case T_DATA:
1314 if (LIKELY(RTYPEDDATA_P(obj))) {
1315 RB_OBJ_WRITE(obj, &RTYPEDDATA(obj)->fields_obj, 0);
1316 break;
1317 }
1318 goto generic_fields;
1319 case T_STRUCT:
1320 if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
1321 RSTRUCT_SET_FIELDS_OBJ(obj, 0);
1322 break;
1323 }
1324 goto generic_fields;
1325 default:
1326 generic_fields:
1327 {
1328 // Other EC may have stale caches, so fields_obj should be
1329 // invalidated and the GC will replace with Qundef
1330 rb_execution_context_t *ec = GET_EC();
1331 if (ec->gen_fields_cache.obj == obj) {
1332 ec->gen_fields_cache.obj = Qundef;
1333 ec->gen_fields_cache.fields_obj = Qundef;
1334 }
1335 RB_VM_LOCKING() {
1336 if (!st_delete(generic_fields_tbl_no_ractor_check(), &key, &value)) {
1337 rb_bug("Object is missing entry in generic_fields_tbl");
1338 }
1339 }
1340 }
1341 }
1342 RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
1343 }
1344}
1345
1346static void
1347rb_obj_set_fields(VALUE obj, VALUE fields_obj, ID field_name, VALUE original_fields_obj)
1348{
1349 ivar_ractor_check(obj, field_name);
1350
1351 if (!fields_obj) {
1352 RUBY_ASSERT(original_fields_obj);
1353 rb_free_generic_ivar(obj);
1354 rb_imemo_fields_clear(original_fields_obj);
1355 return;
1356 }
1357
1358 RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
1359 RUBY_ASSERT(!original_fields_obj || IMEMO_TYPE_P(original_fields_obj, imemo_fields));
1360
1361 if (fields_obj != original_fields_obj) {
1362 switch (BUILTIN_TYPE(obj)) {
1363 case T_DATA:
1364 if (LIKELY(RTYPEDDATA_P(obj))) {
1365 RB_OBJ_WRITE(obj, &RTYPEDDATA(obj)->fields_obj, fields_obj);
1366 break;
1367 }
1368 goto generic_fields;
1369 case T_STRUCT:
1370 if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
1371 RSTRUCT_SET_FIELDS_OBJ(obj, fields_obj);
1372 break;
1373 }
1374 goto generic_fields;
1375 default:
1376 generic_fields:
1377 {
1378 RB_VM_LOCKING() {
1379 st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj);
1380 }
1381 RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj);
1382
1383 rb_execution_context_t *ec = GET_EC();
1384 if (ec->gen_fields_cache.fields_obj != fields_obj) {
1385 ec->gen_fields_cache.obj = obj;
1386 ec->gen_fields_cache.fields_obj = fields_obj;
1387 }
1388 }
1389 }
1390
1391 if (original_fields_obj) {
1392 // Clear root shape to avoid triggering cleanup such as free_object_id.
1393 rb_imemo_fields_clear(original_fields_obj);
1394 }
1395 }
1396
1397 RBASIC_SET_SHAPE_ID(obj, RBASIC_SHAPE_ID(fields_obj));
1398}
1399
1400void
1401rb_obj_replace_fields(VALUE obj, VALUE fields_obj)
1402{
1403 RB_VM_LOCKING() {
1404 VALUE original_fields_obj = rb_obj_fields_no_ractor_check(obj);
1405 rb_obj_set_fields(obj, fields_obj, 0, original_fields_obj);
1406 }
1407}
1408
1409 VALUE
1410rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
1411{
1412 RUBY_ASSERT(!SPECIAL_CONST_P(obj));
1413 RUBY_ASSERT(RSHAPE_TYPE_P(target_shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(target_shape_id, SHAPE_OBJ_ID));
1414
1415 VALUE fields_obj;
1416
1417 switch (BUILTIN_TYPE(obj)) {
1418 case T_CLASS:
1419 case T_MODULE:
1420 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1421 break;
1422 case T_OBJECT:
1423 fields_obj = obj;
1424 break;
1425 case T_IMEMO:
1426 RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
1427 fields_obj = obj;
1428 break;
1429 default:
1430 fields_obj = rb_obj_fields(obj, RSHAPE_EDGE_NAME(target_shape_id));
1431 break;
1432 }
1433
1434 if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) {
1435 st_table *fields_hash = rb_imemo_fields_complex_tbl(fields_obj);
1436 VALUE value = Qundef;
1437 st_lookup(fields_hash, RSHAPE_EDGE_NAME(target_shape_id), &value);
1438 RUBY_ASSERT(!UNDEF_P(value));
1439 return value;
1440 }
1441
1442 attr_index_t index = RSHAPE_INDEX(target_shape_id);
1443 return rb_imemo_fields_ptr(fields_obj)[index];
1444}
1445
1446 VALUE
1447rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
1448{
1449 if (SPECIAL_CONST_P(obj)) return undef;
1450
1451 VALUE fields_obj;
1452
1453 switch (BUILTIN_TYPE(obj)) {
1454 case T_CLASS:
1455 case T_MODULE:
1456 {
1457 VALUE val = rb_ivar_lookup(RCLASS_WRITABLE_FIELDS_OBJ(obj), id, undef);
1458 if (val != undef &&
1459 rb_is_instance_id(id) &&
1460 UNLIKELY(!rb_ractor_main_p()) &&
1461 !rb_ractor_shareable_p(val)) {
1462 rb_raise(rb_eRactorIsolationError,
1463 "can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")",
1464 rb_id2str(id), obj);
1465 }
1466 return val;
1467 }
1468 case T_IMEMO:
1469 // Handled like T_OBJECT
1470 RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
1471 fields_obj = obj;
1472 break;
1473 case T_OBJECT:
1474 fields_obj = obj;
1475 break;
1476 default:
1477 fields_obj = rb_obj_fields(obj, id);
1478 break;
1479 }
1480
1481 if (!fields_obj) {
1482 return undef;
1483 }
1484
1485 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
1486
1487 if (UNLIKELY(rb_shape_too_complex_p(shape_id))) {
1488 st_table *iv_table = rb_imemo_fields_complex_tbl(fields_obj);
1489 VALUE val;
1490 if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
1491 return val;
1492 }
1493 return undef;
1494 }
1495
1496 attr_index_t index = 0;
1497 if (rb_shape_get_iv_index(shape_id, id, &index)) {
1498 return rb_imemo_fields_ptr(fields_obj)[index];
1499 }
1500
1501 return undef;
1502}
1503
1504 VALUE
1505rb_ivar_get(VALUE obj, ID id)
1506{
1507 VALUE iv = rb_ivar_lookup(obj, id, Qnil);
1508 RB_DEBUG_COUNTER_INC(ivar_get_base);
1509 return iv;
1510}
1511
1512 VALUE
1513rb_ivar_get_at(VALUE obj, attr_index_t index, ID id)
1514{
1515 RUBY_ASSERT(rb_is_instance_id(id));
1516 // Used by JITs, but never for T_OBJECT.
1517
1518 switch (BUILTIN_TYPE(obj)) {
1519 case T_OBJECT:
1520 UNREACHABLE_RETURN(Qundef);
1521 case T_CLASS:
1522 case T_MODULE:
1523 {
1524 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1525 VALUE val = rb_imemo_fields_ptr(fields_obj)[index];
1526
1527 if (UNLIKELY(!rb_ractor_main_p()) && !rb_ractor_shareable_p(val)) {
1528 rb_raise(rb_eRactorIsolationError,
1529 "can not get unshareable values from instance variables of classes/modules from non-main Ractors");
1530 }
1531
1532 return val;
1533 }
1534 default:
1535 {
1536 VALUE fields_obj = rb_obj_fields(obj, id);
1537 return rb_imemo_fields_ptr(fields_obj)[index];
1538 }
1539 }
1540}
1541
1542 VALUE
1543rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index)
1544{
1545 // Used by JITs, but never for T_OBJECT.
1546
1547 VALUE fields_obj;
1548 switch (BUILTIN_TYPE(obj)) {
1549 case T_OBJECT:
1550 UNREACHABLE_RETURN(Qundef);
1551 case T_CLASS:
1552 case T_MODULE:
1553 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1554 break;
1555 default:
1556 fields_obj = rb_obj_fields_no_ractor_check(obj);
1557 break;
1558 }
1559 return rb_imemo_fields_ptr(fields_obj)[index];
1560}
1561
1562 VALUE
1563rb_attr_get(VALUE obj, ID id)
1564{
1565 return rb_ivar_lookup(obj, id, Qnil);
1566}
1567
1568void rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table);
1569static VALUE imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id);
1570
1571static shape_id_t
1572obj_transition_too_complex(VALUE obj, st_table *table)
1573{
1574 RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
1575 shape_id_t shape_id = rb_shape_transition_complex(obj);
1576
1577 switch (BUILTIN_TYPE(obj)) {
1578 case T_OBJECT:
1579 {
1580 VALUE *old_fields = NULL;
1581 if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
1582 old_fields = ROBJECT_FIELDS(obj);
1583 }
1584 else {
1585 FL_SET_RAW(obj, ROBJECT_HEAP);
1586 }
1587 RBASIC_SET_SHAPE_ID(obj, shape_id);
1588 ROBJECT_SET_FIELDS_HASH(obj, table);
1589 if (old_fields) {
1590 xfree(old_fields);
1591 }
1592 }
1593 break;
1594 case T_CLASS:
1595 case T_MODULE:
1596 case T_IMEMO:
1597 UNREACHABLE;
1598 break;
1599 default:
1600 {
1601 VALUE fields_obj = rb_imemo_fields_new_complex_tbl(obj, table, RB_OBJ_SHAREABLE_P(obj));
1602 RBASIC_SET_SHAPE_ID(fields_obj, shape_id);
1603 rb_obj_replace_fields(obj, fields_obj);
1604 }
1605 }
1606
1607 return shape_id;
1608}
1609
1610// Copy all object fields, including ivars and internal object_id, etc
1611static shape_id_t
1612rb_evict_fields_to_hash(VALUE obj)
1613{
1614 RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
1615
1616 st_table *table = st_init_numtable_with_size(RSHAPE_LEN(RBASIC_SHAPE_ID(obj)));
1617 rb_obj_copy_fields_to_hash_table(obj, table);
1618 shape_id_t new_shape_id = obj_transition_too_complex(obj, table);
1619
1620 RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
1621 return new_shape_id;
1622}
1623
1624void
1625rb_evict_ivars_to_hash(VALUE obj)
1626{
1627 RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
1628
1629 st_table *table = st_init_numtable_with_size(rb_ivar_count(obj));
1630
1631 // Evacuate all previous values from shape into id_table
1632 rb_obj_copy_ivs_to_hash_table(obj, table);
1633 obj_transition_too_complex(obj, table);
1634
1635 RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
1636}
1637
1638static VALUE
1639rb_ivar_delete(VALUE obj, ID id, VALUE undef)
1640{
1641 rb_check_frozen(obj);
1642
1643 VALUE val = undef;
1644 VALUE fields_obj;
1645 bool concurrent = false;
1646 int type = BUILTIN_TYPE(obj);
1647
1648 switch(type) {
1649 case T_CLASS:
1650 case T_MODULE:
1651 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1652
1653 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1654 if (rb_multi_ractor_p()) {
1655 concurrent = true;
1656 }
1657 break;
1658 case T_OBJECT:
1659 fields_obj = obj;
1660 break;
1661 default: {
1662 fields_obj = rb_obj_fields(obj, id);
1663 break;
1664 }
1665 }
1666
1667 if (!fields_obj) {
1668 return undef;
1669 }
1670
1671 const VALUE original_fields_obj = fields_obj;
1672 if (concurrent) {
1673 fields_obj = rb_imemo_fields_clone(fields_obj);
1674 }
1675
1676 shape_id_t old_shape_id = RBASIC_SHAPE_ID(fields_obj);
1677 shape_id_t removed_shape_id;
1678 shape_id_t next_shape_id = rb_shape_transition_remove_ivar(fields_obj, id, &removed_shape_id);
1679
1680 if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
1681 if (UNLIKELY(!rb_shape_too_complex_p(old_shape_id))) {
1682 if (type == T_OBJECT) {
1683 rb_evict_fields_to_hash(obj);
1684 }
1685 else {
1686 fields_obj = imemo_fields_complex_from_obj(obj, fields_obj, next_shape_id);
1687 }
1688 }
1689 st_data_t key = id;
1690 if (!st_delete(rb_imemo_fields_complex_tbl(fields_obj), &key, (st_data_t *)&val)) {
1691 val = undef;
1692 }
1693 }
1694 else {
1695 if (next_shape_id == old_shape_id) {
1696 return undef;
1697 }
1698
1699 RUBY_ASSERT(removed_shape_id != INVALID_SHAPE_ID);
1700 RUBY_ASSERT(RSHAPE_LEN(next_shape_id) == RSHAPE_LEN(old_shape_id) - 1);
1701
1702 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
1703 attr_index_t removed_index = RSHAPE_INDEX(removed_shape_id);
1704 val = fields[removed_index];
1705
1706 attr_index_t new_fields_count = RSHAPE_LEN(next_shape_id);
1707 if (new_fields_count) {
1708 size_t trailing_fields = new_fields_count - removed_index;
1709
1710 MEMMOVE(&fields[removed_index], &fields[removed_index + 1], VALUE, trailing_fields);
1711 RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
1712
1713 if (FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP) && rb_obj_embedded_size(new_fields_count) <= rb_gc_obj_slot_size(fields_obj)) {
1714 // Re-embed objects when instances become small enough
1715 // This is necessary because YJIT assumes that objects with the same shape
1716 // have the same embeddedness for efficiency (avoid extra checks)
1717 FL_UNSET_RAW(fields_obj, ROBJECT_HEAP);
1718 MEMCPY(rb_imemo_fields_ptr(fields_obj), fields, VALUE, new_fields_count);
1719 xfree(fields);
1720 }
1721 }
1722 else {
1723 fields_obj = 0;
1724 rb_free_generic_ivar(obj);
1725 }
1726 }
1727
1728 RBASIC_SET_SHAPE_ID(obj, next_shape_id);
1729 if (fields_obj != original_fields_obj) {
1730 switch (type) {
1731 case T_OBJECT:
1732 break;
1733 case T_CLASS:
1734 case T_MODULE:
1735 RCLASS_WRITABLE_SET_FIELDS_OBJ(obj, fields_obj);
1736 break;
1737 default:
1738 rb_obj_set_fields(obj, fields_obj, id, original_fields_obj);
1739 break;
1740 }
1741 }
1742
1743 return val;
1744}
1745
1746 VALUE
1747rb_attr_delete(VALUE obj, ID id)
1748{
1749 return rb_ivar_delete(obj, id, Qnil);
1750}
1751
1752void
1753rb_obj_init_too_complex(VALUE obj, st_table *table)
1754{
1755 // This method is meant to be called on newly allocated object.
1756 RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
1757 RUBY_ASSERT(rb_shape_canonical_p(RBASIC_SHAPE_ID(obj)));
1758 RUBY_ASSERT(RSHAPE_LEN(RBASIC_SHAPE_ID(obj)) == 0);
1759
1760 obj_transition_too_complex(obj, table);
1761}
1762
1763static int
1764imemo_fields_complex_from_obj_i(ID key, VALUE val, st_data_t arg)
1765{
1766 VALUE fields = (VALUE)arg;
1767 st_table *table = rb_imemo_fields_complex_tbl(fields);
1768
1769 RUBY_ASSERT(!st_lookup(table, (st_data_t)key, NULL));
1770 st_add_direct(table, (st_data_t)key, (st_data_t)val);
1771 RB_OBJ_WRITTEN(fields, Qundef, val);
1772
1773 return ST_CONTINUE;
1774}
1775
1776static VALUE
1777imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id)
1778{
1779 attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0;
1780 VALUE fields_obj = rb_imemo_fields_new_complex(owner, len + 1, RB_OBJ_SHAREABLE_P(owner));
1781
1782 rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false);
1783 RBASIC_SET_SHAPE_ID(fields_obj, shape_id);
1784
1785 return fields_obj;
1786}
1787
1788static VALUE
1789imemo_fields_copy_capa(VALUE owner, VALUE source_fields_obj, attr_index_t new_size)
1790{
1791 VALUE fields_obj = rb_imemo_fields_new(owner, new_size, RB_OBJ_SHAREABLE_P(owner));
1792 if (source_fields_obj) {
1793 attr_index_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj));
1794 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
1795 MEMCPY(fields, rb_imemo_fields_ptr(source_fields_obj), VALUE, fields_count);
1796 RBASIC_SET_SHAPE_ID(fields_obj, RBASIC_SHAPE_ID(source_fields_obj));
1797 for (attr_index_t i = 0; i < fields_count; i++) {
1798 RB_OBJ_WRITTEN(fields_obj, Qundef, fields[i]);
1799 }
1800 }
1801 return fields_obj;
1802}
1803
1804static VALUE
1805imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
1806{
1807 const VALUE original_fields_obj = fields_obj;
1808 shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID(fields_obj) : ROOT_SHAPE_ID;
1809
1810 if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) {
1811 if (rb_shape_too_complex_p(current_shape_id)) {
1812 if (concurrent) {
1813 // In multi-ractor case, we must always work on a copy because
1814 // even if the field already exist, inserting in a st_table may
1815 // cause a rebuild.
1816 fields_obj = rb_imemo_fields_clone(fields_obj);
1817 }
1818 }
1819 else {
1820 fields_obj = imemo_fields_complex_from_obj(owner, original_fields_obj, target_shape_id);
1821 current_shape_id = target_shape_id;
1822 }
1823
1824 st_table *table = rb_imemo_fields_complex_tbl(fields_obj);
1825
1826 RUBY_ASSERT(field_name);
1827 st_insert(table, (st_data_t)field_name, (st_data_t)val);
1828 RB_OBJ_WRITTEN(fields_obj, Qundef, val);
1829 RBASIC_SET_SHAPE_ID(fields_obj, target_shape_id);
1830 }
1831 else {
1832 attr_index_t index = RSHAPE_INDEX(target_shape_id);
1833 if (concurrent || index >= RSHAPE_CAPACITY(current_shape_id)) {
1834 fields_obj = imemo_fields_copy_capa(owner, original_fields_obj, RSHAPE_CAPACITY(target_shape_id));
1835 }
1836
1837 VALUE *table = rb_imemo_fields_ptr(fields_obj);
1838 RB_OBJ_WRITE(fields_obj, &table[index], val);
1839
1840 if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) {
1841 RBASIC_SET_SHAPE_ID(fields_obj, target_shape_id);
1842 }
1843 }
1844
1845 return fields_obj;
1846}
1847
1848static attr_index_t
1849generic_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
1850{
1851 if (!field_name) {
1852 field_name = RSHAPE_EDGE_NAME(target_shape_id);
1853 RUBY_ASSERT(field_name);
1854 }
1855
1856 const VALUE original_fields_obj = rb_obj_fields(obj, field_name);
1857 VALUE fields_obj = imemo_fields_set(obj, original_fields_obj, target_shape_id, field_name, val, false);
1858
1859 rb_obj_set_fields(obj, fields_obj, field_name, original_fields_obj);
1860 return rb_shape_too_complex_p(target_shape_id) ? ATTR_INDEX_NOT_SET : RSHAPE_INDEX(target_shape_id);
1861}
1862
1863static shape_id_t
1864generic_shape_ivar(VALUE obj, ID id, bool *new_ivar_out)
1865{
1866 bool new_ivar = false;
1867 shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
1868 shape_id_t target_shape_id = current_shape_id;
1869
1870 if (!rb_shape_too_complex_p(current_shape_id)) {
1871 if (!rb_shape_find_ivar(current_shape_id, id, &target_shape_id)) {
1872 if (RSHAPE_LEN(current_shape_id) >= SHAPE_MAX_FIELDS) {
1873 rb_raise(rb_eArgError, "too many instance variables");
1874 }
1875
1876 new_ivar = true;
1877 target_shape_id = rb_shape_transition_add_ivar(obj, id);
1878 }
1879 }
1880
1881 *new_ivar_out = new_ivar;
1882 return target_shape_id;
1883}
1884
1885static attr_index_t
1886generic_ivar_set(VALUE obj, ID id, VALUE val)
1887{
1888 bool dontcare;
1889 shape_id_t target_shape_id = generic_shape_ivar(obj, id, &dontcare);
1890 return generic_field_set(obj, target_shape_id, id, val);
1891}
1892
1893void
1894rb_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t new_capacity)
1895{
1896 RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
1897
1898 if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
1899 REALLOC_N(ROBJECT(obj)->as.heap.fields, VALUE, new_capacity);
1900 }
1901 else {
1902 VALUE *ptr = ROBJECT_FIELDS(obj);
1903 VALUE *newptr = ALLOC_N(VALUE, new_capacity);
1904 MEMCPY(newptr, ptr, VALUE, current_len);
1905 FL_SET_RAW(obj, ROBJECT_HEAP);
1906 ROBJECT(obj)->as.heap.fields = newptr;
1907 }
1908}
1909
1910static int
1911rb_obj_copy_ivs_to_hash_table_i(ID key, VALUE val, st_data_t arg)
1912{
1913 RUBY_ASSERT(!st_lookup((st_table *)arg, (st_data_t)key, NULL));
1914
1915 st_add_direct((st_table *)arg, (st_data_t)key, (st_data_t)val);
1916 return ST_CONTINUE;
1917}
1918
1919void
1920rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table)
1921{
1922 rb_ivar_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table);
1923}
1924
1925void
1926rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table)
1927{
1928 rb_field_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table, false);
1929}
1930
1931static attr_index_t
1932obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
1933{
1934 shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
1935
1936 if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) {
1937 if (UNLIKELY(!rb_shape_too_complex_p(current_shape_id))) {
1938 current_shape_id = rb_evict_fields_to_hash(obj);
1939 }
1940
1941 if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) {
1942 RBASIC_SET_SHAPE_ID(obj, target_shape_id);
1943 }
1944
1945 if (!field_name) {
1946 field_name = RSHAPE_EDGE_NAME(target_shape_id);
1947 RUBY_ASSERT(field_name);
1948 }
1949
1950 st_insert(ROBJECT_FIELDS_HASH(obj), (st_data_t)field_name, (st_data_t)val);
1951 RB_OBJ_WRITTEN(obj, Qundef, val);
1952
1953 return ATTR_INDEX_NOT_SET;
1954 }
1955 else {
1956 attr_index_t index = RSHAPE_INDEX(target_shape_id);
1957
1958 if (index >= RSHAPE_LEN(current_shape_id)) {
1959 if (UNLIKELY(index >= RSHAPE_CAPACITY(current_shape_id))) {
1960 rb_ensure_iv_list_size(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(target_shape_id));
1961 }
1962 RBASIC_SET_SHAPE_ID(obj, target_shape_id);
1963 }
1964
1965 RB_OBJ_WRITE(obj, &ROBJECT_FIELDS(obj)[index], val);
1966
1967 return index;
1968 }
1969}
1970
1971static attr_index_t
1972obj_ivar_set(VALUE obj, ID id, VALUE val)
1973{
1974 bool dontcare;
1975 shape_id_t target_shape_id = generic_shape_ivar(obj, id, &dontcare);
1976 return obj_field_set(obj, target_shape_id, id, val);
1977}
1978
1979/* Set the instance variable +val+ on object +obj+ at ivar name +id+.
1980 * This function only works with T_OBJECT objects, so make sure
1981 * +obj+ is of type T_OBJECT before using this function.
1982 */
1983 VALUE
1984rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val)
1985{
1986 rb_check_frozen(obj);
1987 obj_ivar_set(obj, id, val);
1988 return val;
1989}
1990
1991 void rb_obj_freeze_inline(VALUE x)
1992{
1993 if (RB_FL_ABLE(x)) {
1994 RB_FL_SET_RAW(x, RUBY_FL_FREEZE);
1995 if (TYPE(x) == T_STRING) {
1996 RB_FL_UNSET_RAW(x, FL_USER2 | FL_USER3); // STR_CHILLED
1997 }
1998
1999 RB_SET_SHAPE_ID(x, rb_shape_transition_frozen(x));
2000
2001 if (RBASIC_CLASS(x)) {
2002 rb_freeze_singleton_class(x);
2003 }
2004 }
2005}
2006
2007static attr_index_t class_ivar_set(VALUE obj, ID id, VALUE val, bool *new_ivar);
2008
2009static attr_index_t
2010ivar_set(VALUE obj, ID id, VALUE val)
2011{
2012 RB_DEBUG_COUNTER_INC(ivar_set_base);
2013
2014 switch (BUILTIN_TYPE(obj)) {
2015 case T_OBJECT:
2016 return obj_ivar_set(obj, id, val);
2017 case T_CLASS:
2018 case T_MODULE:
2019 {
2020 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
2021 bool dontcare;
2022 return class_ivar_set(obj, id, val, &dontcare);
2023 }
2024 default:
2025 return generic_ivar_set(obj, id, val);
2026 }
2027}
2028
2029 VALUE
2030rb_ivar_set(VALUE obj, ID id, VALUE val)
2031{
2032 rb_check_frozen(obj);
2033 ivar_set(obj, id, val);
2034 return val;
2035}
2036
2037attr_index_t
2038rb_ivar_set_index(VALUE obj, ID id, VALUE val)
2039{
2040 return ivar_set(obj, id, val);
2041}
2042
2043void
2044rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
2045{
2046 // should be internal instance variable name (no @ prefix)
2047 VM_ASSERT(!rb_is_instance_id(id));
2048
2049 ivar_set(obj, id, val);
2050}
2051
2052attr_index_t
2053rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
2054{
2055 switch (BUILTIN_TYPE(obj)) {
2056 case T_OBJECT:
2057 return obj_field_set(obj, target_shape_id, field_name, val);
2058 case T_CLASS:
2059 case T_MODULE:
2060 // The only field is object_id and T_CLASS handle it differently.
2061 rb_bug("Unreachable");
2062 break;
2063 default:
2064 return generic_field_set(obj, target_shape_id, field_name, val);
2065 }
2066}
2067
2068static VALUE
2069ivar_defined0(VALUE obj, ID id)
2070{
2071 attr_index_t index;
2072
2073 if (rb_shape_obj_too_complex_p(obj)) {
2074 VALUE idx;
2075 st_table *table = NULL;
2076 switch (BUILTIN_TYPE(obj)) {
2077 case T_CLASS:
2078 case T_MODULE:
2079 rb_bug("Unreachable");
2080 break;
2081
2082 case T_IMEMO:
2083 RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
2084 table = rb_imemo_fields_complex_tbl(obj);
2085 break;
2086
2087 case T_OBJECT:
2088 table = ROBJECT_FIELDS_HASH(obj);
2089 break;
2090
2091 default: {
2092 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj); // defined? doesn't require ractor checks
2093 table = rb_imemo_fields_complex_tbl(fields_obj);
2094 }
2095 }
2096
2097 if (!table || !rb_st_lookup(table, id, &idx)) {
2098 return Qfalse;
2099 }
2100
2101 return Qtrue;
2102 }
2103 else {
2104 return RBOOL(rb_shape_get_iv_index(RBASIC_SHAPE_ID(obj), id, &index));
2105 }
2106}
2107
2108 VALUE
2109rb_ivar_defined(VALUE obj, ID id)
2110{
2111 if (SPECIAL_CONST_P(obj)) return Qfalse;
2112
2113 VALUE defined = Qfalse;
2114 switch (BUILTIN_TYPE(obj)) {
2115 case T_CLASS:
2116 case T_MODULE:
2117 {
2118 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
2119 if (fields_obj) {
2120 defined = ivar_defined0(fields_obj, id);
2121 }
2122 }
2123 break;
2124 default:
2125 defined = ivar_defined0(obj, id);
2126 break;
2127 }
2128 return defined;
2129}
2130
2131 struct iv_itr_data {
2132 VALUE obj;
2133 struct gen_fields_tbl *fields_tbl;
2134 st_data_t arg;
2135 rb_ivar_foreach_callback_func *func;
2136 VALUE *fields;
2137 shape_id_t shape_id;
2138 bool ivar_only;
2139};
2140
2141static int
2142iterate_over_shapes_callback(shape_id_t shape_id, void *data)
2143{
2144 struct iv_itr_data *itr_data = data;
2145
2146 if (itr_data->ivar_only && !RSHAPE_TYPE_P(shape_id, SHAPE_IVAR)) {
2147 return ST_CONTINUE;
2148 }
2149
2150 VALUE *fields;
2151 switch (BUILTIN_TYPE(itr_data->obj)) {
2152 case T_OBJECT:
2153 RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2154 fields = ROBJECT_FIELDS(itr_data->obj);
2155 break;
2156 case T_IMEMO:
2157 RUBY_ASSERT(IMEMO_TYPE_P(itr_data->obj, imemo_fields));
2158 RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2159
2160 fields = rb_imemo_fields_ptr(itr_data->obj);
2161 break;
2162 default:
2163 rb_bug("Unreachable");
2164 }
2165
2166 RUBY_ASSERT(itr_data->shape_id == RBASIC_SHAPE_ID(itr_data->obj));
2167
2168 VALUE val = fields[RSHAPE_INDEX(shape_id)];
2169 int ret = itr_data->func(RSHAPE_EDGE_NAME(shape_id), val, itr_data->arg);
2170
2171 RUBY_ASSERT(itr_data->shape_id == RBASIC_SHAPE_ID(itr_data->obj));
2172
2173 return ret;
2174}
2175
2176/*
2177 * Returns a flag to stop iterating depending on the result of +callback+.
2178 */
2179static void
2180iterate_over_shapes(shape_id_t shape_id, rb_ivar_foreach_callback_func *callback, struct iv_itr_data *itr_data)
2181{
2182 rb_shape_foreach_field(shape_id, iterate_over_shapes_callback, itr_data);
2183}
2184
2185static int
2186each_hash_iv(st_data_t id, st_data_t val, st_data_t data)
2187{
2188 struct iv_itr_data * itr_data = (struct iv_itr_data *)data;
2189 rb_ivar_foreach_callback_func *callback = itr_data->func;
2190 if (is_internal_id((ID)id)) {
2191 return ST_CONTINUE;
2192 }
2193 return callback((ID)id, (VALUE)val, itr_data->arg);
2194}
2195
2196static void
2197obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
2198{
2199 struct iv_itr_data itr_data = {
2200 .obj = obj,
2201 .arg = arg,
2202 .func = func,
2203 .ivar_only = ivar_only,
2204 };
2205
2206 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
2207 if (rb_shape_too_complex_p(shape_id)) {
2208 st_foreach_safe(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
2209 }
2210 else {
2211 itr_data.fields = ROBJECT_FIELDS(obj);
2212 itr_data.shape_id = shape_id;
2213 iterate_over_shapes(shape_id, func, &itr_data);
2214 }
2215}
2216
2217static void
2218imemo_fields_each(VALUE fields_obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
2219{
2220 IMEMO_TYPE_P(fields_obj, imemo_fields);
2221
2222 struct iv_itr_data itr_data = {
2223 .obj = fields_obj,
2224 .arg = arg,
2225 .func = func,
2226 .ivar_only = ivar_only,
2227 };
2228
2229 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
2230 if (rb_shape_too_complex_p(shape_id)) {
2231 rb_st_foreach(rb_imemo_fields_complex_tbl(fields_obj), each_hash_iv, (st_data_t)&itr_data);
2232 }
2233 else {
2234 itr_data.fields = rb_imemo_fields_ptr(fields_obj);
2235 itr_data.shape_id = shape_id;
2236 iterate_over_shapes(shape_id, func, &itr_data);
2237 }
2238}
2239
2240void
2241rb_copy_generic_ivar(VALUE dest, VALUE obj)
2242{
2243 VALUE new_fields_obj;
2244
2245 rb_check_frozen(dest);
2246
2247 if (!rb_obj_gen_fields_p(obj)) {
2248 return;
2249 }
2250
2251 shape_id_t src_shape_id = rb_obj_shape_id(obj);
2252
2253 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2254 if (fields_obj) {
2255 unsigned long src_num_ivs = rb_ivar_count(fields_obj);
2256 if (!src_num_ivs) {
2257 goto clear;
2258 }
2259
2260 if (rb_shape_too_complex_p(src_shape_id)) {
2261 rb_shape_copy_complex_ivars(dest, obj, src_shape_id, rb_imemo_fields_complex_tbl(fields_obj));
2262 return;
2263 }
2264
2265 shape_id_t dest_shape_id = src_shape_id;
2266 shape_id_t initial_shape_id = rb_obj_shape_id(dest);
2267
2268 if (!rb_shape_canonical_p(src_shape_id)) {
2269 RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
2270
2271 dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
2272 if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) {
2273 st_table *table = rb_st_init_numtable_with_size(src_num_ivs);
2274 rb_obj_copy_ivs_to_hash_table(obj, table);
2275 rb_obj_init_too_complex(dest, table);
2276 return;
2277 }
2278 }
2279
2280 if (!RSHAPE_LEN(dest_shape_id)) {
2281 RBASIC_SET_SHAPE_ID(dest, dest_shape_id);
2282 return;
2283 }
2284
2285 new_fields_obj = rb_imemo_fields_new(dest, RSHAPE_CAPACITY(dest_shape_id), RB_OBJ_SHAREABLE_P(dest));
2286 VALUE *src_buf = rb_imemo_fields_ptr(fields_obj);
2287 VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj);
2288 rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id);
2289 RBASIC_SET_SHAPE_ID(new_fields_obj, dest_shape_id);
2290
2291 rb_obj_replace_fields(dest, new_fields_obj);
2292 }
2293 return;
2294
2295 clear:
2296 rb_free_generic_ivar(dest);
2297}
2298
2299void
2300rb_replace_generic_ivar(VALUE clone, VALUE obj)
2301{
2302 RB_VM_LOCKING() {
2303 st_data_t fields_tbl, obj_data = (st_data_t)obj;
2304 if (st_delete(generic_fields_tbl_, &obj_data, &fields_tbl)) {
2305 st_insert(generic_fields_tbl_, (st_data_t)clone, fields_tbl);
2306 RB_OBJ_WRITTEN(clone, Qundef, fields_tbl);
2307 }
2308 else {
2309 rb_bug("unreachable");
2310 }
2311 }
2312}
2313
2314void
2315rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
2316{
2317 if (SPECIAL_CONST_P(obj)) return;
2318 switch (BUILTIN_TYPE(obj)) {
2319 case T_IMEMO:
2320 if (IMEMO_TYPE_P(obj, imemo_fields)) {
2321 imemo_fields_each(obj, func, arg, ivar_only);
2322 }
2323 break;
2324 case T_OBJECT:
2325 obj_fields_each(obj, func, arg, ivar_only);
2326 break;
2327 case T_CLASS:
2328 case T_MODULE:
2329 {
2330 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
2331 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
2332 if (fields_obj) {
2333 imemo_fields_each(fields_obj, func, arg, ivar_only);
2334 }
2335 }
2336 break;
2337 default:
2338 {
2339 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2340 if (fields_obj) {
2341 imemo_fields_each(fields_obj, func, arg, ivar_only);
2342 }
2343 }
2344 break;
2345 }
2346}
2347
2348 struct ivar_buf_entry {
2349 ID name;
2350 VALUE val;
2351};
2352
2353static int
2354collect_ivar_i(ID id, VALUE val, st_data_t arg)
2355{
2356 struct ivar_buf_entry **pos = (struct ivar_buf_entry **)arg;
2357 (*pos)->name = id;
2358 (*pos)->val = val;
2359 (*pos)++;
2360 return ST_CONTINUE;
2361}
2362
2363void
2364 rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
2365{
2366 rb_field_foreach(obj, func, arg, true);
2367}
2368
2369void
2370rb_ivar_foreach_buffered(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
2371{
2372 st_index_t count = rb_ivar_count(obj);
2373 if (count == 0) return;
2374
2375 VALUE tmpbuf;
2376 struct ivar_buf_entry *buf = ALLOCV_N(struct ivar_buf_entry, tmpbuf, count);
2377 struct ivar_buf_entry *pos = buf;
2378
2379 rb_field_foreach(obj, collect_ivar_i, (st_data_t)&pos, true);
2380 RUBY_ASSERT((st_index_t)(pos - buf) == count);
2381
2382 for (st_index_t i = 0; i < count; i++) {
2383 if (func(buf[i].name, buf[i].val, arg) == ST_STOP) break;
2384 }
2385
2386 ALLOCV_END(tmpbuf);
2387}
2388
2389st_index_t
2390rb_ivar_count(VALUE obj)
2391{
2392 if (SPECIAL_CONST_P(obj)) return 0;
2393
2394 st_index_t iv_count = 0;
2395 switch (BUILTIN_TYPE(obj)) {
2396 case T_OBJECT:
2397 iv_count = ROBJECT_FIELDS_COUNT(obj);
2398 break;
2399
2400 case T_CLASS:
2401 case T_MODULE:
2402 {
2403 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
2404 if (!fields_obj) {
2405 return 0;
2406 }
2407 if (rb_shape_obj_too_complex_p(fields_obj)) {
2408 iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
2409 }
2410 else {
2411 iv_count = RBASIC_FIELDS_COUNT(fields_obj);
2412 }
2413 }
2414 break;
2415
2416 case T_IMEMO:
2417 RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
2418
2419 if (rb_shape_obj_too_complex_p(obj)) {
2420 iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(obj));
2421 }
2422 else {
2423 iv_count = RBASIC_FIELDS_COUNT(obj);
2424 }
2425 break;
2426
2427 default:
2428 {
2429 VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
2430 if (fields_obj) {
2431 if (rb_shape_obj_too_complex_p(fields_obj)) {
2432 iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
2433 }
2434 else {
2435 iv_count = RBASIC_FIELDS_COUNT(obj);
2436 }
2437 }
2438 }
2439 break;
2440 }
2441
2442 if (rb_shape_obj_has_id(obj)) {
2443 iv_count--;
2444 }
2445
2446 return iv_count;
2447}
2448
2449static int
2450ivar_i(ID key, VALUE v, st_data_t a)
2451{
2452 VALUE ary = (VALUE)a;
2453
2454 if (rb_is_instance_id(key)) {
2455 rb_ary_push(ary, ID2SYM(key));
2456 }
2457 return ST_CONTINUE;
2458}
2459
2460/*
2461 * call-seq:
2462 * obj.instance_variables -> array
2463 *
2464 * Returns an array of instance variable names for the receiver. Note
2465 * that simply defining an accessor does not create the corresponding
2466 * instance variable.
2467 *
2468 * class Fred
2469 * attr_accessor :a1
2470 * def initialize
2471 * @iv = 3
2472 * end
2473 * end
2474 * Fred.new.instance_variables #=> [:@iv]
2475 */
2476
2477 VALUE
2478rb_obj_instance_variables(VALUE obj)
2479{
2480 VALUE ary;
2481
2482 ary = rb_ary_new();
2483 rb_ivar_foreach(obj, ivar_i, ary);
2484 return ary;
2485}
2486
2487#define rb_is_constant_id rb_is_const_id
2488#define rb_is_constant_name rb_is_const_name
2489#define id_for_var(obj, name, part, type) \
2490 id_for_var_message(obj, name, type, "'%1$s' is not allowed as "#part" "#type" variable name")
2491#define id_for_var_message(obj, name, type, message) \
2492 check_id_type(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message))
2493static ID
2494check_id_type(VALUE obj, VALUE *pname,
2495 int (*valid_id_p)(ID), int (*valid_name_p)(VALUE),
2496 const char *message, size_t message_len)
2497{
2498 ID id = rb_check_id(pname);
2499 VALUE name = *pname;
2500
2501 if (id ? !valid_id_p(id) : !valid_name_p(name)) {
2502 rb_name_err_raise_str(rb_fstring_new(message, message_len),
2503 obj, name);
2504 }
2505 return id;
2506}
2507
2508/*
2509 * call-seq:
2510 * obj.remove_instance_variable(symbol) -> obj
2511 * obj.remove_instance_variable(string) -> obj
2512 *
2513 * Removes the named instance variable from <i>obj</i>, returning that
2514 * variable's value. The name can be passed as a symbol or as a string.
2515 *
2516 * class Dummy
2517 * attr_reader :var
2518 * def initialize
2519 * @var = 99
2520 * end
2521 * def remove
2522 * remove_instance_variable(:@var)
2523 * end
2524 * end
2525 * d = Dummy.new
2526 * d.var #=> 99
2527 * d.remove #=> 99
2528 * d.var #=> nil
2529 */
2530
2531 VALUE
2532rb_obj_remove_instance_variable(VALUE obj, VALUE name)
2533{
2534 const ID id = id_for_var(obj, name, an, instance);
2535
2536 // Frozen check comes here because it's expected that we raise a
2537 // NameError (from the id_for_var check) before we raise a FrozenError
2538 rb_check_frozen(obj);
2539
2540 if (id) {
2541 VALUE val = rb_ivar_delete(obj, id, Qundef);
2542
2543 if (!UNDEF_P(val)) return val;
2544 }
2545
2546 rb_name_err_raise("instance variable %1$s not defined",
2547 obj, name);
2548 UNREACHABLE_RETURN(Qnil);
2549}
2550
2551NORETURN(static void uninitialized_constant(VALUE, VALUE));
2552static void
2553uninitialized_constant(VALUE klass, VALUE name)
2554{
2555 if (klass && rb_class_real(klass) != rb_cObject)
2556 rb_name_err_raise("uninitialized constant %2$s::%1$s",
2557 klass, name);
2558 else
2559 rb_name_err_raise("uninitialized constant %1$s",
2560 klass, name);
2561}
2562
2563 VALUE
2564rb_const_missing(VALUE klass, VALUE name)
2565{
2566 VALUE value = rb_funcallv(klass, idConst_missing, 1, &name);
2567 rb_vm_inc_const_missing_count();
2568 return value;
2569}
2570
2571
2572/*
2573 * call-seq:
2574 * mod.const_missing(sym) -> obj
2575 *
2576 * Invoked when a reference is made to an undefined constant in
2577 * <i>mod</i>. It is passed a symbol for the undefined constant, and
2578 * returns a value to be used for that constant. For example, consider:
2579 *
2580 * def Foo.const_missing(name)
2581 * name # return the constant name as Symbol
2582 * end
2583 *
2584 * Foo::UNDEFINED_CONST #=> :UNDEFINED_CONST: symbol returned
2585 *
2586 * As the example above shows, +const_missing+ is not required to create the
2587 * missing constant in <i>mod</i>, though that is often a side-effect. The
2588 * caller gets its return value when triggered. If the constant is also defined,
2589 * further lookups won't hit +const_missing+ and will return the value stored in
2590 * the constant as usual. Otherwise, +const_missing+ will be invoked again.
2591 *
2592 * In the next example, when a reference is made to an undefined constant,
2593 * +const_missing+ attempts to load a file whose path is the lowercase version
2594 * of the constant name (thus class <code>Fred</code> is assumed to be in file
2595 * <code>fred.rb</code>). If defined as a side-effect of loading the file, the
2596 * method returns the value stored in the constant. This implements an autoload
2597 * feature similar to Kernel#autoload and Module#autoload, though it differs in
2598 * important ways.
2599 *
2600 * def Object.const_missing(name)
2601 * @looked_for ||= {}
2602 * str_name = name.to_s
2603 * raise "Constant not found: #{name}" if @looked_for[str_name]
2604 * @looked_for[str_name] = 1
2605 * file = str_name.downcase
2606 * require file
2607 * const_get(name, false)
2608 * end
2609 *
2610 */
2611
2612 VALUE
2613rb_mod_const_missing(VALUE klass, VALUE name)
2614{
2615 rb_execution_context_t *ec = GET_EC();
2616 VALUE ref = ec->private_const_reference;
2617 rb_vm_pop_cfunc_frame();
2618 if (ref) {
2619 ec->private_const_reference = 0;
2620 rb_name_err_raise("private constant %2$s::%1$s referenced", ref, name);
2621 }
2622 uninitialized_constant(klass, name);
2623
2624 UNREACHABLE_RETURN(Qnil);
2625}
2626
2627static void
2628autoload_table_mark(void *ptr)
2629{
2630 rb_mark_tbl_no_pin((st_table *)ptr);
2631}
2632
2633static void
2634autoload_table_free(void *ptr)
2635{
2636 st_free_table((st_table *)ptr);
2637}
2638
2639static size_t
2640autoload_table_memsize(const void *ptr)
2641{
2642 const st_table *tbl = ptr;
2643 return st_memsize(tbl);
2644}
2645
2646static void
2647autoload_table_compact(void *ptr)
2648{
2649 rb_gc_ref_update_table_values_only((st_table *)ptr);
2650}
2651
2652static const rb_data_type_t autoload_table_type = {
2653 "autoload_table",
2654 {autoload_table_mark, autoload_table_free, autoload_table_memsize, autoload_table_compact,},
2655 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
2656};
2657
2658#define check_autoload_table(av) \
2659 (struct st_table *)rb_check_typeddata((av), &autoload_table_type)
2660
2661static VALUE
2662 autoload_data(VALUE mod, ID id)
2663{
2664 struct st_table *tbl;
2665 st_data_t val;
2666
2667 // If we are called with a non-origin ICLASS, fetch the autoload data from
2668 // the original module.
2669 if (RB_TYPE_P(mod, T_ICLASS)) {
2670 if (RICLASS_IS_ORIGIN_P(mod)) {
2671 return 0;
2672 }
2673 else {
2674 mod = RBASIC(mod)->klass;
2675 }
2676 }
2677
2678 RUBY_ASSERT(RB_TYPE_P(mod, T_CLASS) || RB_TYPE_P(mod, T_MODULE));
2679
2680 // Look up the instance variable table for `autoload`, then index into that table with the given constant name `id`.
2681
2682 VALUE tbl_value = rb_ivar_lookup(mod, autoload, Qfalse);
2683 if (!RTEST(tbl_value) || !(tbl = check_autoload_table(tbl_value)) || !st_lookup(tbl, (st_data_t)id, &val)) {
2684 return 0;
2685 }
2686
2687 return (VALUE)val;
2688}
2689
2690// Every autoload constant has exactly one instance of autoload_const, stored in `autoload_features`. Since multiple autoload constants can refer to the same file, every `autoload_const` refers to a de-duplicated `autoload_data`.
2691 struct autoload_const {
2692 // The linked list node of all constants which are loaded by the related autoload feature.
2693 struct ccan_list_node cnode; /* <=> autoload_data.constants */
2694
2695 // The shared "autoload_data" if multiple constants are defined from the same feature.
2696 VALUE autoload_data_value;
2697
2698 // The box object when the autoload is called in a user box
2699 // Otherwise, Qnil means the root box
2700 VALUE box_value;
2701
2702 // The module we are loading a constant into.
2703 VALUE module;
2704
2705 // The name of the constant we are loading.
2706 ID name;
2707
2708 // The value of the constant (after it's loaded).
2709 VALUE value;
2710
2711 // The constant entry flags which need to be re-applied after autoloading the feature.
2712 rb_const_flag_t flag;
2713
2714 // The source file and line number that defined this constant (different from feature path).
2715 VALUE file;
2716 int line;
2717};
2718
2719// Each `autoload_data` uniquely represents a specific feature which can be loaded, and a list of constants which it is able to define. We use a mutex to coordinate multiple threads trying to load the same feature.
2720 struct autoload_data {
2721 // The feature path to require to load this constant.
2722 VALUE feature;
2723
2724 // The mutex which is protecting autoloading this feature.
2725 VALUE mutex;
2726
2727 // The process fork serial number since the autoload mutex will become invalid on fork.
2728 rb_serial_t fork_gen;
2729
2730 // The linked list of all constants that are going to be loaded by this autoload.
2731 struct ccan_list_head constants; /* <=> autoload_const.cnode */
2732};
2733
2734static void
2735autoload_data_mark_and_move(void *ptr)
2736{
2737 struct autoload_data *p = ptr;
2738
2739 rb_gc_mark_and_move(&p->feature);
2740 rb_gc_mark_and_move(&p->mutex);
2741}
2742
2743static void
2744autoload_data_free(void *ptr)
2745{
2746 struct autoload_data *p = ptr;
2747
2748 struct autoload_const *autoload_const, *next;
2749 ccan_list_for_each_safe(&p->constants, autoload_const, next, cnode) {
2750 ccan_list_del_init(&autoload_const->cnode);
2751 }
2752
2753 ruby_xfree(p);
2754}
2755
2756static size_t
2757autoload_data_memsize(const void *ptr)
2758{
2759 return sizeof(struct autoload_data);
2760}
2761
2762static const rb_data_type_t autoload_data_type = {
2763 "autoload_data",
2764 {autoload_data_mark_and_move, autoload_data_free, autoload_data_memsize, autoload_data_mark_and_move},
2765 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
2766};
2767
2768static void
2769autoload_const_mark_and_move(void *ptr)
2770{
2771 struct autoload_const *ac = ptr;
2772
2773 rb_gc_mark_and_move(&ac->module);
2774 rb_gc_mark_and_move(&ac->autoload_data_value);
2775 rb_gc_mark_and_move(&ac->value);
2776 rb_gc_mark_and_move(&ac->file);
2777 rb_gc_mark_and_move(&ac->box_value);
2778}
2779
2780static size_t
2781autoload_const_memsize(const void *ptr)
2782{
2783 return sizeof(struct autoload_const);
2784}
2785
2786static void
2787autoload_const_free(void *ptr)
2788{
2789 struct autoload_const *autoload_const = ptr;
2790
2791 ccan_list_del(&autoload_const->cnode);
2792 ruby_xfree(ptr);
2793}
2794
2795static const rb_data_type_t autoload_const_type = {
2796 "autoload_const",
2797 {autoload_const_mark_and_move, autoload_const_free, autoload_const_memsize, autoload_const_mark_and_move,},
2798 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
2799};
2800
2801static struct autoload_data *
2802get_autoload_data(VALUE autoload_const_value, struct autoload_const **autoload_const_pointer)
2803{
2804 struct autoload_const *autoload_const = rb_check_typeddata(autoload_const_value, &autoload_const_type);
2805
2806 VALUE autoload_data_value = autoload_const->autoload_data_value;
2807 struct autoload_data *autoload_data = rb_check_typeddata(autoload_data_value, &autoload_data_type);
2808
2809 /* do not reach across stack for ->state after forking: */
2810 if (autoload_data && autoload_data->fork_gen != GET_VM()->fork_gen) {
2811 RB_OBJ_WRITE(autoload_data_value, &autoload_data->mutex, Qnil);
2812 autoload_data->fork_gen = 0;
2813 }
2814
2815 if (autoload_const_pointer) *autoload_const_pointer = autoload_const;
2816
2817 return autoload_data;
2818}
2819
2820 struct autoload_copy_table_data {
2821 VALUE dst_tbl_value;
2822 struct st_table *dst_tbl;
2823 const rb_box_t *box;
2824};
2825
2826static int
2827autoload_copy_table_for_box_i(st_data_t key, st_data_t value, st_data_t arg)
2828{
2829 struct autoload_const *autoload_const;
2830 struct autoload_copy_table_data *data = (struct autoload_copy_table_data *)arg;
2831 struct st_table *tbl = data->dst_tbl;
2832 VALUE tbl_value = data->dst_tbl_value;
2833 const rb_box_t *box = data->box;
2834
2835 VALUE src_value = (VALUE)value;
2836 struct autoload_const *src_const = rb_check_typeddata(src_value, &autoload_const_type);
2837 // autoload_data can be shared between copies because the feature is equal between copies.
2838 VALUE autoload_data_value = src_const->autoload_data_value;
2839 struct autoload_data *autoload_data = rb_check_typeddata(autoload_data_value, &autoload_data_type);
2840
2841 VALUE new_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
2842 RB_OBJ_WRITE(new_value, &autoload_const->box_value, rb_get_box_object((rb_box_t *)box));
2843 RB_OBJ_WRITE(new_value, &autoload_const->module, src_const->module);
2844 autoload_const->name = src_const->name;
2845 RB_OBJ_WRITE(new_value, &autoload_const->value, src_const->value);
2846 autoload_const->flag = src_const->flag;
2847 RB_OBJ_WRITE(new_value, &autoload_const->autoload_data_value, autoload_data_value);
2848 ccan_list_add_tail(&autoload_data->constants, &autoload_const->cnode);
2849
2850 st_insert(tbl, (st_data_t)autoload_const->name, (st_data_t)new_value);
2851 RB_OBJ_WRITTEN(tbl_value, Qundef, new_value);
2852
2853 return ST_CONTINUE;
2854}
2855
2856void
2857rb_autoload_copy_table_for_box(st_table *iv_ptr, const rb_box_t *box)
2858{
2859 struct st_table *src_tbl, *dst_tbl;
2860 VALUE src_tbl_value, dst_tbl_value;
2861 if (!rb_st_lookup(iv_ptr, (st_data_t)autoload, (st_data_t *)&src_tbl_value)) {
2862 // the class has no autoload table yet.
2863 return;
2864 }
2865 if (!RTEST(src_tbl_value) || !(src_tbl = check_autoload_table(src_tbl_value))) {
2866 // the __autoload__ ivar value isn't autoload table value.
2867 return;
2868 }
2869 src_tbl = check_autoload_table(src_tbl_value);
2870
2871 dst_tbl_value = TypedData_Wrap_Struct(0, &autoload_table_type, NULL);
2872 RTYPEDDATA_DATA(dst_tbl_value) = dst_tbl = st_init_numtable();
2873
2874 struct autoload_copy_table_data data = {
2875 .dst_tbl_value = dst_tbl_value,
2876 .dst_tbl = dst_tbl,
2877 .box = box,
2878 };
2879
2880 st_foreach(src_tbl, autoload_copy_table_for_box_i, (st_data_t)&data);
2881 st_insert(iv_ptr, (st_data_t)autoload, (st_data_t)dst_tbl_value);
2882}
2883
2884void
2885rb_autoload(VALUE module, ID name, const char *feature)
2886{
2887 if (!feature || !*feature) {
2888 rb_raise(rb_eArgError, "empty feature name");
2889 }
2890
2891 rb_autoload_str(module, name, rb_fstring_cstr(feature));
2892}
2893
2894static void const_set(VALUE klass, ID id, VALUE val);
2895static void const_added(VALUE klass, ID const_name);
2896
2897 struct autoload_arguments {
2898 VALUE module;
2899 ID name;
2900 VALUE feature;
2901 VALUE box_value;
2902};
2903
2904static VALUE
2905autoload_feature_lookup_or_create(VALUE feature, struct autoload_data **autoload_data_pointer)
2906{
2907 RUBY_ASSERT_MUTEX_OWNED(autoload_mutex);
2908 RUBY_ASSERT_CRITICAL_SECTION_ENTER();
2909
2910 VALUE autoload_data_value = rb_hash_aref(autoload_features, feature);
2911 struct autoload_data *autoload_data;
2912
2913 if (NIL_P(autoload_data_value)) {
2914 autoload_data_value = TypedData_Make_Struct(0, struct autoload_data, &autoload_data_type, autoload_data);
2915 RB_OBJ_WRITE(autoload_data_value, &autoload_data->feature, feature);
2916 RB_OBJ_WRITE(autoload_data_value, &autoload_data->mutex, Qnil);
2917 ccan_list_head_init(&autoload_data->constants);
2918
2919 if (autoload_data_pointer) *autoload_data_pointer = autoload_data;
2920
2921 rb_hash_aset(autoload_features, feature, autoload_data_value);
2922 }
2923 else if (autoload_data_pointer) {
2924 *autoload_data_pointer = rb_check_typeddata(autoload_data_value, &autoload_data_type);
2925 }
2926
2927 RUBY_ASSERT_CRITICAL_SECTION_LEAVE();
2928 return autoload_data_value;
2929}
2930
2931static VALUE
2932autoload_table_lookup_or_create(VALUE module)
2933{
2934 VALUE autoload_table_value = rb_ivar_lookup(module, autoload, Qfalse);
2935 if (RTEST(autoload_table_value)) {
2936 return autoload_table_value;
2937 }
2938 else {
2939 autoload_table_value = TypedData_Wrap_Struct(0, &autoload_table_type, NULL);
2940 rb_class_ivar_set(module, autoload, autoload_table_value);
2941 RTYPEDDATA_DATA(autoload_table_value) = st_init_numtable();
2942 return autoload_table_value;
2943 }
2944}
2945
2946static VALUE
2947autoload_synchronized(VALUE _arguments)
2948{
2949 struct autoload_arguments *arguments = (struct autoload_arguments *)_arguments;
2950
2951 rb_const_entry_t *constant_entry = rb_const_lookup(arguments->module, arguments->name);
2952 if (constant_entry && !UNDEF_P(constant_entry->value)) {
2953 return Qfalse;
2954 }
2955
2956 // Reset any state associated with any previous constant:
2957 const_set(arguments->module, arguments->name, Qundef);
2958
2959 VALUE autoload_table_value = autoload_table_lookup_or_create(arguments->module);
2960 struct st_table *autoload_table = check_autoload_table(autoload_table_value);
2961
2962 // Ensure the string is uniqued since we use an identity lookup:
2963 VALUE feature = rb_fstring(arguments->feature);
2964
2965 struct autoload_data *autoload_data;
2966 VALUE autoload_data_value = autoload_feature_lookup_or_create(feature, &autoload_data);
2967
2968 {
2969 struct autoload_const *autoload_const;
2970 VALUE autoload_const_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
2971 RB_OBJ_WRITE(autoload_const_value, &autoload_const->box_value, arguments->box_value);
2972 RB_OBJ_WRITE(autoload_const_value, &autoload_const->module, arguments->module);
2973 autoload_const->name = arguments->name;
2974 autoload_const->value = Qundef;
2975 autoload_const->flag = CONST_PUBLIC;
2976 RB_OBJ_WRITE(autoload_const_value, &autoload_const->autoload_data_value, autoload_data_value);
2977 ccan_list_add_tail(&autoload_data->constants, &autoload_const->cnode);
2978 st_insert(autoload_table, (st_data_t)arguments->name, (st_data_t)autoload_const_value);
2979 RB_OBJ_WRITTEN(autoload_table_value, Qundef, autoload_const_value);
2980 }
2981
2982 return Qtrue;
2983}
2984
2985void
2986rb_autoload_str(VALUE module, ID name, VALUE feature)
2987{
2988 const rb_box_t *box = rb_current_box();
2989 VALUE current_box_value = rb_get_box_object((rb_box_t *)box);
2990
2991 if (!rb_is_const_id(name)) {
2992 rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"", QUOTE_ID(name));
2993 }
2994
2995 Check_Type(feature, T_STRING);
2996 if (!RSTRING_LEN(feature)) {
2997 rb_raise(rb_eArgError, "empty feature name");
2998 }
2999
3000 struct autoload_arguments arguments = {
3001 .module = module,
3002 .name = name,
3003 .feature = feature,
3004 .box_value = current_box_value,
3005 };
3006
3007 VALUE result = rb_mutex_synchronize(autoload_mutex, autoload_synchronized, (VALUE)&arguments);
3008
3009 if (result == Qtrue) {
3010 const_added(module, name);
3011 }
3012}
3013
3014static void
3015autoload_delete(VALUE module, ID name)
3016{
3017 RUBY_ASSERT_CRITICAL_SECTION_ENTER();
3018
3019 st_data_t load = 0, key = name;
3020
3021 RUBY_ASSERT(RB_TYPE_P(module, T_CLASS) || RB_TYPE_P(module, T_MODULE));
3022
3023 VALUE table_value = rb_ivar_lookup(module, autoload, Qfalse);
3024 if (RTEST(table_value)) {
3025 struct st_table *table = check_autoload_table(table_value);
3026
3027 st_delete(table, &key, &load);
3028 RB_OBJ_WRITTEN(table_value, load, Qundef);
3029
3030 /* Qfalse can indicate already deleted */
3031 if (load != Qfalse) {
3032 struct autoload_const *autoload_const;
3033 struct autoload_data *autoload_data = get_autoload_data((VALUE)load, &autoload_const);
3034
3035 VM_ASSERT(autoload_data);
3036 VM_ASSERT(!ccan_list_empty(&autoload_data->constants));
3037
3038 /*
3039 * we must delete here to avoid "already initialized" warnings
3040 * with parallel autoload. Using list_del_init here so list_del
3041 * works in autoload_const_free
3042 */
3043 ccan_list_del_init(&autoload_const->cnode);
3044
3045 if (ccan_list_empty(&autoload_data->constants)) {
3046 rb_hash_delete(autoload_features, autoload_data->feature);
3047 }
3048
3049 // If the autoload table is empty, we can delete it.
3050 if (table->num_entries == 0) {
3051 rb_attr_delete(module, autoload);
3052 }
3053 }
3054 }
3055
3056 RUBY_ASSERT_CRITICAL_SECTION_LEAVE();
3057}
3058
3059static int
3060autoload_by_someone_else(struct autoload_data *ele)
3061{
3062 return ele->mutex != Qnil && !rb_mutex_owned_p(ele->mutex);
3063}
3064
3065static VALUE
3066check_autoload_required(VALUE mod, ID id, const char **loadingpath)
3067{
3068 VALUE autoload_const_value = autoload_data(mod, id);
3069 struct autoload_data *autoload_data;
3070 const char *loading;
3071
3072 if (!autoload_const_value || !(autoload_data = get_autoload_data(autoload_const_value, 0))) {
3073 return 0;
3074 }
3075
3076 VALUE feature = autoload_data->feature;
3077
3078 /*
3079 * if somebody else is autoloading, we MUST wait for them, since
3080 * rb_provide_feature can provide a feature before autoload_const_set
3081 * completes. We must wait until autoload_const_set finishes in
3082 * the other thread.
3083 */
3084 if (autoload_by_someone_else(autoload_data)) {
3085 return autoload_const_value;
3086 }
3087
3088 loading = RSTRING_PTR(feature);
3089
3090 if (!rb_feature_provided(loading, &loading)) {
3091 return autoload_const_value;
3092 }
3093
3094 if (loadingpath && loading) {
3095 *loadingpath = loading;
3096 return autoload_const_value;
3097 }
3098
3099 return 0;
3100}
3101
3102static struct autoload_const *autoloading_const_entry(VALUE mod, ID id);
3103
3104int
3105rb_autoloading_value(VALUE mod, ID id, VALUE* value, rb_const_flag_t *flag)
3106{
3107 struct autoload_const *ac = autoloading_const_entry(mod, id);
3108 if (!ac) return FALSE;
3109
3110 if (value) {
3111 *value = ac->value;
3112 }
3113
3114 if (flag) {
3115 *flag = ac->flag;
3116 }
3117
3118 return TRUE;
3119}
3120
3121static int
3122autoload_by_current(struct autoload_data *ele)
3123{
3124 return ele->mutex != Qnil && rb_mutex_owned_p(ele->mutex);
3125}
3126
3127// If there is an autoloading constant and it has been set by the current
3128// execution context, return it. This allows threads which are loading code to
3129// refer to their own autoloaded constants.
3130struct autoload_const *
3131autoloading_const_entry(VALUE mod, ID id)
3132{
3133 VALUE load = autoload_data(mod, id);
3134 struct autoload_data *ele;
3135 struct autoload_const *ac;
3136
3137 // Find the autoloading state:
3138 if (!load || !(ele = get_autoload_data(load, &ac))) {
3139 // Couldn't be found:
3140 return 0;
3141 }
3142
3143 // Check if it's being loaded by the current thread/fiber:
3144 if (autoload_by_current(ele)) {
3145 if (!UNDEF_P(ac->value)) {
3146 return ac;
3147 }
3148 }
3149
3150 return 0;
3151}
3152
3153static int
3154autoload_defined_p(VALUE mod, ID id)
3155{
3156 rb_const_entry_t *ce = rb_const_lookup(mod, id);
3157
3158 // If there is no constant or the constant is not undefined (special marker for autoloading):
3159 if (!ce || !UNDEF_P(ce->value)) {
3160 // We are not autoloading:
3161 return 0;
3162 }
3163
3164 // Otherwise check if there is an autoload in flight right now:
3165 return !rb_autoloading_value(mod, id, NULL, NULL);
3166}
3167
3168static void const_tbl_update(struct autoload_const *, int);
3169
3170 struct autoload_load_arguments {
3171 VALUE module;
3172 ID name;
3173 int flag;
3174
3175 VALUE mutex;
3176
3177 // The specific constant which triggered the autoload code to fire:
3178 struct autoload_const *autoload_const;
3179
3180 // The parent autoload data which is shared between multiple constants:
3181 struct autoload_data *autoload_data;
3182};
3183
3184static VALUE
3185autoload_const_set(struct autoload_const *ac)
3186{
3187 check_before_mod_set(ac->module, ac->name, ac->value, "constant");
3188
3189 RB_VM_LOCKING() {
3190 const_tbl_update(ac, true);
3191 }
3192
3193 return 0; /* ignored */
3194}
3195
3196static VALUE
3197autoload_load_needed(VALUE _arguments)
3198{
3199 struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
3200
3201 const char *loading = 0, *src;
3202
3203 if (!autoload_defined_p(arguments->module, arguments->name)) {
3204 return Qfalse;
3205 }
3206
3207 VALUE autoload_const_value = check_autoload_required(arguments->module, arguments->name, &loading);
3208 if (!autoload_const_value) {
3209 return Qfalse;
3210 }
3211
3212 src = rb_sourcefile();
3213 if (src && loading && strcmp(src, loading) == 0) {
3214 return Qfalse;
3215 }
3216
3217 struct autoload_const *autoload_const;
3218 struct autoload_data *autoload_data;
3219 if (!(autoload_data = get_autoload_data(autoload_const_value, &autoload_const))) {
3220 return Qfalse;
3221 }
3222
3223 if (NIL_P(autoload_data->mutex)) {
3224 RB_OBJ_WRITE(autoload_const->autoload_data_value, &autoload_data->mutex, rb_mutex_new());
3225 autoload_data->fork_gen = GET_VM()->fork_gen;
3226 }
3227 else if (rb_mutex_owned_p(autoload_data->mutex)) {
3228 return Qfalse;
3229 }
3230
3231 arguments->mutex = autoload_data->mutex;
3232 arguments->autoload_const = autoload_const;
3233
3234 return autoload_const_value;
3235}
3236
3237static VALUE
3238autoload_apply_constants(VALUE _arguments)
3239{
3240 RUBY_ASSERT_CRITICAL_SECTION_ENTER();
3241
3242 struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
3243
3244 struct autoload_const *autoload_const = 0; // for ccan_container_off_var()
3245 struct autoload_const *next;
3246
3247 // We use safe iteration here because `autoload_const_set` will eventually invoke
3248 // `autoload_delete` which will remove the constant from the linked list. In theory, once
3249 // the `autoload_data->constants` linked list is empty, we can remove it.
3250
3251 // Iterate over all constants and assign them:
3252 ccan_list_for_each_safe(&arguments->autoload_data->constants, autoload_const, next, cnode) {
3253 if (!UNDEF_P(autoload_const->value)) {
3254 autoload_const_set(autoload_const);
3255 }
3256 }
3257
3258 RUBY_ASSERT_CRITICAL_SECTION_LEAVE();
3259
3260 return Qtrue;
3261}
3262
3263static VALUE
3264autoload_feature_require(VALUE _arguments)
3265{
3266 VALUE receiver = rb_vm_top_self();
3267
3268 struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
3269
3270 struct autoload_const *autoload_const = arguments->autoload_const;
3271 VALUE autoload_box_value = autoload_const->box_value;
3272
3273 // We save this for later use in autoload_apply_constants:
3274 arguments->autoload_data = rb_check_typeddata(autoload_const->autoload_data_value, &autoload_data_type);
3275
3276 if (rb_box_available() && BOX_OBJ_P(autoload_box_value))
3277 receiver = autoload_box_value;
3278
3279 /*
3280 * Clear the global cc cache table because the require method can be different from the current
3281 * box's one and it may cause inconsistent cc-cme states.
3282 * For example, the assertion below may fail in gccct_method_search();
3283 * VM_ASSERT(vm_cc_check_cme(cc, rb_callable_method_entry(klass, mid)))
3284 */
3285 rb_gccct_clear_table(Qnil);
3286
3287 VALUE result = rb_funcall(receiver, rb_intern("require"), 1, arguments->autoload_data->feature);
3288
3289 if (RTEST(result)) {
3290 return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, _arguments);
3291 }
3292 return result;
3293}
3294
3295static VALUE
3296autoload_try_load(VALUE _arguments)
3297{
3298 struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
3299
3300 VALUE result = autoload_feature_require(_arguments);
3301
3302 // After we loaded the feature, if the constant is not defined, we remove it completely:
3303 rb_const_entry_t *ce = rb_const_lookup(arguments->module, arguments->name);
3304
3305 if (!ce || UNDEF_P(ce->value)) {
3306 result = Qfalse;
3307
3308 rb_const_remove(arguments->module, arguments->name);
3309
3310 if (arguments->module == rb_cObject) {
3311 rb_warning(
3312 "Expected %"PRIsVALUE" to define %"PRIsVALUE" but it didn't",
3313 arguments->autoload_data->feature,
3314 ID2SYM(arguments->name)
3315 );
3316 }
3317 else {
3318 rb_warning(
3319 "Expected %"PRIsVALUE" to define %"PRIsVALUE"::%"PRIsVALUE" but it didn't",
3320 arguments->autoload_data->feature,
3321 arguments->module,
3322 ID2SYM(arguments->name)
3323 );
3324 }
3325 }
3326 else {
3327 // Otherwise, it was loaded, copy the flags from the autoload constant:
3328 ce->flag |= arguments->flag;
3329 }
3330
3331 return result;
3332}
3333
3334 VALUE
3335rb_autoload_load(VALUE module, ID name)
3336{
3337 rb_const_entry_t *ce = rb_const_lookup(module, name);
3338
3339 // We bail out as early as possible without any synchronisation:
3340 if (!ce || !UNDEF_P(ce->value)) {
3341 return Qfalse;
3342 }
3343
3344 // At this point, we assume there might be autoloading, so fail if it's ractor:
3345 if (UNLIKELY(!rb_ractor_main_p())) {
3346 return rb_ractor_autoload_load(module, name);
3347 }
3348
3349 // This state is stored on the stack and is used during the autoload process.
3350 struct autoload_load_arguments arguments = {.module = module, .name = name, .mutex = Qnil};
3351
3352 // Figure out whether we can autoload the named constant:
3353 VALUE autoload_const_value = rb_mutex_synchronize(autoload_mutex, autoload_load_needed, (VALUE)&arguments);
3354
3355 // This confirms whether autoloading is required or not:
3356 if (autoload_const_value == Qfalse) return autoload_const_value;
3357
3358 arguments.flag = ce->flag & (CONST_DEPRECATED | CONST_VISIBILITY_MASK);
3359
3360 // Only one thread will enter here at a time:
3361 VALUE result = rb_mutex_synchronize(arguments.mutex, autoload_try_load, (VALUE)&arguments);
3362
3363 // If you don't guard this value, it's possible for the autoload constant to
3364 // be freed by another thread which loads multiple constants, one of which
3365 // resolves to the constant this thread is trying to load, so proteect this
3366 // so that it is not freed until we are done with it in `autoload_try_load`:
3367 RB_GC_GUARD(autoload_const_value);
3368
3369 return result;
3370}
3371
3372 VALUE
3373rb_autoload_p(VALUE mod, ID id)
3374{
3375 return rb_autoload_at_p(mod, id, TRUE);
3376}
3377
3378 VALUE
3379rb_autoload_at_p(VALUE mod, ID id, int recur)
3380{
3381 VALUE load;
3382 struct autoload_data *ele;
3383
3384 while (!autoload_defined_p(mod, id)) {
3385 if (!recur) return Qnil;
3386 mod = RCLASS_SUPER(mod);
3387 if (!mod) return Qnil;
3388 }
3389 load = check_autoload_required(mod, id, 0);
3390 if (!load) return Qnil;
3391 return (ele = get_autoload_data(load, 0)) ? ele->feature : Qnil;
3392}
3393
3394void
3395rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id)
3396{
3397 if (RB_CONST_DEPRECATED_P(ce) &&
3398 rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) {
3399 if (klass == rb_cObject) {
3400 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "constant ::%"PRIsVALUE" is deprecated", QUOTE_ID(id));
3401 }
3402 else {
3403 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "constant %"PRIsVALUE"::%"PRIsVALUE" is deprecated",
3404 rb_class_name(klass), QUOTE_ID(id));
3405 }
3406 }
3407}
3408
3409static VALUE
3410rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
3411{
3412 VALUE found_in;
3413 VALUE c = rb_const_search(klass, id, exclude, recurse, visibility, &found_in);
3414 if (!UNDEF_P(c)) {
3415 if (UNLIKELY(!rb_ractor_main_p())) {
3416 if (!rb_ractor_shareable_p(c)) {
3417 rb_raise(rb_eRactorIsolationError, "can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.", rb_class_path(found_in), rb_id2str(id));
3418 }
3419 }
3420 return c;
3421 }
3422 return rb_const_missing(klass, ID2SYM(id));
3423}
3424
3425static VALUE
3426rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in)
3427{
3428 VALUE value, current;
3429 bool first_iteration = true;
3430
3431 for (current = klass;
3432 RTEST(current);
3433 current = RCLASS_SUPER(current), first_iteration = false) {
3434 VALUE tmp;
3435 VALUE am = 0;
3436 rb_const_entry_t *ce;
3437
3438 if (!first_iteration && RCLASS_ORIGIN(current) != current) {
3439 // This item in the super chain has an origin iclass
3440 // that comes later in the chain. Skip this item so
3441 // prepended modules take precedence.
3442 continue;
3443 }
3444
3445 // Do lookup in original class or module in case we are at an origin
3446 // iclass in the chain.
3447 tmp = current;
3448 if (BUILTIN_TYPE(tmp) == T_ICLASS) tmp = RBASIC(tmp)->klass;
3449
3450 // Do the lookup. Loop in case of autoload.
3451 while ((ce = rb_const_lookup(tmp, id))) {
3452 if (visibility && RB_CONST_PRIVATE_P(ce)) {
3453 GET_EC()->private_const_reference = tmp;
3454 return Qundef;
3455 }
3456 rb_const_warn_if_deprecated(ce, tmp, id);
3457 value = ce->value;
3458 if (UNDEF_P(value)) {
3459 struct autoload_const *ac;
3460 if (am == tmp) break;
3461 am = tmp;
3462 ac = autoloading_const_entry(tmp, id);
3463 if (ac) {
3464 if (found_in) { *found_in = tmp; }
3465 return ac->value;
3466 }
3467 rb_autoload_load(tmp, id);
3468 continue;
3469 }
3470 if (exclude && tmp == rb_cObject) {
3471 goto not_found;
3472 }
3473 if (found_in) { *found_in = tmp; }
3474 return value;
3475 }
3476 if (!recurse) break;
3477 }
3478
3479 not_found:
3480 GET_EC()->private_const_reference = 0;
3481 return Qundef;
3482}
3483
3484static VALUE
3485rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in)
3486{
3487 VALUE value;
3488
3489 if (klass == rb_cObject) exclude = FALSE;
3490 value = rb_const_search_from(klass, id, exclude, recurse, visibility, found_in);
3491 if (!UNDEF_P(value)) return value;
3492 if (exclude) return value;
3493 if (BUILTIN_TYPE(klass) != T_MODULE) return value;
3494 /* search global const too, if klass is a module */
3495 return rb_const_search_from(rb_cObject, id, FALSE, recurse, visibility, found_in);
3496}
3497
3498 VALUE
3499rb_const_get_from(VALUE klass, ID id)
3500{
3501 return rb_const_get_0(klass, id, TRUE, TRUE, FALSE);
3502}
3503
3504 VALUE
3505rb_const_get(VALUE klass, ID id)
3506{
3507 return rb_const_get_0(klass, id, FALSE, TRUE, FALSE);
3508}
3509
3510 VALUE
3511rb_const_get_at(VALUE klass, ID id)
3512{
3513 return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
3514}
3515
3516 VALUE
3517rb_public_const_get_from(VALUE klass, ID id)
3518{
3519 return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
3520}
3521
3522 VALUE
3523rb_public_const_get_at(VALUE klass, ID id)
3524{
3525 return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
3526}
3527
3528NORETURN(static void undefined_constant(VALUE mod, VALUE name));
3529static void
3530undefined_constant(VALUE mod, VALUE name)
3531{
3532 rb_name_err_raise("constant %2$s::%1$s not defined",
3533 mod, name);
3534}
3535
3536static VALUE
3537rb_const_location_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
3538{
3539 while (RTEST(klass)) {
3540 rb_const_entry_t *ce;
3541
3542 while ((ce = rb_const_lookup(klass, id))) {
3543 if (visibility && RB_CONST_PRIVATE_P(ce)) {
3544 return Qnil;
3545 }
3546 if (exclude && klass == rb_cObject) {
3547 goto not_found;
3548 }
3549
3550 if (UNDEF_P(ce->value)) { // autoload
3551 VALUE autoload_const_value = autoload_data(klass, id);
3552 if (RTEST(autoload_const_value)) {
3553 struct autoload_const *autoload_const;
3554 struct autoload_data *autoload_data = get_autoload_data(autoload_const_value, &autoload_const);
3555
3556 if (!UNDEF_P(autoload_const->value) && RTEST(rb_mutex_owned_p(autoload_data->mutex))) {
3557 return rb_assoc_new(autoload_const->file, INT2NUM(autoload_const->line));
3558 }
3559 }
3560 }
3561
3562 if (NIL_P(ce->file)) return rb_ary_new();
3563 return rb_assoc_new(ce->file, INT2NUM(ce->line));
3564 }
3565 if (!recurse) break;
3566 klass = RCLASS_SUPER(klass);
3567 }
3568
3569 not_found:
3570 return Qnil;
3571}
3572
3573static VALUE
3574rb_const_location(VALUE klass, ID id, int exclude, int recurse, int visibility)
3575{
3576 VALUE loc;
3577
3578 if (klass == rb_cObject) exclude = FALSE;
3579 loc = rb_const_location_from(klass, id, exclude, recurse, visibility);
3580 if (!NIL_P(loc)) return loc;
3581 if (exclude) return loc;
3582 if (BUILTIN_TYPE(klass) != T_MODULE) return loc;
3583 /* search global const too, if klass is a module */
3584 return rb_const_location_from(rb_cObject, id, FALSE, recurse, visibility);
3585}
3586
3587 VALUE
3588rb_const_source_location(VALUE klass, ID id)
3589{
3590 return rb_const_location(klass, id, FALSE, TRUE, FALSE);
3591}
3592
3593 VALUE
3594rb_const_source_location_at(VALUE klass, ID id)
3595{
3596 return rb_const_location(klass, id, TRUE, FALSE, FALSE);
3597}
3598
3599/*
3600 * call-seq:
3601 * remove_const(sym) -> obj
3602 *
3603 * Removes the definition of the given constant, returning that
3604 * constant's previous value. If that constant referred to
3605 * a module, this will not change that module's name and can lead
3606 * to confusion.
3607 */
3608
3609 VALUE
3610rb_mod_remove_const(VALUE mod, VALUE name)
3611{
3612 const ID id = id_for_var(mod, name, a, constant);
3613
3614 if (!id) {
3615 undefined_constant(mod, name);
3616 }
3617 return rb_const_remove(mod, id);
3618}
3619
3620static rb_const_entry_t * const_lookup(struct rb_id_table *tbl, ID id);
3621
3622 VALUE
3623rb_const_remove(VALUE mod, ID id)
3624{
3625 VALUE val;
3626 rb_const_entry_t *ce;
3627
3628 rb_check_frozen(mod);
3629
3630 ce = rb_const_lookup(mod, id);
3631
3632 if (!ce) {
3633 if (rb_const_defined_at(mod, id)) {
3634 rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
3635 }
3636
3637 undefined_constant(mod, ID2SYM(id));
3638 }
3639
3640 VALUE writable_ce = 0;
3641 if (rb_id_table_lookup(RCLASS_WRITABLE_CONST_TBL(mod), id, &writable_ce)) {
3642 rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id);
3643 if ((rb_const_entry_t *)writable_ce != ce) {
3644 xfree((rb_const_entry_t *)writable_ce);
3645 }
3646 }
3647
3648 rb_const_warn_if_deprecated(ce, mod, id);
3649 rb_clear_constant_cache_for_id(id);
3650
3651 val = ce->value;
3652
3653 if (UNDEF_P(val)) {
3654 autoload_delete(mod, id);
3655 val = Qnil;
3656 }
3657
3658 if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
3659 ruby_xfree(ce);
3660 }
3661 // else - skip free'ing the ce because it still exists in the prime classext
3662
3663 return val;
3664}
3665
3666static int
3667cv_i_update(st_data_t *k, st_data_t *v, st_data_t a, int existing)
3668{
3669 if (existing) return ST_STOP;
3670 *v = a;
3671 return ST_CONTINUE;
3672}
3673
3674static enum rb_id_table_iterator_result
3675sv_i(ID key, VALUE v, void *a)
3676{
3677 rb_const_entry_t *ce = (rb_const_entry_t *)v;
3678 st_table *tbl = a;
3679
3680 if (rb_is_const_id(key)) {
3681 st_update(tbl, (st_data_t)key, cv_i_update, (st_data_t)ce);
3682 }
3683 return ID_TABLE_CONTINUE;
3684}
3685
3686static enum rb_id_table_iterator_result
3687rb_local_constants_i(ID const_name, VALUE const_value, void *ary)
3688{
3689 if (rb_is_const_id(const_name) && !RB_CONST_PRIVATE_P((rb_const_entry_t *)const_value)) {
3690 rb_ary_push((VALUE)ary, ID2SYM(const_name));
3691 }
3692 return ID_TABLE_CONTINUE;
3693}
3694
3695static VALUE
3696rb_local_constants(VALUE mod)
3697{
3698 struct rb_id_table *tbl = RCLASS_CONST_TBL(mod);
3699 VALUE ary;
3700
3701 if (!tbl) return rb_ary_new2(0);
3702
3703 RB_VM_LOCKING() {
3704 ary = rb_ary_new2(rb_id_table_size(tbl));
3705 rb_id_table_foreach(tbl, rb_local_constants_i, (void *)ary);
3706 }
3707
3708 return ary;
3709}
3710
3711void*
3712rb_mod_const_at(VALUE mod, void *data)
3713{
3714 st_table *tbl = data;
3715 if (!tbl) {
3716 tbl = st_init_numtable();
3717 }
3718 if (RCLASS_CONST_TBL(mod)) {
3719 RB_VM_LOCKING() {
3720 rb_id_table_foreach(RCLASS_CONST_TBL(mod), sv_i, tbl);
3721 }
3722 }
3723 return tbl;
3724}
3725
3726void*
3727rb_mod_const_of(VALUE mod, void *data)
3728{
3729 VALUE tmp = mod;
3730 for (;;) {
3731 data = rb_mod_const_at(tmp, data);
3732 tmp = RCLASS_SUPER(tmp);
3733 if (!tmp) break;
3734 if (tmp == rb_cObject && mod != rb_cObject) break;
3735 }
3736 return data;
3737}
3738
3739static int
3740list_i(st_data_t key, st_data_t value, VALUE ary)
3741{
3742 ID sym = (ID)key;
3743 rb_const_entry_t *ce = (rb_const_entry_t *)value;
3744 if (RB_CONST_PUBLIC_P(ce)) rb_ary_push(ary, ID2SYM(sym));
3745 return ST_CONTINUE;
3746}
3747
3748 VALUE
3749rb_const_list(void *data)
3750{
3751 st_table *tbl = data;
3752 VALUE ary;
3753
3754 if (!tbl) return rb_ary_new2(0);
3755 ary = rb_ary_new2(tbl->num_entries);
3756 st_foreach_safe(tbl, list_i, ary);
3757 st_free_table(tbl);
3758
3759 return ary;
3760}
3761
3762/*
3763 * call-seq:
3764 * mod.constants(inherit=true) -> array
3765 *
3766 * Returns an array of the names of the constants accessible in
3767 * <i>mod</i>. This includes the names of constants in any included
3768 * modules (example at start of section), unless the <i>inherit</i>
3769 * parameter is set to <code>false</code>.
3770 *
3771 * The implementation makes no guarantees about the order in which the
3772 * constants are yielded.
3773 *
3774 * IO.constants.include?(:SYNC) #=> true
3775 * IO.constants(false).include?(:SYNC) #=> false
3776 *
3777 * Also see Module#const_defined?.
3778 */
3779
3780 VALUE
3781rb_mod_constants(int argc, const VALUE *argv, VALUE mod)
3782{
3783 bool inherit = true;
3784
3785 if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
3786
3787 if (inherit) {
3788 return rb_const_list(rb_mod_const_of(mod, 0));
3789 }
3790 else {
3791 return rb_local_constants(mod);
3792 }
3793}
3794
3795static int
3796rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
3797{
3798 VALUE tmp;
3799 int mod_retry = 0;
3800 rb_const_entry_t *ce;
3801
3802 tmp = klass;
3803 retry:
3804 while (tmp) {
3805 if ((ce = rb_const_lookup(tmp, id))) {
3806 if (visibility && RB_CONST_PRIVATE_P(ce)) {
3807 return (int)Qfalse;
3808 }
3809 if (UNDEF_P(ce->value) && !check_autoload_required(tmp, id, 0) &&
3810 !rb_autoloading_value(tmp, id, NULL, NULL))
3811 return (int)Qfalse;
3812
3813 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
3814 return (int)Qfalse;
3815 }
3816
3817 return (int)Qtrue;
3818 }
3819 if (!recurse) break;
3820 tmp = RCLASS_SUPER(tmp);
3821 }
3822 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
3823 mod_retry = 1;
3824 tmp = rb_cObject;
3825 goto retry;
3826 }
3827 return (int)Qfalse;
3828}
3829
3830int
3831rb_const_defined_from(VALUE klass, ID id)
3832{
3833 return rb_const_defined_0(klass, id, TRUE, TRUE, FALSE);
3834}
3835
3836int
3837rb_const_defined(VALUE klass, ID id)
3838{
3839 return rb_const_defined_0(klass, id, FALSE, TRUE, FALSE);
3840}
3841
3842int
3843rb_const_defined_at(VALUE klass, ID id)
3844{
3845 return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
3846}
3847
3848int
3849rb_public_const_defined_from(VALUE klass, ID id)
3850{
3851 return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
3852}
3853
3854static void
3855check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
3856{
3857 rb_check_frozen(klass);
3858}
3859
3860static void set_namespace_path(VALUE named_namespace, VALUE name);
3861
3862static enum rb_id_table_iterator_result
3863set_namespace_path_i(ID id, VALUE v, void *payload)
3864{
3865 rb_const_entry_t *ce = (rb_const_entry_t *)v;
3866 VALUE value = ce->value;
3867 VALUE parental_path = *((VALUE *) payload);
3868 if (!rb_is_const_id(id) || !rb_namespace_p(value)) {
3869 return ID_TABLE_CONTINUE;
3870 }
3871
3872 bool has_permanent_classpath;
3873 classname(value, &has_permanent_classpath);
3874 if (has_permanent_classpath) {
3875 return ID_TABLE_CONTINUE;
3876 }
3877 set_namespace_path(value, build_const_path(parental_path, id));
3878
3879 if (!RCLASS_PERMANENT_CLASSPATH_P(value)) {
3880 RCLASS_WRITE_CLASSPATH(value, 0, false);
3881 }
3882
3883 return ID_TABLE_CONTINUE;
3884}
3885
3886/*
3887 * Assign permanent classpaths to all namespaces that are directly or indirectly
3888 * nested under +named_namespace+. +named_namespace+ must have a permanent
3889 * classpath.
3890 */
3891static void
3892set_namespace_path(VALUE named_namespace, VALUE namespace_path)
3893{
3894 struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
3895 RB_OBJ_SET_SHAREABLE(namespace_path);
3896
3897 RB_VM_LOCKING() {
3898 RCLASS_WRITE_CLASSPATH(named_namespace, namespace_path, true);
3899
3900 if (const_table) {
3901 rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path);
3902 }
3903 }
3904}
3905
3906static void
3907const_added(VALUE klass, ID const_name)
3908{
3909 if (GET_VM()->running) {
3910 VALUE name = ID2SYM(const_name);
3911 rb_funcallv(klass, idConst_added, 1, &name);
3912 }
3913}
3914
3915static void
3916const_set(VALUE klass, ID id, VALUE val)
3917{
3918 rb_const_entry_t *ce;
3919
3920 if (NIL_P(klass)) {
3921 rb_raise(rb_eTypeError, "no class/module to define constant %"PRIsVALUE"",
3922 QUOTE_ID(id));
3923 }
3924
3925 if (!rb_ractor_main_p() && !rb_ractor_shareable_p(val)) {
3926 rb_raise(rb_eRactorIsolationError, "can not set constants with non-shareable objects by non-main Ractors");
3927 }
3928
3929 check_before_mod_set(klass, id, val, "constant");
3930
3931 RB_VM_LOCKING() {
3932 struct rb_id_table *tbl = RCLASS_WRITABLE_CONST_TBL(klass);
3933 if (!tbl) {
3934 tbl = rb_id_table_create(0);
3935 RCLASS_WRITE_CONST_TBL(klass, tbl, false);
3936 rb_clear_constant_cache_for_id(id);
3937 ce = ZALLOC(rb_const_entry_t);
3938 rb_id_table_insert(tbl, id, (VALUE)ce);
3939 setup_const_entry(ce, klass, val, CONST_PUBLIC);
3940 }
3941 else {
3942 struct autoload_const ac = {
3943 .module = klass, .name = id,
3944 .value = val, .flag = CONST_PUBLIC,
3945 /* fill the rest with 0 */
3946 };
3947 ac.file = rb_source_location(&ac.line);
3948 const_tbl_update(&ac, false);
3949 }
3950 }
3951
3952 /*
3953 * Resolve and cache class name immediately to resolve ambiguity
3954 * and avoid order-dependency on const_tbl
3955 */
3956 if (rb_cObject && rb_namespace_p(val)) {
3957 bool val_path_permanent;
3958 VALUE val_path = classname(val, &val_path_permanent);
3959 if (NIL_P(val_path) || !val_path_permanent) {
3960 if (klass == rb_cObject) {
3961 set_namespace_path(val, rb_id2str(id));
3962 }
3963 else {
3964 bool parental_path_permanent;
3965 VALUE parental_path = classname(klass, &parental_path_permanent);
3966 if (NIL_P(parental_path)) {
3967 bool throwaway;
3968 parental_path = rb_tmp_class_path(klass, &throwaway, make_temporary_path);
3969 }
3970 if (parental_path_permanent && !val_path_permanent) {
3971 set_namespace_path(val, build_const_path(parental_path, id));
3972 }
3973 else if (!parental_path_permanent && NIL_P(val_path)) {
3974 VALUE path = build_const_path(parental_path, id);
3975 RCLASS_SET_CLASSPATH(val, path, false);
3976 }
3977 }
3978 }
3979 }
3980}
3981
3982void
3983rb_const_set(VALUE klass, ID id, VALUE val)
3984{
3985 const_set(klass, id, val);
3986 const_added(klass, id);
3987}
3988
3989static VALUE
3990autoload_const_value_for_named_constant(VALUE module, ID name, struct autoload_const **autoload_const_pointer)
3991{
3992 VALUE autoload_const_value = autoload_data(module, name);
3993 if (!autoload_const_value) return Qfalse;
3994
3995 struct autoload_data *autoload_data = get_autoload_data(autoload_const_value, autoload_const_pointer);
3996 if (!autoload_data) return Qfalse;
3997
3998 /* for autoloading thread, keep the defined value to autoloading storage */
3999 if (autoload_by_current(autoload_data)) {
4000 return autoload_const_value;
4001 }
4002
4003 return Qfalse;
4004}
4005
4006static void
4007const_tbl_update(struct autoload_const *ac, int autoload_force)
4008{
4009 VALUE value;
4010 VALUE klass = ac->module;
4011 VALUE val = ac->value;
4012 ID id = ac->name;
4013 struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
4014 rb_const_flag_t visibility = ac->flag;
4015 rb_const_entry_t *ce;
4016
4017 if (rb_id_table_lookup(tbl, id, &value)) {
4018 ce = (rb_const_entry_t *)value;
4019 if (UNDEF_P(ce->value)) {
4020 RUBY_ASSERT_CRITICAL_SECTION_ENTER();
4021 VALUE file = ac->file;
4022 int line = ac->line;
4023 VALUE autoload_const_value = autoload_const_value_for_named_constant(klass, id, &ac);
4024
4025 if (!autoload_force && autoload_const_value) {
4026 rb_clear_constant_cache_for_id(id);
4027
4028 RB_OBJ_WRITE(autoload_const_value, &ac->value, val);
4029 RB_OBJ_WRITE(autoload_const_value, &ac->file, rb_source_location(&ac->line));
4030 }
4031 else {
4032 /* otherwise autoloaded constant, allow to override */
4033 autoload_delete(klass, id);
4034 ce->flag = visibility;
4035 RB_OBJ_WRITE(klass, &ce->value, val);
4036 RB_OBJ_WRITE(klass, &ce->file, file);
4037 ce->line = line;
4038 }
4039 RUBY_ASSERT_CRITICAL_SECTION_LEAVE();
4040 return;
4041 }
4042 else {
4043 VALUE name = QUOTE_ID(id);
4044 visibility = ce->flag;
4045 if (klass == rb_cObject)
4046 rb_warn("already initialized constant %"PRIsVALUE"", name);
4047 else
4048 rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"",
4049 rb_class_name(klass), name);
4050 if (!NIL_P(ce->file) && ce->line) {
4051 rb_compile_warn(RSTRING_PTR(ce->file), ce->line,
4052 "previous definition of %"PRIsVALUE" was here", name);
4053 }
4054 }
4055 rb_clear_constant_cache_for_id(id);
4056 setup_const_entry(ce, klass, val, visibility);
4057 }
4058 else {
4059 tbl = RCLASS_WRITABLE_CONST_TBL(klass);
4060 rb_clear_constant_cache_for_id(id);
4061
4062 ce = ZALLOC(rb_const_entry_t);
4063 rb_id_table_insert(tbl, id, (VALUE)ce);
4064 setup_const_entry(ce, klass, val, visibility);
4065 }
4066}
4067
4068static void
4069setup_const_entry(rb_const_entry_t *ce, VALUE klass, VALUE val,
4070 rb_const_flag_t visibility)
4071{
4072 ce->flag = visibility;
4073 RB_OBJ_WRITE(klass, &ce->value, val);
4074 RB_OBJ_WRITE(klass, &ce->file, rb_source_location(&ce->line));
4075}
4076
4077void
4078rb_define_const(VALUE klass, const char *name, VALUE val)
4079{
4080 ID id = rb_intern(name);
4081
4082 if (!rb_is_const_id(id)) {
4083 rb_warn("rb_define_const: invalid name '%s' for constant", name);
4084 }
4085 if (!RB_SPECIAL_CONST_P(val)) {
4086 rb_vm_register_global_object(val);
4087 }
4088 rb_const_set(klass, id, val);
4089}
4090
4091void
4092rb_define_global_const(const char *name, VALUE val)
4093{
4094 rb_define_const(rb_cObject, name, val);
4095}
4096
4097static void
4098set_const_visibility(VALUE mod, int argc, const VALUE *argv,
4099 rb_const_flag_t flag, rb_const_flag_t mask)
4100{
4101 int i;
4102 rb_const_entry_t *ce;
4103 ID id;
4104
4105 rb_class_modify_check(mod);
4106 if (argc == 0) {
4107 rb_warning("%"PRIsVALUE" with no argument is just ignored",
4108 QUOTE_ID(rb_frame_callee()));
4109 return;
4110 }
4111
4112 for (i = 0; i < argc; i++) {
4113 struct autoload_const *ac;
4114 VALUE val = argv[i];
4115 id = rb_check_id(&val);
4116 if (!id) {
4117 undefined_constant(mod, val);
4118 }
4119 if ((ce = rb_const_lookup(mod, id))) {
4120 ce->flag &= ~mask;
4121 ce->flag |= flag;
4122 if (UNDEF_P(ce->value)) {
4123 if (autoload_const_value_for_named_constant(mod, id, &ac)) {
4124 ac->flag &= ~mask;
4125 ac->flag |= flag;
4126 }
4127 }
4128 rb_clear_constant_cache_for_id(id);
4129 }
4130 else {
4131 undefined_constant(mod, ID2SYM(id));
4132 }
4133 }
4134}
4135
4136void
4137rb_deprecate_constant(VALUE mod, const char *name)
4138{
4139 rb_const_entry_t *ce;
4140 ID id;
4141 long len = strlen(name);
4142
4143 rb_class_modify_check(mod);
4144 if (!(id = rb_check_id_cstr(name, len, NULL))) {
4145 undefined_constant(mod, rb_fstring_new(name, len));
4146 }
4147 if (!(ce = rb_const_lookup(mod, id))) {
4148 undefined_constant(mod, ID2SYM(id));
4149 }
4150 ce->flag |= CONST_DEPRECATED;
4151}
4152
4153/*
4154 * call-seq:
4155 * mod.private_constant(symbol, ...) => mod
4156 *
4157 * Makes a list of existing constants private.
4158 */
4159
4160 VALUE
4161rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj)
4162{
4163 set_const_visibility(obj, argc, argv, CONST_PRIVATE, CONST_VISIBILITY_MASK);
4164 return obj;
4165}
4166
4167/*
4168 * call-seq:
4169 * mod.public_constant(symbol, ...) => mod
4170 *
4171 * Makes a list of existing constants public.
4172 */
4173
4174 VALUE
4175rb_mod_public_constant(int argc, const VALUE *argv, VALUE obj)
4176{
4177 set_const_visibility(obj, argc, argv, CONST_PUBLIC, CONST_VISIBILITY_MASK);
4178 return obj;
4179}
4180
4181/*
4182 * call-seq:
4183 * mod.deprecate_constant(symbol, ...) => mod
4184 *
4185 * Makes a list of existing constants deprecated. Attempt
4186 * to refer to them will produce a warning.
4187 *
4188 * module HTTP
4189 * NotFound = Exception.new
4190 * NOT_FOUND = NotFound # previous version of the library used this name
4191 *
4192 * deprecate_constant :NOT_FOUND
4193 * end
4194 *
4195 * HTTP::NOT_FOUND
4196 * # warning: constant HTTP::NOT_FOUND is deprecated
4197 *
4198 */
4199
4200 VALUE
4201rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj)
4202{
4203 set_const_visibility(obj, argc, argv, CONST_DEPRECATED, CONST_DEPRECATED);
4204 return obj;
4205}
4206
4207static VALUE
4208original_module(VALUE c)
4209{
4210 if (RB_TYPE_P(c, T_ICLASS))
4211 return RBASIC(c)->klass;
4212 return c;
4213}
4214
4215static int
4216cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
4217{
4218 if (RB_TYPE_P(klass, T_ICLASS)) {
4219 if (RICLASS_IS_ORIGIN_P(klass)) {
4220 return 0;
4221 }
4222 else {
4223 // check the original module
4224 klass = RBASIC(klass)->klass;
4225 }
4226 }
4227
4228 VALUE n = rb_ivar_lookup(klass, id, Qundef);
4229 if (UNDEF_P(n)) return 0;
4230
4231 if (v) *v = n;
4232 return 1;
4233}
4234
4235static VALUE
4236cvar_front_klass(VALUE klass)
4237{
4238 if (RCLASS_SINGLETON_P(klass)) {
4239 VALUE obj = RCLASS_ATTACHED_OBJECT(klass);
4240 if (rb_namespace_p(obj)) {
4241 return obj;
4242 }
4243 }
4244 return RCLASS_SUPER(klass);
4245}
4246
4247static void
4248cvar_overtaken(VALUE front, VALUE target, ID id)
4249{
4250 if (front && target != front) {
4251 if (original_module(front) != original_module(target)) {
4252 rb_raise(rb_eRuntimeError,
4253 "class variable % "PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
4254 ID2SYM(id), rb_class_name(original_module(front)),
4255 rb_class_name(original_module(target)));
4256 }
4257 if (BUILTIN_TYPE(front) == T_CLASS) {
4258 rb_ivar_delete(front, id, Qundef);
4259 }
4260 }
4261}
4262
4263#define CVAR_FOREACH_ANCESTORS(klass, v, r) \
4264 for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
4265 if (cvar_lookup_at(klass, id, (v))) { \
4266 r; \
4267 } \
4268 }
4269
4270#define CVAR_LOOKUP(v,r) do {\
4271 CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(klass, id); \
4272 if (cvar_lookup_at(klass, id, (v))) {r;}\
4273 CVAR_FOREACH_ANCESTORS(klass, v, r);\
4274} while(0)
4275
4276static VALUE
4277find_cvar(VALUE klass, VALUE * front, VALUE * target, ID id)
4278{
4279 VALUE v = Qundef;
4280 CVAR_LOOKUP(&v, {
4281 if (!*front) {
4282 *front = klass;
4283 }
4284 *target = klass;
4285 });
4286
4287 return v;
4288}
4289
4290static void
4291check_for_cvar_table(VALUE subclass, VALUE key)
4292{
4293 if (RB_TYPE_P(subclass, T_ICLASS)) return; // skip refinement ICLASSes
4294
4295 if (RTEST(rb_ivar_defined(subclass, key))) {
4296 RB_DEBUG_COUNTER_INC(cvar_class_invalidate);
4297 ruby_vm_global_cvar_state++;
4298 return;
4299 }
4300
4301 rb_class_foreach_subclass(subclass, check_for_cvar_table, key);
4302}
4303
4304void
4305rb_cvar_set(VALUE klass, ID id, VALUE val)
4306{
4307 VALUE tmp, front = 0, target = 0;
4308
4309 tmp = klass;
4310 CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
4311 if (target) {
4312 cvar_overtaken(front, target, id);
4313 }
4314 else {
4315 target = tmp;
4316 }
4317
4318 if (RB_TYPE_P(target, T_ICLASS)) {
4319 target = RBASIC(target)->klass;
4320 }
4321 check_before_mod_set(target, id, val, "class variable");
4322
4323 bool new_cvar = rb_class_ivar_set(target, id, val);
4324
4325 VALUE cvc_tbl = RCLASS_WRITABLE_CVC_TBL(target);
4326
4327 struct rb_cvar_class_tbl_entry *ent;
4328 VALUE ent_data;
4329
4330 if (!cvc_tbl || !rb_marked_id_table_lookup(cvc_tbl, id, &ent_data)) {
4331 ent = (struct rb_cvar_class_tbl_entry *)SHAREABLE_IMEMO_NEW(struct rb_cvar_class_tbl_entry, imemo_cvar_entry, 0);
4332 RB_OBJ_WRITE((VALUE)ent, &ent->class_value, target);
4333 RB_OBJ_WRITE((VALUE)ent, &ent->cref, 0);
4334 ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
4335
4336 VALUE new_cvc_tbl = cvc_tbl;
4337 if (!new_cvc_tbl) {
4338 new_cvc_tbl = rb_marked_id_table_new(2);
4339 }
4340 else if (rb_multi_ractor_p()) {
4341 new_cvc_tbl = rb_marked_id_table_dup(cvc_tbl);
4342 }
4343
4344 rb_marked_id_table_insert(new_cvc_tbl, id, (VALUE)ent);
4345 if (new_cvc_tbl != cvc_tbl) {
4346 RCLASS_WRITE_CVC_TBL(target, new_cvc_tbl);
4347 }
4348 RB_DEBUG_COUNTER_INC(cvar_inline_miss);
4349 }
4350 else {
4351 ent = (void *)ent_data;
4352 ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
4353 }
4354
4355 // Break the cvar cache if this is a new class variable
4356 // and target is a module or a subclass with the same
4357 // cvar in this lookup.
4358 if (new_cvar) {
4359 if (RB_TYPE_P(target, T_CLASS)) {
4360 if (RCLASS_SUBCLASSES_FIRST(target)) {
4361 rb_class_foreach_subclass(target, check_for_cvar_table, id);
4362 }
4363 }
4364 }
4365}
4366
4367 VALUE
4368rb_cvar_find(VALUE klass, ID id, VALUE *front)
4369{
4370 VALUE target = 0;
4371 VALUE value;
4372
4373 value = find_cvar(klass, front, &target, id);
4374 if (!target) {
4375 rb_name_err_raise("uninitialized class variable %1$s in %2$s",
4376 klass, ID2SYM(id));
4377 }
4378 cvar_overtaken(*front, target, id);
4379 return (VALUE)value;
4380}
4381
4382 VALUE
4383rb_cvar_get(VALUE klass, ID id)
4384{
4385 VALUE front = 0;
4386 return rb_cvar_find(klass, id, &front);
4387}
4388
4389 VALUE
4390rb_cvar_defined(VALUE klass, ID id)
4391{
4392 if (!klass) return Qfalse;
4393 CVAR_LOOKUP(0,return Qtrue);
4394 return Qfalse;
4395}
4396
4397static ID
4398cv_intern(VALUE klass, const char *name)
4399{
4400 ID id = rb_intern(name);
4401 if (!rb_is_class_id(id)) {
4402 rb_name_err_raise("wrong class variable name %1$s",
4403 klass, rb_str_new_cstr(name));
4404 }
4405 return id;
4406}
4407
4408void
4409rb_cv_set(VALUE klass, const char *name, VALUE val)
4410{
4411 ID id = cv_intern(klass, name);
4412 rb_cvar_set(klass, id, val);
4413}
4414
4415 VALUE
4416rb_cv_get(VALUE klass, const char *name)
4417{
4418 ID id = cv_intern(klass, name);
4419 return rb_cvar_get(klass, id);
4420}
4421
4422void
4423rb_define_class_variable(VALUE klass, const char *name, VALUE val)
4424{
4425 rb_cv_set(klass, name, val);
4426}
4427
4428static int
4429cv_i(ID key, VALUE v, st_data_t a)
4430{
4431 st_table *tbl = (st_table *)a;
4432
4433 if (rb_is_class_id(key)) {
4434 st_update(tbl, (st_data_t)key, cv_i_update, 0);
4435 }
4436 return ST_CONTINUE;
4437}
4438
4439static void*
4440mod_cvar_at(VALUE mod, void *data)
4441{
4442 st_table *tbl = data;
4443 if (!tbl) {
4444 tbl = st_init_numtable();
4445 }
4446 mod = original_module(mod);
4447
4448 rb_ivar_foreach(mod, cv_i, (st_data_t)tbl);
4449 return tbl;
4450}
4451
4452static void*
4453mod_cvar_of(VALUE mod, void *data)
4454{
4455 VALUE tmp = mod;
4456 if (RCLASS_SINGLETON_P(mod)) {
4457 if (rb_namespace_p(RCLASS_ATTACHED_OBJECT(mod))) {
4458 data = mod_cvar_at(tmp, data);
4459 tmp = cvar_front_klass(tmp);
4460 }
4461 }
4462 for (;;) {
4463 data = mod_cvar_at(tmp, data);
4464 tmp = RCLASS_SUPER(tmp);
4465 if (!tmp) break;
4466 }
4467 return data;
4468}
4469
4470static int
4471cv_list_i(st_data_t key, st_data_t value, VALUE ary)
4472{
4473 ID sym = (ID)key;
4474 rb_ary_push(ary, ID2SYM(sym));
4475 return ST_CONTINUE;
4476}
4477
4478static VALUE
4479cvar_list(void *data)
4480{
4481 st_table *tbl = data;
4482 VALUE ary;
4483
4484 if (!tbl) return rb_ary_new2(0);
4485 ary = rb_ary_new2(tbl->num_entries);
4486 st_foreach_safe(tbl, cv_list_i, ary);
4487 st_free_table(tbl);
4488
4489 return ary;
4490}
4491
4492/*
4493 * call-seq:
4494 * mod.class_variables(inherit=true) -> array
4495 *
4496 * Returns an array of the names of class variables in <i>mod</i>.
4497 * This includes the names of class variables in any included
4498 * modules, unless the <i>inherit</i> parameter is set to
4499 * <code>false</code>.
4500 *
4501 * class One
4502 * @@var1 = 1
4503 * end
4504 * class Two < One
4505 * @@var2 = 2
4506 * end
4507 * One.class_variables #=> [:@@var1]
4508 * Two.class_variables #=> [:@@var2, :@@var1]
4509 * Two.class_variables(false) #=> [:@@var2]
4510 */
4511
4512 VALUE
4513rb_mod_class_variables(int argc, const VALUE *argv, VALUE mod)
4514{
4515 bool inherit = true;
4516 st_table *tbl;
4517
4518 if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
4519 if (inherit) {
4520 tbl = mod_cvar_of(mod, 0);
4521 }
4522 else {
4523 tbl = mod_cvar_at(mod, 0);
4524 }
4525 return cvar_list(tbl);
4526}
4527
4528/*
4529 * call-seq:
4530 * remove_class_variable(sym) -> obj
4531 *
4532 * Removes the named class variable from the receiver, returning that
4533 * variable's value.
4534 *
4535 * class Example
4536 * @@var = 99
4537 * puts remove_class_variable(:@@var)
4538 * p(defined? @@var)
4539 * end
4540 *
4541 * <em>produces:</em>
4542 *
4543 * 99
4544 * nil
4545 */
4546
4547 VALUE
4548rb_mod_remove_cvar(VALUE mod, VALUE name)
4549{
4550 const ID id = id_for_var_message(mod, name, class, "wrong class variable name %1$s");
4551 st_data_t val;
4552
4553 if (!id) {
4554 goto not_defined;
4555 }
4556 rb_check_frozen(mod);
4557 val = rb_ivar_delete(mod, id, Qundef);
4558 if (!UNDEF_P(val)) {
4559 return (VALUE)val;
4560 }
4561 if (rb_cvar_defined(mod, id)) {
4562 rb_name_err_raise("cannot remove %1$s for %2$s", mod, ID2SYM(id));
4563 }
4564 not_defined:
4565 rb_name_err_raise("class variable %1$s not defined for %2$s",
4566 mod, name);
4567 UNREACHABLE_RETURN(Qundef);
4568}
4569
4570 VALUE
4571rb_iv_get(VALUE obj, const char *name)
4572{
4573 ID id = rb_check_id_cstr(name, strlen(name), rb_usascii_encoding());
4574
4575 if (!id) {
4576 return Qnil;
4577 }
4578 return rb_ivar_get(obj, id);
4579}
4580
4581 VALUE
4582rb_iv_set(VALUE obj, const char *name, VALUE val)
4583{
4584 ID id = rb_intern(name);
4585
4586 return rb_ivar_set(obj, id, val);
4587}
4588
4589static attr_index_t
4590class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool concurrent, VALUE *new_fields_obj, bool *new_ivar_out)
4591{
4592 const VALUE original_fields_obj = fields_obj;
4593 fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, 1, true);
4594
4595 shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj);
4596 shape_id_t next_shape_id = current_shape_id; // for too_complex
4597 if (UNLIKELY(rb_shape_too_complex_p(current_shape_id))) {
4598 goto too_complex;
4599 }
4600
4601 bool new_ivar;
4602 next_shape_id = generic_shape_ivar(fields_obj, id, &new_ivar);
4603
4604 if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
4605 fields_obj = imemo_fields_complex_from_obj(klass, fields_obj, next_shape_id);
4606 goto too_complex;
4607 }
4608
4609 attr_index_t index = RSHAPE_INDEX(next_shape_id);
4610 if (new_ivar) {
4611 if (index >= RSHAPE_CAPACITY(current_shape_id)) {
4612 // We allocate a new fields_obj even when concurrency isn't a concern
4613 // so that we're embedded as long as possible.
4614 fields_obj = imemo_fields_copy_capa(klass, fields_obj, RSHAPE_CAPACITY(next_shape_id));
4615 }
4616 }
4617
4618 VALUE *fields = rb_imemo_fields_ptr(fields_obj);
4619
4620 if (concurrent && original_fields_obj == fields_obj) {
4621 // In the concurrent case, if we're mutating the existing
4622 // fields_obj, we must use an atomic write, because if we're
4623 // adding a new field, the shape_id must be written after the field
4624 // and if we're updating an existing field, we at least need a relaxed
4625 // write to avoid reaping.
4626 RB_OBJ_ATOMIC_WRITE(fields_obj, &fields[index], val);
4627 }
4628 else {
4629 RB_OBJ_WRITE(fields_obj, &fields[index], val);
4630 }
4631
4632 if (new_ivar) {
4633 RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
4634 }
4635
4636 *new_fields_obj = fields_obj;
4637 *new_ivar_out = new_ivar;
4638 return index;
4639
4640too_complex:
4641 {
4642 if (concurrent && fields_obj == original_fields_obj) {
4643 // In multi-ractor case, we must always work on a copy because
4644 // even if the field already exist, inserting in a st_table may
4645 // cause a rebuild.
4646 fields_obj = rb_imemo_fields_clone(fields_obj);
4647 }
4648
4649 st_table *table = rb_imemo_fields_complex_tbl(fields_obj);
4650 new_ivar = !st_insert(table, (st_data_t)id, (st_data_t)val);
4651 RB_OBJ_WRITTEN(fields_obj, Qundef, val);
4652
4653 if (fields_obj != original_fields_obj) {
4654 RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
4655 }
4656 }
4657
4658 *new_fields_obj = fields_obj;
4659 *new_ivar_out = new_ivar;
4660 return ATTR_INDEX_NOT_SET;
4661}
4662
4663static attr_index_t
4664class_ivar_set(VALUE obj, ID id, VALUE val, bool *new_ivar)
4665{
4666 rb_class_ensure_writable(obj);
4667
4668 const VALUE original_fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
4669 VALUE new_fields_obj = 0;
4670
4671 attr_index_t index = class_fields_ivar_set(obj, original_fields_obj, id, val, rb_multi_ractor_p(), &new_fields_obj, new_ivar);
4672
4673 if (new_fields_obj != original_fields_obj) {
4674 RCLASS_WRITABLE_SET_FIELDS_OBJ(obj, new_fields_obj);
4675 }
4676
4677 // TODO: What should we set as the T_CLASS shape_id?
4678 // In most case we can replicate the single `fields_obj` shape
4679 // but in namespaced case? Perhaps INVALID_SHAPE_ID?
4680 RBASIC_SET_SHAPE_ID(obj, RBASIC_SHAPE_ID(new_fields_obj));
4681 return index;
4682}
4683
4684bool
4685rb_class_ivar_set(VALUE obj, ID id, VALUE val)
4686{
4687 RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
4688 rb_check_frozen(obj);
4689
4690 bool new_ivar;
4691 class_ivar_set(obj, id, val, &new_ivar);
4692 return new_ivar;
4693}
4694
4695void
4696rb_fields_tbl_copy(VALUE dst, VALUE src)
4697{
4698 RUBY_ASSERT(rb_type(dst) == rb_type(src));
4699 RUBY_ASSERT(RB_TYPE_P(dst, T_CLASS) || RB_TYPE_P(dst, T_MODULE));
4700 RUBY_ASSERT(RSHAPE_TYPE_P(RBASIC_SHAPE_ID(dst), SHAPE_ROOT));
4701
4702 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(src);
4703 if (fields_obj) {
4704 RCLASS_WRITABLE_SET_FIELDS_OBJ(dst, rb_imemo_fields_clone(fields_obj));
4705 RBASIC_SET_SHAPE_ID(dst, RBASIC_SHAPE_ID(src));
4706 }
4707}
4708
4709static rb_const_entry_t *
4710const_lookup(struct rb_id_table *tbl, ID id)
4711{
4712 if (tbl) {
4713 VALUE val;
4714 bool r;
4715 RB_VM_LOCKING() {
4716 r = rb_id_table_lookup(tbl, id, &val);
4717 }
4718
4719 if (r) return (rb_const_entry_t *)val;
4720 }
4721 return NULL;
4722}
4723
4724rb_const_entry_t *
4725rb_const_lookup(VALUE klass, ID id)
4726{
4727 return const_lookup(RCLASS_CONST_TBL(klass), id);
4728}
RUBY_ASSERT
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
RUBY_EXTERN
#define RUBY_EXTERN
Declaration of externally visible global variables.
Definition dllexport.h:45
RB_OBJ_FROZEN_RAW
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
Definition fl_type.h:877
RB_FL_ABLE
static bool RB_FL_ABLE(VALUE obj)
Checks if the object is flaggable.
Definition fl_type.h:440
RB_FL_SET_RAW
static void RB_FL_SET_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_SET().
Definition fl_type.h:600
rb_obj_freeze_inline
void rb_obj_freeze_inline(VALUE obj)
Prevents further modifications to the given object.
Definition variable.c:1991
RB_FL_UNSET_RAW
static void RB_FL_UNSET_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_UNSET().
Definition fl_type.h:660
RUBY_FL_FREEZE
@ RUBY_FL_FREEZE
This flag has something to do with data immutability.
Definition fl_type.h:320
rb_class_modify_check
void rb_class_modify_check(VALUE klass)
Asserts that klass is not a frozen class.
Definition eval.c:432
rb_freeze_singleton_class
void rb_freeze_singleton_class(VALUE x)
This is an implementation detail of RB_OBJ_FREEZE().
Definition class.c:2764
rb_scan_args
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:3132
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
FL_UNSET_RAW
#define FL_UNSET_RAW
Old name of RB_FL_UNSET_RAW.
Definition fl_type.h:133
FL_USER3
#define FL_USER3
Old name of RUBY_FL_USER3.
Definition fl_type.h:73
REALLOC_N
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
ALLOC
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
xfree
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
T_IMEMO
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition value_type.h:67
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
SPECIAL_CONST_P
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
Definition special_consts.h:56
T_STRUCT
#define T_STRUCT
Old name of RUBY_T_STRUCT.
Definition value_type.h:79
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
T_DATA
#define T_DATA
Old name of RUBY_T_DATA.
Definition value_type.h:60
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
T_MODULE
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
T_ICLASS
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
FL_TEST_RAW
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:131
rb_ary_new3
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:658
FL_USER2
#define FL_USER2
Old name of RUBY_FL_USER2.
Definition fl_type.h:72
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
INT2NUM
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
T_OBJECT
#define T_OBJECT
Old name of RUBY_T_OBJECT.
Definition value_type.h:75
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
ALLOCV_N
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
T_CLASS
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
BUILTIN_TYPE
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
rb_ary_new2
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
FL_SET_RAW
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:129
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
rb_name_error
void rb_name_error(ID id, const char *fmt,...)
Raises an instance of rb_eNameError.
Definition error.c:2345
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
rb_name_error_str
void rb_name_error_str(VALUE str, const char *fmt,...)
Identical to rb_name_error(), except it takes a VALUE instead of ID.
Definition error.c:2360
rb_eNameError
VALUE rb_eNameError
NameError exception.
Definition error.c:1436
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
rb_check_typeddata
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead of returning false.
Definition error.c:1398
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
rb_warning
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:497
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
rb_cModule
VALUE rb_cModule
Module class.
Definition object.c:62
rb_class_real
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:255
rb_obj_embedded_size
size_t rb_obj_embedded_size(uint32_t fields_count)
Internal header for Object.
Definition object.c:94
RB_OBJ_WRITTEN
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
RB_OBJ_WRITE
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
encoding.h
Encoding relates APIs.
rb_usascii_encoding
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
Definition encoding.c:1547
rb_check_id_cstr
ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id(), except it takes a pointer to a memory region instead of Ruby's string.
Definition symbol.c:1223
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
rb_ary_new
VALUE rb_ary_new(void)
Allocates a new, empty array.
rb_ary_hidden_new
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
rb_check_arity
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
rb_frame_callee
ID rb_frame_callee(void)
Identical to rb_frame_this_func(), except it returns the named used to call the method.
Definition eval.c:1210
st_foreach_safe
#define st_foreach_safe
Just another name of rb_st_foreach_safe.
Definition hash.h:51
rb_feature_provided
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:666
rb_backref_get
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
Definition vm.c:2030
rb_is_instance_id
int rb_is_instance_id(ID id)
Classifies the given ID, then sees if it is an instance variable.
Definition symbol.c:1097
rb_is_const_id
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
rb_is_class_id
int rb_is_class_id(ID id)
Classifies the given ID, then sees if it is a class variable.
Definition symbol.c:1085
rb_block_proc
VALUE rb_block_proc(void)
Constructs a Proc object from implicitly passed components.
Definition proc.c:983
rb_reg_nth_defined
VALUE rb_reg_nth_defined(int n, VALUE md)
Identical to rb_reg_nth_match(), except it just returns Boolean.
Definition re.c:1905
rb_str_append
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:3799
rb_str_subseq
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:3155
rb_str_new_frozen
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1518
rb_str_dup
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1996
rb_str_new_cstr
#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:1515
rb_str_intern
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:937
rb_mutex_new
VALUE rb_mutex_new(void)
Creates a mutex.
Definition thread_sync.c:184
rb_mutex_synchronize
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
Definition thread_sync.c:649
rb_exec_recursive_paired
VALUE rb_exec_recursive_paired(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE p, VALUE h)
Identical to rb_exec_recursive(), except it checks for the recursion on the ordered pair of { g,...
Definition thread.c:5617
rb_mod_remove_cvar
VALUE rb_mod_remove_cvar(VALUE mod, VALUE name)
Resembles Module#remove_class_variable.
Definition variable.c:4548
rb_obj_instance_variables
VALUE rb_obj_instance_variables(VALUE obj)
Resembles Object#instance_variables.
Definition variable.c:2478
rb_f_untrace_var
VALUE rb_f_untrace_var(int argc, const VALUE *argv)
Deletes the passed tracer from the passed global variable, or if omitted, deletes everything.
Definition variable.c:924
rb_const_get
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3505
rb_const_list
VALUE rb_const_list(void *)
This is another mysterious API that comes with no documents at all.
Definition variable.c:3749
rb_path2class
VALUE rb_path2class(const char *path)
Resolves a Q::W::E::R-style path string to the actual class it points.
Definition variable.c:494
rb_autoload_p
VALUE rb_autoload_p(VALUE space, ID name)
Queries if an autoload is defined at a point.
Definition variable.c:3373
rb_set_class_path
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
rb_ivar_set
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2030
rb_mod_remove_const
VALUE rb_mod_remove_const(VALUE space, VALUE name)
Resembles Module#remove_const.
Definition variable.c:3610
rb_class_path_cached
VALUE rb_class_path_cached(VALUE mod)
Just another name of rb_mod_name.
Definition variable.c:389
rb_f_trace_var
VALUE rb_f_trace_var(int argc, const VALUE *argv)
Traces a global variable.
Definition variable.c:878
rb_cvar_set
void rb_cvar_set(VALUE klass, ID name, VALUE val)
Assigns a value to a class variable.
Definition variable.c:4305
rb_cvar_get
VALUE rb_cvar_get(VALUE klass, ID name)
Obtains a value from a class variable.
Definition variable.c:4383
rb_mod_constants
VALUE rb_mod_constants(int argc, const VALUE *argv, VALUE recv)
Resembles Module#constants.
Definition variable.c:3781
rb_cvar_find
VALUE rb_cvar_find(VALUE klass, ID name, VALUE *front)
Identical to rb_cvar_get(), except it takes additional "front" pointer.
Definition variable.c:4368
rb_path_to_class
VALUE rb_path_to_class(VALUE path)
Identical to rb_path2class(), except it accepts the path as Ruby's string instead of C's.
Definition variable.c:449
rb_ivar_get
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1505
rb_const_set
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:3983
rb_autoload_load
VALUE rb_autoload_load(VALUE space, ID name)
Kicks the autoload procedure as if it was "touched".
Definition variable.c:3335
rb_mod_name
VALUE rb_mod_name(VALUE mod)
Queries the name of a module.
Definition variable.c:136
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
rb_const_get_at
VALUE rb_const_get_at(VALUE space, ID name)
Identical to rb_const_defined_at(), except it returns the actual defined value.
Definition variable.c:3511
rb_set_class_path_string
void rb_set_class_path_string(VALUE klass, VALUE space, VALUE name)
Identical to rb_set_class_path(), except it accepts the name as Ruby's string instead of C's.
Definition variable.c:423
rb_alias_variable
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition variable.c:1166
rb_define_class_variable
void rb_define_class_variable(VALUE, const char *, VALUE)
Just another name of rb_cv_set.
Definition variable.c:4423
rb_obj_remove_instance_variable
VALUE rb_obj_remove_instance_variable(VALUE obj, VALUE name)
Resembles Object#remove_instance_variable.
Definition variable.c:2532
rb_mod_const_of
void * rb_mod_const_of(VALUE, void *)
This is a variant of rb_mod_const_at().
Definition variable.c:3727
rb_ivar_count
st_index_t rb_ivar_count(VALUE obj)
Number of instance variables defined on an object.
Definition variable.c:2390
rb_mod_const_at
void * rb_mod_const_at(VALUE, void *)
This API is mysterious.
Definition variable.c:3712
rb_const_remove
VALUE rb_const_remove(VALUE space, ID name)
Identical to rb_mod_remove_const(), except it takes the name as ID instead of VALUE.
Definition variable.c:3623
rb_const_get_from
VALUE rb_const_get_from(VALUE space, ID name)
Identical to rb_const_defined_at(), except it returns the actual defined value.
Definition variable.c:3499
rb_ivar_defined
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2109
rb_cv_get
VALUE rb_cv_get(VALUE klass, const char *name)
Identical to rb_cvar_get(), except it accepts C's string instead of ID.
Definition variable.c:4416
rb_const_defined_at
int rb_const_defined_at(VALUE space, ID name)
Identical to rb_const_defined(), except it doesn't look for parent classes.
Definition variable.c:3843
rb_cv_set
void rb_cv_set(VALUE klass, const char *name, VALUE val)
Identical to rb_cvar_set(), except it accepts C's string instead of ID.
Definition variable.c:4409
rb_mod_class_variables
VALUE rb_mod_class_variables(int argc, const VALUE *argv, VALUE recv)
Resembles Module#class_variables.
Definition variable.c:4513
rb_f_global_variables
VALUE rb_f_global_variables(void)
Queries the list of global variables.
Definition variable.c:1133
rb_cvar_defined
VALUE rb_cvar_defined(VALUE klass, ID name)
Queries if the given class has the given class variable.
Definition variable.c:4390
rb_class_path
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:380
rb_const_defined_from
int rb_const_defined_from(VALUE space, ID name)
Identical to rb_const_defined(), except it returns false for private constants.
Definition variable.c:3831
rb_const_defined
int rb_const_defined(VALUE space, ID name)
Queries if the constant is defined at the namespace.
Definition variable.c:3837
rb_free_generic_ivar
void rb_free_generic_ivar(VALUE obj)
Frees the list of instance variables.
Definition variable.c:1308
rb_sourcefile
const char * rb_sourcefile(void)
Resembles __FILE__.
Definition vm.c:2067
rb_clear_constant_cache_for_id
void rb_clear_constant_cache_for_id(ID id)
Clears the inline constant caches associated with a particular ID.
Definition vm_method.c:332
rb_obj_respond_to
int rb_obj_respond_to(VALUE obj, ID mid, int private_p)
Identical to rb_respond_to(), except it additionally takes the visibility parameter.
Definition vm_method.c:3447
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
rb_id2sym
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:974
rb_check_id
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1133
rb_to_id
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:12664
rb_gvar_var_setter
rb_gvar_setter_t rb_gvar_var_setter
Definition variable.h:119
rb_gvar_var_marker
rb_gvar_marker_t rb_gvar_var_marker
Definition variable.h:128
rb_define_global_const
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4092
rb_gv_get
VALUE rb_gv_get(const char *name)
Obtains a global variable.
Definition variable.c:1091
rb_define_variable
void rb_define_variable(const char *name, VALUE *var)
"Shares" a global variable between Ruby and C.
Definition variable.c:849
rb_gvar_marker_t
void rb_gvar_marker_t(VALUE *var)
Type that represents a global variable marker function.
Definition variable.h:53
rb_deprecate_constant
void rb_deprecate_constant(VALUE mod, const char *name)
Asserts that the given constant is deprecated.
Definition variable.c:4137
rb_gvar_setter_t
void rb_gvar_setter_t(VALUE val, ID id, VALUE *data)
Type that represents a global variable setter function.
Definition variable.h:46
rb_gvar_val_setter
rb_gvar_setter_t rb_gvar_val_setter
This is the setter function that backs global variables defined from a ruby script.
Definition variable.h:94
rb_gvar_undef_marker
rb_gvar_marker_t rb_gvar_undef_marker
Definition variable.h:80
rb_define_readonly_variable
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:855
rb_gvar_readonly_setter
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
rb_gvar_undef_getter
rb_gvar_getter_t rb_gvar_undef_getter
Definition variable.h:62
rb_gv_set
VALUE rb_gv_set(const char *name, VALUE val)
Assigns to a global variable.
Definition variable.c:1046
rb_gvar_val_marker
rb_gvar_marker_t rb_gvar_val_marker
This is the setter function that backs global variables defined from a ruby script.
Definition variable.h:101
rb_gvar_getter_t
VALUE rb_gvar_getter_t(ID id, VALUE *data)
Type that represents a global variable getter function.
Definition variable.h:37
rb_iv_get
VALUE rb_iv_get(VALUE obj, const char *name)
Obtains an instance variable.
Definition variable.c:4571
rb_gvar_undef_setter
rb_gvar_setter_t rb_gvar_undef_setter
Definition variable.h:71
rb_gvar_val_getter
rb_gvar_getter_t rb_gvar_val_getter
This is the getter function that backs global variables defined from a ruby script.
Definition variable.h:87
rb_iv_set
VALUE rb_iv_set(VALUE obj, const char *name, VALUE val)
Assigns to an instance variable.
Definition variable.c:4582
rb_gvar_var_getter
rb_gvar_getter_t rb_gvar_var_getter
Definition variable.h:110
len
int len
Length of the buffer.
Definition io.h:8
rb_ractor_shareable_p
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
Definition ractor.h:249
RB_OBJ_SHAREABLE_P
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
util.h
MEMCPY
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
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::st_foreach
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition cxxanyargs.hpp:432
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
ruby::backward::cxxanyargs::rb_ivar_foreach
void rb_ivar_foreach(VALUE q, int_type *w, VALUE e)
Iteration over each instance variable of the object.
Definition cxxanyargs.hpp:498
ruby::backward::cxxanyargs::rb_ensure
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Definition cxxanyargs.hpp:310
rb_copy_generic_ivar
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
Definition variable.c:2241
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RBASIC_CLASS
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
RBASIC
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
RCLASS_SUPER
#define RCLASS_SUPER
Just another name of rb_class_get_superclass.
Definition rclass.h:44
ROBJECT
#define ROBJECT(obj)
Convenient casting macro.
Definition robject.h:43
ROBJECT_FIELDS
static VALUE * ROBJECT_FIELDS(VALUE obj)
Queries the instance variables.
Definition robject.h:128
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
RSTRING_END
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
RTYPEDDATA_P
static bool RTYPEDDATA_P(VALUE obj)
Checks whether the passed object is RTypedData or RData.
Definition rtypeddata.h:575
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:461
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
RTYPEDDATA
#define RTYPEDDATA(obj)
Convenient casting macro.
Definition rtypeddata.h:95
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
rb_class2name
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition variable.c:506
rb_obj_classname
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
Definition variable.c:515
RB_NO_KEYWORDS
#define RB_NO_KEYWORDS
Do not pass keywords.
Definition scan_args.h:69
RB_SPECIAL_CONST_P
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
Definition special_consts.h:327
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
stdbool.h
C99 shim for <stdbool.h>.
autoload_arguments
Definition variable.c:2897
autoload_const
Definition variable.c:2691
autoload_copy_table_data
Definition variable.c:2820
autoload_data
Definition variable.c:2720
autoload_load_arguments
Definition variable.c:3170
iv_itr_data
Definition variable.c:2131
ivar_buf_entry
Definition variable.c:2348
rb_cvar_class_tbl_entry
Definition class.h:37
rb_global_entry
Definition variable.c:540
rb_global_variable
Definition variable.c:527
rb_id_table
Definition id_table.c:41
st_table
Definition st.h:79
sub_temporary_name_args
Definition variable.c:175
trace_data
Definition variable.c:967
trace_var
Definition variable.c:520
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
rb_type
static enum ruby_value_type rb_type(VALUE obj)
Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
Definition value_type.h:225
RB_BUILTIN_TYPE
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
Definition value_type.h:182
Check_Type
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:433
RB_TYPE_P
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