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