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