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