Ruby: variable.c Source File

Ruby 3.4.4p34 (2025-05-14 revision a38531fd3f617bf734ef7d6c595325f69985ea1d)

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