Ruby: vm_callinfo.h Source File

Ruby 4.0.6p0 (2026-07-14 revision 03b6d3f8898a28604fe6cb00eae3226b821168f4)

vm_callinfo.h
1#ifndef RUBY_VM_CALLINFO_H /*-*-C-*-vi:se ft=c:*/
2#define RUBY_VM_CALLINFO_H
10
11#include "debug_counter.h"
12#include "internal/class.h"
13#include "shape.h"
14
15enum vm_call_flag_bits {
16 VM_CALL_ARGS_SPLAT_bit, // m(*args)
17 VM_CALL_ARGS_BLOCKARG_bit, // m(&block)
18 VM_CALL_FCALL_bit, // m(args) # receiver is self
19 VM_CALL_VCALL_bit, // m # method call that looks like a local variable
20 VM_CALL_ARGS_SIMPLE_bit, // !(ci->flag & (SPLAT|BLOCKARG|KWARG|KW_SPLAT|FORWARDING)) && !has_block_iseq
21 VM_CALL_KWARG_bit, // has kwarg
22 VM_CALL_KW_SPLAT_bit, // m(**opts)
23 VM_CALL_TAILCALL_bit, // located at tail position
24 VM_CALL_SUPER_bit, // super
25 VM_CALL_ZSUPER_bit, // zsuper
26 VM_CALL_OPT_SEND_bit, // internal flag
27 VM_CALL_KW_SPLAT_MUT_bit, // kw splat hash can be modified (to avoid allocating a new one)
28 VM_CALL_ARGS_SPLAT_MUT_bit, // args splat can be modified (to avoid allocating a new one)
29 VM_CALL_FORWARDING_bit, // m(...)
30 VM_CALL__END
31};
32
33#define VM_CALL_ARGS_SPLAT (0x01 << VM_CALL_ARGS_SPLAT_bit)
34#define VM_CALL_ARGS_BLOCKARG (0x01 << VM_CALL_ARGS_BLOCKARG_bit)
35#define VM_CALL_FCALL (0x01 << VM_CALL_FCALL_bit)
36#define VM_CALL_VCALL (0x01 << VM_CALL_VCALL_bit)
37#define VM_CALL_ARGS_SIMPLE (0x01 << VM_CALL_ARGS_SIMPLE_bit)
38#define VM_CALL_KWARG (0x01 << VM_CALL_KWARG_bit)
39#define VM_CALL_KW_SPLAT (0x01 << VM_CALL_KW_SPLAT_bit)
40#define VM_CALL_TAILCALL (0x01 << VM_CALL_TAILCALL_bit)
41#define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit)
42#define VM_CALL_ZSUPER (0x01 << VM_CALL_ZSUPER_bit)
43#define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit)
44#define VM_CALL_KW_SPLAT_MUT (0x01 << VM_CALL_KW_SPLAT_MUT_bit)
45#define VM_CALL_ARGS_SPLAT_MUT (0x01 << VM_CALL_ARGS_SPLAT_MUT_bit)
46#define VM_CALL_FORWARDING (0x01 << VM_CALL_FORWARDING_bit)
47
48 struct rb_callinfo_kwarg {
49 int keyword_len;
50 rb_atomic_t references;
51 VALUE keywords[];
52};
53
54static inline size_t
55rb_callinfo_kwarg_bytes(int keyword_len)
56{
57 return rb_size_mul_add_or_raise(
58 keyword_len,
59 sizeof(VALUE),
60 sizeof(struct rb_callinfo_kwarg),
61 rb_eRuntimeError);
62}
63
64static inline void
65rb_callinfo_kwarg_retain(struct rb_callinfo_kwarg *kwarg)
66{
67 if (kwarg) RUBY_ATOMIC_INC(kwarg->references);
68}
69
70static inline void
71rb_callinfo_kwarg_release(struct rb_callinfo_kwarg *kwarg)
72{
73 if (kwarg && RUBY_ATOMIC_FETCH_SUB(kwarg->references, 1) == 1) {
74 ruby_sized_xfree(kwarg, rb_callinfo_kwarg_bytes(kwarg->keyword_len));
75 }
76}
77
78// imemo_callinfo
79 struct rb_callinfo {
80 VALUE flags;
81 const struct rb_callinfo_kwarg *kwarg;
82 VALUE mid;
83 VALUE flag;
84 VALUE argc;
85};
86
87#if !defined(USE_EMBED_CI) || (USE_EMBED_CI+0)
88#undef USE_EMBED_CI
89#define USE_EMBED_CI 1
90#else
91#undef USE_EMBED_CI
92#define USE_EMBED_CI 0
93#endif
94
95#if SIZEOF_VALUE == 8
96#define CI_EMBED_TAG_bits 1
97#define CI_EMBED_ARGC_bits 15
98#define CI_EMBED_FLAG_bits 16
99#define CI_EMBED_ID_bits 32
100#elif SIZEOF_VALUE == 4
101#define CI_EMBED_TAG_bits 1
102#define CI_EMBED_ARGC_bits 3
103#define CI_EMBED_FLAG_bits 13
104#define CI_EMBED_ID_bits 15
105#endif
106
107#if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
108#error
109#endif
110
111#define CI_EMBED_FLAG 0x01
112#define CI_EMBED_ARGC_SHFT (CI_EMBED_TAG_bits)
113#define CI_EMBED_ARGC_MASK ((((VALUE)1)<<CI_EMBED_ARGC_bits) - 1)
114#define CI_EMBED_FLAG_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits)
115#define CI_EMBED_FLAG_MASK ((((VALUE)1)<<CI_EMBED_FLAG_bits) - 1)
116#define CI_EMBED_ID_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits)
117#define CI_EMBED_ID_MASK ((((VALUE)1)<<CI_EMBED_ID_bits) - 1)
118
119static inline bool
120vm_ci_packed_p(const struct rb_callinfo *ci)
121{
122 if (!USE_EMBED_CI) {
123 return 0;
124 }
125 if (LIKELY(((VALUE)ci) & 0x01)) {
126 return 1;
127 }
128 else {
129 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
130 return 0;
131 }
132}
133
134static inline bool
135vm_ci_p(const struct rb_callinfo *ci)
136{
137 if (vm_ci_packed_p(ci) || IMEMO_TYPE_P(ci, imemo_callinfo)) {
138 return 1;
139 }
140 else {
141 return 0;
142 }
143}
144
145static inline ID
146vm_ci_mid(const struct rb_callinfo *ci)
147{
148 if (vm_ci_packed_p(ci)) {
149 return (((VALUE)ci) >> CI_EMBED_ID_SHFT) & CI_EMBED_ID_MASK;
150 }
151 else {
152 return (ID)ci->mid;
153 }
154}
155
156static inline unsigned int
157vm_ci_flag(const struct rb_callinfo *ci)
158{
159 if (vm_ci_packed_p(ci)) {
160 return (unsigned int)((((VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
161 }
162 else {
163 return (unsigned int)ci->flag;
164 }
165}
166
167static inline unsigned int
168vm_ci_argc(const struct rb_callinfo *ci)
169{
170 if (vm_ci_packed_p(ci)) {
171 return (unsigned int)((((VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
172 }
173 else {
174 return (unsigned int)ci->argc;
175 }
176}
177
178static inline const struct rb_callinfo_kwarg *
179vm_ci_kwarg(const struct rb_callinfo *ci)
180{
181 if (vm_ci_packed_p(ci)) {
182 return NULL;
183 }
184 else {
185 return ci->kwarg;
186 }
187}
188
189static inline void
190vm_ci_dump(const struct rb_callinfo *ci)
191{
192 if (vm_ci_packed_p(ci)) {
193 ruby_debug_printf("packed_ci ID:%s flag:%x argc:%u\n",
194 rb_id2name(vm_ci_mid(ci)), vm_ci_flag(ci), vm_ci_argc(ci));
195 }
196 else {
197 rp(ci);
198 }
199}
200
201#define vm_ci_new(mid, flag, argc, kwarg) vm_ci_new_(mid, flag, argc, kwarg, __FILE__, __LINE__)
202#define vm_ci_new_runtime(mid, flag, argc, kwarg) vm_ci_new_runtime_(mid, flag, argc, kwarg, __FILE__, __LINE__)
203
204/* This is passed to STATIC_ASSERT. Cannot be an inline function. */
205#define VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg) \
206 (((mid ) & ~CI_EMBED_ID_MASK) ? false : \
207 ((flag) & ~CI_EMBED_FLAG_MASK) ? false : \
208 ((argc) & ~CI_EMBED_ARGC_MASK) ? false : \
209 (kwarg) ? false : true)
210
211#define vm_ci_new_id(mid, flag, argc, must_zero) \
212 ((const struct rb_callinfo *) \
213 ((((VALUE)(mid )) << CI_EMBED_ID_SHFT) | \
214 (((VALUE)(flag)) << CI_EMBED_FLAG_SHFT) | \
215 (((VALUE)(argc)) << CI_EMBED_ARGC_SHFT) | \
216 RUBY_FIXNUM_FLAG))
217
218// vm_method.c
219const struct rb_callinfo *rb_vm_ci_lookup(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg);
220void rb_vm_ci_free(const struct rb_callinfo *);
221
222static inline const struct rb_callinfo *
223vm_ci_new_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
224{
225 if (USE_EMBED_CI && VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg)) {
226 RB_DEBUG_COUNTER_INC(ci_packed);
227 return vm_ci_new_id(mid, flag, argc, kwarg);
228 }
229
230 const bool debug = 0;
231 if (debug) ruby_debug_printf("%s:%d ", file, line);
232
233 const struct rb_callinfo *ci = rb_vm_ci_lookup(mid, flag, argc, kwarg);
234
235 if (debug) rp(ci);
236 if (kwarg) {
237 RB_DEBUG_COUNTER_INC(ci_kw);
238 }
239 else {
240 RB_DEBUG_COUNTER_INC(ci_nokw);
241 }
242
243 VM_ASSERT(vm_ci_flag(ci) == flag);
244 VM_ASSERT(vm_ci_argc(ci) == argc);
245
246 return ci;
247}
248
249
250static inline const struct rb_callinfo *
251vm_ci_new_runtime_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
252{
253 RB_DEBUG_COUNTER_INC(ci_runtime);
254 return vm_ci_new_(mid, flag, argc, kwarg, file, line);
255}
256
257#define VM_CALLINFO_NOT_UNDER_GC IMEMO_FL_USER0
258
259static inline bool
260vm_ci_markable(const struct rb_callinfo *ci)
261{
262 if (! ci) {
263 return false; /* or true? This is Qfalse... */
264 }
265 else if (vm_ci_packed_p(ci)) {
266 return true;
267 }
268 else {
269 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
270 return ! FL_ANY_RAW((VALUE)ci, VM_CALLINFO_NOT_UNDER_GC);
271 }
272}
273
274#define VM_CI_ON_STACK(mid_, flags_, argc_, kwarg_) \
275 (struct rb_callinfo) { \
276 .flags = T_IMEMO | \
277 (imemo_callinfo << FL_USHIFT) | \
278 VM_CALLINFO_NOT_UNDER_GC, \
279 .mid = mid_, \
280 .flag = flags_, \
281 .argc = argc_, \
282 .kwarg = kwarg_, \
283 }
284
285typedef VALUE (*vm_call_handler)(
286 struct rb_execution_context_struct *ec,
287 struct rb_control_frame_struct *cfp,
288 struct rb_calling_info *calling);
289
290// imemo_callcache
291
292 struct rb_callcache {
293 const VALUE flags;
294
295 /* inline cache: key */
296 const VALUE klass; // Weak reference. When klass is collected, `cc->klass = Qundef`.
297
298 /* inline cache: values */
299 const struct rb_callable_method_entry_struct * const cme_;
300 const vm_call_handler call_;
301
302 union {
303 struct {
304 uint64_t value; // Shape ID in former half, index in latter half
305 } attr;
306 const enum method_missing_reason method_missing_reason; /* used by method_missing */
307 VALUE v;
308 const struct rb_builtin_function *bf;
309 } aux_;
310};
311
312/* VM_CALLCACHE_IVAR used for IVAR/ATTRSET/STRUCT_AREF/STRUCT_ASET methods */
313#define VM_CALLCACHE_IVAR IMEMO_FL_USER0
314#define VM_CALLCACHE_BF IMEMO_FL_USER1
315#define VM_CALLCACHE_SUPER IMEMO_FL_USER2
316#define VM_CALLCACHE_REFINEMENT IMEMO_FL_USER3
317#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER4
318#define VM_CALLCACHE_ON_STACK IMEMO_FL_USER5
319#define VM_CALLCACHE_INVALID_SUPER IMEMO_FL_USER6
320
321enum vm_cc_type {
322 cc_type_normal, // chained from ccs
323 cc_type_super,
324 cc_type_refinement,
325};
326
327extern const struct rb_callcache *rb_vm_empty_cc(void);
328extern const struct rb_callcache *rb_vm_empty_cc_for_super(void);
329
330#define vm_cc_empty() rb_vm_empty_cc()
331
332static inline void vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id);
333
334static inline void
335vm_cc_attr_index_initialize(const struct rb_callcache *cc, shape_id_t shape_id)
336{
337 vm_cc_attr_index_set(cc, (attr_index_t)-1, shape_id);
338}
339
340static inline VALUE
341cc_check_class(VALUE klass)
342{
343 VM_ASSERT(klass == Qundef || RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
344 return klass;
345}
346
347 VALUE rb_vm_cc_table_create(size_t capa);
348 VALUE rb_vm_cc_table_dup(VALUE old_table);
349void rb_vm_cc_table_delete(VALUE table, ID mid);
350
351static inline const struct rb_callcache *
352vm_cc_new(VALUE klass,
353 const struct rb_callable_method_entry_struct *cme,
354 vm_call_handler call,
355 enum vm_cc_type type)
356{
357 cc_check_class(klass);
358 struct rb_callcache *cc = SHAREABLE_IMEMO_NEW(struct rb_callcache, imemo_callcache, klass);
359 *((struct rb_callable_method_entry_struct **)&cc->cme_) = (struct rb_callable_method_entry_struct *)cme;
360 *((vm_call_handler *)&cc->call_) = call;
361
362 switch (type) {
363 case cc_type_normal:
364 break;
365 case cc_type_super:
366 *(VALUE *)&cc->flags |= VM_CALLCACHE_SUPER;
367 break;
368 case cc_type_refinement:
369 *(VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT;
370 rb_vm_insert_cc_refinement(cc);
371 break;
372 }
373
374 if (cme) {
375 if (cme->def->type == VM_METHOD_TYPE_ATTRSET || cme->def->type == VM_METHOD_TYPE_IVAR) {
376 vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
377 }
378 }
379 else {
380 *(VALUE *)&cc->flags |= VM_CALLCACHE_INVALID_SUPER;
381 }
382
383 RB_DEBUG_COUNTER_INC(cc_new);
384 return cc;
385}
386
387static inline bool
388vm_cc_super_p(const struct rb_callcache *cc)
389{
390 return (cc->flags & VM_CALLCACHE_SUPER) != 0;
391}
392
393static inline bool
394vm_cc_refinement_p(const struct rb_callcache *cc)
395{
396 return (cc->flags & VM_CALLCACHE_REFINEMENT) != 0;
397}
398
399#define VM_CC_ON_STACK(clazz, call, aux, cme) \
400 (struct rb_callcache) { \
401 .flags = T_IMEMO | \
402 (imemo_callcache << FL_USHIFT) | \
403 VM_CALLCACHE_UNMARKABLE | \
404 VM_CALLCACHE_ON_STACK, \
405 .klass = cc_check_class(clazz), \
406 .cme_ = cme, \
407 .call_ = call, \
408 .aux_ = aux, \
409 }
410
411static inline bool
412vm_cc_class_check(const struct rb_callcache *cc, VALUE klass)
413{
414 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
415 VM_ASSERT(cc_check_class(cc->klass));
416 return cc->klass == klass;
417}
418
419static inline int
420vm_cc_markable(const struct rb_callcache *cc)
421{
422 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
423 return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_UNMARKABLE) == 0;
424}
425
426static inline bool
427vm_cc_invalid_super(const struct rb_callcache *cc)
428{
429 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
430 // Set when calling super and there is no superclass.
431 return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_INVALID_SUPER);
432}
433
434static inline bool
435vm_cc_valid(const struct rb_callcache *cc)
436{
437 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
438 VM_ASSERT(cc_check_class(cc->klass));
439
440 return !UNDEF_P(cc->klass);
441}
442
443static inline const struct rb_callable_method_entry_struct *
444vm_cc_cme(const struct rb_callcache *cc)
445{
446 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
447 VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
448 VM_ASSERT(cc_check_class(cc->klass));
449 VM_ASSERT(cc->call_ == NULL || // not initialized yet
450 !vm_cc_markable(cc) ||
451 vm_cc_invalid_super(cc) ||
452 cc->cme_ != NULL);
453
454 return cc->cme_;
455}
456
457static inline vm_call_handler
458vm_cc_call(const struct rb_callcache *cc)
459{
460 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
461 VM_ASSERT(cc->call_ != NULL);
462 VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
463 VM_ASSERT(cc_check_class(cc->klass));
464 return cc->call_;
465}
466
467static inline void
468vm_unpack_shape_and_index(const uint64_t cache_value, shape_id_t *shape_id, attr_index_t *index)
469{
470 union rb_attr_index_cache cache = {
471 .pack = cache_value,
472 };
473 *shape_id = cache.unpack.shape_id;
474 *index = cache.unpack.index - 1;
475}
476
477static inline void
478vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t *shape_id, attr_index_t *index)
479{
480 vm_unpack_shape_and_index(ATOMIC_U64_LOAD_RELAXED(cc->aux_.attr.value), shape_id, index);
481}
482
483static inline void
484vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t *shape_id, attr_index_t *index)
485{
486 vm_unpack_shape_and_index(ATOMIC_U64_LOAD_RELAXED(ic->value), shape_id, index);
487}
488
489static inline unsigned int
490vm_cc_cmethod_missing_reason(const struct rb_callcache *cc)
491{
492 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
493 return cc->aux_.method_missing_reason;
494}
495
496static inline bool
497vm_cc_invalidated_p(const struct rb_callcache *cc)
498{
499 if (vm_cc_valid(cc) && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
500 return false;
501 }
502 else {
503 return true;
504 }
505}
506
507/* callcache: mutate */
508
509static inline void
510vm_cc_call_set(const struct rb_callcache *cc, vm_call_handler call)
511{
512 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
513 VM_ASSERT(cc != vm_cc_empty());
514 *(vm_call_handler *)&cc->call_ = call;
515}
516
517static inline void
518set_vm_cc_ivar(const struct rb_callcache *cc)
519{
520 *(VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
521}
522
523static inline uint64_t
524vm_pack_shape_and_index(shape_id_t shape_id, attr_index_t index)
525{
526 union rb_attr_index_cache cache = {
527 .unpack = {
528 .shape_id = shape_id,
529 .index = index + 1,
530 }
531 };
532 return cache.pack;
533}
534
535static inline void
536vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id)
537{
538 uint64_t *attr_value = (uint64_t *)&cc->aux_.attr.value;
539 if (!vm_cc_markable(cc)) {
540 *attr_value = vm_pack_shape_and_index(INVALID_SHAPE_ID, ATTR_INDEX_NOT_SET);
541 return;
542 }
543 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
544 VM_ASSERT(cc != vm_cc_empty());
545 *attr_value = vm_pack_shape_and_index(dest_shape_id, index);
546 set_vm_cc_ivar(cc);
547}
548
549static inline bool
550vm_cc_ivar_p(const struct rb_callcache *cc)
551{
552 return (cc->flags & VM_CALLCACHE_IVAR) != 0;
553}
554
555static inline void
556vm_ic_attr_index_set(const rb_iseq_t *iseq, struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t dest_shape_id)
557{
558 ATOMIC_U64_SET_RELAXED(ic->value, vm_pack_shape_and_index(dest_shape_id, index));
559}
560
561static inline void
562vm_ic_attr_index_initialize(struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
563{
564 ATOMIC_U64_SET_RELAXED(ic->value, vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET));
565}
566
567static inline void
568vm_cc_method_missing_reason_set(const struct rb_callcache *cc, enum method_missing_reason reason)
569{
570 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
571 VM_ASSERT(cc != vm_cc_empty());
572 *(enum method_missing_reason *)&cc->aux_.method_missing_reason = reason;
573}
574
575static inline void
576vm_cc_bf_set(const struct rb_callcache *cc, const struct rb_builtin_function *bf)
577{
578 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
579 VM_ASSERT(cc != vm_cc_empty());
580 *(const struct rb_builtin_function **)&cc->aux_.bf = bf;
581 *(VALUE *)&cc->flags |= VM_CALLCACHE_BF;
582}
583
584static inline bool
585vm_cc_bf_p(const struct rb_callcache *cc)
586{
587 return (cc->flags & VM_CALLCACHE_BF) != 0;
588}
589
590static inline void
591vm_cc_invalidate(const struct rb_callcache *cc)
592{
593 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
594 VM_ASSERT(cc != vm_cc_empty());
595 // TODO: rb_multi_ractor_p() is a workaround to stabilize CI
596 VM_ASSERT(cc->klass != Qundef || rb_multi_ractor_p()); // should be enable
597
598 *(VALUE *)&cc->klass = Qundef;
599 RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
600}
601
602/* calldata */
603
604 struct rb_call_data {
605 const struct rb_callinfo *ci;
606 const struct rb_callcache *cc;
607};
608
609 struct rb_class_cc_entries {
610#if VM_CHECK_MODE > 0
611 VALUE debug_sig;
612#endif
613 int capa;
614 int len;
615 const struct rb_callable_method_entry_struct *cme;
616 struct rb_class_cc_entries_entry {
617 const struct rb_callcache *cc;
618 unsigned int argc;
619 unsigned short flag;
620 unsigned short kw_len;
621 } entries[FLEX_ARY_LEN];
622};
623
624/* entries[].flag is an unsigned short, so every VM_CALL flag bit must fit in 16 bits. */
625STATIC_ASSERT(cc_entries_flag_fits_in_short, VM_CALL__END <= 16);
626
627/* entries[].kw_len is an unsigned short, so a call site cannot carry, nor a method
628 declare, more keyword arguments than this. Enforced at compile time. */
629#define VM_CALL_KW_LEN_MAX UINT16_MAX
630
631static inline size_t
632vm_ccs_alloc_size(size_t capa)
633{
634 return offsetof(struct rb_class_cc_entries, entries) + (sizeof(struct rb_class_cc_entries_entry) * capa);
635}
636
637#if VM_CHECK_MODE > 0
638
639const rb_callable_method_entry_t *rb_vm_lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
640void rb_vm_dump_overloaded_cme_table(void);
641
642static inline bool
643vm_ccs_p(const struct rb_class_cc_entries *ccs)
644{
645 return ccs->debug_sig == ~(VALUE)ccs;
646}
647
648static inline bool
649vm_cc_check_cme(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme)
650{
651 bool valid;
652 RB_VM_LOCKING_NO_BARRIER() {
653 valid = vm_cc_cme(cc) == cme ||
654 (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme));
655 }
656 if (valid) {
657 return true;
658 }
659#if 1
660 // debug print
661
662 fprintf(stderr, "iseq_overload:%d, cme:%p (def:%p), cm_cc_cme(cc):%p (def:%p)\n",
663 (int)cme->def->iseq_overload,
664 cme, cme->def,
665 vm_cc_cme(cc), vm_cc_cme(cc)->def);
666 rp(cme);
667 rp(vm_cc_cme(cc));
668 rp(rb_vm_lookup_overloaded_cme(cme));
669#endif
670 return false;
671}
672
673#endif
674
675#endif /* RUBY_VM_CALLINFO_H */
RUBY_ATOMIC_INC
#define RUBY_ATOMIC_INC(var)
Atomically increments the value pointed by var.
Definition atomic.h:214
rb_atomic_t
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
RUBY_ATOMIC_FETCH_SUB
#define RUBY_ATOMIC_FETCH_SUB(var, val)
Atomically replaces the value pointed by var with the result of subtraction of val to the old value o...
Definition atomic.h:129
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
T_ICLASS
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
FL_TEST_RAW
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:131
FL_ANY_RAW
#define FL_ANY_RAW
Old name of RB_FL_ANY_RAW.
Definition fl_type.h:125
T_CLASS
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
capa
int capa
Designed capacity of the buffer.
Definition io.h:11
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition cxxanyargs.hpp:56
iseq_inline_iv_cache_entry
Definition vm_core.h:288
rb_builtin_function
Definition builtin.h:6
rb_call_data
Definition vm_callinfo.h:604
rb_callable_method_entry_struct
Definition method.h:63
rb_callcache
Definition vm_callinfo.h:292
rb_callinfo_kwarg
Definition vm_callinfo.h:48
rb_callinfo
Definition vm_callinfo.h:79
rb_calling_info
Definition vm_core.h:306
rb_class_cc_entries::rb_class_cc_entries_entry
Definition vm_callinfo.h:616
rb_class_cc_entries
Definition vm_callinfo.h:609
rb_control_frame_struct
Definition vm_core.h:912
rb_execution_context_struct
Definition vm_core.h:1034
rb_attr_index_cache
Definition shape.h:133
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376