Ruby: variable.c Source File

Ruby 3.4.1p0 (2024-12-25 revision 48d4efcb85000e1ebae42004e963b5d0cedddcf2)

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