1 #ifndef RUBY_VM_CALLINFO_H /*-*-C-*-vi:se ft=c:*/
2 #define RUBY_VM_CALLINFO_H
4 * @author Ruby developers <ruby-core@ruby-lang.org>
5 * @copyright This file is a part of the programming language Ruby.
6 * Permission is hereby granted, to either redistribute and/or
7 * modify this file, provided that the conditions mentioned in the
8 * file COPYING are met. Consult the file for details.
11 #include "debug_counter.h"
13 enum vm_call_flag_bits
{
14 VM_CALL_ARGS_SPLAT_bit
, /* m(*args) */
15 VM_CALL_ARGS_BLOCKARG_bit
, /* m(&block) */
16 VM_CALL_FCALL_bit
, /* m(...) */
17 VM_CALL_VCALL_bit
, /* m */
18 VM_CALL_ARGS_SIMPLE_bit
, /* (ci->flag & (SPLAT|BLOCKARG)) && blockiseq == NULL && ci->kw_arg == NULL */
19 VM_CALL_BLOCKISEQ_bit
, /* has blockiseq */
20 VM_CALL_KWARG_bit
, /* has kwarg */
21 VM_CALL_KW_SPLAT_bit
, /* m(**opts) */
22 VM_CALL_TAILCALL_bit
, /* located at tail position */
23 VM_CALL_SUPER_bit
, /* super */
24 VM_CALL_ZSUPER_bit
, /* zsuper */
25 VM_CALL_OPT_SEND_bit
, /* internal flag */
26 VM_CALL_KW_SPLAT_MUT_bit
, /* kw splat hash can be modified (to avoid allocating a new one) */
30 #define VM_CALL_ARGS_SPLAT (0x01 << VM_CALL_ARGS_SPLAT_bit)
31 #define VM_CALL_ARGS_BLOCKARG (0x01 << VM_CALL_ARGS_BLOCKARG_bit)
32 #define VM_CALL_FCALL (0x01 << VM_CALL_FCALL_bit)
33 #define VM_CALL_VCALL (0x01 << VM_CALL_VCALL_bit)
34 #define VM_CALL_ARGS_SIMPLE (0x01 << VM_CALL_ARGS_SIMPLE_bit)
35 #define VM_CALL_BLOCKISEQ (0x01 << VM_CALL_BLOCKISEQ_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)
44 struct rb_callinfo_kwarg
{
50 rb_callinfo_kwarg_bytes(int keyword_len
)
52 return rb_size_mul_add_or_raise(
55 sizeof(struct rb_callinfo_kwarg
),
62 const struct rb_callinfo_kwarg
*kwarg
;
69 #define USE_EMBED_CI 1
73 #define CI_EMBED_TAG_bits 1
74 #define CI_EMBED_ARGC_bits 15
75 #define CI_EMBED_FLAG_bits 16
76 #define CI_EMBED_ID_bits 32
77 #elif SIZEOF_VALUE == 4
78 #define CI_EMBED_TAG_bits 1
79 #define CI_EMBED_ARGC_bits 3
80 #define CI_EMBED_FLAG_bits 13
81 #define CI_EMBED_ID_bits 15
84 #if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
88 #define CI_EMBED_FLAG 0x01
89 #define CI_EMBED_ARGC_SHFT (CI_EMBED_TAG_bits)
90 #define CI_EMBED_ARGC_MASK ((((VALUE)1)<<CI_EMBED_ARGC_bits) - 1)
91 #define CI_EMBED_FLAG_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits)
92 #define CI_EMBED_FLAG_MASK ((((VALUE)1)<<CI_EMBED_FLAG_bits) - 1)
93 #define CI_EMBED_ID_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits)
94 #define CI_EMBED_ID_MASK ((((VALUE)1)<<CI_EMBED_ID_bits) - 1)
97 vm_ci_packed_p(const struct rb_callinfo
*ci
)
100 if (LIKELY(((VALUE
)ci
) & 0x01)) {
104 VM_ASSERT(IMEMO_TYPE_P(ci
, imemo_callinfo
));
113 vm_ci_p(const struct rb_callinfo
*ci
)
115 if (vm_ci_packed_p(ci
) || IMEMO_TYPE_P(ci
, imemo_callinfo
)) {
124 vm_ci_mid(const struct rb_callinfo
*ci
)
126 if (vm_ci_packed_p(ci
)) {
127 return (((VALUE
)ci
) >> CI_EMBED_ID_SHFT
) & CI_EMBED_ID_MASK
;
134 static inline unsigned int
135 vm_ci_flag(const struct rb_callinfo
*ci
)
137 if (vm_ci_packed_p(ci
)) {
138 return (unsigned int)((((VALUE
)ci
) >> CI_EMBED_FLAG_SHFT
) & CI_EMBED_FLAG_MASK
);
141 return (unsigned int)ci
->flag
;
145 static inline unsigned int
146 vm_ci_argc(const struct rb_callinfo
*ci
)
148 if (vm_ci_packed_p(ci
)) {
149 return (unsigned int)((((VALUE
)ci
) >> CI_EMBED_ARGC_SHFT
) & CI_EMBED_ARGC_MASK
);
152 return (unsigned int)ci
->argc
;
156 static inline const struct rb_callinfo_kwarg
*
157 vm_ci_kwarg(const struct rb_callinfo
*ci
)
159 if (vm_ci_packed_p(ci
)) {
168 vm_ci_dump(const struct rb_callinfo
*ci
)
170 if (vm_ci_packed_p(ci
)) {
171 ruby_debug_printf("packed_ci ID:%s flag:%x argc:%u\n",
172 rb_id2name(vm_ci_mid(ci
)), vm_ci_flag(ci
), vm_ci_argc(ci
));
179 #define vm_ci_new(mid, flag, argc, kwarg) vm_ci_new_(mid, flag, argc, kwarg, __FILE__, __LINE__)
180 #define vm_ci_new_runtime(mid, flag, argc, kwarg) vm_ci_new_runtime_(mid, flag, argc, kwarg, __FILE__, __LINE__)
182 #/* This is passed to STATIC_ASSERT. Cannot be an inline function. */
183 #define VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg) \
184 (((mid ) & ~CI_EMBED_ID_MASK) ? false : \
185 ((flag) & ~CI_EMBED_FLAG_MASK) ? false : \
186 ((argc) & ~CI_EMBED_ARGC_MASK) ? false : \
187 (kwarg) ? false : true)
189 #define vm_ci_new_id(mid, flag, argc, must_zero) \
190 ((const struct rb_callinfo *) \
191 ((((VALUE)(mid )) << CI_EMBED_ID_SHFT) | \
192 (((VALUE)(flag)) << CI_EMBED_FLAG_SHFT) | \
193 (((VALUE)(argc)) << CI_EMBED_ARGC_SHFT) | \
196 static inline const struct rb_callinfo
*
197 vm_ci_new_(ID mid
, unsigned int flag
, unsigned int argc
, const struct rb_callinfo_kwarg
*kwarg
, const char *file
, int line
)
200 if (VM_CI_EMBEDDABLE_P(mid
, flag
, argc
, kwarg
)) {
201 RB_DEBUG_COUNTER_INC(ci_packed
);
202 return vm_ci_new_id(mid
, flag
, argc
, kwarg
);
206 const bool debug
= 0;
207 if (debug
) ruby_debug_printf("%s:%d ", file
, line
);
210 const struct rb_callinfo
*ci
= (const struct rb_callinfo
*)
211 rb_imemo_new(imemo_callinfo
,
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
);
231 static inline const struct rb_callinfo
*
232 vm_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
241 vm_ci_markable(const struct rb_callinfo
*ci
)
244 return false; /* or true? This is Qfalse... */
246 else if (vm_ci_packed_p(ci
)) {
250 VM_ASSERT(IMEMO_TYPE_P(ci
, imemo_callinfo
));
251 return ! FL_ANY_RAW((VALUE
)ci
, VM_CALLINFO_NOT_UNDER_GC
);
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, \
266 typedef VALUE (*vm_call_handler
)(
267 struct rb_execution_context_struct
*ec
,
268 struct rb_control_frame_struct
*cfp
,
269 struct rb_calling_info
*calling
);
273 struct rb_callcache
{
276 /* inline cache: key */
277 const VALUE klass
; // should not mark it because klass can not be free'd
278 // because of this marking. When klass is collected,
279 // cc will be cleared (cc->klass = 0) at vm_ccs_free().
281 /* inline cache: values */
282 const struct rb_callable_method_entry_struct
* const cme_
;
283 const vm_call_handler call_
;
286 const unsigned int attr_index
;
287 const enum method_missing_reason method_missing_reason
; /* used by method_missing */
292 #define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER0
293 #define VM_CALLCACHE_ON_STACK IMEMO_FL_USER1
295 static inline const struct rb_callcache
*
296 vm_cc_new(VALUE klass
,
297 const struct rb_callable_method_entry_struct
*cme
,
298 vm_call_handler call
)
300 const struct rb_callcache
*cc
= (const struct rb_callcache
*)rb_imemo_new(imemo_callcache
, (VALUE
)cme
, (VALUE
)call
, 0, klass
);
301 RB_DEBUG_COUNTER_INC(cc_new
);
305 #define VM_CC_ON_STACK(clazz, call, aux, cme) \
306 (struct rb_callcache) { \
308 (imemo_callcache << FL_USHIFT) | \
309 VM_CALLCACHE_UNMARKABLE | \
310 VM_CALLCACHE_ON_STACK, \
318 vm_cc_class_check(const struct rb_callcache
*cc
, VALUE klass
)
320 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
321 VM_ASSERT(cc
->klass
== 0 ||
322 RB_TYPE_P(cc
->klass
, T_CLASS
) || RB_TYPE_P(cc
->klass
, T_ICLASS
));
323 return cc
->klass
== klass
;
327 vm_cc_markable(const struct rb_callcache
*cc
)
329 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
330 return FL_TEST_RAW((VALUE
)cc
, VM_CALLCACHE_UNMARKABLE
) == 0;
333 static inline const struct rb_callable_method_entry_struct
*
334 vm_cc_cme(const struct rb_callcache
*cc
)
336 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
337 VM_ASSERT(cc
->call_
== NULL
|| // not initialized yet
338 !vm_cc_markable(cc
) ||
344 static inline vm_call_handler
345 vm_cc_call(const struct rb_callcache
*cc
)
347 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
348 VM_ASSERT(cc
->call_
!= NULL
);
352 static inline unsigned int
353 vm_cc_attr_index(const struct rb_callcache
*cc
)
355 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
356 return cc
->aux_
.attr_index
;
359 static inline unsigned int
360 vm_cc_cmethod_missing_reason(const struct rb_callcache
*cc
)
362 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
363 return cc
->aux_
.method_missing_reason
;
367 vm_cc_invalidated_p(const struct rb_callcache
*cc
)
369 if (cc
->klass
&& !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc
))) {
377 // For MJIT. cc_cme is supposed to have inlined `vm_cc_cme(cc)`.
379 vm_cc_valid_p(const struct rb_callcache
*cc
, const rb_callable_method_entry_t
*cc_cme
, VALUE klass
)
381 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
382 if (cc
->klass
== klass
&& !METHOD_ENTRY_INVALIDATED(cc_cme
)) {
390 extern const struct rb_callcache
*rb_vm_empty_cc(void);
391 extern const struct rb_callcache
*rb_vm_empty_cc_for_super(void);
392 #define vm_cc_empty() rb_vm_empty_cc()
394 /* callcache: mutate */
397 vm_cc_call_set(const struct rb_callcache
*cc
, vm_call_handler call
)
399 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
400 VM_ASSERT(cc
!= vm_cc_empty());
401 *(vm_call_handler
*)&cc
->call_
= call
;
405 vm_cc_attr_index_set(const struct rb_callcache
*cc
, int index
)
407 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
408 VM_ASSERT(cc
!= vm_cc_empty());
409 *(int *)&cc
->aux_
.attr_index
= index
;
413 vm_cc_method_missing_reason_set(const struct rb_callcache
*cc
, enum method_missing_reason reason
)
415 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
416 VM_ASSERT(cc
!= vm_cc_empty());
417 *(enum method_missing_reason
*)&cc
->aux_
.method_missing_reason
= reason
;
421 vm_cc_invalidate(const struct rb_callcache
*cc
)
423 VM_ASSERT(IMEMO_TYPE_P(cc
, imemo_callcache
));
424 VM_ASSERT(cc
!= vm_cc_empty());
425 VM_ASSERT(cc
->klass
!= 0); // should be enable
427 *(VALUE
*)&cc
->klass
= 0;
428 RB_DEBUG_COUNTER_INC(cc_ent_invalidate
);
433 struct rb_call_data
{
434 const struct rb_callinfo
*ci
;
435 const struct rb_callcache
*cc
;
438 struct rb_class_cc_entries
{
439 #if VM_CHECK_MODE > 0
444 const struct rb_callable_method_entry_struct
*cme
;
445 struct rb_class_cc_entries_entry
{
446 const struct rb_callinfo
*ci
;
447 const struct rb_callcache
*cc
;
451 #if VM_CHECK_MODE > 0
453 const rb_callable_method_entry_t
*rb_vm_lookup_overloaded_cme(const rb_callable_method_entry_t
*cme
);
454 void rb_vm_dump_overloaded_cme_table(void);
457 vm_ccs_p(const struct rb_class_cc_entries
*ccs
)
459 return ccs
->debug_sig
== ~(VALUE
)ccs
;
463 vm_cc_check_cme(const struct rb_callcache
*cc
, const rb_callable_method_entry_t
*cme
)
465 if (vm_cc_cme(cc
) == cme
||
466 (cme
->def
->iseq_overload
&& vm_cc_cme(cc
) == rb_vm_lookup_overloaded_cme(cme
))) {
473 fprintf(stderr
, "iseq_overload:%d\n", (int)cme
->def
->iseq_overload
);
476 rb_vm_lookup_overloaded_cme(cme
);
485 void rb_vm_ccs_free(struct rb_class_cc_entries
*ccs
);
487 #endif /* RUBY_VM_CALLINFO_H */