Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
vm_callinfo.h
Go to the documentation of this file.
1#ifndef RUBY_VM_CALLINFO_H /*-*-C-*-vi:se ft=c:*/
2#define RUBY_VM_CALLINFO_H
12#include "debug_counter.h"
13
15 VM_CALL_ARGS_SPLAT_bit, /* m(*args) */
17 VM_CALL_FCALL_bit, /* m(...) */
19 VM_CALL_ARGS_SIMPLE_bit, /* (ci->flag & (SPLAT|BLOCKARG)) && blockiseq == NULL && ci->kw_arg == NULL */
20 VM_CALL_BLOCKISEQ_bit, /* has blockiseq */
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) */
29};
30
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_BLOCKISEQ (0x01 << VM_CALL_BLOCKISEQ_bit)
37#define VM_CALL_KWARG (0x01 << VM_CALL_KWARG_bit)
38#define VM_CALL_KW_SPLAT (0x01 << VM_CALL_KW_SPLAT_bit)
39#define VM_CALL_TAILCALL (0x01 << VM_CALL_TAILCALL_bit)
40#define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit)
41#define VM_CALL_ZSUPER (0x01 << VM_CALL_ZSUPER_bit)
42#define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit)
43#define VM_CALL_KW_SPLAT_MUT (0x01 << VM_CALL_KW_SPLAT_MUT_bit)
44
48};
49
50static inline size_t
51rb_callinfo_kwarg_bytes(int keyword_len)
52{
54 keyword_len,
55 sizeof(VALUE),
56 sizeof(struct rb_callinfo_kwarg),
58}
59
60// imemo_callinfo
63 const struct rb_callinfo_kwarg *kwarg;
67};
68
69#ifndef USE_EMBED_CI
70#define USE_EMBED_CI 1
71#endif
72
73#if SIZEOF_VALUE == 8
74#define CI_EMBED_TAG_bits 1
75#define CI_EMBED_ARGC_bits 15
76#define CI_EMBED_FLAG_bits 16
77#define CI_EMBED_ID_bits 32
78#elif SIZEOF_VALUE == 4
79#define CI_EMBED_TAG_bits 1
80#define CI_EMBED_ARGC_bits 3
81#define CI_EMBED_FLAG_bits 13
82#define CI_EMBED_ID_bits 15
83#endif
84
85#if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
86#error
87#endif
88
89#define CI_EMBED_FLAG 0x01
90#define CI_EMBED_ARGC_SHFT (CI_EMBED_TAG_bits)
91#define CI_EMBED_ARGC_MASK ((((VALUE)1)<<CI_EMBED_ARGC_bits) - 1)
92#define CI_EMBED_FLAG_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits)
93#define CI_EMBED_FLAG_MASK ((((VALUE)1)<<CI_EMBED_FLAG_bits) - 1)
94#define CI_EMBED_ID_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits)
95#define CI_EMBED_ID_MASK ((((VALUE)1)<<CI_EMBED_ID_bits) - 1)
96
97static inline bool
98vm_ci_packed_p(const struct rb_callinfo *ci)
99{
100#if USE_EMBED_CI
101 if (LIKELY(((VALUE)ci) & 0x01)) {
102 return 1;
103 }
104 else {
106 return 0;
107 }
108#else
109 return 0;
110#endif
111}
112
113static inline bool
114vm_ci_p(const struct rb_callinfo *ci)
115{
116 if (vm_ci_packed_p(ci) || IMEMO_TYPE_P(ci, imemo_callinfo)) {
117 return 1;
118 }
119 else {
120 return 0;
121 }
122}
123
124static inline ID
125vm_ci_mid(const struct rb_callinfo *ci)
126{
127 if (vm_ci_packed_p(ci)) {
128 return (((VALUE)ci) >> CI_EMBED_ID_SHFT) & CI_EMBED_ID_MASK;
129 }
130 else {
131 return (ID)ci->mid;
132 }
133}
134
135static inline unsigned int
136vm_ci_flag(const struct rb_callinfo *ci)
137{
138 if (vm_ci_packed_p(ci)) {
139 return (unsigned int)((((VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
140 }
141 else {
142 return (unsigned int)ci->flag;
143 }
144}
145
146static inline unsigned int
147vm_ci_argc(const struct rb_callinfo *ci)
148{
149 if (vm_ci_packed_p(ci)) {
150 return (unsigned int)((((VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
151 }
152 else {
153 return (unsigned int)ci->argc;
154 }
155}
156
157static inline const struct rb_callinfo_kwarg *
158vm_ci_kwarg(const struct rb_callinfo *ci)
159{
160 if (vm_ci_packed_p(ci)) {
161 return NULL;
162 }
163 else {
164 return ci->kwarg;
165 }
166}
167
168static inline void
169vm_ci_dump(const struct rb_callinfo *ci)
170{
171 if (vm_ci_packed_p(ci)) {
172 fprintf(stderr, "packed_ci ID:%s flag:%x argc:%u\n",
173 rb_id2name(vm_ci_mid(ci)), vm_ci_flag(ci), vm_ci_argc(ci));
174 }
175 else {
176 rp(ci);
177 }
178}
179
180#define vm_ci_new(mid, flag, argc, kwarg) vm_ci_new_(mid, flag, argc, kwarg, __FILE__, __LINE__)
181#define vm_ci_new_runtime(mid, flag, argc, kwarg) vm_ci_new_runtime_(mid, flag, argc, kwarg, __FILE__, __LINE__)
182
183#/* This is passed to STATIC_ASSERT. Cannot be an inline function. */
184#define VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg) \
185 (((mid ) & ~CI_EMBED_ID_MASK) ? false : \
186 ((flag) & ~CI_EMBED_FLAG_MASK) ? false : \
187 ((argc) & ~CI_EMBED_ARGC_MASK) ? false : \
188 (kwarg) ? false : true)
189
190#define vm_ci_new_id(mid, flag, argc, must_zero) \
191 ((const struct rb_callinfo *) \
192 ((((VALUE)(mid )) << CI_EMBED_ID_SHFT) | \
193 (((VALUE)(flag)) << CI_EMBED_FLAG_SHFT) | \
194 (((VALUE)(argc)) << CI_EMBED_ARGC_SHFT) | \
195 RUBY_FIXNUM_FLAG))
196
197static inline const struct rb_callinfo *
198vm_ci_new_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
199{
200#if USE_EMBED_CI
202 RB_DEBUG_COUNTER_INC(ci_packed);
203 return vm_ci_new_id(mid, flag, argc, kwarg);
204 }
205#endif
206
207 const bool debug = 0;
208 if (debug) fprintf(stderr, "%s:%d ", file, line);
209
210 // TODO: dedup
211 const struct rb_callinfo *ci = (const struct rb_callinfo *)
213 (VALUE)mid,
214 (VALUE)flag,
215 (VALUE)argc,
216 (VALUE)kwarg);
217 if (debug) rp(ci);
218 if (kwarg) {
220 }
221 else {
222 RB_DEBUG_COUNTER_INC(ci_nokw);
223 }
224
225 VM_ASSERT(vm_ci_flag(ci) == flag);
226 VM_ASSERT(vm_ci_argc(ci) == argc);
227
228 return ci;
229}
230
231
232static inline const struct rb_callinfo *
233vm_ci_new_runtime_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
234{
235 RB_DEBUG_COUNTER_INC(ci_runtime);
236 return vm_ci_new_(mid, flag, argc, kwarg, file, line);
237}
238
239#define VM_CALLINFO_NOT_UNDER_GC IMEMO_FL_USER0
240
241static inline bool
242vm_ci_markable(const struct rb_callinfo *ci)
243{
244 if (! ci) {
245 return false; /* or true? This is Qfalse... */
246 }
247 else if (vm_ci_packed_p(ci)) {
248 return true;
249 }
250 else {
253 }
254}
255
256#define VM_CI_ON_STACK(mid_, flags_, argc_, kwarg_) \
257 (struct rb_callinfo) { \
258 .flags = T_IMEMO | \
259 (imemo_callinfo << FL_USHIFT) | \
260 VM_CALLINFO_NOT_UNDER_GC, \
261 .mid = mid_, \
262 .flag = flags_, \
263 .argc = argc_, \
264 .kwarg = kwarg_, \
265 }
266
269 struct rb_control_frame_struct *cfp,
270 struct rb_calling_info *calling);
271
272// imemo_callcache
273
276
277 /* inline cache: key */
278 const VALUE klass; // should not mark it because klass can not be free'd
279 // because of this marking. When klass is collected,
280 // cc will be cleared (cc->klass = 0) at vm_ccs_free().
281
282 /* inline cache: values */
285
286 union {
287 const unsigned int attr_index;
288 const enum method_missing_reason method_missing_reason; /* used by method_missing */
291};
292
293#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER0
294
295static inline const struct rb_callcache *
296vm_cc_new(VALUE klass,
297 const struct rb_callable_method_entry_struct *cme,
298 vm_call_handler call)
299{
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);
302 return cc;
303}
304
305#define VM_CC_ON_STACK(clazz, call, aux, cme) \
306 (struct rb_callcache) { \
307 .flags = T_IMEMO | \
308 (imemo_callcache << FL_USHIFT) | \
309 VM_CALLCACHE_UNMARKABLE, \
310 .klass = clazz, \
311 .cme_ = cme, \
312 .call_ = call, \
313 .aux_ = aux, \
314 }
315
316static inline bool
317vm_cc_class_check(const struct rb_callcache *cc, VALUE klass)
318{
320 VM_ASSERT(cc->klass == 0 ||
321 RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
322 return cc->klass == klass;
323}
324
325static inline const struct rb_callable_method_entry_struct *
326vm_cc_cme(const struct rb_callcache *cc)
327{
329 return cc->cme_;
330}
331
332static inline vm_call_handler
333vm_cc_call(const struct rb_callcache *cc)
334{
336 return cc->call_;
337}
338
339static inline unsigned int
340vm_cc_attr_index(const struct rb_callcache *cc)
341{
343 return cc->aux_.attr_index;
344}
345
346static inline unsigned int
347vm_cc_cmethod_missing_reason(const struct rb_callcache *cc)
348{
350 return cc->aux_.method_missing_reason;
351}
352
353static inline int
354vm_cc_markable(const struct rb_callcache *cc)
355{
357 return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_UNMARKABLE) == 0;
358}
359
360static inline bool
361vm_cc_invalidated_p(const struct rb_callcache *cc)
362{
363 if (cc->klass && METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
364 return false;
365 }
366 else {
367 return true;
368 }
369}
370
371// For MJIT. cc_cme is supposed to have inlined `vm_cc_cme(cc)`.
372static inline bool
373vm_cc_valid_p(const struct rb_callcache *cc, const rb_callable_method_entry_t *cc_cme, VALUE klass)
374{
376 if (cc->klass == klass && !METHOD_ENTRY_INVALIDATED(cc_cme)) {
377 return 1;
378 }
379 else {
380 return 0;
381 }
382}
383
384extern const struct rb_callcache *rb_vm_empty_cc(void);
385#define vm_cc_empty() rb_vm_empty_cc()
386
387/* callcache: mutate */
388
389static inline void
390vm_cc_call_set(const struct rb_callcache *cc, vm_call_handler call)
391{
393 VM_ASSERT(cc != vm_cc_empty());
394 *(vm_call_handler *)&cc->call_ = call;
395}
396
397static inline void
398vm_cc_attr_index_set(const struct rb_callcache *cc, int index)
399{
401 VM_ASSERT(cc != vm_cc_empty());
402 *(int *)&cc->aux_.attr_index = index;
403}
404
405static inline void
406vm_cc_method_missing_reason_set(const struct rb_callcache *cc, enum method_missing_reason reason)
407{
409 VM_ASSERT(cc != vm_cc_empty());
410 *(enum method_missing_reason *)&cc->aux_.method_missing_reason = reason;
411}
412
413static inline void
414vm_cc_invalidate(const struct rb_callcache *cc)
415{
417 VM_ASSERT(cc != vm_cc_empty());
418 VM_ASSERT(cc->klass != 0); // should be enable
419
420 *(VALUE *)&cc->klass = 0;
421 RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
422}
423
424/* calldata */
425
427 const struct rb_callinfo *ci;
428 const struct rb_callcache *cc;
429};
430
432#if VM_CHECK_MODE > 0
433 VALUE debug_sig;
434#endif
435 int capa;
436 int len;
439 const struct rb_callinfo *ci;
440 const struct rb_callcache *cc;
442};
443
444#if VM_CHECK_MODE > 0
445static inline bool
446vm_ccs_p(const struct rb_class_cc_entries *ccs)
447{
448 return ccs->debug_sig == ~(VALUE)ccs;
449}
450#endif
451
452// gc.c
453void rb_vm_ccs_free(struct rb_class_cc_entries *ccs);
454
455#endif /* RUBY_VM_CALLINFO_H */
#define RB_DEBUG_COUNTER_INC(type)
#define LIKELY(x)
Definition: ffi_common.h:125
size_t rb_size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
Definition: gc.c:215
VALUE rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0)
Definition: gc.c:2412
#define FL_TEST_RAW
Definition: fl_type.h:131
#define FL_ANY_RAW
Definition: fl_type.h:125
VALUE rb_eRuntimeError
Definition: error.c:1055
#define IMEMO_TYPE_P(v, t)
Definition: imemo.h:178
@ imemo_callinfo
Definition: imemo.h:46
@ imemo_callcache
Definition: imemo.h:47
const char * rb_id2name(ID)
Definition: symbol.c:944
method_missing_reason
Definition: vm.h:32
#define rp(obj)
Definition: internal.h:95
#define METHOD_ENTRY_INVALIDATED(me)
Definition: method.h:76
#define debug(lvl, x...)
Definition: ffi.c:52
#define NULL
Definition: regenc.h:69
int argc
Definition: ruby.c:240
Definition: gzappend.c:170
const struct rb_callcache * cc
Definition: vm_callinfo.h:428
const struct rb_callinfo * ci
Definition: vm_callinfo.h:427
Definition: method.h:62
const VALUE klass
Definition: vm_callinfo.h:278
const VALUE flags
Definition: vm_callinfo.h:275
const vm_call_handler call_
Definition: vm_callinfo.h:284
const struct rb_callable_method_entry_struct *const cme_
Definition: vm_callinfo.h:283
union rb_callcache::@184 aux_
enum method_missing_reason method_missing_reason
Definition: vm_callinfo.h:288
const unsigned int attr_index
Definition: vm_callinfo.h:287
VALUE argc
Definition: vm_callinfo.h:66
const struct rb_callinfo_kwarg * kwarg
Definition: vm_callinfo.h:63
VALUE flag
Definition: vm_callinfo.h:65
VALUE flags
Definition: vm_callinfo.h:62
Definition: vm_callinfo.h:438
const struct rb_callcache * cc
Definition: vm_callinfo.h:440
const struct rb_callinfo * ci
Definition: vm_callinfo.h:439
const struct rb_callable_method_entry_struct * cme
Definition: vm_callinfo.h:437
struct rb_class_cc_entries::rb_class_cc_entries_entry * entries
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_ICLASS
Definition: value_type.h:65
#define T_CLASS
Definition: value_type.h:57
#define CI_EMBED_ID_MASK
Definition: vm_callinfo.h:95
VALUE(* vm_call_handler)(struct rb_execution_context_struct *ec, struct rb_control_frame_struct *cfp, struct rb_calling_info *calling)
Definition: vm_callinfo.h:267
vm_call_flag_bits
Definition: vm_callinfo.h:14
@ VM_CALL_ARGS_SIMPLE_bit
Definition: vm_callinfo.h:19
@ VM_CALL_KW_SPLAT_bit
Definition: vm_callinfo.h:22
@ VM_CALL_FCALL_bit
Definition: vm_callinfo.h:17
@ VM_CALL_SUPER_bit
Definition: vm_callinfo.h:24
@ VM_CALL_KW_SPLAT_MUT_bit
Definition: vm_callinfo.h:27
@ VM_CALL_VCALL_bit
Definition: vm_callinfo.h:18
@ VM_CALL__END
Definition: vm_callinfo.h:28
@ VM_CALL_ZSUPER_bit
Definition: vm_callinfo.h:25
@ VM_CALL_BLOCKISEQ_bit
Definition: vm_callinfo.h:20
@ VM_CALL_OPT_SEND_bit
Definition: vm_callinfo.h:26
@ VM_CALL_ARGS_BLOCKARG_bit
Definition: vm_callinfo.h:16
@ VM_CALL_TAILCALL_bit
Definition: vm_callinfo.h:23
@ VM_CALL_ARGS_SPLAT_bit
Definition: vm_callinfo.h:15
@ VM_CALL_KWARG_bit
Definition: vm_callinfo.h:21
#define CI_EMBED_ARGC_MASK
Definition: vm_callinfo.h:91
#define VM_CALLCACHE_UNMARKABLE
Definition: vm_callinfo.h:293
#define CI_EMBED_ARGC_SHFT
Definition: vm_callinfo.h:90
#define vm_ci_new_id(mid, flag, argc, must_zero)
Definition: vm_callinfo.h:190
#define VM_CALLINFO_NOT_UNDER_GC
Definition: vm_callinfo.h:239
#define vm_cc_empty()
Definition: vm_callinfo.h:385
#define CI_EMBED_FLAG_SHFT
Definition: vm_callinfo.h:92
#define CI_EMBED_FLAG_MASK
Definition: vm_callinfo.h:93
#define CI_EMBED_ID_SHFT
Definition: vm_callinfo.h:94
void rb_vm_ccs_free(struct rb_class_cc_entries *ccs)
Definition: gc.c:2649
const struct rb_callcache * rb_vm_empty_cc(void)
Definition: vm.c:4100
#define VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg)
Definition: vm_callinfo.h:184
#define VM_ASSERT(expr)
Definition: vm_core.h:61