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