1 /**********************************************************************
6 created at: Tue Apr 19 23:55:15 JST 1994
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
12 **********************************************************************/
14 #include "ruby/internal/config.h"
16 #include "ruby/internal/stdbool.h"
17 #include "ccan/list/list.h"
19 #include "debug_counter.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"
35 #include "ruby/util.h"
36 #include "transient_heap.h"
39 #include "ractor_core.h"
42 RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state
;
43 #define GET_GLOBAL_CVAR_STATE() (ruby_vm_global_cvar_state)
45 typedef void rb_gvar_compact_t(void *var
);
47 static struct rb_id_table
*rb_global_tbl
;
48 static ID autoload
, classpath
, tmp_classpath
;
49 static VALUE autoload_featuremap
; /* feature => autoload_i */
51 static void check_before_mod_set(VALUE
, ID
, VALUE
, const char *);
52 static void setup_const_entry(rb_const_entry_t
*, VALUE
, VALUE
, rb_const_flag_t
);
53 static VALUE
rb_const_search(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
);
54 static st_table
*generic_iv_tbl_
;
58 st_table
*iv_index_tbl
;
59 struct gen_ivtbl
*ivtbl
;
68 rb_global_tbl
= rb_id_table_create(0);
69 generic_iv_tbl_
= st_init_numtable();
70 autoload
= rb_intern_const("__autoload__");
71 /* __classpath__: fully qualified class path */
72 classpath
= rb_intern_const("__classpath__");
73 /* __tmp_classpath__: temporary class path which contains anonymous names */
74 tmp_classpath
= rb_intern_const("__tmp_classpath__");
78 rb_namespace_p(VALUE obj
)
80 if (RB_SPECIAL_CONST_P(obj
)) return false;
81 switch (RB_BUILTIN_TYPE(obj
)) {
82 case T_MODULE
: case T_CLASS
: return true;
89 * Returns +classpath+ of _klass_, if it is named, or +nil+ for
90 * anonymous +class+/+module+. A named +classpath+ may contain
91 * an anonymous component, but the last component is guaranteed
92 * to not be anonymous. <code>*permanent</code> is set to 1
93 * if +classpath+ has no anonymous components. There is no builtin
94 * Ruby level APIs that can change a permanent +classpath+.
97 classname(VALUE klass
, int *permanent
)
103 if (!RCLASS_EXT(klass
)) return Qnil
;
104 if (!(ivtbl
= RCLASS_IV_TBL(klass
))) return Qnil
;
105 if (st_lookup(ivtbl
, (st_data_t
)classpath
, &n
)) {
109 if (st_lookup(ivtbl
, (st_data_t
)tmp_classpath
, &n
)) return (VALUE
)n
;
117 * Returns the name of the module <i>mod</i>. Returns nil for anonymous modules.
121 rb_mod_name(VALUE mod
)
124 return classname(mod
, &permanent
);
128 make_temporary_path(VALUE obj
, VALUE klass
)
133 path
= rb_sprintf("#<Class:%p>", (void*)obj
);
136 path
= rb_sprintf("#<Module:%p>", (void*)obj
);
139 path
= rb_sprintf("#<%"PRIsVALUE
":%p>", klass
, (void*)obj
);
146 typedef VALUE (*fallback_func
)(VALUE obj
, VALUE name
);
149 rb_tmp_class_path(VALUE klass
, int *permanent
, fallback_func fallback
)
151 VALUE path
= classname(klass
, permanent
);
157 if (RB_TYPE_P(klass
, T_MODULE
)) {
158 if (rb_obj_class(klass
) == rb_cModule
) {
163 path
= rb_tmp_class_path(RBASIC(klass
)->klass
, &perm
, fallback
);
167 return fallback(klass
, path
);
172 rb_class_path(VALUE klass
)
175 VALUE path
= rb_tmp_class_path(klass
, &permanent
, make_temporary_path
);
176 if (!NIL_P(path
)) path
= rb_str_dup(path
);
181 rb_class_path_cached(VALUE klass
)
183 return rb_mod_name(klass
);
187 no_fallback(VALUE obj
, VALUE name
)
193 rb_search_class_path(VALUE klass
)
196 return rb_tmp_class_path(klass
, &permanent
, no_fallback
);
200 build_const_pathname(VALUE head
, VALUE tail
)
202 VALUE path
= rb_str_dup(head
);
203 rb_str_cat2(path
, "::");
204 rb_str_append(path
, tail
);
205 return rb_fstring(path
);
209 build_const_path(VALUE head
, ID tail
)
211 return build_const_pathname(head
, rb_id2str(tail
));
215 rb_set_class_path_string(VALUE klass
, VALUE under
, VALUE name
)
218 ID pathid
= classpath
;
220 if (under
== rb_cObject
) {
221 str
= rb_str_new_frozen(name
);
225 str
= rb_tmp_class_path(under
, &permanent
, make_temporary_path
);
226 str
= build_const_pathname(str
, name
);
228 pathid
= tmp_classpath
;
231 rb_ivar_set(klass
, pathid
, str
);
235 rb_set_class_path(VALUE klass
, VALUE under
, const char *name
)
237 VALUE str
= rb_str_new2(name
);
239 rb_set_class_path_string(klass
, under
, str
);
243 rb_path_to_class(VALUE pathname
)
245 rb_encoding
*enc
= rb_enc_get(pathname
);
246 const char *pbeg
, *pend
, *p
, *path
= RSTRING_PTR(pathname
);
248 VALUE c
= rb_cObject
;
250 if (!rb_enc_asciicompat(enc
)) {
251 rb_raise(rb_eArgError
, "invalid class path encoding (non ASCII)");
254 pend
= path
+ RSTRING_LEN(pathname
);
255 if (path
== pend
|| path
[0] == '#') {
256 rb_raise(rb_eArgError
, "can't retrieve anonymous class %"PRIsVALUE
,
260 while (p
< pend
&& *p
!= ':') p
++;
261 id
= rb_check_id_cstr(pbeg
, p
-pbeg
, enc
);
262 if (p
< pend
&& p
[0] == ':') {
263 if ((size_t)(pend
- p
) < 2 || p
[1] != ':') goto undefined_class
;
268 goto undefined_class
;
270 c
= rb_const_search(c
, id
, TRUE
, FALSE
, FALSE
);
271 if (c
== Qundef
) goto undefined_class
;
272 if (!rb_namespace_p(c
)) {
273 rb_raise(rb_eTypeError
, "%"PRIsVALUE
" does not refer to class/module",
277 RB_GC_GUARD(pathname
);
282 rb_raise(rb_eArgError
, "undefined class/module % "PRIsVALUE
,
283 rb_str_subseq(pathname
, 0, p
-path
));
284 UNREACHABLE_RETURN(Qundef
);
288 rb_path2class(const char *path
)
290 return rb_path_to_class(rb_str_new_cstr(path
));
294 rb_class_name(VALUE klass
)
296 return rb_class_path(rb_class_real(klass
));
300 rb_class2name(VALUE klass
)
303 VALUE path
= rb_tmp_class_path(rb_class_real(klass
), &permanent
, make_temporary_path
);
304 if (NIL_P(path
)) return NULL
;
305 return RSTRING_PTR(path
);
309 rb_obj_classname(VALUE obj
)
311 return rb_class2name(CLASS_OF(obj
));
316 void (*func
)(VALUE arg
, VALUE val
);
318 struct trace_var
*next
;
321 struct rb_global_variable
{
325 rb_gvar_getter_t
*getter
;
326 rb_gvar_setter_t
*setter
;
327 rb_gvar_marker_t
*marker
;
328 rb_gvar_compact_t
*compactor
;
329 struct trace_var
*trace
;
332 struct rb_global_entry
{
333 struct rb_global_variable
*var
;
338 static struct rb_global_entry
*
339 rb_find_global_entry(ID id
)
341 struct rb_global_entry
*entry
;
344 if (!rb_id_table_lookup(rb_global_tbl
, id
, &data
)) {
348 entry
= (struct rb_global_entry
*)data
;
349 RUBY_ASSERT(entry
!= NULL
);
352 if (UNLIKELY(!rb_ractor_main_p()) && (!entry
|| !entry
->ractor_local
)) {
353 rb_raise(rb_eRactorIsolationError
, "can not access global variables %s from non-main Ractors", rb_id2name(id
));
360 rb_gvar_ractor_local(const char *name
)
362 struct rb_global_entry
*entry
= rb_find_global_entry(rb_intern(name
));
363 entry
->ractor_local
= true;
367 rb_gvar_undef_compactor(void *var
)
371 static struct rb_global_entry
*
372 rb_global_entry(ID id
)
374 struct rb_global_entry
*entry
= rb_find_global_entry(id
);
376 struct rb_global_variable
*var
;
377 entry
= ALLOC(struct rb_global_entry
);
378 var
= ALLOC(struct rb_global_variable
);
381 entry
->ractor_local
= false;
384 var
->getter
= rb_gvar_undef_getter
;
385 var
->setter
= rb_gvar_undef_setter
;
386 var
->marker
= rb_gvar_undef_marker
;
387 var
->compactor
= rb_gvar_undef_compactor
;
389 var
->block_trace
= 0;
391 rb_id_table_insert(rb_global_tbl
, id
, (VALUE
)entry
);
397 rb_gvar_undef_getter(ID id
, VALUE
*_
)
399 rb_warning("global variable `%"PRIsVALUE
"' not initialized", QUOTE_ID(id
));
405 rb_gvar_val_compactor(void *_var
)
407 struct rb_global_variable
*var
= (struct rb_global_variable
*)_var
;
409 VALUE obj
= (VALUE
)var
->data
;
412 VALUE
new = rb_gc_location(obj
);
414 var
->data
= (void*)new;
420 rb_gvar_undef_setter(VALUE val
, ID id
, VALUE
*_
)
422 struct rb_global_variable
*var
= rb_global_entry(id
)->var
;
423 var
->getter
= rb_gvar_val_getter
;
424 var
->setter
= rb_gvar_val_setter
;
425 var
->marker
= rb_gvar_val_marker
;
426 var
->compactor
= rb_gvar_val_compactor
;
428 var
->data
= (void*)val
;
432 rb_gvar_undef_marker(VALUE
*var
)
437 rb_gvar_val_getter(ID id
, VALUE
*data
)
443 rb_gvar_val_setter(VALUE val
, ID id
, VALUE
*_
)
445 struct rb_global_variable
*var
= rb_global_entry(id
)->var
;
446 var
->data
= (void*)val
;
450 rb_gvar_val_marker(VALUE
*var
)
452 VALUE data
= (VALUE
)var
;
453 if (data
) rb_gc_mark_movable(data
);
457 rb_gvar_var_getter(ID id
, VALUE
*var
)
459 if (!var
) return Qnil
;
464 rb_gvar_var_setter(VALUE val
, ID id
, VALUE
*data
)
470 rb_gvar_var_marker(VALUE
*var
)
472 if (var
) rb_gc_mark_maybe(*var
);
476 rb_gvar_readonly_setter(VALUE v
, ID id
, VALUE
*_
)
478 rb_name_error(id
, "%"PRIsVALUE
" is a read-only variable", QUOTE_ID(id
));
481 static enum rb_id_table_iterator_result
482 mark_global_entry(VALUE v
, void *ignored
)
484 struct rb_global_entry
*entry
= (struct rb_global_entry
*)v
;
485 struct trace_var
*trace
;
486 struct rb_global_variable
*var
= entry
->var
;
488 (*var
->marker
)(var
->data
);
491 if (trace
->data
) rb_gc_mark_maybe(trace
->data
);
494 return ID_TABLE_CONTINUE
;
498 rb_gc_mark_global_tbl(void)
501 rb_id_table_foreach_values(rb_global_tbl
, mark_global_entry
, 0);
505 static enum rb_id_table_iterator_result
506 update_global_entry(VALUE v
, void *ignored
)
508 struct rb_global_entry
*entry
= (struct rb_global_entry
*)v
;
509 struct rb_global_variable
*var
= entry
->var
;
511 (*var
->compactor
)(var
);
512 return ID_TABLE_CONTINUE
;
516 rb_gc_update_global_tbl(void)
519 rb_id_table_foreach_values(rb_global_tbl
, update_global_entry
, 0);
524 global_id(const char *name
)
528 if (name
[0] == '$') id
= rb_intern(name
);
530 size_t len
= strlen(name
);
532 char *buf
= ALLOCV_N(char, vbuf
, len
+1);
534 memcpy(buf
+1, name
, len
);
535 id
= rb_intern2(buf
, len
+1);
542 find_global_id(const char *name
)
545 size_t len
= strlen(name
);
547 if (name
[0] == '$') {
548 id
= rb_check_id_cstr(name
, len
, NULL
);
552 char *buf
= ALLOCV_N(char, vbuf
, len
+1);
554 memcpy(buf
+1, name
, len
);
555 id
= rb_check_id_cstr(buf
, len
+1, NULL
);
563 rb_define_hooked_variable(
566 rb_gvar_getter_t
*getter
,
567 rb_gvar_setter_t
*setter
)
569 volatile VALUE tmp
= var
? *var
: Qnil
;
570 ID id
= global_id(name
);
571 struct rb_global_variable
*gvar
= rb_global_entry(id
)->var
;
573 gvar
->data
= (void*)var
;
574 gvar
->getter
= getter
? (rb_gvar_getter_t
*)getter
: rb_gvar_var_getter
;
575 gvar
->setter
= setter
? (rb_gvar_setter_t
*)setter
: rb_gvar_var_setter
;
576 gvar
->marker
= rb_gvar_var_marker
;
582 rb_define_variable(const char *name
, VALUE
*var
)
584 rb_define_hooked_variable(name
, var
, 0, 0);
588 rb_define_readonly_variable(const char *name
, const VALUE
*var
)
590 rb_define_hooked_variable(name
, (VALUE
*)var
, 0, rb_gvar_readonly_setter
);
594 rb_define_virtual_variable(
596 rb_gvar_getter_t
*getter
,
597 rb_gvar_setter_t
*setter
)
599 if (!getter
) getter
= rb_gvar_val_getter
;
600 if (!setter
) setter
= rb_gvar_readonly_setter
;
601 rb_define_hooked_variable(name
, 0, getter
, setter
);
605 rb_trace_eval(VALUE cmd
, VALUE val
)
607 rb_eval_cmd_kw(cmd
, rb_ary_new3(1, val
), RB_NO_KEYWORDS
);
611 rb_f_trace_var(int argc
, const VALUE
*argv
)
614 struct rb_global_entry
*entry
;
615 struct trace_var
*trace
;
617 if (rb_scan_args(argc
, argv
, "11", &var
, &cmd
) == 1) {
618 cmd
= rb_block_proc();
621 return rb_f_untrace_var(argc
, argv
);
623 entry
= rb_global_entry(rb_to_id(var
));
624 trace
= ALLOC(struct trace_var
);
625 trace
->next
= entry
->var
->trace
;
626 trace
->func
= rb_trace_eval
;
629 entry
->var
->trace
= trace
;
635 remove_trace(struct rb_global_variable
*var
)
637 struct trace_var
*trace
= var
->trace
;
639 struct trace_var
*next
;
643 while (trace
->next
) {
646 trace
->next
= next
->next
;
657 rb_f_untrace_var(int argc
, const VALUE
*argv
)
661 struct rb_global_entry
*entry
;
662 struct trace_var
*trace
;
664 rb_scan_args(argc
, argv
, "11", &var
, &cmd
);
665 id
= rb_check_id(&var
);
667 rb_name_error_str(var
, "undefined global variable %"PRIsVALUE
"", QUOTE(var
));
669 if ((entry
= rb_find_global_entry(id
)) == NULL
) {
670 rb_name_error(id
, "undefined global variable %"PRIsVALUE
"", QUOTE_ID(id
));
673 trace
= entry
->var
->trace
;
675 VALUE ary
= rb_ary_new();
678 struct trace_var
*next
= trace
->next
;
679 rb_ary_push(ary
, (VALUE
)trace
->data
);
684 if (!entry
->var
->block_trace
) remove_trace(entry
->var
);
689 if (trace
->data
== cmd
) {
691 if (!entry
->var
->block_trace
) remove_trace(entry
->var
);
692 return rb_ary_new3(1, cmd
);
701 struct trace_var
*trace
;
708 struct trace_data
*data
= (void *)v
;
709 struct trace_var
*trace
= data
->trace
;
712 (*trace
->func
)(trace
->data
, data
->val
);
722 struct rb_global_variable
*var
= (void *)v
;
723 var
->block_trace
= 0;
725 return Qnil
; /* not reached */
729 rb_gvar_set_entry(struct rb_global_entry
*entry
, VALUE val
)
731 struct trace_data trace
;
732 struct rb_global_variable
*var
= entry
->var
;
734 (*var
->setter
)(val
, entry
->id
, var
->data
);
736 if (var
->trace
&& !var
->block_trace
) {
737 var
->block_trace
= 1;
738 trace
.trace
= var
->trace
;
740 rb_ensure(trace_ev
, (VALUE
)&trace
, trace_en
, (VALUE
)var
);
746 rb_gvar_set(ID id
, VALUE val
)
748 struct rb_global_entry
*entry
;
749 entry
= rb_global_entry(id
);
751 return rb_gvar_set_entry(entry
, val
);
755 rb_gv_set(const char *name
, VALUE val
)
757 return rb_gvar_set(global_id(name
), val
);
763 struct rb_global_entry
*entry
= rb_global_entry(id
);
764 struct rb_global_variable
*var
= entry
->var
;
765 return (*var
->getter
)(entry
->id
, var
->data
);
769 rb_gv_get(const char *name
)
771 ID id
= find_global_id(name
);
774 rb_warning("global variable `%s' not initialized", name
);
778 return rb_gvar_get(id
);
781 MJIT_FUNC_EXPORTED VALUE
782 rb_gvar_defined(ID id
)
784 struct rb_global_entry
*entry
= rb_global_entry(id
);
785 return RBOOL(entry
->var
->getter
!= rb_gvar_undef_getter
);
789 rb_gvar_getter_function_of(ID id
)
791 const struct rb_global_entry
*entry
= rb_global_entry(id
);
792 return entry
->var
->getter
;
796 rb_gvar_setter_function_of(ID id
)
798 const struct rb_global_entry
*entry
= rb_global_entry(id
);
799 return entry
->var
->setter
;
802 static enum rb_id_table_iterator_result
803 gvar_i(ID key
, VALUE val
, void *a
)
805 VALUE ary
= (VALUE
)a
;
806 rb_ary_push(ary
, ID2SYM(key
));
807 return ID_TABLE_CONTINUE
;
811 rb_f_global_variables(void)
813 VALUE ary
= rb_ary_new();
814 VALUE sym
, backref
= rb_backref_get();
816 if (!rb_ractor_main_p()) {
817 rb_raise(rb_eRactorIsolationError
, "can not access global variables from non-main Ractors");
820 rb_id_table_foreach(rb_global_tbl
, gvar_i
, (void *)ary
);
821 if (!NIL_P(backref
)) {
823 int i
, nmatch
= rb_match_count(backref
);
825 for (i
= 1; i
<= nmatch
; ++i
) {
826 if (!rb_match_nth_defined(i
, backref
)) continue;
828 /* probably reused, make static ID */
829 buf
[1] = (char)(i
+ '0');
830 sym
= ID2SYM(rb_intern2(buf
, 2));
834 sym
= rb_str_intern(rb_sprintf("$%d", i
));
836 rb_ary_push(ary
, sym
);
843 rb_alias_variable(ID name1
, ID name2
)
845 struct rb_global_entry
*entry1
, *entry2
;
847 struct rb_id_table
*gtbl
= rb_global_tbl
;
849 if (!rb_ractor_main_p()) {
850 rb_raise(rb_eRactorIsolationError
, "can not access global variables from non-main Ractors");
853 entry2
= rb_global_entry(name2
);
854 if (!rb_id_table_lookup(gtbl
, name1
, &data1
)) {
855 entry1
= ALLOC(struct rb_global_entry
);
857 rb_id_table_insert(gtbl
, name1
, (VALUE
)entry1
);
859 else if ((entry1
= (struct rb_global_entry
*)data1
)->var
!= entry2
->var
) {
860 struct rb_global_variable
*var
= entry1
->var
;
861 if (var
->block_trace
) {
862 rb_raise(rb_eRuntimeError
, "can't alias in tracer");
865 if (var
->counter
== 0) {
866 struct trace_var
*trace
= var
->trace
;
868 struct trace_var
*next
= trace
->next
;
878 entry2
->var
->counter
++;
879 entry1
->var
= entry2
->var
;
883 iv_index_tbl_lookup(struct st_table
*tbl
, ID id
, uint32_t *indexp
)
888 if (tbl
== NULL
) return false;
892 r
= st_lookup(tbl
, (st_data_t
)id
, &ent_data
);
897 struct rb_iv_index_tbl_entry
*ent
= (void *)ent_data
;
898 *indexp
= ent
->index
;
907 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id
)
909 if (UNLIKELY(!rb_ractor_main_p())) {
910 if (rb_is_instance_id(id
)) { // check only normal ivars
911 rb_raise(rb_eRactorIsolationError
, "can not set instance variables of classes/modules by non-main Ractors");
916 #define CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() \
917 if (UNLIKELY(!rb_ractor_main_p())) { \
918 rb_raise(rb_eRactorIsolationError, "can not access class variables from non-main Ractors"); \
921 static inline struct st_table
*
922 generic_ivtbl(VALUE obj
, ID id
, bool force_check_ractor
)
926 if ((force_check_ractor
|| LIKELY(rb_is_instance_id(id
)) /* not internal ID */ ) &&
927 !RB_OBJ_FROZEN_RAW(obj
) &&
928 UNLIKELY(!rb_ractor_main_p()) &&
929 UNLIKELY(rb_ractor_shareable_p(obj
))) {
931 rb_raise(rb_eRactorIsolationError
, "can not access instance variables of shareable objects from non-main Ractors");
933 return generic_iv_tbl_
;
936 static inline struct st_table
*
937 generic_ivtbl_no_ractor_check(VALUE obj
)
939 return generic_ivtbl(obj
, 0, false);
943 gen_ivtbl_get(VALUE obj
, ID id
, struct gen_ivtbl
**ivtbl
)
950 if (st_lookup(generic_ivtbl(obj
, id
, false), (st_data_t
)obj
, &data
)) {
951 *ivtbl
= (struct gen_ivtbl
*)data
;
960 MJIT_FUNC_EXPORTED
int
961 rb_ivar_generic_ivtbl_lookup(VALUE obj
, struct gen_ivtbl
**ivtbl
)
963 return gen_ivtbl_get(obj
, 0, ivtbl
);
966 MJIT_FUNC_EXPORTED VALUE
967 rb_ivar_generic_lookup_with_index(VALUE obj
, ID id
, uint32_t index
)
969 struct gen_ivtbl
*ivtbl
;
971 if (gen_ivtbl_get(obj
, id
, &ivtbl
)) {
972 if (LIKELY(index
< ivtbl
->numiv
)) {
973 VALUE val
= ivtbl
->ivptr
[index
];
982 generic_ivar_delete(VALUE obj
, ID id
, VALUE undef
)
984 struct gen_ivtbl
*ivtbl
;
986 if (gen_ivtbl_get(obj
, id
, &ivtbl
)) {
987 st_table
*iv_index_tbl
= RCLASS_IV_INDEX_TBL(rb_obj_class(obj
));
990 if (iv_index_tbl
&& iv_index_tbl_lookup(iv_index_tbl
, id
, &index
)) {
991 if (index
< ivtbl
->numiv
) {
992 VALUE ret
= ivtbl
->ivptr
[index
];
994 ivtbl
->ivptr
[index
] = Qundef
;
995 return ret
== Qundef
? undef
: ret
;
1003 generic_ivar_get(VALUE obj
, ID id
, VALUE undef
)
1005 struct gen_ivtbl
*ivtbl
;
1007 if (gen_ivtbl_get(obj
, id
, &ivtbl
)) {
1008 st_table
*iv_index_tbl
= RCLASS_IV_INDEX_TBL(rb_obj_class(obj
));
1011 if (iv_index_tbl
&& iv_index_tbl_lookup(iv_index_tbl
, id
, &index
)) {
1012 if (index
< ivtbl
->numiv
) {
1013 VALUE ret
= ivtbl
->ivptr
[index
];
1015 return ret
== Qundef
? undef
: ret
;
1023 gen_ivtbl_bytes(size_t n
)
1025 return offsetof(struct gen_ivtbl
, ivptr
) + n
* sizeof(VALUE
);
1028 static struct gen_ivtbl
*
1029 gen_ivtbl_resize(struct gen_ivtbl
*old
, uint32_t n
)
1031 uint32_t len
= old
? old
->numiv
: 0;
1032 struct gen_ivtbl
*ivtbl
= xrealloc(old
, gen_ivtbl_bytes(n
));
1035 for (; len
< n
; len
++) {
1036 ivtbl
->ivptr
[len
] = Qundef
;
1043 static struct gen_ivtbl
*
1044 gen_ivtbl_dup(const struct gen_ivtbl
*orig
)
1046 size_t s
= gen_ivtbl_bytes(orig
->numiv
);
1047 struct gen_ivtbl
*ivtbl
= xmalloc(s
);
1049 memcpy(ivtbl
, orig
, s
);
1056 iv_index_tbl_newsize(struct ivar_update
*ivup
)
1058 if (!ivup
->iv_extended
) {
1059 return (uint32_t)ivup
->u
.iv_index_tbl
->num_entries
;
1062 uint32_t index
= (uint32_t)ivup
->index
; /* should not overflow */
1063 return (index
+1) + (index
+1)/4; /* (index+1)*1.25 */
1068 generic_ivar_update(st_data_t
*k
, st_data_t
*v
, st_data_t u
, int existing
)
1070 ASSERT_vm_locking();
1072 struct ivar_update
*ivup
= (struct ivar_update
*)u
;
1073 struct gen_ivtbl
*ivtbl
= 0;
1076 ivtbl
= (struct gen_ivtbl
*)*v
;
1077 if (ivup
->index
< ivtbl
->numiv
) {
1078 ivup
->u
.ivtbl
= ivtbl
;
1082 FL_SET((VALUE
)*k
, FL_EXIVAR
);
1083 uint32_t newsize
= iv_index_tbl_newsize(ivup
);
1084 ivtbl
= gen_ivtbl_resize(ivtbl
, newsize
);
1085 *v
= (st_data_t
)ivtbl
;
1086 ivup
->u
.ivtbl
= ivtbl
;
1091 generic_ivar_defined(VALUE obj
, ID id
)
1093 struct gen_ivtbl
*ivtbl
;
1094 st_table
*iv_index_tbl
= RCLASS_IV_INDEX_TBL(rb_obj_class(obj
));
1097 if (!iv_index_tbl_lookup(iv_index_tbl
, id
, &index
)) return Qfalse
;
1098 if (!gen_ivtbl_get(obj
, id
, &ivtbl
)) return Qfalse
;
1100 return RBOOL((index
< ivtbl
->numiv
) && (ivtbl
->ivptr
[index
] != Qundef
));
1104 generic_ivar_remove(VALUE obj
, ID id
, VALUE
*valp
)
1106 struct gen_ivtbl
*ivtbl
;
1108 st_table
*iv_index_tbl
= RCLASS_IV_INDEX_TBL(rb_obj_class(obj
));
1110 if (!iv_index_tbl
) return 0;
1111 if (!iv_index_tbl_lookup(iv_index_tbl
, id
, &index
)) return 0;
1112 if (!gen_ivtbl_get(obj
, id
, &ivtbl
)) return 0;
1114 if (index
< ivtbl
->numiv
) {
1115 if (ivtbl
->ivptr
[index
] != Qundef
) {
1116 *valp
= ivtbl
->ivptr
[index
];
1117 ivtbl
->ivptr
[index
] = Qundef
;
1125 gen_ivtbl_mark(const struct gen_ivtbl
*ivtbl
)
1129 for (i
= 0; i
< ivtbl
->numiv
; i
++) {
1130 rb_gc_mark(ivtbl
->ivptr
[i
]);
1135 rb_mark_generic_ivar(VALUE obj
)
1137 struct gen_ivtbl
*ivtbl
;
1139 if (gen_ivtbl_get(obj
, 0, &ivtbl
)) {
1140 gen_ivtbl_mark(ivtbl
);
1145 rb_mv_generic_ivar(VALUE rsrc
, VALUE dst
)
1147 st_data_t key
= (st_data_t
)rsrc
;
1150 if (st_delete(generic_ivtbl_no_ractor_check(rsrc
), &key
, &ivtbl
))
1151 st_insert(generic_ivtbl_no_ractor_check(dst
), (st_data_t
)dst
, ivtbl
);
1155 rb_free_generic_ivar(VALUE obj
)
1157 st_data_t key
= (st_data_t
)obj
, ivtbl
;
1159 if (st_delete(generic_ivtbl_no_ractor_check(obj
), &key
, &ivtbl
))
1160 xfree((struct gen_ivtbl
*)ivtbl
);
1163 RUBY_FUNC_EXPORTED
size_t
1164 rb_generic_ivar_memsize(VALUE obj
)
1166 struct gen_ivtbl
*ivtbl
;
1168 if (gen_ivtbl_get(obj
, 0, &ivtbl
))
1169 return gen_ivtbl_bytes(ivtbl
->numiv
);
1174 gen_ivtbl_count(const struct gen_ivtbl
*ivtbl
)
1179 for (i
= 0; i
< ivtbl
->numiv
; i
++) {
1180 if (ivtbl
->ivptr
[i
] != Qundef
) {
1189 lock_st_lookup(st_table
*tab
, st_data_t key
, st_data_t
*value
)
1194 r
= st_lookup(tab
, key
, value
);
1201 lock_st_delete(st_table
*tab
, st_data_t
*key
, st_data_t
*value
)
1206 r
= st_delete(tab
, key
, value
);
1213 lock_st_is_member(st_table
*tab
, st_data_t key
)
1218 r
= st_is_member(tab
, key
);
1225 lock_st_insert(st_table
*tab
, st_data_t key
, st_data_t value
)
1230 r
= st_insert(tab
, key
, value
);
1237 rb_ivar_lookup(VALUE obj
, ID id
, VALUE undef
)
1239 if (SPECIAL_CONST_P(obj
)) return undef
;
1240 switch (BUILTIN_TYPE(obj
)) {
1244 uint32_t len
= ROBJECT_NUMIV(obj
);
1245 VALUE
*ptr
= ROBJECT_IVPTR(obj
);
1248 if (iv_index_tbl_lookup(ROBJECT_IV_INDEX_TBL(obj
), id
, &index
) &&
1250 (val
= ptr
[index
]) != Qundef
) {
1262 if (RCLASS_IV_TBL(obj
) &&
1263 lock_st_lookup(RCLASS_IV_TBL(obj
), (st_data_t
)id
, &val
)) {
1264 if (rb_is_instance_id(id
) &&
1265 UNLIKELY(!rb_ractor_main_p()) &&
1266 !rb_ractor_shareable_p(val
)) {
1267 rb_raise(rb_eRactorIsolationError
,
1268 "can not get unshareable values from instance variables of classes/modules from non-main Ractors");
1277 if (FL_TEST(obj
, FL_EXIVAR
))
1278 return generic_ivar_get(obj
, id
, undef
);
1285 rb_ivar_get(VALUE obj
, ID id
)
1287 VALUE iv
= rb_ivar_lookup(obj
, id
, Qnil
);
1288 RB_DEBUG_COUNTER_INC(ivar_get_base
);
1293 rb_attr_get(VALUE obj
, ID id
)
1295 return rb_ivar_lookup(obj
, id
, Qnil
);
1299 rb_ivar_delete(VALUE obj
, ID id
, VALUE undef
)
1302 struct st_table
*iv_index_tbl
;
1303 uint32_t len
, index
;
1305 rb_check_frozen(obj
);
1306 switch (BUILTIN_TYPE(obj
)) {
1308 len
= ROBJECT_NUMIV(obj
);
1309 ptr
= ROBJECT_IVPTR(obj
);
1310 iv_index_tbl
= ROBJECT_IV_INDEX_TBL(obj
);
1311 if (iv_index_tbl_lookup(iv_index_tbl
, id
, &index
) &&
1313 VALUE val
= ptr
[index
];
1314 ptr
[index
] = Qundef
;
1316 if (val
!= Qundef
) {
1323 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id
);
1324 if (RCLASS_IV_TBL(obj
)) {
1325 st_data_t id_data
= (st_data_t
)id
, val
;
1326 if (lock_st_delete(RCLASS_IV_TBL(obj
), &id_data
, &val
)) {
1332 if (FL_TEST(obj
, FL_EXIVAR
))
1333 return generic_ivar_delete(obj
, id
, undef
);
1340 rb_attr_delete(VALUE obj
, ID id
)
1342 return rb_ivar_delete(obj
, id
, Qnil
);
1346 iv_index_tbl_make(VALUE obj
, VALUE klass
)
1348 st_table
*iv_index_tbl
;
1350 if (UNLIKELY(!klass
)) {
1351 rb_raise(rb_eTypeError
, "hidden object cannot have instance variables");
1354 if ((iv_index_tbl
= RCLASS_IV_INDEX_TBL(klass
)) == NULL
) {
1356 if ((iv_index_tbl
= RCLASS_IV_INDEX_TBL(klass
)) == NULL
) {
1357 iv_index_tbl
= RCLASS_IV_INDEX_TBL(klass
) = st_init_numtable();
1362 return iv_index_tbl
;
1366 iv_index_tbl_extend(struct ivar_update
*ivup
, ID id
, VALUE klass
)
1368 ASSERT_vm_locking();
1370 struct rb_iv_index_tbl_entry
*ent
;
1372 if (st_lookup(ivup
->u
.iv_index_tbl
, (st_data_t
)id
, &ent_data
)) {
1373 ent
= (void *)ent_data
;
1374 ivup
->index
= ent
->index
;
1377 if (ivup
->u
.iv_index_tbl
->num_entries
>= INT_MAX
) {
1378 rb_raise(rb_eArgError
, "too many instance variables");
1380 ent
= ALLOC(struct rb_iv_index_tbl_entry
);
1381 ent
->index
= ivup
->index
= (uint32_t)ivup
->u
.iv_index_tbl
->num_entries
;
1382 ent
->class_value
= klass
;
1383 ent
->class_serial
= RCLASS_SERIAL(klass
);
1384 st_add_direct(ivup
->u
.iv_index_tbl
, (st_data_t
)id
, (st_data_t
)ent
);
1385 ivup
->iv_extended
= 1;
1389 generic_ivar_set(VALUE obj
, ID id
, VALUE val
)
1391 VALUE klass
= rb_obj_class(obj
);
1392 struct ivar_update ivup
;
1393 ivup
.iv_extended
= 0;
1394 ivup
.u
.iv_index_tbl
= iv_index_tbl_make(obj
, klass
);
1398 iv_index_tbl_extend(&ivup
, id
, klass
);
1399 st_update(generic_ivtbl(obj
, id
, false), (st_data_t
)obj
, generic_ivar_update
,
1404 ivup
.u
.ivtbl
->ivptr
[ivup
.index
] = val
;
1406 RB_OBJ_WRITTEN(obj
, Qundef
, val
);
1410 obj_ivar_heap_alloc(VALUE obj
, size_t newsize
)
1412 VALUE
*newptr
= rb_transient_heap_alloc(obj
, sizeof(VALUE
) * newsize
);
1414 if (newptr
!= NULL
) {
1415 ROBJ_TRANSIENT_SET(obj
);
1418 ROBJ_TRANSIENT_UNSET(obj
);
1419 newptr
= ALLOC_N(VALUE
, newsize
);
1425 obj_ivar_heap_realloc(VALUE obj
, int32_t len
, size_t newsize
)
1430 if (ROBJ_TRANSIENT_P(obj
)) {
1431 const VALUE
*orig_ptr
= ROBJECT(obj
)->as
.heap
.ivptr
;
1432 newptr
= obj_ivar_heap_alloc(obj
, newsize
);
1435 ROBJECT(obj
)->as
.heap
.ivptr
= newptr
;
1436 for (i
=0; i
<(int)len
; i
++) {
1437 newptr
[i
] = orig_ptr
[i
];
1441 REALLOC_N(ROBJECT(obj
)->as
.heap
.ivptr
, VALUE
, newsize
);
1442 newptr
= ROBJECT(obj
)->as
.heap
.ivptr
;
1448 #if USE_TRANSIENT_HEAP
1450 rb_obj_transient_heap_evacuate(VALUE obj
, int promote
)
1452 if (ROBJ_TRANSIENT_P(obj
)) {
1453 uint32_t len
= ROBJECT_NUMIV(obj
);
1454 const VALUE
*old_ptr
= ROBJECT_IVPTR(obj
);
1458 new_ptr
= ALLOC_N(VALUE
, len
);
1459 ROBJ_TRANSIENT_UNSET(obj
);
1462 new_ptr
= obj_ivar_heap_alloc(obj
, len
);
1464 MEMCPY(new_ptr
, old_ptr
, VALUE
, len
);
1465 ROBJECT(obj
)->as
.heap
.ivptr
= new_ptr
;
1471 init_iv_list(VALUE obj
, uint32_t len
, uint32_t newsize
, st_table
*index_tbl
)
1473 VALUE
*ptr
= ROBJECT_IVPTR(obj
);
1476 if (RBASIC(obj
)->flags
& ROBJECT_EMBED
) {
1477 newptr
= obj_ivar_heap_alloc(obj
, newsize
);
1478 MEMCPY(newptr
, ptr
, VALUE
, len
);
1479 RBASIC(obj
)->flags
&= ~ROBJECT_EMBED
;
1480 ROBJECT(obj
)->as
.heap
.ivptr
= newptr
;
1483 newptr
= obj_ivar_heap_realloc(obj
, len
, newsize
);
1486 for (; len
< newsize
; len
++) {
1487 newptr
[len
] = Qundef
;
1489 ROBJECT(obj
)->as
.heap
.numiv
= newsize
;
1490 ROBJECT(obj
)->as
.heap
.iv_index_tbl
= index_tbl
;
1494 rb_init_iv_list(VALUE obj
)
1496 st_table
*index_tbl
= ROBJECT_IV_INDEX_TBL(obj
);
1497 uint32_t newsize
= (uint32_t)index_tbl
->num_entries
;
1498 uint32_t len
= ROBJECT_NUMIV(obj
);
1499 init_iv_list(obj
, len
, newsize
, index_tbl
);
1502 // Retrieve or create the id-to-index mapping for a given object and an
1503 // instance variable name.
1504 static struct ivar_update
1505 obj_ensure_iv_index_mapping(VALUE obj
, ID id
)
1507 VALUE klass
= rb_obj_class(obj
);
1508 struct ivar_update ivup
;
1509 ivup
.iv_extended
= 0;
1510 ivup
.u
.iv_index_tbl
= iv_index_tbl_make(obj
, klass
);
1514 iv_index_tbl_extend(&ivup
, id
, klass
);
1521 // Return the instance variable index for a given name and T_OBJECT object. The
1522 // mapping between name and index lives on `rb_obj_class(obj)` and is created
1523 // if not already present.
1525 // @note May raise when there are too many instance variables.
1526 // @note YJIT uses this function at compile time to simplify the work needed to
1527 // access the variable at runtime.
1529 rb_obj_ensure_iv_index_mapping(VALUE obj
, ID id
)
1531 RUBY_ASSERT(RB_TYPE_P(obj
, T_OBJECT
));
1532 // This uint32_t cast shouldn't lose information as it's checked in
1533 // iv_index_tbl_extend(). The index is stored as an uint32_t in
1534 // struct rb_iv_index_tbl_entry.
1535 return (uint32_t)obj_ensure_iv_index_mapping(obj
, id
).index
;
1539 obj_ivar_set(VALUE obj
, ID id
, VALUE val
)
1542 struct ivar_update ivup
= obj_ensure_iv_index_mapping(obj
, id
);
1544 len
= ROBJECT_NUMIV(obj
);
1545 if (len
<= ivup
.index
) {
1546 uint32_t newsize
= iv_index_tbl_newsize(&ivup
);
1547 init_iv_list(obj
, len
, newsize
, ivup
.u
.iv_index_tbl
);
1549 RB_OBJ_WRITE(obj
, &ROBJECT_IVPTR(obj
)[ivup
.index
], val
);
1555 ivar_set(VALUE obj
, ID id
, VALUE val
)
1557 RB_DEBUG_COUNTER_INC(ivar_set_base
);
1559 switch (BUILTIN_TYPE(obj
)) {
1561 obj_ivar_set(obj
, id
, val
);
1565 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id
);
1566 rb_class_ivar_set(obj
, id
, val
);
1569 generic_ivar_set(obj
, id
, val
);
1575 rb_ivar_set(VALUE obj
, ID id
, VALUE val
)
1577 rb_check_frozen(obj
);
1578 ivar_set(obj
, id
, val
);
1583 rb_ivar_set_internal(VALUE obj
, ID id
, VALUE val
)
1585 // should be internal instance variable name (no @ prefix)
1586 VM_ASSERT(!rb_is_instance_id(id
));
1588 ivar_set(obj
, id
, val
);
1592 rb_ivar_defined(VALUE obj
, ID id
)
1595 struct st_table
*iv_index_tbl
;
1598 if (SPECIAL_CONST_P(obj
)) return Qfalse
;
1599 switch (BUILTIN_TYPE(obj
)) {
1601 iv_index_tbl
= ROBJECT_IV_INDEX_TBL(obj
);
1602 if (iv_index_tbl_lookup(iv_index_tbl
, id
, &index
) &&
1603 index
< ROBJECT_NUMIV(obj
) &&
1604 (val
= ROBJECT_IVPTR(obj
)[index
]) != Qundef
) {
1610 if (RCLASS_IV_TBL(obj
) && lock_st_is_member(RCLASS_IV_TBL(obj
), (st_data_t
)id
))
1614 if (FL_TEST(obj
, FL_EXIVAR
))
1615 return generic_ivar_defined(obj
, id
);
1621 typedef int rb_ivar_foreach_callback_func(ID key
, VALUE val
, st_data_t arg
);
1622 st_data_t
rb_st_nth_key(st_table
*tab
, st_index_t index
);
1625 iv_index_tbl_nth_id(st_table
*iv_index_tbl
, uint32_t index
)
1630 key
= rb_st_nth_key(iv_index_tbl
, index
);
1637 ivar_each_i(st_table
*iv_index_tbl
, VALUE val
, uint32_t i
, rb_ivar_foreach_callback_func
*func
, st_data_t arg
)
1639 if (val
!= Qundef
) {
1640 ID id
= iv_index_tbl_nth_id(iv_index_tbl
, i
);
1641 switch (func(id
, val
, arg
)) {
1648 rb_bug("unreachable");
1655 obj_ivar_each(VALUE obj
, rb_ivar_foreach_callback_func
*func
, st_data_t arg
)
1657 st_table
*iv_index_tbl
= ROBJECT_IV_INDEX_TBL(obj
);
1658 if (!iv_index_tbl
) return;
1661 for (i
=0; i
< ROBJECT_NUMIV(obj
); i
++) {
1662 VALUE val
= ROBJECT_IVPTR(obj
)[i
];
1663 if (ivar_each_i(iv_index_tbl
, val
, i
, func
, arg
)) {
1670 gen_ivar_each(VALUE obj
, rb_ivar_foreach_callback_func
*func
, st_data_t arg
)
1672 struct gen_ivtbl
*ivtbl
;
1673 st_table
*iv_index_tbl
= RCLASS_IV_INDEX_TBL(rb_obj_class(obj
));
1674 if (!iv_index_tbl
) return;
1675 if (!gen_ivtbl_get(obj
, 0, &ivtbl
)) return;
1677 for (uint32_t i
=0; i
<ivtbl
->numiv
; i
++) {
1678 VALUE val
= ivtbl
->ivptr
[i
];
1679 if (ivar_each_i(iv_index_tbl
, val
, i
, func
, arg
)) {
1688 st_table
*iv_index_tbl
;
1689 struct gen_ivtbl
*ivtbl
;
1693 gen_ivar_copy(ID id
, VALUE val
, st_data_t arg
)
1695 struct givar_copy
*c
= (struct givar_copy
*)arg
;
1696 struct ivar_update ivup
;
1698 ivup
.iv_extended
= 0;
1699 ivup
.u
.iv_index_tbl
= c
->iv_index_tbl
;
1703 iv_index_tbl_extend(&ivup
, id
, c
->klass
);
1707 if (ivup
.index
>= c
->ivtbl
->numiv
) {
1708 uint32_t newsize
= iv_index_tbl_newsize(&ivup
);
1709 c
->ivtbl
= gen_ivtbl_resize(c
->ivtbl
, newsize
);
1711 c
->ivtbl
->ivptr
[ivup
.index
] = val
;
1713 RB_OBJ_WRITTEN(c
->obj
, Qundef
, val
);
1719 rb_copy_generic_ivar(VALUE clone
, VALUE obj
)
1721 struct gen_ivtbl
*ivtbl
;
1723 rb_check_frozen(clone
);
1725 if (!FL_TEST(obj
, FL_EXIVAR
)) {
1728 if (gen_ivtbl_get(obj
, 0, &ivtbl
)) {
1729 struct givar_copy c
;
1732 if (gen_ivtbl_count(ivtbl
) == 0)
1735 if (gen_ivtbl_get(clone
, 0, &c
.ivtbl
)) {
1736 for (i
= 0; i
< c
.ivtbl
->numiv
; i
++)
1737 c
.ivtbl
->ivptr
[i
] = Qundef
;
1740 c
.ivtbl
= gen_ivtbl_resize(0, ivtbl
->numiv
);
1741 FL_SET(clone
, FL_EXIVAR
);
1744 VALUE klass
= rb_obj_class(clone
);
1745 c
.iv_index_tbl
= iv_index_tbl_make(clone
, klass
);
1748 gen_ivar_each(obj
, gen_ivar_copy
, (st_data_t
)&c
);
1750 * c.ivtbl may change in gen_ivar_copy due to realloc,
1755 generic_ivtbl_no_ractor_check(clone
);
1756 st_insert(generic_ivtbl_no_ractor_check(obj
), (st_data_t
)clone
, (st_data_t
)c
.ivtbl
);
1763 if (FL_TEST(clone
, FL_EXIVAR
)) {
1764 rb_free_generic_ivar(clone
);
1765 FL_UNSET(clone
, FL_EXIVAR
);
1770 rb_replace_generic_ivar(VALUE clone
, VALUE obj
)
1772 RUBY_ASSERT(FL_TEST(obj
, FL_EXIVAR
));
1776 st_data_t ivtbl
, obj_data
= (st_data_t
)obj
;
1777 if (st_lookup(generic_iv_tbl_
, (st_data_t
)obj
, &ivtbl
)) {
1778 st_insert(generic_iv_tbl_
, (st_data_t
)clone
, ivtbl
);
1779 st_delete(generic_iv_tbl_
, &obj_data
, NULL
);
1782 rb_bug("unreachable");
1787 FL_SET(clone
, FL_EXIVAR
);
1791 rb_ivar_foreach(VALUE obj
, rb_ivar_foreach_callback_func
*func
, st_data_t arg
)
1793 if (SPECIAL_CONST_P(obj
)) return;
1794 switch (BUILTIN_TYPE(obj
)) {
1796 obj_ivar_each(obj
, func
, arg
);
1800 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
1801 if (RCLASS_IV_TBL(obj
)) {
1804 st_foreach_safe(RCLASS_IV_TBL(obj
), func
, arg
);
1810 if (FL_TEST(obj
, FL_EXIVAR
)) {
1811 gen_ivar_each(obj
, func
, arg
);
1818 rb_ivar_count(VALUE obj
)
1822 if (SPECIAL_CONST_P(obj
)) return 0;
1824 switch (BUILTIN_TYPE(obj
)) {
1826 if (ROBJECT_IV_INDEX_TBL(obj
) != 0) {
1827 st_index_t i
, count
, num
= ROBJECT_NUMIV(obj
);
1828 const VALUE
*const ivptr
= ROBJECT_IVPTR(obj
);
1829 for (i
= count
= 0; i
< num
; ++i
) {
1830 if (ivptr
[i
] != Qundef
) {
1839 if ((tbl
= RCLASS_IV_TBL(obj
)) != 0) {
1840 return tbl
->num_entries
;
1844 if (FL_TEST(obj
, FL_EXIVAR
)) {
1845 struct gen_ivtbl
*ivtbl
;
1847 if (gen_ivtbl_get(obj
, 0, &ivtbl
)) {
1848 return gen_ivtbl_count(ivtbl
);
1857 ivar_i(st_data_t k
, st_data_t v
, st_data_t a
)
1860 VALUE ary
= (VALUE
)a
;
1862 if (rb_is_instance_id(key
)) {
1863 rb_ary_push(ary
, ID2SYM(key
));
1870 * obj.instance_variables -> array
1872 * Returns an array of instance variable names for the receiver. Note
1873 * that simply defining an accessor does not create the corresponding
1874 * instance variable.
1882 * Fred.new.instance_variables #=> [:@iv]
1886 rb_obj_instance_variables(VALUE obj
)
1891 rb_ivar_foreach(obj
, ivar_i
, ary
);
1895 #define rb_is_constant_id rb_is_const_id
1896 #define rb_is_constant_name rb_is_const_name
1897 #define id_for_var(obj, name, part, type) \
1898 id_for_var_message(obj, name, type, "`%1$s' is not allowed as "#part" "#type" variable name")
1899 #define id_for_var_message(obj, name, type, message) \
1900 check_id_type(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message))
1902 check_id_type(VALUE obj
, VALUE
*pname
,
1903 int (*valid_id_p
)(ID
), int (*valid_name_p
)(VALUE
),
1904 const char *message
, size_t message_len
)
1906 ID id
= rb_check_id(pname
);
1907 VALUE name
= *pname
;
1909 if (id
? !valid_id_p(id
) : !valid_name_p(name
)) {
1910 rb_name_err_raise_str(rb_fstring_new(message
, message_len
),
1918 * obj.remove_instance_variable(symbol) -> obj
1919 * obj.remove_instance_variable(string) -> obj
1921 * Removes the named instance variable from <i>obj</i>, returning that
1923 * String arguments are converted to symbols.
1931 * remove_instance_variable(:@var)
1941 rb_obj_remove_instance_variable(VALUE obj
, VALUE name
)
1944 const ID id
= id_for_var(obj
, name
, an
, instance
);
1946 struct st_table
*iv_index_tbl
;
1949 rb_check_frozen(obj
);
1954 switch (BUILTIN_TYPE(obj
)) {
1956 iv_index_tbl
= ROBJECT_IV_INDEX_TBL(obj
);
1957 if (iv_index_tbl_lookup(iv_index_tbl
, id
, &index
) &&
1958 index
< ROBJECT_NUMIV(obj
) &&
1959 (val
= ROBJECT_IVPTR(obj
)[index
]) != Qundef
) {
1960 ROBJECT_IVPTR(obj
)[index
] = Qundef
;
1966 IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id
);
1968 if (RCLASS_IV_TBL(obj
) && lock_st_delete(RCLASS_IV_TBL(obj
), &n
, &v
)) {
1973 if (FL_TEST(obj
, FL_EXIVAR
)) {
1974 if (generic_ivar_remove(obj
, id
, &val
)) {
1982 rb_name_err_raise("instance variable %1$s not defined",
1984 UNREACHABLE_RETURN(Qnil
);
1987 NORETURN(static void uninitialized_constant(VALUE
, VALUE
));
1989 uninitialized_constant(VALUE klass
, VALUE name
)
1991 if (klass
&& rb_class_real(klass
) != rb_cObject
)
1992 rb_name_err_raise("uninitialized constant %2$s::%1$s",
1995 rb_name_err_raise("uninitialized constant %1$s",
2000 rb_const_missing(VALUE klass
, VALUE name
)
2002 VALUE value
= rb_funcallv(klass
, idConst_missing
, 1, &name
);
2003 rb_vm_inc_const_missing_count();
2010 * mod.const_missing(sym) -> obj
2012 * Invoked when a reference is made to an undefined constant in
2013 * <i>mod</i>. It is passed a symbol for the undefined constant, and
2014 * returns a value to be used for that constant. The
2015 * following code is an example of the same:
2017 * def Foo.const_missing(name)
2018 * name # return the constant name as Symbol
2021 * Foo::UNDEFINED_CONST #=> :UNDEFINED_CONST: symbol returned
2023 * In the next example when a reference is made to an undefined constant,
2024 * it attempts to load a file whose name is the lowercase version of the
2025 * constant (thus class <code>Fred</code> is assumed to be in file
2026 * <code>fred.rb</code>). If found, it returns the loaded class. It
2027 * therefore implements an autoload feature similar to Kernel#autoload and
2030 * def Object.const_missing(name)
2031 * @looked_for ||= {}
2032 * str_name = name.to_s
2033 * raise "Class not found: #{name}" if @looked_for[str_name]
2034 * @looked_for[str_name] = 1
2035 * file = str_name.downcase
2037 * klass = const_get(name)
2038 * return klass if klass
2039 * raise "Class not found: #{name}"
2045 rb_mod_const_missing(VALUE klass
, VALUE name
)
2047 VALUE ref
= GET_EC()->private_const_reference
;
2048 rb_vm_pop_cfunc_frame();
2050 rb_name_err_raise("private constant %2$s::%1$s referenced",
2053 uninitialized_constant(klass
, name
);
2055 UNREACHABLE_RETURN(Qnil
);
2059 autoload_mark(void *ptr
)
2061 rb_mark_tbl_no_pin((st_table
*)ptr
);
2065 autoload_free(void *ptr
)
2067 st_free_table((st_table
*)ptr
);
2071 autoload_memsize(const void *ptr
)
2073 const st_table
*tbl
= ptr
;
2074 return st_memsize(tbl
);
2078 autoload_compact(void *ptr
)
2080 rb_gc_update_tbl_refs((st_table
*)ptr
);
2083 static const rb_data_type_t autoload_data_type
= {
2085 {autoload_mark
, autoload_free
, autoload_memsize
, autoload_compact
,},
2086 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
2089 #define check_autoload_table(av) \
2090 (struct st_table *)rb_check_typeddata((av), &autoload_data_type)
2093 autoload_data(VALUE mod
, ID id
)
2095 struct st_table
*tbl
;
2098 if (!st_lookup(RCLASS_IV_TBL(mod
), autoload
, &val
) ||
2099 !(tbl
= check_autoload_table((VALUE
)val
)) ||
2100 !st_lookup(tbl
, (st_data_t
)id
, &val
)) {
2106 struct autoload_const
{
2107 struct list_node cnode
; /* <=> autoload_data_i.constants */
2109 VALUE ad
; /* autoload_data_i */
2113 rb_const_flag_t flag
;
2117 /* always on stack, no need to mark */
2118 struct autoload_state
{
2119 struct autoload_const
*ac
;
2122 struct list_head waitq
;
2125 struct autoload_data_i
{
2127 struct autoload_state
*state
; /* points to on-stack struct */
2128 rb_serial_t fork_gen
;
2129 struct list_head constants
; /* <=> autoload_const.cnode */
2133 autoload_i_compact(void *ptr
)
2135 struct autoload_data_i
*p
= ptr
;
2136 p
->feature
= rb_gc_location(p
->feature
);
2140 autoload_i_mark(void *ptr
)
2142 struct autoload_data_i
*p
= ptr
;
2144 rb_gc_mark_movable(p
->feature
);
2146 /* allow GC to free us if no modules refer to this via autoload_const.ad */
2147 if (list_empty(&p
->constants
)) {
2148 rb_hash_delete(autoload_featuremap
, p
->feature
);
2153 autoload_i_free(void *ptr
)
2155 struct autoload_data_i
*p
= ptr
;
2157 /* we may leak some memory at VM shutdown time, no big deal */
2158 if (list_empty(&p
->constants
)) {
2164 autoload_i_memsize(const void *ptr
)
2166 return sizeof(struct autoload_data_i
);
2169 static const rb_data_type_t autoload_data_i_type
= {
2171 {autoload_i_mark
, autoload_i_free
, autoload_i_memsize
, autoload_i_compact
},
2172 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
2176 autoload_c_compact(void *ptr
)
2178 struct autoload_const
*ac
= ptr
;
2180 ac
->mod
= rb_gc_location(ac
->mod
);
2181 ac
->ad
= rb_gc_location(ac
->ad
);
2182 ac
->value
= rb_gc_location(ac
->value
);
2183 ac
->file
= rb_gc_location(ac
->file
);
2187 autoload_c_mark(void *ptr
)
2189 struct autoload_const
*ac
= ptr
;
2191 rb_gc_mark_movable(ac
->mod
);
2192 rb_gc_mark_movable(ac
->ad
);
2193 rb_gc_mark_movable(ac
->value
);
2194 rb_gc_mark_movable(ac
->file
);
2198 autoload_c_free(void *ptr
)
2200 struct autoload_const
*ac
= ptr
;
2201 list_del(&ac
->cnode
);
2206 autoload_c_memsize(const void *ptr
)
2208 return sizeof(struct autoload_const
);
2211 static const rb_data_type_t autoload_const_type
= {
2213 {autoload_c_mark
, autoload_c_free
, autoload_c_memsize
, autoload_c_compact
,},
2214 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
2217 static struct autoload_data_i
*
2218 get_autoload_data(VALUE acv
, struct autoload_const
**acp
)
2220 struct autoload_const
*ac
= rb_check_typeddata(acv
, &autoload_const_type
);
2221 struct autoload_data_i
*ele
;
2223 ele
= rb_check_typeddata(ac
->ad
, &autoload_data_i_type
);
2224 /* do not reach across stack for ->state after forking: */
2225 if (ele
&& ele
->state
&& ele
->fork_gen
!= GET_VM()->fork_gen
) {
2233 RUBY_FUNC_EXPORTED
void
2234 rb_autoload(VALUE mod
, ID id
, const char *file
)
2236 if (!file
|| !*file
) {
2237 rb_raise(rb_eArgError
, "empty file name");
2239 rb_autoload_str(mod
, id
, rb_fstring_cstr(file
));
2243 rb_autoload_str(VALUE mod
, ID id
, VALUE file
)
2247 struct st_table
*tbl
;
2248 struct autoload_data_i
*ele
;
2249 rb_const_entry_t
*ce
;
2251 if (!rb_is_const_id(id
)) {
2252 rb_raise(rb_eNameError
, "autoload must be constant name: %"PRIsVALUE
"",
2256 Check_Type(file
, T_STRING
);
2257 if (!RSTRING_LEN(file
)) {
2258 rb_raise(rb_eArgError
, "empty file name");
2261 ce
= rb_const_lookup(mod
, id
);
2262 if (ce
&& ce
->value
!= Qundef
) {
2266 rb_const_set(mod
, id
, Qundef
);
2267 tbl
= RCLASS_IV_TBL(mod
);
2268 if (tbl
&& st_lookup(tbl
, (st_data_t
)autoload
, &av
)) {
2269 tbl
= check_autoload_table((VALUE
)av
);
2272 if (!tbl
) tbl
= RCLASS_IV_TBL(mod
) = st_init_numtable();
2273 av
= (st_data_t
)TypedData_Wrap_Struct(0, &autoload_data_type
, 0);
2274 st_add_direct(tbl
, (st_data_t
)autoload
, av
);
2275 RB_OBJ_WRITTEN(mod
, Qnil
, av
);
2276 DATA_PTR(av
) = tbl
= st_init_numtable();
2279 file
= rb_fstring(file
);
2280 if (!autoload_featuremap
) {
2281 autoload_featuremap
= rb_ident_hash_new();
2282 rb_obj_hide(autoload_featuremap
);
2283 rb_gc_register_mark_object(autoload_featuremap
);
2285 ad
= rb_hash_aref(autoload_featuremap
, file
);
2287 ad
= TypedData_Make_Struct(0, struct autoload_data_i
,
2288 &autoload_data_i_type
, ele
);
2289 ele
->feature
= file
;
2291 list_head_init(&ele
->constants
);
2292 rb_hash_aset(autoload_featuremap
, file
, ad
);
2295 ele
= rb_check_typeddata(ad
, &autoload_data_i_type
);
2299 struct autoload_const
*ac
;
2300 acv
= TypedData_Make_Struct(0, struct autoload_const
,
2301 &autoload_const_type
, ac
);
2305 ac
->flag
= CONST_PUBLIC
;
2307 list_add_tail(&ele
->constants
, &ac
->cnode
);
2308 st_insert(tbl
, (st_data_t
)id
, (st_data_t
)acv
);
2313 autoload_delete(VALUE mod
, ID id
)
2315 st_data_t val
, load
= 0, n
= id
;
2317 if (st_lookup(RCLASS_IV_TBL(mod
), (st_data_t
)autoload
, &val
)) {
2318 struct st_table
*tbl
= check_autoload_table((VALUE
)val
);
2319 struct autoload_data_i
*ele
;
2320 struct autoload_const
*ac
;
2322 st_delete(tbl
, &n
, &load
);
2323 /* Qfalse can indicate already deleted */
2324 if (load
!= Qfalse
) {
2325 ele
= get_autoload_data((VALUE
)load
, &ac
);
2328 VM_ASSERT(!list_empty(&ele
->constants
));
2332 * we must delete here to avoid "already initialized" warnings
2333 * with parallel autoload. Using list_del_init here so list_del
2334 * works in autoload_c_free
2336 list_del_init(&ac
->cnode
);
2338 if (tbl
->num_entries
== 0) {
2340 st_delete(RCLASS_IV_TBL(mod
), &n
, &val
);
2347 check_autoload_required(VALUE mod
, ID id
, const char **loadingpath
)
2350 VALUE load
= autoload_data(mod
, id
);
2351 struct autoload_data_i
*ele
;
2352 const char *loading
;
2354 if (!load
|| !(ele
= get_autoload_data(load
, 0))) {
2357 file
= ele
->feature
;
2358 Check_Type(file
, T_STRING
);
2359 if (!RSTRING_LEN(file
) || !*RSTRING_PTR(file
)) {
2360 rb_raise(rb_eArgError
, "empty file name");
2364 * if somebody else is autoloading, we MUST wait for them, since
2365 * rb_provide_feature can provide a feature before autoload_const_set
2366 * completes. We must wait until autoload_const_set finishes in
2369 if (ele
->state
&& ele
->state
->thread
!= rb_thread_current()) {
2373 loading
= RSTRING_PTR(file
);
2374 if (!rb_feature_provided(loading
, &loading
)) {
2377 if (loadingpath
&& loading
) {
2378 *loadingpath
= loading
;
2384 static struct autoload_const
*autoloading_const_entry(VALUE mod
, ID id
);
2386 MJIT_FUNC_EXPORTED
int
2387 rb_autoloading_value(VALUE mod
, ID id
, VALUE
* value
, rb_const_flag_t
*flag
)
2389 struct autoload_const
*ac
= autoloading_const_entry(mod
, id
);
2390 if (!ac
) return FALSE
;
2401 struct autoload_const
*
2402 autoloading_const_entry(VALUE mod
, ID id
)
2404 VALUE load
= autoload_data(mod
, id
);
2405 struct autoload_data_i
*ele
;
2406 struct autoload_const
*ac
;
2408 if (!load
|| !(ele
= get_autoload_data(load
, &ac
))) {
2412 if (ele
->state
&& ele
->state
->thread
== rb_thread_current()) {
2413 if (ac
->value
!= Qundef
) {
2421 autoload_defined_p(VALUE mod
, ID id
)
2423 rb_const_entry_t
*ce
= rb_const_lookup(mod
, id
);
2425 if (!ce
|| ce
->value
!= Qundef
) {
2428 return !rb_autoloading_value(mod
, id
, NULL
, NULL
);
2431 static void const_tbl_update(struct autoload_const
*);
2434 autoload_const_set(struct autoload_const
*ac
)
2436 VALUE klass
= ac
->mod
;
2438 check_before_mod_set(klass
, id
, ac
->value
, "constant");
2442 const_tbl_update(ac
);
2446 return 0; /* ignored */
2450 autoload_require(VALUE arg
)
2452 struct autoload_state
*state
= (struct autoload_state
*)arg
;
2453 struct autoload_const
*ac
= state
->ac
;
2454 struct autoload_data_i
*ele
;
2456 ele
= rb_check_typeddata(ac
->ad
, &autoload_data_i_type
);
2457 /* this may release GVL and switch threads: */
2458 state
->result
= rb_funcall(rb_vm_top_self(), rb_intern("require"), 1,
2461 return state
->result
;
2465 autoload_reset(VALUE arg
)
2467 struct autoload_state
*state
= (struct autoload_state
*)arg
;
2468 int need_wakeups
= 0;
2469 struct autoload_const
*ac
= state
->ac
;
2470 struct autoload_data_i
*ele
;
2472 ele
= rb_check_typeddata(ac
->ad
, &autoload_data_i_type
);
2473 if (ele
->state
== state
) {
2479 /* At the last, move a value defined in autoload to constant table */
2480 if (RTEST(state
->result
)) {
2481 struct autoload_const
*next
;
2483 list_for_each_safe(&ele
->constants
, ac
, next
, cnode
) {
2484 if (ac
->value
!= Qundef
) {
2485 autoload_const_set(ac
);
2490 /* wakeup any waiters we had */
2492 struct autoload_state
*cur
= 0, *nxt
;
2494 list_for_each_safe(&state
->waitq
, cur
, nxt
, waitq
.n
) {
2495 VALUE th
= cur
->thread
;
2497 cur
->thread
= Qfalse
;
2498 list_del_init(&cur
->waitq
.n
); /* idempotent */
2501 * cur is stored on the stack of cur->waiting_th,
2502 * do not touch cur after waking up waiting_th
2504 rb_thread_wakeup_alive(th
);
2508 return 0; /* ignored */
2512 autoload_sleep(VALUE arg
)
2514 struct autoload_state
*state
= (struct autoload_state
*)arg
;
2517 * autoload_reset in other thread will resume us and remove us
2518 * from the waitq list
2521 rb_thread_sleep_deadly();
2522 } while (state
->thread
!= Qfalse
);
2528 autoload_sleep_done(VALUE arg
)
2530 struct autoload_state
*state
= (struct autoload_state
*)arg
;
2532 if (state
->thread
!= Qfalse
&& rb_thread_to_be_killed(state
->thread
)) {
2533 list_del(&state
->waitq
.n
); /* idempotent after list_del_init */
2540 rb_autoload_load(VALUE mod
, ID id
)
2543 const char *loading
= 0, *src
;
2544 struct autoload_data_i
*ele
;
2545 struct autoload_const
*ac
;
2546 struct autoload_state state
;
2548 rb_const_entry_t
*ce
;
2550 if (!autoload_defined_p(mod
, id
)) return Qfalse
;
2551 load
= check_autoload_required(mod
, id
, &loading
);
2552 if (!load
) return Qfalse
;
2553 src
= rb_sourcefile();
2554 if (src
&& loading
&& strcmp(src
, loading
) == 0) return Qfalse
;
2556 if (UNLIKELY(!rb_ractor_main_p())) {
2557 rb_raise(rb_eRactorUnsafeError
, "require by autoload on non-main Ractor is not supported (%s)", rb_id2name(id
));
2560 if ((ce
= rb_const_lookup(mod
, id
))) {
2561 flag
= ce
->flag
& (CONST_DEPRECATED
| CONST_VISIBILITY_MASK
);
2564 /* set ele->state for a marker of autoloading thread */
2565 if (!(ele
= get_autoload_data(load
, &ac
))) {
2569 state
.thread
= rb_thread_current();
2571 ele
->state
= &state
;
2572 ele
->fork_gen
= GET_VM()->fork_gen
;
2575 * autoload_reset will wake up any threads added to this
2576 * if and only if the GVL is released during autoload_require
2578 list_head_init(&state
.waitq
);
2580 else if (state
.thread
== ele
->state
->thread
) {
2584 list_add_tail(&ele
->state
->waitq
, &state
.waitq
.n
);
2586 rb_ensure(autoload_sleep
, (VALUE
)&state
,
2587 autoload_sleep_done
, (VALUE
)&state
);
2590 /* autoload_data_i can be deleted by another thread while require */
2591 state
.result
= Qfalse
;
2592 result
= rb_ensure(autoload_require
, (VALUE
)&state
,
2593 autoload_reset
, (VALUE
)&state
);
2595 if (!(ce
= rb_const_lookup(mod
, id
)) || ce
->value
== Qundef
) {
2596 rb_const_remove(mod
, id
);
2598 else if (flag
> 0) {
2606 rb_autoload_p(VALUE mod
, ID id
)
2608 return rb_autoload_at_p(mod
, id
, TRUE
);
2612 rb_autoload_at_p(VALUE mod
, ID id
, int recur
)
2615 struct autoload_data_i
*ele
;
2617 while (!autoload_defined_p(mod
, id
)) {
2618 if (!recur
) return Qnil
;
2619 mod
= RCLASS_SUPER(mod
);
2620 if (!mod
) return Qnil
;
2622 load
= check_autoload_required(mod
, id
, 0);
2623 if (!load
) return Qnil
;
2624 return (ele
= get_autoload_data(load
, 0)) ? ele
->feature
: Qnil
;
2627 MJIT_FUNC_EXPORTED
void
2628 rb_const_warn_if_deprecated(const rb_const_entry_t
*ce
, VALUE klass
, ID id
)
2630 if (RB_CONST_DEPRECATED_P(ce
) &&
2631 rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED
)) {
2632 if (klass
== rb_cObject
) {
2633 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED
, "constant ::%"PRIsVALUE
" is deprecated", QUOTE_ID(id
));
2636 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED
, "constant %"PRIsVALUE
"::%"PRIsVALUE
" is deprecated",
2637 rb_class_name(klass
), QUOTE_ID(id
));
2643 rb_const_get_0(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
2645 VALUE c
= rb_const_search(klass
, id
, exclude
, recurse
, visibility
);
2647 if (UNLIKELY(!rb_ractor_main_p())) {
2648 if (!rb_ractor_shareable_p(c
)) {
2649 rb_raise(rb_eRactorIsolationError
, "can not access non-shareable objects in constant %"PRIsVALUE
"::%s by non-main Ractor.", rb_class_path(klass
), rb_id2name(id
));
2654 return rb_const_missing(klass
, ID2SYM(id
));
2658 rb_const_search_from(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
2660 VALUE value
, current
;
2661 bool first_iteration
= true;
2663 for (current
= klass
;
2665 current
= RCLASS_SUPER(current
), first_iteration
= false) {
2668 rb_const_entry_t
*ce
;
2670 if (!first_iteration
&& RCLASS_ORIGIN(current
) != current
) {
2671 // This item in the super chain has an origin iclass
2672 // that comes later in the chain. Skip this item so
2673 // prepended modules take precedence.
2677 // Do lookup in original class or module in case we are at an origin
2678 // iclass in the chain.
2680 if (BUILTIN_TYPE(tmp
) == T_ICLASS
) tmp
= RBASIC(tmp
)->klass
;
2682 // Do the lookup. Loop in case of autoload.
2683 while ((ce
= rb_const_lookup(tmp
, id
))) {
2684 if (visibility
&& RB_CONST_PRIVATE_P(ce
)) {
2685 GET_EC()->private_const_reference
= tmp
;
2688 rb_const_warn_if_deprecated(ce
, tmp
, id
);
2690 if (value
== Qundef
) {
2691 struct autoload_const
*ac
;
2692 if (am
== tmp
) break;
2694 ac
= autoloading_const_entry(tmp
, id
);
2695 if (ac
) return ac
->value
;
2696 rb_autoload_load(tmp
, id
);
2699 if (exclude
&& tmp
== rb_cObject
) {
2704 if (!recurse
) break;
2708 GET_EC()->private_const_reference
= 0;
2713 rb_const_search(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
2717 if (klass
== rb_cObject
) exclude
= FALSE
;
2718 value
= rb_const_search_from(klass
, id
, exclude
, recurse
, visibility
);
2719 if (value
!= Qundef
) return value
;
2720 if (exclude
) return value
;
2721 if (BUILTIN_TYPE(klass
) != T_MODULE
) return value
;
2722 /* search global const too, if klass is a module */
2723 return rb_const_search_from(rb_cObject
, id
, FALSE
, recurse
, visibility
);
2727 rb_const_get_from(VALUE klass
, ID id
)
2729 return rb_const_get_0(klass
, id
, TRUE
, TRUE
, FALSE
);
2733 rb_const_get(VALUE klass
, ID id
)
2735 return rb_const_get_0(klass
, id
, FALSE
, TRUE
, FALSE
);
2739 rb_const_get_at(VALUE klass
, ID id
)
2741 return rb_const_get_0(klass
, id
, TRUE
, FALSE
, FALSE
);
2744 MJIT_FUNC_EXPORTED VALUE
2745 rb_public_const_get_from(VALUE klass
, ID id
)
2747 return rb_const_get_0(klass
, id
, TRUE
, TRUE
, TRUE
);
2750 MJIT_FUNC_EXPORTED VALUE
2751 rb_public_const_get_at(VALUE klass
, ID id
)
2753 return rb_const_get_0(klass
, id
, TRUE
, FALSE
, TRUE
);
2756 NORETURN(static void undefined_constant(VALUE mod
, VALUE name
));
2758 undefined_constant(VALUE mod
, VALUE name
)
2760 rb_name_err_raise("constant %2$s::%1$s not defined",
2765 rb_const_location_from(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
2767 while (RTEST(klass
)) {
2768 rb_const_entry_t
*ce
;
2770 while ((ce
= rb_const_lookup(klass
, id
))) {
2771 if (visibility
&& RB_CONST_PRIVATE_P(ce
)) {
2774 if (exclude
&& klass
== rb_cObject
) {
2777 if (NIL_P(ce
->file
)) return rb_ary_new();
2778 return rb_assoc_new(ce
->file
, INT2NUM(ce
->line
));
2780 if (!recurse
) break;
2781 klass
= RCLASS_SUPER(klass
);
2789 rb_const_location(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
2793 if (klass
== rb_cObject
) exclude
= FALSE
;
2794 loc
= rb_const_location_from(klass
, id
, exclude
, recurse
, visibility
);
2795 if (!NIL_P(loc
)) return loc
;
2796 if (exclude
) return loc
;
2797 if (BUILTIN_TYPE(klass
) != T_MODULE
) return loc
;
2798 /* search global const too, if klass is a module */
2799 return rb_const_location_from(rb_cObject
, id
, FALSE
, recurse
, visibility
);
2803 rb_const_source_location(VALUE klass
, ID id
)
2805 return rb_const_location(klass
, id
, FALSE
, TRUE
, FALSE
);
2808 MJIT_FUNC_EXPORTED VALUE
2809 rb_const_source_location_at(VALUE klass
, ID id
)
2811 return rb_const_location(klass
, id
, TRUE
, FALSE
, FALSE
);
2816 * remove_const(sym) -> obj
2818 * Removes the definition of the given constant, returning that
2819 * constant's previous value. If that constant referred to
2820 * a module, this will not change that module's name and can lead
2825 rb_mod_remove_const(VALUE mod
, VALUE name
)
2827 const ID id
= id_for_var(mod
, name
, a
, constant
);
2830 undefined_constant(mod
, name
);
2832 return rb_const_remove(mod
, id
);
2836 rb_const_remove(VALUE mod
, ID id
)
2839 rb_const_entry_t
*ce
;
2841 rb_check_frozen(mod
);
2842 ce
= rb_const_lookup(mod
, id
);
2843 if (!ce
|| !rb_id_table_delete(RCLASS_CONST_TBL(mod
), id
)) {
2844 if (rb_const_defined_at(mod
, id
)) {
2845 rb_name_err_raise("cannot remove %2$s::%1$s",
2848 undefined_constant(mod
, ID2SYM(id
));
2851 rb_clear_constant_cache();
2854 if (val
== Qundef
) {
2855 autoload_delete(mod
, id
);
2863 cv_i_update(st_data_t
*k
, st_data_t
*v
, st_data_t a
, int existing
)
2865 if (existing
) return ST_STOP
;
2870 static enum rb_id_table_iterator_result
2871 sv_i(ID key
, VALUE v
, void *a
)
2873 rb_const_entry_t
*ce
= (rb_const_entry_t
*)v
;
2876 if (rb_is_const_id(key
)) {
2877 st_update(tbl
, (st_data_t
)key
, cv_i_update
, (st_data_t
)ce
);
2879 return ID_TABLE_CONTINUE
;
2882 static enum rb_id_table_iterator_result
2883 rb_local_constants_i(ID const_name
, VALUE const_value
, void *ary
)
2885 if (rb_is_const_id(const_name
) && !RB_CONST_PRIVATE_P((rb_const_entry_t
*)const_value
)) {
2886 rb_ary_push((VALUE
)ary
, ID2SYM(const_name
));
2888 return ID_TABLE_CONTINUE
;
2892 rb_local_constants(VALUE mod
)
2894 struct rb_id_table
*tbl
= RCLASS_CONST_TBL(mod
);
2897 if (!tbl
) return rb_ary_new2(0);
2901 ary
= rb_ary_new2(rb_id_table_size(tbl
));
2902 rb_id_table_foreach(tbl
, rb_local_constants_i
, (void *)ary
);
2910 rb_mod_const_at(VALUE mod
, void *data
)
2912 st_table
*tbl
= data
;
2914 tbl
= st_init_numtable();
2916 if (RCLASS_CONST_TBL(mod
)) {
2919 rb_id_table_foreach(RCLASS_CONST_TBL(mod
), sv_i
, tbl
);
2927 rb_mod_const_of(VALUE mod
, void *data
)
2931 data
= rb_mod_const_at(tmp
, data
);
2932 tmp
= RCLASS_SUPER(tmp
);
2934 if (tmp
== rb_cObject
&& mod
!= rb_cObject
) break;
2940 list_i(st_data_t key
, st_data_t value
, VALUE ary
)
2943 rb_const_entry_t
*ce
= (rb_const_entry_t
*)value
;
2944 if (RB_CONST_PUBLIC_P(ce
)) rb_ary_push(ary
, ID2SYM(sym
));
2949 rb_const_list(void *data
)
2951 st_table
*tbl
= data
;
2954 if (!tbl
) return rb_ary_new2(0);
2955 ary
= rb_ary_new2(tbl
->num_entries
);
2956 st_foreach_safe(tbl
, list_i
, ary
);
2964 * mod.constants(inherit=true) -> array
2966 * Returns an array of the names of the constants accessible in
2967 * <i>mod</i>. This includes the names of constants in any included
2968 * modules (example at start of section), unless the <i>inherit</i>
2969 * parameter is set to <code>false</code>.
2971 * The implementation makes no guarantees about the order in which the
2972 * constants are yielded.
2974 * IO.constants.include?(:SYNC) #=> true
2975 * IO.constants(false).include?(:SYNC) #=> false
2977 * Also see Module#const_defined?.
2981 rb_mod_constants(int argc
, const VALUE
*argv
, VALUE mod
)
2983 bool inherit
= true;
2985 if (rb_check_arity(argc
, 0, 1)) inherit
= RTEST(argv
[0]);
2988 return rb_const_list(rb_mod_const_of(mod
, 0));
2991 return rb_local_constants(mod
);
2996 rb_const_defined_0(VALUE klass
, ID id
, int exclude
, int recurse
, int visibility
)
3000 rb_const_entry_t
*ce
;
3005 if ((ce
= rb_const_lookup(tmp
, id
))) {
3006 if (visibility
&& RB_CONST_PRIVATE_P(ce
)) {
3009 if (ce
->value
== Qundef
&& !check_autoload_required(tmp
, id
, 0) &&
3010 !rb_autoloading_value(tmp
, id
, NULL
, NULL
))
3013 if (exclude
&& tmp
== rb_cObject
&& klass
!= rb_cObject
) {
3019 if (!recurse
) break;
3020 tmp
= RCLASS_SUPER(tmp
);
3022 if (!exclude
&& !mod_retry
&& BUILTIN_TYPE(klass
) == T_MODULE
) {
3031 rb_const_defined_from(VALUE klass
, ID id
)
3033 return rb_const_defined_0(klass
, id
, TRUE
, TRUE
, FALSE
);
3037 rb_const_defined(VALUE klass
, ID id
)
3039 return rb_const_defined_0(klass
, id
, FALSE
, TRUE
, FALSE
);
3043 rb_const_defined_at(VALUE klass
, ID id
)
3045 return rb_const_defined_0(klass
, id
, TRUE
, FALSE
, FALSE
);
3048 MJIT_FUNC_EXPORTED
int
3049 rb_public_const_defined_from(VALUE klass
, ID id
)
3051 return rb_const_defined_0(klass
, id
, TRUE
, TRUE
, TRUE
);
3055 check_before_mod_set(VALUE klass
, ID id
, VALUE val
, const char *dest
)
3057 rb_check_frozen(klass
);
3060 static void set_namespace_path(VALUE named_namespace
, VALUE name
);
3062 static enum rb_id_table_iterator_result
3063 set_namespace_path_i(ID id
, VALUE v
, void *payload
)
3065 rb_const_entry_t
*ce
= (rb_const_entry_t
*)v
;
3066 VALUE value
= ce
->value
;
3067 int has_permanent_classpath
;
3068 VALUE parental_path
= *((VALUE
*) payload
);
3069 if (!rb_is_const_id(id
) || !rb_namespace_p(value
)) {
3070 return ID_TABLE_CONTINUE
;
3072 classname(value
, &has_permanent_classpath
);
3073 if (has_permanent_classpath
) {
3074 return ID_TABLE_CONTINUE
;
3076 set_namespace_path(value
, build_const_path(parental_path
, id
));
3077 if (RCLASS_IV_TBL(value
)) {
3078 st_data_t tmp
= tmp_classpath
;
3079 st_delete(RCLASS_IV_TBL(value
), &tmp
, 0);
3082 return ID_TABLE_CONTINUE
;
3086 * Assign permanent classpaths to all namespaces that are directly or indirectly
3087 * nested under +named_namespace+. +named_namespace+ must have a permanent
3091 set_namespace_path(VALUE named_namespace
, VALUE namespace_path
)
3093 struct rb_id_table
*const_table
= RCLASS_CONST_TBL(named_namespace
);
3097 rb_class_ivar_set(named_namespace
, classpath
, namespace_path
);
3099 rb_id_table_foreach(const_table
, set_namespace_path_i
, &namespace_path
);
3106 const_added(VALUE klass
, ID const_name
)
3108 if (GET_VM()->running
) {
3109 VALUE name
= ID2SYM(const_name
);
3110 rb_funcallv(klass
, idConst_added
, 1, &name
);
3115 rb_const_set(VALUE klass
, ID id
, VALUE val
)
3117 rb_const_entry_t
*ce
;
3120 rb_raise(rb_eTypeError
, "no class/module to define constant %"PRIsVALUE
"",
3124 if (!rb_ractor_main_p() && !rb_ractor_shareable_p(val
)) {
3125 rb_raise(rb_eRactorIsolationError
, "can not set constants with non-shareable objects by non-main Ractors");
3128 check_before_mod_set(klass
, id
, val
, "constant");
3132 struct rb_id_table
*tbl
= RCLASS_CONST_TBL(klass
);
3134 RCLASS_CONST_TBL(klass
) = tbl
= rb_id_table_create(0);
3135 rb_clear_constant_cache();
3136 ce
= ZALLOC(rb_const_entry_t
);
3137 rb_id_table_insert(tbl
, id
, (VALUE
)ce
);
3138 setup_const_entry(ce
, klass
, val
, CONST_PUBLIC
);
3141 struct autoload_const ac
= {
3142 .mod
= klass
, .id
= id
,
3143 .value
= val
, .flag
= CONST_PUBLIC
,
3144 /* fill the rest with 0 */
3146 const_tbl_update(&ac
);
3152 * Resolve and cache class name immediately to resolve ambiguity
3153 * and avoid order-dependency on const_tbl
3155 if (rb_cObject
&& rb_namespace_p(val
)) {
3156 int val_path_permanent
;
3157 VALUE val_path
= classname(val
, &val_path_permanent
);
3158 if (NIL_P(val_path
) || !val_path_permanent
) {
3159 if (klass
== rb_cObject
) {
3160 set_namespace_path(val
, rb_id2str(id
));
3163 int parental_path_permanent
;
3164 VALUE parental_path
= classname(klass
, &parental_path_permanent
);
3165 if (NIL_P(parental_path
)) {
3167 parental_path
= rb_tmp_class_path(klass
, &throwaway
, make_temporary_path
);
3169 if (parental_path_permanent
&& !val_path_permanent
) {
3170 set_namespace_path(val
, build_const_path(parental_path
, id
));
3172 else if (!parental_path_permanent
&& NIL_P(val_path
)) {
3173 ivar_set(val
, tmp_classpath
, build_const_path(parental_path
, id
));
3178 const_added(klass
, id
);
3181 static struct autoload_data_i
*
3182 current_autoload_data(VALUE mod
, ID id
, struct autoload_const
**acp
)
3184 struct autoload_data_i
*ele
;
3185 VALUE load
= autoload_data(mod
, id
);
3186 if (!load
) return 0;
3187 ele
= get_autoload_data(load
, acp
);
3189 /* for autoloading thread, keep the defined value to autoloading storage */
3190 if (ele
->state
&& (ele
->state
->thread
== rb_thread_current())) {
3197 const_tbl_update(struct autoload_const
*ac
)
3200 VALUE klass
= ac
->mod
;
3201 VALUE val
= ac
->value
;
3203 struct rb_id_table
*tbl
= RCLASS_CONST_TBL(klass
);
3204 rb_const_flag_t visibility
= ac
->flag
;
3205 rb_const_entry_t
*ce
;
3207 if (rb_id_table_lookup(tbl
, id
, &value
)) {
3208 ce
= (rb_const_entry_t
*)value
;
3209 if (ce
->value
== Qundef
) {
3210 struct autoload_data_i
*ele
= current_autoload_data(klass
, id
, &ac
);
3213 rb_clear_constant_cache();
3215 ac
->value
= val
; /* autoload_i is non-WB-protected */
3216 ac
->file
= rb_source_location(&ac
->line
);
3219 /* otherwise autoloaded constant, allow to override */
3220 autoload_delete(klass
, id
);
3221 ce
->flag
= visibility
;
3222 RB_OBJ_WRITE(klass
, &ce
->value
, val
);
3223 RB_OBJ_WRITE(klass
, &ce
->file
, ac
->file
);
3224 ce
->line
= ac
->line
;
3229 VALUE name
= QUOTE_ID(id
);
3230 visibility
= ce
->flag
;
3231 if (klass
== rb_cObject
)
3232 rb_warn("already initialized constant %"PRIsVALUE
"", name
);
3234 rb_warn("already initialized constant %"PRIsVALUE
"::%"PRIsVALUE
"",
3235 rb_class_name(klass
), name
);
3236 if (!NIL_P(ce
->file
) && ce
->line
) {
3237 rb_compile_warn(RSTRING_PTR(ce
->file
), ce
->line
,
3238 "previous definition of %"PRIsVALUE
" was here", name
);
3241 rb_clear_constant_cache();
3242 setup_const_entry(ce
, klass
, val
, visibility
);
3245 rb_clear_constant_cache();
3247 ce
= ZALLOC(rb_const_entry_t
);
3248 rb_id_table_insert(tbl
, id
, (VALUE
)ce
);
3249 setup_const_entry(ce
, klass
, val
, visibility
);
3254 setup_const_entry(rb_const_entry_t
*ce
, VALUE klass
, VALUE val
,
3255 rb_const_flag_t visibility
)
3257 ce
->flag
= visibility
;
3258 RB_OBJ_WRITE(klass
, &ce
->value
, val
);
3259 RB_OBJ_WRITE(klass
, &ce
->file
, rb_source_location(&ce
->line
));
3263 rb_define_const(VALUE klass
, const char *name
, VALUE val
)
3265 ID id
= rb_intern(name
);
3267 if (!rb_is_const_id(id
)) {
3268 rb_warn("rb_define_const: invalid name `%s' for constant", name
);
3270 rb_gc_register_mark_object(val
);
3271 rb_const_set(klass
, id
, val
);
3275 rb_define_global_const(const char *name
, VALUE val
)
3277 rb_define_const(rb_cObject
, name
, val
);
3281 set_const_visibility(VALUE mod
, int argc
, const VALUE
*argv
,
3282 rb_const_flag_t flag
, rb_const_flag_t mask
)
3285 rb_const_entry_t
*ce
;
3288 rb_class_modify_check(mod
);
3290 rb_warning("%"PRIsVALUE
" with no argument is just ignored",
3291 QUOTE_ID(rb_frame_callee()));
3295 for (i
= 0; i
< argc
; i
++) {
3296 struct autoload_const
*ac
;
3297 VALUE val
= argv
[i
];
3298 id
= rb_check_id(&val
);
3301 rb_clear_constant_cache();
3304 undefined_constant(mod
, val
);
3306 if ((ce
= rb_const_lookup(mod
, id
))) {
3309 if (ce
->value
== Qundef
) {
3310 struct autoload_data_i
*ele
;
3312 ele
= current_autoload_data(mod
, id
, &ac
);
3321 rb_clear_constant_cache();
3323 undefined_constant(mod
, ID2SYM(id
));
3326 rb_clear_constant_cache();
3330 rb_deprecate_constant(VALUE mod
, const char *name
)
3332 rb_const_entry_t
*ce
;
3334 long len
= strlen(name
);
3336 rb_class_modify_check(mod
);
3337 if (!(id
= rb_check_id_cstr(name
, len
, NULL
))) {
3338 undefined_constant(mod
, rb_fstring_new(name
, len
));
3340 if (!(ce
= rb_const_lookup(mod
, id
))) {
3341 undefined_constant(mod
, ID2SYM(id
));
3343 ce
->flag
|= CONST_DEPRECATED
;
3348 * mod.private_constant(symbol, ...) => mod
3350 * Makes a list of existing constants private.
3354 rb_mod_private_constant(int argc
, const VALUE
*argv
, VALUE obj
)
3356 set_const_visibility(obj
, argc
, argv
, CONST_PRIVATE
, CONST_VISIBILITY_MASK
);
3362 * mod.public_constant(symbol, ...) => mod
3364 * Makes a list of existing constants public.
3368 rb_mod_public_constant(int argc
, const VALUE
*argv
, VALUE obj
)
3370 set_const_visibility(obj
, argc
, argv
, CONST_PUBLIC
, CONST_VISIBILITY_MASK
);
3376 * mod.deprecate_constant(symbol, ...) => mod
3378 * Makes a list of existing constants deprecated. Attempt
3379 * to refer to them will produce a warning.
3382 * NotFound = Exception.new
3383 * NOT_FOUND = NotFound # previous version of the library used this name
3385 * deprecate_constant :NOT_FOUND
3389 * # warning: constant HTTP::NOT_FOUND is deprecated
3394 rb_mod_deprecate_constant(int argc
, const VALUE
*argv
, VALUE obj
)
3396 set_const_visibility(obj
, argc
, argv
, CONST_DEPRECATED
, CONST_DEPRECATED
);
3401 original_module(VALUE c
)
3403 if (RB_TYPE_P(c
, T_ICLASS
))
3404 return RBASIC(c
)->klass
;
3409 cvar_lookup_at(VALUE klass
, ID id
, st_data_t
*v
)
3411 if (!RCLASS_IV_TBL(klass
)) return 0;
3412 return st_lookup(RCLASS_IV_TBL(klass
), (st_data_t
)id
, v
);
3416 cvar_front_klass(VALUE klass
)
3418 if (FL_TEST(klass
, FL_SINGLETON
)) {
3419 VALUE obj
= rb_ivar_get(klass
, id__attached__
);
3420 if (rb_namespace_p(obj
)) {
3424 return RCLASS_SUPER(klass
);
3428 cvar_overtaken(VALUE front
, VALUE target
, ID id
)
3430 if (front
&& target
!= front
) {
3431 st_data_t did
= (st_data_t
)id
;
3433 if (original_module(front
) != original_module(target
)) {
3434 rb_raise(rb_eRuntimeError
,
3435 "class variable % "PRIsVALUE
" of %"PRIsVALUE
" is overtaken by %"PRIsVALUE
"",
3436 ID2SYM(id
), rb_class_name(original_module(front
)),
3437 rb_class_name(original_module(target
)));
3439 if (BUILTIN_TYPE(front
) == T_CLASS
) {
3440 st_delete(RCLASS_IV_TBL(front
), &did
, 0);
3446 find_cvar(VALUE klass
, VALUE
* front
, VALUE
* target
, ID id
)
3449 CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR();
3450 if (cvar_lookup_at(klass
, id
, (&v
))) {
3457 for (klass
= cvar_front_klass(klass
); klass
; klass
= RCLASS_SUPER(klass
)) {
3458 if (cvar_lookup_at(klass
, id
, (&v
))) {
3469 #define CVAR_FOREACH_ANCESTORS(klass, v, r) \
3470 for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
3471 if (cvar_lookup_at(klass, id, (v))) { \
3476 #define CVAR_LOOKUP(v,r) do {\
3477 CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(); \
3478 if (cvar_lookup_at(klass, id, (v))) {r;}\
3479 CVAR_FOREACH_ANCESTORS(klass, v, r);\
3483 check_for_cvar_table(VALUE subclass
, VALUE key
)
3485 st_table
*tbl
= RCLASS_IV_TBL(subclass
);
3487 if (tbl
&& st_lookup(tbl
, key
, NULL
)) {
3488 RB_DEBUG_COUNTER_INC(cvar_class_invalidate
);
3489 ruby_vm_global_cvar_state
++;
3493 rb_class_foreach_subclass(subclass
, check_for_cvar_table
, key
);
3497 rb_cvar_set(VALUE klass
, ID id
, VALUE val
)
3499 VALUE tmp
, front
= 0, target
= 0;
3502 CVAR_LOOKUP(0, {if (!front
) front
= klass
; target
= klass
;});
3504 cvar_overtaken(front
, target
, id
);
3510 if (RB_TYPE_P(target
, T_ICLASS
)) {
3511 target
= RBASIC(target
)->klass
;
3513 check_before_mod_set(target
, id
, val
, "class variable");
3515 int result
= rb_class_ivar_set(target
, id
, val
);
3517 struct rb_id_table
*rb_cvc_tbl
= RCLASS_CVC_TBL(target
);
3520 rb_cvc_tbl
= RCLASS_CVC_TBL(target
) = rb_id_table_create(2);
3523 struct rb_cvar_class_tbl_entry
*ent
;
3526 if (!rb_id_table_lookup(rb_cvc_tbl
, id
, &ent_data
)) {
3527 ent
= ALLOC(struct rb_cvar_class_tbl_entry
);
3528 ent
->class_value
= target
;
3529 ent
->global_cvar_state
= GET_GLOBAL_CVAR_STATE();
3530 rb_id_table_insert(rb_cvc_tbl
, id
, (VALUE
)ent
);
3531 RB_DEBUG_COUNTER_INC(cvar_inline_miss
);
3534 ent
= (void *)ent_data
;
3535 ent
->global_cvar_state
= GET_GLOBAL_CVAR_STATE();
3538 // Break the cvar cache if this is a new class variable
3539 // and target is a module or a subclass with the same
3540 // cvar in this lookup.
3542 if (RB_TYPE_P(target
, T_CLASS
)) {
3543 if (RCLASS_SUBCLASSES(target
)) {
3544 rb_class_foreach_subclass(target
, check_for_cvar_table
, id
);
3551 rb_cvar_find(VALUE klass
, ID id
, VALUE
*front
)
3556 value
= find_cvar(klass
, front
, &target
, id
);
3558 rb_name_err_raise("uninitialized class variable %1$s in %2$s",
3561 cvar_overtaken(*front
, target
, id
);
3562 return (VALUE
)value
;
3566 rb_cvar_get(VALUE klass
, ID id
)
3569 return rb_cvar_find(klass
, id
, &front
);
3573 rb_cvar_defined(VALUE klass
, ID id
)
3575 if (!klass
) return Qfalse
;
3576 CVAR_LOOKUP(0,return Qtrue
);
3581 cv_intern(VALUE klass
, const char *name
)
3583 ID id
= rb_intern(name
);
3584 if (!rb_is_class_id(id
)) {
3585 rb_name_err_raise("wrong class variable name %1$s",
3586 klass
, rb_str_new_cstr(name
));
3592 rb_cv_set(VALUE klass
, const char *name
, VALUE val
)
3594 ID id
= cv_intern(klass
, name
);
3595 rb_cvar_set(klass
, id
, val
);
3599 rb_cv_get(VALUE klass
, const char *name
)
3601 ID id
= cv_intern(klass
, name
);
3602 return rb_cvar_get(klass
, id
);
3606 rb_define_class_variable(VALUE klass
, const char *name
, VALUE val
)
3608 rb_cv_set(klass
, name
, val
);
3612 cv_i(st_data_t k
, st_data_t v
, st_data_t a
)
3615 st_table
*tbl
= (st_table
*)a
;
3617 if (rb_is_class_id(key
)) {
3618 st_update(tbl
, (st_data_t
)key
, cv_i_update
, 0);
3624 mod_cvar_at(VALUE mod
, void *data
)
3626 st_table
*tbl
= data
;
3628 tbl
= st_init_numtable();
3630 if (RCLASS_IV_TBL(mod
)) {
3631 st_foreach_safe(RCLASS_IV_TBL(mod
), cv_i
, (st_data_t
)tbl
);
3637 mod_cvar_of(VALUE mod
, void *data
)
3640 if (FL_TEST(mod
, FL_SINGLETON
)) {
3641 if (rb_namespace_p(rb_ivar_get(mod
, id__attached__
))) {
3642 data
= mod_cvar_at(tmp
, data
);
3643 tmp
= cvar_front_klass(tmp
);
3647 data
= mod_cvar_at(tmp
, data
);
3648 tmp
= RCLASS_SUPER(tmp
);
3655 cv_list_i(st_data_t key
, st_data_t value
, VALUE ary
)
3658 rb_ary_push(ary
, ID2SYM(sym
));
3663 cvar_list(void *data
)
3665 st_table
*tbl
= data
;
3668 if (!tbl
) return rb_ary_new2(0);
3669 ary
= rb_ary_new2(tbl
->num_entries
);
3670 st_foreach_safe(tbl
, cv_list_i
, ary
);
3678 * mod.class_variables(inherit=true) -> array
3680 * Returns an array of the names of class variables in <i>mod</i>.
3681 * This includes the names of class variables in any included
3682 * modules, unless the <i>inherit</i> parameter is set to
3683 * <code>false</code>.
3691 * One.class_variables #=> [:@@var1]
3692 * Two.class_variables #=> [:@@var2, :@@var1]
3693 * Two.class_variables(false) #=> [:@@var2]
3697 rb_mod_class_variables(int argc
, const VALUE
*argv
, VALUE mod
)
3699 bool inherit
= true;
3702 if (rb_check_arity(argc
, 0, 1)) inherit
= RTEST(argv
[0]);
3704 tbl
= mod_cvar_of(mod
, 0);
3707 tbl
= mod_cvar_at(mod
, 0);
3709 return cvar_list(tbl
);
3714 * remove_class_variable(sym) -> obj
3716 * Removes the named class variable from the receiver, returning that
3721 * puts remove_class_variable(:@@var)
3725 * <em>produces:</em>
3732 rb_mod_remove_cvar(VALUE mod
, VALUE name
)
3734 const ID id
= id_for_var_message(mod
, name
, class, "wrong class variable name %1$s");
3735 st_data_t val
, n
= id
;
3740 rb_check_frozen(mod
);
3741 if (RCLASS_IV_TBL(mod
) && st_delete(RCLASS_IV_TBL(mod
), &n
, &val
)) {
3744 if (rb_cvar_defined(mod
, id
)) {
3745 rb_name_err_raise("cannot remove %1$s for %2$s", mod
, ID2SYM(id
));
3748 rb_name_err_raise("class variable %1$s not defined for %2$s",
3750 UNREACHABLE_RETURN(Qundef
);
3754 rb_iv_get(VALUE obj
, const char *name
)
3756 ID id
= rb_check_id_cstr(name
, strlen(name
), rb_usascii_encoding());
3761 return rb_ivar_get(obj
, id
);
3765 rb_iv_set(VALUE obj
, const char *name
, VALUE val
)
3767 ID id
= rb_intern(name
);
3769 return rb_ivar_set(obj
, id
, val
);
3772 /* tbl = xx(obj); tbl[key] = value; */
3774 rb_class_ivar_set(VALUE obj
, ID key
, VALUE value
)
3776 if (!RCLASS_IV_TBL(obj
)) {
3777 RCLASS_IV_TBL(obj
) = st_init_numtable();
3780 st_table
*tbl
= RCLASS_IV_TBL(obj
);
3781 int result
= lock_st_insert(tbl
, (st_data_t
)key
, (st_data_t
)value
);
3782 RB_OBJ_WRITTEN(obj
, Qundef
, value
);
3787 tbl_copy_i(st_data_t key
, st_data_t value
, st_data_t data
)
3789 RB_OBJ_WRITTEN((VALUE
)data
, Qundef
, (VALUE
)value
);
3794 rb_iv_tbl_copy(VALUE dst
, VALUE src
)
3796 st_table
*orig_tbl
= RCLASS_IV_TBL(src
);
3797 st_table
*new_tbl
= st_copy(orig_tbl
);
3798 st_foreach(new_tbl
, tbl_copy_i
, (st_data_t
)dst
);
3799 RCLASS_IV_TBL(dst
) = new_tbl
;
3802 MJIT_FUNC_EXPORTED rb_const_entry_t
*
3803 rb_const_lookup(VALUE klass
, ID id
)
3805 struct rb_id_table
*tbl
= RCLASS_CONST_TBL(klass
);
3812 r
= rb_id_table_lookup(tbl
, id
, &val
);
3816 if (r
) return (rb_const_entry_t
*)val
;