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