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