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