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