1#ifndef RUBY_VM_CALLINFO_H
2#define RUBY_VM_CALLINFO_H
11#include "debug_counter.h"
12#include "internal/class.h"
15enum vm_call_flag_bits {
16 VM_CALL_ARGS_SPLAT_bit,
17 VM_CALL_ARGS_BLOCKARG_bit,
20 VM_CALL_ARGS_SIMPLE_bit,
27 VM_CALL_KW_SPLAT_MUT_bit,
28 VM_CALL_ARGS_SPLAT_MUT_bit,
29 VM_CALL_FORWARDING_bit,
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)
55rb_callinfo_kwarg_bytes(
int keyword_len)
57 return rb_size_mul_add_or_raise(
74 ruby_xfree_sized(kwarg, rb_callinfo_kwarg_bytes(kwarg->keyword_len));
87#if !defined(USE_EMBED_CI) || (USE_EMBED_CI+0)
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
107#if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
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)
125 if (LIKELY(((
VALUE)ci) & 0x01)) {
129 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
137 if (vm_ci_packed_p(ci) || IMEMO_TYPE_P(ci, imemo_callinfo)) {
148 if (vm_ci_packed_p(ci)) {
149 return (((
VALUE)ci) >> CI_EMBED_ID_SHFT) & CI_EMBED_ID_MASK;
156static inline unsigned int
159 if (vm_ci_packed_p(ci)) {
160 return (
unsigned int)((((
VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
167static inline unsigned int
170 if (vm_ci_packed_p(ci)) {
171 return (
unsigned int)((((
VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
181 if (vm_ci_packed_p(ci)) {
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));
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__)
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)
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) | \
223vm_ci_new_(
ID mid,
unsigned int flag,
unsigned int argc,
const struct rb_callinfo_kwarg *kwarg,
const char *file,
int line)
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);
230 const bool debug = 0;
231 if (debug) ruby_debug_printf(
"%s:%d ", file, line);
233 const struct rb_callinfo *ci = rb_vm_ci_lookup(mid, flag, argc, kwarg);
237 RB_DEBUG_COUNTER_INC(ci_kw);
240 RB_DEBUG_COUNTER_INC(ci_nokw);
243 VM_ASSERT(vm_ci_flag(ci) == flag);
244 VM_ASSERT(vm_ci_argc(ci) == argc);
251vm_ci_new_runtime_(
ID mid,
unsigned int flag,
unsigned int argc,
const struct rb_callinfo_kwarg *kwarg,
const char *file,
int line)
253 RB_DEBUG_COUNTER_INC(ci_runtime);
254 return vm_ci_new_(mid, flag, argc, kwarg, file, line);
257#define VM_CALLINFO_NOT_UNDER_GC IMEMO_FL_USER0
265 else if (vm_ci_packed_p(ci)) {
269 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
274#define VM_CI_ON_STACK(mid_, flags_, argc_, kwarg_) \
275 (struct rb_callinfo) { \
277 (imemo_callinfo << FL_USHIFT) | \
278 VM_CALLINFO_NOT_UNDER_GC, \
285typedef VALUE (*vm_call_handler)(
300 const vm_call_handler call_;
306 const enum method_missing_reason method_missing_reason;
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
328extern const struct rb_callcache *rb_vm_empty_cc_for_super(
void);
330#define vm_cc_empty() rb_vm_empty_cc()
333cc_check_class(
VALUE klass)
341void rb_vm_cc_table_delete(
VALUE table,
ID mid);
343static inline void vm_cc_attr_index_set(
const struct rb_callcache *cc, uint64_t packed_cache);
346vm_cc_new(
VALUE klass,
348 vm_call_handler call,
349 enum vm_cc_type
type)
351 cc_check_class(klass);
353 rb_gc_declare_weak_references((
VALUE)cc);
356 *((vm_call_handler *)&cc->call_) = call;
362 *(
VALUE *)&cc->flags |= VM_CALLCACHE_SUPER;
364 case cc_type_refinement:
365 *(
VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT;
366 rb_vm_insert_cc_refinement(cc);
371 if (cme->def->type == VM_METHOD_TYPE_ATTRSET) {
372 vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
374 else if (cme->def->type == VM_METHOD_TYPE_IVAR) {
375 vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
379 *(
VALUE *)&cc->flags |= VM_CALLCACHE_INVALID_SUPER;
382 RB_DEBUG_COUNTER_INC(cc_new);
389 return (cc->flags & VM_CALLCACHE_SUPER) != 0;
395 return (cc->flags & VM_CALLCACHE_REFINEMENT) != 0;
398#define VM_CC_ON_STACK(clazz, call, aux, cme) \
399 (struct rb_callcache) { \
401 (imemo_callcache << FL_USHIFT) | \
402 VM_CALLCACHE_UNMARKABLE | \
403 VM_CALLCACHE_ON_STACK, \
404 .klass = cc_check_class(clazz), \
413 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
414 VM_ASSERT(cc_check_class(cc->klass));
415 return cc->klass == klass;
421 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
428 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
436 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
437 VM_ASSERT(cc_check_class(cc->klass));
439 return !UNDEF_P(cc->klass);
449# define VM_CC_RACED_P() rb_multi_ractor_p()
451# define VM_CC_RACED_P() true
457 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
461 VM_ASSERT(cc->klass !=
Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc) || VM_CC_RACED_P());
462 VM_ASSERT(cc_check_class(cc->klass));
463 VM_ASSERT(cc->call_ == NULL ||
464 !vm_cc_markable(cc) ||
465 vm_cc_invalid_super(cc) ||
471static inline vm_call_handler
474 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
475 VM_ASSERT(cc->call_ != NULL);
476 VM_ASSERT(cc->klass !=
Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc) || VM_CC_RACED_P());
477 VM_ASSERT(cc_check_class(cc->klass));
481static inline uint64_t
484 return ATOMIC_U64_LOAD_RELAXED(cc->aux_.attr.value);
487static inline uint64_t
490 return ATOMIC_U64_LOAD_RELAXED(ic->value);
493static inline uint64_t
497 return vm_cc_atomic_cache_read(cc);
500 return vm_ic_atomic_cache_read(ic);
504static inline unsigned int
505vm_cc_cmethod_missing_reason(
const struct rb_callcache *cc)
507 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
508 return cc->aux_.method_missing_reason;
514 if (vm_cc_valid(cc) && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
525vm_cc_call_set(
const struct rb_callcache *cc, vm_call_handler call)
527 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
528 VM_ASSERT(cc != vm_cc_empty());
529 *(vm_call_handler *)&cc->call_ = call;
535 *(
VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
541 return (cc->flags & VM_CALLCACHE_IVAR) != 0;
545vm_cc_attr_index_set(
const struct rb_callcache *cc, uint64_t packed_cache)
547 uint64_t *attr_value = (uint64_t *)&cc->aux_.attr.value;
548 if (!vm_cc_markable(cc)) {
549 *attr_value = IVAR_CACHE_INIT;
552 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
553 VM_ASSERT(cc != vm_cc_empty());
554 *attr_value = packed_cache;
562 vm_cc_attr_index_set(cc, packed_cache);
565 ATOMIC_U64_SET_RELAXED(ic->value, packed_cache);
570vm_cc_method_missing_reason_set(
const struct rb_callcache *cc,
enum method_missing_reason reason)
572 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
573 VM_ASSERT(cc != vm_cc_empty());
574 *(
enum method_missing_reason *)&cc->aux_.method_missing_reason = reason;
580 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
581 VM_ASSERT(cc != vm_cc_empty());
583 *(
VALUE *)&cc->flags |= VM_CALLCACHE_BF;
589 return (cc->flags & VM_CALLCACHE_BF) != 0;
595 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
596 VM_ASSERT(cc != vm_cc_empty());
598 VM_ASSERT(cc->klass !=
Qundef || rb_multi_ractor_p());
601 RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
622 unsigned short kw_len;
623 } entries[FLEX_ARY_LEN];
627STATIC_ASSERT(cc_entries_flag_fits_in_short, VM_CALL__END <= 16);
631#define VM_CALL_KW_LEN_MAX UINT16_MAX
634vm_ccs_alloc_size(
size_t capa)
642void rb_vm_dump_overloaded_cme_table(
void);
647 return ccs->debug_sig == ~(
VALUE)ccs;
653 return vm_cc_cme(cc) == cme ||
654 (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme));
661 if (rb_current_execution_context(
false) == NULL) {
662 valid = vm_cc_check_cme_unlocked(cc, cme);
665 RB_VM_LOCKING_NO_BARRIER() {
666 valid = vm_cc_check_cme_unlocked(cc, cme);
675 fprintf(stderr,
"iseq_overload:%d, cme:%p (def:%p), cm_cc_cme(cc):%p (def:%p)\n",
676 (
int)cme->def->iseq_overload,
677 (
void *)cme, (
void *)cme->def,
678 (
void *)vm_cc_cme(cc), (
void *)vm_cc_cme(cc)->def);
681 rp(rb_vm_lookup_overloaded_cme(cme));
#define RUBY_ATOMIC_INC(var)
Atomically increments the value pointed by var.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#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...
#define Qundef
Old name of RUBY_Qundef.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#define FL_ANY_RAW
Old name of RB_FL_ANY_RAW.
#define T_CLASS
Old name of RUBY_T_CLASS.
VALUE rb_eRuntimeError
RuntimeError exception.
int capa
Designed capacity of the buffer.
VALUE type(ANYARGS)
ANYARGS-ed function type.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.