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,
31#define VM_CALL_ARGS_SPLAT (0x01 << VM_CALL_ARGS_SPLAT_bit)
32#define VM_CALL_ARGS_BLOCKARG (0x01 << VM_CALL_ARGS_BLOCKARG_bit)
33#define VM_CALL_FCALL (0x01 << VM_CALL_FCALL_bit)
34#define VM_CALL_VCALL (0x01 << VM_CALL_VCALL_bit)
35#define VM_CALL_ARGS_SIMPLE (0x01 << VM_CALL_ARGS_SIMPLE_bit)
36#define VM_CALL_KWARG (0x01 << VM_CALL_KWARG_bit)
37#define VM_CALL_KW_SPLAT (0x01 << VM_CALL_KW_SPLAT_bit)
38#define VM_CALL_TAILCALL (0x01 << VM_CALL_TAILCALL_bit)
39#define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit)
40#define VM_CALL_ZSUPER (0x01 << VM_CALL_ZSUPER_bit)
41#define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit)
42#define VM_CALL_KW_SPLAT_MUT (0x01 << VM_CALL_KW_SPLAT_MUT_bit)
51rb_callinfo_kwarg_bytes(
int keyword_len)
53 return rb_size_mul_add_or_raise(
69#if !defined(USE_EMBED_CI) || (USE_EMBED_CI+0)
78#define CI_EMBED_TAG_bits 1
79#define CI_EMBED_ARGC_bits 15
80#define CI_EMBED_FLAG_bits 16
81#define CI_EMBED_ID_bits 32
82#elif SIZEOF_VALUE == 4
83#define CI_EMBED_TAG_bits 1
84#define CI_EMBED_ARGC_bits 3
85#define CI_EMBED_FLAG_bits 13
86#define CI_EMBED_ID_bits 15
89#if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
93#define CI_EMBED_FLAG 0x01
94#define CI_EMBED_ARGC_SHFT (CI_EMBED_TAG_bits)
95#define CI_EMBED_ARGC_MASK ((((VALUE)1)<<CI_EMBED_ARGC_bits) - 1)
96#define CI_EMBED_FLAG_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits)
97#define CI_EMBED_FLAG_MASK ((((VALUE)1)<<CI_EMBED_FLAG_bits) - 1)
98#define CI_EMBED_ID_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits)
99#define CI_EMBED_ID_MASK ((((VALUE)1)<<CI_EMBED_ID_bits) - 1)
107 if (LIKELY(((
VALUE)ci) & 0x01)) {
111 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
119 if (vm_ci_packed_p(ci) || IMEMO_TYPE_P(ci, imemo_callinfo)) {
130 if (vm_ci_packed_p(ci)) {
131 return (((
VALUE)ci) >> CI_EMBED_ID_SHFT) & CI_EMBED_ID_MASK;
138static inline unsigned int
141 if (vm_ci_packed_p(ci)) {
142 return (
unsigned int)((((
VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
145 return (
unsigned int)ci->flag;
149static inline unsigned int
152 if (vm_ci_packed_p(ci)) {
153 return (
unsigned int)((((
VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
156 return (
unsigned int)ci->argc;
163 if (vm_ci_packed_p(ci)) {
174 if (vm_ci_packed_p(ci)) {
175 ruby_debug_printf(
"packed_ci ID:%s flag:%x argc:%u\n",
176 rb_id2name(vm_ci_mid(ci)), vm_ci_flag(ci), vm_ci_argc(ci));
183#define vm_ci_new(mid, flag, argc, kwarg) vm_ci_new_(mid, flag, argc, kwarg, __FILE__, __LINE__)
184#define vm_ci_new_runtime(mid, flag, argc, kwarg) vm_ci_new_runtime_(mid, flag, argc, kwarg, __FILE__, __LINE__)
187#define VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg) \
188 (((mid ) & ~CI_EMBED_ID_MASK) ? false : \
189 ((flag) & ~CI_EMBED_FLAG_MASK) ? false : \
190 ((argc) & ~CI_EMBED_ARGC_MASK) ? false : \
191 (kwarg) ? false : true)
193#define vm_ci_new_id(mid, flag, argc, must_zero) \
194 ((const struct rb_callinfo *) \
195 ((((VALUE)(mid )) << CI_EMBED_ID_SHFT) | \
196 (((VALUE)(flag)) << CI_EMBED_FLAG_SHFT) | \
197 (((VALUE)(argc)) << CI_EMBED_ARGC_SHFT) | \
205vm_ci_new_(
ID mid,
unsigned int flag,
unsigned int argc,
const struct rb_callinfo_kwarg *kwarg,
const char *file,
int line)
207 if (USE_EMBED_CI && VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg)) {
208 RB_DEBUG_COUNTER_INC(ci_packed);
209 return vm_ci_new_id(mid, flag, argc, kwarg);
212 const bool debug = 0;
213 if (debug) ruby_debug_printf(
"%s:%d ", file, line);
215 const struct rb_callinfo *ci = rb_vm_ci_lookup(mid, flag, argc, kwarg);
218 RB_DEBUG_COUNTER_INC(ci_kw);
221 RB_DEBUG_COUNTER_INC(ci_nokw);
224 VM_ASSERT(vm_ci_flag(ci) == flag);
225 VM_ASSERT(vm_ci_argc(ci) == argc);
232vm_ci_new_runtime_(
ID mid,
unsigned int flag,
unsigned int argc,
const struct rb_callinfo_kwarg *kwarg,
const char *file,
int line)
234 RB_DEBUG_COUNTER_INC(ci_runtime);
235 return vm_ci_new_(mid, flag, argc, kwarg, file, line);
238#define VM_CALLINFO_NOT_UNDER_GC IMEMO_FL_USER0
246 else if (vm_ci_packed_p(ci)) {
250 VM_ASSERT(IMEMO_TYPE_P(ci, imemo_callinfo));
255#define VM_CI_ON_STACK(mid_, flags_, argc_, kwarg_) \
256 (struct rb_callinfo) { \
258 (imemo_callinfo << FL_USHIFT) | \
259 VM_CALLINFO_NOT_UNDER_GC, \
266typedef VALUE (*vm_call_handler)(
283 const vm_call_handler call_;
289 const enum method_missing_reason method_missing_reason;
295#define VM_CALLCACHE_UNMARKABLE FL_FREEZE
296#define VM_CALLCACHE_ON_STACK FL_EXIVAR
299#define VM_CALLCACHE_IVAR IMEMO_FL_USER0
300#define VM_CALLCACHE_BF IMEMO_FL_USER1
301#define VM_CALLCACHE_SUPER IMEMO_FL_USER2
302#define VM_CALLCACHE_REFINEMENT IMEMO_FL_USER3
311extern const struct rb_callcache *rb_vm_empty_cc_for_super(
void);
313#define vm_cc_empty() rb_vm_empty_cc()
315static inline void vm_cc_attr_index_set(
const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id);
318vm_cc_attr_index_initialize(
const struct rb_callcache *cc, shape_id_t shape_id)
320 vm_cc_attr_index_set(cc, (attr_index_t)-1, shape_id);
324vm_cc_new(
VALUE klass,
326 vm_call_handler call,
327 enum vm_cc_type
type)
335 *(
VALUE *)&cc->flags |= VM_CALLCACHE_SUPER;
337 case cc_type_refinement:
338 *(
VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT;
342 vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
343 RB_DEBUG_COUNTER_INC(cc_new);
350 return (cc->flags & VM_CALLCACHE_SUPER) != 0;
356 return (cc->flags & VM_CALLCACHE_REFINEMENT) != 0;
359#define VM_CC_ON_STACK(clazz, call, aux, cme) \
360 (struct rb_callcache) { \
362 (imemo_callcache << FL_USHIFT) | \
363 VM_CALLCACHE_UNMARKABLE | \
364 VM_CALLCACHE_ON_STACK, \
374 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
375 VM_ASSERT(cc->klass == 0 ||
377 return cc->klass == klass;
383 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
390 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
391 VM_ASSERT(cc->call_ == NULL ||
392 !vm_cc_markable(cc) ||
398static inline vm_call_handler
401 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
402 VM_ASSERT(cc->call_ != NULL);
406static inline attr_index_t
409 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
410 return (attr_index_t)((cc->aux_.attr.value & SHAPE_FLAG_MASK) - 1);
413static inline shape_id_t
414vm_cc_attr_index_dest_shape_id(
const struct rb_callcache *cc)
416 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
418 return cc->aux_.attr.value >> SHAPE_FLAG_SHIFT;
422vm_cc_atomic_shape_and_index(
const struct rb_callcache *cc, shape_id_t * shape_id, attr_index_t * index)
424 uintptr_t cache_value = cc->aux_.attr.value;
425 *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
426 *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
433 uintptr_t cache_value = ic->value;
434 *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
435 *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
439static inline shape_id_t
442 return (shape_id_t)(ic->value >> SHAPE_FLAG_SHIFT);
445static inline unsigned int
446vm_cc_cmethod_missing_reason(
const struct rb_callcache *cc)
448 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
449 return cc->aux_.method_missing_reason;
455 if (cc->klass && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
467 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
468 if (cc->klass == klass && !METHOD_ENTRY_INVALIDATED(cc_cme)) {
479vm_cc_call_set(
const struct rb_callcache *cc, vm_call_handler call)
481 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
482 VM_ASSERT(cc != vm_cc_empty());
483 *(vm_call_handler *)&cc->call_ = call;
489 *(
VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
493vm_cc_attr_index_set(
const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id)
495 uintptr_t *attr_value = (uintptr_t *)&cc->aux_.attr.value;
496 if (!vm_cc_markable(cc)) {
497 *attr_value = (uintptr_t)INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT;
500 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
501 VM_ASSERT(cc != vm_cc_empty());
502 *attr_value = (attr_index_t)(index + 1) | ((uintptr_t)(dest_shape_id) << SHAPE_FLAG_SHIFT);
509 return (cc->flags & VM_CALLCACHE_IVAR) != 0;
515 *(uintptr_t *)&ic->value = ((uintptr_t)dest_shape_id << SHAPE_FLAG_SHIFT) | (attr_index_t)(index + 1);
521 *(uintptr_t *)&ic->value = (uintptr_t)shape_id << SHAPE_FLAG_SHIFT;
525vm_cc_method_missing_reason_set(
const struct rb_callcache *cc,
enum method_missing_reason reason)
527 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
528 VM_ASSERT(cc != vm_cc_empty());
529 *(
enum method_missing_reason *)&cc->aux_.method_missing_reason = reason;
535 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
536 VM_ASSERT(cc != vm_cc_empty());
538 *(
VALUE *)&cc->flags |= VM_CALLCACHE_BF;
544 return (cc->flags & VM_CALLCACHE_BF) != 0;
550 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
551 VM_ASSERT(cc != vm_cc_empty());
552 VM_ASSERT(cc->klass != 0);
554 *(
VALUE *)&cc->klass = 0;
555 RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
581void rb_vm_dump_overloaded_cme_table(
void);
586 return ccs->debug_sig == ~(
VALUE)ccs;
592 if (vm_cc_cme(cc) == cme ||
593 (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme))) {
600 fprintf(stderr,
"iseq_overload:%d\n", (
int)cme->def->iseq_overload);
603 rb_vm_lookup_overloaded_cme(cme);
#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.
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.