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