Ruby 4.1.0dev (2026-09-27 revision b58bea071d47d44220efd6e71a3d8584963640c3)
vm_insnhelper.c (b58bea071d47d44220efd6e71a3d8584963640c3)
1/**********************************************************************
2
3 vm_insnhelper.c - instruction helper functions. Included into vm.c.
4
5 $Author$
6
7 Copyright (C) 2007 Koichi Sasada
8
9**********************************************************************/
10
11#include "ruby/internal/config.h"
12
13#include <math.h>
14
15#ifdef HAVE_STDATOMIC_H
16 #include <stdatomic.h>
17#endif
18
19#include "constant.h"
20#include "debug_counter.h"
21#include "internal.h"
22#include "internal/class.h"
23#include "internal/compar.h"
24#include "internal/hash.h"
25#include "internal/numeric.h"
26#include "internal/proc.h"
27#include "internal/random.h"
28#include "internal/variable.h"
29#include "internal/set.h"
30#include "internal/set_table.h"
31#include "internal/struct.h"
32#include "ruby/thread.h"
33#include "variable.h"
34
35/* finish iseq array */
36#include "insns.inc"
37#include "insns_info.inc"
38
39extern rb_method_definition_t *rb_method_definition_create(rb_method_type_t type, ID mid);
40extern void rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
41extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
42extern VALUE rb_make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
43 int argc, const VALUE *argv, int priv);
44
45static const struct rb_callcache vm_empty_cc;
46static const struct rb_callcache vm_empty_cc_for_super;
47
48/* control stack frame */
49
50static rb_control_frame_t *vm_get_ruby_level_caller_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp);
51
53ruby_vm_special_exception_copy(VALUE exc)
54{
56 rb_obj_copy_ivar(e, exc);
57 return e;
58}
59
60NORETURN(static void ec_stack_overflow(rb_execution_context_t *ec, int));
61static void
62ec_stack_overflow(rb_execution_context_t *ec, int setup)
63{
64 VALUE mesg = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_sysstack];
65 ec->raised_flag = RAISED_STACKOVERFLOW;
66 if (setup) {
67 VALUE at = rb_ec_backtrace_object(ec);
68 mesg = ruby_vm_special_exception_copy(mesg);
69 rb_ivar_set(mesg, idBt, at);
70 rb_ivar_set(mesg, idBt_locations, at);
71 }
72 ec->errinfo = mesg;
73 EC_JUMP_TAG(ec, TAG_RAISE);
74}
75
76NORETURN(static void vm_stackoverflow(void));
77
78static void
79vm_stackoverflow(void)
80{
81 ec_stack_overflow(GET_EC(), TRUE);
82}
83
84void
85rb_ec_stack_overflow(rb_execution_context_t *ec, ruby_stack_overflow_critical_level crit)
86{
87 if (rb_during_gc()) {
88 rb_bug("system stack overflow during GC. Faulty native extension?");
89 }
90 if (crit >= rb_stack_overflow_fatal) {
91 ec->raised_flag = RAISED_STACKOVERFLOW;
92 ec->errinfo = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_stackfatal];
93 EC_JUMP_TAG(ec, TAG_RAISE);
94 }
95 ec_stack_overflow(ec, crit < rb_stack_overflow_signal);
96}
97
98static inline void stack_check(rb_execution_context_t *ec);
99
100#if VM_CHECK_MODE > 0
101static int
102callable_class_p(VALUE klass)
103{
104#if VM_CHECK_MODE >= 2
105 if (!klass) return FALSE;
106 switch (RB_BUILTIN_TYPE(klass)) {
107 default:
108 break;
109 case T_ICLASS:
110 if (!RB_TYPE_P(RCLASS_SUPER(klass), T_MODULE)) break;
111 case T_MODULE:
112 return TRUE;
113 }
114 while (klass) {
115 if (klass == rb_cBasicObject) {
116 return TRUE;
117 }
118 klass = RCLASS_SUPER(klass);
119 }
120 return FALSE;
121#else
122 return klass != 0;
123#endif
124}
125
126static int
127callable_method_entry_p(const rb_callable_method_entry_t *cme)
128{
129 if (cme == NULL) {
130 return TRUE;
131 }
132 else {
133 VM_ASSERT(IMEMO_TYPE_P((VALUE)cme, imemo_ment), "imemo_type:%s", rb_imemo_name(imemo_type((VALUE)cme)));
134
135 if (callable_class_p(cme->defined_class)) {
136 return TRUE;
137 }
138 else {
139 return FALSE;
140 }
141 }
142}
143
144static void
145vm_check_frame_detail(VALUE type, int req_block, int req_me, int req_cref, VALUE specval, VALUE cref_or_me, int is_cframe, const rb_iseq_t *iseq)
146{
147 unsigned int magic = (unsigned int)(type & VM_FRAME_MAGIC_MASK);
148 enum imemo_type cref_or_me_type = imemo_env; /* impossible value */
149
150 if (RB_TYPE_P(cref_or_me, T_IMEMO)) {
151 cref_or_me_type = imemo_type(cref_or_me);
152 }
153 if (type & VM_FRAME_FLAG_BMETHOD) {
154 req_me = TRUE;
155 }
156
157 if (req_block && (type & VM_ENV_FLAG_LOCAL) == 0) {
158 rb_bug("vm_push_frame: specval (%p) should be a block_ptr on %x frame", (void *)specval, magic);
159 }
160 if (!req_block && (type & VM_ENV_FLAG_LOCAL) != 0) {
161 rb_bug("vm_push_frame: specval (%p) should not be a block_ptr on %x frame", (void *)specval, magic);
162 }
163
164 if (req_me) {
165 if (cref_or_me_type != imemo_ment) {
166 rb_bug("vm_push_frame: (%s) should be method entry on %x frame", rb_obj_info(cref_or_me), magic);
167 }
168 }
169 else {
170 if (req_cref && cref_or_me_type != imemo_cref) {
171 rb_bug("vm_push_frame: (%s) should be CREF on %x frame", rb_obj_info(cref_or_me), magic);
172 }
173 else { /* cref or Qfalse */
174 if (cref_or_me != Qfalse && cref_or_me_type != imemo_cref) {
175 if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC || magic == VM_FRAME_MAGIC_DUMMY) && (cref_or_me_type == imemo_ment)) {
176 /* ignore */
177 }
178 else {
179 rb_bug("vm_push_frame: (%s) should be false or cref on %x frame", rb_obj_info(cref_or_me), magic);
180 }
181 }
182 }
183 }
184
185 if (cref_or_me_type == imemo_ment) {
186 const rb_callable_method_entry_t *me = (const rb_callable_method_entry_t *)cref_or_me;
187
188 if (!callable_method_entry_p(me)) {
189 rb_bug("vm_push_frame: ment (%s) should be callable on %x frame.", rb_obj_info(cref_or_me), magic);
190 }
191 }
192
193 if ((type & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
194 VM_ASSERT(iseq == NULL ||
195 RBASIC_CLASS((VALUE)iseq) == 0 || // dummy frame for loading
196 RUBY_VM_NORMAL_ISEQ_P(iseq) //argument error
197 );
198 }
199 else {
200 VM_ASSERT(is_cframe == !RUBY_VM_NORMAL_ISEQ_P(iseq));
201 }
202}
203
204static void
205vm_check_frame(VALUE type,
206 VALUE specval,
207 VALUE cref_or_me,
208 const rb_iseq_t *iseq)
209{
210 VALUE given_magic = type & VM_FRAME_MAGIC_MASK;
211 VM_ASSERT(FIXNUM_P(type));
212
213#define CHECK(magic, req_block, req_me, req_cref, is_cframe) \
214 case magic: \
215 vm_check_frame_detail(type, req_block, req_me, req_cref, \
216 specval, cref_or_me, is_cframe, iseq); \
217 break
218 switch (given_magic) {
219 /* BLK ME CREF CFRAME */
220 CHECK(VM_FRAME_MAGIC_METHOD, TRUE, TRUE, FALSE, FALSE);
221 CHECK(VM_FRAME_MAGIC_CLASS, TRUE, FALSE, TRUE, FALSE);
222 CHECK(VM_FRAME_MAGIC_TOP, TRUE, FALSE, TRUE, FALSE);
223 CHECK(VM_FRAME_MAGIC_CFUNC, TRUE, TRUE, FALSE, TRUE);
224 CHECK(VM_FRAME_MAGIC_BLOCK, FALSE, FALSE, FALSE, FALSE);
225 CHECK(VM_FRAME_MAGIC_IFUNC, FALSE, FALSE, FALSE, TRUE);
226 CHECK(VM_FRAME_MAGIC_EVAL, FALSE, FALSE, FALSE, FALSE);
227 CHECK(VM_FRAME_MAGIC_RESCUE, FALSE, FALSE, FALSE, FALSE);
228 CHECK(VM_FRAME_MAGIC_DUMMY, TRUE, FALSE, FALSE, FALSE);
229 default:
230 rb_bug("vm_push_frame: unknown type (%x)", (unsigned int)given_magic);
231 }
232#undef CHECK
233}
234
235static VALUE vm_stack_canary; /* Initialized later */
236static bool vm_stack_canary_was_born = false;
237
238// Return the index of the instruction right before the given PC.
239// This is needed because insn_entry advances PC before the insn body.
240static unsigned int
241previous_insn_index(const rb_iseq_t *iseq, const VALUE *pc)
242{
243 unsigned int pos = 0;
244 while (pos < ISEQ_BODY(iseq)->iseq_size) {
245 int opcode = rb_vm_insn_addr2opcode((void *)ISEQ_BODY(iseq)->iseq_encoded[pos]);
246 unsigned int next_pos = pos + insn_len(opcode);
247 if (ISEQ_BODY(iseq)->iseq_encoded + next_pos == pc) {
248 return pos;
249 }
250 pos = next_pos;
251 }
252 rb_bug("failed to find the previous insn");
253}
254
255void
256rb_vm_check_canary(const rb_execution_context_t *ec, VALUE *sp)
257{
258 const struct rb_control_frame_struct *reg_cfp = ec->cfp;
259 const struct rb_iseq_struct *iseq;
260
261 if (! LIKELY(vm_stack_canary_was_born)) {
262 return; /* :FIXME: isn't it rather fatal to enter this branch? */
263 }
264 else if ((VALUE *)reg_cfp == ec->vm_stack + ec->vm_stack_size) {
265 /* This is at the very beginning of a thread. cfp does not exist. */
266 return;
267 }
268 else if (! (iseq = GET_ISEQ())) {
269 return;
270 }
271 else if (LIKELY(sp[0] != vm_stack_canary)) {
272 return;
273 }
274 else {
275 /* we are going to call methods below; squash the canary to
276 * prevent infinite loop. */
277 sp[0] = Qundef;
278 }
279
280 const VALUE *orig = rb_iseq_original_iseq(iseq);
281 const VALUE iseqw = rb_iseqw_new(iseq);
282 const VALUE inspection = rb_inspect(iseqw);
283 const char *stri = rb_str_to_cstr(inspection);
284 const VALUE disasm = rb_iseq_disasm(iseq);
285 const char *strd = rb_str_to_cstr(disasm);
286 const ptrdiff_t pos = previous_insn_index(iseq, GET_PC());
287 const enum ruby_vminsn_type insn = (enum ruby_vminsn_type)orig[pos];
288 const char *name = insn_name(insn);
289
290 /* rb_bug() is not capable of outputting this large contents. It
291 is designed to run form a SIGSEGV handler, which tends to be
292 very restricted. */
293 ruby_debug_printf(
294 "We are killing the stack canary set by %s, "
295 "at %s@pc=%"PRIdPTR"\n"
296 "watch out the C stack trace.\n"
297 "%s",
298 name, stri, pos, strd);
299 rb_bug("see above.");
300}
301#define vm_check_canary(ec, sp) rb_vm_check_canary(ec, sp)
302
303#else
304#define vm_check_canary(ec, sp)
305#define vm_check_frame(a, b, c, d)
306#endif /* VM_CHECK_MODE > 0 */
307
308#if USE_DEBUG_COUNTER
309static void
310vm_push_frame_debug_counter_inc(
311 const struct rb_execution_context_struct *ec,
312 const struct rb_control_frame_struct *reg_cfp,
313 VALUE type)
314{
315 const struct rb_control_frame_struct *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(reg_cfp);
316
317 RB_DEBUG_COUNTER_INC(frame_push);
318
319 if (RUBY_VM_END_CONTROL_FRAME(ec) != prev_cfp) {
320 const bool curr = VM_FRAME_RUBYFRAME_P(reg_cfp);
321 const bool prev = VM_FRAME_RUBYFRAME_P(prev_cfp);
322 if (prev) {
323 if (curr) {
324 RB_DEBUG_COUNTER_INC(frame_R2R);
325 }
326 else {
327 RB_DEBUG_COUNTER_INC(frame_R2C);
328 }
329 }
330 else {
331 if (curr) {
332 RB_DEBUG_COUNTER_INC(frame_C2R);
333 }
334 else {
335 RB_DEBUG_COUNTER_INC(frame_C2C);
336 }
337 }
338 }
339
340 switch (type & VM_FRAME_MAGIC_MASK) {
341 case VM_FRAME_MAGIC_METHOD: RB_DEBUG_COUNTER_INC(frame_push_method); return;
342 case VM_FRAME_MAGIC_BLOCK: RB_DEBUG_COUNTER_INC(frame_push_block); return;
343 case VM_FRAME_MAGIC_CLASS: RB_DEBUG_COUNTER_INC(frame_push_class); return;
344 case VM_FRAME_MAGIC_TOP: RB_DEBUG_COUNTER_INC(frame_push_top); return;
345 case VM_FRAME_MAGIC_CFUNC: RB_DEBUG_COUNTER_INC(frame_push_cfunc); return;
346 case VM_FRAME_MAGIC_IFUNC: RB_DEBUG_COUNTER_INC(frame_push_ifunc); return;
347 case VM_FRAME_MAGIC_EVAL: RB_DEBUG_COUNTER_INC(frame_push_eval); return;
348 case VM_FRAME_MAGIC_RESCUE: RB_DEBUG_COUNTER_INC(frame_push_rescue); return;
349 case VM_FRAME_MAGIC_DUMMY: RB_DEBUG_COUNTER_INC(frame_push_dummy); return;
350 }
351
352 rb_bug("unreachable");
353}
354#else
355#define vm_push_frame_debug_counter_inc(ec, cfp, t) /* void */
356#endif
357
358// Return a poison value to be set above the stack top to verify leafness.
359VALUE
360rb_vm_stack_canary(void)
361{
362#if VM_CHECK_MODE > 0
363 return vm_stack_canary;
364#else
365 return 0;
366#endif
367}
368
369STATIC_ASSERT(VM_ENV_DATA_INDEX_ME_CREF, VM_ENV_DATA_INDEX_ME_CREF == -2);
370STATIC_ASSERT(VM_ENV_DATA_INDEX_SPECVAL, VM_ENV_DATA_INDEX_SPECVAL == -1);
371STATIC_ASSERT(VM_ENV_DATA_INDEX_FLAGS, VM_ENV_DATA_INDEX_FLAGS == -0);
372
373static void
374vm_push_frame(rb_execution_context_t *ec,
375 const rb_iseq_t *iseq,
376 VALUE type,
377 VALUE self,
378 VALUE specval,
379 VALUE cref_or_me,
380 const VALUE *pc,
381 VALUE *sp,
382 int local_size,
383 int stack_max)
384{
385 rb_control_frame_t *const cfp = RUBY_VM_NEXT_CONTROL_FRAME(ec->cfp);
386
387 vm_check_frame(type, specval, cref_or_me, iseq);
388 VM_ASSERT(local_size >= 0);
389
390 /* check stack overflow */
391 CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + stack_max);
392 vm_check_canary(ec, sp);
393
394 /* setup vm value stack */
395
396 /* initialize local variables */
397 for (int i=0; i < local_size; i++) {
398 *sp++ = Qnil;
399 }
400
401 /* setup ep with managing data */
402 *sp++ = cref_or_me; /* ep[-2] / Qnil or T_IMEMO(cref) or T_IMEMO(ment) */
403 *sp++ = specval /* ep[-1] / block handler or prev env ptr */;
404 *sp++ = type; /* ep[-0] / ENV_FLAGS */
405
406 /* setup new frame */
407 *cfp = (const struct rb_control_frame_struct) {
408 .pc = pc,
409 .sp = sp,
410 ._iseq = iseq,
411 .self = self,
412 .ep = sp - 1,
413 .block_code = NULL,
414#if VM_DEBUG_BP_CHECK
415 .bp_check = sp,
416#endif
417 .jit_return = NULL,
418 };
419
420 /* Ensure the initialization of `*cfp` above never gets reordered with the update of `ec->cfp` below.
421 This is a no-op in all cases we've looked at (https://godbolt.org/z/3oxd1446K), but should guarantee it for all
422 future/untested compilers/platforms. */
423
424 #if defined HAVE_DECL_ATOMIC_SIGNAL_FENCE && HAVE_DECL_ATOMIC_SIGNAL_FENCE
425 atomic_signal_fence(memory_order_seq_cst);
426 #endif
427
428 ec->cfp = cfp;
429
430 if (VMDEBUG == 2) {
431 SDR();
432 }
433 vm_push_frame_debug_counter_inc(ec, cfp, type);
434}
435
436void
437rb_vm_pop_frame_no_int(rb_execution_context_t *ec)
438{
439 rb_control_frame_t *cfp = ec->cfp;
440
441 if (VMDEBUG == 2) SDR();
442
443 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
444}
445
446/* return TRUE if the frame is finished */
447static inline int
448vm_pop_frame(rb_execution_context_t *ec, rb_control_frame_t *cfp, const VALUE *ep)
449{
450 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
451
452 if (VMDEBUG == 2) SDR();
453
454 RUBY_VM_CHECK_INTS(ec);
455 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
456
457 return flags & VM_FRAME_FLAG_FINISH;
458}
459
460void
461rb_vm_pop_frame(rb_execution_context_t *ec)
462{
463 vm_pop_frame(ec, ec->cfp, ec->cfp->ep);
464}
465
466// it pushes pseudo-frame with fname filename.
467VALUE
468rb_vm_push_frame_fname(rb_execution_context_t *ec, VALUE fname)
469{
470 rb_iseq_t *rb_iseq_alloc_with_dummy_path(VALUE fname);
471 rb_iseq_t *dmy_iseq = rb_iseq_alloc_with_dummy_path(fname);
472
473 vm_push_frame(ec,
474 dmy_iseq, //const rb_iseq_t *iseq,
475 VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH, // VALUE type,
476 ec->cfp->self, // VALUE self,
477 VM_BLOCK_HANDLER_NONE, // VALUE specval,
478 Qfalse, // VALUE cref_or_me,
479 NULL, // const VALUE *pc,
480 ec->cfp->sp, // VALUE *sp,
481 0, // int local_size,
482 0); // int stack_max
483
484 return (VALUE)dmy_iseq;
485}
486
487/* method dispatch */
488static inline VALUE
489rb_arity_error_new(int argc, int min, int max)
490{
491 VALUE err_mess = rb_sprintf("wrong number of arguments (given %d, expected %d", argc, min);
492 if (min == max) {
493 /* max is not needed */
494 }
495 else if (max == UNLIMITED_ARGUMENTS) {
496 rb_str_cat_cstr(err_mess, "+");
497 }
498 else {
499 rb_str_catf(err_mess, "..%d", max);
500 }
501 rb_str_cat_cstr(err_mess, ")");
502 return rb_exc_new3(rb_eArgError, err_mess);
503}
504
505void
506rb_error_arity(int argc, int min, int max)
507{
508 rb_exc_raise(rb_arity_error_new(argc, min, max));
509}
510
511/* lvar */
512
513NOINLINE(static void vm_env_write_slowpath(const VALUE *ep, int index, VALUE v));
514
515static void
516vm_env_write_slowpath(const VALUE *ep, int index, VALUE v)
517{
518 const VALUE envval = VM_ENV_ENVVAL(ep);
519
520 if (RB_FL_TEST_RAW(envval, RUBY_FL_SHAREABLE)) {
521 /* Writing to a SHAREABLE env (an isolated proc) can create a shareable ->
522 * unshareable edge; only a full barrier sets the shref bit keeping v alive
523 * through its owner's local GC. WB_REQUIRED stays: later writes need it too. */
524 if (!SPECIAL_CONST_P(v)) {
525 rb_gc_writebarrier(envval, v);
526 }
527 VM_FORCE_WRITE(&ep[index], v);
528 }
529 else {
530 /* remember env value forcely */
531 rb_gc_writebarrier_remember(envval);
532 VM_FORCE_WRITE(&ep[index], v);
533 VM_ENV_FLAGS_UNSET(ep, VM_ENV_FLAG_WB_REQUIRED);
534 }
535 RB_DEBUG_COUNTER_INC(lvar_set_slowpath);
536}
537
538// YJIT assumes this function never runs GC
539static inline void
540vm_env_write(const VALUE *ep, int index, VALUE v)
541{
542 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
543 if (LIKELY((flags & VM_ENV_FLAG_WB_REQUIRED) == 0)) {
544 VM_STACK_ENV_WRITE(ep, index, v);
545 }
546 else {
547 vm_env_write_slowpath(ep, index, v);
548 }
549}
550
551void
552rb_vm_env_write(const VALUE *ep, int index, VALUE v)
553{
554 vm_env_write(ep, index, v);
555}
556
557VALUE
558rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler)
559{
560 if (block_handler == VM_BLOCK_HANDLER_NONE) {
561 return Qnil;
562 }
563 else {
564 switch (vm_block_handler_type(block_handler)) {
565 case block_handler_type_iseq:
566 case block_handler_type_ifunc:
567 return rb_vm_make_proc(ec, VM_BH_TO_CAPT_BLOCK(block_handler), rb_cProc);
568 case block_handler_type_symbol:
569 return rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler));
570 case block_handler_type_proc:
571 return VM_BH_TO_PROC(block_handler);
572 default:
573 VM_UNREACHABLE(rb_vm_bh_to_procval);
574 }
575 }
576}
577
578/* svar */
579
580#if VM_CHECK_MODE > 0
581static int
582vm_svar_valid_p(VALUE svar)
583{
584 if (RB_TYPE_P((VALUE)svar, T_IMEMO)) {
585 switch (imemo_type(svar)) {
586 case imemo_svar:
587 case imemo_cref:
588 case imemo_ment:
589 return TRUE;
590 default:
591 break;
592 }
593 }
594 rb_bug("vm_svar_valid_p: unknown type: %s", rb_obj_info(svar));
595 return FALSE;
596}
597#endif
598
599/* Should this frame's special variables live in the env's svar slot? A SHAREABLE env
600 * (isolated proc) can run in several Ractors at once, making svar shared mutable state
601 * leaking $~/$_ across Ractors: keep them per-EC instead. */
602static inline bool
603lep_svar_in_env_p(const rb_execution_context_t *ec, const VALUE *lep)
604{
605 if (!lep) return false;
606 if (ec == NULL) return true;
607 if (ec->root_lep == lep) return false;
608 /* lep may be a stale on-stack ep of a frame whose env already escaped: lep[0]
609 * still holds the imemo_env, so flags is not a FIXNUM and VM_ENV_ESCAPED_P
610 * asserts. That is not a live shareable proc's env, so fall back to in-env. */
611 if (FIXNUM_P(lep[VM_ENV_DATA_INDEX_FLAGS]) &&
612 VM_ENV_ESCAPED_P(lep) &&
613 RB_FL_TEST_RAW(VM_ENV_ENVVAL(lep), RUBY_FL_SHAREABLE)) {
614 return false;
615 }
616 return true;
617}
618
619static inline struct vm_svar *
620lep_svar(const rb_execution_context_t *ec, const VALUE *lep)
621{
622 VALUE svar;
623
624 if (lep_svar_in_env_p(ec, lep)) {
625 svar = lep[VM_ENV_DATA_INDEX_ME_CREF];
626 }
627 else {
628 svar = ec->root_svar;
629 }
630
631 VM_ASSERT(svar == Qfalse || vm_svar_valid_p(svar));
632
633 return (struct vm_svar *)svar;
634}
635
636static inline void
637lep_svar_write(const rb_execution_context_t *ec, const VALUE *lep, const struct vm_svar *svar)
638{
639 VM_ASSERT(vm_svar_valid_p((VALUE)svar));
640
641 if (lep_svar_in_env_p(ec, lep)) {
642 vm_env_write(lep, VM_ENV_DATA_INDEX_ME_CREF, (VALUE)svar);
643 }
644 else {
645 RB_OBJ_WRITE(rb_ec_thread_ptr(ec)->self, &ec->root_svar, svar);
646 }
647}
648
649static VALUE
650lep_svar_get(const rb_execution_context_t *ec, const VALUE *lep, rb_num_t key)
651{
652 const struct vm_svar *svar = lep_svar(ec, lep);
653
654 if ((VALUE)svar == Qfalse || imemo_type((VALUE)svar) != imemo_svar) return Qnil;
655
656 switch (key) {
657 case VM_SVAR_LASTLINE:
658 return svar->lastline;
659 case VM_SVAR_BACKREF:
660 return svar->backref;
661 default: {
662 const VALUE ary = svar->others;
663
664 if (NIL_P(ary)) {
665 return Qnil;
666 }
667 else {
668 return rb_ary_entry(ary, key - VM_SVAR_EXTRA_START);
669 }
670 }
671 }
672}
673
674static struct vm_svar *
675svar_new(VALUE obj)
676{
677 struct vm_svar *svar = IMEMO_NEW(struct vm_svar, imemo_svar, obj);
678 *((VALUE *)&svar->lastline) = Qnil;
679 *((VALUE *)&svar->backref) = Qnil;
680 *((VALUE *)&svar->others) = Qnil;
681
682 return svar;
683}
684
685static void
686lep_svar_set(const rb_execution_context_t *ec, const VALUE *lep, rb_num_t key, VALUE val)
687{
688 struct vm_svar *svar = lep_svar(ec, lep);
689
690 if ((VALUE)svar == Qfalse || imemo_type((VALUE)svar) != imemo_svar) {
691 lep_svar_write(ec, lep, svar = svar_new((VALUE)svar));
692 }
693
694 switch (key) {
695 case VM_SVAR_LASTLINE:
696 RB_OBJ_WRITE(svar, &svar->lastline, val);
697 return;
698 case VM_SVAR_BACKREF:
699 RB_OBJ_WRITE(svar, &svar->backref, val);
700 return;
701 default: {
702 VALUE ary = svar->others;
703
704 if (NIL_P(ary)) {
705 RB_OBJ_WRITE(svar, &svar->others, ary = rb_ary_new());
706 }
707 rb_ary_store(ary, key - VM_SVAR_EXTRA_START, val);
708 }
709 }
710}
711
712static inline VALUE
713vm_getspecial(const rb_execution_context_t *ec, const VALUE *lep, rb_num_t key, rb_num_t type)
714{
715 VALUE val;
716
717 if (type == 0) {
718 val = lep_svar_get(ec, lep, key);
719 }
720 else {
721 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
722
723 if (type & 0x01) {
724 switch (type >> 1) {
725 case '&':
726 val = rb_reg_last_match(backref);
727 break;
728 case '`':
729 val = rb_reg_match_pre(backref);
730 break;
731 case '\'':
732 val = rb_reg_match_post(backref);
733 break;
734 case '+':
735 val = rb_reg_match_last(backref);
736 break;
737 default:
738 rb_bug("unexpected back-ref");
739 }
740 }
741 else {
742 val = rb_reg_nth_match((int)(type >> 1), backref);
743 }
744 }
745 return val;
746}
747
748static inline VALUE
749vm_backref_defined(const rb_execution_context_t *ec, const VALUE *lep, rb_num_t type)
750{
751 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
752 int nth = 0;
753
754 if (type & 0x01) {
755 switch (type >> 1) {
756 case '&':
757 case '`':
758 case '\'':
759 break;
760 case '+':
761 return rb_reg_last_defined(backref);
762 default:
763 rb_bug("unexpected back-ref");
764 }
765 }
766 else {
767 nth = (int)(type >> 1);
768 }
769 return rb_reg_nth_defined(nth, backref);
770}
771
772PUREFUNC(static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar));
774check_method_entry(VALUE obj, int can_be_svar)
775{
776 if (obj == Qfalse) return NULL;
777
778#if VM_CHECK_MODE > 0
779 if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
780#endif
781
782 switch (imemo_type(obj)) {
783 case imemo_ment:
784 return (rb_callable_method_entry_t *)obj;
785 case imemo_cref:
786 return NULL;
787 case imemo_svar:
788 if (can_be_svar) {
789 return check_method_entry(((struct vm_svar *)obj)->cref_or_me, FALSE);
790 }
791 default:
792#if VM_CHECK_MODE > 0
793 rb_bug("check_method_entry: svar should not be there:");
794#endif
795 return NULL;
796 }
797}
798
800env_method_entry_unchecked(VALUE obj, int can_be_svar)
801{
802 if (obj == Qfalse) return NULL;
803
804 switch (imemo_type(obj)) {
805 case imemo_ment:
806 return (rb_callable_method_entry_t *)obj;
807 case imemo_cref:
808 return NULL;
809 case imemo_svar:
810 if (can_be_svar) {
811 return env_method_entry_unchecked(((struct vm_svar *)obj)->cref_or_me, FALSE);
812 }
813 default:
814 return NULL;
815 }
816}
817
819rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
820{
821 const VALUE *ep = cfp->ep;
823
824 while (!VM_ENV_LOCAL_P(ep)) {
825 if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
826 ep = VM_ENV_PREV_EP(ep);
827 }
828
829 return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
830}
831
833rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp)
834{
835 const VALUE *ep = cfp->ep;
837
838 while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) {
839 if ((me = env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
840 ep = VM_ENV_PREV_EP_UNCHECKED(ep);
841 }
842
843 return env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
844}
845
846static const rb_iseq_t *
847method_entry_iseqptr(const rb_callable_method_entry_t *me)
848{
849 switch (me->def->type) {
850 case VM_METHOD_TYPE_ISEQ:
851 return me->def->body.iseq.iseqptr;
852 default:
853 return NULL;
854 }
855}
856
857static rb_cref_t *
858method_entry_cref(const rb_callable_method_entry_t *me)
859{
860 switch (me->def->type) {
861 case VM_METHOD_TYPE_ISEQ:
862 return me->def->body.iseq.cref;
863 default:
864 return NULL;
865 }
866}
867
868#if VM_CHECK_MODE == 0
869PUREFUNC(static rb_cref_t *check_cref(VALUE, int));
870#endif
871static rb_cref_t *
872check_cref(VALUE obj, int can_be_svar)
873{
874 if (obj == Qfalse) return NULL;
875
876#if VM_CHECK_MODE > 0
877 if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_cref: unknown type: %s", rb_obj_info(obj));
878#endif
879
880 switch (imemo_type(obj)) {
881 case imemo_ment:
882 return method_entry_cref((rb_callable_method_entry_t *)obj);
883 case imemo_cref:
884 return (rb_cref_t *)obj;
885 case imemo_svar:
886 if (can_be_svar) {
887 return check_cref(((struct vm_svar *)obj)->cref_or_me, FALSE);
888 }
889 default:
890#if VM_CHECK_MODE > 0
891 rb_bug("check_method_entry: svar should not be there:");
892#endif
893 return NULL;
894 }
895}
896
897static inline rb_cref_t *
898vm_env_cref(const VALUE *ep)
899{
900 rb_cref_t *cref;
901
902 while (!VM_ENV_LOCAL_P(ep)) {
903 if ((cref = check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return cref;
904 ep = VM_ENV_PREV_EP(ep);
905 }
906
907 return check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
908}
909
910static int
911is_cref(const VALUE v, int can_be_svar)
912{
913 if (RB_TYPE_P(v, T_IMEMO)) {
914 switch (imemo_type(v)) {
915 case imemo_cref:
916 return TRUE;
917 case imemo_svar:
918 if (can_be_svar) return is_cref(((struct vm_svar *)v)->cref_or_me, FALSE);
919 default:
920 break;
921 }
922 }
923 return FALSE;
924}
925
926static int
927vm_env_cref_by_cref(const VALUE *ep)
928{
929 while (!VM_ENV_LOCAL_P(ep)) {
930 if (is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) return TRUE;
931 ep = VM_ENV_PREV_EP(ep);
932 }
933 return is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
934}
935
936static rb_cref_t *
937cref_replace_with_duplicated_cref_each_frame(const VALUE *vptr, int can_be_svar, VALUE parent)
938{
939 const VALUE v = *vptr;
940 rb_cref_t *cref, *new_cref;
941
942 if (RB_TYPE_P(v, T_IMEMO)) {
943 switch (imemo_type(v)) {
944 case imemo_cref:
945 cref = (rb_cref_t *)v;
946 new_cref = rb_vm_cref_dup(cref);
947 if (parent) {
948 RB_OBJ_WRITE(parent, vptr, new_cref);
949 }
950 else {
951 VM_FORCE_WRITE(vptr, (VALUE)new_cref);
952 }
953 return (rb_cref_t *)new_cref;
954 case imemo_svar:
955 if (can_be_svar) {
956 return cref_replace_with_duplicated_cref_each_frame(&((struct vm_svar *)v)->cref_or_me, FALSE, v);
957 }
958 /* fall through */
959 case imemo_ment:
960 rb_bug("cref_replace_with_duplicated_cref_each_frame: unreachable");
961 default:
962 break;
963 }
964 }
965 return NULL;
966}
967
968static rb_cref_t *
969vm_cref_replace_with_duplicated_cref(const VALUE *ep)
970{
971 if (vm_env_cref_by_cref(ep)) {
972 rb_cref_t *cref;
973 VALUE envval;
974
975 while (!VM_ENV_LOCAL_P(ep)) {
976 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) : Qfalse;
977 if ((cref = cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE, envval)) != NULL) {
978 return cref;
979 }
980 ep = VM_ENV_PREV_EP(ep);
981 }
982 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) : Qfalse;
983 return cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE, envval);
984 }
985 else {
986 rb_bug("vm_cref_dup: unreachable");
987 }
988}
989
990static rb_cref_t *
991vm_get_cref(const VALUE *ep)
992{
993 rb_cref_t *cref = vm_env_cref(ep);
994
995 if (cref != NULL) {
996 return cref;
997 }
998 else {
999 rb_bug("vm_get_cref: unreachable");
1000 }
1001}
1002
1003rb_cref_t *
1004rb_vm_get_cref(const VALUE *ep)
1005{
1006 return vm_get_cref(ep);
1007}
1008
1009static rb_cref_t *
1010vm_ec_cref(const rb_execution_context_t *ec)
1011{
1012 const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
1013
1014 if (cfp == NULL) {
1015 return NULL;
1016 }
1017 return vm_get_cref(cfp->ep);
1018}
1019
1020static const rb_cref_t *
1021vm_get_const_key_cref(const VALUE *ep)
1022{
1023 const rb_cref_t *cref = vm_get_cref(ep);
1024 const rb_cref_t *key_cref = cref;
1025
1026 while (cref) {
1027 if (CREF_DYNAMIC(cref)) {
1028 return key_cref;
1029 }
1030 cref = CREF_NEXT(cref);
1031 }
1032
1033 /* no dynamic singleton class or cloned class found */
1034 return NULL;
1035}
1036
1037static rb_cref_t *
1038vm_cref_push(const rb_execution_context_t *ec, VALUE klass, const VALUE *ep, int pushed_by_eval, int singleton)
1039{
1040 rb_cref_t *prev_cref = NULL;
1041
1042 if (ep) {
1043 prev_cref = vm_env_cref(ep);
1044 }
1045 else {
1046 rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(ec, ec->cfp);
1047
1048 if (cfp) {
1049 prev_cref = vm_env_cref(cfp->ep);
1050 }
1051 }
1052
1053 return vm_cref_new(klass, METHOD_VISI_PUBLIC, FALSE, prev_cref, pushed_by_eval, singleton);
1054}
1055
1056static inline VALUE
1057vm_get_cbase(const VALUE *ep)
1058{
1059 const rb_cref_t *cref = vm_get_cref(ep);
1060
1061 return CREF_CLASS_FOR_DEFINITION(cref);
1062}
1063
1064static inline VALUE
1065vm_get_const_base(const VALUE *ep)
1066{
1067 const rb_cref_t *cref = vm_get_cref(ep);
1068
1069 while (cref) {
1070 if (!CREF_PUSHED_BY_EVAL(cref)) {
1071 return CREF_CLASS_FOR_DEFINITION(cref);
1072 }
1073 cref = CREF_NEXT(cref);
1074 }
1075
1076 return Qundef;
1077}
1078
1079static inline void
1080vm_check_if_namespace(VALUE klass)
1081{
1082 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE)) {
1083 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a class/module", klass);
1084 }
1085}
1086
1087static inline void
1088vm_ensure_not_refinement_module(VALUE self)
1089{
1090 if (RB_TYPE_P(self, T_MODULE) && FL_TEST(self, RMODULE_IS_REFINEMENT)) {
1091 rb_warn("not defined at the refinement, but at the outer class/module");
1092 }
1093}
1094
1095static inline VALUE
1096vm_get_iclass(const rb_control_frame_t *cfp, VALUE klass)
1097{
1098 return klass;
1099}
1100
1101static inline VALUE
1102vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, bool allow_nil, int is_defined)
1103{
1104 void rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id);
1105 VALUE val;
1106
1107 if (NIL_P(orig_klass) && allow_nil) {
1108 /* in current lexical scope */
1109 const rb_cref_t *root_cref = vm_get_cref(ec->cfp->ep);
1110 const rb_cref_t *cref;
1111 VALUE klass = Qnil;
1112
1113 while (root_cref && CREF_PUSHED_BY_EVAL(root_cref)) {
1114 root_cref = CREF_NEXT(root_cref);
1115 }
1116 cref = root_cref;
1117 while (cref && CREF_NEXT(cref)) {
1118 if (CREF_PUSHED_BY_EVAL(cref)) {
1119 klass = Qnil;
1120 }
1121 else {
1122 klass = CREF_CLASS(cref);
1123 }
1124 cref = CREF_NEXT(cref);
1125
1126 if (!NIL_P(klass)) {
1127 VALUE av, am = 0;
1128 rb_const_entry_t *ce;
1129 search_continue:
1130 if ((ce = rb_const_lookup(klass, id))) {
1131 rb_const_warn_if_deprecated(ce, klass, id);
1132 val = ce->value;
1133 if (UNDEF_P(val)) {
1134 if (am == klass) break;
1135 am = klass;
1136 if (is_defined) return 1;
1137 if (rb_autoloading_value(klass, id, &av, NULL)) return av;
1138 rb_autoload_load(klass, id);
1139 goto search_continue;
1140 }
1141 else {
1142 if (is_defined) {
1143 return 1;
1144 }
1145 else {
1146 if (UNLIKELY(!rb_class_owned_p(klass))) {
1147 if (!rb_ractor_shareable_p(val)) {
1148 rb_raise(rb_eRactorIsolationError,
1149 "can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" of a class/module created by another Ractor.", rb_class_path(klass), rb_id2str(id));
1150 }
1151 }
1152 return val;
1153 }
1154 }
1155 }
1156 }
1157 }
1158
1159 /* search self */
1160 if (root_cref && !NIL_P(CREF_CLASS(root_cref))) {
1161 klass = vm_get_iclass(ec->cfp, CREF_CLASS(root_cref));
1162 }
1163 else {
1164 klass = CLASS_OF(ec->cfp->self);
1165 }
1166
1167 if (is_defined) {
1168 return rb_const_defined(klass, id);
1169 }
1170 else {
1171 return rb_const_get(klass, id);
1172 }
1173 }
1174 else {
1175 vm_check_if_namespace(orig_klass);
1176 if (is_defined) {
1177 return rb_public_const_defined_from(orig_klass, id);
1178 }
1179 else {
1180 return rb_public_const_get_from(orig_klass, id);
1181 }
1182 }
1183}
1184
1185VALUE
1186rb_vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, VALUE allow_nil)
1187{
1188 return vm_get_ev_const(ec, orig_klass, id, allow_nil == Qtrue, 0);
1189}
1190
1191static inline VALUE
1192vm_get_ev_const_chain(rb_execution_context_t *ec, const ID *segments)
1193{
1194 VALUE val = Qnil;
1195 int idx = 0;
1196 int allow_nil = TRUE;
1197 if (segments[0] == idNULL) {
1198 val = rb_cObject;
1199 idx++;
1200 allow_nil = FALSE;
1201 }
1202 while (segments[idx]) {
1203 ID id = segments[idx++];
1204 val = vm_get_ev_const(ec, val, id, allow_nil, 0);
1205 allow_nil = FALSE;
1206 }
1207 return val;
1208}
1209
1210
1211static inline VALUE
1212vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_level_raise)
1213{
1214 VALUE klass;
1215
1216 if (!cref) {
1217 rb_bug("vm_get_cvar_base: no cref");
1218 }
1219
1220 while (CREF_NEXT(cref) &&
1221 (NIL_P(CREF_CLASS(cref)) || RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
1222 CREF_PUSHED_BY_EVAL(cref) || CREF_SINGLETON(cref))) {
1223 cref = CREF_NEXT(cref);
1224 }
1225 if (top_level_raise && !CREF_NEXT(cref)) {
1226 rb_raise(rb_eRuntimeError, "class variable access from toplevel");
1227 }
1228
1229 klass = vm_get_iclass(cfp, CREF_CLASS(cref));
1230
1231 if (NIL_P(klass)) {
1232 rb_raise(rb_eTypeError, "no class variables available");
1233 }
1234 return klass;
1235}
1236
1237#define ractor_incidental_shareable_p(cond, val) \
1238 (!(cond) || rb_ractor_shareable_p(val))
1239#define ractor_object_incidental_shareable_p(obj, val) \
1240 ractor_incidental_shareable_p(rb_ractor_shareable_p(obj), val)
1241
1242ALWAYS_INLINE(static VALUE vm_getivar(VALUE, ID, const rb_iseq_t *, IVC, const struct rb_callcache *, int, VALUE));
1243static inline VALUE
1244vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, VALUE default_value)
1245{
1246 VALUE fields_obj;
1247#if OPT_IC_FOR_IVAR
1248 if (SPECIAL_CONST_P(obj)) {
1249 return default_value;
1250 }
1251
1252 switch (BUILTIN_TYPE(obj)) {
1253 case T_OBJECT:
1254 fields_obj = ROBJECT_FIELDS_OBJ(obj);
1255 break;
1256 case T_CLASS:
1257 case T_MODULE:
1258 {
1259 if (UNLIKELY(!rb_class_owned_p(obj))) {
1260 // For two reasons we can only use the fast path on the Ractor
1261 // that owns the class.
1262 // First, only the owner Ractor is allowed to set ivars on classes
1263 // and modules. So we can skip locking.
1264 // Second, other ractors need to check the shareability of the
1265 // values returned from the class ivars.
1266
1267 if (default_value == Qundef) { // defined?
1268 return rb_ivar_defined(obj, id) ? Qtrue : Qundef;
1269 }
1270 else {
1271 goto general_path;
1272 }
1273 }
1274
1275 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1276 break;
1277 }
1278 default:
1279 fields_obj = rb_obj_fields(obj, id);
1280 }
1281
1282 if (!fields_obj) {
1283 return default_value;
1284 }
1285
1286 VALUE val = Qundef;
1287
1288 shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj);
1289 VALUE *ivar_list = rb_imemo_fields_ptr(fields_obj);
1290
1291 rb_getivar_cache cache = rb_getivar_cache_unpack(vm_cache_attr_index_atomic_read(is_attr, ic, cc));
1292
1293 if (LIKELY(cache.shape_offset == shape_id)) {
1294 if (cache.index == ATTR_INDEX_NOT_SET) {
1295 return default_value;
1296 }
1297
1298 val = ivar_list[cache.index];
1299#if USE_DEBUG_COUNTER
1300 RB_DEBUG_COUNTER_INC(ivar_get_ic_hit);
1301
1302 if (RB_TYPE_P(obj, T_OBJECT)) {
1303 RB_DEBUG_COUNTER_INC(ivar_get_obj_hit);
1304 }
1305#endif
1306 RUBY_ASSERT(!UNDEF_P(val));
1307 }
1308 else { // cache miss case
1309#if USE_DEBUG_COUNTER
1310 if (is_attr) {
1311 if (cache.shape_offset != INVALID_SHAPE_ID) {
1312 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set);
1313 }
1314 else {
1315 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_unset);
1316 }
1317 }
1318 else {
1319 if (cache.shape_offset != INVALID_SHAPE_ID) {
1320 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set);
1321 }
1322 else {
1323 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_unset);
1324 }
1325 }
1326 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1327
1328 if (RB_TYPE_P(obj, T_OBJECT)) {
1329 RB_DEBUG_COUNTER_INC(ivar_get_obj_miss);
1330 }
1331#endif
1332
1333 if (UNLIKELY(rb_shape_complex_p(shape_id))) {
1334 st_table *table = (st_table *)ivar_list;
1335
1336 RUBY_ASSERT(table);
1337 RUBY_ASSERT(table == rb_imemo_fields_complex_tbl(fields_obj));
1338
1339 if (!st_lookup(table, id, &val)) {
1340 val = default_value;
1341 }
1342 }
1343 else {
1344 shape_id_t previous_cached_offset = cache.shape_offset;
1345 if (rb_shape_get_iv_index_with_hint(shape_id, id, &cache.index, &cache.shape_offset)) {
1346 if (cache.shape_offset != previous_cached_offset) {
1347 RUBY_ASSERT(!rb_shape_complex_p(cache.shape_offset));
1348 RUBY_ASSERT(cache.shape_offset != INVALID_SHAPE_ID);
1349
1350 uint64_t packed_cache = rb_getivar_cache_pack(cache.shape_offset, cache.index);
1351 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1352 }
1353
1354 if (cache.index == ATTR_INDEX_NOT_SET) {
1355 val = default_value;
1356 }
1357 else {
1358 // We fetched the ivar list above
1359 val = ivar_list[cache.index];
1360 RUBY_ASSERT(!UNDEF_P(val));
1361 }
1362 }
1363 else {
1364 vm_cache_attr_index_set(is_attr, ic, cc, rb_getivar_cache_pack(shape_id, ATTR_INDEX_NOT_SET));
1365 val = default_value;
1366 }
1367 }
1368 }
1369
1370 if (!UNDEF_P(default_value)) {
1371 RUBY_ASSERT(!UNDEF_P(val));
1372 }
1373
1374 return val;
1375
1376general_path:
1377#endif /* OPT_IC_FOR_IVAR */
1378 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1379
1380 if (is_attr) {
1381 return rb_attr_get(obj, id);
1382 }
1383 else {
1384 return rb_ivar_get(obj, id);
1385 }
1386}
1387
1388ALWAYS_INLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr));
1389NOINLINE(static VALUE vm_setivar_slowpath_ivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic));
1390NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache *cc));
1391
1392static VALUE
1393vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)
1394{
1395#if OPT_IC_FOR_IVAR
1396 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
1397
1398 rb_check_ivar_modifiable(obj);
1399
1400 shape_id_t previous_shape_id = RBASIC_SHAPE_ID(obj);
1401 attr_index_t index = rb_ivar_set_index(obj, id, val);
1402 shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj);
1403
1404 if (!rb_shape_complex_p(next_shape_id)) {
1405 uint64_t packed_cache = rb_setivar_cache_pack(RSHAPE_OFFSET(previous_shape_id), RSHAPE_OFFSET(next_shape_id), index);
1406 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1407 }
1408
1409 RB_DEBUG_COUNTER_INC(ivar_set_obj_miss);
1410 return val;
1411#else
1412 return rb_ivar_set(obj, id, val);
1413#endif
1414}
1415
1416static VALUE
1417vm_setivar_slowpath_ivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic)
1418{
1419 return vm_setivar_slowpath(obj, id, val, iseq, ic, NULL, false);
1420}
1421
1422static VALUE
1423vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache *cc)
1424{
1425 return vm_setivar_slowpath(obj, id, val, NULL, NULL, cc, true);
1426}
1427
1428NOINLINE(static VALUE vm_setivar_class(VALUE obj, VALUE val, rb_setivar_cache cache));
1429static VALUE
1430vm_setivar_class(VALUE obj, VALUE val, rb_setivar_cache cache)
1431{
1432 if (UNLIKELY(!rb_class_owned_p(obj))) {
1433 return Qundef;
1434 }
1435
1436 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1437 if (UNLIKELY(!fields_obj)) {
1438 return Qundef;
1439 }
1440
1441 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
1442 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1443 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1444 return Qundef;
1445 }
1446
1447 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1448
1449 if (shape_id != dest_shape_id) {
1450 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1451 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1452 }
1453
1454 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1455
1456 return val;
1457}
1458
1459NOINLINE(static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, rb_setivar_cache cache));
1460static VALUE
1461vm_setivar_default(VALUE obj, ID id, VALUE val, rb_setivar_cache cache)
1462{
1463 VALUE fields_obj = rb_obj_fields(obj, id);
1464 if (UNLIKELY(!fields_obj)) {
1465 return Qundef;
1466 }
1467
1468 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1469 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1470 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1471 return Qundef;
1472 }
1473
1474 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1475
1476 if (shape_id != dest_shape_id) {
1477 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1478 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1479 }
1480
1481 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1482
1483 return val;
1484}
1485
1486static inline VALUE
1487vm_setivar(VALUE obj, VALUE val, rb_setivar_cache cache)
1488{
1489#if OPT_IC_FOR_IVAR
1490 switch (BUILTIN_TYPE(obj)) {
1491 case T_OBJECT:
1492 {
1493 VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj));
1494
1495 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1496 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, shape_id, cache);
1497 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1498 break;
1499 }
1500
1501 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
1502 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1503 if (shape_id != dest_shape_id) {
1504 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1505 if (fields_obj != obj) {
1506 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1507 }
1508 }
1509
1510 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1511 RB_DEBUG_COUNTER_INC(ivar_set_obj_hit);
1512 return val;
1513 }
1514 break;
1515 case T_CLASS:
1516 case T_MODULE:
1517 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject);
1518 default:
1519 break;
1520 }
1521
1522 return Qundef;
1523#endif /* OPT_IC_FOR_IVAR */
1524}
1525
1526static VALUE
1527update_classvariable_cache(const rb_iseq_t *iseq, VALUE klass, ID id, const rb_cref_t * cref, ICVARC ic)
1528{
1529 VALUE defined_class = 0;
1530 VALUE cvar_value = rb_cvar_find(klass, id, &defined_class);
1531
1532 if (RB_TYPE_P(defined_class, T_ICLASS)) {
1533 defined_class = RBASIC(defined_class)->klass;
1534 }
1535
1536 VALUE rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
1537 if (!rb_cvc_tbl) {
1538 rb_bug("the cvc table should be set");
1539 }
1540
1541 VALUE ent_data;
1542 if (!rb_marked_id_table_lookup(rb_cvc_tbl, id, &ent_data)) {
1543 rb_bug("should have cvar cache entry");
1544 }
1545
1546 struct rb_cvar_class_tbl_entry *ent = (void *)ent_data;
1547
1548 ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
1549 RB_OBJ_WRITE((VALUE)ent, &ent->cref, cref);
1550 RB_OBJ_WRITE(iseq, &ic->entry, ent);
1551
1552 RUBY_ASSERT(BUILTIN_TYPE((VALUE)cref) == T_IMEMO && IMEMO_TYPE_P(cref, imemo_cref));
1553
1554 return cvar_value;
1555}
1556
1557static inline VALUE
1558vm_getclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *reg_cfp, ID id, ICVARC ic)
1559{
1560 const rb_cref_t *cref;
1561 cref = vm_get_cref(GET_EP());
1562
1563 // The fast path skips rb_cvar_find's checks, so it is for class_value's owner:
1564 // the sole writer, and the only one allowed to see an unshareable value.
1565 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1566 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1567 RB_DEBUG_COUNTER_INC(cvar_read_inline_hit);
1568
1569 VALUE v = rb_ivar_lookup(ic->entry->class_value, id, Qundef);
1570 RUBY_ASSERT(!UNDEF_P(v));
1571
1572 return v;
1573 }
1574
1575 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1576
1577 return update_classvariable_cache(iseq, klass, id, cref, ic);
1578}
1579
1580VALUE
1581rb_vm_getclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, ICVARC ic)
1582{
1583 return vm_getclassvariable(iseq, cfp, id, ic);
1584}
1585
1586static inline void
1587vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *reg_cfp, ID id, VALUE val, ICVARC ic)
1588{
1589 const rb_cref_t *cref;
1590 cref = vm_get_cref(GET_EP());
1591
1592 // as on the read side: the fast path writes straight into class_value
1593 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1594 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1595 RB_DEBUG_COUNTER_INC(cvar_write_inline_hit);
1596
1597 rb_class_ivar_set(ic->entry->class_value, id, val);
1598 return;
1599 }
1600
1601 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1602
1603 rb_cvar_set(klass, id, val);
1604
1605 update_classvariable_cache(iseq, klass, id, cref, ic);
1606}
1607
1608void
1609rb_vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, VALUE val, ICVARC ic)
1610{
1611 vm_setclassvariable(iseq, cfp, id, val, ic);
1612}
1613
1614ALWAYS_INLINE(static VALUE vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic));
1615static inline VALUE
1616vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic)
1617{
1618 return vm_getivar(obj, id, iseq, ic, NULL, FALSE, Qnil);
1619}
1620
1621static inline void
1622vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic)
1623{
1624 if (RB_SPECIAL_CONST_P(obj)) {
1626 return;
1627 }
1628
1629 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_ic_atomic_cache_read(ic));
1630 if (UNLIKELY(UNDEF_P(vm_setivar(obj, val, cache)))) {
1631 switch (BUILTIN_TYPE(obj)) {
1632 case T_OBJECT:
1633 break;
1634 case T_CLASS:
1635 case T_MODULE:
1636 if (!UNDEF_P(vm_setivar_class(obj, val, cache))) {
1637 return;
1638 }
1639 break;
1640 default:
1641 if (!UNDEF_P(vm_setivar_default(obj, id, val, cache))) {
1642 return;
1643 }
1644 }
1645 vm_setivar_slowpath_ivar(obj, id, val, iseq, ic);
1646 }
1647}
1648
1649void
1650rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic)
1651{
1652 vm_setinstancevariable(iseq, obj, id, val, ic);
1653}
1654
1655VALUE
1656rb_vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic)
1657{
1658 return vm_getinstancevariable(iseq, obj, id, ic);
1659}
1660
1661static VALUE
1662vm_throw_continue(const rb_execution_context_t *ec, VALUE err)
1663{
1664 /* continue throw */
1665
1666 if (FIXNUM_P(err)) {
1667 ec->tag->state = RUBY_TAG_FATAL;
1668 }
1669 else if (SYMBOL_P(err)) {
1670 ec->tag->state = TAG_THROW;
1671 }
1672 else if (THROW_DATA_P(err)) {
1673 ec->tag->state = THROW_DATA_STATE((struct vm_throw_data *)err);
1674 }
1675 else {
1676 ec->tag->state = TAG_RAISE;
1677 }
1678 return err;
1679}
1680
1681static VALUE
1682vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_cfp, enum ruby_tag_type state,
1683 const int flag, const VALUE throwobj)
1684{
1685 const rb_control_frame_t *escape_cfp = NULL;
1686 const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(ec); /* end of control frame pointer */
1687
1688 if (flag != 0) {
1689 /* do nothing */
1690 }
1691 else if (state == TAG_BREAK) {
1692 int is_orphan = 1;
1693 const VALUE *ep = GET_EP();
1694 const rb_iseq_t *base_iseq = GET_ISEQ();
1695 escape_cfp = reg_cfp;
1696
1697 while (ISEQ_BODY(base_iseq)->type != ISEQ_TYPE_BLOCK) {
1698 if (ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_CLASS) {
1699 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1700 ep = escape_cfp->ep;
1701 base_iseq = CFP_ISEQ(escape_cfp);
1702 }
1703 else {
1704 ep = VM_ENV_PREV_EP(ep);
1705 base_iseq = ISEQ_BODY(base_iseq)->parent_iseq;
1706 escape_cfp = rb_vm_search_cf_from_ep(ec, escape_cfp, ep);
1707 VM_ASSERT(CFP_ISEQ(escape_cfp) == base_iseq);
1708 }
1709 }
1710
1711 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1712 /* lambda{... break ...} */
1713 is_orphan = 0;
1714 state = TAG_RETURN;
1715 }
1716 else {
1717 ep = VM_ENV_PREV_EP(ep);
1718
1719 while (escape_cfp < eocfp) {
1720 if (escape_cfp->ep == ep) {
1721 const rb_iseq_t *const iseq = CFP_ISEQ(escape_cfp);
1722 const VALUE epc = CFP_PC(escape_cfp) - ISEQ_BODY(iseq)->iseq_encoded;
1723 const struct iseq_catch_table *const ct = ISEQ_BODY(iseq)->catch_table;
1724 unsigned int i;
1725
1726 if (!ct) break;
1727 for (i=0; i < ct->size; i++) {
1728 const struct iseq_catch_table_entry *const entry =
1729 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1730
1731 if (entry->type == CATCH_TYPE_BREAK &&
1732 entry->iseq == base_iseq &&
1733 entry->start < epc && entry->end >= epc) {
1734 if (entry->cont == epc) { /* found! */
1735 is_orphan = 0;
1736 }
1737 break;
1738 }
1739 }
1740 break;
1741 }
1742
1743 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1744 }
1745 }
1746
1747 if (is_orphan) {
1748 rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
1749 }
1750 }
1751 else if (state == TAG_RETRY) {
1752 const VALUE *ep = VM_ENV_PREV_EP(GET_EP());
1753
1754 escape_cfp = rb_vm_search_cf_from_ep(ec, reg_cfp, ep);
1755 }
1756 else if (state == TAG_RETURN) {
1757 const VALUE *current_ep = GET_EP();
1758 const VALUE *target_ep = NULL, *target_lep, *ep = current_ep;
1759 int in_class_frame = 0;
1760 int toplevel = 1;
1761 escape_cfp = reg_cfp;
1762
1763 // find target_lep, target_ep
1764 while (!VM_ENV_LOCAL_P(ep)) {
1765 if (VM_ENV_FLAGS(ep, VM_FRAME_FLAG_LAMBDA) && target_ep == NULL) {
1766 target_ep = ep;
1767 }
1768 ep = VM_ENV_PREV_EP(ep);
1769 }
1770 target_lep = ep;
1771
1772 while (escape_cfp < eocfp) {
1773 const VALUE *lep = VM_CF_LEP(escape_cfp);
1774
1775 if (!target_lep) {
1776 target_lep = lep;
1777 }
1778
1779 if (lep == target_lep &&
1780 VM_FRAME_RUBYFRAME_P(escape_cfp) &&
1781 ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_CLASS) {
1782 in_class_frame = 1;
1783 target_lep = 0;
1784 }
1785
1786 if (lep == target_lep) {
1787 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1788 toplevel = 0;
1789 if (in_class_frame) {
1790 /* lambda {class A; ... return ...; end} */
1791 goto valid_return;
1792 }
1793 else {
1794 const VALUE *tep = current_ep;
1795
1796 while (target_lep != tep) {
1797 if (escape_cfp->ep == tep) {
1798 /* in lambda */
1799 if (tep == target_ep) {
1800 goto valid_return;
1801 }
1802 else {
1803 goto unexpected_return;
1804 }
1805 }
1806 tep = VM_ENV_PREV_EP(tep);
1807 }
1808 }
1809 }
1810 else if (VM_FRAME_RUBYFRAME_P(escape_cfp)) {
1811 switch (ISEQ_BODY(CFP_ISEQ(escape_cfp))->type) {
1812 case ISEQ_TYPE_TOP:
1813 case ISEQ_TYPE_MAIN:
1814 if (toplevel) {
1815 if (in_class_frame) goto unexpected_return;
1816 if (target_ep == NULL) {
1817 goto valid_return;
1818 }
1819 else {
1820 goto unexpected_return;
1821 }
1822 }
1823 break;
1824 case ISEQ_TYPE_EVAL: {
1825 const rb_iseq_t *is = CFP_ISEQ(escape_cfp);
1826 enum rb_iseq_type t = ISEQ_BODY(is)->type;
1827 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE || t == ISEQ_TYPE_EVAL) {
1828 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
1829 t = ISEQ_BODY(is)->type;
1830 }
1831 toplevel = t == ISEQ_TYPE_TOP || t == ISEQ_TYPE_MAIN;
1832 break;
1833 }
1834 case ISEQ_TYPE_CLASS:
1835 toplevel = 0;
1836 break;
1837 default:
1838 break;
1839 }
1840 }
1841 }
1842
1843 if (escape_cfp->ep == target_lep && ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_METHOD) {
1844 if (target_ep == NULL) {
1845 goto valid_return;
1846 }
1847 else {
1848 goto unexpected_return;
1849 }
1850 }
1851
1852 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1853 }
1854 unexpected_return:;
1855 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
1856
1857 valid_return:;
1858 /* do nothing */
1859 }
1860 else {
1861 rb_bug("isns(throw): unsupported throw type");
1862 }
1863
1864 ec->tag->state = state;
1865 return (VALUE)THROW_DATA_NEW(throwobj, escape_cfp, state);
1866}
1867
1868static VALUE
1869vm_throw(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
1870 rb_num_t throw_state, VALUE throwobj)
1871{
1872 const int state = (int)(throw_state & VM_THROW_STATE_MASK);
1873 const int flag = (int)(throw_state & VM_THROW_NO_ESCAPE_FLAG);
1874
1875 if (state != 0) {
1876 return vm_throw_start(ec, reg_cfp, state, flag, throwobj);
1877 }
1878 else {
1879 return vm_throw_continue(ec, throwobj);
1880 }
1881}
1882
1883// Fallback for YJIT. Prepare throw data and return it.
1884VALUE
1885rb_vm_throw(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj)
1886{
1887 return vm_throw(ec, reg_cfp, throw_state, throwobj);
1888}
1889
1890NORETURN(VALUE rb_zjit_throw(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj));
1891
1892// Fallback for ZJIT. Make a longjmp and unwind to the most recent vm_exec().
1893VALUE
1894rb_zjit_throw(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj)
1895{
1896 VALUE val = vm_throw(ec, reg_cfp, throw_state, throwobj);
1897
1898 // vm_throw() has set ec->tag->state. On the longjmp path, vm_exec() reads the throw data from
1899 // ec->errinfo instead of vm_exec_core()'s return value like THROW_EXCEPTION()'s path does, so
1900 // we need to put it there instead.
1901 enum ruby_tag_type state = ec->tag->state;
1902 ec->errinfo = val;
1903 EC_JUMP_TAG(ec, state);
1904
1906}
1907
1908static inline void
1909vm_expandarray(struct rb_control_frame_struct *cfp, VALUE ary, rb_num_t num, int flag)
1910{
1911 int is_splat = flag & 0x01;
1912 const VALUE *ptr;
1913 rb_num_t len;
1914 const VALUE obj = ary;
1915
1916 if (!RB_TYPE_P(ary, T_ARRAY) && NIL_P(ary = rb_check_array_type(ary))) {
1917 ary = obj;
1918 ptr = &ary;
1919 len = 1;
1920 }
1921 else {
1922 ptr = RARRAY_CONST_PTR(ary);
1923 len = (rb_num_t)RARRAY_LEN(ary);
1924 }
1925
1926 if (num + is_splat == 0) {
1927 /* no space left on stack */
1928 }
1929 else if (flag & 0x02) {
1930 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
1931 rb_num_t i = 0, j;
1932
1933 if (len < num) {
1934 for (i = 0; i < num - len; i++) {
1935 *cfp->sp++ = Qnil;
1936 }
1937 }
1938
1939 for (j = 0; i < num; i++, j++) {
1940 VALUE v = ptr[len - j - 1];
1941 *cfp->sp++ = v;
1942 }
1943
1944 if (is_splat) {
1945 *cfp->sp++ = rb_ary_new4(len - j, ptr);
1946 }
1947 }
1948 else {
1949 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
1950 if (is_splat) {
1951 if (num > len) {
1952 *cfp->sp++ = rb_ary_new();
1953 }
1954 else {
1955 *cfp->sp++ = rb_ary_new4(len - num, ptr + num);
1956 }
1957 }
1958
1959 if (num > len) {
1960 rb_num_t i = 0;
1961 for (; i < num - len; i++) {
1962 *cfp->sp++ = Qnil;
1963 }
1964
1965 for (rb_num_t j = 0; i < num; i++, j++) {
1966 *cfp->sp++ = ptr[len - j - 1];
1967 }
1968 }
1969 else {
1970 for (rb_num_t j = 0; j < num; j++) {
1971 *cfp->sp++ = ptr[num - j - 1];
1972 }
1973 }
1974 }
1975
1976 RB_GC_GUARD(ary);
1977}
1978
1979static VALUE vm_call_general(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling);
1980
1981static VALUE vm_mtbl_dump(VALUE klass, ID target_mid);
1982
1983static struct rb_class_cc_entries *
1984vm_ccs_create(VALUE klass, VALUE cc_tbl, ID mid, const rb_callable_method_entry_t *cme)
1985{
1986 int initial_capa = 2;
1987 struct rb_class_cc_entries *ccs = ruby_xmalloc(vm_ccs_alloc_size(initial_capa));
1988#if VM_CHECK_MODE > 0
1989 ccs->debug_sig = ~(VALUE)ccs;
1990#endif
1991 ccs->capa = initial_capa;
1992 ccs->len = 0;
1993 ccs->cme = cme;
1994 METHOD_ENTRY_CACHED_SET((rb_callable_method_entry_t *)cme);
1995
1996 rb_managed_id_table_insert(cc_tbl, mid, (VALUE)ccs);
1997 RB_OBJ_WRITTEN(cc_tbl, Qundef, cme);
1998 return ccs;
1999}
2000
2001static void
2002vm_ccs_push(VALUE cc_tbl, ID mid, struct rb_class_cc_entries *ccs, const struct rb_callinfo *ci, const struct rb_callcache *cc)
2003{
2004 if (! vm_cc_markable(cc)) {
2005 return;
2006 }
2007
2008 if (UNLIKELY(ccs->len == ccs->capa)) {
2009 RUBY_ASSERT(ccs->capa > 0);
2010 ccs->capa *= 2;
2011 ccs = ruby_xrealloc(ccs, vm_ccs_alloc_size(ccs->capa));
2012#if VM_CHECK_MODE > 0
2013 ccs->debug_sig = ~(VALUE)ccs;
2014#endif
2015 // GC?
2016 rb_managed_id_table_insert(cc_tbl, mid, (VALUE)ccs);
2017 }
2018 VM_ASSERT(ccs->len < ccs->capa);
2019
2020 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
2021 const int pos = ccs->len++;
2022 ccs->entries[pos].argc = vm_ci_argc(ci);
2023 ccs->entries[pos].flag = (unsigned short)vm_ci_flag(ci);
2024 ccs->entries[pos].kw_len = (unsigned short)(kwarg ? kwarg->keyword_len : 0);
2025 RB_OBJ_WRITE(cc_tbl, &ccs->entries[pos].cc, cc);
2026
2027 if (RB_DEBUG_COUNTER_SETMAX(ccs_maxlen, ccs->len)) {
2028 // for tuning
2029 // vm_mtbl_dump(klass, 0);
2030 }
2031}
2032
2033#if VM_CHECK_MODE > 0
2034void
2035rb_vm_ccs_dump(struct rb_class_cc_entries *ccs)
2036{
2037 ruby_debug_printf("ccs:%p (%d,%d)\n", (void *)ccs, ccs->len, ccs->capa);
2038 for (int i=0; i<ccs->len; i++) {
2039 ruby_debug_printf("CCS CI ID:flag:%x argc:%u kw_len:%u\n",
2040 ccs->entries[i].flag,
2041 ccs->entries[i].argc,
2042 ccs->entries[i].kw_len);
2043 rp(ccs->entries[i].cc);
2044 }
2045}
2046
2047static int
2048vm_ccs_verify(struct rb_class_cc_entries *ccs, ID mid, VALUE klass)
2049{
2050 VM_ASSERT(vm_ccs_p(ccs));
2051 VM_ASSERT(ccs->len <= ccs->capa);
2052
2053 for (int i=0; i<ccs->len; i++) {
2054 const struct rb_callcache *cc = ccs->entries[i].cc;
2055
2056 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2057 VM_ASSERT(vm_cc_class_check(cc, klass));
2058 VM_ASSERT(vm_cc_check_cme(cc, ccs->cme));
2059 VM_ASSERT(!vm_cc_super_p(cc));
2060 VM_ASSERT(!vm_cc_refinement_p(cc));
2061 }
2062 return TRUE;
2063}
2064#endif
2065
2066const rb_callable_method_entry_t *rb_check_overloaded_cme(const rb_callable_method_entry_t *cme, const struct rb_callinfo * const ci);
2067
2068static void
2069vm_evict_cc(VALUE klass, VALUE cc_tbl, ID mid)
2070{
2071 ASSERT_vm_locking();
2072
2073 if (rb_multi_ractor_p()) {
2074 if (RCLASS_WRITABLE_CC_TBL(klass) != cc_tbl) {
2075 // Another ractor updated the CC table while we were waiting on the VM lock.
2076 // We have to retry.
2077 return;
2078 }
2079
2080 VALUE ccs_obj = 0;
2081 rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj);
2082 struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_obj;
2083
2084 if (!ccs || !METHOD_ENTRY_INVALIDATED(ccs->cme)) {
2085 // Another ractor replaced that entry while we were waiting on the VM lock.
2086 return;
2087 }
2088
2089 VALUE new_table = rb_vm_cc_table_dup(cc_tbl);
2090 rb_vm_cc_table_delete(new_table, mid);
2091 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), new_table);
2092 }
2093 else {
2094 rb_vm_cc_table_delete(cc_tbl, mid);
2095 }
2096}
2097
2098static const struct rb_callcache *
2099vm_populate_cc(VALUE klass, const struct rb_callinfo * const ci, ID mid)
2100{
2101 ASSERT_vm_locking();
2102
2103 RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
2104
2105 const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
2106
2107 VM_ASSERT(cme == NULL || IMEMO_TYPE_P(cme, imemo_ment));
2108
2109 if (cme == NULL) {
2110 // undef or not found: can't cache the information
2111 VM_ASSERT(vm_cc_cme(&vm_empty_cc) == NULL);
2112 return &vm_empty_cc;
2113 }
2114
2115 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
2116 const VALUE original_cc_table = cc_tbl;
2117 if (!cc_tbl) {
2118 // Is this possible after rb_callable_method_entry ?
2119 cc_tbl = rb_vm_cc_table_create(1);
2120 }
2121 else if (rb_multi_ractor_p()) {
2122 cc_tbl = rb_vm_cc_table_dup(cc_tbl);
2123 }
2124
2125 VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
2126
2127 METHOD_ENTRY_CACHED_SET((struct rb_callable_method_entry_struct *)cme);
2128
2129 VM_ASSERT(cc_tbl);
2130
2131 struct rb_class_cc_entries *ccs = NULL;
2132 {
2133 VALUE ccs_obj;
2134 if (UNLIKELY(rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj))) {
2135 ccs = (struct rb_class_cc_entries *)ccs_obj;
2136 }
2137 else {
2138 // TODO: required?
2139 ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
2140 }
2141 }
2142
2143 cme = rb_check_overloaded_cme(cme, ci);
2144
2145 const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
2146 vm_ccs_push(cc_tbl, mid, ccs, ci, cc);
2147
2148 VM_ASSERT(vm_cc_cme(cc) != NULL);
2149 VM_ASSERT(cme->called_id == mid);
2150 VM_ASSERT(vm_cc_cme(cc)->called_id == mid);
2151
2152 if (original_cc_table != cc_tbl) {
2153 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), cc_tbl);
2154 }
2155
2156 return cc;
2157}
2158
2159static const struct rb_callcache *
2160vm_lookup_cc(const VALUE klass, const struct rb_callinfo * const ci, ID mid)
2161{
2162 VALUE cc_tbl;
2163 struct rb_class_cc_entries *ccs;
2164retry:
2165 cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
2166 ccs = NULL;
2167
2168 if (cc_tbl) {
2169 // CCS data is keyed on method id, so we don't need the method id
2170 // for doing comparisons in the `for` loop below.
2171
2172 VALUE ccs_obj;
2173 if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj)) {
2174 ccs = (struct rb_class_cc_entries *)ccs_obj;
2175 const int ccs_len = ccs->len;
2176
2177 if (UNLIKELY(METHOD_ENTRY_INVALIDATED(ccs->cme))) {
2178 RB_VM_LOCKING() {
2179 vm_evict_cc(klass, cc_tbl, mid);
2180 }
2181 goto retry;
2182 }
2183 else {
2184 VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
2185
2186 // We already know the method id is correct because we had
2187 // to look up the ccs_data by method id. We compare argc and
2188 // flag, plus the keyword argument count: two call sites with
2189 // the same argc and flag can still differ in how many of the
2190 // arguments are keywords (e.g. `m(a: 1, b: 2)` vs `m(1, b: 2)`),
2191 // which selects a different argument setup fastpath.
2192 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
2193 unsigned int argc = vm_ci_argc(ci);
2194 unsigned int flag = vm_ci_flag(ci);
2195 unsigned int kw_len = kwarg ? kwarg->keyword_len : 0;
2196
2197 for (int i=0; i<ccs_len; i++) {
2198 unsigned int ccs_ci_argc = ccs->entries[i].argc;
2199 unsigned int ccs_ci_flag = ccs->entries[i].flag;
2200 unsigned int ccs_ci_kw_len = ccs->entries[i].kw_len;
2201 const struct rb_callcache *ccs_cc = ccs->entries[i].cc;
2202
2203 VM_ASSERT(IMEMO_TYPE_P(ccs_cc, imemo_callcache));
2204
2205 if (ccs_ci_argc == argc && ccs_ci_flag == flag && ccs_ci_kw_len == kw_len) {
2206 RB_DEBUG_COUNTER_INC(cc_found_in_ccs);
2207
2208 VM_ASSERT(vm_cc_cme(ccs_cc)->called_id == mid);
2209 VM_ASSERT(ccs_cc->klass == klass);
2210 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(ccs_cc)));
2211
2212 return ccs_cc;
2213 }
2214 }
2215 }
2216 }
2217 }
2218
2219 RB_GC_GUARD(cc_tbl);
2220 return NULL;
2221}
2222
2223static const struct rb_callcache *
2224vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
2225{
2226 const ID mid = vm_ci_mid(ci);
2227
2228 const struct rb_callcache *cc = vm_lookup_cc(klass, ci, mid);
2229 if (cc) {
2230 return cc;
2231 }
2232
2233 RB_VM_LOCKING() {
2234 if (rb_multi_ractor_p()) {
2235 // The CC may have been populated by another ractor while we were waiting on the lock,
2236 // so we must lookup a second time.
2237 cc = vm_lookup_cc(klass, ci, mid);
2238 }
2239
2240 if (!cc) {
2241 cc = vm_populate_cc(klass, ci, mid);
2242 }
2243 }
2244
2245 return cc;
2246}
2247
2248const struct rb_callcache *
2249rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass)
2250{
2251 const struct rb_callcache *cc;
2252
2253 VM_ASSERT(!SPECIAL_CONST_P(klass));
2254
2255 if (RB_BUILTIN_TYPE(klass) == T_NONE) {
2256 // If we find a T_NONE here, it's most likely we called CLASS_OF(obj) on a
2257 // garbage collected object (the freelist is stored in the class pointer),
2258 // but it's possible that just the class was GC'd.
2259 // This message intentionally tries to imply the former, but make an
2260 // accurate statement for either case.
2261 rb_bug("attempted to search method '%s' on a garbage collected object",
2262 rb_id2name(vm_ci_mid(ci)));
2263 }
2264
2265 VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
2266
2267 cc = vm_search_cc(klass, ci);
2268
2269 VM_ASSERT(cc);
2270 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2271 VM_ASSERT(cc == vm_cc_empty() || cc->klass == klass);
2272 VM_ASSERT(cc == vm_cc_empty() || callable_method_entry_p(vm_cc_cme(cc)));
2273 VM_ASSERT(cc == vm_cc_empty() || !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)));
2274 VM_ASSERT(cc == vm_cc_empty() || vm_cc_cme(cc)->called_id == vm_ci_mid(ci));
2275
2276 return cc;
2277}
2278
2279#if VM_CHECK_MODE > 0
2280static bool
2281vm_cd_owned_by_iseq_p(const struct rb_call_data *cd, const rb_iseq_t *iseq)
2282{
2283 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
2284 return cd >= body->call_data && cd < body->call_data + body->ci_size;
2285}
2286#endif
2287
2288static const struct rb_callcache *
2289vm_search_method_slowpath0(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
2290{
2291#if USE_DEBUG_COUNTER
2292 const struct rb_callcache *old_cc = cd->cc;
2293 const rb_callable_method_entry_t *const old_cme = old_cc ? old_cc->cme_ : NULL;
2294#endif
2295
2296 const struct rb_callcache *cc = rb_vm_search_method_slowpath(cd->ci, klass);
2297 const rb_callable_method_entry_t *const new_cme = vm_cc_cme(cc);
2298
2299#if OPT_INLINE_METHOD_CACHE
2300 cd->cc = cc;
2301
2302 const struct rb_callcache *empty_cc = &vm_empty_cc;
2303 if (cd_owner && cc != empty_cc) {
2304 // invokesuper dispatches with a cd on the machine stack, which has no
2305 // owning iseq to remember and keeps its ci out of the GC.
2306 VM_ASSERT(!vm_ci_markable(cd->ci) ||
2307 vm_cd_owned_by_iseq_p(cd, (const rb_iseq_t *)cd_owner));
2308 RB_OBJ_WRITTEN(cd_owner, Qundef, cc);
2309 }
2310
2311#if USE_DEBUG_COUNTER
2312 if (!old_cc || old_cc == empty_cc) {
2313 // empty
2314 RB_DEBUG_COUNTER_INC(mc_inline_miss_empty);
2315 }
2316 else if (old_cc == cc) {
2317 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cc);
2318 }
2319 else if (old_cme == new_cme) {
2320 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cme);
2321 }
2322 else if (old_cme && new_cme && old_cme->def == new_cme->def) {
2323 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_def);
2324 }
2325 else {
2326 RB_DEBUG_COUNTER_INC(mc_inline_miss_diff);
2327 }
2328#endif
2329#endif // OPT_INLINE_METHOD_CACHE
2330
2331 if (new_cme) VM_ASSERT(new_cme->called_id == vm_ci_mid(cd->ci));
2332
2333 return cc;
2334}
2335
2336ALWAYS_INLINE(static bool vm_cc_hit_p(const struct rb_callcache *cc, const struct rb_call_data *cd, VALUE klass));
2337static bool
2338vm_cc_hit_p(const struct rb_callcache *cc, const struct rb_call_data *cd, VALUE klass)
2339{
2340 VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
2341
2342#if OPT_INLINE_METHOD_CACHE
2343 if (LIKELY(vm_cc_class_check(cc, klass))) {
2344 if (LIKELY(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)))) {
2345 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
2346 RB_DEBUG_COUNTER_INC(mc_inline_hit);
2347 VM_ASSERT(vm_cc_cme(cc) == NULL || // not found
2348 (vm_ci_flag(cd->ci) & VM_CALL_SUPER) || // search_super w/ define_method
2349 vm_cc_cme(cc)->called_id == vm_ci_mid(cd->ci)); // cme->called_id == ci->mid
2350
2351 return true;
2352 }
2353 RB_DEBUG_COUNTER_INC(mc_inline_miss_invalidated);
2354 }
2355 else {
2356 RB_DEBUG_COUNTER_INC(mc_inline_miss_klass);
2357 }
2358#endif
2359
2360 return false;
2361}
2362
2363ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass));
2364static const struct rb_callcache *
2365vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass)
2366{
2367 const struct rb_callcache *cc = cd->cc;
2368 if (vm_cc_hit_p(cc, cd, klass)) {
2369 return cc;
2370 }
2371
2372 return vm_search_method_slowpath0((VALUE)CFP_ISEQ(reg_cfp), cd, klass);
2373}
2374
2375static const struct rb_callable_method_entry_struct *
2376vm_search_method(struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE recv)
2377{
2378 VALUE klass = CLASS_OF(recv);
2379 VM_ASSERT(klass != Qfalse);
2380 VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
2381
2382 const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
2383 return vm_cc_cme(cc);
2384}
2385
2387rb_zjit_vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
2388{
2389 // Called from ZJIT with the compile-time iseq, which may differ from
2390 // the iseq on the current CFP.
2391 VALUE klass = CLASS_OF(recv);
2392 const struct rb_callcache *cc = cd->cc;
2393 if (!vm_cc_hit_p(cc, cd, klass)) {
2394 cc = vm_search_method_slowpath0(cd_owner, cd, klass);
2395 }
2396 return vm_cc_cme(cc);
2397}
2398
2399#if __has_attribute(transparent_union)
2400typedef union {
2401 VALUE (*anyargs)(ANYARGS);
2402 VALUE (*f00)(VALUE);
2403 VALUE (*f01)(VALUE, VALUE);
2404 VALUE (*f02)(VALUE, VALUE, VALUE);
2405 VALUE (*f03)(VALUE, VALUE, VALUE, VALUE);
2406 VALUE (*f04)(VALUE, VALUE, VALUE, VALUE, VALUE);
2407 VALUE (*f05)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
2408 VALUE (*f06)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
2409 VALUE (*f07)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
2418 VALUE (*fm1)(int, union { VALUE *x; const VALUE *y; } __attribute__((__transparent_union__)), VALUE);
2419} __attribute__((__transparent_union__)) cfunc_type;
2420# define make_cfunc_type(f) (cfunc_type){.anyargs = (VALUE (*)(ANYARGS))(f)}
2421#else
2422typedef VALUE (*cfunc_type)(ANYARGS);
2423# define make_cfunc_type(f) (cfunc_type)(f)
2424#endif
2425
2426static inline int
2427check_cfunc(const rb_callable_method_entry_t *me, cfunc_type func)
2428{
2429 if (! me) {
2430 return false;
2431 }
2432 else {
2433 VM_ASSERT(IMEMO_TYPE_P(me, imemo_ment));
2434 VM_ASSERT(callable_method_entry_p(me));
2435 VM_ASSERT(me->def);
2436 if (me->def->type != VM_METHOD_TYPE_CFUNC) {
2437 return false;
2438 }
2439 else {
2440#if __has_attribute(transparent_union)
2441 return me->def->body.cfunc.func == func.anyargs;
2442#else
2443 return me->def->body.cfunc.func == func;
2444#endif
2445 }
2446 }
2447}
2448
2449static inline int
2450check_method_basic_definition(const rb_callable_method_entry_t *me)
2451{
2452 return me && METHOD_ENTRY_BASIC(me);
2453}
2454
2455static inline int
2456vm_method_cfunc_is(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv, cfunc_type func)
2457{
2458 VM_ASSERT(reg_cfp != NULL);
2459 const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
2460 return check_cfunc(cme, func);
2461}
2462
2463bool
2464rb_zjit_cme_is_cfunc(const rb_callable_method_entry_t *me, const cfunc_type func)
2465{
2466 return check_cfunc(me, func);
2467}
2468
2469int
2470rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
2471{
2472 const struct rb_callable_method_entry_struct *cme = rb_zjit_vm_search_method((VALUE)iseq, cd, recv);
2473 return check_cfunc(cme, func);
2474}
2475
2476#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
2477#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))
2478
2479#define OP_UNREDEFINED_P(op, t) BASIC_OP_UNREDEFINED_P(BOP_##op, t##_REDEFINED_OP_FLAG)
2480#define EQ_UNREDEFINED_P(t) OP_UNREDEFINED_P(EQ, t)
2481
2482static inline bool
2483FIXNUM_2_P(VALUE a, VALUE b)
2484{
2485 /* FIXNUM_P(a) && FIXNUM_P(b)
2486 * == ((a & 1) && (b & 1))
2487 * == a & b & 1 */
2488 SIGNED_VALUE x = a;
2489 SIGNED_VALUE y = b;
2490 SIGNED_VALUE z = x & y & 1;
2491 return z == 1;
2492}
2493
2494static inline bool
2495FLONUM_2_P(VALUE a, VALUE b)
2496{
2497#if USE_FLONUM
2498 /* FLONUM_P(a) && FLONUM_P(b)
2499 * == ((a & 3) == 2) && ((b & 3) == 2)
2500 * == ! ((a ^ 2) | (b ^ 2) & 3)
2501 */
2502 SIGNED_VALUE x = a;
2503 SIGNED_VALUE y = b;
2504 SIGNED_VALUE z = ((x ^ 2) | (y ^ 2)) & 3;
2505 return !z;
2506#else
2507 return false;
2508#endif
2509}
2510
2511static VALUE
2512opt_equality_specialized(VALUE recv, VALUE obj)
2513{
2514 if (FIXNUM_2_P(recv, obj) && EQ_UNREDEFINED_P(INTEGER)) {
2515 goto compare_by_identity;
2516 }
2517 else if (FLONUM_2_P(recv, obj) && EQ_UNREDEFINED_P(FLOAT)) {
2518 goto compare_by_identity;
2519 }
2520 else if (STATIC_SYM_P(recv) && STATIC_SYM_P(obj) && EQ_UNREDEFINED_P(SYMBOL)) {
2521 goto compare_by_identity;
2522 }
2523 else if (SPECIAL_CONST_P(recv)) {
2524 //
2525 }
2526 else if (RBASIC_CLASS(recv) == rb_cFloat && RB_FLOAT_TYPE_P(obj) && EQ_UNREDEFINED_P(FLOAT)) {
2527 double a = RFLOAT_VALUE(recv);
2528 double b = RFLOAT_VALUE(obj);
2529
2530 return RBOOL(a == b);
2531 }
2532 else if (RBASIC_CLASS(recv) == rb_cString && EQ_UNREDEFINED_P(STRING)) {
2533 if (recv == obj) {
2534 return Qtrue;
2535 }
2536 else if (RB_TYPE_P(obj, T_STRING)) {
2537 return rb_str_eql_internal(obj, recv);
2538 }
2539 }
2540 return Qundef;
2541
2542 compare_by_identity:
2543 return RBOOL(recv == obj);
2544}
2545
2546static VALUE
2547opt_equality(struct rb_control_frame_struct *reg_cfp, VALUE recv, VALUE obj, CALL_DATA cd)
2548{
2549 VM_ASSERT(reg_cfp != NULL);
2550
2551 VALUE val = opt_equality_specialized(recv, obj);
2552 if (!UNDEF_P(val)) return val;
2553
2554 if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
2555 return Qundef;
2556 }
2557 else {
2558 return RBOOL(recv == obj);
2559 }
2560}
2561
2562static inline const struct rb_callcache *gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci); // vm_eval.c
2563NOINLINE(static VALUE opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid));
2564
2565static VALUE
2566opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid)
2567{
2568 const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, &VM_CI_ON_STACK(mid, 0, 1, NULL));
2569
2570 if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) {
2571 return RBOOL(recv == obj);
2572 }
2573 else {
2574 return Qundef;
2575 }
2576}
2577
2578static VALUE
2579opt_equality_by_mid(VALUE recv, VALUE obj, ID mid)
2580{
2581 VALUE val = opt_equality_specialized(recv, obj);
2582 if (!UNDEF_P(val)) {
2583 return val;
2584 }
2585 else {
2586 return opt_equality_by_mid_slowpath(recv, obj, mid);
2587 }
2588}
2589
2590VALUE
2591rb_equal_opt(VALUE obj1, VALUE obj2)
2592{
2593 return opt_equality_by_mid(obj1, obj2, idEq);
2594}
2595
2596VALUE
2597rb_eql_opt(VALUE obj1, VALUE obj2)
2598{
2599 return opt_equality_by_mid(obj1, obj2, idEqlP);
2600}
2601
2602extern VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *, int kw_splat);
2603extern VALUE rb_vm_call_with_refinements(rb_execution_context_t *, VALUE, ID, int, const VALUE *, int);
2604
2605static VALUE
2606check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_check_match_type type)
2607{
2608 switch (type) {
2609 case VM_CHECKMATCH_TYPE_WHEN:
2610 return pattern;
2611 case VM_CHECKMATCH_TYPE_RESCUE:
2612 if (!rb_obj_is_kind_of(pattern, rb_cModule)) {
2613 rb_raise(rb_eTypeError, "class or module required for rescue clause");
2614 }
2615 /* fall through */
2616 case VM_CHECKMATCH_TYPE_CASE: {
2617 return rb_vm_call_with_refinements(ec, pattern, idEqq, 1, &target, RB_NO_KEYWORDS);
2618 }
2619 default:
2620 rb_bug("check_match: unreachable");
2621 }
2622}
2623
2624
2625static inline VALUE
2626double_cmp_lt(double a, double b)
2627{
2628 return RBOOL(a < b);
2629}
2630
2631static inline VALUE
2632double_cmp_le(double a, double b)
2633{
2634 return RBOOL(a <= b);
2635}
2636
2637static inline VALUE
2638double_cmp_gt(double a, double b)
2639{
2640 return RBOOL(a > b);
2641}
2642
2643static inline VALUE
2644double_cmp_ge(double a, double b)
2645{
2646 return RBOOL(a >= b);
2647}
2648
2649// Copied by vm_dump.c
2650static inline VALUE *
2651vm_base_ptr(const rb_control_frame_t *cfp)
2652{
2653 const rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
2654
2655 if (CFP_ISEQ(cfp) && VM_FRAME_RUBYFRAME_P(cfp)) {
2656 VALUE *bp = prev_cfp->sp + ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size + VM_ENV_DATA_SIZE;
2657
2658 if (ISEQ_BODY(CFP_ISEQ(cfp))->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
2659 int lts = ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size;
2660 int params = ISEQ_BODY(CFP_ISEQ(cfp))->param.size;
2661
2662 CALL_INFO ci = (CALL_INFO)cfp->ep[-(VM_ENV_DATA_SIZE + (lts - params))]; // skip EP stuff, CI should be last local
2663 bp += vm_ci_argc(ci);
2664 }
2665
2666 if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
2667 /* adjust `self' */
2668 bp += 1;
2669 }
2670#if VM_DEBUG_BP_CHECK
2671 if (bp != cfp->bp_check) {
2672 ruby_debug_printf("bp_check: %ld, bp: %ld\n",
2673 (long)(cfp->bp_check - GET_EC()->vm_stack),
2674 (long)(bp - GET_EC()->vm_stack));
2675 rb_bug("vm_base_ptr: unreachable");
2676 }
2677#endif
2678 return bp;
2679 }
2680 else {
2681 return NULL;
2682 }
2683}
2684
2685VALUE *
2686rb_vm_base_ptr(const rb_control_frame_t *cfp)
2687{
2688 return vm_base_ptr(cfp);
2689}
2690
2691/* method call processes with call_info */
2692
2693#include "vm_args.c"
2694
2695static inline VALUE vm_call_iseq_setup_2(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, int opt_pc, int param_size, int local_size);
2696ALWAYS_INLINE(static VALUE vm_call_iseq_setup_normal(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, const rb_callable_method_entry_t *me, int opt_pc, int param_size, int local_size));
2697static inline VALUE vm_call_iseq_setup_tailcall(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, int opt_pc);
2698static VALUE vm_call_super_method(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling);
2699static VALUE vm_call_method_nome(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling);
2700static VALUE vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling);
2701static inline VALUE vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling);
2702
2703static vm_call_handler vm_call_iseq_setup_func(const struct rb_callinfo *ci, const int param_size, const int local_size);
2704
2705static VALUE
2706vm_call_iseq_setup_tailcall_0start(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
2707{
2708 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_tailcall_0start);
2709
2710 return vm_call_iseq_setup_tailcall(ec, cfp, calling, 0);
2711}
2712
2713static VALUE
2714vm_call_iseq_setup_normal_0start(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
2715{
2716 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_0start);
2717
2718 const struct rb_callcache *cc = calling->cc;
2719 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
2720 int param = ISEQ_BODY(iseq)->param.size;
2721 int local = ISEQ_BODY(iseq)->local_table_size;
2722 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
2723}
2724
2725bool
2726rb_simple_iseq_p(const rb_iseq_t *iseq)
2727{
2728 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2729 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2730 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2731 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2732 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2733 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2734 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2735 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2736 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2737}
2738
2739bool
2740rb_iseq_only_optparam_p(const rb_iseq_t *iseq)
2741{
2742 return ISEQ_BODY(iseq)->param.flags.has_opt == TRUE &&
2743 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2744 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2745 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2746 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2747 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2748 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2749 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2750 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2751}
2752
2753bool
2754rb_iseq_only_kwparam_p(const rb_iseq_t *iseq)
2755{
2756 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2757 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2758 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2759 ISEQ_BODY(iseq)->param.flags.has_kw == TRUE &&
2760 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2761 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2762 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2763 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2764}
2765
2766#define ALLOW_HEAP_ARGV (-2)
2767#define ALLOW_HEAP_ARGV_KEEP_KWSPLAT (-3)
2768
2769static inline bool
2770vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calling, VALUE ary, int max_args)
2771{
2772 vm_check_canary(GET_EC(), cfp->sp);
2773 bool ret = false;
2774
2775 if (!NIL_P(ary)) {
2776 const VALUE *ptr = RARRAY_CONST_PTR(ary);
2777 long len = RARRAY_LEN(ary);
2778 int argc = calling->argc;
2779
2780 if (UNLIKELY(max_args <= ALLOW_HEAP_ARGV && len + argc > VM_ARGC_STACK_MAX)) {
2781 /* Avoid SystemStackError when splatting large arrays by storing arguments in
2782 * a temporary array, instead of trying to keeping arguments on the VM stack.
2783 */
2784 VALUE *argv = cfp->sp - argc;
2785 VALUE argv_ary = rb_ary_hidden_new(len + argc + 1);
2786 rb_ary_cat(argv_ary, argv, argc);
2787 rb_ary_cat(argv_ary, ptr, len);
2788 cfp->sp -= argc - 1;
2789 cfp->sp[-1] = argv_ary;
2790 calling->argc = 1;
2791 calling->heap_argv = argv_ary;
2792 RB_GC_GUARD(ary);
2793 }
2794 else {
2795 long i;
2796
2797 if (max_args >= 0 && len + argc > max_args) {
2798 /* If only a given max_args is allowed, copy up to max args.
2799 * Used by vm_callee_setup_block_arg for non-lambda blocks,
2800 * where additional arguments are ignored.
2801 *
2802 * Also, copy up to one more argument than the maximum,
2803 * in case it is an empty keyword hash that will be removed.
2804 */
2805 calling->argc += len - (max_args - argc + 1);
2806 len = max_args - argc + 1;
2807 ret = true;
2808 }
2809 else {
2810 /* Unset heap_argv if set originally. Can happen when
2811 * forwarding modified arguments, where heap_argv was used
2812 * originally, but heap_argv not supported by the forwarded
2813 * method in all cases.
2814 */
2815 calling->heap_argv = 0;
2816 }
2817 CHECK_VM_STACK_OVERFLOW(cfp, len);
2818
2819 for (i = 0; i < len; i++) {
2820 *cfp->sp++ = ptr[i];
2821 }
2822 calling->argc += i;
2823 }
2824 }
2825
2826 return ret;
2827}
2828
2829static inline void
2830vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_callinfo *ci)
2831{
2832 const VALUE *const passed_keywords = vm_ci_kwarg(ci)->keywords;
2833 const int kw_len = vm_ci_kwarg(ci)->keyword_len;
2834 const VALUE h = rb_hash_new_capa(kw_len);
2835 VALUE *sp = cfp->sp;
2836 int i;
2837
2838 for (i=0; i<kw_len; i++) {
2839 rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
2840 }
2841 (sp-kw_len)[0] = h;
2842
2843 cfp->sp -= kw_len - 1;
2844 calling->argc -= kw_len - 1;
2845 calling->kw_splat = 1;
2846}
2847
2848static inline VALUE
2849vm_caller_setup_keyword_hash(const struct rb_callinfo *ci, VALUE keyword_hash)
2850{
2851 if (UNLIKELY(!RB_TYPE_P(keyword_hash, T_HASH))) {
2852 if (keyword_hash != Qnil) {
2853 /* Convert a non-hash keyword splat to a new hash */
2854 keyword_hash = rb_hash_dup(rb_to_hash_type(keyword_hash));
2855 }
2856 }
2857 else if (!IS_ARGS_KW_SPLAT_MUT(ci) && !RHASH_EMPTY_P(keyword_hash)) {
2858 /* Convert a hash keyword splat to a new hash unless
2859 * a mutable keyword splat was passed.
2860 * Skip allocating new hash for empty keyword splat, as empty
2861 * keyword splat will be ignored by both callers.
2862 */
2863 keyword_hash = rb_hash_dup(keyword_hash);
2864 }
2865 return keyword_hash;
2866}
2867
2868static inline void
2869CALLER_SETUP_ARG(struct rb_control_frame_struct *restrict cfp,
2870 struct rb_calling_info *restrict calling,
2871 const struct rb_callinfo *restrict ci, int max_args)
2872{
2873 if (UNLIKELY(IS_ARGS_SPLAT(ci))) {
2874 if (IS_ARGS_KW_SPLAT(ci)) {
2875 // f(*a, **kw)
2876 VM_ASSERT(calling->kw_splat == 1);
2877
2878 cfp->sp -= 2;
2879 calling->argc -= 2;
2880 VALUE ary = cfp->sp[0];
2881 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[1]);
2882
2883 // splat a
2884 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args)) return;
2885
2886 // put kw
2887 if (kwh != Qnil && !RHASH_EMPTY_P(kwh)) {
2888 if (UNLIKELY(calling->heap_argv)) {
2889 rb_ary_push(calling->heap_argv, kwh);
2890 ((struct RHash *)kwh)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
2891 if (max_args != ALLOW_HEAP_ARGV_KEEP_KWSPLAT) {
2892 calling->kw_splat = 0;
2893 }
2894 }
2895 else {
2896 cfp->sp[0] = kwh;
2897 cfp->sp++;
2898 calling->argc++;
2899
2900 VM_ASSERT(calling->kw_splat == 1);
2901 }
2902 }
2903 else {
2904 calling->kw_splat = 0;
2905 }
2906 }
2907 else {
2908 // f(*a)
2909 VM_ASSERT(calling->kw_splat == 0);
2910
2911 cfp->sp -= 1;
2912 calling->argc -= 1;
2913 VALUE ary = cfp->sp[0];
2914
2915 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args)) {
2916 goto check_keyword;
2917 }
2918
2919 // check the last argument
2920 VALUE last_hash, argv_ary;
2921 if (UNLIKELY(argv_ary = calling->heap_argv)) {
2922 if (!IS_ARGS_KEYWORD(ci) &&
2923 RARRAY_LEN(argv_ary) > 0 &&
2924 RB_TYPE_P((last_hash = rb_ary_last(0, NULL, argv_ary)), T_HASH) &&
2925 (((struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2926
2927 rb_ary_pop(argv_ary);
2928 if (!RHASH_EMPTY_P(last_hash)) {
2929 rb_ary_push(argv_ary, rb_hash_dup(last_hash));
2930 calling->kw_splat = 1;
2931 }
2932 }
2933 }
2934 else {
2935check_keyword:
2936 if (!IS_ARGS_KEYWORD(ci) &&
2937 calling->argc > 0 &&
2938 RB_TYPE_P((last_hash = cfp->sp[-1]), T_HASH) &&
2939 (((struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2940
2941 if (RHASH_EMPTY_P(last_hash)) {
2942 calling->argc--;
2943 cfp->sp -= 1;
2944 }
2945 else {
2946 cfp->sp[-1] = rb_hash_dup(last_hash);
2947 calling->kw_splat = 1;
2948 }
2949 }
2950 }
2951 }
2952 }
2953 else if (UNLIKELY(IS_ARGS_KW_SPLAT(ci))) {
2954 // f(**kw)
2955 VM_ASSERT(calling->kw_splat == 1);
2956 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[-1]);
2957
2958 if (kwh == Qnil || RHASH_EMPTY_P(kwh)) {
2959 cfp->sp--;
2960 calling->argc--;
2961 calling->kw_splat = 0;
2962 }
2963 else {
2964 cfp->sp[-1] = kwh;
2965 }
2966 }
2967 else if (UNLIKELY(IS_ARGS_KEYWORD(ci))) {
2968 // f(k1:1, k2:2)
2969 VM_ASSERT(calling->kw_splat == 0);
2970
2971 /* This converts VM_CALL_KWARG style to VM_CALL_KW_SPLAT style
2972 * by creating a keyword hash.
2973 * So, vm_ci_flag(ci) & VM_CALL_KWARG is now inconsistent.
2974 */
2975 vm_caller_setup_arg_kw(cfp, calling, ci);
2976 }
2977}
2978
2979#define USE_OPT_HIST 0
2980
2981#if USE_OPT_HIST
2982#define OPT_HIST_MAX 64
2983static int opt_hist[OPT_HIST_MAX+1];
2984
2985__attribute__((destructor))
2986static void
2987opt_hist_show_results_at_exit(void)
2988{
2989 for (int i=0; i<OPT_HIST_MAX; i++) {
2990 ruby_debug_printf("opt_hist\t%d\t%d\n", i, opt_hist[i]);
2991 }
2992}
2993#endif
2994
2995static VALUE
2996vm_call_iseq_setup_normal_opt_start(rb_execution_context_t *ec, rb_control_frame_t *cfp,
2997 struct rb_calling_info *calling)
2998{
2999 const struct rb_callcache *cc = calling->cc;
3000 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3001 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3002 const int opt = calling->argc - lead_num;
3003 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3004 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3005 const int param = ISEQ_BODY(iseq)->param.size;
3006 const int local = ISEQ_BODY(iseq)->local_table_size;
3007 const int delta = opt_num - opt;
3008
3009 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3010
3011#if USE_OPT_HIST
3012 if (opt_pc < OPT_HIST_MAX) {
3013 opt_hist[opt]++;
3014 }
3015 else {
3016 opt_hist[OPT_HIST_MAX]++;
3017 }
3018#endif
3019
3020 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param - delta, local);
3021}
3022
3023static VALUE
3024vm_call_iseq_setup_tailcall_opt_start(rb_execution_context_t *ec, rb_control_frame_t *cfp,
3025 struct rb_calling_info *calling)
3026{
3027 const struct rb_callcache *cc = calling->cc;
3028 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3029 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3030 const int opt = calling->argc - lead_num;
3031 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3032
3033 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3034
3035#if USE_OPT_HIST
3036 if (opt_pc < OPT_HIST_MAX) {
3037 opt_hist[opt]++;
3038 }
3039 else {
3040 opt_hist[OPT_HIST_MAX]++;
3041 }
3042#endif
3043
3044 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3045}
3046
3047static void
3048args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
3049 VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
3050 VALUE *const locals);
3051
3052static VALUE
3053vm_call_iseq_forwardable(rb_execution_context_t *ec, rb_control_frame_t *cfp,
3054 struct rb_calling_info *calling)
3055{
3056 const struct rb_callcache *cc = calling->cc;
3057 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3058 int param_size = ISEQ_BODY(iseq)->param.size;
3059 int local_size = ISEQ_BODY(iseq)->local_table_size;
3060
3061 // Setting up local size and param size
3062 VM_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3063
3064 local_size = local_size + vm_ci_argc(calling->cd->ci);
3065 param_size = param_size + vm_ci_argc(calling->cd->ci);
3066
3067 cfp->sp[0] = (VALUE)calling->cd->ci;
3068
3069 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param_size, local_size);
3070}
3071
3072static VALUE
3073vm_call_iseq_setup_kwparm_kwarg(rb_execution_context_t *ec, rb_control_frame_t *cfp,
3074 struct rb_calling_info *calling)
3075{
3076 const struct rb_callinfo *ci = calling->cd->ci;
3077 const struct rb_callcache *cc = calling->cc;
3078
3079 VM_ASSERT(vm_ci_flag(ci) & VM_CALL_KWARG);
3080 RB_DEBUG_COUNTER_INC(ccf_iseq_kw1);
3081
3082 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3083 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3084 const struct rb_callinfo_kwarg *kw_arg = vm_ci_kwarg(ci);
3085 const int ci_kw_len = kw_arg->keyword_len;
3086 const VALUE * const ci_keywords = kw_arg->keywords;
3087 VALUE *argv = cfp->sp - calling->argc;
3088 VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
3089 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3090 VALUE * const ci_kws = ALLOCA_N(VALUE, ci_kw_len);
3091 MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
3092 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3093
3094 int param = ISEQ_BODY(iseq)->param.size;
3095 int local = ISEQ_BODY(iseq)->local_table_size;
3096 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3097}
3098
3099static VALUE
3100vm_call_iseq_setup_kwparm_nokwarg(rb_execution_context_t *ec, rb_control_frame_t *cfp,
3101 struct rb_calling_info *calling)
3102{
3103 const struct rb_callinfo *MAYBE_UNUSED(ci) = calling->cd->ci;
3104 const struct rb_callcache *cc = calling->cc;
3105
3106 VM_ASSERT((vm_ci_flag(ci) & VM_CALL_KWARG) == 0);
3107 RB_DEBUG_COUNTER_INC(ccf_iseq_kw2);
3108
3109 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3110 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3111 VALUE * const argv = cfp->sp - calling->argc;
3112 VALUE * const klocals = argv + kw_param->bits_start - kw_param->num;
3113
3114 int i;
3115 for (i=0; i<kw_param->num; i++) {
3116 klocals[i] = kw_param->default_values[i];
3117 }
3118 klocals[i] = INT2FIX(0); // kw specify flag
3119 // NOTE:
3120 // nobody check this value, but it should be cleared because it can
3121 // points invalid VALUE (T_NONE objects, raw pointer and so on).
3122
3123 int param = ISEQ_BODY(iseq)->param.size;
3124 int local = ISEQ_BODY(iseq)->local_table_size;
3125 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3126}
3127
3128static VALUE builtin_invoker0(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr);
3129
3130static VALUE
3131vm_call_single_noarg_leaf_builtin(rb_execution_context_t *ec, rb_control_frame_t *cfp,
3132 struct rb_calling_info *calling)
3133{
3134 const struct rb_builtin_function *bf = calling->cc->aux_.bf;
3135 cfp->sp -= (calling->argc + 1);
3136 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
3137 return builtin_invoker0(ec, calling->recv, NULL, func_ptr);
3138}
3139
3140VALUE rb_gen_method_name(VALUE owner, VALUE name); // in vm_backtrace.c
3141
3142static void
3143warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, void *pc)
3144{
3145 rb_vm_t *vm = GET_VM();
3146 set_table *dup_check_table = &vm->unused_block_warning_table;
3147 st_data_t key;
3148 bool strict_unused_block = rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
3149
3150 union {
3151 VALUE v;
3152 unsigned char b[SIZEOF_VALUE];
3153 } k1 = {
3154 .v = (VALUE)pc,
3155 }, k2 = {
3156 .v = (VALUE)cme->def,
3157 };
3158
3159 // relax check
3160 if (!strict_unused_block) {
3161 key = (st_data_t)cme->def->original_id;
3162
3163 if (set_table_lookup(dup_check_table, key)) {
3164 return;
3165 }
3166 }
3167
3168 // strict check
3169 // make unique key from pc and me->def pointer
3170 key = 0;
3171 for (int i=0; i<SIZEOF_VALUE; i++) {
3172 // fprintf(stderr, "k1:%3d k2:%3d\n", k1.b[i], k2.b[SIZEOF_VALUE-1-i]);
3173 key |= (st_data_t)(k1.b[i] ^ k2.b[SIZEOF_VALUE-1-i]) << (8 * i);
3174 }
3175
3176 if (0) {
3177 fprintf(stderr, "SIZEOF_VALUE:%d\n", SIZEOF_VALUE);
3178 fprintf(stderr, "pc:%p def:%p\n", pc, (void *)cme->def);
3179 fprintf(stderr, "key:%p\n", (void *)key);
3180 }
3181
3182 // duplication check
3183 if (set_insert(dup_check_table, key)) {
3184 // already shown
3185 }
3186 else if (RTEST(ruby_verbose) || strict_unused_block) {
3187 VALUE m_loc = rb_method_entry_location((const rb_method_entry_t *)cme);
3188 VALUE name = rb_gen_method_name(cme->defined_class, rb_iseq_base_label(iseq));
3189
3190 if (!NIL_P(m_loc)) {
3191 rb_warn("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
3192 name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
3193 }
3194 else {
3195 rb_warn("the block may be ignored because '%"PRIsVALUE"' does not use a block", name);
3196 }
3197 }
3198}
3199
3200static inline int
3201vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
3202 const rb_iseq_t *iseq, VALUE *argv, int param_size, int local_size)
3203{
3204 const struct rb_callinfo *ci = calling->cd->ci;
3205 const struct rb_callcache *cc = calling->cc;
3206
3207 VM_ASSERT((vm_ci_argc(ci), 1));
3208 VM_ASSERT(vm_cc_cme(cc) != NULL);
3209
3210 if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
3211 calling->block_handler != VM_BLOCK_HANDLER_NONE &&
3212 !(vm_ci_flag(calling->cd->ci) & (VM_CALL_OPT_SEND | VM_CALL_SUPER)))) {
3213 warn_unused_block(vm_cc_cme(cc), iseq, (void *)CFP_PC(ec->cfp));
3214 }
3215
3216 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_KW_SPLAT))) {
3217 if (LIKELY(rb_simple_iseq_p(iseq))) {
3218 rb_control_frame_t *cfp = ec->cfp;
3219 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3220 CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
3221
3222 if (calling->argc != lead_num) {
3223 argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
3224 }
3225
3226 //VM_ASSERT(ci == calling->cd->ci);
3227 VM_ASSERT(cc == calling->cc);
3228
3229 if (vm_call_iseq_optimizable_p(ci, cc)) {
3230 if ((ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) && ruby_vm_c_events_enabled == 0) {
3231 VM_ASSERT(ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF);
3232 vm_cc_bf_set(cc, (void *)ISEQ_BODY(iseq)->iseq_encoded[1]);
3233 CC_SET_FASTPATH(cc, vm_call_single_noarg_leaf_builtin, true);
3234 }
3235 else {
3236 CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size), true);
3237 }
3238 }
3239 return 0;
3240 }
3241 else if (rb_iseq_only_optparam_p(iseq)) {
3242 rb_control_frame_t *cfp = ec->cfp;
3243
3244 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3245 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3246
3247 CALLER_SETUP_ARG(cfp, calling, ci, lead_num + opt_num);
3248 const int argc = calling->argc;
3249 const int opt = argc - lead_num;
3250
3251 if (opt < 0 || opt > opt_num) {
3252 argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
3253 }
3254
3255 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3256 CC_SET_FASTPATH(cc, vm_call_iseq_setup_normal_opt_start,
3257 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3258 vm_call_cacheable(ci, cc));
3259 }
3260 else {
3261 CC_SET_FASTPATH(cc, vm_call_iseq_setup_tailcall_opt_start,
3262 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3263 vm_call_cacheable(ci, cc));
3264 }
3265
3266 /* initialize opt vars for self-references */
3267 VM_ASSERT((int)ISEQ_BODY(iseq)->param.size == lead_num + opt_num);
3268 for (int i=argc; i<lead_num + opt_num; i++) {
3269 argv[i] = Qnil;
3270 }
3271 return (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3272 }
3273 else if (rb_iseq_only_kwparam_p(iseq) && !IS_ARGS_SPLAT(ci)) {
3274 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3275 const int argc = calling->argc;
3276 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3277
3278 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
3279 const struct rb_callinfo_kwarg *kw_arg = vm_ci_kwarg(ci);
3280
3281 if (argc - kw_arg->keyword_len == lead_num) {
3282 const int ci_kw_len = kw_arg->keyword_len;
3283 const VALUE * const ci_keywords = kw_arg->keywords;
3284 VALUE * const ci_kws = ALLOCA_N(VALUE, ci_kw_len);
3285 MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
3286
3287 VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
3288 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3289
3290 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
3291 vm_call_cacheable(ci, cc));
3292
3293 return 0;
3294 }
3295 }
3296 else if (argc == lead_num) {
3297 /* no kwarg */
3298 VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
3299 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
3300
3301 if (klocals[kw_param->num] == INT2FIX(0)) {
3302 /* copy from default_values */
3303 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_nokwarg,
3304 vm_call_cacheable(ci, cc));
3305 }
3306
3307 return 0;
3308 }
3309 }
3310 }
3311
3312 // Called iseq is using ... param
3313 // def foo(...) # <- iseq for foo will have "forwardable"
3314 //
3315 // We want to set the `...` local to the caller's CI
3316 // foo(1, 2) # <- the ci for this should end up as `...`
3317 //
3318 // So hopefully the stack looks like:
3319 //
3320 // => 1
3321 // => 2
3322 // => *
3323 // => **
3324 // => &
3325 // => ... # <- points at `foo`s CI
3326 // => cref_or_me
3327 // => specval
3328 // => type
3329 //
3330 if (ISEQ_BODY(iseq)->param.flags.forwardable) {
3331 bool can_fastpath = true;
3332
3333 if ((vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
3334 struct rb_forwarding_call_data * forward_cd = (struct rb_forwarding_call_data *)calling->cd;
3335 if (vm_ci_argc(ci) != vm_ci_argc(forward_cd->caller_ci)) {
3336 ci = vm_ci_new_runtime(
3337 vm_ci_mid(ci),
3338 vm_ci_flag(ci),
3339 vm_ci_argc(ci),
3340 vm_ci_kwarg(ci));
3341 }
3342 else {
3343 ci = forward_cd->caller_ci;
3344 }
3345 can_fastpath = false;
3346 }
3347 // C functions calling iseqs will stack allocate a CI,
3348 // so we need to convert it to heap allocated
3349 if (!vm_ci_markable(ci)) {
3350 ci = vm_ci_new_runtime(
3351 vm_ci_mid(ci),
3352 vm_ci_flag(ci),
3353 vm_ci_argc(ci),
3354 vm_ci_kwarg(ci));
3355 can_fastpath = false;
3356 }
3357 argv[param_size - 1] = (VALUE)ci;
3358 CC_SET_FASTPATH(cc, vm_call_iseq_forwardable, can_fastpath);
3359 return 0;
3360 }
3361
3362 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_method);
3363}
3364
3365static void
3366vm_adjust_stack_forwarding(const struct rb_execution_context_struct *ec, struct rb_control_frame_struct *cfp, int argc, VALUE splat)
3367{
3368 // This case is when the caller is using a ... parameter.
3369 // For example `bar(...)`. The call info will have VM_CALL_FORWARDING
3370 // In this case the caller's caller's CI will be on the stack.
3371 //
3372 // For example:
3373 //
3374 // def bar(a, b); a + b; end
3375 // def foo(...); bar(...); end
3376 // foo(1, 2) # <- this CI will be on the stack when we call `bar(...)`
3377 //
3378 // Stack layout will be:
3379 //
3380 // > 1
3381 // > 2
3382 // > CI for foo(1, 2)
3383 // > cref_or_me
3384 // > specval
3385 // > type
3386 // > receiver
3387 // > CI for foo(1, 2), via `getlocal ...`
3388 // > ( SP points here )
3389 const VALUE * lep = VM_CF_LEP(cfp);
3390
3391 const rb_iseq_t *iseq;
3392
3393 // If we're in an escaped environment (lambda for example), get the iseq
3394 // from the captured env.
3395 if (VM_ENV_FLAGS(lep, VM_ENV_FLAG_ESCAPED)) {
3396 rb_env_t * env = (rb_env_t *)lep[VM_ENV_DATA_INDEX_ENV];
3397 iseq = env->iseq;
3398 }
3399 else { // Otherwise use the lep to find the caller
3400 iseq = CFP_ISEQ(rb_vm_search_cf_from_ep(ec, cfp, lep));
3401 }
3402
3403 // Our local storage is below the args we need to copy
3404 int local_size = ISEQ_BODY(iseq)->local_table_size + argc;
3405
3406 const VALUE * from = lep - (local_size + VM_ENV_DATA_SIZE - 1); // 2 for EP values
3407 VALUE * to = cfp->sp - 1; // clobber the CI
3408
3409 if (RTEST(splat)) {
3410 to -= 1; // clobber the splat array
3411 CHECK_VM_STACK_OVERFLOW0(cfp, to, RARRAY_LEN(splat));
3412 MEMCPY(to, RARRAY_CONST_PTR(splat), VALUE, RARRAY_LEN(splat));
3413 to += RARRAY_LEN(splat);
3414 }
3415
3416 CHECK_VM_STACK_OVERFLOW0(cfp, to, argc);
3417 MEMCPY(to, from, VALUE, argc);
3418 cfp->sp = to + argc;
3419
3420 // Stack layout should now be:
3421 //
3422 // > 1
3423 // > 2
3424 // > CI for foo(1, 2)
3425 // > cref_or_me
3426 // > specval
3427 // > type
3428 // > receiver
3429 // > 1
3430 // > 2
3431 // > ( SP points here )
3432}
3433
3434static VALUE
3435vm_call_iseq_setup(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
3436{
3437 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3438
3439 const struct rb_callcache *cc = calling->cc;
3440 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3441 int param_size = ISEQ_BODY(iseq)->param.size;
3442 int local_size = ISEQ_BODY(iseq)->local_table_size;
3443
3444 RUBY_ASSERT(!ISEQ_BODY(iseq)->param.flags.forwardable);
3445
3446 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3447 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3448}
3449
3450static VALUE
3451vm_call_iseq_fwd_setup(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
3452{
3453 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3454
3455 const struct rb_callcache *cc = calling->cc;
3456 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3457 int param_size = ISEQ_BODY(iseq)->param.size;
3458 int local_size = ISEQ_BODY(iseq)->local_table_size;
3459
3460 RUBY_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3461
3462 // Setting up local size and param size
3463 local_size = local_size + vm_ci_argc(calling->cd->ci);
3464 param_size = param_size + vm_ci_argc(calling->cd->ci);
3465
3466 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3467 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3468}
3469
3470static inline VALUE
3471vm_call_iseq_setup_2(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling,
3472 int opt_pc, int param_size, int local_size)
3473{
3474 const struct rb_callinfo *ci = calling->cd->ci;
3475 const struct rb_callcache *cc = calling->cc;
3476
3477 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3478 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param_size, local_size);
3479 }
3480 else {
3481 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3482 }
3483}
3484
3485static inline VALUE
3486vm_call_iseq_setup_normal(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, const rb_callable_method_entry_t *me,
3487 int opt_pc, int param_size, int local_size)
3488{
3489 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3490 VALUE *argv = cfp->sp - calling->argc;
3491 VALUE *sp = argv + param_size;
3492 cfp->sp = argv - 1 /* recv */;
3493
3494 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling->recv,
3495 calling->block_handler, (VALUE)me,
3496 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3497 local_size - param_size,
3498 ISEQ_BODY(iseq)->stack_max);
3499 return Qundef;
3500}
3501
3502static inline VALUE
3503vm_call_iseq_setup_tailcall(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, int opt_pc)
3504{
3505 const struct rb_callcache *cc = calling->cc;
3506 unsigned int i;
3507 VALUE *argv = cfp->sp - calling->argc;
3508 const rb_callable_method_entry_t *me = vm_cc_cme(cc);
3509 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3510 VALUE *src_argv = argv;
3511 VALUE *sp_orig, *sp;
3512 VALUE finish_flag = VM_FRAME_FINISHED_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
3513
3514 if (VM_BH_FROM_CFP_P(calling->block_handler, cfp)) {
3515 struct rb_captured_block *dst_captured = VM_CFP_TO_CAPTURED_BLOCK(RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
3516 const struct rb_captured_block *src_captured = VM_BH_TO_CAPT_BLOCK(calling->block_handler);
3517 dst_captured->code.val = src_captured->code.val;
3518 if (VM_BH_ISEQ_BLOCK_P(calling->block_handler)) {
3519 calling->block_handler = VM_BH_FROM_ISEQ_BLOCK(dst_captured);
3520 }
3521 else {
3522 calling->block_handler = VM_BH_FROM_IFUNC_BLOCK(dst_captured);
3523 }
3524 }
3525
3526 vm_pop_frame(ec, cfp, cfp->ep);
3527 cfp = ec->cfp;
3528
3529 sp_orig = sp = cfp->sp;
3530
3531 /* push self */
3532 sp[0] = calling->recv;
3533 sp++;
3534
3535 /* copy arguments */
3536 for (i=0; i < ISEQ_BODY(iseq)->param.size; i++) {
3537 *sp++ = src_argv[i];
3538 }
3539
3540 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL | finish_flag,
3541 calling->recv, calling->block_handler, (VALUE)me,
3542 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3543 ISEQ_BODY(iseq)->local_table_size - ISEQ_BODY(iseq)->param.size,
3544 ISEQ_BODY(iseq)->stack_max);
3545
3546 cfp->sp = sp_orig;
3547
3548 return Qundef;
3549}
3550
3551static void
3552ractor_unsafe_check(void)
3553{
3554 if (!rb_ractor_main_p()) {
3555 rb_raise(rb_eRactorUnsafeError, "ractor unsafe method called from not main ractor");
3556 }
3557}
3558
3559static VALUE
3560call_cfunc_m2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3561{
3562 ractor_unsafe_check();
3563 VALUE(*f)(VALUE, VALUE) = (VALUE(*)(VALUE, VALUE))func;
3564 return (*f)(recv, rb_ary_new4(argc, argv));
3565}
3566
3567static VALUE
3568call_cfunc_m1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3569{
3570 ractor_unsafe_check();
3571 VALUE(*f)(int, const VALUE *, VALUE) = (VALUE(*)(int, const VALUE *, VALUE))func;
3572 return (*f)(argc, argv, recv);
3573}
3574
3575static VALUE
3576call_cfunc_0(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3577{
3578 ractor_unsafe_check();
3579 VALUE(*f)(VALUE) = (VALUE(*)(VALUE))func;
3580 return (*f)(recv);
3581}
3582
3583static VALUE
3584call_cfunc_1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3585{
3586 ractor_unsafe_check();
3587 VALUE(*f)(VALUE, VALUE) = (VALUE(*)(VALUE, VALUE))func;
3588 return (*f)(recv, argv[0]);
3589}
3590
3591static VALUE
3592call_cfunc_2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3593{
3594 ractor_unsafe_check();
3595 VALUE(*f)(VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE))func;
3596 return (*f)(recv, argv[0], argv[1]);
3597}
3598
3599static VALUE
3600call_cfunc_3(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3601{
3602 ractor_unsafe_check();
3603 VALUE(*f)(VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE))func;
3604 return (*f)(recv, argv[0], argv[1], argv[2]);
3605}
3606
3607static VALUE
3608call_cfunc_4(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3609{
3610 ractor_unsafe_check();
3611 VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE))func;
3612 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3613}
3614
3615static VALUE
3616call_cfunc_5(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3617{
3618 ractor_unsafe_check();
3619 VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
3620 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3621}
3622
3623static VALUE
3624call_cfunc_6(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3625{
3626 ractor_unsafe_check();
3628 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3629}
3630
3631static VALUE
3632call_cfunc_7(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3633{
3634 ractor_unsafe_check();
3636 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3637}
3638
3639static VALUE
3640call_cfunc_8(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3641{
3642 ractor_unsafe_check();
3644 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3645}
3646
3647static VALUE
3648call_cfunc_9(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3649{
3650 ractor_unsafe_check();
3652 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3653}
3654
3655static VALUE
3656call_cfunc_10(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3657{
3658 ractor_unsafe_check();
3660 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3661}
3662
3663static VALUE
3664call_cfunc_11(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3665{
3666 ractor_unsafe_check();
3668 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
3669}
3670
3671static VALUE
3672call_cfunc_12(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3673{
3674 ractor_unsafe_check();
3676 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
3677}
3678
3679static VALUE
3680call_cfunc_13(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3681{
3682 ractor_unsafe_check();
3684 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
3685}
3686
3687static VALUE
3688call_cfunc_14(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3689{
3690 ractor_unsafe_check();
3692 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
3693}
3694
3695static VALUE
3696call_cfunc_15(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3697{
3698 ractor_unsafe_check();
3700 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
3701}
3702
3703static VALUE
3704ractor_safe_call_cfunc_m2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3705{
3706 VALUE(*f)(VALUE, VALUE) = (VALUE(*)(VALUE, VALUE))func;
3707 return (*f)(recv, rb_ary_new4(argc, argv));
3708}
3709
3710static VALUE
3711ractor_safe_call_cfunc_m1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3712{
3713 VALUE(*f)(int, const VALUE *, VALUE) = (VALUE(*)(int, const VALUE *, VALUE))func;
3714 return (*f)(argc, argv, recv);
3715}
3716
3717static VALUE
3718ractor_safe_call_cfunc_0(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3719{
3720 VALUE(*f)(VALUE) = (VALUE(*)(VALUE))func;
3721 return (*f)(recv);
3722}
3723
3724static VALUE
3725ractor_safe_call_cfunc_1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3726{
3727 VALUE(*f)(VALUE, VALUE) = (VALUE(*)(VALUE, VALUE))func;
3728 return (*f)(recv, argv[0]);
3729}
3730
3731static VALUE
3732ractor_safe_call_cfunc_2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3733{
3734 VALUE(*f)(VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE))func;
3735 return (*f)(recv, argv[0], argv[1]);
3736}
3737
3738static VALUE
3739ractor_safe_call_cfunc_3(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3740{
3741 VALUE(*f)(VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE))func;
3742 return (*f)(recv, argv[0], argv[1], argv[2]);
3743}
3744
3745static VALUE
3746ractor_safe_call_cfunc_4(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3747{
3748 VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE))func;
3749 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3750}
3751
3752static VALUE
3753ractor_safe_call_cfunc_5(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3754{
3755 VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
3756 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3757}
3758
3759static VALUE
3760ractor_safe_call_cfunc_6(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3761{
3763 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3764}
3765
3766static VALUE
3767ractor_safe_call_cfunc_7(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3768{
3770 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3771}
3772
3773static VALUE
3774ractor_safe_call_cfunc_8(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3775{
3777 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3778}
3779
3780static VALUE
3781ractor_safe_call_cfunc_9(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3782{
3784 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3785}
3786
3787static VALUE
3788ractor_safe_call_cfunc_10(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3789{
3791 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3792}
3793
3794static VALUE
3795ractor_safe_call_cfunc_11(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3796{
3798 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
3799}
3800
3801static VALUE
3802ractor_safe_call_cfunc_12(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3803{
3805 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
3806}
3807
3808static VALUE
3809ractor_safe_call_cfunc_13(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3810{
3812 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
3813}
3814
3815static VALUE
3816ractor_safe_call_cfunc_14(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3817{
3819 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
3820}
3821
3822static VALUE
3823ractor_safe_call_cfunc_15(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
3824{
3826 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
3827}
3828
3829static inline int
3830vm_cfp_consistent_p(rb_execution_context_t *ec, const rb_control_frame_t *reg_cfp)
3831{
3832 const int ov_flags = RAISED_STACKOVERFLOW;
3833 if (LIKELY(reg_cfp == ec->cfp + 1)) return TRUE;
3834 if (rb_ec_raised_p(ec, ov_flags)) {
3835 rb_ec_raised_reset(ec, ov_flags);
3836 return TRUE;
3837 }
3838 return FALSE;
3839}
3840
3841#define CHECK_CFP_CONSISTENCY(func) \
3842 (LIKELY(vm_cfp_consistent_p(ec, reg_cfp)) ? (void)0 : \
3843 rb_bug(func ": cfp consistency error (%p, %p)", (void *)reg_cfp, (void *)(ec->cfp+1)))
3844
3845static inline
3846const rb_method_cfunc_t *
3847vm_method_cfunc_entry(const rb_callable_method_entry_t *me)
3848{
3849#if VM_DEBUG_VERIFY_METHOD_CACHE
3850 switch (me->def->type) {
3851 case VM_METHOD_TYPE_CFUNC:
3852 case VM_METHOD_TYPE_NOTIMPLEMENTED:
3853 break;
3854# define METHOD_BUG(t) case VM_METHOD_TYPE_##t: rb_bug("wrong method type: " #t)
3855 METHOD_BUG(ISEQ);
3856 METHOD_BUG(ATTRSET);
3857 METHOD_BUG(IVAR);
3858 METHOD_BUG(BMETHOD);
3859 METHOD_BUG(ZSUPER);
3860 METHOD_BUG(UNDEF);
3861 METHOD_BUG(OPTIMIZED);
3862 METHOD_BUG(MISSING);
3863 METHOD_BUG(REFINED);
3864 METHOD_BUG(ALIAS);
3865# undef METHOD_BUG
3866 default:
3867 rb_bug("wrong method type: %d", me->def->type);
3868 }
3869#endif
3870 return UNALIGNED_MEMBER_PTR(me->def, body.cfunc);
3871}
3872
3873static VALUE
3874vm_call_cfunc_with_frame_(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling,
3875 int argc, VALUE *argv, VALUE *stack_bottom)
3876{
3877 RB_DEBUG_COUNTER_INC(ccf_cfunc_with_frame);
3878 const struct rb_callinfo *ci = calling->cd->ci;
3879 const struct rb_callcache *cc = calling->cc;
3880 VALUE val;
3881 const rb_callable_method_entry_t *me = vm_cc_cme(cc);
3882 const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(me);
3883
3884 VALUE recv = calling->recv;
3885 VALUE block_handler = calling->block_handler;
3886 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3887
3888 if (UNLIKELY(calling->kw_splat)) {
3889 frame_type |= VM_FRAME_FLAG_CFRAME_KW;
3890 }
3891
3892 VM_ASSERT(reg_cfp == ec->cfp);
3893
3894 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id);
3895 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, vm_ci_mid(ci), me->owner, Qundef);
3896
3897 vm_push_frame(ec, NULL, frame_type, recv,
3898 block_handler, (VALUE)me,
3899 0, ec->cfp->sp, 0, 0);
3900
3901 int len = cfunc->argc;
3902 if (len >= 0) rb_check_arity(argc, len, len);
3903
3904 reg_cfp->sp = stack_bottom;
3905 val = (*cfunc->invoker)(recv, argc, argv, cfunc->func);
3906
3907 CHECK_CFP_CONSISTENCY("vm_call_cfunc");
3908
3909 rb_vm_pop_frame(ec);
3910
3911 VM_ASSERT(ec->cfp->sp == stack_bottom);
3912
3913 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, recv, me->def->original_id, vm_ci_mid(ci), me->owner, val);
3914 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
3915
3916 return val;
3917}
3918
3919// Push a C method frame for a given cme. This is called when JIT code skipped
3920// pushing a frame but the C method reached a point where a frame is needed.
3921void
3922rb_vm_push_cfunc_frame(const rb_callable_method_entry_t *cme, int recv_idx)
3923{
3924 VM_ASSERT(cme->def->type == VM_METHOD_TYPE_CFUNC);
3925 rb_execution_context_t *ec = GET_EC();
3926 VALUE *sp = ec->cfp->sp;
3927 VALUE recv = *(sp - recv_idx - 1);
3928 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3929 VALUE block_handler = VM_BLOCK_HANDLER_NONE;
3930#if VM_CHECK_MODE > 0
3931 // Clean up the stack canary since we're about to satisfy the "leaf or lazy push" assumption
3932 *(GET_EC()->cfp->sp) = Qfalse;
3933#endif
3934 vm_push_frame(ec, NULL, frame_type, recv, block_handler, (VALUE)cme, 0, ec->cfp->sp, 0, 0);
3935}
3936
3937// If true, cc->call needs to include `CALLER_SETUP_ARG` (i.e. can't be skipped in fastpath)
3938bool
3939rb_splat_or_kwargs_p(const struct rb_callinfo *restrict ci)
3940{
3941 return IS_ARGS_SPLAT(ci) || IS_ARGS_KW_OR_KW_SPLAT(ci);
3942}
3943
3944static VALUE
3945vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
3946{
3947 int argc = calling->argc;
3948 VALUE *stack_bottom = reg_cfp->sp - argc - 1;
3949 VALUE *argv = &stack_bottom[1];
3950
3951 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3952}
3953
3954static VALUE
3955vm_call_cfunc_other(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
3956{
3957 const struct rb_callinfo *ci = calling->cd->ci;
3958 RB_DEBUG_COUNTER_INC(ccf_cfunc_other);
3959
3960 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
3961 VALUE argv_ary;
3962 if (UNLIKELY(argv_ary = calling->heap_argv)) {
3963 VM_ASSERT(!IS_ARGS_KEYWORD(ci));
3964 int argc = RARRAY_LENINT(argv_ary);
3965 VALUE *argv = (VALUE *)RARRAY_CONST_PTR(argv_ary);
3966 VALUE *stack_bottom = reg_cfp->sp - 2;
3967
3968 VM_ASSERT(calling->argc == 1);
3969 VM_ASSERT(RB_TYPE_P(argv_ary, T_ARRAY));
3970 VM_ASSERT(RBASIC_CLASS(argv_ary) == 0); // hidden ary
3971
3972 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3973 }
3974 else {
3975 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_with_frame, !rb_splat_or_kwargs_p(ci) && !calling->kw_splat && !(vm_ci_flag(ci) & VM_CALL_FORWARDING));
3976
3977 return vm_call_cfunc_with_frame(ec, reg_cfp, calling);
3978 }
3979}
3980
3981static inline VALUE
3982vm_call_cfunc_array_argv(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, int stack_offset, int argc_offset)
3983{
3984 VALUE argv_ary = reg_cfp->sp[-1 - stack_offset];
3985 int argc = RARRAY_LENINT(argv_ary) - argc_offset;
3986
3987 if (UNLIKELY(argc > VM_ARGC_STACK_MAX)) {
3988 return vm_call_cfunc_other(ec, reg_cfp, calling);
3989 }
3990
3991 VALUE *argv = (VALUE *)RARRAY_CONST_PTR(argv_ary);
3992 calling->kw_splat = 0;
3993 int i;
3994 VALUE *stack_bottom = reg_cfp->sp - 2 - stack_offset;
3995 VALUE *sp = stack_bottom;
3996 CHECK_VM_STACK_OVERFLOW(reg_cfp, argc);
3997 for(i = 0; i < argc; i++) {
3998 *++sp = argv[i];
3999 }
4000 reg_cfp->sp = sp+1;
4001
4002 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, stack_bottom+1, stack_bottom);
4003}
4004
4005static inline VALUE
4006vm_call_cfunc_only_splat(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4007{
4008 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat);
4009 VALUE argv_ary = reg_cfp->sp[-1];
4010 int argc = RARRAY_LENINT(argv_ary);
4011 VALUE *argv = (VALUE *)RARRAY_CONST_PTR(argv_ary);
4012 VALUE last_hash;
4013 int argc_offset = 0;
4014
4015 if (UNLIKELY(argc > 0 &&
4016 RB_TYPE_P((last_hash = argv[argc-1]), T_HASH) &&
4017 (((struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS))) {
4018 if (!RHASH_EMPTY_P(last_hash)) {
4019 return vm_call_cfunc_other(ec, reg_cfp, calling);
4020 }
4021 argc_offset++;
4022 }
4023 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 0, argc_offset);
4024}
4025
4026static inline VALUE
4027vm_call_cfunc_only_splat_kw(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4028{
4029 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat_kw);
4030 VALUE keyword_hash = reg_cfp->sp[-1];
4031
4032 if (keyword_hash == Qnil || (RB_TYPE_P(keyword_hash, T_HASH) && RHASH_EMPTY_P(keyword_hash))) {
4033 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 1, 0);
4034 }
4035
4036 return vm_call_cfunc_other(ec, reg_cfp, calling);
4037}
4038
4039static VALUE
4040vm_call_cfunc(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4041{
4042 const struct rb_callinfo *ci = calling->cd->ci;
4043 RB_DEBUG_COUNTER_INC(ccf_cfunc);
4044
4045 if (IS_ARGS_SPLAT(ci) && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4046 if (!IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 1) {
4047 // f(*a)
4048 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat, TRUE);
4049 return vm_call_cfunc_only_splat(ec, reg_cfp, calling);
4050 }
4051 if (IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 2) {
4052 // f(*a, **kw)
4053 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat_kw, TRUE);
4054 return vm_call_cfunc_only_splat_kw(ec, reg_cfp, calling);
4055 }
4056 }
4057
4058 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_other, TRUE);
4059 return vm_call_cfunc_other(ec, reg_cfp, calling);
4060}
4061
4062static VALUE
4063vm_call_ivar(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4064{
4065 const struct rb_callcache *cc = calling->cc;
4066 RB_DEBUG_COUNTER_INC(ccf_ivar);
4067 cfp->sp -= 1;
4068 VALUE ivar = vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE, Qnil);
4069 return ivar;
4070}
4071
4072static VALUE
4073vm_call_attrset_direct(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_callcache *cc, VALUE obj)
4074{
4075 RB_DEBUG_COUNTER_INC(ccf_attrset);
4076 VALUE val = *(cfp->sp - 1);
4077 cfp->sp -= 2;
4078 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_cc_atomic_cache_read(cc));
4079 ID id = vm_cc_cme(cc)->def->body.attr.id;
4080 rb_check_frozen(obj);
4081 VALUE res = vm_setivar(obj, val, cache);
4082 if (UNDEF_P(res)) {
4083 switch (BUILTIN_TYPE(obj)) {
4084 case T_OBJECT:
4085 break;
4086 case T_CLASS:
4087 case T_MODULE:
4088 {
4089 res = vm_setivar_class(obj, val, cache);
4090 if (!UNDEF_P(res)) {
4091 return res;
4092 }
4093 }
4094 break;
4095 default:
4096 {
4097 res = vm_setivar_default(obj, id, val, cache);
4098 if (!UNDEF_P(res)) {
4099 return res;
4100 }
4101 }
4102 }
4103 res = vm_setivar_slowpath_attr(obj, id, val, cc);
4104 }
4105 return res;
4106}
4107
4108static VALUE
4109vm_call_attrset(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4110{
4111 return vm_call_attrset_direct(ec, cfp, calling->cc, calling->recv);
4112}
4113
4114static inline VALUE
4115vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv)
4116{
4117 rb_proc_t *proc;
4118 VALUE val;
4119 const struct rb_callcache *cc = calling->cc;
4120 const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
4121 VALUE procv = cme->def->body.bmethod.proc;
4122
4123 if (!RB_OBJ_SHAREABLE_P(procv) &&
4124 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4125 rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
4126 }
4127
4128 /* control block frame */
4129 GetProcPtr(procv, proc);
4130 val = vm_invoke_bmethod(ec, proc, calling->recv, CALLING_ARGC(calling), argv, calling->kw_splat, calling->block_handler, vm_cc_cme(cc));
4131
4132 return val;
4133}
4134
4135static int vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *calling, const struct rb_callinfo *ci, const rb_iseq_t *iseq, VALUE *argv, const enum arg_setup_type arg_setup_type);
4136
4137static VALUE
4138vm_call_iseq_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4139{
4140 RB_DEBUG_COUNTER_INC(ccf_iseq_bmethod);
4141
4142 const struct rb_callcache *cc = calling->cc;
4143 const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
4144 VALUE procv = cme->def->body.bmethod.proc;
4145
4146 if (!RB_OBJ_SHAREABLE_P(procv) &&
4147 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4148 rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
4149 }
4150
4151 rb_proc_t *proc;
4152 GetProcPtr(procv, proc);
4153 const struct rb_block *block = &proc->block;
4154
4155 while (vm_block_type(block) == block_type_proc) {
4156 block = vm_proc_block(block->as.proc);
4157 }
4158 VM_ASSERT(vm_block_type(block) == block_type_iseq);
4159
4160 const struct rb_captured_block *captured = &block->as.captured;
4161 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
4162 VALUE * const argv = cfp->sp - calling->argc;
4163 const int arg_size = ISEQ_BODY(iseq)->param.size;
4164
4165 int opt_pc;
4166 if (vm_ci_flag(calling->cd->ci) & VM_CALL_ARGS_SIMPLE) {
4167 opt_pc = vm_callee_setup_block_arg(ec, calling, calling->cd->ci, iseq, argv, arg_setup_method);
4168 }
4169 else {
4170 opt_pc = setup_parameters_complex(ec, iseq, calling, calling->cd->ci, argv, arg_setup_method);
4171 }
4172
4173 cfp->sp = argv - 1; // -1 for the receiver
4174
4175 vm_push_frame(ec, iseq,
4176 VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_BMETHOD | VM_FRAME_FLAG_LAMBDA,
4177 calling->recv,
4178 VM_GUARDED_PREV_EP(captured->ep),
4179 (VALUE)cme,
4180 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
4181 argv + arg_size,
4182 ISEQ_BODY(iseq)->local_table_size - arg_size,
4183 ISEQ_BODY(iseq)->stack_max);
4184
4185 return Qundef;
4186}
4187
4188static VALUE
4189vm_call_noniseq_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4190{
4191 RB_DEBUG_COUNTER_INC(ccf_noniseq_bmethod);
4192
4193 VALUE *argv;
4194 int argc;
4195 CALLER_SETUP_ARG(cfp, calling, calling->cd->ci, ALLOW_HEAP_ARGV);
4196 if (UNLIKELY(calling->heap_argv)) {
4197 argv = RARRAY_PTR(calling->heap_argv);
4198 cfp->sp -= 2;
4199 }
4200 else {
4201 argc = calling->argc;
4202 argv = ALLOCA_N(VALUE, argc);
4203 MEMCPY(argv, cfp->sp - argc, VALUE, argc);
4204 cfp->sp += - argc - 1;
4205 }
4206
4207 return vm_call_bmethod_body(ec, calling, argv);
4208}
4209
4210static VALUE
4211vm_call_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4212{
4213 RB_DEBUG_COUNTER_INC(ccf_bmethod);
4214
4215 const struct rb_callcache *cc = calling->cc;
4216 const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
4217 VALUE procv = cme->def->body.bmethod.proc;
4218 rb_proc_t *proc;
4219 GetProcPtr(procv, proc);
4220 const struct rb_block *block = &proc->block;
4221
4222 while (vm_block_type(block) == block_type_proc) {
4223 block = vm_proc_block(block->as.proc);
4224 }
4225 if (vm_block_type(block) == block_type_iseq) {
4226 CC_SET_FASTPATH(cc, vm_call_iseq_bmethod, TRUE);
4227 return vm_call_iseq_bmethod(ec, cfp, calling);
4228 }
4229
4230 CC_SET_FASTPATH(cc, vm_call_noniseq_bmethod, TRUE);
4231 return vm_call_noniseq_bmethod(ec, cfp, calling);
4232}
4233
4234VALUE
4235rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
4236{
4237 VALUE klass = current_class;
4238
4239 /* for prepended Module, then start from cover class */
4240 if (RB_TYPE_P(klass, T_ICLASS) && RICLASS_IS_ORIGIN_P(klass) &&
4241 RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
4242 klass = RBASIC_CLASS(klass);
4243 }
4244
4245 while (RTEST(klass)) {
4246 VALUE owner = RB_TYPE_P(klass, T_ICLASS) ? RBASIC_CLASS(klass) : klass;
4247 if (owner == target_owner) {
4248 return klass;
4249 }
4250 klass = RCLASS_SUPER(klass);
4251 }
4252
4253 return current_class; /* maybe module function */
4254}
4255
4256static const rb_callable_method_entry_t *
4257aliased_callable_method_entry(const rb_callable_method_entry_t *me)
4258{
4259 const rb_method_entry_t *orig_me = me->def->body.alias.original_me;
4260 const rb_callable_method_entry_t *cme;
4261
4262 if (orig_me->defined_class == 0) {
4263 VALUE defined_class = rb_find_defined_class_by_owner(me->defined_class, orig_me->owner);
4264 VM_ASSERT_TYPE(orig_me->owner, T_MODULE);
4265 cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class);
4266
4267 if (me->def->reference_count == 1) {
4268 RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme);
4269 }
4270 else {
4272 rb_method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id);
4273 rb_method_definition_set((rb_method_entry_t *)me, def, (void *)cme);
4274 }
4275 }
4276 else {
4277 cme = (const rb_callable_method_entry_t *)orig_me;
4278 }
4279
4280 VM_ASSERT(callable_method_entry_p(cme));
4281 return cme;
4282}
4283
4285rb_aliased_callable_method_entry(const rb_callable_method_entry_t *me)
4286{
4287 return aliased_callable_method_entry(me);
4288}
4289
4290static VALUE
4291vm_call_alias(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4292{
4293 calling->cc = &VM_CC_ON_STACK(Qundef,
4294 vm_call_general,
4295 {{0}},
4296 aliased_callable_method_entry(vm_cc_cme(calling->cc)));
4297
4298 return vm_call_method_each_type(ec, cfp, calling);
4299}
4300
4301static enum method_missing_reason
4302ci_missing_reason(const struct rb_callinfo *ci)
4303{
4304 enum method_missing_reason stat = MISSING_NOENTRY;
4305 if (vm_ci_flag(ci) & VM_CALL_VCALL && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) stat |= MISSING_VCALL;
4306 if (vm_ci_flag(ci) & VM_CALL_FCALL) stat |= MISSING_FCALL;
4307 if (vm_ci_flag(ci) & VM_CALL_SUPER) stat |= MISSING_SUPER;
4308 return stat;
4309}
4310
4311static VALUE vm_call_method_missing(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling);
4312
4313static VALUE
4314vm_call_symbol(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
4315 struct rb_calling_info *calling, const struct rb_callinfo *ci, VALUE symbol, int flags)
4316{
4317 ASSUME(calling->argc >= 0);
4318
4319 enum method_missing_reason missing_reason = MISSING_NOENTRY;
4320 int argc = calling->argc;
4321 VALUE recv = calling->recv;
4322 VALUE klass = CLASS_OF(recv);
4323 ID mid = rb_check_id(&symbol);
4324 flags |= VM_CALL_OPT_SEND;
4325
4326 if (UNLIKELY(! mid)) {
4327 mid = idMethodMissing;
4328 missing_reason = ci_missing_reason(ci);
4329 ec->method_missing_reason = missing_reason;
4330
4331 VALUE argv_ary;
4332 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4333 if (rb_method_basic_definition_p(klass, idMethodMissing)) {
4334 rb_ary_unshift(argv_ary, symbol);
4335
4336 /* Inadvertent symbol creation shall be forbidden, see [Feature #5112] */
4337 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4338 VALUE exc = rb_make_no_method_exception(
4339 rb_eNoMethodError, 0, recv, RARRAY_LENINT(argv_ary), RARRAY_CONST_PTR(argv_ary), priv);
4340
4341 rb_exc_raise(exc);
4342 }
4343 rb_ary_unshift(argv_ary, rb_str_intern(symbol));
4344 }
4345 else {
4346 /* E.g. when argc == 2
4347 *
4348 * | | | | TOPN
4349 * | | +------+
4350 * | | +---> | arg1 | 0
4351 * +------+ | +------+
4352 * | arg1 | -+ +-> | arg0 | 1
4353 * +------+ | +------+
4354 * | arg0 | ---+ | sym | 2
4355 * +------+ +------+
4356 * | recv | | recv | 3
4357 * --+------+--------+------+------
4358 */
4359 int i = argc;
4360 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4361 INC_SP(1);
4362 MEMMOVE(&TOPN(i - 1), &TOPN(i), VALUE, i);
4363 argc = ++calling->argc;
4364
4365 if (rb_method_basic_definition_p(klass, idMethodMissing)) {
4366 /* Inadvertent symbol creation shall be forbidden, see [Feature #5112] */
4367 TOPN(i) = symbol;
4368 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4369 const VALUE *argv = STACK_ADDR_FROM_TOP(argc);
4370 VALUE exc = rb_make_no_method_exception(
4371 rb_eNoMethodError, 0, recv, argc, argv, priv);
4372
4373 rb_exc_raise(exc);
4374 }
4375 else {
4376 TOPN(i) = rb_str_intern(symbol);
4377 }
4378 }
4379 }
4380
4381 struct rb_forwarding_call_data new_fcd = {
4382 .cd = {
4383 .ci = &VM_CI_ON_STACK(mid, flags, argc, vm_ci_kwarg(ci)),
4384 .cc = NULL,
4385 },
4386 .caller_ci = NULL,
4387 };
4388
4389 if (!(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4390 calling->cd = &new_fcd.cd;
4391 }
4392 else {
4393 const struct rb_callinfo *caller_ci = ((struct rb_forwarding_call_data *)calling->cd)->caller_ci;
4394 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4395 new_fcd.caller_ci = caller_ci;
4396 calling->cd = (struct rb_call_data *)&new_fcd;
4397 }
4398 calling->cc = &VM_CC_ON_STACK(klass,
4399 vm_call_general,
4400 { .method_missing_reason = missing_reason },
4401 rb_callable_method_entry_with_refinements(klass, mid, NULL));
4402
4403 if (flags & VM_CALL_FCALL) {
4404 return vm_call_method(ec, reg_cfp, calling);
4405 }
4406
4407 const struct rb_callcache *cc = calling->cc;
4408 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
4409
4410 if (vm_cc_cme(cc) != NULL) {
4411 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
4412 case METHOD_VISI_PUBLIC: /* likely */
4413 return vm_call_method_each_type(ec, reg_cfp, calling);
4414 case METHOD_VISI_PRIVATE:
4415 vm_cc_method_missing_reason_set(cc, MISSING_PRIVATE);
4416 break;
4417 case METHOD_VISI_PROTECTED:
4418 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
4419 break;
4420 default:
4421 VM_UNREACHABLE(vm_call_method);
4422 }
4423 return vm_call_method_missing(ec, reg_cfp, calling);
4424 }
4425
4426 return vm_call_method_nome(ec, reg_cfp, calling);
4427}
4428
4429static VALUE
4430vm_call_opt_send0(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, int flags)
4431{
4432 const struct rb_callinfo *ci = calling->cd->ci;
4433 int i;
4434 VALUE sym;
4435
4436 i = calling->argc - 1;
4437
4438 if (calling->argc == 0) {
4439 rb_raise(rb_eArgError, "no method name given");
4440 }
4441
4442 sym = TOPN(i);
4443 /* E.g. when i == 2
4444 *
4445 * | | | | TOPN
4446 * +------+ | |
4447 * | arg1 | ---+ | | 0
4448 * +------+ | +------+
4449 * | arg0 | -+ +-> | arg1 | 1
4450 * +------+ | +------+
4451 * | sym | +---> | arg0 | 2
4452 * +------+ +------+
4453 * | recv | | recv | 3
4454 * --+------+--------+------+------
4455 */
4456 /* shift arguments */
4457 if (i > 0) {
4458 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
4459 }
4460 calling->argc -= 1;
4461 DEC_SP(1);
4462
4463 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4464}
4465
4466static VALUE
4467vm_call_opt_send_complex(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4468{
4469 RB_DEBUG_COUNTER_INC(ccf_opt_send_complex);
4470 const struct rb_callinfo *ci = calling->cd->ci;
4471 int flags = VM_CALL_FCALL;
4472 VALUE sym;
4473
4474 VALUE argv_ary;
4475 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
4476 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4477 sym = rb_ary_shift(argv_ary);
4478 flags |= VM_CALL_ARGS_SPLAT;
4479 if (calling->kw_splat) {
4480 VALUE last_hash = rb_ary_last(0, NULL, argv_ary);
4481 ((struct RHash *)last_hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
4482 calling->kw_splat = 0;
4483 }
4484 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4485 }
4486
4487 if (calling->kw_splat) flags |= VM_CALL_KW_SPLAT;
4488 return vm_call_opt_send0(ec, reg_cfp, calling, flags);
4489}
4490
4491static VALUE
4492vm_call_opt_send_simple(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4493{
4494 RB_DEBUG_COUNTER_INC(ccf_opt_send_simple);
4495 return vm_call_opt_send0(ec, reg_cfp, calling, vm_ci_flag(calling->cd->ci) | VM_CALL_FCALL);
4496}
4497
4498static VALUE
4499vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4500{
4501 RB_DEBUG_COUNTER_INC(ccf_opt_send);
4502
4503 const struct rb_callinfo *ci = calling->cd->ci;
4504 int flags = vm_ci_flag(ci);
4505
4506 if (UNLIKELY((flags & VM_CALL_FORWARDING) || (!(flags & VM_CALL_ARGS_SIMPLE) &&
4507 ((calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
4508 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
4509 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc)))))) {
4510 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_complex, TRUE);
4511 return vm_call_opt_send_complex(ec, reg_cfp, calling);
4512 }
4513
4514 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_simple, TRUE);
4515 return vm_call_opt_send_simple(ec, reg_cfp, calling);
4516}
4517
4518static VALUE
4519vm_call_method_missing_body(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling,
4520 const struct rb_callinfo *orig_ci, enum method_missing_reason reason)
4521{
4522 RB_DEBUG_COUNTER_INC(ccf_method_missing);
4523
4524 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
4525 unsigned int argc, flag;
4526
4527 flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | vm_ci_flag(orig_ci);
4528 argc = ++calling->argc;
4529
4530 /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
4531 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4532 vm_check_canary(ec, reg_cfp->sp);
4533 if (argc > 1) {
4534 MEMMOVE(argv+1, argv, VALUE, argc-1);
4535 }
4536 argv[0] = ID2SYM(vm_ci_mid(orig_ci));
4537 INC_SP(1);
4538
4539 ec->method_missing_reason = reason;
4540
4541 struct rb_forwarding_call_data new_fcd = {
4542 .cd = {
4543 .ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)),
4544 .cc = NULL,
4545 },
4546 .caller_ci = NULL,
4547 };
4548
4549 if (!(flag & VM_CALL_FORWARDING)) {
4550 calling->cd = &new_fcd.cd;
4551 }
4552 else {
4553 const struct rb_callinfo *caller_ci = ((struct rb_forwarding_call_data *)calling->cd)->caller_ci;
4554 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4555 new_fcd.caller_ci = caller_ci;
4556 calling->cd = (struct rb_call_data *)&new_fcd;
4557 }
4558
4559 calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }},
4560 rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL));
4561 return vm_call_method(ec, reg_cfp, calling);
4562}
4563
4564static VALUE
4565vm_call_method_missing(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4566{
4567 return vm_call_method_missing_body(ec, reg_cfp, calling, calling->cd->ci, vm_cc_cmethod_missing_reason(calling->cc));
4568}
4569
4570static const rb_callable_method_entry_t *refined_method_callable_without_refinement(const rb_callable_method_entry_t *me);
4571static VALUE
4572vm_call_zsuper(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, VALUE klass)
4573{
4574 klass = RCLASS_SUPER(klass);
4575
4576 const rb_callable_method_entry_t *cme = klass ? rb_callable_method_entry(klass, vm_ci_mid(calling->cd->ci)) : NULL;
4577 if (cme == NULL) {
4578 return vm_call_method_nome(ec, cfp, calling);
4579 }
4580 if (cme->def->type == VM_METHOD_TYPE_REFINED &&
4581 cme->def->body.refined.orig_me) {
4582 cme = refined_method_callable_without_refinement(cme);
4583 }
4584
4585 calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
4586
4587 return vm_call_method_each_type(ec, cfp, calling);
4588}
4589
4590static inline VALUE
4591find_refinement(VALUE refinements, VALUE klass)
4592{
4593 if (NIL_P(refinements)) {
4594 return Qnil;
4595 }
4596 return rb_hash_lookup(refinements, klass);
4597}
4598
4599PUREFUNC(static rb_control_frame_t * current_method_entry(const rb_execution_context_t *ec, rb_control_frame_t *cfp));
4600static rb_control_frame_t *
4601current_method_entry(const rb_execution_context_t *ec, rb_control_frame_t *cfp)
4602{
4603 rb_control_frame_t *top_cfp = cfp;
4604
4605 if (CFP_ISEQ(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_BLOCK) {
4606 const rb_iseq_t *local_iseq = ISEQ_BODY(CFP_ISEQ(cfp))->local_iseq;
4607
4608 do {
4609 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
4610 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
4611 /* TODO: orphan block */
4612 return top_cfp;
4613 }
4614 } while (CFP_ISEQ(cfp) != local_iseq);
4615 }
4616 return cfp;
4617}
4618
4619static const rb_callable_method_entry_t *
4620refined_method_callable_without_refinement(const rb_callable_method_entry_t *me)
4621{
4622 const rb_method_entry_t *orig_me = me->def->body.refined.orig_me;
4623 const rb_callable_method_entry_t *cme;
4624
4625 if (orig_me->defined_class == 0) {
4626 cme = NULL;
4627 rb_notimplement();
4628 }
4629 else {
4630 cme = (const rb_callable_method_entry_t *)orig_me;
4631 }
4632
4633 VM_ASSERT(callable_method_entry_p(cme));
4634
4635 if (UNDEFINED_METHOD_ENTRY_P(cme)) {
4636 cme = NULL;
4637 }
4638
4639 return cme;
4640}
4641
4642static const rb_callable_method_entry_t *
4643search_refined_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4644{
4645 ID mid = vm_ci_mid(calling->cd->ci);
4646 const rb_cref_t *cref = vm_get_cref(cfp->ep);
4647 const struct rb_callcache * const cc = calling->cc;
4648 const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
4649
4650 for (; cref; cref = CREF_NEXT(cref)) {
4651 const VALUE refinement = find_refinement(CREF_REFINEMENTS(cref), vm_cc_cme(cc)->owner);
4652 if (NIL_P(refinement)) continue;
4653
4654 const rb_callable_method_entry_t *const ref_me =
4655 rb_callable_method_entry(refinement, mid);
4656
4657 if (ref_me) {
4658 if (vm_cc_call(cc) == vm_call_super_method) {
4659 const rb_control_frame_t *top_cfp = current_method_entry(ec, cfp);
4660 const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
4661 if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) {
4662 continue;
4663 }
4664 }
4665
4666 if (cme->def->type != VM_METHOD_TYPE_REFINED ||
4667 cme->def != ref_me->def) {
4668 cme = ref_me;
4669 }
4670 if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
4671 return cme;
4672 }
4673 }
4674 else {
4675 return NULL;
4676 }
4677 }
4678
4679 if (vm_cc_cme(cc)->def->body.refined.orig_me) {
4680 return refined_method_callable_without_refinement(vm_cc_cme(cc));
4681 }
4682 else {
4683 VALUE klass = RCLASS_SUPER(vm_cc_cme(cc)->defined_class);
4684 const rb_callable_method_entry_t *cme = klass ? rb_callable_method_entry(klass, mid) : NULL;
4685 return cme;
4686 }
4687}
4688
4689static VALUE
4690vm_call_refined(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4691{
4692 const rb_callable_method_entry_t *ref_cme = search_refined_method(ec, cfp, calling);
4693
4694 if (ref_cme) {
4695 if (calling->cd->cc) {
4696 const struct rb_callcache *cc = calling->cc = vm_cc_new(vm_cc_cme(calling->cc)->defined_class, ref_cme, vm_call_general, cc_type_refinement);
4697 RB_OBJ_WRITE(CFP_ISEQ(cfp), &calling->cd->cc, cc);
4698 return vm_call_method(ec, cfp, calling);
4699 }
4700 else {
4701 struct rb_callcache *ref_cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, ref_cme);
4702 calling->cc= ref_cc;
4703 return vm_call_method(ec, cfp, calling);
4704 }
4705 }
4706 else {
4707 return vm_call_method_nome(ec, cfp, calling);
4708 }
4709}
4710
4711static inline VALUE vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_callinfo *ci, bool is_lambda, VALUE block_handler);
4712
4713NOINLINE(static VALUE
4714 vm_invoke_block_opt_call(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
4715 struct rb_calling_info *calling, const struct rb_callinfo *ci, VALUE block_handler));
4716
4717static VALUE
4718vm_invoke_block_opt_call(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
4719 struct rb_calling_info *calling, const struct rb_callinfo *ci, VALUE block_handler)
4720{
4721 int argc = calling->argc;
4722
4723 /* remove self */
4724 if (argc > 0) MEMMOVE(&TOPN(argc), &TOPN(argc-1), VALUE, argc);
4725 DEC_SP(1);
4726
4727 return vm_invoke_block(ec, reg_cfp, calling, ci, false, block_handler);
4728}
4729
4730static VALUE
4731vm_call_opt_call(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4732{
4733 RB_DEBUG_COUNTER_INC(ccf_opt_call);
4734
4735 const struct rb_callinfo *ci = calling->cd->ci;
4736 VALUE procval = calling->recv;
4737 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, VM_BH_FROM_PROC(procval));
4738}
4739
4740static VALUE
4741vm_call_opt_block_call(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4742{
4743 RB_DEBUG_COUNTER_INC(ccf_opt_block_call);
4744
4745 VALUE block_handler = VM_ENV_BLOCK_HANDLER(VM_CF_LEP(reg_cfp));
4746 const struct rb_callinfo *ci = calling->cd->ci;
4747
4748 enum ruby_basic_operators bop;
4749 switch (vm_ci_mid(ci)) {
4750 case idAREF: bop = BOP_AREF; break;
4751 case idYield: bop = BOP_YIELD; break;
4752 case idEqq: bop = BOP_EQQ; break;
4753 default: bop = BOP_CALL; break;
4754 }
4755
4756 if (BASIC_OP_UNREDEFINED_P(bop, PROC_REDEFINED_OP_FLAG)) {
4757 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, block_handler);
4758 }
4759 else {
4760 calling->recv = rb_vm_bh_to_procval(ec, block_handler);
4761 calling->cc = rb_vm_search_method_slowpath(ci, CLASS_OF(calling->recv));
4762 return vm_call_general(ec, reg_cfp, calling);
4763 }
4764}
4765
4766static VALUE
4767vm_call_opt_struct_aref0(rb_execution_context_t *ec, struct rb_calling_info *calling)
4768{
4769 VALUE recv = calling->recv;
4770
4771 VM_ASSERT(RB_TYPE_P(recv, T_STRUCT));
4772 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4773 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_AREF);
4774
4775 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4776 return RSTRUCT_GET_RAW(recv, off);
4777}
4778
4779static VALUE
4780vm_call_opt_struct_aref(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4781{
4782 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aref);
4783
4784 VALUE ret = vm_call_opt_struct_aref0(ec, calling);
4785 reg_cfp->sp -= 1;
4786 return ret;
4787}
4788
4789static VALUE
4790vm_call_opt_struct_aset0(rb_execution_context_t *ec, struct rb_calling_info *calling, VALUE val)
4791{
4792 VALUE recv = calling->recv;
4793
4794 VM_ASSERT(RB_TYPE_P(recv, T_STRUCT));
4795 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4796 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_ASET);
4797
4798 rb_check_frozen(recv);
4799
4800 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4801 RSTRUCT_SET_RAW(recv, off, val);
4802
4803 return val;
4804}
4805
4806static VALUE
4807vm_call_opt_struct_aset(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
4808{
4809 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aset);
4810
4811 VALUE ret = vm_call_opt_struct_aset0(ec, calling, *(reg_cfp->sp - 1));
4812 reg_cfp->sp -= 2;
4813 return ret;
4814}
4815
4816NOINLINE(static VALUE vm_call_optimized(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling,
4817 const struct rb_callinfo *ci, const struct rb_callcache *cc));
4818
4819#define VM_CALL_METHOD_ATTR(var, func, nohook) \
4820 if (UNLIKELY(ruby_vm_c_events_enabled > 0)) { \
4821 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, calling->recv, vm_cc_cme(cc)->def->original_id, \
4822 vm_ci_mid(ci), vm_cc_cme(cc)->owner, Qundef); \
4823 var = func; \
4824 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, calling->recv, vm_cc_cme(cc)->def->original_id, \
4825 vm_ci_mid(ci), vm_cc_cme(cc)->owner, (var)); \
4826 } \
4827 else { \
4828 nohook; \
4829 var = func; \
4830 }
4831
4832static VALUE
4833vm_call_optimized(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling,
4834 const struct rb_callinfo *ci, const struct rb_callcache *cc)
4835{
4836 switch (vm_cc_cme(cc)->def->body.optimized.type) {
4837 case OPTIMIZED_METHOD_TYPE_SEND:
4838 CC_SET_FASTPATH(cc, vm_call_opt_send, TRUE);
4839 return vm_call_opt_send(ec, cfp, calling);
4840 case OPTIMIZED_METHOD_TYPE_CALL:
4841 CC_SET_FASTPATH(cc, vm_call_opt_call, TRUE);
4842 return vm_call_opt_call(ec, cfp, calling);
4843 case OPTIMIZED_METHOD_TYPE_BLOCK_CALL:
4844 CC_SET_FASTPATH(cc, vm_call_opt_block_call, TRUE);
4845 return vm_call_opt_block_call(ec, cfp, calling);
4846 case OPTIMIZED_METHOD_TYPE_STRUCT_AREF: {
4847 CALLER_SETUP_ARG(cfp, calling, ci, 0);
4848 rb_check_arity(calling->argc, 0, 0);
4849
4850 VALUE v;
4851 VM_CALL_METHOD_ATTR(v,
4852 vm_call_opt_struct_aref(ec, cfp, calling),
4853 set_vm_cc_ivar(cc); \
4854 CC_SET_FASTPATH(cc, vm_call_opt_struct_aref, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4855 return v;
4856 }
4857 case OPTIMIZED_METHOD_TYPE_STRUCT_ASET: {
4858 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4859 rb_check_arity(calling->argc, 1, 1);
4860
4861 VALUE v;
4862 VM_CALL_METHOD_ATTR(v,
4863 vm_call_opt_struct_aset(ec, cfp, calling),
4864 set_vm_cc_ivar(cc); \
4865 CC_SET_FASTPATH(cc, vm_call_opt_struct_aset, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4866 return v;
4867 }
4868 default:
4869 rb_bug("vm_call_method: unsupported optimized method type (%d)", vm_cc_cme(cc)->def->body.optimized.type);
4870 }
4871}
4872
4873static VALUE
4874vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4875{
4876 const struct rb_callinfo *ci = calling->cd->ci;
4877 const struct rb_callcache *cc = calling->cc;
4878 const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
4879 VALUE v;
4880
4881 VM_ASSERT(! METHOD_ENTRY_INVALIDATED(cme));
4882
4883 switch (cme->def->type) {
4884 case VM_METHOD_TYPE_ISEQ:
4885 if (ISEQ_BODY(def_iseq_ptr(cme->def))->param.flags.forwardable) {
4886 CC_SET_FASTPATH(cc, vm_call_iseq_fwd_setup, TRUE);
4887 return vm_call_iseq_fwd_setup(ec, cfp, calling);
4888 }
4889 else {
4890 CC_SET_FASTPATH(cc, vm_call_iseq_setup, TRUE);
4891 return vm_call_iseq_setup(ec, cfp, calling);
4892 }
4893
4894 case VM_METHOD_TYPE_NOTIMPLEMENTED:
4895 case VM_METHOD_TYPE_CFUNC:
4896 CC_SET_FASTPATH(cc, vm_call_cfunc, TRUE);
4897 return vm_call_cfunc(ec, cfp, calling);
4898
4899 case VM_METHOD_TYPE_ATTRSET:
4900 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4901
4902 rb_check_arity(calling->argc, 1, 1);
4903
4904 const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG | VM_CALL_FORWARDING);
4905
4906 if (vm_cc_markable(cc)) {
4907 vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
4908 VM_CALL_METHOD_ATTR(v,
4909 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4910 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
4911 }
4912 else {
4913 cc = &((struct rb_callcache) {
4914 .flags = T_IMEMO |
4915 (imemo_callcache << FL_USHIFT) |
4916 VM_CALLCACHE_UNMARKABLE |
4917 VM_CALLCACHE_ON_STACK,
4918 .klass = cc->klass,
4919 .cme_ = cc->cme_,
4920 .call_ = cc->call_,
4921 .aux_ = {
4922 .attr = {
4923 .value = IVAR_CACHE_INIT,
4924 }
4925 },
4926 });
4927
4928 VM_CALL_METHOD_ATTR(v,
4929 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4930 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
4931 }
4932 return v;
4933
4934 case VM_METHOD_TYPE_IVAR:
4935 CALLER_SETUP_ARG(cfp, calling, ci, 0);
4936 rb_check_arity(calling->argc, 0, 0);
4937 vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
4938 const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING);
4939 VM_CALL_METHOD_ATTR(v,
4940 vm_call_ivar(ec, cfp, calling),
4941 CC_SET_FASTPATH(cc, vm_call_ivar, !(vm_ci_flag(ci) & ivar_mask)));
4942 return v;
4943
4944 case VM_METHOD_TYPE_MISSING:
4945 vm_cc_method_missing_reason_set(cc, 0);
4946 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
4947 return vm_call_method_missing(ec, cfp, calling);
4948
4949 case VM_METHOD_TYPE_BMETHOD:
4950 CC_SET_FASTPATH(cc, vm_call_bmethod, TRUE);
4951 return vm_call_bmethod(ec, cfp, calling);
4952
4953 case VM_METHOD_TYPE_ALIAS:
4954 CC_SET_FASTPATH(cc, vm_call_alias, TRUE);
4955 return vm_call_alias(ec, cfp, calling);
4956
4957 case VM_METHOD_TYPE_OPTIMIZED:
4958 return vm_call_optimized(ec, cfp, calling, ci, cc);
4959
4960 case VM_METHOD_TYPE_UNDEF:
4961 break;
4962
4963 case VM_METHOD_TYPE_ZSUPER:
4964 return vm_call_zsuper(ec, cfp, calling, RCLASS_ORIGIN(vm_cc_cme(cc)->defined_class));
4965
4966 case VM_METHOD_TYPE_REFINED:
4967 // CC_SET_FASTPATH(cc, vm_call_refined, TRUE);
4968 // should not set FASTPATH since vm_call_refined assumes cc->call is vm_call_super_method on invokesuper.
4969 return vm_call_refined(ec, cfp, calling);
4970 }
4971
4972 rb_bug("vm_call_method: unsupported method type (%d)", vm_cc_cme(cc)->def->type);
4973}
4974
4975NORETURN(static void vm_raise_method_missing(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE obj, int call_status));
4976
4977static VALUE
4978vm_call_method_nome(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
4979{
4980 /* method missing */
4981 const struct rb_callinfo *ci = calling->cd->ci;
4982 const int stat = ci_missing_reason(ci);
4983
4984 if (vm_ci_mid(ci) == idMethodMissing) {
4985 if (UNLIKELY(calling->heap_argv)) {
4986 vm_raise_method_missing(ec, RARRAY_LENINT(calling->heap_argv), RARRAY_CONST_PTR(calling->heap_argv), calling->recv, stat);
4987 }
4988 else {
4989 rb_control_frame_t *reg_cfp = cfp;
4990 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
4991 vm_raise_method_missing(ec, calling->argc, argv, calling->recv, stat);
4992 }
4993 }
4994 else {
4995 return vm_call_method_missing_body(ec, cfp, calling, ci, stat);
4996 }
4997}
4998
4999/* Protected method calls and super invocations need to check that the receiver
5000 * (self for super) inherits the module on which the method is defined.
5001 * In the case of refinements, it should consider the original class not the
5002 * refinement.
5003 */
5004static VALUE
5005vm_defined_class_for_protected_call(const rb_callable_method_entry_t *me)
5006{
5007 VALUE defined_class = me->defined_class;
5008 VALUE refined_class = RCLASS_REFINED_CLASS(defined_class);
5009 return NIL_P(refined_class) ? defined_class : refined_class;
5010}
5011
5012static inline VALUE
5013vm_call_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling)
5014{
5015 const struct rb_callinfo *ci = calling->cd->ci;
5016 const struct rb_callcache *cc = calling->cc;
5017
5018 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
5019
5020 if (vm_cc_cme(cc) != NULL) {
5021 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
5022 case METHOD_VISI_PUBLIC: /* likely */
5023 return vm_call_method_each_type(ec, cfp, calling);
5024
5025 case METHOD_VISI_PRIVATE:
5026 if (!(vm_ci_flag(ci) & VM_CALL_FCALL)) {
5027 enum method_missing_reason stat = MISSING_PRIVATE;
5028 if (vm_ci_flag(ci) & VM_CALL_VCALL) stat |= MISSING_VCALL;
5029
5030 vm_cc_method_missing_reason_set(cc, stat);
5031 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
5032 return vm_call_method_missing(ec, cfp, calling);
5033 }
5034 return vm_call_method_each_type(ec, cfp, calling);
5035
5036 case METHOD_VISI_PROTECTED:
5037 if (!(vm_ci_flag(ci) & (VM_CALL_OPT_SEND | VM_CALL_FCALL))) {
5038 VALUE defined_class = vm_defined_class_for_protected_call(vm_cc_cme(cc));
5039 if (!rb_obj_is_kind_of(cfp->self, defined_class)) {
5040 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
5041 return vm_call_method_missing(ec, cfp, calling);
5042 }
5043 else {
5044 /* caching method info to dummy cc */
5045 VM_ASSERT(vm_cc_cme(cc) != NULL);
5046 struct rb_callcache cc_on_stack = *cc;
5047 FL_SET_RAW((VALUE)&cc_on_stack, VM_CALLCACHE_UNMARKABLE);
5048 calling->cc = &cc_on_stack;
5049 return vm_call_method_each_type(ec, cfp, calling);
5050 }
5051 }
5052 return vm_call_method_each_type(ec, cfp, calling);
5053
5054 default:
5055 rb_bug("unreachable");
5056 }
5057 }
5058 else {
5059 return vm_call_method_nome(ec, cfp, calling);
5060 }
5061}
5062
5063static VALUE
5064vm_call_general(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
5065{
5066 RB_DEBUG_COUNTER_INC(ccf_general);
5067 return vm_call_method(ec, reg_cfp, calling);
5068}
5069
5070void
5071rb_vm_cc_general(const struct rb_callcache *cc)
5072{
5073 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
5074 VM_ASSERT(cc != vm_cc_empty());
5075
5076 *(vm_call_handler *)&cc->call_ = vm_call_general;
5077}
5078
5079static VALUE
5080vm_call_super_method(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling)
5081{
5082 RB_DEBUG_COUNTER_INC(ccf_super_method);
5083
5084 // This line is introduced to make different from `vm_call_general` because some compilers (VC we found)
5085 // can merge the function and the address of the function becomes same.
5086 // The address of `vm_call_super_method` is used in `search_refined_method`, so it should be different.
5087 if (ec == NULL) rb_bug("unreachable");
5088
5089 /* this check is required to distinguish with other functions. */
5090 VM_ASSERT(vm_cc_call(calling->cc) == vm_call_super_method);
5091 return vm_call_method(ec, reg_cfp, calling);
5092}
5093
5094/* super */
5095
5096static inline VALUE
5097vm_search_normal_superclass(VALUE klass)
5098{
5099 if (RICLASS_FOR_REFINEMENT_P(klass)) {
5100 klass = RBASIC(klass)->klass;
5101 }
5102 klass = RCLASS_ORIGIN(klass);
5103 return RCLASS_SUPER(klass);
5104}
5105
5106NORETURN(static void vm_super_outside(void));
5107
5108static void
5109vm_super_outside(void)
5110{
5111 rb_raise(rb_eNoMethodError, "super called outside of method");
5112}
5113
5114static const struct rb_callcache *
5115empty_cc_for_super(void)
5116{
5117 return &vm_empty_cc_for_super;
5118}
5119
5120static const struct rb_callcache *
5121vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *cd, VALUE recv)
5122{
5123 VALUE current_defined_class;
5124 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
5125 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
5126
5127 if (!me) {
5128 vm_super_outside();
5129 }
5130
5131 current_defined_class = vm_defined_class_for_protected_call(me);
5132
5133 if (BUILTIN_TYPE(current_defined_class) != T_MODULE &&
5134 iseq != method_entry_iseqptr(me) &&
5135 !rb_obj_is_kind_of(recv, current_defined_class)) {
5136 VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
5137 RCLASS_INCLUDER(current_defined_class) : current_defined_class;
5138
5139 if (m) { /* not bound UnboundMethod */
5140 rb_raise(rb_eTypeError,
5141 "self has wrong type to call super in this context: "
5142 "%"PRIsVALUE" (expected %"PRIsVALUE")",
5143 rb_obj_class(recv), m);
5144 }
5145 }
5146
5147 if (me->def->type == VM_METHOD_TYPE_BMETHOD && (vm_ci_flag(cd->ci) & VM_CALL_ZSUPER)) {
5148 rb_raise(rb_eRuntimeError,
5149 "implicit argument passing of super from method defined"
5150 " by define_method() is not supported."
5151 " Specify all arguments explicitly.");
5152 }
5153
5154 ID mid = me->def->original_id;
5155
5156 if (!vm_ci_markable(cd->ci)) {
5157 VM_FORCE_WRITE((const VALUE *)&cd->ci->mid, (VALUE)mid);
5158 }
5159 else {
5160 // update iseq. really? (TODO)
5161 cd->ci = vm_ci_new_runtime(mid,
5162 vm_ci_flag(cd->ci),
5163 vm_ci_argc(cd->ci),
5164 vm_ci_kwarg(cd->ci));
5165
5166 RB_OBJ_WRITTEN(iseq, Qundef, cd->ci);
5167 }
5168
5169 const struct rb_callcache *cc;
5170
5171 VALUE klass = vm_search_normal_superclass(me->defined_class);
5172
5173 if (!klass) {
5174 /* bound instance method of module */
5175 cc = vm_cc_new(Qundef, NULL, vm_call_method_missing, cc_type_super);
5176 RB_OBJ_WRITE(iseq, &cd->cc, cc);
5177 }
5178 else if (klass == rb_cBasicObject &&
5179 RB_TYPE_P(me->defined_class, T_ICLASS) &&
5180 RCLASS_INCLUDER(me->defined_class) == 0) {
5181 rb_raise(rb_eNoMethodError,
5182 "super in a method in a module that has been refined and that is called via super"
5183 " from a refinement method is not supported.");
5184 }
5185 else {
5186 cc = vm_search_method_fastpath(reg_cfp, cd, klass);
5187 const rb_callable_method_entry_t *cached_cme = vm_cc_cme(cc);
5188
5189 // define_method can cache for different method id
5190 if (cached_cme == NULL) {
5191 // empty_cc_for_super is not markable object
5192 cd->cc = empty_cc_for_super();
5193 }
5194 else if (cached_cme->called_id != mid) {
5195 const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
5196 if (cme) {
5197 cc = vm_cc_new(klass, cme, vm_call_super_method, cc_type_super);
5198 RB_OBJ_WRITE(iseq, &cd->cc, cc);
5199 }
5200 else {
5201 cd->cc = cc = empty_cc_for_super();
5202 }
5203 }
5204 else {
5205 switch (cached_cme->def->type) {
5206 // vm_call_refined (search_refined_method) assumes cc->call is vm_call_super_method on invokesuper
5207 case VM_METHOD_TYPE_REFINED:
5208 // cc->klass is superclass of receiver class. Checking cc->klass is not enough to invalidate IVC for the receiver class.
5209 case VM_METHOD_TYPE_ATTRSET:
5210 case VM_METHOD_TYPE_IVAR:
5211 vm_cc_call_set(cc, vm_call_super_method); // invalidate fastpath
5212 break;
5213 default:
5214 break; // use fastpath
5215 }
5216 }
5217 }
5218
5219 VM_ASSERT((vm_cc_cme(cc), true));
5220
5221 return cc;
5222}
5223
5224/* yield */
5225
5226static inline int
5227block_proc_is_lambda(const VALUE procval)
5228{
5229 rb_proc_t *proc;
5230
5231 if (procval) {
5232 GetProcPtr(procval, proc);
5233 return proc->header.is_lambda;
5234 }
5235 else {
5236 return 0;
5237 }
5238}
5239
5240static VALUE
5241vm_yield_with_cfunc(rb_execution_context_t *ec,
5242 const struct rb_captured_block *captured,
5243 VALUE self, int argc, const VALUE *argv, int kw_splat, VALUE block_handler,
5245{
5246 int is_lambda = FALSE; /* TODO */
5247 VALUE val, arg, blockarg;
5248 int frame_flag;
5249 const struct vm_ifunc *ifunc = captured->code.ifunc;
5250
5251 if (is_lambda) {
5252 arg = rb_ary_new4(argc, argv);
5253 }
5254 else if (argc == 0) {
5255 arg = Qnil;
5256 }
5257 else {
5258 arg = argv[0];
5259 }
5260
5261 blockarg = rb_vm_bh_to_procval(ec, block_handler);
5262
5263 frame_flag = VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME | (me ? VM_FRAME_FLAG_BMETHOD : 0);
5264 if (kw_splat) {
5265 frame_flag |= VM_FRAME_FLAG_CFRAME_KW;
5266 }
5267
5268 vm_push_frame(ec, (const rb_iseq_t *)captured->code.ifunc,
5269 frame_flag,
5270 self,
5271 VM_GUARDED_PREV_EP(captured->ep),
5272 (VALUE)me,
5273 0, ec->cfp->sp, 0, 0);
5274 val = (*ifunc->func)(arg, (VALUE)ifunc->data, argc, argv, blockarg);
5275 rb_vm_pop_frame(ec);
5276
5277 return val;
5278}
5279
5280VALUE
5281rb_vm_yield_with_cfunc(rb_execution_context_t *ec, const struct rb_captured_block *captured, int argc, const VALUE *argv)
5282{
5283 return vm_yield_with_cfunc(ec, captured, captured->self, argc, argv, 0, VM_BLOCK_HANDLER_NONE, NULL);
5284}
5285
5286static VALUE
5287vm_yield_with_symbol(rb_execution_context_t *ec, VALUE symbol, int argc, const VALUE *argv, int kw_splat, VALUE block_handler)
5288{
5289 VALUE passed_proc = rb_vm_bh_to_procval(ec, block_handler);
5290
5291 if (!rb_box_available()) {
5292 return rb_sym_proc_call(SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5293 }
5294
5295 const rb_control_frame_t *reg_cfp = ec->cfp;
5296 const rb_control_frame_t *ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, reg_cfp);
5297 const rb_box_t *box = NULL;
5298
5299 /*
5300 * Traverse the frames until a user box (Main or Optional Box) is found.
5301 * Frames for built-in methods like <internal:xxx> run in the Root or Master Box,
5302 */
5303 while (ruby_cfp) {
5304 box = current_box_on_cfp(ec, ruby_cfp);
5305 if (BOX_USER_P(box)) {
5306 break;
5307 }
5308 ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ruby_cfp));
5309 }
5310
5311 // Fallback to the normal call if no user box is found
5312 if (!ruby_cfp || !box) {
5313 return rb_sym_proc_call(SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5314 }
5315
5316 /*
5317 * Push a dummy block frame whose outer env is `ruby_cfp` so that the
5318 * method resolves in the caller's box (via the ep chain) and the
5319 * backtrace reads like a usual block invocation at the caller's site.
5320 */
5321 const rb_iseq_t *caller_iseq = CFP_ISEQ(ruby_cfp);
5322 VALUE name = rb_sprintf("block in %"PRIsVALUE, rb_iseq_label(caller_iseq));
5323 const rb_iseq_t *iseq = rb_iseq_new_with_opt(Qnil, name,
5324 rb_iseq_path(caller_iseq), rb_iseq_realpath(caller_iseq),
5325 rb_vm_get_sourceline(ruby_cfp), caller_iseq, 0,
5326 ISEQ_TYPE_BLOCK, NULL, Qnil);
5327 volatile VALUE val = Qnil;
5328 enum ruby_tag_type state;
5329
5330 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_FINISH,
5331 ruby_cfp->self, VM_GUARDED_PREV_EP(ruby_cfp->ep),
5332 Qfalse, /* cref or me */
5333 ISEQ_BODY(iseq)->iseq_encoded, reg_cfp->sp,
5334 ISEQ_BODY(iseq)->local_table_size, ISEQ_BODY(iseq)->stack_max);
5335
5336 /*
5337 * The pushed frame is finished (owned by no vm_exec loop), so catch the
5338 * non-local exit here, pop the frame, and let the caller's handlers see
5339 * the exception.
5340 */
5341 EC_PUSH_TAG(ec);
5342 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
5343 val = rb_sym_proc_call(SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5344 }
5345 EC_POP_TAG();
5346
5347 if (state != TAG_NONE) {
5348 rb_vm_rewind_cfp(ec, (rb_control_frame_t *)reg_cfp);
5349 EC_JUMP_TAG(ec, state);
5350 }
5351
5352 rb_vm_pop_frame(ec);
5353
5354 return val;
5355}
5356
5357static inline int
5358vm_callee_setup_block_arg_arg0_splat(rb_control_frame_t *cfp, const rb_iseq_t *iseq, VALUE *argv, VALUE ary)
5359{
5360 int i;
5361 long len = RARRAY_LEN(ary);
5362
5363 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5364
5365 for (i=0; i<len && i<ISEQ_BODY(iseq)->param.lead_num; i++) {
5366 argv[i] = RARRAY_AREF(ary, i);
5367 }
5368
5369 return i;
5370}
5371
5372static inline VALUE
5373vm_callee_setup_block_arg_arg0_check(VALUE *argv)
5374{
5375 VALUE ary, arg0 = argv[0];
5376 ary = rb_check_array_type(arg0);
5377#if 0
5378 argv[0] = arg0;
5379#else
5380 VM_ASSERT(argv[0] == arg0);
5381#endif
5382 return ary;
5383}
5384
5385static int
5386vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *calling, const struct rb_callinfo *ci, const rb_iseq_t *iseq, VALUE *argv, const enum arg_setup_type arg_setup_type)
5387{
5388 if (rb_simple_iseq_p(iseq)) {
5389 rb_control_frame_t *cfp = ec->cfp;
5390 VALUE arg0;
5391
5392 CALLER_SETUP_ARG(cfp, calling, ci, ISEQ_BODY(iseq)->param.lead_num);
5393
5394 if (arg_setup_type == arg_setup_block &&
5395 calling->argc == 1 &&
5396 ISEQ_BODY(iseq)->param.flags.has_lead &&
5397 !ISEQ_BODY(iseq)->param.flags.ambiguous_param0 &&
5398 !NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv))) {
5399 calling->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0);
5400 }
5401
5402 if (calling->argc != ISEQ_BODY(iseq)->param.lead_num) {
5403 if (arg_setup_type == arg_setup_block) {
5404 if (calling->argc < ISEQ_BODY(iseq)->param.lead_num) {
5405 int i;
5406 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5407 for (i=calling->argc; i<ISEQ_BODY(iseq)->param.lead_num; i++) argv[i] = Qnil;
5408 calling->argc = ISEQ_BODY(iseq)->param.lead_num; /* fill rest parameters */
5409 }
5410 else if (calling->argc > ISEQ_BODY(iseq)->param.lead_num) {
5411 calling->argc = ISEQ_BODY(iseq)->param.lead_num; /* simply truncate arguments */
5412 }
5413 }
5414 else {
5415 argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
5416 }
5417 }
5418
5419 return 0;
5420 }
5421 else {
5422 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_type);
5423 }
5424}
5425
5426static int
5427vm_yield_setup_args(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int argc, VALUE *argv, int flags, VALUE block_handler, enum arg_setup_type arg_setup_type)
5428{
5429 struct rb_calling_info calling_entry, *calling;
5430
5431 calling = &calling_entry;
5432 calling->argc = argc;
5433 calling->block_handler = block_handler;
5434 calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
5435 calling->recv = Qundef;
5436 calling->heap_argv = 0;
5437 calling->cc = NULL;
5438 struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
5439
5440 return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);
5441}
5442
5443/* ruby iseq -> ruby block */
5444
5445static VALUE
5446vm_invoke_iseq_block_with_cref(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5447 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5448 bool is_lambda, VALUE block_handler, const rb_cref_t *cref)
5449{
5450 const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(block_handler);
5451 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
5452 const int arg_size = ISEQ_BODY(iseq)->param.size;
5453 VALUE * const rsp = GET_SP() - calling->argc;
5454 VALUE * const argv = rsp;
5455 int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block);
5456 int frame_flag = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
5457
5458 SET_SP(rsp);
5459
5460 /* cref is normally 0; Proc#refined supplies a refinement cref */
5461 vm_push_frame(ec, iseq,
5462 frame_flag,
5463 captured->self,
5464 VM_GUARDED_PREV_EP(captured->ep), (VALUE)cref,
5465 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
5466 rsp + arg_size,
5467 ISEQ_BODY(iseq)->local_table_size - arg_size, ISEQ_BODY(iseq)->stack_max);
5468
5469 return Qundef;
5470}
5471
5472static VALUE
5473vm_invoke_iseq_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5474 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5475 bool is_lambda, VALUE block_handler)
5476{
5477 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, NULL);
5478}
5479
5480static VALUE
5481vm_invoke_symbol_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5482 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5483 MAYBE_UNUSED(bool is_lambda), VALUE block_handler)
5484{
5485 VALUE symbol = VM_BH_TO_SYMBOL(block_handler);
5486 int flags = vm_ci_flag(ci);
5487
5488 if (UNLIKELY(!(flags & VM_CALL_ARGS_SIMPLE) &&
5489 ((calling->argc == 0) ||
5490 (calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
5491 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
5492 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc))))) {
5493 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
5494 flags = 0;
5495 if (UNLIKELY(calling->heap_argv)) {
5496#if VM_ARGC_STACK_MAX < 0
5497 if (RARRAY_LEN(calling->heap_argv) < 1) {
5498 rb_raise(rb_eArgError, "no receiver given");
5499 }
5500#endif
5501 calling->recv = rb_ary_shift(calling->heap_argv);
5502 // Modify stack to avoid cfp consistency error
5503 reg_cfp->sp++;
5504 reg_cfp->sp[-1] = reg_cfp->sp[-2];
5505 reg_cfp->sp[-2] = calling->recv;
5506 flags |= VM_CALL_ARGS_SPLAT;
5507 }
5508 else {
5509 if (calling->argc < 1) {
5510 rb_raise(rb_eArgError, "no receiver given");
5511 }
5512 calling->recv = TOPN(--calling->argc);
5513 }
5514 if (calling->kw_splat) {
5515 flags |= VM_CALL_KW_SPLAT;
5516 }
5517 }
5518 else {
5519 if (calling->argc < 1) {
5520 rb_raise(rb_eArgError, "no receiver given");
5521 }
5522 calling->recv = TOPN(--calling->argc);
5523 }
5524
5525 return vm_call_symbol(ec, reg_cfp, calling, ci, symbol, flags);
5526}
5527
5528static VALUE
5529vm_invoke_ifunc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5530 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5531 MAYBE_UNUSED(bool is_lambda), VALUE block_handler)
5532{
5533 VALUE val;
5534 int argc;
5535 const struct rb_captured_block *captured = VM_BH_TO_IFUNC_BLOCK(block_handler);
5536 CALLER_SETUP_ARG(ec->cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
5537 argc = calling->argc;
5538 val = vm_yield_with_cfunc(ec, captured, captured->self, CALLING_ARGC(calling), calling->heap_argv ? RARRAY_CONST_PTR(calling->heap_argv) : STACK_ADDR_FROM_TOP(argc), calling->kw_splat, calling->block_handler, NULL);
5539 POPN(argc); /* TODO: should put before C/yield? */
5540 return val;
5541}
5542
5543static inline VALUE
5544vm_block_to_block_handler(const struct rb_block *block)
5545{
5546 switch (vm_block_type(block)) {
5547 case block_type_iseq:
5548 return VM_BH_FROM_ISEQ_BLOCK(&block->as.captured);
5549 case block_type_ifunc:
5550 return VM_BH_FROM_IFUNC_BLOCK(&block->as.captured);
5551 case block_type_symbol:
5552 return VM_BH_FROM_SYMBOL(block->as.symbol);
5553 case block_type_proc:
5554 return VM_BH_FROM_PROC(block->as.proc);
5555 }
5556 VM_UNREACHABLE(vm_yield_with_proc);
5557 return Qundef;
5558}
5559
5560static VALUE
5561vm_proc_to_block_handler(VALUE procval)
5562{
5563 return vm_block_to_block_handler(vm_proc_block(procval));
5564}
5565
5566NOINLINE(static VALUE
5567vm_invoke_proc_block_with_cref(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5568 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5569 bool is_lambda, VALUE block_handler, VALUE refined_procval));
5570static VALUE
5571vm_invoke_proc_block_with_cref(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5572 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5573 bool is_lambda, VALUE block_handler, VALUE refined_procval)
5574{
5575 const rb_cref_t *cref = rb_proc_refinements_cref_for_call(refined_procval);
5576 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, cref);
5577}
5578
5579static VALUE
5580vm_invoke_proc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5581 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5582 bool is_lambda, VALUE block_handler)
5583{
5584 VALUE refined_procval = 0;
5585
5586 while (vm_block_handler_type(block_handler) == block_handler_type_proc) {
5587 VALUE procval = VM_BH_TO_PROC(block_handler);
5588 rb_proc_t *po;
5589 GetProcPtr(procval, po);
5590 if (po->header.is_refined) refined_procval = procval;
5591 is_lambda = po->header.is_lambda;
5592 block_handler = vm_block_to_block_handler(&po->block);
5593 }
5594
5595 if (UNLIKELY(refined_procval) && vm_block_handler_type(block_handler) == block_handler_type_iseq) {
5596 /* should not be inlined so that vm_invoke_proc_block stays leaf/frameless. */
5597 return vm_invoke_proc_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler,
5598 refined_procval);
5599 }
5600
5601 return vm_invoke_block(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5602}
5603
5604static inline VALUE
5605vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5606 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5607 bool is_lambda, VALUE block_handler)
5608{
5609 VALUE (*func)(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
5610 struct rb_calling_info *calling, const struct rb_callinfo *ci,
5611 bool is_lambda, VALUE block_handler);
5612
5613 switch (vm_block_handler_type(block_handler)) {
5614 case block_handler_type_iseq: func = vm_invoke_iseq_block; break;
5615 case block_handler_type_ifunc: func = vm_invoke_ifunc_block; break;
5616 case block_handler_type_proc: func = vm_invoke_proc_block; break;
5617 case block_handler_type_symbol: func = vm_invoke_symbol_block; break;
5618 default: rb_bug("vm_invoke_block: unreachable");
5619 }
5620
5621 return func(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5622}
5623
5624static VALUE
5625vm_make_proc_with_iseq(const rb_iseq_t *blockiseq)
5626{
5627 const rb_execution_context_t *ec = GET_EC();
5628 const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
5629 struct rb_captured_block *captured;
5630
5631 if (cfp == 0) {
5632 rb_bug("vm_make_proc_with_iseq: unreachable");
5633 }
5634
5635 captured = VM_CFP_TO_CAPTURED_BLOCK(cfp);
5636 captured->code.iseq = blockiseq;
5637
5638 return rb_vm_make_proc(ec, captured, rb_cProc);
5639}
5640
5641static VALUE
5642vm_once_exec(VALUE iseq)
5643{
5644 VALUE proc = vm_make_proc_with_iseq((rb_iseq_t *)iseq);
5645 return rb_proc_call_with_block(proc, 0, 0, Qnil);
5646}
5647
5648#define RUNNING_THREAD_ONCE_DONE ((rb_thread_t *)0x1)
5649
5651 rb_vm_t *vm;
5652 union iseq_inline_storage_entry *is;
5653};
5654
5655static void
5656vm_once_broadcast(rb_vm_t *vm)
5657{
5658 rb_native_mutex_lock(&vm->once_lock);
5659 rb_native_cond_broadcast(&vm->once_cond);
5660 rb_native_mutex_unlock(&vm->once_lock);
5661}
5662
5663static void *
5664vm_once_wait_no_gvl(void *ptr)
5665{
5666 struct vm_once_wait_arg *arg = (struct vm_once_wait_arg *)ptr;
5667 rb_vm_t *vm = arg->vm;
5668 rb_thread_t *running_th;
5669
5670 rb_native_mutex_lock(&vm->once_lock);
5671 running_th = rbimpl_atomic_ptr_load((void **)&arg->is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
5672 if (running_th != NULL && running_th != RUNNING_THREAD_ONCE_DONE) {
5673 rb_native_cond_wait(&vm->once_cond, &vm->once_lock);
5674 }
5675 rb_native_mutex_unlock(&vm->once_lock);
5676 return NULL;
5677}
5678
5679static void
5680vm_once_wait_ubf(void *ptr)
5681{
5682 vm_once_broadcast((rb_vm_t *)ptr);
5683}
5684
5685static VALUE
5686vm_once_clear(VALUE data)
5687{
5688 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)data;
5689 rbimpl_atomic_ptr_store((volatile void **)&is->once.running_thread, NULL, RBIMPL_ATOMIC_RELEASE);
5690 vm_once_broadcast(GET_VM());
5691 return Qnil;
5692}
5693
5694/* defined insn */
5695
5696static bool
5697check_respond_to_missing(VALUE obj, VALUE v)
5698{
5699 VALUE args[2];
5700 VALUE r;
5701
5702 args[0] = obj; args[1] = Qfalse;
5703 r = rb_check_funcall(v, idRespond_to_missing, 2, args);
5704 if (!UNDEF_P(r) && RTEST(r)) {
5705 return true;
5706 }
5707 else {
5708 return false;
5709 }
5710}
5711
5712static bool
5713vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE obj, VALUE v)
5714{
5715 VALUE klass;
5716 enum defined_type type = (enum defined_type)op_type;
5717
5718 switch (type) {
5719 case DEFINED_IVAR:
5720 return rb_ivar_defined(GET_SELF(), SYM2ID(obj));
5721 break;
5722 case DEFINED_GVAR:
5723 return rb_gvar_defined(SYM2ID(obj));
5724 break;
5725 case DEFINED_CVAR: {
5726 const rb_cref_t *cref = vm_get_cref(GET_EP());
5727 klass = vm_get_cvar_base(cref, GET_CFP(), 0);
5728 return rb_cvar_defined(klass, SYM2ID(obj));
5729 break;
5730 }
5731 case DEFINED_CONST:
5732 case DEFINED_CONST_FROM: {
5733 bool allow_nil = type == DEFINED_CONST;
5734 klass = v;
5735 return vm_get_ev_const(ec, klass, SYM2ID(obj), allow_nil, true);
5736 break;
5737 }
5738 case DEFINED_FUNC:
5739 klass = CLASS_OF(v);
5740 return rb_ec_obj_respond_to(ec, v, SYM2ID(obj), TRUE);
5741 break;
5742 case DEFINED_METHOD:{
5743 VALUE klass = CLASS_OF(v);
5744 const rb_callable_method_entry_t *cme = rb_callable_method_entry_with_refinements(klass, SYM2ID(obj), NULL);
5745
5746 if (cme) {
5747 switch (METHOD_ENTRY_VISI(cme)) {
5748 case METHOD_VISI_PRIVATE:
5749 break;
5750 case METHOD_VISI_PROTECTED:
5751 if (!rb_obj_is_kind_of(GET_SELF(), vm_defined_class_for_protected_call(cme))) {
5752 break;
5753 }
5754 case METHOD_VISI_PUBLIC:
5755 return true;
5756 break;
5757 default:
5758 rb_bug("vm_defined: unreachable: %u", (unsigned int)METHOD_ENTRY_VISI(cme));
5759 }
5760 }
5761 else {
5762 return check_respond_to_missing(obj, v);
5763 }
5764 break;
5765 }
5766 case DEFINED_YIELD:
5767 if (GET_BLOCK_HANDLER() != VM_BLOCK_HANDLER_NONE) {
5768 return true;
5769 }
5770 break;
5771 case DEFINED_ZSUPER:
5772 {
5773 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(GET_CFP());
5774
5775 if (me) {
5776 VALUE klass = vm_search_normal_superclass(me->defined_class);
5777 if (!klass) return false;
5778
5779 ID id = me->def->original_id;
5780
5781 return rb_method_boundp(klass, id, 0);
5782 }
5783 }
5784 break;
5785 case DEFINED_REF:
5786 return RTEST(vm_backref_defined(ec, GET_LEP(), FIX2INT(obj)));
5787 default:
5788 rb_bug("unimplemented defined? type (VM)");
5789 break;
5790 }
5791
5792 return false;
5793}
5794
5795bool
5796rb_vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE obj, VALUE v)
5797{
5798 return vm_defined(ec, reg_cfp, op_type, obj, v);
5799}
5800
5801static const VALUE *
5802vm_get_ep(const VALUE *const reg_ep, rb_num_t lv)
5803{
5804 rb_num_t i;
5805 const VALUE *ep = reg_ep;
5806 for (i = 0; i < lv; i++) {
5807 ep = GET_PREV_EP(ep);
5808 }
5809 return ep;
5810}
5811
5812static VALUE
5813vm_get_special_object(const VALUE *const reg_ep,
5814 enum vm_special_object_type type)
5815{
5816 switch (type) {
5817 case VM_SPECIAL_OBJECT_VMCORE:
5818 return rb_mRubyVMFrozenCore;
5819 case VM_SPECIAL_OBJECT_CBASE:
5820 return vm_get_cbase(reg_ep);
5821 case VM_SPECIAL_OBJECT_CONST_BASE:
5822 return vm_get_const_base(reg_ep);
5823 default:
5824 rb_bug("putspecialobject insn: unknown value_type %d", type);
5825 }
5826}
5827
5828// ZJIT implementation is using the C function
5829// and needs to call a non-static function
5830VALUE
5831rb_vm_get_special_object(const VALUE *reg_ep, enum vm_special_object_type type)
5832{
5833 return vm_get_special_object(reg_ep, type);
5834}
5835
5836static VALUE
5837vm_concat_array(VALUE ary1, VALUE ary2st)
5838{
5839 const VALUE ary2 = ary2st;
5840 VALUE tmp1 = rb_check_to_array(ary1);
5841 VALUE tmp2 = rb_check_to_array(ary2);
5842
5843 if (NIL_P(tmp1)) {
5844 tmp1 = rb_ary_new3(1, ary1);
5845 }
5846 if (tmp1 == ary1) {
5847 tmp1 = rb_ary_dup(ary1);
5848 }
5849
5850 if (NIL_P(tmp2)) {
5851 return rb_ary_push(tmp1, ary2);
5852 }
5853 else {
5854 return rb_ary_concat(tmp1, tmp2);
5855 }
5856}
5857
5858static VALUE
5859vm_concat_to_array(VALUE ary1, VALUE ary2st)
5860{
5861 /* ary1 must be a newly created array */
5862 const VALUE ary2 = ary2st;
5863
5864 if (NIL_P(ary2)) return ary1;
5865
5866 VALUE tmp2 = rb_check_to_array(ary2);
5867
5868 if (NIL_P(tmp2)) {
5869 return rb_ary_push(ary1, ary2);
5870 }
5871 else {
5872 return rb_ary_concat(ary1, tmp2);
5873 }
5874}
5875
5876// YJIT implementation is using the C function
5877// and needs to call a non-static function
5878VALUE
5879rb_vm_concat_array(VALUE ary1, VALUE ary2st)
5880{
5881 return vm_concat_array(ary1, ary2st);
5882}
5883
5884VALUE
5885rb_vm_concat_to_array(VALUE ary1, VALUE ary2st)
5886{
5887 return vm_concat_to_array(ary1, ary2st);
5888}
5889
5890static VALUE
5891vm_splat_array(VALUE flag, VALUE ary)
5892{
5893 if (NIL_P(ary)) {
5894 return RTEST(flag) ? rb_ary_new() : rb_cArray_empty_frozen;
5895 }
5896 VALUE tmp = rb_check_to_array(ary);
5897 if (NIL_P(tmp)) {
5898 return rb_ary_new3(1, ary);
5899 }
5900 else if (RTEST(flag)) {
5901 return rb_ary_dup(tmp);
5902 }
5903 else {
5904 return tmp;
5905 }
5906}
5907
5908// YJIT implementation is using the C function
5909// and needs to call a non-static function
5910VALUE
5911rb_vm_splat_array(VALUE flag, VALUE ary)
5912{
5913 return vm_splat_array(flag, ary);
5914}
5915
5916static VALUE
5917vm_check_match(rb_execution_context_t *ec, VALUE target, VALUE pattern, rb_num_t flag)
5918{
5919 enum vm_check_match_type type = ((int)flag) & VM_CHECKMATCH_TYPE_MASK;
5920
5921 if (flag & VM_CHECKMATCH_ARRAY) {
5922 long i;
5923 const long n = RARRAY_LEN(pattern);
5924
5925 for (i = 0; i < n; i++) {
5926 VALUE v = RARRAY_AREF(pattern, i);
5927 VALUE c = check_match(ec, v, target, type);
5928
5929 if (RTEST(c)) {
5930 return c;
5931 }
5932 }
5933 return Qfalse;
5934 }
5935 else {
5936 return check_match(ec, pattern, target, type);
5937 }
5938}
5939
5940VALUE
5941rb_vm_check_match(rb_execution_context_t *ec, VALUE target, VALUE pattern, rb_num_t flag)
5942{
5943 return vm_check_match(ec, target, pattern, flag);
5944}
5945
5946static VALUE
5947vm_check_keyword(lindex_t bits, lindex_t idx, const VALUE *ep)
5948{
5949 const VALUE kw_bits = *(ep - bits);
5950
5951 if (FIXNUM_P(kw_bits)) {
5952 unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
5953 if ((idx < VM_KW_SPECIFIED_BITS_MAX) && (b & (0x01 << idx)))
5954 return Qfalse;
5955 }
5956 else {
5957 VM_ASSERT(rb_set_p(kw_bits), "%s", rb_obj_info(kw_bits));
5958 if (rb_set_lookup(kw_bits, INT2FIX(idx))) return Qfalse;
5959 }
5960 return Qtrue;
5961}
5962
5963static void
5964vm_dtrace(rb_event_flag_t flag, rb_execution_context_t *ec)
5965{
5966 if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() ||
5967 RUBY_DTRACE_METHOD_RETURN_ENABLED() ||
5968 RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() ||
5969 RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) {
5970
5971 switch (flag) {
5972 case RUBY_EVENT_CALL:
5973 RUBY_DTRACE_METHOD_ENTRY_HOOK(ec, 0, 0);
5974 return;
5975 case RUBY_EVENT_C_CALL:
5976 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, 0, 0);
5977 return;
5978 case RUBY_EVENT_RETURN:
5979 RUBY_DTRACE_METHOD_RETURN_HOOK(ec, 0, 0);
5980 return;
5982 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, 0, 0);
5983 return;
5984 }
5985 }
5986}
5987
5988static VALUE
5989vm_const_get_under(ID id, rb_num_t flags, VALUE cbase)
5990{
5991 if (!rb_const_defined_at(cbase, id)) {
5992 return 0;
5993 }
5994 else if (VM_DEFINECLASS_SCOPED_P(flags)) {
5995 return rb_public_const_get_at(cbase, id);
5996 }
5997 else {
5998 return rb_const_get_at(cbase, id);
5999 }
6000}
6001
6002static VALUE
6003vm_check_if_class(ID id, rb_num_t flags, VALUE super, VALUE klass)
6004{
6005 if (!RB_TYPE_P(klass, T_CLASS)) {
6006 return 0;
6007 }
6008 else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) {
6009 VALUE tmp = rb_class_real(RCLASS_SUPER(klass));
6010
6011 if (tmp != super) {
6012 rb_raise(rb_eTypeError,
6013 "superclass mismatch for class %"PRIsVALUE"",
6014 rb_id2str(id));
6015 }
6016 else {
6017 return klass;
6018 }
6019 }
6020 else {
6021 return klass;
6022 }
6023}
6024
6025static VALUE
6026vm_check_if_module(ID id, VALUE mod)
6027{
6028 if (!RB_TYPE_P(mod, T_MODULE)) {
6029 return 0;
6030 }
6031 else {
6032 return mod;
6033 }
6034}
6035
6036static VALUE
6037declare_under(ID id, VALUE cbase, VALUE c)
6038{
6039 rb_set_class_path_string(c, cbase, rb_id2str(id));
6040 rb_const_set(cbase, id, c);
6041 return c;
6042}
6043
6044static VALUE
6045vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
6046{
6047 /* new class declaration */
6048 VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject;
6049 VALUE c = declare_under(id, cbase, rb_define_class_id(id, s));
6050 rb_class_inherited(s, c);
6051 return c;
6052}
6053
6054static VALUE
6055vm_declare_module(ID id, VALUE cbase)
6056{
6057 /* new module declaration */
6058 return declare_under(id, cbase, rb_module_new());
6059}
6060
6061NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old));
6062static void
6063unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old)
6064{
6065 VALUE name = rb_id2str(id);
6066 VALUE message = rb_sprintf("%"PRIsVALUE" is not a %s",
6067 name, type);
6068 VALUE location = rb_const_source_location_at(cbase, id);
6069 if (!NIL_P(location)) {
6070 rb_str_catf(message, "\n%"PRIsVALUE":%"PRIsVALUE":"
6071 " previous definition of %"PRIsVALUE" was here",
6072 rb_ary_entry(location, 0), rb_ary_entry(location, 1), name);
6073 }
6075}
6076
6077static VALUE
6078vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
6079{
6080 VALUE klass;
6081
6082 if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) && !RB_TYPE_P(super, T_CLASS)) {
6083 rb_raise(rb_eTypeError,
6084 "superclass must be an instance of Class (given an instance of %"PRIsVALUE")",
6085 rb_obj_class(super));
6086 }
6087
6088 vm_check_if_namespace(cbase);
6089
6090 /* find klass */
6091 rb_autoload_load(cbase, id);
6092
6093 if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
6094 if (!vm_check_if_class(id, flags, super, klass))
6095 unmatched_redefinition("class", cbase, id, klass);
6096 return klass;
6097 }
6098 else {
6099 return vm_declare_class(id, flags, cbase, super);
6100 }
6101}
6102
6103static VALUE
6104vm_define_module(ID id, rb_num_t flags, VALUE cbase)
6105{
6106 VALUE mod;
6107
6108 vm_check_if_namespace(cbase);
6109 if ((mod = vm_const_get_under(id, flags, cbase)) != 0) {
6110 if (!vm_check_if_module(id, mod))
6111 unmatched_redefinition("module", cbase, id, mod);
6112 return mod;
6113 }
6114 else {
6115 return vm_declare_module(id, cbase);
6116 }
6117}
6118
6119static VALUE
6120vm_find_or_create_class_by_id(ID id,
6121 rb_num_t flags,
6122 VALUE cbase,
6123 VALUE super)
6124{
6125 rb_vm_defineclass_type_t type = VM_DEFINECLASS_TYPE(flags);
6126
6127 switch (type) {
6128 case VM_DEFINECLASS_TYPE_CLASS:
6129 /* classdef returns class scope value */
6130 return vm_define_class(id, flags, cbase, super);
6131
6132 case VM_DEFINECLASS_TYPE_SINGLETON_CLASS:
6133 /* classdef returns class scope value */
6134 return rb_singleton_class(cbase);
6135
6136 case VM_DEFINECLASS_TYPE_MODULE:
6137 /* classdef returns class scope value */
6138 return vm_define_module(id, flags, cbase);
6139
6140 default:
6141 rb_bug("unknown defineclass type: %d", (int)type);
6142 }
6143}
6144
6145static rb_method_visibility_t
6146vm_scope_visibility_get(const rb_execution_context_t *ec)
6147{
6148 const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
6149
6150 if (!vm_env_cref_by_cref(cfp->ep)) {
6151 return METHOD_VISI_PUBLIC;
6152 }
6153 else {
6154 return CREF_SCOPE_VISI(vm_ec_cref(ec))->method_visi;
6155 }
6156}
6157
6158static int
6159vm_scope_module_func_check(const rb_execution_context_t *ec)
6160{
6161 const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
6162
6163 if (!vm_env_cref_by_cref(cfp->ep)) {
6164 return FALSE;
6165 }
6166 else {
6167 return CREF_SCOPE_VISI(vm_ec_cref(ec))->module_func;
6168 }
6169}
6170
6171static void
6172vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqval, int is_singleton)
6173{
6174 VALUE klass;
6175 rb_method_visibility_t visi;
6176 rb_cref_t *cref = vm_ec_cref(ec);
6177
6178 if (is_singleton) {
6179 klass = rb_singleton_class(obj); /* class and frozen checked in this API */
6180 visi = METHOD_VISI_PUBLIC;
6181 }
6182 else {
6183 klass = CREF_CLASS_FOR_DEFINITION(cref);
6184 visi = vm_scope_visibility_get(ec);
6185 }
6186
6187 if (NIL_P(klass)) {
6188 rb_raise(rb_eTypeError, "no class/module to add method");
6189 }
6190
6191 rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi);
6192 // Set max_iv_count on klasses based on number of ivar sets that are in the initialize method
6193 if (id == idInitialize && RB_TYPE_P(klass, T_CLASS) &&
6194 !RCLASS_SINGLETON_P(klass) && !RCLASS_EXPECT_NO_IVAR(klass) &&
6195 (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
6196 RCLASS_SET_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval));
6197 }
6198
6199 if (!is_singleton && vm_scope_module_func_check(ec)) {
6200 klass = rb_singleton_class(klass);
6201 rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, METHOD_VISI_PUBLIC);
6202 }
6203}
6204
6205// Return the untagged block handler:
6206// * If it's VM_BLOCK_HANDLER_NONE, return nil
6207// * If it's an ISEQ or an IFUNC, fetch it from its rb_captured_block
6208// * If it's a PROC or SYMBOL, return it as is
6209VALUE
6210rb_vm_untag_block_handler(VALUE block_handler)
6211{
6212 if (VM_BLOCK_HANDLER_NONE == block_handler) return Qnil;
6213
6214 switch (vm_block_handler_type(block_handler)) {
6215 case block_handler_type_iseq:
6216 case block_handler_type_ifunc: {
6217 struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03);
6218 return captured->code.val;
6219 }
6220 case block_handler_type_proc:
6221 case block_handler_type_symbol:
6222 return block_handler;
6223 default:
6224 rb_bug("rb_vm_untag_block_handler: unreachable");
6225 }
6226}
6227
6228VALUE
6229rb_vm_get_untagged_block_handler(rb_control_frame_t *reg_cfp)
6230{
6231 return rb_vm_untag_block_handler(VM_CF_BLOCK_HANDLER(reg_cfp));
6232}
6233
6234static VALUE
6235vm_invokeblock_i(struct rb_execution_context_struct *ec,
6236 struct rb_control_frame_struct *reg_cfp,
6237 struct rb_calling_info *calling)
6238{
6239 const struct rb_callinfo *ci = calling->cd->ci;
6240 VALUE block_handler = VM_CF_BLOCK_HANDLER(GET_CFP());
6241
6242 if (block_handler == VM_BLOCK_HANDLER_NONE) {
6243 rb_vm_localjump_error("no block given (yield)", Qnil, 0);
6244 }
6245 else {
6246 return vm_invoke_block(ec, GET_CFP(), calling, ci, false, block_handler);
6247 }
6248}
6249
6250enum method_explorer_type {
6251 mexp_search_method,
6252 mexp_search_invokeblock,
6253 mexp_search_super,
6254};
6255
6256ALWAYS_INLINE(static VALUE vm_sendish(struct rb_execution_context_struct *ec,
6257 struct rb_control_frame_struct *reg_cfp,
6258 struct rb_call_data *cd, VALUE block_handler,
6259 enum method_explorer_type method_explorer));
6260static inline VALUE
6261vm_sendish(
6262 struct rb_execution_context_struct *ec,
6263 struct rb_control_frame_struct *reg_cfp,
6264 struct rb_call_data *cd,
6265 VALUE block_handler,
6266 enum method_explorer_type method_explorer
6267) {
6268 VALUE val = Qundef;
6269 const struct rb_callinfo *ci = cd->ci;
6270 const struct rb_callcache *cc;
6271 int argc = vm_ci_argc(ci);
6272 VALUE recv = TOPN(argc);
6273 struct rb_calling_info calling = {
6274 .block_handler = block_handler,
6275 .kw_splat = IS_ARGS_KW_SPLAT(ci) > 0,
6276 .recv = recv,
6277 .argc = argc,
6278 .cd = cd,
6279 };
6280
6281 switch (method_explorer) {
6282 case mexp_search_method:
6283 calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd, CLASS_OF(recv));
6284 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6285 break;
6286 case mexp_search_super:
6287 calling.cc = cc = vm_search_super_method(reg_cfp, cd, recv);
6288 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6289 break;
6290 case mexp_search_invokeblock:
6291 val = vm_invokeblock_i(ec, GET_CFP(), &calling);
6292 break;
6293 }
6294 return val;
6295}
6296
6297VALUE
6298rb_vm_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
6299{
6300 stack_check(ec);
6301 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
6302 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6303 VM_EXEC(ec, val);
6304 return val;
6305}
6306
6307// Fallback for YJIT/ZJIT, not used by the interpreter
6308VALUE
6309rb_vm_sendforward(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
6310{
6311 stack_check(ec);
6312
6313 struct rb_forwarding_call_data adjusted_cd;
6314 struct rb_callinfo adjusted_ci;
6315
6316 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, false, &adjusted_cd, &adjusted_ci);
6317
6318 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
6319
6320 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6321 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6322 }
6323
6324 VM_EXEC(ec, val);
6325 return val;
6326}
6327
6328VALUE
6329rb_vm_opt_send_without_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd)
6330{
6331 stack_check(ec);
6332 VALUE bh = VM_BLOCK_HANDLER_NONE;
6333 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6334 VM_EXEC(ec, val);
6335 return val;
6336}
6337
6338VALUE
6339rb_vm_invokesuper(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
6340{
6341 stack_check(ec);
6342
6343 struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
6344 vm_ci_flag(cd->ci),
6345 vm_ci_argc(cd->ci),
6346 vm_ci_kwarg(cd->ci));
6347 const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
6348 struct rb_call_data adjusted_cd = {
6349 .ci = &adjusted_ci,
6350 .cc = original_cc,
6351 };
6352
6353 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true);
6354 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
6355
6356 if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
6357 rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
6358 RB_OBJ_WRITTEN(CFP_ISEQ(GET_CFP()), Qundef, adjusted_cd.cc);
6359 }
6360
6361 VM_EXEC(ec, val);
6362 return val;
6363}
6364
6365// Fallback for YJIT/ZJIT, not used by the interpreter
6366VALUE
6367rb_vm_invokesuperforward(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
6368{
6369 stack_check(ec);
6370 struct rb_forwarding_call_data adjusted_cd;
6371 struct rb_callinfo adjusted_ci;
6372
6373 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, true, &adjusted_cd, &adjusted_ci);
6374
6375 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
6376
6377 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6378 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6379 }
6380
6381 VM_EXEC(ec, val);
6382 return val;
6383}
6384
6385VALUE
6386rb_vm_invokeblock(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd)
6387{
6388 stack_check(ec);
6389 VALUE bh = VM_BLOCK_HANDLER_NONE;
6390 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
6391 VM_EXEC(ec, val);
6392 return val;
6393}
6394
6395/* object.c */
6396VALUE rb_nil_to_s(VALUE);
6397VALUE rb_true_to_s(VALUE);
6398VALUE rb_false_to_s(VALUE);
6399/* numeric.c */
6400VALUE rb_int_to_s(int argc, VALUE *argv, VALUE x);
6401VALUE rb_fix_to_s(VALUE);
6402/* variable.c */
6403VALUE rb_mod_to_s(VALUE);
6405
6406static VALUE
6407vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
6408{
6409 int type = TYPE(recv);
6410 if (type == T_STRING) {
6411 return recv;
6412 }
6413
6414 const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
6415
6416 switch (type) {
6417 case T_SYMBOL:
6418 if (check_method_basic_definition(cme)) {
6419 return rb_sym2str(recv);
6420 }
6421 break;
6422 case T_MODULE:
6423 case T_CLASS:
6424 if (check_cfunc(cme, rb_mod_to_s)) {
6425 // rb_mod_to_s() allocates a mutable string, but since we are only
6426 // going to use this string for interpolation, it's fine to use the
6427 // frozen string.
6428 VALUE val = rb_mod_name(recv);
6429 if (NIL_P(val)) {
6430 val = rb_mod_to_s(recv);
6431 }
6432 return val;
6433 }
6434 break;
6435 case T_NIL:
6436 if (check_cfunc(cme, rb_nil_to_s)) {
6437 return rb_nil_to_s(recv);
6438 }
6439 break;
6440 case T_TRUE:
6441 if (check_cfunc(cme, rb_true_to_s)) {
6442 return rb_true_to_s(recv);
6443 }
6444 break;
6445 case T_FALSE:
6446 if (check_cfunc(cme, rb_false_to_s)) {
6447 return rb_false_to_s(recv);
6448 }
6449 break;
6450 case T_FIXNUM:
6451 if (check_cfunc(cme, rb_int_to_s)) {
6452 return rb_fix_to_s(recv);
6453 }
6454 break;
6455 }
6456 return Qundef;
6457}
6458
6459// ZJIT implementation is using the C function
6460// and needs to call a non-static function
6461VALUE
6462rb_vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
6463{
6464 return vm_objtostring(reg_cfp, recv, cd);
6465}
6466
6467static VALUE
6468vm_opt_ary_freeze(VALUE ary, int bop, ID id)
6469{
6470 if (BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
6471 return ary;
6472 }
6473 else {
6474 return Qundef;
6475 }
6476}
6477
6478static VALUE
6479vm_opt_hash_freeze(VALUE hash, int bop, ID id)
6480{
6481 if (BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
6482 return hash;
6483 }
6484 else {
6485 return Qundef;
6486 }
6487}
6488
6489static VALUE
6490vm_opt_str_freeze(VALUE str, int bop, ID id)
6491{
6492 if (BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
6493 return str;
6494 }
6495 else {
6496 return Qundef;
6497 }
6498}
6499
6500/* this macro is mandatory to use OPTIMIZED_CMP. What a design! */
6501#define id_cmp idCmp
6502
6503static VALUE
6504vm_opt_duparray_include_p(rb_execution_context_t *ec, const VALUE ary, VALUE target)
6505{
6506 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6507 return rb_ary_includes(ary, target);
6508 }
6509 else {
6510 VALUE args[1] = {target};
6511
6512 // duparray
6513 RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
6514 VALUE dupary = rb_ary_resurrect(ary);
6515
6516 return rb_vm_call_with_refinements(ec, dupary, idIncludeP, 1, args, RB_NO_KEYWORDS);
6517 }
6518}
6519
6520VALUE
6521rb_vm_opt_duparray_include_p(rb_execution_context_t *ec, const VALUE ary, VALUE target)
6522{
6523 return vm_opt_duparray_include_p(ec, ary, target);
6524}
6525
6526static VALUE
6527vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6528{
6529 if (OP_UNREDEFINED_P(MAX, ARRAY)) {
6530 if (array_len == 0) {
6531 return Qnil;
6532 }
6533 else {
6534 VALUE result = *ptr;
6535 rb_snum_t i = array_len - 1;
6536 while (i-- > 0) {
6537 const VALUE v = *++ptr;
6538 if (OPTIMIZED_CMP(v, result) > 0) {
6539 result = v;
6540 }
6541 }
6542 return result;
6543 }
6544 }
6545 else {
6546 return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idMax, 0, NULL, RB_NO_KEYWORDS);
6547 }
6548}
6549
6550VALUE
6551rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6552{
6553 return vm_opt_newarray_max(ec, array_len, ptr);
6554}
6555
6556static VALUE
6557vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6558{
6559 if (OP_UNREDEFINED_P(MIN, ARRAY)) {
6560 if (array_len == 0) {
6561 return Qnil;
6562 }
6563 else {
6564 VALUE result = *ptr;
6565 rb_snum_t i = array_len - 1;
6566 while (i-- > 0) {
6567 const VALUE v = *++ptr;
6568 if (OPTIMIZED_CMP(v, result) < 0) {
6569 result = v;
6570 }
6571 }
6572 return result;
6573 }
6574 }
6575 else {
6576 return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idMin, 0, NULL, RB_NO_KEYWORDS);
6577 }
6578}
6579
6580VALUE
6581rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6582{
6583 return vm_opt_newarray_min(ec, array_len, ptr);
6584}
6585
6586static VALUE
6587vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6588{
6589 // If Array#hash is _not_ monkeypatched, use the optimized call
6590 if (OP_UNREDEFINED_P(HASH, ARRAY)) {
6591 return rb_ary_hash_values(array_len, ptr);
6592 }
6593 else {
6594 return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idHash, 0, NULL, RB_NO_KEYWORDS);
6595 }
6596}
6597
6598VALUE
6599rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
6600{
6601 return vm_opt_newarray_hash(ec, array_len, ptr);
6602}
6603
6604VALUE rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len);
6605VALUE rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer);
6606
6607static VALUE
6608vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE target)
6609{
6610 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6611 struct RArray fake_ary = {RBASIC_INIT};
6612 VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, array_len);
6613 return rb_ary_includes(ary, target);
6614 }
6615 else {
6616 VALUE args[1] = {target};
6617 return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idIncludeP, 1, args, RB_NO_KEYWORDS);
6618 }
6619}
6620
6621VALUE
6622rb_vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE target)
6623{
6624 return vm_opt_newarray_include_p(ec, array_len, ptr, target);
6625}
6626
6627static VALUE
6628vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE fmt, VALUE buffer)
6629{
6630 if (OP_UNREDEFINED_P(PACK, ARRAY)) {
6631 struct RArray fake_ary = {RBASIC_INIT};
6632 VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, array_len);
6633 return rb_ec_pack_ary(ec, ary, fmt, (UNDEF_P(buffer) ? Qnil : buffer));
6634 }
6635 else {
6636 // The opt_newarray_send insn drops the keyword args so we need to rebuild them.
6637 // Setup an array with room for keyword hash.
6638 VALUE args[2];
6639 args[0] = fmt;
6640 int kw_splat = RB_NO_KEYWORDS;
6641 int argc = 1;
6642
6643 if (!UNDEF_P(buffer)) {
6644 args[1] = rb_hash_new_capa(1);
6645 rb_hash_aset(args[1], ID2SYM(idBuffer), buffer);
6646 kw_splat = RB_PASS_KEYWORDS;
6647 argc++;
6648 }
6649
6650 return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idPack, argc, args, kw_splat);
6651 }
6652}
6653
6654VALUE
6655rb_vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE fmt, VALUE buffer)
6656{
6657 return vm_opt_newarray_pack_buffer(ec, array_len, ptr, fmt, buffer);
6658}
6659
6660
6661#undef id_cmp
6662
6663static void
6664vm_track_constant_cache(ID id, void *ic)
6665{
6666 rb_vm_t *vm = GET_VM();
6667 struct rb_id_table *const_cache = &vm->constant_cache;
6668 VALUE lookup_result;
6669 set_table *ics;
6670
6671 if (rb_id_table_lookup(const_cache, id, &lookup_result)) {
6672 ics = (set_table *)lookup_result;
6673 }
6674 else {
6675 ics = set_init_numtable();
6676 rb_id_table_insert(const_cache, id, (VALUE)ics);
6677 }
6678
6679 /* The call below to st_insert could allocate which could trigger a GC.
6680 * If it triggers a GC, it may free an iseq that also holds a cache to this
6681 * constant. If that iseq is the last iseq with a cache to this constant, then
6682 * it will free this ST table, which would cause an use-after-free during this
6683 * st_insert.
6684 *
6685 * So to fix this issue, we store the ID that is currently being inserted
6686 * and, in remove_from_constant_cache, we don't free the ST table for ID
6687 * equal to this one.
6688 *
6689 * See [Bug #20921].
6690 */
6691 vm->inserting_constant_cache_id = id;
6692
6693 set_insert(ics, (st_data_t)ic);
6694
6695 vm->inserting_constant_cache_id = (ID)0;
6696}
6697
6698static void
6699vm_ic_track_const_chain(rb_control_frame_t *cfp, IC ic, const ID *segments)
6700{
6701 RB_VM_LOCKING() {
6702 for (int i = 0; segments[i]; i++) {
6703 ID id = segments[i];
6704 if (id == idNULL) continue;
6705 vm_track_constant_cache(id, ic);
6706 }
6707 }
6708}
6709
6710// For JIT inlining
6711static inline bool
6712vm_inlined_ic_hit_p(VALUE flags, VALUE value, const rb_cref_t *ic_cref, rb_serial_t ractor_id, const VALUE *reg_ep)
6713{
6714 // Not rb_ractor_main_p(): an owner Ractor may now cache an unshareable constant
6715 // of its own class, and only it may be handed that value back.
6716 if ((flags & IMEMO_CONST_CACHE_SHAREABLE) || ractor_id == rb_ractor_id(GET_RACTOR())) {
6717 VM_ASSERT(ractor_incidental_shareable_p(flags & IMEMO_CONST_CACHE_SHAREABLE, value));
6718
6719 return (ic_cref == NULL || // no need to check CREF
6720 ic_cref == vm_get_cref(reg_ep));
6721 }
6722 return false;
6723}
6724
6725static bool
6726vm_ic_hit_p(const struct iseq_inline_constant_cache_entry *ice, const VALUE *reg_ep)
6727{
6728 VM_ASSERT(IMEMO_TYPE_P(ice, imemo_constcache));
6729 return vm_inlined_ic_hit_p(ice->flags, ice->value, ice->ic_cref, ice->ractor_id, reg_ep);
6730}
6731
6732// YJIT needs this function to never allocate and never raise
6733bool
6734rb_vm_ic_hit_p(IC ic, const VALUE *reg_ep)
6735{
6736 return ic->entry && vm_ic_hit_p(ic->entry, reg_ep);
6737}
6738
6739static void
6740vm_ic_update(const rb_iseq_t *iseq, IC ic, VALUE val, const VALUE *reg_ep, const VALUE *pc)
6741{
6742 if (ruby_vm_const_missing_count > 0) {
6743 ruby_vm_const_missing_count = 0;
6744 ic->entry = NULL;
6745 return;
6746 }
6747
6748 struct iseq_inline_constant_cache_entry *ice = SHAREABLE_IMEMO_NEW(struct iseq_inline_constant_cache_entry, imemo_constcache, 0);
6749 RB_OBJ_WRITE(ice, &ice->value, val);
6750 ice->ic_cref = vm_get_const_key_cref(reg_ep);
6751 ice->ractor_id = rb_ractor_id(GET_RACTOR());
6752
6753 if (rb_ractor_shareable_p(val)) {
6754 RUBY_ASSERT((rb_gc_verify_shareable(val), 1));
6755 ice->flags |= IMEMO_CONST_CACHE_SHAREABLE;
6756 }
6757 RB_OBJ_WRITE(iseq, &ic->entry, ice);
6758 RUBY_ASSERT(pc >= ISEQ_BODY(iseq)->iseq_encoded);
6759 unsigned pos = (unsigned)(pc - ISEQ_BODY(iseq)->iseq_encoded);
6760 rb_yjit_constant_ic_update(iseq, ic, pos);
6761}
6762
6763VALUE
6764rb_vm_opt_getconstant_path(rb_execution_context_t *ec, rb_control_frame_t *const reg_cfp, IC ic)
6765{
6766 VALUE val;
6767 const ID *segments = ic->segments;
6768 struct iseq_inline_constant_cache_entry *ice = ic->entry;
6769
6770 if (ice && vm_ic_hit_p(ice, GET_EP())) {
6771 val = ice->value;
6772
6773 // On a non-main ractor another ractor can concurrently reassign a
6774 // shareable constant (which invalidates ICs asynchronously), so the
6775 // cached-but-still-shareable value may legitimately differ from a
6776 // freshly recomputed chain. Only assert equality when single-ractor.
6777 VM_ASSERT(val == vm_get_ev_const_chain(ec, segments) || rb_multi_ractor_p());
6778 }
6779 else {
6780 ruby_vm_constant_cache_misses++;
6781 val = vm_get_ev_const_chain(ec, segments);
6782 vm_ic_track_const_chain(GET_CFP(), ic, segments);
6783 // Undo the PC increment to get the address to this instruction
6784 // INSN_ATTR(width) == 2
6785 vm_ic_update(CFP_ISEQ(GET_CFP()), ic, val, GET_EP(), CFP_PC(GET_CFP()) - 2);
6786 }
6787 return val;
6788}
6789
6790// Return true if the once value is already computed and set *result to the value.
6791// Otherwise, return false.
6792// Used for ZJIT. Keep in sync with `vm_once_dispatch` below.
6793bool
6794rb_vm_once_done_value(ISE is, VALUE *result)
6795{
6796 rb_thread_t *running_th = rbimpl_atomic_ptr_load((void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6797 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6798 *result = is->once.value;
6799 return true;
6800 }
6801 return false;
6802}
6803
6804static VALUE
6805vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, ISE is)
6806{
6807 rb_thread_t *th = rb_ec_thread_ptr(ec);
6808 rb_thread_t *running_th;
6809
6810 again:
6811 running_th = rbimpl_atomic_ptr_load((void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6812 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6813 return is->once.value;
6814 }
6815 else if (running_th == NULL) {
6816 VALUE val = Qundef;
6817 enum ruby_tag_type state;
6818 if (rbimpl_atomic_ptr_cas((void**)&is->once.running_thread, running_th, th, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED) != running_th) {
6819 goto again;
6820 }
6821 EC_PUSH_TAG(ec);
6822 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
6823 val = vm_once_exec((VALUE)iseq);
6824 }
6825 EC_POP_TAG();
6826 if (state != TAG_NONE) {
6827 vm_once_clear((VALUE)is);
6828 EC_JUMP_TAG(ec, state);
6829 }
6830
6831 // TODO: confirm that it is shareable
6832 if (RB_FL_ABLE(val)) {
6834 }
6835
6836 RB_OBJ_WRITE(CFP_ISEQ(ec->cfp), &is->once.value, val);
6837
6838 rbimpl_atomic_ptr_store((volatile void**)&is->once.running_thread, RUNNING_THREAD_ONCE_DONE, RBIMPL_ATOMIC_RELEASE); /* success */
6839 vm_once_broadcast(rb_ec_vm_ptr(ec));
6840 return val;
6841 }
6842 else if (running_th == th) {
6843 /* recursive once */
6844 return vm_once_exec((VALUE)iseq);
6845 }
6846 else {
6847 /* wait for the winner to finish */
6848 struct vm_once_wait_arg arg = { .vm = rb_ec_vm_ptr(ec), .is = is };
6849 rb_nogvl(vm_once_wait_no_gvl, &arg, vm_once_wait_ubf, arg.vm,
6851 RUBY_VM_CHECK_INTS(ec);
6852 goto again;
6853 }
6854}
6855
6856static OFFSET
6857vm_case_dispatch(CDHASH hash, OFFSET else_offset, VALUE key)
6858{
6859 switch (OBJ_BUILTIN_TYPE(key)) {
6860 case -1:
6861 case T_FLOAT:
6862 case T_SYMBOL:
6863 case T_BIGNUM:
6864 case T_STRING:
6865 if (BASIC_OP_UNREDEFINED_P(BOP_EQQ,
6866 SYMBOL_REDEFINED_OP_FLAG |
6867 INTEGER_REDEFINED_OP_FLAG |
6868 FLOAT_REDEFINED_OP_FLAG |
6869 NIL_REDEFINED_OP_FLAG |
6870 TRUE_REDEFINED_OP_FLAG |
6871 FALSE_REDEFINED_OP_FLAG |
6872 STRING_REDEFINED_OP_FLAG)) {
6873 st_data_t val;
6874 if (RB_FLOAT_TYPE_P(key)) {
6875 double kval = RFLOAT_VALUE(key);
6876 if (!isinf(kval) && modf(kval, &kval) == 0.0) {
6877 key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval);
6878 }
6879 }
6880 if (st_lookup(rb_imemo_cdhash_tbl(hash), key, &val)) {
6881 return (VALUE)val;
6882 }
6883 else {
6884 return else_offset;
6885 }
6886 }
6887 }
6888 return 0;
6889}
6890
6891NORETURN(static void
6892 vm_stack_consistency_error(const rb_execution_context_t *ec,
6893 const rb_control_frame_t *,
6894 const VALUE *));
6895static void
6896vm_stack_consistency_error(const rb_execution_context_t *ec,
6897 const rb_control_frame_t *cfp,
6898 const VALUE *bp)
6899{
6900 const ptrdiff_t nsp = VM_SP_CNT(ec, cfp->sp);
6901 const ptrdiff_t nbp = VM_SP_CNT(ec, bp);
6902 static const char stack_consistency_error[] =
6903 "Stack consistency error (sp: %"PRIdPTRDIFF", bp: %"PRIdPTRDIFF")";
6904#if defined RUBY_DEVEL
6905 VALUE mesg = rb_sprintf(stack_consistency_error, nsp, nbp);
6906 rb_str_cat_cstr(mesg, "\n");
6907 rb_str_append(mesg, rb_iseq_disasm(CFP_ISEQ(cfp)));
6909#else
6910 rb_bug(stack_consistency_error, nsp, nbp);
6911#endif
6912}
6913
6914static VALUE
6915vm_opt_plus(VALUE recv, VALUE obj)
6916{
6917 if (FIXNUM_2_P(recv, obj) &&
6918 OP_UNREDEFINED_P(PLUS, INTEGER)) {
6919 return rb_fix_plus_fix(recv, obj);
6920 }
6921 else if (FLONUM_2_P(recv, obj) &&
6922 OP_UNREDEFINED_P(PLUS, FLOAT)) {
6923 return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
6924 }
6925 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
6926 return Qundef;
6927 }
6928 else if (RBASIC_CLASS(recv) == rb_cFloat &&
6929 RBASIC_CLASS(obj) == rb_cFloat &&
6930 OP_UNREDEFINED_P(PLUS, FLOAT)) {
6931 return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
6932 }
6933 else if (RBASIC_CLASS(recv) == rb_cString &&
6934 RBASIC_CLASS(obj) == rb_cString &&
6935 OP_UNREDEFINED_P(PLUS, STRING)) {
6936 return rb_str_opt_plus(recv, obj);
6937 }
6938 else if (RBASIC_CLASS(recv) == rb_cArray &&
6939 RBASIC_CLASS(obj) == rb_cArray &&
6940 OP_UNREDEFINED_P(PLUS, ARRAY)) {
6941 return rb_ary_plus(recv, obj);
6942 }
6943 else {
6944 return Qundef;
6945 }
6946}
6947
6948static VALUE
6949vm_opt_minus(VALUE recv, VALUE obj)
6950{
6951 if (FIXNUM_2_P(recv, obj) &&
6952 OP_UNREDEFINED_P(MINUS, INTEGER)) {
6953 return rb_fix_minus_fix(recv, obj);
6954 }
6955 else if (FLONUM_2_P(recv, obj) &&
6956 OP_UNREDEFINED_P(MINUS, FLOAT)) {
6957 return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj));
6958 }
6959 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
6960 return Qundef;
6961 }
6962 else if (RBASIC_CLASS(recv) == rb_cFloat &&
6963 RBASIC_CLASS(obj) == rb_cFloat &&
6964 OP_UNREDEFINED_P(MINUS, FLOAT)) {
6965 return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj));
6966 }
6967 else {
6968 return Qundef;
6969 }
6970}
6971
6972static VALUE
6973vm_opt_mult(VALUE recv, VALUE obj)
6974{
6975 if (FIXNUM_2_P(recv, obj) &&
6976 OP_UNREDEFINED_P(MULT, INTEGER)) {
6977 return rb_fix_mul_fix(recv, obj);
6978 }
6979 else if (FLONUM_2_P(recv, obj) &&
6980 OP_UNREDEFINED_P(MULT, FLOAT)) {
6981 return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
6982 }
6983 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
6984 return Qundef;
6985 }
6986 else if (RBASIC_CLASS(recv) == rb_cFloat &&
6987 RBASIC_CLASS(obj) == rb_cFloat &&
6988 OP_UNREDEFINED_P(MULT, FLOAT)) {
6989 return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
6990 }
6991 else {
6992 return Qundef;
6993 }
6994}
6995
6996static VALUE
6997vm_opt_div(VALUE recv, VALUE obj)
6998{
6999 if (FIXNUM_2_P(recv, obj) &&
7000 OP_UNREDEFINED_P(DIV, INTEGER)) {
7001 return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_div_fix(recv, obj);
7002 }
7003 else if (FLONUM_2_P(recv, obj) &&
7004 OP_UNREDEFINED_P(DIV, FLOAT)) {
7005 return rb_flo_div_flo(recv, obj);
7006 }
7007 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7008 return Qundef;
7009 }
7010 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7011 RBASIC_CLASS(obj) == rb_cFloat &&
7012 OP_UNREDEFINED_P(DIV, FLOAT)) {
7013 return rb_flo_div_flo(recv, obj);
7014 }
7015 else {
7016 return Qundef;
7017 }
7018}
7019
7020static VALUE
7021vm_opt_mod(VALUE recv, VALUE obj)
7022{
7023 if (FIXNUM_2_P(recv, obj) &&
7024 OP_UNREDEFINED_P(MOD, INTEGER)) {
7025 return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_mod_fix(recv, obj);
7026 }
7027 else if (FLONUM_2_P(recv, obj) &&
7028 OP_UNREDEFINED_P(MOD, FLOAT)) {
7029 return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
7030 }
7031 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7032 return Qundef;
7033 }
7034 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7035 RBASIC_CLASS(obj) == rb_cFloat &&
7036 OP_UNREDEFINED_P(MOD, FLOAT)) {
7037 return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
7038 }
7039 else {
7040 return Qundef;
7041 }
7042}
7043
7044static VALUE
7045vm_opt_neq(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
7046{
7047 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
7048 VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);
7049
7050 if (!UNDEF_P(val)) {
7051 return RBOOL(!RTEST(val));
7052 }
7053 }
7054
7055 return Qundef;
7056}
7057
7058static VALUE
7059vm_opt_lt(VALUE recv, VALUE obj)
7060{
7061 if (FIXNUM_2_P(recv, obj) &&
7062 OP_UNREDEFINED_P(LT, INTEGER)) {
7063 return RBOOL((SIGNED_VALUE)recv < (SIGNED_VALUE)obj);
7064 }
7065 else if (FLONUM_2_P(recv, obj) &&
7066 OP_UNREDEFINED_P(LT, FLOAT)) {
7067 return RBOOL(RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj));
7068 }
7069 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7070 return Qundef;
7071 }
7072 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7073 RBASIC_CLASS(obj) == rb_cFloat &&
7074 OP_UNREDEFINED_P(LT, FLOAT)) {
7075 return RBOOL(RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj));
7076 }
7077 else {
7078 return Qundef;
7079 }
7080}
7081
7082static VALUE
7083vm_opt_le(VALUE recv, VALUE obj)
7084{
7085 if (FIXNUM_2_P(recv, obj) &&
7086 OP_UNREDEFINED_P(LE, INTEGER)) {
7087 return RBOOL((SIGNED_VALUE)recv <= (SIGNED_VALUE)obj);
7088 }
7089 else if (FLONUM_2_P(recv, obj) &&
7090 OP_UNREDEFINED_P(LE, FLOAT)) {
7091 return RBOOL(RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj));
7092 }
7093 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7094 return Qundef;
7095 }
7096 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7097 RBASIC_CLASS(obj) == rb_cFloat &&
7098 OP_UNREDEFINED_P(LE, FLOAT)) {
7099 return RBOOL(RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj));
7100 }
7101 else {
7102 return Qundef;
7103 }
7104}
7105
7106static VALUE
7107vm_opt_gt(VALUE recv, VALUE obj)
7108{
7109 if (FIXNUM_2_P(recv, obj) &&
7110 OP_UNREDEFINED_P(GT, INTEGER)) {
7111 return RBOOL((SIGNED_VALUE)recv > (SIGNED_VALUE)obj);
7112 }
7113 else if (FLONUM_2_P(recv, obj) &&
7114 OP_UNREDEFINED_P(GT, FLOAT)) {
7115 return RBOOL(RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj));
7116 }
7117 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7118 return Qundef;
7119 }
7120 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7121 RBASIC_CLASS(obj) == rb_cFloat &&
7122 OP_UNREDEFINED_P(GT, FLOAT)) {
7123 return RBOOL(RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj));
7124 }
7125 else {
7126 return Qundef;
7127 }
7128}
7129
7130static VALUE
7131vm_opt_ge(VALUE recv, VALUE obj)
7132{
7133 if (FIXNUM_2_P(recv, obj) &&
7134 OP_UNREDEFINED_P(GE, INTEGER)) {
7135 return RBOOL((SIGNED_VALUE)recv >= (SIGNED_VALUE)obj);
7136 }
7137 else if (FLONUM_2_P(recv, obj) &&
7138 OP_UNREDEFINED_P(GE, FLOAT)) {
7139 return RBOOL(RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj));
7140 }
7141 else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
7142 return Qundef;
7143 }
7144 else if (RBASIC_CLASS(recv) == rb_cFloat &&
7145 RBASIC_CLASS(obj) == rb_cFloat &&
7146 OP_UNREDEFINED_P(GE, FLOAT)) {
7147 return RBOOL(RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj));
7148 }
7149 else {
7150 return Qundef;
7151 }
7152}
7153
7154
7155static VALUE
7156vm_opt_ltlt(VALUE recv, VALUE obj)
7157{
7158 if (SPECIAL_CONST_P(recv)) {
7159 return Qundef;
7160 }
7161 else if (RBASIC_CLASS(recv) == rb_cString &&
7162 OP_UNREDEFINED_P(LTLT, STRING)) {
7163 if (LIKELY(RB_TYPE_P(obj, T_STRING))) {
7164 return rb_str_buf_append(recv, obj);
7165 }
7166 else {
7167 return rb_str_concat(recv, obj);
7168 }
7169 }
7170 else if (RBASIC_CLASS(recv) == rb_cArray &&
7171 OP_UNREDEFINED_P(LTLT, ARRAY)) {
7172 return rb_ary_push(recv, obj);
7173 }
7174 else {
7175 return Qundef;
7176 }
7177}
7178
7179static VALUE
7180vm_opt_and(VALUE recv, VALUE obj)
7181{
7182 // If recv and obj are both fixnums, then the bottom tag bit
7183 // will be 1 on both. 1 & 1 == 1, so the result value will also
7184 // be a fixnum. If either side is *not* a fixnum, then the tag bit
7185 // will be 0, and we return Qundef.
7186 VALUE ret = ((SIGNED_VALUE) recv) & ((SIGNED_VALUE) obj);
7187
7188 if (FIXNUM_P(ret) &&
7189 OP_UNREDEFINED_P(AND, INTEGER)) {
7190 return ret;
7191 }
7192 else {
7193 return Qundef;
7194 }
7195}
7196
7197static VALUE
7198vm_opt_or(VALUE recv, VALUE obj)
7199{
7200 if (FIXNUM_2_P(recv, obj) &&
7201 OP_UNREDEFINED_P(OR, INTEGER)) {
7202 return recv | obj;
7203 }
7204 else {
7205 return Qundef;
7206 }
7207}
7208
7209static VALUE
7210vm_opt_aref(VALUE recv, VALUE obj)
7211{
7212 if (SPECIAL_CONST_P(recv)) {
7213 if (FIXNUM_2_P(recv, obj) &&
7214 OP_UNREDEFINED_P(AREF, INTEGER)) {
7215 return rb_fix_aref(recv, obj);
7216 }
7217 return Qundef;
7218 }
7219 else if (RBASIC_CLASS(recv) == rb_cArray &&
7220 OP_UNREDEFINED_P(AREF, ARRAY)) {
7221 if (FIXNUM_P(obj)) {
7222 return rb_ary_entry_internal(recv, FIX2LONG(obj));
7223 }
7224 else {
7225 return rb_ary_aref1(recv, obj);
7226 }
7227 }
7228 else if (RBASIC_CLASS(recv) == rb_cHash &&
7229 OP_UNREDEFINED_P(AREF, HASH)) {
7230 return rb_hash_aref(recv, obj);
7231 }
7232 else {
7233 return Qundef;
7234 }
7235}
7236
7237static VALUE
7238vm_opt_aset(VALUE recv, VALUE obj, VALUE set)
7239{
7240 if (SPECIAL_CONST_P(recv)) {
7241 return Qundef;
7242 }
7243 else if (RBASIC_CLASS(recv) == rb_cArray &&
7244 OP_UNREDEFINED_P(ASET, ARRAY) &&
7245 FIXNUM_P(obj)) {
7246 rb_ary_store(recv, FIX2LONG(obj), set);
7247 return set;
7248 }
7249 else if (RBASIC_CLASS(recv) == rb_cHash &&
7250 OP_UNREDEFINED_P(ASET, HASH)) {
7251 rb_hash_aset(recv, obj, set);
7252 return set;
7253 }
7254 else {
7255 return Qundef;
7256 }
7257}
7258
7259static VALUE
7260vm_opt_length(VALUE recv, int bop)
7261{
7262 if (SPECIAL_CONST_P(recv)) {
7263 return Qundef;
7264 }
7265 else if (RBASIC_CLASS(recv) == rb_cString &&
7266 BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
7267 if (bop == BOP_EMPTY_P) {
7268 return LONG2NUM(RSTRING_LEN(recv));
7269 }
7270 else {
7271 return rb_str_length(recv);
7272 }
7273 }
7274 else if (RBASIC_CLASS(recv) == rb_cArray &&
7275 BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
7276 return LONG2NUM(RARRAY_LEN(recv));
7277 }
7278 else if (RBASIC_CLASS(recv) == rb_cHash &&
7279 BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
7280 return INT2FIX(RHASH_SIZE(recv));
7281 }
7282 else {
7283 return Qundef;
7284 }
7285}
7286
7287static VALUE
7288vm_opt_empty_p(VALUE recv)
7289{
7290 switch (vm_opt_length(recv, BOP_EMPTY_P)) {
7291 case Qundef: return Qundef;
7292 case INT2FIX(0): return Qtrue;
7293 default: return Qfalse;
7294 }
7295}
7296
7297VALUE rb_false(VALUE obj);
7298
7299static VALUE
7300vm_opt_nil_p(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
7301{
7302 if (NIL_P(recv) &&
7303 OP_UNREDEFINED_P(NIL_P, NIL)) {
7304 return Qtrue;
7305 }
7306 else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
7307 return Qfalse;
7308 }
7309 else {
7310 return Qundef;
7311 }
7312}
7313
7314static VALUE
7315fix_succ(VALUE x)
7316{
7317 switch (x) {
7318 case ~0UL:
7319 /* 0xFFFF_FFFF == INT2FIX(-1)
7320 * `-1.succ` is of course 0. */
7321 return INT2FIX(0);
7322 case RSHIFT(~0UL, 1):
7323 /* 0x7FFF_FFFF == LONG2FIX(0x3FFF_FFFF)
7324 * 0x3FFF_FFFF + 1 == 0x4000_0000, which is a Bignum. */
7325 return rb_uint2big(1UL << (SIZEOF_LONG * CHAR_BIT - 2));
7326 default:
7327 /* LONG2FIX(FIX2LONG(x)+FIX2LONG(y))
7328 * == ((lx*2+1)/2 + (ly*2+1)/2)*2+1
7329 * == lx*2 + ly*2 + 1
7330 * == (lx*2+1) + (ly*2+1) - 1
7331 * == x + y - 1
7332 *
7333 * Here, if we put y := INT2FIX(1):
7334 *
7335 * == x + INT2FIX(1) - 1
7336 * == x + 2 .
7337 */
7338 return x + 2;
7339 }
7340}
7341
7342static VALUE
7343vm_opt_succ(VALUE recv)
7344{
7345 if (FIXNUM_P(recv) &&
7346 OP_UNREDEFINED_P(SUCC, INTEGER)) {
7347 return fix_succ(recv);
7348 }
7349 else if (SPECIAL_CONST_P(recv)) {
7350 return Qundef;
7351 }
7352 else if (RBASIC_CLASS(recv) == rb_cString &&
7353 OP_UNREDEFINED_P(SUCC, STRING)) {
7354 return rb_str_succ(recv);
7355 }
7356 else {
7357 return Qundef;
7358 }
7359}
7360
7361static VALUE
7362vm_opt_not(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
7363{
7364 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
7365 return RBOOL(!RTEST(recv));
7366 }
7367 else {
7368 return Qundef;
7369 }
7370}
7371
7372static VALUE
7373vm_opt_regexpmatch2(VALUE recv, VALUE obj)
7374{
7375 if (SPECIAL_CONST_P(recv)) {
7376 return Qundef;
7377 }
7378 else if (RBASIC_CLASS(recv) == rb_cString &&
7379 CLASS_OF(obj) == rb_cRegexp &&
7380 OP_UNREDEFINED_P(MATCH, STRING)) {
7381 return rb_reg_match(obj, recv);
7382 }
7383 else if (RBASIC_CLASS(recv) == rb_cRegexp &&
7384 OP_UNREDEFINED_P(MATCH, REGEXP)) {
7385 return rb_reg_match(recv, obj);
7386 }
7387 else {
7388 return Qundef;
7389 }
7390}
7391
7392#undef EQ_UNREDEFINED_P
7393#undef OP_UNREDEFINED_P
7394
7395rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos);
7396
7397NOINLINE(static void vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp));
7398
7399static inline void
7400vm_trace_hook(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE *pc,
7401 rb_event_flag_t pc_events, rb_event_flag_t target_event,
7402 rb_hook_list_t *global_hooks, rb_hook_list_t *local_hooks, VALUE val)
7403{
7404 rb_event_flag_t event = pc_events & target_event;
7405 VALUE self = GET_SELF();
7406
7407 VM_ASSERT(rb_popcount64((uint64_t)event) == 1);
7408
7409 if (local_hooks) local_hooks->running++; // make sure they don't get deleted while global hooks run
7410
7411 if (event & global_hooks->events) {
7412 /* increment PC because source line is calculated with PC-1 */
7413 reg_cfp->pc++;
7414 vm_dtrace(event, ec);
7415 rb_exec_event_hook_orig(ec, global_hooks, event, self, 0, 0, 0 , val, 0);
7416 reg_cfp->pc--;
7417 }
7418
7419 if (local_hooks) local_hooks->running--;
7420 if (local_hooks != NULL) {
7421 if (event & local_hooks->events) {
7422 /* increment PC because source line is calculated with PC-1 */
7423 reg_cfp->pc++;
7424 rb_exec_event_hook_orig(ec, local_hooks, event, self, 0, 0, 0 , val, 0);
7425 reg_cfp->pc--;
7426 }
7427 }
7428}
7429
7430/* Re-fetch the iseq-local hook list before each event: a hook fired by an
7431 * earlier event at this pc can disable the last targeted TracePoint on this
7432 * iseq, which frees local_hooks. Reload from its stable source (the ractor's
7433 * targeted-hooks table) so we never dereference a dangling pointer. */
7434#define VM_TRACE_HOOK(target_event, val) do { \
7435 if ((pc_events & (target_event)) & enabled_flags) { \
7436 if (local_hooks_cnt > 0) local_hooks = rb_iseq_local_hooks(iseq, r, false); \
7437 vm_trace_hook(ec, reg_cfp, pc, pc_events, (target_event), global_hooks, local_hooks, (val)); \
7438 } \
7439} while (0)
7440
7441static VALUE
7442rescue_errinfo(rb_execution_context_t *ec, rb_control_frame_t *cfp)
7443{
7444 VM_ASSERT(VM_FRAME_RUBYFRAME_P(cfp));
7445 VM_ASSERT(ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_RESCUE);
7446 return cfp->ep[VM_ENV_INDEX_LAST_LVAR];
7447}
7448
7449static void
7450vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
7451{
7452 const VALUE *pc = reg_cfp->pc;
7453 rb_ractor_t *r = rb_ec_ractor_ptr(ec);
7454 rb_event_flag_t enabled_flags = r->pub.hooks.events & ISEQ_TRACE_EVENTS;
7455 rb_event_flag_t ractor_events = enabled_flags;
7456
7457 if (enabled_flags == 0 && rb_ractor_targeted_hooks_cnt(r) == 0) {
7458 return;
7459 }
7460 else {
7461 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
7462 size_t pos = pc - ISEQ_BODY(iseq)->iseq_encoded;
7463 rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pos);
7464 unsigned int local_hooks_cnt = iseq->aux.exec.local_hooks_cnt;
7465 rb_hook_list_t *local_hooks = NULL;
7466 if (RB_UNLIKELY(local_hooks_cnt > 0)) {
7467 st_data_t val;
7468 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
7469 local_hooks = (rb_hook_list_t*)val;
7470 }
7471 }
7472 rb_event_flag_t iseq_local_events = local_hooks != NULL ? local_hooks->events : 0;
7473
7474 rb_hook_list_t *bmethod_local_hooks = NULL;
7475 rb_event_flag_t bmethod_local_events = 0;
7476 unsigned int bmethod_hooks_cnt = 0;
7477 rb_method_definition_t *bmethod_def = NULL;
7478 const bool bmethod_frame = VM_FRAME_BMETHOD_P(reg_cfp);
7479 enabled_flags |= iseq_local_events;
7480
7481 VM_ASSERT((iseq_local_events & ~ISEQ_TRACE_EVENTS) == 0);
7482
7483 if (bmethod_frame) {
7484 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
7485 VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
7486 bmethod_def = me->def;
7487 bmethod_hooks_cnt = me->def->body.bmethod.local_hooks_cnt;
7488 if (RB_UNLIKELY(bmethod_hooks_cnt > 0)) {
7489 st_data_t val;
7490 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)me->def, &val)) {
7491 bmethod_local_hooks = (rb_hook_list_t*)val;
7492 }
7493 if (bmethod_local_hooks) {
7494 bmethod_local_events = bmethod_local_hooks->events;
7495 }
7496 }
7497 }
7498
7499 if ((pc_events & enabled_flags) == 0 && !bmethod_frame) {
7500#if 0
7501 /* disable trace */
7502 /* TODO: incomplete */
7503 rb_iseq_trace_set(iseq, vm_event_flags & ISEQ_TRACE_EVENTS);
7504#else
7505 /* do not disable trace because of performance problem
7506 * (re-enable overhead)
7507 */
7508#endif
7509 return;
7510 }
7511 else if (ec->trace_arg != NULL) {
7512 /* already tracing */
7513 return;
7514 }
7515 else {
7516 rb_hook_list_t *global_hooks = rb_ec_ractor_hooks(ec);
7517 /* Note, not considering iseq local events here since the same
7518 * iseq could be used in multiple bmethods. */
7519 rb_event_flag_t bmethod_events = ractor_events | bmethod_local_events;
7520
7521 if (0) {
7522 VALUE path = rb_iseq_path(iseq);
7523 VALUE label = rb_iseq_label(iseq);
7524 ruby_debug_printf("vm_trace>>%4d (%4x) - %.*s:%d %.*s\n",
7525 (int)pos,
7526 (int)pc_events,
7527 RSTRING_LENINT(path), RSTRING_PTR(path),
7528 (int)rb_iseq_line_no(iseq, pos),
7529 RSTRING_LENINT(label), RSTRING_PTR(label));
7530 }
7531 VM_ASSERT(reg_cfp->pc == pc);
7532 VM_ASSERT(pc_events != 0);
7533
7534 /* check traces */
7535 if ((pc_events & RUBY_EVENT_B_CALL) && bmethod_frame && (bmethod_events & RUBY_EVENT_CALL)) {
7536 /* b_call instruction running as a method. Fire call event. */
7537 vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_CALL, RUBY_EVENT_CALL, global_hooks, bmethod_local_hooks, Qundef);
7538 }
7540 VM_TRACE_HOOK(RUBY_EVENT_RESCUE, rescue_errinfo(ec, reg_cfp));
7541 VM_TRACE_HOOK(RUBY_EVENT_LINE, Qundef);
7542 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_LINE, Qundef);
7543 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH, Qundef);
7544 VM_TRACE_HOOK(RUBY_EVENT_END | RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN, TOPN(0));
7545 if ((pc_events & RUBY_EVENT_B_RETURN) && bmethod_frame && (bmethod_events & RUBY_EVENT_RETURN)) {
7546 /* b_return instruction running as a method. Fire return event. */
7547 /* An earlier event's hook at this pc may have freed bmethod_local_hooks
7548 * (see VM_TRACE_HOOK); reload it from its stable source. */
7549 if (bmethod_hooks_cnt > 0) bmethod_local_hooks = rb_method_def_local_hooks(bmethod_def, r, false);
7550 vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_RETURN, RUBY_EVENT_RETURN, global_hooks, bmethod_local_hooks, TOPN(0));
7551 }
7552 }
7553 }
7554}
7555#undef VM_TRACE_HOOK
7556
7557#if VM_CHECK_MODE > 0
7558NORETURN( NOINLINE( COLDFUNC
7559void rb_vm_canary_is_found_dead(enum ruby_vminsn_type i, VALUE c)));
7560
7561void
7562Init_vm_stack_canary(void)
7563{
7564 /* This has to be called _after_ our PRNG is properly set up. */
7565 int n = ruby_fill_random_bytes(&vm_stack_canary, sizeof vm_stack_canary, false);
7566 vm_stack_canary |= 0x01; // valid VALUE (Fixnum)
7567
7568 vm_stack_canary_was_born = true;
7569 VM_ASSERT(n == 0);
7570}
7571
7572void
7573rb_vm_canary_is_found_dead(enum ruby_vminsn_type i, VALUE c)
7574{
7575 /* Because a method has already been called, why not call
7576 * another one. */
7577 const char *insn = rb_insns_name(i);
7578 VALUE inspection = rb_inspect(c);
7579 const char *str = StringValueCStr(inspection);
7580
7581 rb_bug("dead canary found at %s: %s", insn, str);
7582}
7583
7584#else
7585void Init_vm_stack_canary(void) { /* nothing to do */ }
7586#endif
7587
7588
7589/* a part of the following code is generated by this ruby script:
7590
759116.times{|i|
7592 typedef_args = (0...i).map{|j| "VALUE v#{j+1}"}.join(", ")
7593 typedef_args.prepend(", ") if i != 0
7594 call_args = (0...i).map{|j| "argv[#{j}]"}.join(", ")
7595 call_args.prepend(", ") if i != 0
7596 puts %Q{
7597static VALUE
7598builtin_invoker#{i}(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7599{
7600 typedef VALUE (*rb_invoke_funcptr#{i}_t)(rb_execution_context_t *ec, VALUE self#{typedef_args});
7601 return (*(rb_invoke_funcptr#{i}_t)funcptr)(ec, self#{call_args});
7602}}
7603}
7604
7605puts
7606puts "static VALUE (* const cfunc_invokers[])(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr) = {"
760716.times{|i|
7608 puts " builtin_invoker#{i},"
7609}
7610puts "};"
7611*/
7612
7613static VALUE
7614builtin_invoker0(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7615{
7616 typedef VALUE (*rb_invoke_funcptr0_t)(rb_execution_context_t *ec, VALUE self);
7617 return (*(rb_invoke_funcptr0_t)funcptr)(ec, self);
7618}
7619
7620static VALUE
7621builtin_invoker1(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7622{
7623 typedef VALUE (*rb_invoke_funcptr1_t)(rb_execution_context_t *ec, VALUE self, VALUE v1);
7624 return (*(rb_invoke_funcptr1_t)funcptr)(ec, self, argv[0]);
7625}
7626
7627static VALUE
7628builtin_invoker2(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7629{
7630 typedef VALUE (*rb_invoke_funcptr2_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2);
7631 return (*(rb_invoke_funcptr2_t)funcptr)(ec, self, argv[0], argv[1]);
7632}
7633
7634static VALUE
7635builtin_invoker3(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7636{
7637 typedef VALUE (*rb_invoke_funcptr3_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3);
7638 return (*(rb_invoke_funcptr3_t)funcptr)(ec, self, argv[0], argv[1], argv[2]);
7639}
7640
7641static VALUE
7642builtin_invoker4(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7643{
7644 typedef VALUE (*rb_invoke_funcptr4_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4);
7645 return (*(rb_invoke_funcptr4_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3]);
7646}
7647
7648static VALUE
7649builtin_invoker5(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7650{
7651 typedef VALUE (*rb_invoke_funcptr5_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5);
7652 return (*(rb_invoke_funcptr5_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4]);
7653}
7654
7655static VALUE
7656builtin_invoker6(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7657{
7658 typedef VALUE (*rb_invoke_funcptr6_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6);
7659 return (*(rb_invoke_funcptr6_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
7660}
7661
7662static VALUE
7663builtin_invoker7(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7664{
7665 typedef VALUE (*rb_invoke_funcptr7_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7);
7666 return (*(rb_invoke_funcptr7_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
7667}
7668
7669static VALUE
7670builtin_invoker8(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7671{
7672 typedef VALUE (*rb_invoke_funcptr8_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8);
7673 return (*(rb_invoke_funcptr8_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
7674}
7675
7676static VALUE
7677builtin_invoker9(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7678{
7679 typedef VALUE (*rb_invoke_funcptr9_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9);
7680 return (*(rb_invoke_funcptr9_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
7681}
7682
7683static VALUE
7684builtin_invoker10(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7685{
7686 typedef VALUE (*rb_invoke_funcptr10_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10);
7687 return (*(rb_invoke_funcptr10_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
7688}
7689
7690static VALUE
7691builtin_invoker11(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7692{
7693 typedef VALUE (*rb_invoke_funcptr11_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10, VALUE v11);
7694 return (*(rb_invoke_funcptr11_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
7695}
7696
7697static VALUE
7698builtin_invoker12(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7699{
7700 typedef VALUE (*rb_invoke_funcptr12_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10, VALUE v11, VALUE v12);
7701 return (*(rb_invoke_funcptr12_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
7702}
7703
7704static VALUE
7705builtin_invoker13(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7706{
7707 typedef VALUE (*rb_invoke_funcptr13_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10, VALUE v11, VALUE v12, VALUE v13);
7708 return (*(rb_invoke_funcptr13_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
7709}
7710
7711static VALUE
7712builtin_invoker14(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7713{
7714 typedef VALUE (*rb_invoke_funcptr14_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10, VALUE v11, VALUE v12, VALUE v13, VALUE v14);
7715 return (*(rb_invoke_funcptr14_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
7716}
7717
7718static VALUE
7719builtin_invoker15(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr)
7720{
7721 typedef VALUE (*rb_invoke_funcptr15_t)(rb_execution_context_t *ec, VALUE self, VALUE v1, VALUE v2, VALUE v3, VALUE v4, VALUE v5, VALUE v6, VALUE v7, VALUE v8, VALUE v9, VALUE v10, VALUE v11, VALUE v12, VALUE v13, VALUE v14, VALUE v15);
7722 return (*(rb_invoke_funcptr15_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
7723}
7724
7725typedef VALUE (*builtin_invoker)(rb_execution_context_t *ec, VALUE self, const VALUE *argv, rb_insn_func_t funcptr);
7726
7727static builtin_invoker
7728lookup_builtin_invoker(int argc)
7729{
7730 static const builtin_invoker invokers[] = {
7731 builtin_invoker0,
7732 builtin_invoker1,
7733 builtin_invoker2,
7734 builtin_invoker3,
7735 builtin_invoker4,
7736 builtin_invoker5,
7737 builtin_invoker6,
7738 builtin_invoker7,
7739 builtin_invoker8,
7740 builtin_invoker9,
7741 builtin_invoker10,
7742 builtin_invoker11,
7743 builtin_invoker12,
7744 builtin_invoker13,
7745 builtin_invoker14,
7746 builtin_invoker15,
7747 };
7748
7749 return invokers[argc];
7750}
7751
7752static inline VALUE
7753invoke_bf(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const struct rb_builtin_function* bf, const VALUE *argv)
7754{
7755 const bool canary_p = ISEQ_BODY(CFP_ISEQ(reg_cfp))->builtin_attrs & BUILTIN_ATTR_LEAF; // Verify an assumption of `Primitive.attr! :leaf`
7756 SETUP_CANARY(canary_p);
7757 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
7758 VALUE ret = (*lookup_builtin_invoker(bf->argc))(ec, reg_cfp->self, argv, func_ptr);
7759 CHECK_CANARY(canary_p, BIN(invokebuiltin));
7760 return ret;
7761}
7762
7763static VALUE
7764vm_invoke_builtin(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_builtin_function* bf, const VALUE *argv)
7765{
7766 return invoke_bf(ec, cfp, bf, argv);
7767}
7768
7769static VALUE
7770vm_invoke_builtin_delegate(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_builtin_function *bf, unsigned int start_index)
7771{
7772 if (0) { // debug print
7773 fputs("vm_invoke_builtin_delegate: passing -> ", stderr);
7774 for (int i=0; i<bf->argc; i++) {
7775 ruby_debug_printf(":%s ", rb_id2name(ISEQ_BODY(CFP_ISEQ(cfp))->local_table[i+start_index]));
7776 }
7777 ruby_debug_printf("\n" "%s %s(%d):%p\n", RUBY_FUNCTION_NAME_STRING, bf->name, bf->argc,
7778 (void *)(uintptr_t)bf->func_ptr);
7779 }
7780
7781 if (bf->argc == 0) {
7782 return invoke_bf(ec, cfp, bf, NULL);
7783 }
7784 else {
7785 const VALUE *argv = cfp->ep - ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
7786 return invoke_bf(ec, cfp, bf, argv);
7787 }
7788}
7789
7790// for __builtin_inline!()
7791
7792VALUE
7793rb_vm_lvar_exposed(rb_execution_context_t *ec, int index)
7794{
7795 const rb_control_frame_t *cfp = ec->cfp;
7796 return cfp->ep[index];
7797}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
Definition fl_type.h:407
static bool RB_FL_ABLE(VALUE obj)
Checks if the object is flaggable.
Definition fl_type.h:384
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
Definition fl_type.h:253
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:3051
VALUE rb_module_new(void)
Creates a new, anonymous module.
Definition class.c:1661
VALUE rb_class_inherited(VALUE super, VALUE klass)
Calls Class::inherited.
Definition class.c:1561
VALUE rb_define_class_id(ID id, VALUE super)
This is a very badly designed API that creates an anonymous class.
Definition class.c:1540
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition value_type.h:67
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
Definition value_type.h:79
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define T_NONE
Old name of RUBY_T_NONE.
Definition value_type.h:74
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define FIX2ULONG
Old name of RB_FIX2ULONG.
Definition long.h:47
#define T_TRUE
Old name of RUBY_T_TRUE.
Definition value_type.h:81
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:658
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define T_FALSE
Old name of RUBY_T_FALSE.
Definition value_type.h:61
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define T_OBJECT
Old name of RUBY_T_OBJECT.
Definition value_type.h:75
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define FL_USHIFT
Old name of RUBY_FL_USHIFT.
Definition fl_type.h:67
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
Definition fl_type.h:126
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eFatal
fatal exception.
Definition error.c:1469
VALUE rb_eNoMethodError
NoMethodError exception.
Definition error.c:1481
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:691
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
void rb_error_frozen_object(VALUE frozen_obj)
Identical to rb_error_frozen(), except it takes arbitrary Ruby object instead of C's string.
Definition error.c:4336
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
Definition error.c:1524
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_cClass
Class class.
Definition object.c:62
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2252
VALUE rb_cRegexp
Regexp class.
Definition re.c:2828
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
Definition object.c:1316
VALUE rb_cHash
Hash class.
Definition hash.c:123
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:669
VALUE rb_cBasicObject
BasicObject class.
Definition object.c:58
VALUE rb_cModule
Module class.
Definition object.c:61
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:225
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:906
VALUE rb_cFloat
Float class.
Definition numeric.c:201
VALUE rb_cProc
Proc class.
Definition proc.c:46
VALUE rb_cString
String class.
Definition string.c:85
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_includes(VALUE ary, VALUE elem)
Queries if the passed array has the passed entry.
VALUE rb_ary_plus(VALUE lhs, VALUE rhs)
Creates a new array, concatenating the former to the latter.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE proc)
Identical to rb_proc_call(), except you can additionally pass another proc object,...
Definition proc.c:1763
VALUE rb_reg_last_match(VALUE md)
This just returns the argument, stringified.
Definition re.c:2095
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
Definition re.c:3970
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
Definition re.c:2071
VALUE rb_reg_match_post(VALUE md)
The portion of the original string after the given match.
Definition re.c:2150
VALUE rb_reg_nth_defined(int n, VALUE md)
Identical to rb_reg_nth_match(), except it just returns Boolean.
Definition re.c:2055
VALUE rb_reg_match_pre(VALUE md)
The portion of the original string before the given match.
Definition re.c:2119
VALUE rb_reg_match_last(VALUE md)
The portion of the original string that captured at the very last.
Definition re.c:2179
bool rb_set_lookup(VALUE set, VALUE element)
Whether the set contains the given element.
Definition set.c:2350
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3906
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
Definition string.c:5450
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3872
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4143
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1657
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
Definition string.c:2499
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:1085
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3505
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2141
void rb_cvar_set(VALUE klass, ID name, VALUE val)
Assigns a value to a class variable.
Definition variable.c:4294
VALUE rb_cvar_find(VALUE klass, ID name, VALUE *front)
Identical to rb_cvar_get(), except it takes additional "front" pointer.
Definition variable.c:4354
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1641
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:3984
VALUE rb_autoload_load(VALUE space, ID name)
Kicks the autoload procedure as if it was "touched".
Definition variable.c:3335
VALUE rb_mod_name(VALUE mod)
Queries the name of a module.
Definition variable.c:152
VALUE rb_const_get_at(VALUE space, ID name)
Identical to rb_const_defined_at(), except it returns the actual defined value.
Definition variable.c:3511
void rb_set_class_path_string(VALUE klass, VALUE space, VALUE name)
Identical to rb_set_class_path(), except it accepts the name as Ruby's string instead of C's.
Definition variable.c:441
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
Definition variable.c:2201
int rb_const_defined_at(VALUE space, ID name)
Identical to rb_const_defined(), except it doesn't look for parent classes.
Definition variable.c:3844
VALUE rb_cvar_defined(VALUE klass, ID name)
Queries if the given class has the given class variable.
Definition variable.c:4380
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:398
int rb_const_defined(VALUE space, ID name)
Queries if the constant is defined at the namespace.
Definition variable.c:3838
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition vm_method.c:3561
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:691
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries the allocator function of a class.
Definition vm_method.c:1852
int rb_method_boundp(VALUE klass, ID id, int ex)
Queries if the klass has this method.
Definition vm_method.c:2462
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1289
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
Definition ractor.h:269
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
#define RB_NOGVL_UBF_ASYNC_SAFE
Passing this flag to rb_nogvl() indicates that the passed UBF is async-signal-safe.
Definition thread.h:71
#define RB_NOGVL_INTR_FAIL
Passing this flag to rb_nogvl() prevents it from processing interrupts after the given function retur...
Definition thread.h:50
void * rb_nogvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int flags)
Identical to rb_thread_call_without_gvl(), except it additionally takes "flags" that change the behav...
Definition thread.c:1773
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
static VALUE * RARRAY_PTR(VALUE ary)
Wild use of a C pointer.
Definition rarray.h:365
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define RCLASS_SUPER
Just another name of rb_class_get_superclass.
Definition rclass.h:44
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
Definition rhash.h:79
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RB_PASS_KEYWORDS
Pass keywords, final argument must be a hash of keywords.
Definition scan_args.h:72
#define RB_NO_KEYWORDS
Do not pass keywords.
Definition scan_args.h:69
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define ANYARGS
Functions declared using this macro take arbitrary arguments, including void.
Definition stdarg.h:64
Ruby's array.
Definition rarray.h:127
const VALUE ary[1]
Embedded elements.
Definition rarray.h:187
const VALUE * ptr
Pointer to the C array that holds the elements of the array.
Definition rarray.h:174
Definition hash.h:54
Definition iseq.h:367
Definition vm_core.h:260
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:287
Definition vm_core.h:295
Definition vm_core.h:290
Internal header for Ruby Box.
Definition box.h:14
Definition method.h:63
Definition constant.h:33
CREF (Class REFerence)
Definition method.h:45
Internal header for Class.
Definition class.h:31
Definition method.h:55
rb_cref_t * cref
class reference, should be marked
Definition method.h:144
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:143
Definition st.h:79
IFUNC (Internal FUNCtion)
Definition imemo.h:87
SVAR (Special VARiable)
Definition imemo.h:52
const VALUE cref_or_me
class reference or rb_method_entry_t
Definition imemo.h:54
THROW_DATA.
Definition imemo.h:61
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
Waits for the passed condition variable to be signalled.
Definition vm_core.h:299
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
Definition value_type.h:182
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
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