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