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