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