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