Ruby: variable.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

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