Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
variable.c
Go to the documentation of this file.
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
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 "transient_heap.h"
37#include "variable.h"
38#include "vm_core.h"
39#include "ractor_core.h"
40#include "vm_sync.h"
41
42typedef void rb_gvar_compact_t(void *var);
43
44static struct rb_id_table *rb_global_tbl;
45static ID autoload, classpath, tmp_classpath;
46static VALUE autoload_featuremap; /* feature => autoload_i */
47
48static void check_before_mod_set(VALUE, ID, VALUE, const char *);
49static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
50static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility);
51static st_table *generic_iv_tbl_;
52
54 union {
57 } u;
60};
61
62void
64{
65 rb_global_tbl = rb_id_table_create(0);
66 generic_iv_tbl_ = st_init_numtable();
67 autoload = rb_intern_const("__autoload__");
68 /* __classpath__: fully qualified class path */
69 classpath = rb_intern_const("__classpath__");
70 /* __tmp_classpath__: temporary class path which contains anonymous names */
71 tmp_classpath = rb_intern_const("__tmp_classpath__");
72}
73
74static inline bool
75rb_namespace_p(VALUE obj)
76{
77 if (RB_SPECIAL_CONST_P(obj)) return false;
78 switch (RB_BUILTIN_TYPE(obj)) {
79 case T_MODULE: case T_CLASS: return true;
80 default: break;
81 }
82 return false;
83}
84
93static VALUE
94classname(VALUE klass, int *permanent)
95{
96 st_table *ivtbl;
97 st_data_t n;
98
99 *permanent = 0;
100 if (!RCLASS_EXT(klass)) return Qnil;
101 if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
102 if (st_lookup(ivtbl, (st_data_t)classpath, &n)) {
103 *permanent = 1;
104 return (VALUE)n;
105 }
106 if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
107 return Qnil;
108}
109
110/*
111 * call-seq:
112 * mod.name -> string
113 *
114 * Returns the name of the module <i>mod</i>. Returns nil for anonymous modules.
115 */
116
117VALUE
119{
120 int permanent;
121 return classname(mod, &permanent);
122}
123
124static VALUE
125make_temporary_path(VALUE obj, VALUE klass)
126{
127 VALUE path;
128 switch (klass) {
129 case Qnil:
130 path = rb_sprintf("#<Class:%p>", (void*)obj);
131 break;
132 case Qfalse:
133 path = rb_sprintf("#<Module:%p>", (void*)obj);
134 break;
135 default:
136 path = rb_sprintf("#<%"PRIsVALUE":%p>", klass, (void*)obj);
137 break;
138 }
139 OBJ_FREEZE(path);
140 return path;
141}
142
144
145static VALUE
146rb_tmp_class_path(VALUE klass, int *permanent, fallback_func fallback)
147{
148 VALUE path = classname(klass, permanent);
149
150 if (!NIL_P(path)) {
151 return path;
152 }
153 else {
154 if (RB_TYPE_P(klass, T_MODULE)) {
155 if (rb_obj_class(klass) == rb_cModule) {
156 path = Qfalse;
157 }
158 else {
159 int perm;
160 path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, fallback);
161 }
162 }
163 *permanent = 0;
164 return fallback(klass, path);
165 }
166}
167
168VALUE
170{
171 int permanent;
172 VALUE path = rb_tmp_class_path(klass, &permanent, make_temporary_path);
173 if (!NIL_P(path)) path = rb_str_dup(path);
174 return path;
175}
176
177VALUE
179{
180 int permanent;
181 return classname(klass, &permanent);
182}
183
184static VALUE
185no_fallback(VALUE obj, VALUE name)
186{
187 return name;
188}
189
190VALUE
192{
193 int permanent;
194 return rb_tmp_class_path(klass, &permanent, no_fallback);
195}
196
197static VALUE
198build_const_pathname(VALUE head, VALUE tail)
199{
200 VALUE path = rb_str_dup(head);
201 rb_str_cat2(path, "::");
202 rb_str_append(path, tail);
203 OBJ_FREEZE(path);
204 return path;
205}
206
207static VALUE
208build_const_path(VALUE head, ID tail)
209{
210 return build_const_pathname(head, rb_id2str(tail));
211}
212
213void
215{
216 VALUE str;
217 ID pathid = classpath;
218
219 if (under == rb_cObject) {
221 }
222 else {
223 int permanent;
224 str = rb_tmp_class_path(under, &permanent, make_temporary_path);
225 str = build_const_pathname(str, name);
226 if (!permanent) {
227 pathid = tmp_classpath;
228 }
229 }
230 rb_ivar_set(klass, pathid, str);
231}
232
233void
234rb_set_class_path(VALUE klass, VALUE under, const char *name)
235{
238 rb_set_class_path_string(klass, under, str);
239}
240
241VALUE
243{
244 rb_encoding *enc = rb_enc_get(pathname);
245 const char *pbeg, *pend, *p, *path = RSTRING_PTR(pathname);
246 ID id;
247 VALUE c = rb_cObject;
248
249 if (!rb_enc_asciicompat(enc)) {
250 rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
251 }
252 pbeg = p = path;
253 pend = path + RSTRING_LEN(pathname);
254 if (path == pend || path[0] == '#') {
255 rb_raise(rb_eArgError, "can't retrieve anonymous class %"PRIsVALUE,
256 QUOTE(pathname));
257 }
258 while (p < pend) {
259 while (p < pend && *p != ':') p++;
260 id = rb_check_id_cstr(pbeg, p-pbeg, enc);
261 if (p < pend && p[0] == ':') {
262 if ((size_t)(pend - p) < 2 || p[1] != ':') goto undefined_class;
263 p += 2;
264 pbeg = p;
265 }
266 if (!id) {
267 goto undefined_class;
268 }
269 c = rb_const_search(c, id, TRUE, FALSE, FALSE);
270 if (c == Qundef) goto undefined_class;
271 if (!rb_namespace_p(c)) {
272 rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
273 pathname);
274 }
275 }
276 RB_GC_GUARD(pathname);
277
278 return c;
279
280 undefined_class:
281 rb_raise(rb_eArgError, "undefined class/module % "PRIsVALUE,
282 rb_str_subseq(pathname, 0, p-path));
284}
285
286VALUE
287rb_path2class(const char *path)
288{
289 return rb_path_to_class(rb_str_new_cstr(path));
290}
291
292VALUE
294{
295 return rb_class_path(rb_class_real(klass));
296}
297
298const char *
300{
301 int permanent;
302 VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, make_temporary_path);
303 if (NIL_P(path)) return NULL;
304 return RSTRING_PTR(path);
305}
306
307const char *
309{
310 return rb_class2name(CLASS_OF(obj));
311}
312
313struct trace_var {
315 void (*func)(VALUE arg, VALUE val);
318};
319
329};
330
335};
336
337static struct rb_global_entry*
338rb_find_global_entry(ID id)
339{
340 struct rb_global_entry *entry;
341 VALUE data;
342
343 if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
344 entry = NULL;
345 }
346 else {
347 entry = (struct rb_global_entry *)data;
348 RUBY_ASSERT(entry != NULL);
349 }
350
351 if (UNLIKELY(!rb_ractor_main_p()) && (!entry || !entry->ractor_local)) {
352 rb_raise(rb_eRactorIsolationError, "can not access global variables %s from non-main Ractors", rb_id2name(id));
353 }
354
355 return entry;
356}
357
358void
360{
361 struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
362 entry->ractor_local = true;
363}
364
365static void
366rb_gvar_undef_compactor(void *var)
367{
368}
369
370static struct rb_global_entry*
372{
373 struct rb_global_entry *entry = rb_find_global_entry(id);
374 if (!entry) {
375 struct rb_global_variable *var;
376 entry = ALLOC(struct rb_global_entry);
377 var = ALLOC(struct rb_global_variable);
378 entry->id = id;
379 entry->var = var;
380 entry->ractor_local = false;
381 var->counter = 1;
382 var->data = 0;
386 var->compactor = rb_gvar_undef_compactor;
387
388 var->block_trace = 0;
389 var->trace = 0;
390 rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
391 }
392 return entry;
393}
394
395VALUE
397{
398 rb_warning("global variable `%"PRIsVALUE"' not initialized", QUOTE_ID(id));
399
400 return Qnil;
401}
402
403static void
404rb_gvar_val_compactor(void *_var)
405{
406 struct rb_global_variable *var = (struct rb_global_variable *)_var;
407
408 VALUE obj = (VALUE)var->data;
409
410 if (obj) {
411 VALUE new = rb_gc_location(obj);
412 if (new != obj) {
413 var->data = (void*)new;
414 }
415 }
416}
417
418void
420{
421 struct rb_global_variable *var = rb_global_entry(id)->var;
425 var->compactor = rb_gvar_val_compactor;
426
427 var->data = (void*)val;
428}
429
430void
432{
433}
434
435VALUE
437{
438 return (VALUE)data;
439}
440
441void
443{
444 struct rb_global_variable *var = rb_global_entry(id)->var;
445 var->data = (void*)val;
446}
447
448void
450{
451 VALUE data = (VALUE)var;
453}
454
455VALUE
457{
458 if (!var) return Qnil;
459 return *var;
460}
461
462void
464{
465 *data = val;
466}
467
468void
470{
471 if (var) rb_gc_mark_maybe(*var);
472}
473
474void
476{
477 rb_name_error(id, "%"PRIsVALUE" is a read-only variable", QUOTE_ID(id));
478}
479
481mark_global_entry(VALUE v, void *ignored)
482{
483 struct rb_global_entry *entry = (struct rb_global_entry *)v;
484 struct trace_var *trace;
485 struct rb_global_variable *var = entry->var;
486
487 (*var->marker)(var->data);
488 trace = var->trace;
489 while (trace) {
491 trace = trace->next;
492 }
493 return ID_TABLE_CONTINUE;
494}
495
496void
498{
499 if (rb_global_tbl) {
500 rb_id_table_foreach_values(rb_global_tbl, mark_global_entry, 0);
501 }
502}
503
505update_global_entry(VALUE v, void *ignored)
506{
507 struct rb_global_entry *entry = (struct rb_global_entry *)v;
508 struct rb_global_variable *var = entry->var;
509
510 (*var->compactor)(var);
511 return ID_TABLE_CONTINUE;
512}
513
514void
516{
517 if (rb_global_tbl) {
518 rb_id_table_foreach_values(rb_global_tbl, update_global_entry, 0);
519 }
520}
521
522static ID
523global_id(const char *name)
524{
525 ID id;
526
527 if (name[0] == '$') id = rb_intern(name);
528 else {
529 size_t len = strlen(name);
530 VALUE vbuf = 0;
531 char *buf = ALLOCV_N(char, vbuf, len+1);
532 buf[0] = '$';
533 memcpy(buf+1, name, len);
534 id = rb_intern2(buf, len+1);
535 ALLOCV_END(vbuf);
536 }
537 return id;
538}
539
540static ID
541find_global_id(const char *name)
542{
543 ID id;
544 size_t len = strlen(name);
545
546 if (name[0] == '$') {
548 }
549 else {
550 VALUE vbuf = 0;
551 char *buf = ALLOCV_N(char, vbuf, len+1);
552 buf[0] = '$';
553 memcpy(buf+1, name, len);
554 id = rb_check_id_cstr(buf, len+1, NULL);
555 ALLOCV_END(vbuf);
556 }
557
558 return id;
559}
560
561void
563 const char *name,
564 VALUE *var,
567{
568 volatile VALUE tmp = var ? *var : Qnil;
569 ID id = global_id(name);
570 struct rb_global_variable *gvar = rb_global_entry(id)->var;
571
572 gvar->data = (void*)var;
576
577 RB_GC_GUARD(tmp);
578}
579
580void
581rb_define_variable(const char *name, VALUE *var)
582{
584}
585
586void
587rb_define_readonly_variable(const char *name, const VALUE *var)
588{
590}
591
592void
594 const char *name,
597{
601}
602
603static void
604rb_trace_eval(VALUE cmd, VALUE val)
605{
607}
608
609VALUE
611{
612 VALUE var, cmd;
613 struct rb_global_entry *entry;
614 struct trace_var *trace;
615
616 if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
617 cmd = rb_block_proc();
618 }
619 if (NIL_P(cmd)) {
620 return rb_f_untrace_var(argc, argv);
621 }
622 entry = rb_global_entry(rb_to_id(var));
623 trace = ALLOC(struct trace_var);
624 trace->next = entry->var->trace;
625 trace->func = rb_trace_eval;
626 trace->data = cmd;
627 trace->removed = 0;
628 entry->var->trace = trace;
629
630 return Qnil;
631}
632
633static void
634remove_trace(struct rb_global_variable *var)
635{
636 struct trace_var *trace = var->trace;
637 struct trace_var t;
638 struct trace_var *next;
639
640 t.next = trace;
641 trace = &t;
642 while (trace->next) {
643 next = trace->next;
644 if (next->removed) {
645 trace->next = next->next;
646 xfree(next);
647 }
648 else {
649 trace = next;
650 }
651 }
652 var->trace = t.next;
653}
654
655VALUE
657{
658 VALUE var, cmd;
659 ID id;
660 struct rb_global_entry *entry;
661 struct trace_var *trace;
662
663 rb_scan_args(argc, argv, "11", &var, &cmd);
664 id = rb_check_id(&var);
665 if (!id) {
666 rb_name_error_str(var, "undefined global variable %"PRIsVALUE"", QUOTE(var));
667 }
668 if ((entry = rb_find_global_entry(id)) == NULL) {
669 rb_name_error(id, "undefined global variable %"PRIsVALUE"", QUOTE_ID(id));
670 }
671
672 trace = entry->var->trace;
673 if (NIL_P(cmd)) {
674 VALUE ary = rb_ary_new();
675
676 while (trace) {
677 struct trace_var *next = trace->next;
678 rb_ary_push(ary, (VALUE)trace->data);
679 trace->removed = 1;
680 trace = next;
681 }
682
683 if (!entry->var->block_trace) remove_trace(entry->var);
684 return ary;
685 }
686 else {
687 while (trace) {
688 if (trace->data == cmd) {
689 trace->removed = 1;
690 if (!entry->var->block_trace) remove_trace(entry->var);
691 return rb_ary_new3(1, cmd);
692 }
693 trace = trace->next;
694 }
695 }
696 return Qnil;
697}
698
702};
703
704static VALUE
705trace_ev(VALUE v)
706{
707 struct trace_data *data = (void *)v;
708 struct trace_var *trace = data->trace;
709
710 while (trace) {
711 (*trace->func)(trace->data, data->val);
712 trace = trace->next;
713 }
714
715 return Qnil;
716}
717
718static VALUE
719trace_en(VALUE v)
720{
721 struct rb_global_variable *var = (void *)v;
722 var->block_trace = 0;
723 remove_trace(var);
724 return Qnil; /* not reached */
725}
726
727static VALUE
728rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val)
729{
730 struct trace_data trace;
731 struct rb_global_variable *var = entry->var;
732
733 (*var->setter)(val, entry->id, var->data);
734
735 if (var->trace && !var->block_trace) {
736 var->block_trace = 1;
737 trace.trace = var->trace;
738 trace.val = val;
739 rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
740 }
741 return val;
742}
743
744VALUE
746{
747 struct rb_global_entry *entry;
748 entry = rb_global_entry(id);
749
750 return rb_gvar_set_entry(entry, val);
751}
752
753VALUE
754rb_gv_set(const char *name, VALUE val)
755{
756 return rb_gvar_set(global_id(name), val);
757}
758
759VALUE
761{
762 struct rb_global_entry *entry = rb_global_entry(id);
763 struct rb_global_variable *var = entry->var;
764 return (*var->getter)(entry->id, var->data);
765}
766
767VALUE
768rb_gv_get(const char *name)
769{
770 ID id = find_global_id(name);
771
772 if (!id) {
773 rb_warning("global variable `%s' not initialized", name);
774 return Qnil;
775 }
776
777 return rb_gvar_get(id);
778}
779
782{
783 struct rb_global_entry *entry = rb_global_entry(id);
784 if (entry->var->getter == rb_gvar_undef_getter) return Qfalse;
785 return Qtrue;
786}
787
790{
791 const struct rb_global_entry *entry = rb_global_entry(id);
792 return entry->var->getter;
793}
794
797{
798 const struct rb_global_entry *entry = rb_global_entry(id);
799 return entry->var->setter;
800}
801
803gvar_i(ID key, VALUE val, void *a)
804{
805 VALUE ary = (VALUE)a;
806 rb_ary_push(ary, ID2SYM(key));
807 return ID_TABLE_CONTINUE;
808}
809
810VALUE
812{
813 VALUE ary = rb_ary_new();
814 VALUE sym, backref = rb_backref_get();
815
816 if (!rb_ractor_main_p()) {
817 rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
818 }
819
820 rb_id_table_foreach(rb_global_tbl, gvar_i, (void *)ary);
821 if (!NIL_P(backref)) {
822 char buf[2];
823 int i, nmatch = rb_match_count(backref);
824 buf[0] = '$';
825 for (i = 1; i <= nmatch; ++i) {
826 if (!rb_match_nth_defined(i, backref)) continue;
827 if (i < 10) {
828 /* probably reused, make static ID */
829 buf[1] = (char)(i + '0');
830 sym = ID2SYM(rb_intern2(buf, 2));
831 }
832 else {
833 /* dynamic symbol */
834 sym = rb_str_intern(rb_sprintf("$%d", i));
835 }
836 rb_ary_push(ary, sym);
837 }
838 }
839 return ary;
840}
841
842void
844{
845 struct rb_global_entry *entry1, *entry2;
846 VALUE data1;
847 struct rb_id_table *gtbl = rb_global_tbl;
848
849 if (!rb_ractor_main_p()) {
850 rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
851 }
852
853 entry2 = rb_global_entry(name2);
854 if (!rb_id_table_lookup(gtbl, name1, &data1)) {
855 entry1 = ALLOC(struct rb_global_entry);
856 entry1->id = name1;
857 rb_id_table_insert(gtbl, name1, (VALUE)entry1);
858 }
859 else if ((entry1 = (struct rb_global_entry *)data1)->var != entry2->var) {
860 struct rb_global_variable *var = entry1->var;
861 if (var->block_trace) {
862 rb_raise(rb_eRuntimeError, "can't alias in tracer");
863 }
864 var->counter--;
865 if (var->counter == 0) {
866 struct trace_var *trace = var->trace;
867 while (trace) {
868 struct trace_var *next = trace->next;
869 xfree(trace);
870 trace = next;
871 }
872 xfree(var);
873 }
874 }
875 else {
876 return;
877 }
878 entry2->var->counter++;
879 entry1->var = entry2->var;
880}
881
882static bool
883iv_index_tbl_lookup(struct st_table *tbl, ID id, uint32_t *indexp)
884{
885 struct rb_iv_index_tbl_entry *ent;
886 int r;
887
888 if (tbl == NULL) return false;
889
891 {
892 r = st_lookup(tbl, (st_data_t)id, (st_data_t *)&ent);
893 }
895
896 if (r) {
897 *indexp = ent->index;
898 return true;
899 }
900 else {
901 return false;
902 }
903}
904
905static void
906IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
907{
908 if (UNLIKELY(!rb_ractor_main_p())) {
909 if (rb_is_instance_id(id)) { // check only normal ivars
910 rb_raise(rb_eRactorIsolationError, "can not access instance variables of classes/modules from non-main Ractors");
911 }
912 }
913}
914
915#define CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() \
916 if (UNLIKELY(!rb_ractor_main_p())) { \
917 rb_raise(rb_eRactorIsolationError, "can not access class variables from non-main Ractors"); \
918 }
919
920static inline struct st_table *
921generic_ivtbl(VALUE obj, ID id, bool force_check_ractor)
922{
924
925 if ((force_check_ractor || LIKELY(rb_is_instance_id(id)) /* not internal ID */ ) &&
926 !RB_OBJ_FROZEN_RAW(obj) &&
927 UNLIKELY(!rb_ractor_main_p()) &&
928 UNLIKELY(rb_ractor_shareable_p(obj))) {
929
930 rb_raise(rb_eRactorIsolationError, "can not access instance variables of shareable objects from non-main Ractors");
931 }
932 return generic_iv_tbl_;
933}
934
935static inline struct st_table *
936generic_ivtbl_no_ractor_check(VALUE obj)
937{
938 return generic_ivtbl(obj, 0, false);
939}
940
941static int
942gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl)
943{
944 st_data_t data;
945 int r = 0;
946
948 {
949 if (st_lookup(generic_ivtbl(obj, id, false), (st_data_t)obj, &data)) {
950 *ivtbl = (struct gen_ivtbl *)data;
951 r = 1;
952 }
953 }
955
956 return r;
957}
958
961{
962 return gen_ivtbl_get(obj, 0, ivtbl);
963}
964
967{
968 struct gen_ivtbl *ivtbl;
969
970 if (gen_ivtbl_get(obj, id, &ivtbl)) {
971 if (LIKELY(index < ivtbl->numiv)) {
972 VALUE val = ivtbl->ivptr[index];
973 return val;
974 }
975 }
976
977 return Qundef;
978}
979
980static VALUE
981generic_ivar_delete(VALUE obj, ID id, VALUE undef)
982{
983 struct gen_ivtbl *ivtbl;
984
985 if (gen_ivtbl_get(obj, id, &ivtbl)) {
986 st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
987 uint32_t index;
988
989 if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) {
990 if (index < ivtbl->numiv) {
991 VALUE ret = ivtbl->ivptr[index];
992
993 ivtbl->ivptr[index] = Qundef;
994 return ret == Qundef ? undef : ret;
995 }
996 }
997 }
998 return undef;
999}
1000
1001static VALUE
1002generic_ivar_get(VALUE obj, ID id, VALUE undef)
1003{
1004 struct gen_ivtbl *ivtbl;
1005
1006 if (gen_ivtbl_get(obj, id, &ivtbl)) {
1007 st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1008 uint32_t index;
1009
1010 if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) {
1011 if (index < ivtbl->numiv) {
1012 VALUE ret = ivtbl->ivptr[index];
1013
1014 return ret == Qundef ? undef : ret;
1015 }
1016 }
1017 }
1018 return undef;
1019}
1020
1021static size_t
1022gen_ivtbl_bytes(size_t n)
1023{
1024 return offsetof(struct gen_ivtbl, ivptr) + n * sizeof(VALUE);
1025}
1026
1027static struct gen_ivtbl *
1028gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n)
1029{
1030 uint32_t len = old ? old->numiv : 0;
1031 struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
1032
1033 ivtbl->numiv = n;
1034 for (; len < n; len++) {
1035 ivtbl->ivptr[len] = Qundef;
1036 }
1037
1038 return ivtbl;
1039}
1040
1041#if 0
1042static struct gen_ivtbl *
1043gen_ivtbl_dup(const struct gen_ivtbl *orig)
1044{
1045 size_t s = gen_ivtbl_bytes(orig->numiv);
1046 struct gen_ivtbl *ivtbl = xmalloc(s);
1047
1048 memcpy(ivtbl, orig, s);
1049
1050 return ivtbl;
1051}
1052#endif
1053
1054static uint32_t
1055iv_index_tbl_newsize(struct ivar_update *ivup)
1056{
1057 if (!ivup->iv_extended) {
1058 return (uint32_t)ivup->u.iv_index_tbl->num_entries;
1059 }
1060 else {
1061 uint32_t index = (uint32_t)ivup->index; /* should not overflow */
1062 return (index+1) + (index+1)/4; /* (index+1)*1.25 */
1063 }
1064}
1065
1066static int
1067generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
1068{
1070
1071 struct ivar_update *ivup = (struct ivar_update *)u;
1072 struct gen_ivtbl *ivtbl = 0;
1073
1074 if (existing) {
1075 ivtbl = (struct gen_ivtbl *)*v;
1076 if (ivup->index < ivtbl->numiv) {
1077 ivup->u.ivtbl = ivtbl;
1078 return ST_STOP;
1079 }
1080 }
1081 FL_SET((VALUE)*k, FL_EXIVAR);
1082 uint32_t newsize = iv_index_tbl_newsize(ivup);
1083 ivtbl = gen_ivtbl_resize(ivtbl, newsize);
1084 *v = (st_data_t)ivtbl;
1085 ivup->u.ivtbl = ivtbl;
1086 return ST_CONTINUE;
1087}
1088
1089static VALUE
1090generic_ivar_defined(VALUE obj, ID id)
1091{
1092 struct gen_ivtbl *ivtbl;
1093 st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1094 uint32_t index;
1095
1096 if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return Qfalse;
1097 if (!gen_ivtbl_get(obj, id, &ivtbl)) return Qfalse;
1098
1099 if ((index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef))
1100 return Qtrue;
1101
1102 return Qfalse;
1103}
1104
1105static int
1106generic_ivar_remove(VALUE obj, ID id, VALUE *valp)
1107{
1108 struct gen_ivtbl *ivtbl;
1109 uint32_t index;
1110 st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1111
1112 if (!iv_index_tbl) return 0;
1113 if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return 0;
1114 if (!gen_ivtbl_get(obj, id, &ivtbl)) return 0;
1115
1116 if (index < ivtbl->numiv) {
1117 if (ivtbl->ivptr[index] != Qundef) {
1118 *valp = ivtbl->ivptr[index];
1119 ivtbl->ivptr[index] = Qundef;
1120 return 1;
1121 }
1122 }
1123 return 0;
1124}
1125
1126static void
1127gen_ivtbl_mark(const struct gen_ivtbl *ivtbl)
1128{
1129 uint32_t i;
1130
1131 for (i = 0; i < ivtbl->numiv; i++) {
1132 rb_gc_mark(ivtbl->ivptr[i]);
1133 }
1134}
1135
1136void
1138{
1139 struct gen_ivtbl *ivtbl;
1140
1141 if (gen_ivtbl_get(obj, 0, &ivtbl)) {
1142 gen_ivtbl_mark(ivtbl);
1143 }
1144}
1145
1146void
1148{
1149 st_data_t key = (st_data_t)rsrc;
1150 struct gen_ivtbl *ivtbl;
1151
1152 if (st_delete(generic_ivtbl_no_ractor_check(rsrc), &key, (st_data_t *)&ivtbl))
1153 st_insert(generic_ivtbl_no_ractor_check(dst), (st_data_t)dst, (st_data_t)ivtbl);
1154}
1155
1156void
1158{
1159 st_data_t key = (st_data_t)obj;
1160 struct gen_ivtbl *ivtbl;
1161
1162 if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, (st_data_t *)&ivtbl))
1163 xfree(ivtbl);
1164}
1165
1166RUBY_FUNC_EXPORTED size_t
1168{
1169 struct gen_ivtbl *ivtbl;
1170
1171 if (gen_ivtbl_get(obj, 0, &ivtbl))
1172 return gen_ivtbl_bytes(ivtbl->numiv);
1173 return 0;
1174}
1175
1176static size_t
1177gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
1178{
1179 uint32_t i;
1180 size_t n = 0;
1181
1182 for (i = 0; i < ivtbl->numiv; i++) {
1183 if (ivtbl->ivptr[i] != Qundef) {
1184 n++;
1185 }
1186 }
1187
1188 return n;
1189}
1190
1191VALUE
1193{
1194 VALUE val;
1195
1196 if (SPECIAL_CONST_P(obj)) return undef;
1197 switch (BUILTIN_TYPE(obj)) {
1198 case T_OBJECT:
1199 {
1200 uint32_t index;
1201 uint32_t len = ROBJECT_NUMIV(obj);
1202 VALUE *ptr = ROBJECT_IVPTR(obj);
1203
1204 if (iv_index_tbl_lookup(ROBJECT_IV_INDEX_TBL(obj), id, &index) &&
1205 index < len &&
1206 (val = ptr[index]) != Qundef) {
1207 return val;
1208 }
1209 else {
1210 break;
1211 }
1212 }
1213 case T_CLASS:
1214 case T_MODULE:
1215 {
1216 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1217 if (RCLASS_IV_TBL(obj) &&
1218 st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, (st_data_t *)&val)) {
1219 return val;
1220 }
1221 else {
1222 break;
1223 }
1224 }
1225 default:
1226 if (FL_TEST(obj, FL_EXIVAR))
1227 return generic_ivar_get(obj, id, undef);
1228 break;
1229 }
1230 return undef;
1231}
1232
1233VALUE
1235{
1236 VALUE iv = rb_ivar_lookup(obj, id, Qnil);
1237 RB_DEBUG_COUNTER_INC(ivar_get_base);
1238 return iv;
1239}
1240
1241VALUE
1243{
1244 return rb_ivar_lookup(obj, id, Qnil);
1245}
1246
1247static VALUE
1248rb_ivar_delete(VALUE obj, ID id, VALUE undef)
1249{
1250 VALUE val, *ptr;
1251 struct st_table *iv_index_tbl;
1252 uint32_t len, index;
1253
1254 rb_check_frozen(obj);
1255 switch (BUILTIN_TYPE(obj)) {
1256 case T_OBJECT:
1257 len = ROBJECT_NUMIV(obj);
1258 ptr = ROBJECT_IVPTR(obj);
1259 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1260 if (iv_index_tbl_lookup(iv_index_tbl, id, &index) &&
1261 index < len) {
1262 val = ptr[index];
1263 ptr[index] = Qundef;
1264
1265 if (val != Qundef) {
1266 return val;
1267 }
1268 }
1269 break;
1270 case T_CLASS:
1271 case T_MODULE:
1272 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1273 if (RCLASS_IV_TBL(obj) &&
1274 st_delete(RCLASS_IV_TBL(obj), (st_data_t *)&id, (st_data_t *)&val)) {
1275 return val;
1276 }
1277 break;
1278 default:
1279 if (FL_TEST(obj, FL_EXIVAR))
1280 return generic_ivar_delete(obj, id, undef);
1281 break;
1282 }
1283 return undef;
1284}
1285
1286VALUE
1288{
1289 return rb_ivar_delete(obj, id, Qnil);
1290}
1291
1292static st_table *
1293iv_index_tbl_make(VALUE obj, VALUE klass)
1294{
1295 st_table *iv_index_tbl;
1296
1297 if (UNLIKELY(!klass)) {
1298 rb_raise(rb_eTypeError, "hidden object cannot have instance variables");
1299 }
1300
1301 if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) {
1303 if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) {
1304 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
1305 }
1307 }
1308
1309 return iv_index_tbl;
1310}
1311
1312static void
1313iv_index_tbl_extend(struct ivar_update *ivup, ID id, VALUE klass)
1314{
1316 struct rb_iv_index_tbl_entry *ent;
1317
1318 if (st_lookup(ivup->u.iv_index_tbl, (st_data_t)id, (st_data_t *)&ent)) {
1319 ivup->index = ent->index;
1320 return;
1321 }
1322 if (ivup->u.iv_index_tbl->num_entries >= INT_MAX) {
1323 rb_raise(rb_eArgError, "too many instance variables");
1324 }
1325 ent = ALLOC(struct rb_iv_index_tbl_entry);
1326 ent->index = ivup->index = (uint32_t)ivup->u.iv_index_tbl->num_entries;
1327 ent->class_value = klass;
1328 ent->class_serial = RCLASS_SERIAL(klass);
1330 ivup->iv_extended = 1;
1331}
1332
1333static void
1334generic_ivar_set(VALUE obj, ID id, VALUE val)
1335{
1336 VALUE klass = rb_obj_class(obj);
1337 struct ivar_update ivup;
1338 ivup.iv_extended = 0;
1339 ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass);
1340
1342 {
1343 iv_index_tbl_extend(&ivup, id, klass);
1344 st_update(generic_ivtbl(obj, id, false), (st_data_t)obj, generic_ivar_update,
1345 (st_data_t)&ivup);
1346 }
1348
1349 ivup.u.ivtbl->ivptr[ivup.index] = val;
1350
1351 RB_OBJ_WRITTEN(obj, Qundef, val);
1352}
1353
1354static VALUE *
1355obj_ivar_heap_alloc(VALUE obj, size_t newsize)
1356{
1357 VALUE *newptr = rb_transient_heap_alloc(obj, sizeof(VALUE) * newsize);
1358
1359 if (newptr != NULL) {
1360 ROBJ_TRANSIENT_SET(obj);
1361 }
1362 else {
1363 ROBJ_TRANSIENT_UNSET(obj);
1364 newptr = ALLOC_N(VALUE, newsize);
1365 }
1366 return newptr;
1367}
1368
1369static VALUE *
1370obj_ivar_heap_realloc(VALUE obj, int32_t len, size_t newsize)
1371{
1372 VALUE *newptr;
1373 int i;
1374
1375 if (ROBJ_TRANSIENT_P(obj)) {
1376 const VALUE *orig_ptr = ROBJECT(obj)->as.heap.ivptr;
1377 newptr = obj_ivar_heap_alloc(obj, newsize);
1378
1379 assert(newptr);
1380 ROBJECT(obj)->as.heap.ivptr = newptr;
1381 for (i=0; i<(int)len; i++) {
1382 newptr[i] = orig_ptr[i];
1383 }
1384 }
1385 else {
1386 REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
1387 newptr = ROBJECT(obj)->as.heap.ivptr;
1388 }
1389
1390 return newptr;
1391}
1392
1393#if USE_TRANSIENT_HEAP
1394void
1395rb_obj_transient_heap_evacuate(VALUE obj, int promote)
1396{
1397 if (ROBJ_TRANSIENT_P(obj)) {
1398 uint32_t len = ROBJECT_NUMIV(obj);
1399 const VALUE *old_ptr = ROBJECT_IVPTR(obj);
1400 VALUE *new_ptr;
1401
1402 if (promote) {
1403 new_ptr = ALLOC_N(VALUE, len);
1404 ROBJ_TRANSIENT_UNSET(obj);
1405 }
1406 else {
1407 new_ptr = obj_ivar_heap_alloc(obj, len);
1408 }
1409 MEMCPY(new_ptr, old_ptr, VALUE, len);
1410 ROBJECT(obj)->as.heap.ivptr = new_ptr;
1411 }
1412}
1413#endif
1414
1415static void
1416init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table *index_tbl)
1417{
1418 VALUE *ptr = ROBJECT_IVPTR(obj);
1419 VALUE *newptr;
1420
1421 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
1422 newptr = obj_ivar_heap_alloc(obj, newsize);
1423 MEMCPY(newptr, ptr, VALUE, len);
1424 RBASIC(obj)->flags &= ~ROBJECT_EMBED;
1425 ROBJECT(obj)->as.heap.ivptr = newptr;
1426 } else {
1427 newptr = obj_ivar_heap_realloc(obj, len, newsize);
1428 }
1429
1430 for (; len < newsize; len++) {
1431 newptr[len] = Qundef;
1432 }
1433 ROBJECT(obj)->as.heap.numiv = newsize;
1434 ROBJECT(obj)->as.heap.iv_index_tbl = index_tbl;
1435}
1436
1437void
1439{
1440 st_table *index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1441 uint32_t newsize = (uint32_t)index_tbl->num_entries;
1442 uint32_t len = ROBJECT_NUMIV(obj);
1443 init_iv_list(obj, len, newsize, index_tbl);
1444}
1445
1446static VALUE
1447obj_ivar_set(VALUE obj, ID id, VALUE val)
1448{
1449 VALUE klass = rb_obj_class(obj);
1450 struct ivar_update ivup;
1451 uint32_t len;
1452 ivup.iv_extended = 0;
1453 ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass);
1454
1456 {
1457 iv_index_tbl_extend(&ivup, id, klass);
1458 }
1460
1461 len = ROBJECT_NUMIV(obj);
1462 if (len <= ivup.index) {
1463 uint32_t newsize = iv_index_tbl_newsize(&ivup);
1464 init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl);
1465 }
1466 RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
1467
1468 return val;
1469}
1470
1471static void
1472ivar_set(VALUE obj, ID id, VALUE val)
1473{
1474 RB_DEBUG_COUNTER_INC(ivar_set_base);
1475
1476 switch (BUILTIN_TYPE(obj)) {
1477 case T_OBJECT:
1478 obj_ivar_set(obj, id, val);
1479 break;
1480 case T_CLASS:
1481 case T_MODULE:
1482 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1483 if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
1484 rb_class_ivar_set(obj, id, val);
1485 break;
1486 default:
1487 generic_ivar_set(obj, id, val);
1488 break;
1489 }
1490}
1491
1492VALUE
1494{
1495 rb_check_frozen(obj);
1496 ivar_set(obj, id, val);
1497 return val;
1498}
1499
1500void
1502{
1503 // should be internal instance variable name (no @ prefix)
1505
1506 ivar_set(obj, id, val);
1507}
1508
1509VALUE
1511{
1512 VALUE val;
1513 struct st_table *iv_index_tbl;
1514 uint32_t index;
1515
1516 if (SPECIAL_CONST_P(obj)) return Qfalse;
1517 switch (BUILTIN_TYPE(obj)) {
1518 case T_OBJECT:
1519 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1520 if (iv_index_tbl_lookup(iv_index_tbl, id, &index) &&
1521 index < ROBJECT_NUMIV(obj) &&
1522 (val = ROBJECT_IVPTR(obj)[index]) != Qundef) {
1523 return Qtrue;
1524 }
1525 break;
1526 case T_CLASS:
1527 case T_MODULE:
1528 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1529 if (RCLASS_IV_TBL(obj) && st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id))
1530 return Qtrue;
1531 break;
1532 default:
1533 if (FL_TEST(obj, FL_EXIVAR))
1534 return generic_ivar_defined(obj, id);
1535 break;
1536 }
1537 return Qfalse;
1538}
1539
1542
1543static ID
1544iv_index_tbl_nth_id(st_table *iv_index_tbl, uint32_t index)
1545{
1546 st_data_t key;
1548 {
1549 key = rb_st_nth_key(iv_index_tbl, index);
1550 }
1552 return (ID)key;
1553}
1554
1555static inline bool
1556ivar_each_i(st_table *iv_index_tbl, VALUE val, uint32_t i, rb_ivar_foreach_callback_func *func, st_data_t arg)
1557{
1558 if (val != Qundef) {
1559 ID id = iv_index_tbl_nth_id(iv_index_tbl, i);
1560 switch (func(id, val, arg)) {
1561 case ST_CHECK:
1562 case ST_CONTINUE:
1563 break;
1564 case ST_STOP:
1565 return true;
1566 default:
1567 rb_bug("unreachable");
1568 }
1569 }
1570 return false;
1571}
1572
1573static void
1574obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
1575{
1576 st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1577 if (!iv_index_tbl) return;
1578 uint32_t i=0;
1579
1580 for (i=0; i < ROBJECT_NUMIV(obj); i++) {
1581 VALUE val = ROBJECT_IVPTR(obj)[i];
1582 if (ivar_each_i(iv_index_tbl, val, i, func, arg)) {
1583 return;
1584 }
1585 }
1586}
1587
1588static void
1589gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
1590{
1591 struct gen_ivtbl *ivtbl;
1592 st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1593 if (!iv_index_tbl) return;
1594 if (!gen_ivtbl_get(obj, 0, &ivtbl)) return;
1595
1596 for (uint32_t i=0; i<ivtbl->numiv; i++) {
1597 VALUE val = ivtbl->ivptr[i];
1598 if (ivar_each_i(iv_index_tbl, val, i, func, arg)) {
1599 return;
1600 }
1601 }
1602}
1603
1609};
1610
1611static int
1612gen_ivar_copy(ID id, VALUE val, st_data_t arg)
1613{
1614 struct givar_copy *c = (struct givar_copy *)arg;
1615 struct ivar_update ivup;
1616
1617 ivup.iv_extended = 0;
1618 ivup.u.iv_index_tbl = c->iv_index_tbl;
1619
1621 {
1622 iv_index_tbl_extend(&ivup, id, c->klass);
1623 }
1625
1626 if (ivup.index >= c->ivtbl->numiv) {
1627 uint32_t newsize = iv_index_tbl_newsize(&ivup);
1628 c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize);
1629 }
1630 c->ivtbl->ivptr[ivup.index] = val;
1631
1632 RB_OBJ_WRITTEN(c->obj, Qundef, val);
1633
1634 return ST_CONTINUE;
1635}
1636
1637void
1639{
1640 struct gen_ivtbl *ivtbl;
1641
1642 rb_check_frozen(clone);
1643
1644 if (!FL_TEST(obj, FL_EXIVAR)) {
1645 goto clear;
1646 }
1647 if (gen_ivtbl_get(obj, 0, &ivtbl)) {
1648 struct givar_copy c;
1649 uint32_t i;
1650
1651 if (gen_ivtbl_count(ivtbl) == 0)
1652 goto clear;
1653
1654 if (gen_ivtbl_get(clone, 0, &c.ivtbl)) {
1655 for (i = 0; i < c.ivtbl->numiv; i++)
1656 c.ivtbl->ivptr[i] = Qundef;
1657 }
1658 else {
1659 c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv);
1660 FL_SET(clone, FL_EXIVAR);
1661 }
1662
1663 VALUE klass = rb_obj_class(clone);
1664 c.iv_index_tbl = iv_index_tbl_make(clone, klass);
1665 c.obj = clone;
1666 c.klass = klass;
1667 gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c);
1668 /*
1669 * c.ivtbl may change in gen_ivar_copy due to realloc,
1670 * no need to free
1671 */
1673 {
1674 generic_ivtbl_no_ractor_check(clone);
1675 st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)c.ivtbl);
1676 }
1678 }
1679 return;
1680
1681 clear:
1682 if (FL_TEST(clone, FL_EXIVAR)) {
1683 rb_free_generic_ivar(clone);
1684 FL_UNSET(clone, FL_EXIVAR);
1685 }
1686}
1687
1688void
1690{
1692
1694 {
1695 struct gen_ivtbl **ivtbl;
1696 if (st_lookup(generic_iv_tbl_, (st_data_t)obj, (st_data_t *)&ivtbl)) {
1697 st_insert(generic_iv_tbl_, (st_data_t)clone, (st_data_t)ivtbl);
1698 st_delete(generic_iv_tbl_, (st_data_t *)&obj, NULL);
1699 }
1700 else {
1701 rb_bug("unreachable");
1702 }
1703 }
1705
1706 FL_SET(clone, FL_EXIVAR);
1707}
1708
1709void
1711{
1712 if (SPECIAL_CONST_P(obj)) return;
1713 switch (BUILTIN_TYPE(obj)) {
1714 case T_OBJECT:
1715 obj_ivar_each(obj, func, arg);
1716 break;
1717 case T_CLASS:
1718 case T_MODULE:
1719 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
1720 if (RCLASS_IV_TBL(obj)) {
1721 st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
1722 }
1723 break;
1724 default:
1725 if (FL_TEST(obj, FL_EXIVAR)) {
1726 gen_ivar_each(obj, func, arg);
1727 }
1728 break;
1729 }
1730}
1731
1734{
1735 st_table *tbl;
1736
1737 if (SPECIAL_CONST_P(obj)) return 0;
1738
1739 switch (BUILTIN_TYPE(obj)) {
1740 case T_OBJECT:
1741 if (ROBJECT_IV_INDEX_TBL(obj) != 0) {
1742 st_index_t i, count, num = ROBJECT_NUMIV(obj);
1743 const VALUE *const ivptr = ROBJECT_IVPTR(obj);
1744 for (i = count = 0; i < num; ++i) {
1745 if (ivptr[i] != Qundef) {
1746 count++;
1747 }
1748 }
1749 return count;
1750 }
1751 break;
1752 case T_CLASS:
1753 case T_MODULE:
1754 if ((tbl = RCLASS_IV_TBL(obj)) != 0) {
1755 return tbl->num_entries;
1756 }
1757 break;
1758 default:
1759 if (FL_TEST(obj, FL_EXIVAR)) {
1760 struct gen_ivtbl *ivtbl;
1761
1762 if (gen_ivtbl_get(obj, 0, &ivtbl)) {
1763 return gen_ivtbl_count(ivtbl);
1764 }
1765 }
1766 break;
1767 }
1768 return 0;
1769}
1770
1771static int
1772ivar_i(st_data_t k, st_data_t v, st_data_t a)
1773{
1774 ID key = (ID)k;
1775 VALUE ary = (VALUE)a;
1776
1777 if (rb_is_instance_id(key)) {
1778 rb_ary_push(ary, ID2SYM(key));
1779 }
1780 return ST_CONTINUE;
1781}
1782
1783/*
1784 * call-seq:
1785 * obj.instance_variables -> array
1786 *
1787 * Returns an array of instance variable names for the receiver. Note
1788 * that simply defining an accessor does not create the corresponding
1789 * instance variable.
1790 *
1791 * class Fred
1792 * attr_accessor :a1
1793 * def initialize
1794 * @iv = 3
1795 * end
1796 * end
1797 * Fred.new.instance_variables #=> [:@iv]
1798 */
1799
1800VALUE
1802{
1803 VALUE ary;
1804
1805 ary = rb_ary_new();
1806 rb_ivar_foreach(obj, ivar_i, ary);
1807 return ary;
1808}
1809
1810#define rb_is_constant_id rb_is_const_id
1811#define rb_is_constant_name rb_is_const_name
1812#define id_for_var(obj, name, part, type) \
1813 id_for_var_message(obj, name, type, "`%1$s' is not allowed as "#part" "#type" variable name")
1814#define id_for_var_message(obj, name, type, message) \
1815 check_id_type(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message))
1816static ID
1817check_id_type(VALUE obj, VALUE *pname,
1818 int (*valid_id_p)(ID), int (*valid_name_p)(VALUE),
1819 const char *message, size_t message_len)
1820{
1821 ID id = rb_check_id(pname);
1822 VALUE name = *pname;
1823
1824 if (id ? !valid_id_p(id) : !valid_name_p(name)) {
1825 rb_name_err_raise_str(rb_fstring_new(message, message_len),
1826 obj, name);
1827 }
1828 return id;
1829}
1830
1831/*
1832 * call-seq:
1833 * obj.remove_instance_variable(symbol) -> obj
1834 * obj.remove_instance_variable(string) -> obj
1835 *
1836 * Removes the named instance variable from <i>obj</i>, returning that
1837 * variable's value.
1838 * String arguments are converted to symbols.
1839 *
1840 * class Dummy
1841 * attr_reader :var
1842 * def initialize
1843 * @var = 99
1844 * end
1845 * def remove
1846 * remove_instance_variable(:@var)
1847 * end
1848 * end
1849 * d = Dummy.new
1850 * d.var #=> 99
1851 * d.remove #=> 99
1852 * d.var #=> nil
1853 */
1854
1855VALUE
1857{
1858 VALUE val = Qnil;
1859 const ID id = id_for_var(obj, name, an, instance);
1860 st_data_t n, v;
1861 struct st_table *iv_index_tbl;
1862 uint32_t index;
1863
1864 rb_check_frozen(obj);
1865 if (!id) {
1866 goto not_defined;
1867 }
1868
1869 switch (BUILTIN_TYPE(obj)) {
1870 case T_OBJECT:
1871 iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1872 if (iv_index_tbl_lookup(iv_index_tbl, id, &index) &&
1873 index < ROBJECT_NUMIV(obj) &&
1874 (val = ROBJECT_IVPTR(obj)[index]) != Qundef) {
1875 ROBJECT_IVPTR(obj)[index] = Qundef;
1876 return val;
1877 }
1878 break;
1879 case T_CLASS:
1880 case T_MODULE:
1881 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
1882 n = id;
1883 if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), &n, &v)) {
1884 return (VALUE)v;
1885 }
1886 break;
1887 default:
1888 if (FL_TEST(obj, FL_EXIVAR)) {
1889 if (generic_ivar_remove(obj, id, &val)) {
1890 return val;
1891 }
1892 }
1893 break;
1894 }
1895
1896 not_defined:
1897 rb_name_err_raise("instance variable %1$s not defined",
1898 obj, name);
1900}
1901
1902NORETURN(static void uninitialized_constant(VALUE, VALUE));
1903static void
1904uninitialized_constant(VALUE klass, VALUE name)
1905{
1906 if (klass && rb_class_real(klass) != rb_cObject)
1907 rb_name_err_raise("uninitialized constant %2$s::%1$s",
1908 klass, name);
1909 else
1910 rb_name_err_raise("uninitialized constant %1$s",
1911 klass, name);
1912}
1913
1914VALUE
1916{
1917 VALUE value = rb_funcallv(klass, idConst_missing, 1, &name);
1919 return value;
1920}
1921
1922
1923/*
1924 * call-seq:
1925 * mod.const_missing(sym) -> obj
1926 *
1927 * Invoked when a reference is made to an undefined constant in
1928 * <i>mod</i>. It is passed a symbol for the undefined constant, and
1929 * returns a value to be used for that constant. The
1930 * following code is an example of the same:
1931 *
1932 * def Foo.const_missing(name)
1933 * name # return the constant name as Symbol
1934 * end
1935 *
1936 * Foo::UNDEFINED_CONST #=> :UNDEFINED_CONST: symbol returned
1937 *
1938 * In the next example when a reference is made to an undefined constant,
1939 * it attempts to load a file whose name is the lowercase version of the
1940 * constant (thus class <code>Fred</code> is assumed to be in file
1941 * <code>fred.rb</code>). If found, it returns the loaded class. It
1942 * therefore implements an autoload feature similar to Kernel#autoload and
1943 * Module#autoload.
1944 *
1945 * def Object.const_missing(name)
1946 * @looked_for ||= {}
1947 * str_name = name.to_s
1948 * raise "Class not found: #{name}" if @looked_for[str_name]
1949 * @looked_for[str_name] = 1
1950 * file = str_name.downcase
1951 * require file
1952 * klass = const_get(name)
1953 * return klass if klass
1954 * raise "Class not found: #{name}"
1955 * end
1956 *
1957 */
1958
1959VALUE
1961{
1962 VALUE ref = GET_EC()->private_const_reference;
1964 if (ref) {
1965 rb_name_err_raise("private constant %2$s::%1$s referenced",
1966 ref, name);
1967 }
1968 uninitialized_constant(klass, name);
1969
1971}
1972
1973static void
1974autoload_mark(void *ptr)
1975{
1977}
1978
1979static void
1980autoload_free(void *ptr)
1981{
1983}
1984
1985static size_t
1986autoload_memsize(const void *ptr)
1987{
1988 const st_table *tbl = ptr;
1989 return st_memsize(tbl);
1990}
1991
1992static void
1993autoload_compact(void *ptr)
1994{
1996}
1997
1998static const rb_data_type_t autoload_data_type = {
1999 "autoload",
2000 {autoload_mark, autoload_free, autoload_memsize, autoload_compact,},
2002};
2003
2004#define check_autoload_table(av) \
2005 (struct st_table *)rb_check_typeddata((av), &autoload_data_type)
2006
2007static VALUE
2008autoload_data(VALUE mod, ID id)
2009{
2010 struct st_table *tbl;
2011 st_data_t val;
2012
2013 if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
2014 !(tbl = check_autoload_table((VALUE)val)) ||
2015 !st_lookup(tbl, (st_data_t)id, &val)) {
2016 return 0;
2017 }
2018 return (VALUE)val;
2019}
2020
2022 struct list_node cnode; /* <=> autoload_data_i.constants */
2024 VALUE ad; /* autoload_data_i */
2029 int line;
2030};
2031
2032/* always on stack, no need to mark */
2037 struct list_node waitq;
2038};
2039
2042 struct autoload_state *state; /* points to on-stack struct */
2044 struct list_head constants; /* <=> autoload_const.cnode */
2045};
2046
2047static void
2048autoload_i_compact(void *ptr)
2049{
2050 struct autoload_data_i *p = ptr;
2052}
2053
2054static void
2055autoload_i_mark(void *ptr)
2056{
2057 struct autoload_data_i *p = ptr;
2058
2060
2061 /* allow GC to free us if no modules refer to this via autoload_const.ad */
2062 if (list_empty(&p->constants)) {
2063 rb_hash_delete(autoload_featuremap, p->feature);
2064 }
2065}
2066
2067static void
2068autoload_i_free(void *ptr)
2069{
2070 struct autoload_data_i *p = ptr;
2071
2072 /* we may leak some memory at VM shutdown time, no big deal */
2073 if (list_empty(&p->constants)) {
2074 xfree(p);
2075 }
2076}
2077
2078static size_t
2079autoload_i_memsize(const void *ptr)
2080{
2081 return sizeof(struct autoload_data_i);
2082}
2083
2084static const rb_data_type_t autoload_data_i_type = {
2085 "autoload_i",
2086 {autoload_i_mark, autoload_i_free, autoload_i_memsize, autoload_i_compact},
2088};
2089
2090static void
2091autoload_c_compact(void *ptr)
2092{
2093 struct autoload_const *ac = ptr;
2094
2095 ac->mod = rb_gc_location(ac->mod);
2096 ac->ad = rb_gc_location(ac->ad);
2097 ac->value = rb_gc_location(ac->value);
2098 ac->file = rb_gc_location(ac->file);
2099}
2100
2101static void
2102autoload_c_mark(void *ptr)
2103{
2104 struct autoload_const *ac = ptr;
2105
2110}
2111
2112static void
2113autoload_c_free(void *ptr)
2114{
2115 struct autoload_const *ac = ptr;
2116 list_del(&ac->cnode);
2117 xfree(ac);
2118}
2119
2120static size_t
2121autoload_c_memsize(const void *ptr)
2122{
2123 return sizeof(struct autoload_const);
2124}
2125
2126static const rb_data_type_t autoload_const_type = {
2127 "autoload_const",
2128 {autoload_c_mark, autoload_c_free, autoload_c_memsize, autoload_c_compact,},
2130};
2131
2132static struct autoload_data_i *
2133get_autoload_data(VALUE acv, struct autoload_const **acp)
2134{
2135 struct autoload_const *ac = rb_check_typeddata(acv, &autoload_const_type);
2136 struct autoload_data_i *ele;
2137
2138 ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
2139 /* do not reach across stack for ->state after forking: */
2140 if (ele && ele->state && ele->fork_gen != GET_VM()->fork_gen) {
2141 ele->state = 0;
2142 ele->fork_gen = 0;
2143 }
2144 if (acp) *acp = ac;
2145 return ele;
2146}
2147
2148RUBY_FUNC_EXPORTED void
2149rb_autoload(VALUE mod, ID id, const char *file)
2150{
2151 if (!file || !*file) {
2152 rb_raise(rb_eArgError, "empty file name");
2153 }
2155}
2156
2157void
2159{
2160 st_data_t av;
2161 VALUE ad;
2162 struct st_table *tbl;
2163 struct autoload_data_i *ele;
2164 rb_const_entry_t *ce;
2165
2166 if (!rb_is_const_id(id)) {
2167 rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"",
2168 QUOTE_ID(id));
2169 }
2170
2171 Check_Type(file, T_STRING);
2172 if (!RSTRING_LEN(file)) {
2173 rb_raise(rb_eArgError, "empty file name");
2174 }
2175
2176 ce = rb_const_lookup(mod, id);
2177 if (ce && ce->value != Qundef) {
2178 return;
2179 }
2180
2181 rb_const_set(mod, id, Qundef);
2182 tbl = RCLASS_IV_TBL(mod);
2183 if (tbl && st_lookup(tbl, (st_data_t)autoload, &av)) {
2184 tbl = check_autoload_table((VALUE)av);
2185 }
2186 else {
2187 if (!tbl) tbl = RCLASS_IV_TBL(mod) = st_init_numtable();
2188 av = (st_data_t)TypedData_Wrap_Struct(0, &autoload_data_type, 0);
2189 st_add_direct(tbl, (st_data_t)autoload, av);
2190 RB_OBJ_WRITTEN(mod, Qnil, av);
2191 DATA_PTR(av) = tbl = st_init_numtable();
2192 }
2193
2194 file = rb_fstring(file);
2195 if (!autoload_featuremap) {
2196 autoload_featuremap = rb_ident_hash_new();
2197 rb_obj_hide(autoload_featuremap);
2198 rb_gc_register_mark_object(autoload_featuremap);
2199 }
2200 ad = rb_hash_aref(autoload_featuremap, file);
2201 if (NIL_P(ad)) {
2203 &autoload_data_i_type, ele);
2204 ele->feature = file;
2205 ele->state = 0;
2206 list_head_init(&ele->constants);
2207 rb_hash_aset(autoload_featuremap, file, ad);
2208 }
2209 else {
2210 ele = rb_check_typeddata(ad, &autoload_data_i_type);
2211 }
2212 {
2213 VALUE acv;
2214 struct autoload_const *ac;
2215 acv = TypedData_Make_Struct(0, struct autoload_const,
2216 &autoload_const_type, ac);
2217 ac->mod = mod;
2218 ac->id = id;
2219 ac->value = Qundef;
2220 ac->flag = CONST_PUBLIC;
2221 ac->ad = ad;
2222 list_add_tail(&ele->constants, &ac->cnode);
2223 st_insert(tbl, (st_data_t)id, (st_data_t)acv);
2224 }
2225}
2226
2227static void
2228autoload_delete(VALUE mod, ID id)
2229{
2230 st_data_t val, load = 0, n = id;
2231
2232 if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
2233 struct st_table *tbl = check_autoload_table((VALUE)val);
2234 struct autoload_data_i *ele;
2235 struct autoload_const *ac;
2236
2237 st_delete(tbl, &n, &load);
2238 ele = get_autoload_data((VALUE)load, &ac);
2239 VM_ASSERT(ele);
2240 if (ele) {
2241 VM_ASSERT(!list_empty(&ele->constants));
2242 }
2243
2244 /*
2245 * we must delete here to avoid "already initialized" warnings
2246 * with parallel autoload. Using list_del_init here so list_del
2247 * works in autoload_c_free
2248 */
2249 list_del_init(&ac->cnode);
2250
2251 if (tbl->num_entries == 0) {
2252 n = autoload;
2253 st_delete(RCLASS_IV_TBL(mod), &n, &val);
2254 }
2255 }
2256}
2257
2258static VALUE
2259check_autoload_required(VALUE mod, ID id, const char **loadingpath)
2260{
2261 VALUE file;
2262 VALUE load = autoload_data(mod, id);
2263 struct autoload_data_i *ele;
2264 const char *loading;
2265
2266 if (!load || !(ele = get_autoload_data(load, 0))) {
2267 return 0;
2268 }
2269 file = ele->feature;
2270 Check_Type(file, T_STRING);
2271 if (!RSTRING_LEN(file) || !*RSTRING_PTR(file)) {
2272 rb_raise(rb_eArgError, "empty file name");
2273 }
2274
2275 /*
2276 * if somebody else is autoloading, we MUST wait for them, since
2277 * rb_provide_feature can provide a feature before autoload_const_set
2278 * completes. We must wait until autoload_const_set finishes in
2279 * the other thread.
2280 */
2281 if (ele->state && ele->state->thread != rb_thread_current()) {
2282 return load;
2283 }
2284
2285 loading = RSTRING_PTR(file);
2286 if (!rb_feature_provided(loading, &loading)) {
2287 return load;
2288 }
2289 if (loadingpath && loading) {
2290 *loadingpath = loading;
2291 return load;
2292 }
2293 return 0;
2294}
2295
2296static struct autoload_const *autoloading_const_entry(VALUE mod, ID id);
2297
2300{
2301 struct autoload_const *ac = autoloading_const_entry(mod, id);
2302 if (!ac) return FALSE;
2303
2304 if (value) {
2305 *value = ac->value;
2306 }
2307 if (flag) {
2308 *flag = ac->flag;
2309 }
2310 return TRUE;
2311}
2312
2313struct autoload_const *
2314autoloading_const_entry(VALUE mod, ID id)
2315{
2316 VALUE load = autoload_data(mod, id);
2317 struct autoload_data_i *ele;
2318 struct autoload_const *ac;
2319
2320 if (!load || !(ele = get_autoload_data(load, &ac))) {
2321 return 0;
2322 }
2323
2324 if (ele->state && ele->state->thread == rb_thread_current()) {
2325 if (ac->value != Qundef) {
2326 return ac;
2327 }
2328 }
2329 return 0;
2330}
2331
2332static int
2333autoload_defined_p(VALUE mod, ID id)
2334{
2336
2337 if (!ce || ce->value != Qundef) {
2338 return 0;
2339 }
2340 return !rb_autoloading_value(mod, id, NULL, NULL);
2341}
2342
2343static void const_tbl_update(struct autoload_const *);
2344
2345static VALUE
2346autoload_const_set(struct autoload_const *ac)
2347{
2348 VALUE klass = ac->mod;
2349 ID id = ac->id;
2350 check_before_mod_set(klass, id, ac->value, "constant");
2351
2353 {
2354 const_tbl_update(ac);
2355 }
2357
2358 return 0; /* ignored */
2359}
2360
2361static VALUE
2362autoload_require(VALUE arg)
2363{
2364 struct autoload_state *state = (struct autoload_state *)arg;
2365 struct autoload_const *ac = state->ac;
2366 struct autoload_data_i *ele;
2367
2368 ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
2369 /* this may release GVL and switch threads: */
2370 state->result = rb_funcall(rb_vm_top_self(), rb_intern("require"), 1,
2371 ele->feature);
2372
2373 return state->result;
2374}
2375
2376static VALUE
2377autoload_reset(VALUE arg)
2378{
2379 struct autoload_state *state = (struct autoload_state *)arg;
2380 int need_wakeups = 0;
2381 struct autoload_const *ac = state->ac;
2382 struct autoload_data_i *ele;
2383
2384 ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
2385 if (ele->state == state) {
2386 need_wakeups = 1;
2387 ele->state = 0;
2388 ele->fork_gen = 0;
2389 }
2390
2391 /* At the last, move a value defined in autoload to constant table */
2392 if (RTEST(state->result)) {
2393 struct autoload_const *next;
2394
2395 list_for_each_safe(&ele->constants, ac, next, cnode) {
2396 if (ac->value != Qundef) {
2397 autoload_const_set(ac);
2398 }
2399 }
2400 }
2401
2402 /* wakeup any waiters we had */
2403 if (need_wakeups) {
2404 struct autoload_state *cur = 0, *nxt;
2405
2406 list_for_each_safe((struct list_head *)&state->waitq, cur, nxt, waitq) {
2407 VALUE th = cur->thread;
2408
2409 cur->thread = Qfalse;
2410 list_del_init(&cur->waitq); /* idempotent */
2411
2412 /*
2413 * cur is stored on the stack of cur->waiting_th,
2414 * do not touch cur after waking up waiting_th
2415 */
2417 }
2418 }
2419
2420 return 0; /* ignored */
2421}
2422
2423static VALUE
2424autoload_sleep(VALUE arg)
2425{
2426 struct autoload_state *state = (struct autoload_state *)arg;
2427
2428 /*
2429 * autoload_reset in other thread will resume us and remove us
2430 * from the waitq list
2431 */
2432 do {
2434 } while (state->thread != Qfalse);
2435
2436 return Qfalse;
2437}
2438
2439static VALUE
2440autoload_sleep_done(VALUE arg)
2441{
2442 struct autoload_state *state = (struct autoload_state *)arg;
2443
2444 if (state->thread != Qfalse && rb_thread_to_be_killed(state->thread)) {
2445 list_del(&state->waitq); /* idempotent after list_del_init */
2446 }
2447
2448 return Qfalse;
2449}
2450
2451VALUE
2453{
2454 VALUE load, result;
2455 const char *loading = 0, *src;
2456 struct autoload_data_i *ele;
2457 struct autoload_const *ac;
2458 struct autoload_state state;
2459 int flag = -1;
2460 rb_const_entry_t *ce;
2461
2462 if (!autoload_defined_p(mod, id)) return Qfalse;
2463 load = check_autoload_required(mod, id, &loading);
2464 if (!load) return Qfalse;
2465 src = rb_sourcefile();
2466 if (src && loading && strcmp(src, loading) == 0) return Qfalse;
2467
2468 if ((ce = rb_const_lookup(mod, id))) {
2470 }
2471
2472 /* set ele->state for a marker of autoloading thread */
2473 if (!(ele = get_autoload_data(load, &ac))) {
2474 return Qfalse;
2475 }
2476 state.ac = ac;
2477 state.thread = rb_thread_current();
2478 if (!ele->state) {
2479 ele->state = &state;
2480 ele->fork_gen = GET_VM()->fork_gen;
2481
2482 /*
2483 * autoload_reset will wake up any threads added to this
2484 * iff the GVL is released during autoload_require
2485 */
2486 list_head_init((struct list_head *)&state.waitq);
2487 }
2488 else if (state.thread == ele->state->thread) {
2489 return Qfalse;
2490 }
2491 else {
2492 list_add_tail((struct list_head *)&ele->state->waitq, &state.waitq);
2493
2494 rb_ensure(autoload_sleep, (VALUE)&state,
2495 autoload_sleep_done, (VALUE)&state);
2496 }
2497
2498 /* autoload_data_i can be deleted by another thread while require */
2499 state.result = Qfalse;
2500 result = rb_ensure(autoload_require, (VALUE)&state,
2501 autoload_reset, (VALUE)&state);
2502
2503 if (flag > 0 && (ce = rb_const_lookup(mod, id))) {
2504 ce->flag |= flag;
2505 }
2507 return result;
2508}
2509
2510VALUE
2512{
2513 return rb_autoload_at_p(mod, id, TRUE);
2514}
2515
2516VALUE
2518{
2519 VALUE load;
2520 struct autoload_data_i *ele;
2521
2522 while (!autoload_defined_p(mod, id)) {
2523 if (!recur) return Qnil;
2524 mod = RCLASS_SUPER(mod);
2525 if (!mod) return Qnil;
2526 }
2527 load = check_autoload_required(mod, id, 0);
2528 if (!load) return Qnil;
2529 return (ele = get_autoload_data(load, 0)) ? ele->feature : Qnil;
2530}
2531
2534{
2535 if (RB_CONST_DEPRECATED_P(ce) &&
2537 if (klass == rb_cObject) {
2538 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "constant ::%"PRIsVALUE" is deprecated", QUOTE_ID(id));
2539 }
2540 else {
2541 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "constant %"PRIsVALUE"::%"PRIsVALUE" is deprecated",
2542 rb_class_name(klass), QUOTE_ID(id));
2543 }
2544 }
2545}
2546
2547static VALUE
2548rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
2549{
2550 VALUE c = rb_const_search(klass, id, exclude, recurse, visibility);
2551 if (c != Qundef) {
2552 if (UNLIKELY(!rb_ractor_main_p())) {
2553 if (!rb_ractor_shareable_p(c)) {
2554 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));
2555 }
2556 }
2557 return c;
2558 }
2559 return rb_const_missing(klass, ID2SYM(id));
2560}
2561
2562static VALUE
2563rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
2564{
2565 VALUE value, tmp;
2566
2567 tmp = klass;
2568 while (RTEST(tmp)) {
2569 VALUE am = 0;
2570 rb_const_entry_t *ce;
2571
2572 while ((ce = rb_const_lookup(tmp, id))) {
2573 if (visibility && RB_CONST_PRIVATE_P(ce)) {
2574 if (BUILTIN_TYPE(tmp) == T_ICLASS) tmp = RBASIC(tmp)->klass;
2575 GET_EC()->private_const_reference = tmp;
2576 return Qundef;
2577 }
2578 rb_const_warn_if_deprecated(ce, tmp, id);
2579 value = ce->value;
2580 if (value == Qundef) {
2581 struct autoload_const *ac;
2582 if (am == tmp) break;
2583 am = tmp;
2584 ac = autoloading_const_entry(tmp, id);
2585 if (ac) return ac->value;
2586 rb_autoload_load(tmp, id);
2587 continue;
2588 }
2589 if (exclude && tmp == rb_cObject) {
2590 goto not_found;
2591 }
2592 return value;
2593 }
2594 if (!recurse) break;
2595 tmp = RCLASS_SUPER(tmp);
2596 }
2597
2598 not_found:
2599 GET_EC()->private_const_reference = 0;
2600 return Qundef;
2601}
2602
2603static VALUE
2604rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility)
2605{
2606 VALUE value;
2607
2608 if (klass == rb_cObject) exclude = FALSE;
2609 value = rb_const_search_from(klass, id, exclude, recurse, visibility);
2610 if (value != Qundef) return value;
2611 if (exclude) return value;
2612 if (BUILTIN_TYPE(klass) != T_MODULE) return value;
2613 /* search global const too, if klass is a module */
2614 return rb_const_search_from(rb_cObject, id, FALSE, recurse, visibility);
2615}
2616
2617VALUE
2619{
2620 return rb_const_get_0(klass, id, TRUE, TRUE, FALSE);
2621}
2622
2623VALUE
2625{
2626 return rb_const_get_0(klass, id, FALSE, TRUE, FALSE);
2627}
2628
2629VALUE
2631{
2632 return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
2633}
2634
2637{
2638 return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
2639}
2640
2643{
2644 return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
2645}
2646
2647NORETURN(static void undefined_constant(VALUE mod, VALUE name));
2648static void
2649undefined_constant(VALUE mod, VALUE name)
2650{
2651 rb_name_err_raise("constant %2$s::%1$s not defined",
2652 mod, name);
2653}
2654
2655static VALUE
2656rb_const_location_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
2657{
2658 while (RTEST(klass)) {
2659 rb_const_entry_t *ce;
2660
2661 while ((ce = rb_const_lookup(klass, id))) {
2662 if (visibility && RB_CONST_PRIVATE_P(ce)) {
2663 return Qnil;
2664 }
2665 if (exclude && klass == rb_cObject) {
2666 goto not_found;
2667 }
2668 if (NIL_P(ce->file)) return rb_ary_new();
2669 return rb_assoc_new(ce->file, INT2NUM(ce->line));
2670 }
2671 if (!recurse) break;
2672 klass = RCLASS_SUPER(klass);
2673 }
2674
2675 not_found:
2676 return Qnil;
2677}
2678
2679static VALUE
2680rb_const_location(VALUE klass, ID id, int exclude, int recurse, int visibility)
2681{
2682 VALUE loc;
2683
2684 if (klass == rb_cObject) exclude = FALSE;
2685 loc = rb_const_location_from(klass, id, exclude, recurse, visibility);
2686 if (!NIL_P(loc)) return loc;
2687 if (exclude) return loc;
2688 if (BUILTIN_TYPE(klass) != T_MODULE) return loc;
2689 /* search global const too, if klass is a module */
2690 return rb_const_location_from(rb_cObject, id, FALSE, recurse, visibility);
2691}
2692
2693VALUE
2695{
2696 return rb_const_location(klass, id, FALSE, TRUE, FALSE);
2697}
2698
2701{
2702 return rb_const_location(klass, id, TRUE, FALSE, FALSE);
2703}
2704
2705/*
2706 * call-seq:
2707 * remove_const(sym) -> obj
2708 *
2709 * Removes the definition of the given constant, returning that
2710 * constant's previous value. If that constant referred to
2711 * a module, this will not change that module's name and can lead
2712 * to confusion.
2713 */
2714
2715VALUE
2717{
2718 const ID id = id_for_var(mod, name, a, constant);
2719
2720 if (!id) {
2721 undefined_constant(mod, name);
2722 }
2723 return rb_const_remove(mod, id);
2724}
2725
2726VALUE
2728{
2729 VALUE val;
2730 rb_const_entry_t *ce;
2731
2733 ce = rb_const_lookup(mod, id);
2734 if (!ce || !rb_id_table_delete(RCLASS_CONST_TBL(mod), id)) {
2735 if (rb_const_defined_at(mod, id)) {
2736 rb_name_err_raise("cannot remove %2$s::%1$s",
2737 mod, ID2SYM(id));
2738 }
2739 undefined_constant(mod, ID2SYM(id));
2740 }
2741
2743
2744 val = ce->value;
2745 if (val == Qundef) {
2746 autoload_delete(mod, id);
2747 val = Qnil;
2748 }
2749 xfree(ce);
2750 return val;
2751}
2752
2753static int
2754cv_i_update(st_data_t *k, st_data_t *v, st_data_t a, int existing)
2755{
2756 if (existing) return ST_STOP;
2757 *v = a;
2758 return ST_CONTINUE;
2759}
2760
2762sv_i(ID key, VALUE v, void *a)
2763{
2765 st_table *tbl = a;
2766
2767 if (rb_is_const_id(key)) {
2768 st_update(tbl, (st_data_t)key, cv_i_update, (st_data_t)ce);
2769 }
2770 return ID_TABLE_CONTINUE;
2771}
2772
2774rb_local_constants_i(ID const_name, VALUE const_value, void *ary)
2775{
2776 if (rb_is_const_id(const_name) && !RB_CONST_PRIVATE_P((rb_const_entry_t *)const_value)) {
2777 rb_ary_push((VALUE)ary, ID2SYM(const_name));
2778 }
2779 return ID_TABLE_CONTINUE;
2780}
2781
2782static VALUE
2783rb_local_constants(VALUE mod)
2784{
2785 struct rb_id_table *tbl = RCLASS_CONST_TBL(mod);
2786 VALUE ary;
2787
2788 if (!tbl) return rb_ary_new2(0);
2789
2791 {
2792 ary = rb_ary_new2(rb_id_table_size(tbl));
2793 rb_id_table_foreach(tbl, rb_local_constants_i, (void *)ary);
2794 }
2796
2797 return ary;
2798}
2799
2800void*
2802{
2803 st_table *tbl = data;
2804 if (!tbl) {
2805 tbl = st_init_numtable();
2806 }
2807 if (RCLASS_CONST_TBL(mod)) {
2809 {
2811 }
2813 }
2814 return tbl;
2815}
2816
2817void*
2819{
2820 VALUE tmp = mod;
2821 for (;;) {
2822 data = rb_mod_const_at(tmp, data);
2823 tmp = RCLASS_SUPER(tmp);
2824 if (!tmp) break;
2825 if (tmp == rb_cObject && mod != rb_cObject) break;
2826 }
2827 return data;
2828}
2829
2830static int
2831list_i(st_data_t key, st_data_t value, VALUE ary)
2832{
2833 ID sym = (ID)key;
2834 rb_const_entry_t *ce = (rb_const_entry_t *)value;
2835 if (RB_CONST_PUBLIC_P(ce)) rb_ary_push(ary, ID2SYM(sym));
2836 return ST_CONTINUE;
2837}
2838
2839VALUE
2840rb_const_list(void *data)
2841{
2842 st_table *tbl = data;
2843 VALUE ary;
2844
2845 if (!tbl) return rb_ary_new2(0);
2846 ary = rb_ary_new2(tbl->num_entries);
2847 st_foreach_safe(tbl, list_i, ary);
2848 st_free_table(tbl);
2849
2850 return ary;
2851}
2852
2853/*
2854 * call-seq:
2855 * mod.constants(inherit=true) -> array
2856 *
2857 * Returns an array of the names of the constants accessible in
2858 * <i>mod</i>. This includes the names of constants in any included
2859 * modules (example at start of section), unless the <i>inherit</i>
2860 * parameter is set to <code>false</code>.
2861 *
2862 * The implementation makes no guarantees about the order in which the
2863 * constants are yielded.
2864 *
2865 * IO.constants.include?(:SYNC) #=> true
2866 * IO.constants(false).include?(:SYNC) #=> false
2867 *
2868 * Also see Module#const_defined?.
2869 */
2870
2871VALUE
2873{
2874 bool inherit = true;
2875
2876 if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
2877
2878 if (inherit) {
2879 return rb_const_list(rb_mod_const_of(mod, 0));
2880 }
2881 else {
2882 return rb_local_constants(mod);
2883 }
2884}
2885
2886static int
2887rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
2888{
2889 VALUE tmp;
2890 int mod_retry = 0;
2891 rb_const_entry_t *ce;
2892
2893 tmp = klass;
2894 retry:
2895 while (tmp) {
2896 if ((ce = rb_const_lookup(tmp, id))) {
2897 if (visibility && RB_CONST_PRIVATE_P(ce)) {
2898 return (int)Qfalse;
2899 }
2900 if (ce->value == Qundef && !check_autoload_required(tmp, id, 0) &&
2901 !rb_autoloading_value(tmp, id, NULL, NULL))
2902 return (int)Qfalse;
2903
2904 if (exclude && tmp == rb_cObject && klass != rb_cObject) {
2905 return (int)Qfalse;
2906 }
2907
2908 return (int)Qtrue;
2909 }
2910 if (!recurse) break;
2911 tmp = RCLASS_SUPER(tmp);
2912 }
2913 if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
2914 mod_retry = 1;
2915 tmp = rb_cObject;
2916 goto retry;
2917 }
2918 return (int)Qfalse;
2919}
2920
2921int
2923{
2924 return rb_const_defined_0(klass, id, TRUE, TRUE, FALSE);
2925}
2926
2927int
2929{
2930 return rb_const_defined_0(klass, id, FALSE, TRUE, FALSE);
2931}
2932
2933int
2935{
2936 return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
2937}
2938
2941{
2942 return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
2943}
2944
2945static void
2946check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
2947{
2948 rb_check_frozen(klass);
2949}
2950
2951static void set_namespace_path(VALUE named_namespace, VALUE name);
2952
2954set_namespace_path_i(ID id, VALUE v, void *payload)
2955{
2957 VALUE value = ce->value;
2958 int has_permanent_classpath;
2959 VALUE parental_path = *((VALUE *) payload);
2960 if (!rb_is_const_id(id)) {
2961 return ID_TABLE_CONTINUE;
2962 }
2963 if (!rb_namespace_p(value)) {
2964 return ID_TABLE_CONTINUE;
2965 }
2966 classname(value, &has_permanent_classpath);
2967 if (has_permanent_classpath) {
2968 return ID_TABLE_CONTINUE;
2969 }
2970 set_namespace_path(value, build_const_path(parental_path, id));
2971 if (RCLASS_IV_TBL(value)) {
2972 st_data_t tmp = tmp_classpath;
2973 st_delete(RCLASS_IV_TBL(value), &tmp, 0);
2974 }
2975
2976 return ID_TABLE_CONTINUE;
2977}
2978
2979/*
2980 * Assign permanent classpaths to all namespaces that are directly or indirectly
2981 * nested under +named_namespace+. +named_namespace+ must have a permanent
2982 * classpath.
2983 */
2984static void
2985set_namespace_path(VALUE named_namespace, VALUE namespace_path)
2986{
2987 struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
2988
2990 {
2991 if (!RCLASS_IV_TBL(named_namespace)) {
2992 RCLASS_IV_TBL(named_namespace) = st_init_numtable();
2993 }
2994 rb_class_ivar_set(named_namespace, classpath, namespace_path);
2995 if (const_table) {
2996 rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path);
2997 }
2998 }
3000}
3001
3002void
3004{
3005 rb_const_entry_t *ce;
3006
3007 if (NIL_P(klass)) {
3008 rb_raise(rb_eTypeError, "no class/module to define constant %"PRIsVALUE"",
3009 QUOTE_ID(id));
3010 }
3011
3012 if (!rb_ractor_main_p() && !rb_ractor_shareable_p(val)) {
3013 rb_raise(rb_eRactorIsolationError, "can not set constants with non-shareable objects by non-main Ractors");
3014 }
3015
3016 check_before_mod_set(klass, id, val, "constant");
3017
3019 {
3020 struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
3021 if (!tbl) {
3022 RCLASS_CONST_TBL(klass) = tbl = rb_id_table_create(0);
3025 rb_id_table_insert(tbl, id, (VALUE)ce);
3026 setup_const_entry(ce, klass, val, CONST_PUBLIC);
3027 }
3028 else {
3029 struct autoload_const ac = {
3030 .mod = klass, .id = id,
3031 .value = val, .flag = CONST_PUBLIC,
3032 /* fill the rest with 0 */
3033 };
3034 const_tbl_update(&ac);
3035 }
3036 }
3038
3039 /*
3040 * Resolve and cache class name immediately to resolve ambiguity
3041 * and avoid order-dependency on const_tbl
3042 */
3043 if (rb_cObject && rb_namespace_p(val)) {
3044 int val_path_permanent;
3045 VALUE val_path = classname(val, &val_path_permanent);
3046 if (NIL_P(val_path) || !val_path_permanent) {
3047 if (klass == rb_cObject) {
3048 set_namespace_path(val, rb_id2str(id));
3049 }
3050 else {
3051 int parental_path_permanent;
3052 VALUE parental_path = classname(klass, &parental_path_permanent);
3053 if (NIL_P(parental_path)) {
3054 int throwaway;
3055 parental_path = rb_tmp_class_path(klass, &throwaway, make_temporary_path);
3056 }
3057 if (parental_path_permanent && !val_path_permanent) {
3058 set_namespace_path(val, build_const_path(parental_path, id));
3059 }
3060 else if (!parental_path_permanent && NIL_P(val_path)) {
3061 rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id));
3062 }
3063 }
3064 }
3065 }
3066}
3067
3068static struct autoload_data_i *
3069current_autoload_data(VALUE mod, ID id, struct autoload_const **acp)
3070{
3071 struct autoload_data_i *ele;
3072 VALUE load = autoload_data(mod, id);
3073 if (!load) return 0;
3074 ele = get_autoload_data(load, acp);
3075 if (!ele) return 0;
3076 /* for autoloading thread, keep the defined value to autoloading storage */
3077 if (ele->state && (ele->state->thread == rb_thread_current())) {
3078 return ele;
3079 }
3080 return 0;
3081}
3082
3083static void
3084const_tbl_update(struct autoload_const *ac)
3085{
3086 VALUE value;
3087 VALUE klass = ac->mod;
3088 VALUE val = ac->value;
3089 ID id = ac->id;
3090 struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
3091 rb_const_flag_t visibility = ac->flag;
3092 rb_const_entry_t *ce;
3093
3094 if (rb_id_table_lookup(tbl, id, &value)) {
3095 ce = (rb_const_entry_t *)value;
3096 if (ce->value == Qundef) {
3097 struct autoload_data_i *ele = current_autoload_data(klass, id, &ac);
3098
3099 if (ele) {
3101
3102 ac->value = val; /* autoload_i is non-WB-protected */
3103 ac->file = rb_source_location(&ac->line);
3104 }
3105 else {
3106 /* otherwise autoloaded constant, allow to override */
3107 autoload_delete(klass, id);
3108 ce->flag = visibility;
3109 RB_OBJ_WRITE(klass, &ce->value, val);
3110 RB_OBJ_WRITE(klass, &ce->file, ac->file);
3111 ce->line = ac->line;
3112 }
3113 return;
3114 }
3115 else {
3116 VALUE name = QUOTE_ID(id);
3117 visibility = ce->flag;
3118 if (klass == rb_cObject)
3119 rb_warn("already initialized constant %"PRIsVALUE"", name);
3120 else
3121 rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"",
3122 rb_class_name(klass), name);
3123 if (!NIL_P(ce->file) && ce->line) {
3125 "previous definition of %"PRIsVALUE" was here", name);
3126 }
3127 }
3129 setup_const_entry(ce, klass, val, visibility);
3130 }
3131 else {
3133
3135 rb_id_table_insert(tbl, id, (VALUE)ce);
3136 setup_const_entry(ce, klass, val, visibility);
3137 }
3138}
3139
3140static void
3141setup_const_entry(rb_const_entry_t *ce, VALUE klass, VALUE val,
3142 rb_const_flag_t visibility)
3143{
3144 ce->flag = visibility;
3145 RB_OBJ_WRITE(klass, &ce->value, val);
3146 RB_OBJ_WRITE(klass, &ce->file, rb_source_location(&ce->line));
3147}
3148
3149void
3150rb_define_const(VALUE klass, const char *name, VALUE val)
3151{
3152 ID id = rb_intern(name);
3153
3154 if (!rb_is_const_id(id)) {
3155 rb_warn("rb_define_const: invalid name `%s' for constant", name);
3156 }
3158 rb_const_set(klass, id, val);
3159}
3160
3161void
3163{
3165}
3166
3167static void
3168set_const_visibility(VALUE mod, int argc, const VALUE *argv,
3170{
3171 int i;
3172 rb_const_entry_t *ce;
3173 ID id;
3174
3176 if (argc == 0) {
3177 rb_warning("%"PRIsVALUE" with no argument is just ignored",
3178 QUOTE_ID(rb_frame_callee()));
3179 return;
3180 }
3181
3182 for (i = 0; i < argc; i++) {
3183 struct autoload_const *ac;
3184 VALUE val = argv[i];
3185 id = rb_check_id(&val);
3186 if (!id) {
3187 if (i > 0) {
3189 }
3190
3191 undefined_constant(mod, val);
3192 }
3193 if ((ce = rb_const_lookup(mod, id))) {
3194 ce->flag &= ~mask;
3195 ce->flag |= flag;
3196 if (ce->value == Qundef) {
3197 struct autoload_data_i *ele;
3198
3199 ele = current_autoload_data(mod, id, &ac);
3200 if (ele) {
3201 ac->flag &= ~mask;
3202 ac->flag |= flag;
3203 }
3204 }
3205 }
3206 else {
3207 if (i > 0) {
3209 }
3210 undefined_constant(mod, ID2SYM(id));
3211 }
3212 }
3214}
3215
3216void
3218{
3219 rb_const_entry_t *ce;
3220 ID id;
3221 long len = strlen(name);
3222
3224 if (!(id = rb_check_id_cstr(name, len, NULL))) {
3225 undefined_constant(mod, rb_fstring_new(name, len));
3226 }
3227 if (!(ce = rb_const_lookup(mod, id))) {
3228 undefined_constant(mod, ID2SYM(id));
3229 }
3230 ce->flag |= CONST_DEPRECATED;
3231}
3232
3233/*
3234 * call-seq:
3235 * mod.private_constant(symbol, ...) => mod
3236 *
3237 * Makes a list of existing constants private.
3238 */
3239
3240VALUE
3242{
3243 set_const_visibility(obj, argc, argv, CONST_PRIVATE, CONST_VISIBILITY_MASK);
3244 return obj;
3245}
3246
3247/*
3248 * call-seq:
3249 * mod.public_constant(symbol, ...) => mod
3250 *
3251 * Makes a list of existing constants public.
3252 */
3253
3254VALUE
3256{
3257 set_const_visibility(obj, argc, argv, CONST_PUBLIC, CONST_VISIBILITY_MASK);
3258 return obj;
3259}
3260
3261/*
3262 * call-seq:
3263 * mod.deprecate_constant(symbol, ...) => mod
3264 *
3265 * Makes a list of existing constants deprecated. Attempt
3266 * to refer to them will produce a warning.
3267 *
3268 * module HTTP
3269 * NotFound = Exception.new
3270 * NOT_FOUND = NotFound # previous version of the library used this name
3271 *
3272 * deprecate_constant :NOT_FOUND
3273 * end
3274 *
3275 * HTTP::NOT_FOUND
3276 * # warning: constant HTTP::NOT_FOUND is deprecated
3277 *
3278 */
3279
3280VALUE
3282{
3283 set_const_visibility(obj, argc, argv, CONST_DEPRECATED, CONST_DEPRECATED);
3284 return obj;
3285}
3286
3287static VALUE
3288original_module(VALUE c)
3289{
3290 if (RB_TYPE_P(c, T_ICLASS))
3291 return RBASIC(c)->klass;
3292 return c;
3293}
3294
3295static int
3296cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
3297{
3298 if (!RCLASS_IV_TBL(klass)) return 0;
3299 return st_lookup(RCLASS_IV_TBL(klass), (st_data_t)id, v);
3300}
3301
3302static VALUE
3303cvar_front_klass(VALUE klass)
3304{
3305 if (FL_TEST(klass, FL_SINGLETON)) {
3306 VALUE obj = rb_ivar_get(klass, id__attached__);
3307 if (rb_namespace_p(obj)) {
3308 return obj;
3309 }
3310 }
3311 return RCLASS_SUPER(klass);
3312}
3313
3314static void
3315cvar_overtaken(VALUE front, VALUE target, ID id)
3316{
3317 if (front && target != front) {
3318 st_data_t did = (st_data_t)id;
3319
3320 if (original_module(front) != original_module(target)) {
3322 "class variable % "PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
3323 ID2SYM(id), rb_class_name(original_module(front)),
3324 rb_class_name(original_module(target)));
3325 }
3326 if (BUILTIN_TYPE(front) == T_CLASS) {
3327 st_delete(RCLASS_IV_TBL(front), &did, 0);
3328 }
3329 }
3330}
3331
3332#define CVAR_FOREACH_ANCESTORS(klass, v, r) \
3333 for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
3334 if (cvar_lookup_at(klass, id, (v))) { \
3335 r; \
3336 } \
3337 }
3338
3339#define CVAR_LOOKUP(v,r) do {\
3340 CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(); \
3341 if (cvar_lookup_at(klass, id, (v))) {r;}\
3342 CVAR_FOREACH_ANCESTORS(klass, v, r);\
3343} while(0)
3344
3345void
3346rb_cvar_set(VALUE klass, ID id, VALUE val)
3347{
3348 VALUE tmp, front = 0, target = 0;
3349
3350 tmp = klass;
3351 CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
3352 if (target) {
3353 cvar_overtaken(front, target, id);
3354 }
3355 else {
3356 target = tmp;
3357 }
3358
3359 if (RB_TYPE_P(target, T_ICLASS)) {
3360 target = RBASIC(target)->klass;
3361 }
3362 check_before_mod_set(target, id, val, "class variable");
3363 if (!RCLASS_IV_TBL(target)) {
3364 RCLASS_IV_TBL(target) = st_init_numtable();
3365 }
3366
3367 rb_class_ivar_set(target, id, val);
3368}
3369
3370VALUE
3372{
3373 VALUE tmp, front = 0, target = 0;
3374 st_data_t value;
3375
3376 tmp = klass;
3377 CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
3378 if (!target) {
3379 rb_name_err_raise("uninitialized class variable %1$s in %2$s",
3380 tmp, ID2SYM(id));
3381 }
3382 cvar_overtaken(front, target, id);
3383 return (VALUE)value;
3384}
3385
3386VALUE
3388{
3389 if (!klass) return Qfalse;
3390 CVAR_LOOKUP(0,return Qtrue);
3391 return Qfalse;
3392}
3393
3394static ID
3395cv_intern(VALUE klass, const char *name)
3396{
3397 ID id = rb_intern(name);
3398 if (!rb_is_class_id(id)) {
3399 rb_name_err_raise("wrong class variable name %1$s",
3400 klass, rb_str_new_cstr(name));
3401 }
3402 return id;
3403}
3404
3405void
3406rb_cv_set(VALUE klass, const char *name, VALUE val)
3407{
3408 ID id = cv_intern(klass, name);
3409 rb_cvar_set(klass, id, val);
3410}
3411
3412VALUE
3413rb_cv_get(VALUE klass, const char *name)
3414{
3415 ID id = cv_intern(klass, name);
3416 return rb_cvar_get(klass, id);
3417}
3418
3419void
3421{
3422 ID id = cv_intern(klass, name);
3423 rb_cvar_set(klass, id, val);
3424}
3425
3426static int
3427cv_i(st_data_t k, st_data_t v, st_data_t a)
3428{
3429 ID key = (ID)k;
3430 st_table *tbl = (st_table *)a;
3431
3432 if (rb_is_class_id(key)) {
3433 st_update(tbl, (st_data_t)key, cv_i_update, 0);
3434 }
3435 return ST_CONTINUE;
3436}
3437
3438static void*
3439mod_cvar_at(VALUE mod, void *data)
3440{
3441 st_table *tbl = data;
3442 if (!tbl) {
3443 tbl = st_init_numtable();
3444 }
3445 if (RCLASS_IV_TBL(mod)) {
3447 }
3448 return tbl;
3449}
3450
3451static void*
3452mod_cvar_of(VALUE mod, void *data)
3453{
3454 VALUE tmp = mod;
3455 if (FL_TEST(mod, FL_SINGLETON)) {
3456 if (rb_namespace_p(rb_ivar_get(mod, id__attached__))) {
3457 data = mod_cvar_at(tmp, data);
3458 tmp = cvar_front_klass(tmp);
3459 }
3460 }
3461 for (;;) {
3462 data = mod_cvar_at(tmp, data);
3463 tmp = RCLASS_SUPER(tmp);
3464 if (!tmp) break;
3465 }
3466 return data;
3467}
3468
3469static int
3470cv_list_i(st_data_t key, st_data_t value, VALUE ary)
3471{
3472 ID sym = (ID)key;
3473 rb_ary_push(ary, ID2SYM(sym));
3474 return ST_CONTINUE;
3475}
3476
3477static VALUE
3478cvar_list(void *data)
3479{
3480 st_table *tbl = data;
3481 VALUE ary;
3482
3483 if (!tbl) return rb_ary_new2(0);
3484 ary = rb_ary_new2(tbl->num_entries);
3485 st_foreach_safe(tbl, cv_list_i, ary);
3486 st_free_table(tbl);
3487
3488 return ary;
3489}
3490
3491/*
3492 * call-seq:
3493 * mod.class_variables(inherit=true) -> array
3494 *
3495 * Returns an array of the names of class variables in <i>mod</i>.
3496 * This includes the names of class variables in any included
3497 * modules, unless the <i>inherit</i> parameter is set to
3498 * <code>false</code>.
3499 *
3500 * class One
3501 * @@var1 = 1
3502 * end
3503 * class Two < One
3504 * @@var2 = 2
3505 * end
3506 * One.class_variables #=> [:@@var1]
3507 * Two.class_variables #=> [:@@var2, :@@var1]
3508 * Two.class_variables(false) #=> [:@@var2]
3509 */
3510
3511VALUE
3513{
3514 bool inherit = true;
3515 st_table *tbl;
3516
3517 if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
3518 if (inherit) {
3519 tbl = mod_cvar_of(mod, 0);
3520 }
3521 else {
3522 tbl = mod_cvar_at(mod, 0);
3523 }
3524 return cvar_list(tbl);
3525}
3526
3527/*
3528 * call-seq:
3529 * remove_class_variable(sym) -> obj
3530 *
3531 * Removes the named class variable from the receiver, returning that
3532 * variable's value.
3533 *
3534 * class Example
3535 * @@var = 99
3536 * puts remove_class_variable(:@@var)
3537 * p(defined? @@var)
3538 * end
3539 *
3540 * <em>produces:</em>
3541 *
3542 * 99
3543 * nil
3544 */
3545
3546VALUE
3548{
3549 const ID id = id_for_var_message(mod, name, class, "wrong class variable name %1$s");
3550 st_data_t val, n = id;
3551
3552 if (!id) {
3553 goto not_defined;
3554 }
3556 if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) {
3557 return (VALUE)val;
3558 }
3559 if (rb_cvar_defined(mod, id)) {
3560 rb_name_err_raise("cannot remove %1$s for %2$s", mod, ID2SYM(id));
3561 }
3562 not_defined:
3563 rb_name_err_raise("class variable %1$s not defined for %2$s",
3564 mod, name);
3566}
3567
3568VALUE
3569rb_iv_get(VALUE obj, const char *name)
3570{
3572
3573 if (!id) {
3574 return Qnil;
3575 }
3576 return rb_ivar_get(obj, id);
3577}
3578
3579VALUE
3580rb_iv_set(VALUE obj, const char *name, VALUE val)
3581{
3582 ID id = rb_intern(name);
3583
3584 return rb_ivar_set(obj, id, val);
3585}
3586
3587/* tbl = xx(obj); tbl[key] = value; */
3588int
3590{
3591 st_table *tbl = RCLASS_IV_TBL(obj);
3592 int result = st_insert(tbl, (st_data_t)key, (st_data_t)value);
3593 RB_OBJ_WRITTEN(obj, Qundef, value);
3594 return result;
3595}
3596
3597static int
3598tbl_copy_i(st_data_t key, st_data_t value, st_data_t data)
3599{
3600 RB_OBJ_WRITTEN((VALUE)data, Qundef, (VALUE)value);
3601 return ST_CONTINUE;
3602}
3603
3604void
3606{
3607 st_table *orig_tbl = RCLASS_IV_TBL(src);
3608 st_table *new_tbl = st_copy(orig_tbl);
3609 st_foreach(new_tbl, tbl_copy_i, (st_data_t)dst);
3610 RCLASS_IV_TBL(dst) = new_tbl;
3611}
3612
3615{
3616 struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
3617
3618 if (tbl) {
3619 VALUE val;
3620 bool r;
3622 {
3623 r = rb_id_table_lookup(tbl, id, &val);
3624 }
3626
3627 if (r) return (rb_const_entry_t *)val;
3628 }
3629 return NULL;
3630}
#define offsetof(p_type, field)
Definition: addrinfo.h:186
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
VALUE rb_ary_new(void)
Definition: array.c:749
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy iff RUBY_DEBUG is truthy.
Definition: assert.h:177
#define NORETURN(x)
Definition: attributes.h:152
#define UNREACHABLE_RETURN
Definition: assume.h:31
#define rb_category_warn(category,...)
Definition: bigdecimal.h:163
Internal header absorbing C compipler differences.
rb_const_flag_t
Definition: constant.h:16
@ CONST_DEPRECATED
Definition: constant.h:17
@ CONST_PRIVATE
Definition: constant.h:21
@ CONST_PUBLIC
Definition: constant.h:20
@ CONST_VISIBILITY_MASK
Definition: constant.h:19
#define RB_CONST_PRIVATE_P(ce)
Definition: constant.h:25
#define RB_CONST_DEPRECATED_P(ce)
Definition: constant.h:30
#define RB_CONST_PUBLIC_P(ce)
Definition: constant.h:27
#define mod(x, y)
Definition: date_strftime.c:28
#define recur(fmt)
enum @11::@13::@14 mask
struct RIMemo * ptr
Definition: debug.c:88
#define RB_DEBUG_COUNTER_INC(type)
#define MJIT_FUNC_EXPORTED
Definition: dllexport.h:55
#define assert(x)
Definition: dlmalloc.c:1176
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:1070
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1549
big_t * num
Definition: enough.c:232
#define sym(name)
Definition: enumerator.c:4007
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define rb_deprecate_constant(mod, name)
Definition: etc.c:60
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define UNLIKELY(x)
Definition: ffi_common.h:126
#define memcpy(d, s, n)
Definition: ffi_common.h:55
#define LIKELY(x)
Definition: ffi_common.h:125
#define FL_SINGLETON
Definition: fl_type.h:49
#define FL_EXIVAR
Definition: fl_type.h:58
#define PRIsVALUE
Definition: function.c:10
VALUE rb_gc_location(VALUE value)
Definition: gc.c:9003
void rb_mark_tbl_no_pin(st_table *tbl)
Definition: gc.c:5899
void rb_gc_mark_movable(VALUE ptr)
Definition: gc.c:6106
void rb_gc_mark_maybe(VALUE obj)
Definition: gc.c:5931
void rb_gc_update_tbl_refs(st_table *ptr)
Definition: gc.c:8850
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8022
#define rb_obj_instance_variables(object)
Definition: generator.h:20
#define CLASS_OF
Definition: globals.h:153
void rb_class_modify_check(VALUE klass)
Asserts that klass is not a frozen class.
Definition: eval.c:477
ID rb_frame_callee(void)
The name of the current method.
Definition: eval.c:1233
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
#define OBJ_FREEZE
Definition: fl_type.h:134
#define FL_SET
Definition: fl_type.h:128
#define FL_TEST
Definition: fl_type.h:130
#define FL_UNSET
Definition: fl_type.h:132
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
void rb_compile_warn(const char *file, int line, const char *fmt,...)
Definition: error.c:351
void rb_bug(const char *fmt,...)
Definition: error.c:768
void rb_name_error(ID id, const char *fmt,...)
Definition: error.c:1649
VALUE rb_ident_hash_new(void)
Definition: hash.c:4443
VALUE rb_eTypeError
Definition: error.c:1057
void rb_name_error_str(VALUE str, const char *fmt,...)
Definition: error.c:1664
VALUE rb_eNameError
Definition: error.c:1062
VALUE rb_eRuntimeError
Definition: error.c:1055
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:1024
void rb_warn(const char *fmt,...)
Definition: error.c:408
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1148
bool rb_warning_category_enabled_p(rb_warning_category_t category)
Definition: error.c:182
void rb_warning(const char *fmt,...)
Definition: error.c:439
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:92
VALUE rb_obj_class(VALUE)
Definition: object.c:245
VALUE rb_cModule
Module class.
Definition: object.c:50
VALUE rb_class_real(VALUE)
Looks up the nearest ancestor of cl, skipping singleton classes or module inclusions.
Definition: object.c:235
VALUE rb_hash_delete(VALUE hash, VALUE key)
Definition: hash.c:2327
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:2046
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:257
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:227
void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data)
Definition: id_table.c:311
size_t rb_id_table_size(const struct rb_id_table *tbl)
Definition: id_table.c:118
struct rb_id_table * rb_id_table_create(size_t capa)
Definition: id_table.c:96
int rb_id_table_delete(struct rb_id_table *tbl, ID id)
Definition: id_table.c:263
void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
Definition: id_table.c:292
rb_id_table_iterator_result
Definition: id_table.h:10
@ ID_TABLE_CONTINUE
Definition: id_table.h:11
#define rb_enc_asciicompat(enc)
Definition: encoding.h:236
ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
Definition: symbol.c:1155
Thin wrapper to ruby/config.h.
@ RB_WARN_CATEGORY_DEPRECATED
Definition: error.h:34
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
#define rb_ary_new3
Definition: array.h:73
#define rb_ary_new2
Definition: array.h:72
#define rb_check_frozen
Definition: error.h:72
#define rb_check_arity
Definition: error.h:34
#define st_foreach_safe
Definition: hash.h:31
int rb_feature_provided(const char *, const char **)
Definition: load.c:571
VALUE rb_backref_get(void)
Definition: vm.c:1544
int rb_is_instance_id(ID)
Definition: symbol.c:1022
int rb_is_class_id(ID)
Definition: symbol.c:1010
int rb_is_const_id(ID)
Definition: symbol.c:1004
VALUE rb_block_proc(void)
Definition: proc.c:826
#define rb_str_new2
Definition: string.h:276
#define rb_str_cat2
Definition: string.h:285
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2624
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
VALUE rb_str_new_frozen(VALUE)
Definition: string.c:1273
VALUE rb_str_intern(VALUE)
Definition: symbol.c:840
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
#define rb_str_new_cstr(str)
Definition: string.h:219
VALUE rb_thread_wakeup_alive(VALUE)
Definition: thread.c:2797
void rb_thread_sleep_deadly(void)
Definition: thread.c:1531
VALUE rb_thread_current(void)
Definition: thread.c:2911
const char * rb_sourcefile(void)
Definition: vm.c:1571
void rb_clear_constant_cache(void)
Definition: vm_method.c:127
VALUE rb_eval_cmd_kw(VALUE, VALUE, int)
Definition: vm_eval.c:1909
#define ID2SYM
Definition: symbol.h:44
const char * rb_id2name(ID)
Definition: symbol.c:944
ID rb_intern2(const char *, long)
Definition: symbol.c:778
ID rb_intern(const char *)
Definition: symbol.c:785
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
Definition: symbol.c:1069
ID rb_to_id(VALUE)
Definition: string.c:11501
rb_gvar_setter_t rb_gvar_var_setter
Definition: variable.h:42
rb_gvar_marker_t rb_gvar_var_marker
Definition: variable.h:43
void rb_gvar_marker_t(VALUE *var)
Definition: variable.h:31
void rb_gvar_setter_t(VALUE val, ID id, VALUE *data)
Definition: variable.h:30
rb_gvar_setter_t rb_gvar_val_setter
Definition: variable.h:38
rb_gvar_marker_t rb_gvar_undef_marker
Definition: variable.h:35
rb_gvar_setter_t rb_gvar_readonly_setter
Definition: variable.h:46
rb_gvar_getter_t rb_gvar_undef_getter
Definition: variable.h:33
rb_gvar_marker_t rb_gvar_val_marker
Definition: variable.h:39
VALUE rb_gvar_getter_t(ID id, VALUE *data)
Definition: variable.h:29
rb_gvar_setter_t rb_gvar_undef_setter
Definition: variable.h:34
rb_gvar_getter_t rb_gvar_val_getter
Definition: variable.h:37
rb_gvar_getter_t rb_gvar_var_getter
Definition: variable.h:41
#define INT2NUM
Definition: int.h:43
Internal header for Class.
#define RCLASS_SERIAL(c)
Definition: class.h:90
#define RCLASS_IV_TBL(c)
Definition: class.h:77
#define RCLASS_CONST_TBL(c)
Definition: class.h:78
#define RCLASS_EXT(c)
Definition: class.h:76
#define RCLASS_IV_INDEX_TBL(c)
Definition: class.h:86
Internal header for Hash.
Internal header for Object.
#define ROBJECT_IV_INDEX_TBL
Definition: object.h:81
Internal header for Regexp.
int rb_match_nth_defined(int nth, VALUE match)
Definition: re.c:1327
int rb_match_count(VALUE match)
Definition: re.c:1317
VALUE rb_fstring(VALUE)
Definition: string.c:353
VALUE rb_fstring_new(const char *ptr, long len)
Definition: string.c:446
Internal header for Thread.
int rb_thread_to_be_killed(VALUE thread)
Definition: thread.c:2720
VALUE rb_vm_top_self(void)
Definition: vm.c:3752
VALUE rb_source_location(int *pline)
Definition: vm.c:1600
void rb_vm_pop_cfunc_frame(void)
Definition: vm.c:625
void rb_vm_inc_const_missing_count(void)
Definition: vm.c:425
#define rb_fstring_cstr(...)
Definition: internal.h:71
#define rb_funcallv(...)
Definition: internal.h:77
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
voidpf void * buf
Definition: ioapi.h:138
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
#define REALLOC_N
Definition: memory.h:137
#define ALLOC_N
Definition: memory.h:133
#define RB_GC_GUARD(v)
Definition: memory.h:91
#define ALLOCV_N
Definition: memory.h:139
#define ALLOCV_END
Definition: memory.h:140
const int id
Definition: nkf.c:209
const char * name
Definition: nkf.c:208
int count
Definition: nkf.c:5055
#define TRUE
Definition: nkf.h:175
#define FALSE
Definition: nkf.h:174
void * load(const char *name, size_t *len)
Definition: pufftest.c:60
VALUE rb_eRactorIsolationError
Definition: ractor.c:23
#define RBASIC(obj)
Definition: rbasic.h:34
#define RCLASS_SUPER
Definition: rclass.h:33
#define DATA_PTR(obj)
Definition: rdata.h:56
#define NULL
Definition: regenc.h:69
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:107
#define RB_OBJ_WRITTEN(a, oldv, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:114
#define ROBJECT(obj)
Definition: robject.h:37
#define ROBJECT_EMBED
Definition: robject.h:39
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: rtypeddata.h:101
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define RB_NO_KEYWORDS
Definition: scan_args.h:46
unsigned LONG_LONG rb_serial_t
Definition: serial.h:19
unsigned int uint32_t
Definition: sha2.h:101
#define Qundef
#define SPECIAL_CONST_P
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
@ ST_STOP
Definition: st.h:99
@ ST_CHECK
Definition: st.h:99
@ ST_CONTINUE
Definition: st.h:99
#define st_copy
Definition: st.h:162
unsigned long st_data_t
Definition: st.h:22
#define st_is_member(table, key)
Definition: st.h:97
#define st_foreach
Definition: st.h:142
#define st_init_numtable
Definition: st.h:106
#define st_lookup
Definition: st.h:128
#define st_add_direct
Definition: st.h:154
#define st_delete
Definition: st.h:118
#define st_memsize
Definition: st.h:174
#define st_insert
Definition: st.h:124
st_data_t st_index_t
Definition: st.h:50
#define st_free_table
Definition: st.h:156
#define st_update
Definition: st.h:136
#define _(args)
Definition: stdarg.h:31
C99 shim for <stdbool.h>
size_t strlen(const char *)
struct list_node cnode
Definition: variable.c:2022
rb_const_flag_t flag
Definition: variable.c:2028
rb_serial_t fork_gen
Definition: variable.c:2043
struct autoload_state * state
Definition: variable.c:2042
struct list_head constants
Definition: variable.c:2044
struct autoload_const * ac
Definition: variable.c:2034
struct list_node waitq
Definition: variable.c:2037
Definition: gzappend.c:170
uint32_t numiv
Definition: variable.h:15
VALUE ivptr[FLEX_ARY_LEN]
Definition: variable.h:16
VALUE obj
Definition: variable.c:1605
VALUE klass
Definition: variable.c:1606
st_table * iv_index_tbl
Definition: variable.c:1607
struct gen_ivtbl * ivtbl
Definition: variable.c:1608
struct gen_ivtbl * ivtbl
Definition: variable.c:56
union ivar_update::@178 u
st_table * iv_index_tbl
Definition: variable.c:55
st_data_t index
Definition: variable.c:58
int iv_extended
Definition: variable.c:59
Definition: constant.h:33
VALUE value
Definition: constant.h:36
rb_const_flag_t flag
Definition: constant.h:34
VALUE file
Definition: constant.h:37
int line
Definition: constant.h:35
Definition: variable.c:331
ID id
Definition: variable.c:333
struct rb_global_variable * var
Definition: variable.c:332
bool ractor_local
Definition: variable.c:334
rb_gvar_marker_t * marker
Definition: variable.c:326
rb_gvar_compact_t * compactor
Definition: variable.c:327
rb_gvar_getter_t * getter
Definition: variable.c:324
rb_gvar_setter_t * setter
Definition: variable.c:325
struct trace_var * trace
Definition: variable.c:328
Definition: class.h:28
uint32_t index
Definition: class.h:29
Definition: st.h:79
st_index_t num_entries
Definition: st.h:86
Definition: blast.c:41
Definition: enough.c:118
struct trace_var * trace
Definition: variable.c:700
VALUE val
Definition: variable.c:701
void(* func)(VALUE arg, VALUE val)
Definition: variable.c:315
VALUE data
Definition: variable.c:316
int removed
Definition: variable.c:314
struct trace_var * next
Definition: variable.c:317
#define t
Definition: symbol.c:253
#define rb_obj_transient_heap_evacuate(x, y)
#define rb_transient_heap_alloc(o, s)
#define ALLOC(size)
Definition: unzip.c:112
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_STRING
Definition: value_type.h:77
#define T_MODULE
Definition: value_type.h:69
#define T_ICLASS
Definition: value_type.h:65
#define T_OBJECT
Definition: value_type.h:74
#define T_CLASS
Definition: value_type.h:57
#define BUILTIN_TYPE
Definition: value_type.h:84
VALUE rb_gvar_defined(ID id)
Definition: variable.c:781
VALUE rb_mod_remove_cvar(VALUE mod, VALUE name)
Definition: variable.c:3547
VALUE rb_const_get_at(VALUE klass, ID id)
Definition: variable.c:2630
void rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id)
Definition: variable.c:2533
rb_gvar_setter_t * rb_gvar_setter_function_of(ID id)
Definition: variable.c:796
VALUE rb_const_source_location_at(VALUE klass, ID id)
Definition: variable.c:2700
VALUE rb_f_untrace_var(int argc, const VALUE *argv)
Definition: variable.c:656
VALUE rb_mod_public_constant(int argc, const VALUE *argv, VALUE obj)
Definition: variable.c:3255
VALUE rb_const_list(void *data)
Definition: variable.c:2840
VALUE rb_gvar_get(ID id)
Definition: variable.c:760
void rb_define_global_const(const char *name, VALUE val)
Definition: variable.c:3162
VALUE rb_gv_get(const char *name)
Definition: variable.c:768
const char * rb_class2name(VALUE klass)
Definition: variable.c:299
VALUE rb_cvar_defined(VALUE klass, ID id)
Definition: variable.c:3387
VALUE rb_path2class(const char *path)
Definition: variable.c:287
#define CVAR_LOOKUP(v, r)
Definition: variable.c:3339
void rb_define_variable(const char *name, VALUE *var)
Definition: variable.c:581
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Definition: variable.c:1638
VALUE(* fallback_func)(VALUE obj, VALUE name)
Definition: variable.c:143
VALUE rb_gvar_set(ID id, VALUE val)
Definition: variable.c:745
VALUE rb_ivar_set(VALUE obj, ID id, VALUE val)
Definition: variable.c:1493
void rb_alias_variable(ID name1, ID name2)
Definition: variable.c:843
void rb_set_class_path(VALUE klass, VALUE under, const char *name)
Definition: variable.c:234
#define id_for_var_message(obj, name, type, message)
Definition: variable.c:1814
VALUE rb_attr_delete(VALUE obj, ID id)
Definition: variable.c:1287
void rb_gvar_compact_t(void *var)
Definition: variable.c:42
int rb_autoloading_value(VALUE mod, ID id, VALUE *value, rb_const_flag_t *flag)
Definition: variable.c:2299
const char * rb_obj_classname(VALUE obj)
Definition: variable.c:308
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
Definition: variable.c:1501
void rb_gc_mark_global_tbl(void)
Definition: variable.c:497
void rb_gvar_ractor_local(const char *name)
Definition: variable.c:359
VALUE rb_mod_constants(int argc, const VALUE *argv, VALUE mod)
Definition: variable.c:2872
VALUE rb_const_get(VALUE klass, ID id)
Definition: variable.c:2624
VALUE rb_f_trace_var(int argc, const VALUE *argv)
Definition: variable.c:610
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
Definition: variable.c:1192
void rb_mv_generic_ivar(VALUE rsrc, VALUE dst)
Definition: variable.c:1147
void rb_mark_generic_ivar(VALUE obj)
Definition: variable.c:1137
VALUE rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj)
Definition: variable.c:3241
VALUE rb_search_class_path(VALUE klass)
Definition: variable.c:191
int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg)
Definition: variable.c:1540
int rb_class_ivar_set(VALUE obj, ID key, VALUE value)
Definition: variable.c:3589
VALUE rb_public_const_get_at(VALUE klass, ID id)
Definition: variable.c:2642
void rb_define_readonly_variable(const char *name, const VALUE *var)
Definition: variable.c:587
void rb_autoload(VALUE mod, ID id, const char *file)
Definition: variable.c:2149
VALUE rb_gv_set(const char *name, VALUE val)
Definition: variable.c:754
rb_const_entry_t * rb_const_lookup(VALUE klass, ID id)
Definition: variable.c:3614
void rb_cvar_set(VALUE klass, ID id, VALUE val)
Definition: variable.c:3346
void rb_iv_tbl_copy(VALUE dst, VALUE src)
Definition: variable.c:3605
VALUE rb_autoload_at_p(VALUE mod, ID id, int recur)
Definition: variable.c:2517
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Definition: variable.c:593
VALUE rb_cvar_get(VALUE klass, ID id)
Definition: variable.c:3371
VALUE rb_mod_name(VALUE mod)
Definition: variable.c:118
void rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
Definition: variable.c:1710
VALUE rb_ivar_get(VALUE obj, ID id)
Definition: variable.c:1234
void Init_var_tables(void)
Definition: variable.c:63
int rb_public_const_defined_from(VALUE klass, ID id)
Definition: variable.c:2940
VALUE rb_class_path_cached(VALUE klass)
Definition: variable.c:178
VALUE rb_autoload_load(VALUE mod, ID id)
Definition: variable.c:2452
size_t rb_generic_ivar_memsize(VALUE obj)
Definition: variable.c:1167
void rb_autoload_str(VALUE mod, ID id, VALUE file)
Definition: variable.c:2158
VALUE rb_const_remove(VALUE mod, ID id)
Definition: variable.c:2727
VALUE rb_const_get_from(VALUE klass, ID id)
Definition: variable.c:2618
void rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
Definition: variable.c:214
int rb_const_defined(VALUE klass, ID id)
Definition: variable.c:2928
void rb_const_set(VALUE klass, ID id, VALUE val)
Definition: variable.c:3003
rb_gvar_getter_t * rb_gvar_getter_function_of(ID id)
Definition: variable.c:789
VALUE rb_obj_remove_instance_variable(VALUE obj, VALUE name)
Definition: variable.c:1856
VALUE rb_path_to_class(VALUE pathname)
Definition: variable.c:242
st_data_t rb_st_nth_key(st_table *tab, st_index_t index)
Definition: st.c:2244
VALUE rb_autoload_p(VALUE mod, ID id)
Definition: variable.c:2511
#define id_for_var(obj, name, part, type)
Definition: variable.c:1812
st_index_t rb_ivar_count(VALUE obj)
Definition: variable.c:1733
void rb_gc_update_global_tbl(void)
Definition: variable.c:515
int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl)
Definition: variable.c:960
void rb_replace_generic_ivar(VALUE clone, VALUE obj)
Definition: variable.c:1689
void * rb_mod_const_at(VALUE mod, void *data)
Definition: variable.c:2801
VALUE rb_cv_get(VALUE klass, const char *name)
Definition: variable.c:3413
VALUE rb_const_source_location(VALUE klass, ID id)
Definition: variable.c:2694
VALUE rb_const_missing(VALUE klass, VALUE name)
Definition: variable.c:1915
void rb_define_const(VALUE klass, const char *name, VALUE val)
Definition: variable.c:3150
VALUE rb_class_name(VALUE klass)
Definition: variable.c:293
void rb_cv_set(VALUE klass, const char *name, VALUE val)
Definition: variable.c:3406
VALUE rb_class_path(VALUE klass)
Definition: variable.c:169
VALUE rb_mod_class_variables(int argc, const VALUE *argv, VALUE mod)
Definition: variable.c:3512
#define check_autoload_table(av)
Definition: variable.c:2004
VALUE rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index)
Definition: variable.c:966
VALUE rb_f_global_variables(void)
Definition: variable.c:811
VALUE rb_iv_get(VALUE obj, const char *name)
Definition: variable.c:3569
VALUE rb_attr_get(VALUE obj, ID id)
Definition: variable.c:1242
VALUE rb_mod_const_missing(VALUE klass, VALUE name)
Definition: variable.c:1960
int rb_const_defined_at(VALUE klass, ID id)
Definition: variable.c:2934
int rb_const_defined_from(VALUE klass, ID id)
Definition: variable.c:2922
VALUE rb_public_const_get_from(VALUE klass, ID id)
Definition: variable.c:2636
VALUE rb_iv_set(VALUE obj, const char *name, VALUE val)
Definition: variable.c:3580
void * rb_mod_const_of(VALUE mod, void *data)
Definition: variable.c:2818
void rb_init_iv_list(VALUE obj)
Definition: variable.c:1438
VALUE rb_mod_remove_const(VALUE mod, VALUE name)
Definition: variable.c:2716
void rb_define_class_variable(VALUE klass, const char *name, VALUE val)
Definition: variable.c:3420
VALUE rb_ivar_defined(VALUE obj, ID id)
Definition: variable.c:1510
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Definition: variable.c:562
VALUE rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj)
Definition: variable.c:3281
void rb_free_generic_ivar(VALUE obj)
Definition: variable.c:1157
#define rb_id2str(id)
Definition: vm_backtrace.c:30
#define VM_ASSERT(expr)
Definition: vm_core.h:61
#define ASSERT_vm_locking()
Definition: vm_sync.h:134
#define RB_VM_LOCK_ENTER()
Definition: vm_sync.h:121
#define RB_VM_LOCK_LEAVE()
Definition: vm_sync.h:122
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
#define xfree
Definition: xmalloc.h:49
#define xrealloc
Definition: xmalloc.h:47
#define xmalloc
Definition: xmalloc.h:44
#define ZALLOC(strm, items, size)
Definition: zutil.h:266