11#include "ruby/internal/config.h"
15#ifdef HAVE_STDATOMIC_H
16 #include <stdatomic.h>
20#include "debug_counter.h"
22#include "internal/class.h"
23#include "internal/compar.h"
24#include "internal/hash.h"
25#include "internal/numeric.h"
26#include "internal/proc.h"
27#include "internal/random.h"
28#include "internal/variable.h"
29#include "internal/set.h"
30#include "internal/set_table.h"
31#include "internal/struct.h"
37#include "insns_info.inc"
43 int argc,
const VALUE *argv,
int priv);
53ruby_vm_special_exception_copy(
VALUE exc)
56 rb_obj_copy_ivar(e, exc);
64 VALUE mesg = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_sysstack];
65 ec->raised_flag = RAISED_STACKOVERFLOW;
67 VALUE at = rb_ec_backtrace_object(ec);
68 mesg = ruby_vm_special_exception_copy(mesg);
73 EC_JUMP_TAG(ec, TAG_RAISE);
76NORETURN(
static void vm_stackoverflow(
void));
81 ec_stack_overflow(GET_EC(), TRUE);
88 rb_bug(
"system stack overflow during GC. Faulty native extension?");
90 if (crit >= rb_stack_overflow_fatal) {
91 ec->raised_flag = RAISED_STACKOVERFLOW;
92 ec->errinfo = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_stackfatal];
93 EC_JUMP_TAG(ec, TAG_RAISE);
95 ec_stack_overflow(ec, crit < rb_stack_overflow_signal);
102callable_class_p(
VALUE klass)
104#if VM_CHECK_MODE >= 2
105 if (!klass)
return FALSE;
133 VM_ASSERT(IMEMO_TYPE_P((
VALUE)cme, imemo_ment),
"imemo_type:%s", rb_imemo_name(imemo_type((
VALUE)cme)));
135 if (callable_class_p(cme->defined_class)) {
145vm_check_frame_detail(
VALUE type,
int req_block,
int req_me,
int req_cref,
VALUE specval,
VALUE cref_or_me,
int is_cframe,
const rb_iseq_t *iseq)
147 unsigned int magic = (
unsigned int)(
type & VM_FRAME_MAGIC_MASK);
148 enum imemo_type cref_or_me_type = imemo_env;
151 cref_or_me_type = imemo_type(cref_or_me);
153 if (
type & VM_FRAME_FLAG_BMETHOD) {
157 if (req_block && (
type & VM_ENV_FLAG_LOCAL) == 0) {
158 rb_bug(
"vm_push_frame: specval (%p) should be a block_ptr on %x frame", (
void *)specval, magic);
160 if (!req_block && (
type & VM_ENV_FLAG_LOCAL) != 0) {
161 rb_bug(
"vm_push_frame: specval (%p) should not be a block_ptr on %x frame", (
void *)specval, magic);
165 if (cref_or_me_type != imemo_ment) {
166 rb_bug(
"vm_push_frame: (%s) should be method entry on %x frame", rb_obj_info(cref_or_me), magic);
170 if (req_cref && cref_or_me_type != imemo_cref) {
171 rb_bug(
"vm_push_frame: (%s) should be CREF on %x frame", rb_obj_info(cref_or_me), magic);
174 if (cref_or_me !=
Qfalse && cref_or_me_type != imemo_cref) {
175 if (((
type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC || magic == VM_FRAME_MAGIC_DUMMY) && (cref_or_me_type == imemo_ment)) {
179 rb_bug(
"vm_push_frame: (%s) should be false or cref on %x frame", rb_obj_info(cref_or_me), magic);
185 if (cref_or_me_type == imemo_ment) {
188 if (!callable_method_entry_p(me)) {
189 rb_bug(
"vm_push_frame: ment (%s) should be callable on %x frame.", rb_obj_info(cref_or_me), magic);
193 if ((
type & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
194 VM_ASSERT(iseq == NULL ||
196 RUBY_VM_NORMAL_ISEQ_P(iseq)
200 VM_ASSERT(is_cframe == !RUBY_VM_NORMAL_ISEQ_P(iseq));
210 VALUE given_magic =
type & VM_FRAME_MAGIC_MASK;
213#define CHECK(magic, req_block, req_me, req_cref, is_cframe) \
215 vm_check_frame_detail(type, req_block, req_me, req_cref, \
216 specval, cref_or_me, is_cframe, iseq); \
218 switch (given_magic) {
220 CHECK(VM_FRAME_MAGIC_METHOD, TRUE, TRUE, FALSE, FALSE);
221 CHECK(VM_FRAME_MAGIC_CLASS, TRUE, FALSE, TRUE, FALSE);
222 CHECK(VM_FRAME_MAGIC_TOP, TRUE, FALSE, TRUE, FALSE);
223 CHECK(VM_FRAME_MAGIC_CFUNC, TRUE, TRUE, FALSE, TRUE);
224 CHECK(VM_FRAME_MAGIC_BLOCK, FALSE, FALSE, FALSE, FALSE);
225 CHECK(VM_FRAME_MAGIC_IFUNC, FALSE, FALSE, FALSE, TRUE);
226 CHECK(VM_FRAME_MAGIC_EVAL, FALSE, FALSE, FALSE, FALSE);
227 CHECK(VM_FRAME_MAGIC_RESCUE, FALSE, FALSE, FALSE, FALSE);
228 CHECK(VM_FRAME_MAGIC_DUMMY, TRUE, FALSE, FALSE, FALSE);
230 rb_bug(
"vm_push_frame: unknown type (%x)", (
unsigned int)given_magic);
235static VALUE vm_stack_canary;
236static bool vm_stack_canary_was_born =
false;
243 unsigned int pos = 0;
244 while (pos < ISEQ_BODY(iseq)->iseq_size) {
245 int opcode = rb_vm_insn_addr2opcode((
void *)ISEQ_BODY(iseq)->iseq_encoded[pos]);
246 unsigned int next_pos = pos + insn_len(opcode);
247 if (ISEQ_BODY(iseq)->iseq_encoded + next_pos == pc) {
252 rb_bug(
"failed to find the previous insn");
261 if (! LIKELY(vm_stack_canary_was_born)) {
264 else if ((
VALUE *)reg_cfp == ec->vm_stack + ec->vm_stack_size) {
268 else if (! VM_FRAME_RUBYFRAME_P(reg_cfp) || ! (iseq = GET_ISEQ())) {
272 else if (LIKELY(sp[0] != vm_stack_canary)) {
281 const VALUE *orig = rb_iseq_original_iseq(iseq);
282 const VALUE iseqw = rb_iseqw_new(iseq);
284 const char *stri = rb_str_to_cstr(inspection);
285 const VALUE disasm = rb_iseq_disasm(iseq);
286 const char *strd = rb_str_to_cstr(disasm);
287 const ptrdiff_t pos = previous_insn_index(iseq, GET_PC());
288 const enum ruby_vminsn_type insn = (
enum ruby_vminsn_type)orig[pos];
289 const char *name = insn_name(insn);
295 "We are killing the stack canary set by %s, "
296 "at %s@pc=%"PRIdPTR
"\n"
297 "watch out the C stack trace.\n"
299 name, stri, pos, strd);
300 rb_bug(
"see above.");
302#define vm_check_canary(ec, sp) rb_vm_check_canary(ec, sp)
305#define vm_check_canary(ec, sp)
306#define vm_check_frame(a, b, c, d)
311vm_push_frame_debug_counter_inc(
318 RB_DEBUG_COUNTER_INC(frame_push);
320 if (RUBY_VM_END_CONTROL_FRAME(ec) != prev_cfp) {
321 const bool curr = VM_FRAME_RUBYFRAME_P(reg_cfp);
322 const bool prev = VM_FRAME_RUBYFRAME_P(prev_cfp);
325 RB_DEBUG_COUNTER_INC(frame_R2R);
328 RB_DEBUG_COUNTER_INC(frame_R2C);
333 RB_DEBUG_COUNTER_INC(frame_C2R);
336 RB_DEBUG_COUNTER_INC(frame_C2C);
341 switch (
type & VM_FRAME_MAGIC_MASK) {
342 case VM_FRAME_MAGIC_METHOD: RB_DEBUG_COUNTER_INC(frame_push_method);
return;
343 case VM_FRAME_MAGIC_BLOCK: RB_DEBUG_COUNTER_INC(frame_push_block);
return;
344 case VM_FRAME_MAGIC_CLASS: RB_DEBUG_COUNTER_INC(frame_push_class);
return;
345 case VM_FRAME_MAGIC_TOP: RB_DEBUG_COUNTER_INC(frame_push_top);
return;
346 case VM_FRAME_MAGIC_CFUNC: RB_DEBUG_COUNTER_INC(frame_push_cfunc);
return;
347 case VM_FRAME_MAGIC_IFUNC: RB_DEBUG_COUNTER_INC(frame_push_ifunc);
return;
348 case VM_FRAME_MAGIC_EVAL: RB_DEBUG_COUNTER_INC(frame_push_eval);
return;
349 case VM_FRAME_MAGIC_RESCUE: RB_DEBUG_COUNTER_INC(frame_push_rescue);
return;
350 case VM_FRAME_MAGIC_DUMMY: RB_DEBUG_COUNTER_INC(frame_push_dummy);
return;
353 rb_bug(
"unreachable");
356#define vm_push_frame_debug_counter_inc(ec, cfp, t)
361rb_vm_stack_canary(
void)
364 return vm_stack_canary;
370STATIC_ASSERT(VM_ENV_DATA_INDEX_ME_CREF, VM_ENV_DATA_INDEX_ME_CREF == -2);
371STATIC_ASSERT(VM_ENV_DATA_INDEX_SPECVAL, VM_ENV_DATA_INDEX_SPECVAL == -1);
372STATIC_ASSERT(VM_ENV_DATA_INDEX_FLAGS, VM_ENV_DATA_INDEX_FLAGS == -0);
388 vm_check_frame(
type, specval, cref_or_me, iseq);
389 VM_ASSERT(local_size >= 0);
392 CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + stack_max);
393 vm_check_canary(ec, sp);
398 for (
int i=0; i < local_size; i++) {
425 #if defined HAVE_DECL_ATOMIC_SIGNAL_FENCE && HAVE_DECL_ATOMIC_SIGNAL_FENCE
426 atomic_signal_fence(memory_order_seq_cst);
434 vm_push_frame_debug_counter_inc(ec, cfp,
type);
442 if (VMDEBUG == 2) SDR();
444 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
451 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
453 if (VMDEBUG == 2) SDR();
455 RUBY_VM_CHECK_INTS(ec);
456 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
458 return flags & VM_FRAME_FLAG_FINISH;
464 vm_pop_frame(ec, ec->cfp, ec->cfp->ep);
472 rb_iseq_t *dmy_iseq = rb_iseq_alloc_with_dummy_path(fname);
476 VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
478 VM_BLOCK_HANDLER_NONE,
485 return (
VALUE)dmy_iseq;
490rb_arity_error_new(
int argc,
int min,
int max)
492 VALUE err_mess = rb_sprintf(
"wrong number of arguments (given %d, expected %d", argc, min);
500 rb_str_catf(err_mess,
"..%d", max);
507rb_error_arity(
int argc,
int min,
int max)
514NOINLINE(
static void vm_env_write_slowpath(
const VALUE *ep,
int index,
VALUE v));
517vm_env_write_slowpath(
const VALUE *ep,
int index,
VALUE v)
519 const VALUE envval = VM_ENV_ENVVAL(ep);
526 rb_gc_writebarrier(envval, v);
528 VM_FORCE_WRITE(&ep[index], v);
532 rb_gc_writebarrier_remember(envval);
533 VM_FORCE_WRITE(&ep[index], v);
534 VM_ENV_FLAGS_UNSET(ep, VM_ENV_FLAG_WB_REQUIRED);
536 RB_DEBUG_COUNTER_INC(lvar_set_slowpath);
541vm_env_write(
const VALUE *ep,
int index,
VALUE v)
543 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
544 if (LIKELY((flags & VM_ENV_FLAG_WB_REQUIRED) == 0)) {
545 VM_STACK_ENV_WRITE(ep, index, v);
548 vm_env_write_slowpath(ep, index, v);
553rb_vm_env_write(
const VALUE *ep,
int index,
VALUE v)
555 vm_env_write(ep, index, v);
561 if (block_handler == VM_BLOCK_HANDLER_NONE) {
565 switch (vm_block_handler_type(block_handler)) {
566 case block_handler_type_iseq:
567 case block_handler_type_ifunc:
568 return rb_vm_make_proc(ec, VM_BH_TO_CAPT_BLOCK(block_handler),
rb_cProc);
569 case block_handler_type_symbol:
570 return rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler));
571 case block_handler_type_proc:
572 return VM_BH_TO_PROC(block_handler);
574 VM_UNREACHABLE(rb_vm_bh_to_procval);
583vm_svar_valid_p(
VALUE svar)
586 switch (imemo_type(svar)) {
595 rb_bug(
"vm_svar_valid_p: unknown type: %s", rb_obj_info(svar));
606 if (!lep)
return false;
607 if (ec == NULL)
return true;
608 if (ec->root_lep == lep)
return false;
612 if (
FIXNUM_P(lep[VM_ENV_DATA_INDEX_FLAGS]) &&
613 VM_ENV_ESCAPED_P(lep) &&
625 if (lep_svar_in_env_p(ec, lep)) {
626 svar = lep[VM_ENV_DATA_INDEX_ME_CREF];
629 svar = ec->root_svar;
632 VM_ASSERT(svar ==
Qfalse || vm_svar_valid_p(svar));
640 VM_ASSERT(vm_svar_valid_p((
VALUE)svar));
642 if (lep_svar_in_env_p(ec, lep)) {
643 vm_env_write(lep, VM_ENV_DATA_INDEX_ME_CREF, (
VALUE)svar);
646 RB_OBJ_WRITE(rb_ec_thread_ptr(ec)->self, &ec->root_svar, svar);
653 const struct vm_svar *svar = lep_svar(ec, lep);
658 case VM_SVAR_LASTLINE:
659 return svar->lastline;
660 case VM_SVAR_BACKREF:
661 return svar->backref;
663 const VALUE ary = svar->others;
678 struct vm_svar *svar = IMEMO_NEW(
struct vm_svar, imemo_svar, obj);
689 struct vm_svar *svar = lep_svar(ec, lep);
692 lep_svar_write(ec, lep, svar = svar_new((
VALUE)svar));
696 case VM_SVAR_LASTLINE:
699 case VM_SVAR_BACKREF:
703 VALUE ary = svar->others;
719 val = lep_svar_get(ec, lep, key);
722 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
739 rb_bug(
"unexpected back-ref");
752 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
762 return rb_reg_last_defined(backref);
764 rb_bug(
"unexpected back-ref");
768 nth = (int)(
type >> 1);
775check_method_entry(
VALUE obj,
int can_be_svar)
777 if (obj ==
Qfalse)
return NULL;
780 if (!
RB_TYPE_P(obj,
T_IMEMO)) rb_bug(
"check_method_entry: unknown type: %s", rb_obj_info(obj));
783 switch (imemo_type(obj)) {
794 rb_bug(
"check_method_entry: svar should not be there:");
801env_method_entry_unchecked(
VALUE obj,
int can_be_svar)
803 if (obj ==
Qfalse)
return NULL;
805 switch (imemo_type(obj)) {
822 const VALUE *ep = cfp->ep;
825 while (!VM_ENV_LOCAL_P(ep)) {
826 if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return me;
827 ep = VM_ENV_PREV_EP(ep);
830 return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
836 const VALUE *ep = cfp->ep;
839 while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) {
840 if ((me = env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return me;
841 ep = VM_ENV_PREV_EP_UNCHECKED(ep);
844 return env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
850 switch (me->def->type) {
851 case VM_METHOD_TYPE_ISEQ:
852 return me->def->body.iseq.
iseqptr;
861 switch (me->def->type) {
862 case VM_METHOD_TYPE_ISEQ:
863 return me->def->body.iseq.
cref;
869#if VM_CHECK_MODE == 0
873check_cref(
VALUE obj,
int can_be_svar)
875 if (obj ==
Qfalse)
return NULL;
878 if (!
RB_TYPE_P(obj,
T_IMEMO)) rb_bug(
"check_cref: unknown type: %s", rb_obj_info(obj));
881 switch (imemo_type(obj)) {
892 rb_bug(
"check_method_entry: svar should not be there:");
899vm_env_cref(
const VALUE *ep)
903 while (!VM_ENV_LOCAL_P(ep)) {
904 if ((cref = check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return cref;
905 ep = VM_ENV_PREV_EP(ep);
908 return check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
912is_cref(
const VALUE v,
int can_be_svar)
915 switch (imemo_type(v)) {
928vm_env_cref_by_cref(
const VALUE *ep)
930 while (!VM_ENV_LOCAL_P(ep)) {
931 if (is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE))
return TRUE;
932 ep = VM_ENV_PREV_EP(ep);
934 return is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
938cref_replace_with_duplicated_cref_each_frame(
const VALUE *vptr,
int can_be_svar,
VALUE parent)
940 const VALUE v = *vptr;
944 switch (imemo_type(v)) {
947 new_cref = rb_vm_cref_dup(cref);
952 VM_FORCE_WRITE(vptr, (
VALUE)new_cref);
957 return cref_replace_with_duplicated_cref_each_frame(&((
struct vm_svar *)v)->
cref_or_me, FALSE, v);
961 rb_bug(
"cref_replace_with_duplicated_cref_each_frame: unreachable");
970vm_cref_replace_with_duplicated_cref(
const VALUE *ep)
972 if (vm_env_cref_by_cref(ep)) {
976 while (!VM_ENV_LOCAL_P(ep)) {
977 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) :
Qfalse;
978 if ((cref = cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE, envval)) != NULL) {
981 ep = VM_ENV_PREV_EP(ep);
983 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) :
Qfalse;
984 return cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE, envval);
987 rb_bug(
"vm_cref_dup: unreachable");
992vm_get_cref(
const VALUE *ep)
1000 rb_bug(
"vm_get_cref: unreachable");
1005rb_vm_get_cref(
const VALUE *ep)
1007 return vm_get_cref(ep);
1018 return vm_get_cref(cfp->ep);
1022vm_get_const_key_cref(
const VALUE *ep)
1024 const rb_cref_t *cref = vm_get_cref(ep);
1028 if (CREF_DYNAMIC(cref)) {
1031 cref = CREF_NEXT(cref);
1044 prev_cref = vm_env_cref(ep);
1050 prev_cref = vm_env_cref(cfp->ep);
1054 return vm_cref_new(klass, METHOD_VISI_PUBLIC, FALSE, prev_cref, pushed_by_eval, singleton);
1058vm_get_cbase(
const VALUE *ep)
1060 const rb_cref_t *cref = vm_get_cref(ep);
1062 return CREF_CLASS_FOR_DEFINITION(cref);
1066vm_get_const_base(
const VALUE *ep)
1068 const rb_cref_t *cref = vm_get_cref(ep);
1071 if (!CREF_PUSHED_BY_EVAL(cref)) {
1072 return CREF_CLASS_FOR_DEFINITION(cref);
1074 cref = CREF_NEXT(cref);
1081vm_check_if_namespace(
VALUE klass)
1084 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a class/module", klass);
1089vm_ensure_not_refinement_module(
VALUE self)
1092 rb_warn(
"not defined at the refinement, but at the outer class/module");
1108 if (
NIL_P(orig_klass) && allow_nil) {
1110 const rb_cref_t *root_cref = vm_get_cref(ec->cfp->ep);
1114 while (root_cref && CREF_PUSHED_BY_EVAL(root_cref)) {
1115 root_cref = CREF_NEXT(root_cref);
1118 while (cref && CREF_NEXT(cref)) {
1119 if (CREF_PUSHED_BY_EVAL(cref)) {
1123 klass = CREF_CLASS(cref);
1125 cref = CREF_NEXT(cref);
1127 if (!
NIL_P(klass)) {
1131 if ((ce = rb_const_lookup(klass,
id))) {
1132 rb_const_warn_if_deprecated(ce, klass,
id);
1135 if (am == klass)
break;
1137 if (is_defined)
return 1;
1138 if (rb_autoloading_value(klass,
id, &av, NULL))
return av;
1140 goto search_continue;
1147 if (UNLIKELY(!rb_class_owned_p(klass))) {
1149 rb_raise(rb_eRactorIsolationError,
1150 "can not access non-shareable objects in constant %"PRIsVALUE
"::%"PRIsVALUE
" of a class/module created by another Ractor.",
rb_class_path(klass), rb_id2str(
id));
1161 if (root_cref && !
NIL_P(CREF_CLASS(root_cref))) {
1162 klass = vm_get_iclass(ec->cfp, CREF_CLASS(root_cref));
1176 vm_check_if_namespace(orig_klass);
1178 return rb_public_const_defined_from(orig_klass,
id);
1181 return rb_public_const_get_from(orig_klass,
id);
1189 return vm_get_ev_const(ec, orig_klass,
id, allow_nil ==
Qtrue, 0);
1197 int allow_nil = TRUE;
1198 if (segments[0] == idNULL) {
1203 while (segments[idx]) {
1204 ID id = segments[idx++];
1205 val = vm_get_ev_const(ec, val,
id, allow_nil, 0);
1218 rb_bug(
"vm_get_cvar_base: no cref");
1221 while (CREF_NEXT(cref) &&
1222 (
NIL_P(CREF_CLASS(cref)) || RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
1223 CREF_PUSHED_BY_EVAL(cref) || CREF_SINGLETON(cref))) {
1224 cref = CREF_NEXT(cref);
1226 if (top_level_raise && !CREF_NEXT(cref)) {
1230 klass = vm_get_iclass(cfp, CREF_CLASS(cref));
1238#define ractor_incidental_shareable_p(cond, val) \
1239 (!(cond) || rb_ractor_shareable_p(val))
1240#define ractor_object_incidental_shareable_p(obj, val) \
1241 ractor_incidental_shareable_p(rb_ractor_shareable_p(obj), val)
1250 return default_value;
1255 fields_obj = ROBJECT_FIELDS_OBJ(obj);
1260 if (UNLIKELY(!rb_class_owned_p(obj))) {
1268 if (default_value ==
Qundef) {
1276 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1280 fields_obj = rb_obj_fields(obj,
id);
1284 return default_value;
1289 shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj);
1290 VALUE *ivar_list = rb_imemo_fields_ptr(fields_obj);
1292 rb_getivar_cache cache = rb_getivar_cache_unpack(vm_cache_attr_index_atomic_read(is_attr, ic, cc));
1294 if (LIKELY(cache.shape_offset == shape_id)) {
1295 if (cache.index == ATTR_INDEX_NOT_SET) {
1296 return default_value;
1299 val = ivar_list[cache.index];
1300#if USE_DEBUG_COUNTER
1301 RB_DEBUG_COUNTER_INC(ivar_get_ic_hit);
1304 RB_DEBUG_COUNTER_INC(ivar_get_obj_hit);
1310#if USE_DEBUG_COUNTER
1312 if (cache.shape_offset != INVALID_SHAPE_ID) {
1313 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set);
1316 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_unset);
1320 if (cache.shape_offset != INVALID_SHAPE_ID) {
1321 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set);
1324 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_unset);
1327 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1330 RB_DEBUG_COUNTER_INC(ivar_get_obj_miss);
1334 if (UNLIKELY(rb_shape_complex_p(shape_id))) {
1338 RUBY_ASSERT(table == rb_imemo_fields_complex_tbl(fields_obj));
1340 if (!st_lookup(table,
id, &val)) {
1341 val = default_value;
1345 shape_id_t previous_cached_offset = cache.shape_offset;
1346 if (rb_shape_get_iv_index_with_hint(shape_id,
id, &cache.index, &cache.shape_offset)) {
1347 if (cache.shape_offset != previous_cached_offset) {
1348 RUBY_ASSERT(!rb_shape_complex_p(cache.shape_offset));
1349 RUBY_ASSERT(cache.shape_offset != INVALID_SHAPE_ID);
1351 uint64_t packed_cache = rb_getivar_cache_pack(cache.shape_offset, cache.index);
1352 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1355 if (cache.index == ATTR_INDEX_NOT_SET) {
1356 val = default_value;
1360 val = ivar_list[cache.index];
1365 vm_cache_attr_index_set(is_attr, ic, cc, rb_getivar_cache_pack(shape_id, ATTR_INDEX_NOT_SET));
1366 val = default_value;
1371 if (!UNDEF_P(default_value)) {
1379 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1382 return rb_attr_get(obj,
id);
1397 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
1399 rb_check_ivar_modifiable(obj);
1401 shape_id_t previous_shape_id = RBASIC_SHAPE_ID(obj);
1402 attr_index_t index = rb_ivar_set_index(obj,
id, val);
1403 shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj);
1405 if (!rb_shape_complex_p(next_shape_id)) {
1406 uint64_t packed_cache = rb_setivar_cache_pack(RSHAPE_OFFSET(previous_shape_id), RSHAPE_OFFSET(next_shape_id), index);
1407 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1410 RB_DEBUG_COUNTER_INC(ivar_set_obj_miss);
1420 return vm_setivar_slowpath(obj,
id, val, iseq, ic, NULL,
false);
1426 return vm_setivar_slowpath(obj,
id, val, NULL, NULL, cc,
true);
1433 if (UNLIKELY(!rb_class_owned_p(obj))) {
1437 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1438 if (UNLIKELY(!fields_obj)) {
1442 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
1443 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1444 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1448 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1450 if (shape_id != dest_shape_id) {
1451 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1452 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1455 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1464 VALUE fields_obj = rb_obj_fields(obj,
id);
1465 if (UNLIKELY(!fields_obj)) {
1469 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1470 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1471 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1475 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1477 if (shape_id != dest_shape_id) {
1478 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1479 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1482 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1496 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1497 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, shape_id, cache);
1498 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1502 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
1503 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1504 if (shape_id != dest_shape_id) {
1505 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1506 if (fields_obj != obj) {
1507 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1511 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1512 RB_DEBUG_COUNTER_INC(ivar_set_obj_hit);
1518 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject);
1530 VALUE defined_class = 0;
1534 defined_class =
RBASIC(defined_class)->klass;
1537 VALUE rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
1539 rb_bug(
"the cvc table should be set");
1543 if (!rb_marked_id_table_lookup(rb_cvc_tbl,
id, &ent_data)) {
1544 rb_bug(
"should have cvar cache entry");
1549 ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
1562 cref = vm_get_cref(GET_EP());
1566 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1567 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1568 RB_DEBUG_COUNTER_INC(cvar_read_inline_hit);
1570 VALUE v = rb_ivar_lookup(ic->entry->class_value,
id,
Qundef);
1576 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1578 return update_classvariable_cache(iseq, klass,
id, cref, ic);
1584 return vm_getclassvariable(iseq, cfp,
id, ic);
1591 cref = vm_get_cref(GET_EP());
1594 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1595 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1596 RB_DEBUG_COUNTER_INC(cvar_write_inline_hit);
1598 rb_class_ivar_set(ic->entry->class_value,
id, val);
1602 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1606 update_classvariable_cache(iseq, klass,
id, cref, ic);
1612 vm_setclassvariable(iseq, cfp,
id, val, ic);
1619 return vm_getivar(obj,
id, iseq, ic, NULL, FALSE,
Qnil);
1630 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_ic_atomic_cache_read(ic));
1631 if (UNLIKELY(UNDEF_P(vm_setivar(obj, val, cache)))) {
1637 if (!UNDEF_P(vm_setivar_class(obj, val, cache))) {
1642 if (!UNDEF_P(vm_setivar_default(obj,
id, val, cache))) {
1646 vm_setivar_slowpath_ivar(obj,
id, val, iseq, ic);
1653 vm_setinstancevariable(iseq, obj,
id, val, ic);
1659 return vm_getinstancevariable(iseq, obj,
id, ic);
1668 ec->tag->state = RUBY_TAG_FATAL;
1671 ec->tag->state = TAG_THROW;
1673 else if (THROW_DATA_P(err)) {
1674 ec->tag->state = THROW_DATA_STATE((
struct vm_throw_data *)err);
1677 ec->tag->state = TAG_RAISE;
1684 const int flag,
const VALUE throwobj)
1692 else if (state == TAG_BREAK) {
1694 const VALUE *ep = GET_EP();
1695 const rb_iseq_t *base_iseq = GET_ISEQ();
1696 escape_cfp = reg_cfp;
1698 while (ISEQ_BODY(base_iseq)->
type != ISEQ_TYPE_BLOCK) {
1699 if (ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_CLASS) {
1700 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1701 ep = escape_cfp->ep;
1702 base_iseq = CFP_ISEQ(escape_cfp);
1705 ep = VM_ENV_PREV_EP(ep);
1706 base_iseq = ISEQ_BODY(base_iseq)->parent_iseq;
1707 escape_cfp = rb_vm_search_cf_from_ep(ec, escape_cfp, ep);
1708 VM_ASSERT(CFP_ISEQ(escape_cfp) == base_iseq);
1712 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1718 ep = VM_ENV_PREV_EP(ep);
1720 while (escape_cfp < eocfp) {
1721 if (escape_cfp->ep == ep) {
1722 const rb_iseq_t *
const iseq = CFP_ISEQ(escape_cfp);
1723 const VALUE epc = CFP_PC(escape_cfp) - ISEQ_BODY(iseq)->iseq_encoded;
1728 for (i=0; i < ct->size; i++) {
1730 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1732 if (entry->type == CATCH_TYPE_BREAK &&
1733 entry->iseq == base_iseq &&
1734 entry->start < epc && entry->end >= epc) {
1735 if (entry->cont == epc) {
1744 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1749 rb_vm_localjump_error(
"break from proc-closure", throwobj, TAG_BREAK);
1752 else if (state == TAG_RETRY) {
1753 const VALUE *ep = VM_ENV_PREV_EP(GET_EP());
1755 escape_cfp = rb_vm_search_cf_from_ep(ec, reg_cfp, ep);
1757 else if (state == TAG_RETURN) {
1758 const VALUE *current_ep = GET_EP();
1759 const VALUE *target_ep = NULL, *target_lep, *ep = current_ep;
1760 int in_class_frame = 0;
1762 escape_cfp = reg_cfp;
1765 while (!VM_ENV_LOCAL_P(ep)) {
1766 if (VM_ENV_FLAGS(ep, VM_FRAME_FLAG_LAMBDA) && target_ep == NULL) {
1769 ep = VM_ENV_PREV_EP(ep);
1773 while (escape_cfp < eocfp) {
1774 const VALUE *lep = VM_CF_LEP(escape_cfp);
1780 if (lep == target_lep &&
1781 VM_FRAME_RUBYFRAME_P(escape_cfp) &&
1782 ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_CLASS) {
1787 if (lep == target_lep) {
1788 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1790 if (in_class_frame) {
1795 const VALUE *tep = current_ep;
1797 while (target_lep != tep) {
1798 if (escape_cfp->ep == tep) {
1800 if (tep == target_ep) {
1804 goto unexpected_return;
1807 tep = VM_ENV_PREV_EP(tep);
1811 else if (VM_FRAME_RUBYFRAME_P(escape_cfp)) {
1812 switch (ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type) {
1814 case ISEQ_TYPE_MAIN:
1816 if (in_class_frame)
goto unexpected_return;
1817 if (target_ep == NULL) {
1821 goto unexpected_return;
1825 case ISEQ_TYPE_EVAL: {
1826 const rb_iseq_t *is = CFP_ISEQ(escape_cfp);
1827 enum rb_iseq_type t = ISEQ_BODY(is)->type;
1828 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE || t == ISEQ_TYPE_EVAL) {
1829 if (!(is = ISEQ_BODY(is)->parent_iseq))
break;
1830 t = ISEQ_BODY(is)->type;
1832 toplevel = t == ISEQ_TYPE_TOP || t == ISEQ_TYPE_MAIN;
1835 case ISEQ_TYPE_CLASS:
1844 if (escape_cfp->ep == target_lep && ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_METHOD) {
1845 if (target_ep == NULL) {
1849 goto unexpected_return;
1853 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1856 rb_vm_localjump_error(
"unexpected return", throwobj, TAG_RETURN);
1862 rb_bug(
"isns(throw): unsupported throw type");
1865 ec->tag->state = state;
1866 return (
VALUE)THROW_DATA_NEW(throwobj, escape_cfp, state);
1871 rb_num_t throw_state,
VALUE throwobj)
1873 const int state = (int)(throw_state & VM_THROW_STATE_MASK);
1874 const int flag = (int)(throw_state & VM_THROW_NO_ESCAPE_FLAG);
1877 return vm_throw_start(ec, reg_cfp, state, flag, throwobj);
1880 return vm_throw_continue(ec, throwobj);
1888 return vm_throw(ec, reg_cfp, throw_state, throwobj);
1897 VALUE val = vm_throw(ec, reg_cfp, throw_state, throwobj);
1902 enum ruby_tag_type state = ec->tag->state;
1904 EC_JUMP_TAG(ec, state);
1912 int is_splat = flag & 0x01;
1915 const VALUE obj = ary;
1927 if (num + is_splat == 0) {
1930 else if (flag & 0x02) {
1935 for (i = 0; i < num -
len; i++) {
1940 for (j = 0; i < num; i++, j++) {
1962 for (; i < num -
len; i++) {
1966 for (rb_num_t j = 0; i < num; i++, j++) {
1967 *cfp->sp++ = ptr[
len - j - 1];
1971 for (rb_num_t j = 0; j < num; j++) {
1972 *cfp->sp++ = ptr[num - j - 1];
1987 int initial_capa = 2;
1989#if VM_CHECK_MODE > 0
1990 ccs->debug_sig = ~(
VALUE)ccs;
1992 ccs->capa = initial_capa;
1997 rb_managed_id_table_insert(cc_tbl, mid, (
VALUE)ccs);
2005 if (! vm_cc_markable(cc)) {
2009 if (UNLIKELY(ccs->len == ccs->capa)) {
2012 ccs = ruby_xrealloc(ccs, vm_ccs_alloc_size(ccs->capa));
2013#if VM_CHECK_MODE > 0
2014 ccs->debug_sig = ~(
VALUE)ccs;
2017 rb_managed_id_table_insert(cc_tbl, mid, (
VALUE)ccs);
2019 VM_ASSERT(ccs->len < ccs->capa);
2022 const int pos = ccs->len++;
2023 ccs->entries[pos].argc = vm_ci_argc(ci);
2024 ccs->entries[pos].flag = (
unsigned short)vm_ci_flag(ci);
2025 ccs->entries[pos].kw_len = (
unsigned short)(kwarg ? kwarg->keyword_len : 0);
2028 if (RB_DEBUG_COUNTER_SETMAX(ccs_maxlen, ccs->len)) {
2034#if VM_CHECK_MODE > 0
2038 ruby_debug_printf(
"ccs:%p (%d,%d)\n", (
void *)ccs, ccs->len, ccs->capa);
2039 for (
int i=0; i<ccs->len; i++) {
2040 ruby_debug_printf(
"CCS CI ID:flag:%x argc:%u kw_len:%u\n",
2041 ccs->entries[i].flag,
2042 ccs->entries[i].argc,
2043 ccs->entries[i].kw_len);
2044 rp(ccs->entries[i].cc);
2051 VM_ASSERT(vm_ccs_p(ccs));
2052 VM_ASSERT(ccs->len <= ccs->capa);
2054 for (
int i=0; i<ccs->len; i++) {
2057 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2058 VM_ASSERT(vm_cc_class_check(cc, klass));
2059 VM_ASSERT(vm_cc_check_cme(cc, ccs->cme));
2060 VM_ASSERT(!vm_cc_super_p(cc));
2061 VM_ASSERT(!vm_cc_refinement_p(cc));
2072 ASSERT_vm_locking();
2074 if (rb_multi_ractor_p()) {
2075 if (RCLASS_WRITABLE_CC_TBL(klass) != cc_tbl) {
2082 rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj);
2085 if (!ccs || !METHOD_ENTRY_INVALIDATED(ccs->cme)) {
2090 VALUE new_table = rb_vm_cc_table_dup(cc_tbl);
2091 rb_vm_cc_table_delete(new_table, mid);
2092 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), new_table);
2095 rb_vm_cc_table_delete(cc_tbl, mid);
2102 ASSERT_vm_locking();
2104 RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
2108 VM_ASSERT(cme == NULL || IMEMO_TYPE_P(cme, imemo_ment));
2112 VM_ASSERT(vm_cc_cme(&vm_empty_cc) == NULL);
2113 return &vm_empty_cc;
2116 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
2117 const VALUE original_cc_table = cc_tbl;
2120 cc_tbl = rb_vm_cc_table_create(1);
2122 else if (rb_multi_ractor_p()) {
2123 cc_tbl = rb_vm_cc_table_dup(cc_tbl);
2126 VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
2135 if (UNLIKELY(rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj))) {
2140 ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
2144 cme = rb_check_overloaded_cme(cme, ci);
2146 const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
2147 vm_ccs_push(cc_tbl, mid, ccs, ci, cc);
2149 VM_ASSERT(vm_cc_cme(cc) != NULL);
2150 VM_ASSERT(cme->called_id == mid);
2151 VM_ASSERT(vm_cc_cme(cc)->called_id == mid);
2153 if (original_cc_table != cc_tbl) {
2154 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), cc_tbl);
2166 cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
2174 if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj)) {
2176 const int ccs_len = ccs->len;
2178 if (UNLIKELY(METHOD_ENTRY_INVALIDATED(ccs->cme))) {
2180 vm_evict_cc(klass, cc_tbl, mid);
2185 VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
2194 unsigned int argc = vm_ci_argc(ci);
2195 unsigned int flag = vm_ci_flag(ci);
2196 unsigned int kw_len = kwarg ? kwarg->keyword_len : 0;
2198 for (
int i=0; i<ccs_len; i++) {
2199 unsigned int ccs_ci_argc = ccs->entries[i].argc;
2200 unsigned int ccs_ci_flag = ccs->entries[i].flag;
2201 unsigned int ccs_ci_kw_len = ccs->entries[i].kw_len;
2202 const struct rb_callcache *ccs_cc = ccs->entries[i].cc;
2204 VM_ASSERT(IMEMO_TYPE_P(ccs_cc, imemo_callcache));
2206 if (ccs_ci_argc == argc && ccs_ci_flag == flag && ccs_ci_kw_len == kw_len) {
2207 RB_DEBUG_COUNTER_INC(cc_found_in_ccs);
2209 VM_ASSERT(vm_cc_cme(ccs_cc)->called_id == mid);
2210 VM_ASSERT(ccs_cc->klass == klass);
2211 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(ccs_cc)));
2227 const ID mid = vm_ci_mid(ci);
2229 const struct rb_callcache *cc = vm_lookup_cc(klass, ci, mid);
2235 if (rb_multi_ractor_p()) {
2238 cc = vm_lookup_cc(klass, ci, mid);
2242 cc = vm_populate_cc(klass, ci, mid);
2262 rb_bug(
"attempted to search method '%s' on a garbage collected object",
2263 rb_id2name(vm_ci_mid(ci)));
2268 cc = vm_search_cc(klass, ci);
2271 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2272 VM_ASSERT(cc == vm_cc_empty() || cc->klass == klass);
2273 VM_ASSERT(cc == vm_cc_empty() || callable_method_entry_p(vm_cc_cme(cc)));
2274 VM_ASSERT(cc == vm_cc_empty() || !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)));
2275 VM_ASSERT(cc == vm_cc_empty() || vm_cc_cme(cc)->called_id == vm_ci_mid(ci));
2280#if VM_CHECK_MODE > 0
2285 return cd >= body->call_data && cd < body->call_data + body->ci_size;
2292#if USE_DEBUG_COUNTER
2297 const struct rb_callcache *cc = rb_vm_search_method_slowpath(cd->ci, klass);
2300#if OPT_INLINE_METHOD_CACHE
2304 if (cd_owner && cc != empty_cc) {
2307 VM_ASSERT(!vm_ci_markable(cd->ci) ||
2308 vm_cd_owned_by_iseq_p(cd, (
const rb_iseq_t *)cd_owner));
2312#if USE_DEBUG_COUNTER
2313 if (!old_cc || old_cc == empty_cc) {
2315 RB_DEBUG_COUNTER_INC(mc_inline_miss_empty);
2317 else if (old_cc == cc) {
2318 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cc);
2320 else if (old_cme == new_cme) {
2321 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cme);
2323 else if (old_cme && new_cme && old_cme->def == new_cme->def) {
2324 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_def);
2327 RB_DEBUG_COUNTER_INC(mc_inline_miss_diff);
2332 if (new_cme) VM_ASSERT(new_cme->called_id == vm_ci_mid(cd->ci));
2343#if OPT_INLINE_METHOD_CACHE
2344 if (LIKELY(vm_cc_class_check(cc, klass))) {
2345 if (LIKELY(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)))) {
2346 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
2347 RB_DEBUG_COUNTER_INC(mc_inline_hit);
2348 VM_ASSERT(vm_cc_cme(cc) == NULL ||
2349 (vm_ci_flag(cd->ci) & VM_CALL_SUPER) ||
2350 vm_cc_cme(cc)->called_id == vm_ci_mid(cd->ci));
2354 RB_DEBUG_COUNTER_INC(mc_inline_miss_invalidated);
2357 RB_DEBUG_COUNTER_INC(mc_inline_miss_klass);
2369 if (vm_cc_hit_p(cc, cd, klass)) {
2373 return vm_search_method_slowpath0((
VALUE)CFP_ISEQ(reg_cfp), cd, klass);
2380 VM_ASSERT(klass !=
Qfalse);
2383 const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
2384 return vm_cc_cme(cc);
2394 if (!vm_cc_hit_p(cc, cd, klass)) {
2395 cc = vm_search_method_slowpath0(cd_owner, cd, klass);
2397 return vm_cc_cme(cc);
2400#if __has_attribute(transparent_union)
2413 VALUE (*f10)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2414 VALUE (*f11)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2415 VALUE (*f12)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2416 VALUE (*f13)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2417 VALUE (*f14)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2418 VALUE (*f15)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2421# define make_cfunc_type(f) (cfunc_type){.anyargs = (VALUE (*)(ANYARGS))(f)}
2424# define make_cfunc_type(f) (cfunc_type)(f)
2434 VM_ASSERT(IMEMO_TYPE_P(me, imemo_ment));
2435 VM_ASSERT(callable_method_entry_p(me));
2437 if (me->def->type != VM_METHOD_TYPE_CFUNC) {
2441#if __has_attribute(transparent_union)
2442 return me->def->body.cfunc.func == func.anyargs;
2444 return me->def->body.cfunc.func == func;
2453 return me && METHOD_ENTRY_BASIC(me);
2459 VM_ASSERT(reg_cfp != NULL);
2461 return check_cfunc(cme, func);
2467 return check_cfunc(me, func);
2474 return check_cfunc(cme, func);
2477#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
2478#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))
2480#define OP_UNREDEFINED_P(op, t) BASIC_OP_UNREDEFINED_P(BOP_##op, t##_REDEFINED_OP_FLAG)
2481#define EQ_UNREDEFINED_P(t) OP_UNREDEFINED_P(EQ, t)
2513opt_equality_specialized(
VALUE recv,
VALUE obj)
2515 if (FIXNUM_2_P(recv, obj) && EQ_UNREDEFINED_P(INTEGER)) {
2516 goto compare_by_identity;
2518 else if (FLONUM_2_P(recv, obj) && EQ_UNREDEFINED_P(FLOAT)) {
2519 goto compare_by_identity;
2522 goto compare_by_identity;
2531 return RBOOL(a == b);
2538 return rb_str_eql_internal(obj, recv);
2543 compare_by_identity:
2544 return RBOOL(recv == obj);
2550 VM_ASSERT(reg_cfp != NULL);
2552 VALUE val = opt_equality_specialized(recv, obj);
2553 if (!UNDEF_P(val))
return val;
2555 if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
2559 return RBOOL(recv == obj);
2564NOINLINE(
static VALUE opt_equality_by_mid_slowpath(
VALUE recv,
VALUE obj,
ID mid));
2567opt_equality_by_mid_slowpath(
VALUE recv,
VALUE obj,
ID mid)
2569 const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, &VM_CI_ON_STACK(mid, 0, 1, NULL));
2571 if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) {
2572 return RBOOL(recv == obj);
2582 VALUE val = opt_equality_specialized(recv, obj);
2583 if (!UNDEF_P(val)) {
2587 return opt_equality_by_mid_slowpath(recv, obj, mid);
2594 return opt_equality_by_mid(obj1, obj2, idEq);
2600 return opt_equality_by_mid(obj1, obj2, idEqlP);
2610 case VM_CHECKMATCH_TYPE_WHEN:
2612 case VM_CHECKMATCH_TYPE_RESCUE:
2614 rb_raise(
rb_eTypeError,
"class or module required for rescue clause");
2617 case VM_CHECKMATCH_TYPE_CASE: {
2618 return rb_vm_call_with_refinements(ec, pattern, idEqq, 1, &target,
RB_NO_KEYWORDS);
2621 rb_bug(
"check_match: unreachable");
2627double_cmp_lt(
double a,
double b)
2629 return RBOOL(a < b);
2633double_cmp_le(
double a,
double b)
2635 return RBOOL(a <= b);
2639double_cmp_gt(
double a,
double b)
2641 return RBOOL(a > b);
2645double_cmp_ge(
double a,
double b)
2647 return RBOOL(a >= b);
2651static inline VALUE *
2656 if (CFP_ISEQ(cfp) && VM_FRAME_RUBYFRAME_P(cfp)) {
2657 VALUE *bp = prev_cfp->sp + ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size + VM_ENV_DATA_SIZE;
2659 if (ISEQ_BODY(CFP_ISEQ(cfp))->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
2660 int lts = ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size;
2661 int params = ISEQ_BODY(CFP_ISEQ(cfp))->param.size;
2664 bp += vm_ci_argc(ci);
2667 if (ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
2671#if VM_DEBUG_BP_CHECK
2672 if (bp != cfp->bp_check) {
2673 ruby_debug_printf(
"bp_check: %ld, bp: %ld\n",
2674 (
long)(cfp->bp_check - GET_EC()->vm_stack),
2675 (
long)(bp - GET_EC()->vm_stack));
2676 rb_bug(
"vm_base_ptr: unreachable");
2689 return vm_base_ptr(cfp);
2704static vm_call_handler vm_call_iseq_setup_func(
const struct rb_callinfo *ci,
const int param_size,
const int local_size);
2709 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_tailcall_0start);
2711 return vm_call_iseq_setup_tailcall(ec, cfp, calling, 0);
2717 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_0start);
2720 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
2721 int param = ISEQ_BODY(iseq)->param.size;
2722 int local = ISEQ_BODY(iseq)->local_table_size;
2723 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
2729 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2730 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2731 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2732 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2733 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2734 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2735 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2736 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2737 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2741rb_iseq_only_optparam_p(
const rb_iseq_t *iseq)
2743 return ISEQ_BODY(iseq)->param.flags.has_opt == TRUE &&
2744 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2745 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2746 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2747 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2748 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2749 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2750 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2751 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2755rb_iseq_only_kwparam_p(
const rb_iseq_t *iseq)
2757 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2758 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2759 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2760 ISEQ_BODY(iseq)->param.flags.has_kw == TRUE &&
2761 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2762 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2763 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2764 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2767#define ALLOW_HEAP_ARGV (-2)
2768#define ALLOW_HEAP_ARGV_KEEP_KWSPLAT (-3)
2773 vm_check_canary(GET_EC(), cfp->sp);
2779 int argc = calling->argc;
2781 if (UNLIKELY(max_args <= ALLOW_HEAP_ARGV && len + argc > VM_ARGC_STACK_MAX)) {
2785 VALUE *argv = cfp->sp - argc;
2789 cfp->sp -= argc - 1;
2790 cfp->sp[-1] = argv_ary;
2792 calling->heap_argv = argv_ary;
2798 if (max_args >= 0 &&
len + argc > max_args) {
2806 calling->argc +=
len - (max_args - argc + 1);
2807 len = max_args - argc + 1;
2816 calling->heap_argv = 0;
2818 CHECK_VM_STACK_OVERFLOW(cfp,
len);
2820 for (i = 0; i <
len; i++) {
2821 *cfp->sp++ = ptr[i];
2833 const VALUE *
const passed_keywords = vm_ci_kwarg(ci)->keywords;
2834 const int kw_len = vm_ci_kwarg(ci)->keyword_len;
2835 const VALUE h = rb_hash_new_capa(kw_len);
2836 VALUE *sp = cfp->sp;
2839 for (i=0; i<kw_len; i++) {
2840 rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
2844 cfp->sp -= kw_len - 1;
2845 calling->argc -= kw_len - 1;
2846 calling->kw_splat = 1;
2850vm_caller_setup_keyword_hash(
const struct rb_callinfo *ci,
VALUE keyword_hash)
2853 if (keyword_hash !=
Qnil) {
2855 keyword_hash = rb_hash_dup(rb_to_hash_type(keyword_hash));
2858 else if (!IS_ARGS_KW_SPLAT_MUT(ci) && !
RHASH_EMPTY_P(keyword_hash)) {
2864 keyword_hash = rb_hash_dup(keyword_hash);
2866 return keyword_hash;
2872 const struct rb_callinfo *restrict ci,
int max_args)
2874 if (UNLIKELY(IS_ARGS_SPLAT(ci))) {
2875 if (IS_ARGS_KW_SPLAT(ci)) {
2877 VM_ASSERT(calling->kw_splat == 1);
2881 VALUE ary = cfp->sp[0];
2882 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[1]);
2885 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args))
return;
2889 if (UNLIKELY(calling->heap_argv)) {
2891 ((
struct RHash *)kwh)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
2892 if (max_args != ALLOW_HEAP_ARGV_KEEP_KWSPLAT) {
2893 calling->kw_splat = 0;
2901 VM_ASSERT(calling->kw_splat == 1);
2905 calling->kw_splat = 0;
2910 VM_ASSERT(calling->kw_splat == 0);
2914 VALUE ary = cfp->sp[0];
2916 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args)) {
2921 VALUE last_hash, argv_ary;
2922 if (UNLIKELY(argv_ary = calling->heap_argv)) {
2923 if (!IS_ARGS_KEYWORD(ci) &&
2926 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2931 calling->kw_splat = 1;
2937 if (!IS_ARGS_KEYWORD(ci) &&
2938 calling->argc > 0 &&
2940 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2947 cfp->sp[-1] = rb_hash_dup(last_hash);
2948 calling->kw_splat = 1;
2954 else if (UNLIKELY(IS_ARGS_KW_SPLAT(ci))) {
2956 VM_ASSERT(calling->kw_splat == 1);
2957 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[-1]);
2962 calling->kw_splat = 0;
2968 else if (UNLIKELY(IS_ARGS_KEYWORD(ci))) {
2970 VM_ASSERT(calling->kw_splat == 0);
2976 vm_caller_setup_arg_kw(cfp, calling, ci);
2980#define USE_OPT_HIST 0
2983#define OPT_HIST_MAX 64
2984static int opt_hist[OPT_HIST_MAX+1];
2988opt_hist_show_results_at_exit(
void)
2990 for (
int i=0; i<OPT_HIST_MAX; i++) {
2991 ruby_debug_printf(
"opt_hist\t%d\t%d\n", i, opt_hist[i]);
3001 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3002 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3003 const int opt = calling->argc - lead_num;
3004 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3005 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3006 const int param = ISEQ_BODY(iseq)->param.size;
3007 const int local = ISEQ_BODY(iseq)->local_table_size;
3008 const int delta = opt_num - opt;
3010 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3013 if (opt_pc < OPT_HIST_MAX) {
3017 opt_hist[OPT_HIST_MAX]++;
3021 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param - delta, local);
3029 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3030 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3031 const int opt = calling->argc - lead_num;
3032 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3034 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3037 if (opt_pc < OPT_HIST_MAX) {
3041 opt_hist[OPT_HIST_MAX]++;
3045 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3050 VALUE *
const passed_values,
const int passed_keyword_len,
const VALUE *
const passed_keywords,
3051 VALUE *
const locals);
3058 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3059 int param_size = ISEQ_BODY(iseq)->param.size;
3060 int local_size = ISEQ_BODY(iseq)->local_table_size;
3063 VM_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3065 local_size = local_size + vm_ci_argc(calling->cd->ci);
3066 param_size = param_size + vm_ci_argc(calling->cd->ci);
3068 cfp->sp[0] = (
VALUE)calling->cd->ci;
3070 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param_size, local_size);
3080 VM_ASSERT(vm_ci_flag(ci) & VM_CALL_KWARG);
3081 RB_DEBUG_COUNTER_INC(ccf_iseq_kw1);
3083 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3084 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3086 const int ci_kw_len = kw_arg->keyword_len;
3087 const VALUE *
const ci_keywords = kw_arg->keywords;
3088 VALUE *argv = cfp->sp - calling->argc;
3089 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3090 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3092 MEMCPY(ci_kws, argv + lead_num,
VALUE, ci_kw_len);
3093 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3095 int param = ISEQ_BODY(iseq)->param.size;
3096 int local = ISEQ_BODY(iseq)->local_table_size;
3097 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3104 const struct rb_callinfo *MAYBE_UNUSED(ci) = calling->cd->ci;
3107 VM_ASSERT((vm_ci_flag(ci) & VM_CALL_KWARG) == 0);
3108 RB_DEBUG_COUNTER_INC(ccf_iseq_kw2);
3110 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3111 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3112 VALUE *
const argv = cfp->sp - calling->argc;
3113 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3116 for (i=0; i<kw_param->num; i++) {
3117 klocals[i] = kw_param->default_values[i];
3124 int param = ISEQ_BODY(iseq)->param.size;
3125 int local = ISEQ_BODY(iseq)->local_table_size;
3126 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3136 cfp->sp -= (calling->argc + 1);
3137 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
3138 return builtin_invoker0(ec, calling->recv, NULL, func_ptr);
3147 set_table *dup_check_table = &vm->unused_block_warning_table;
3157 .v = (
VALUE)cme->def,
3161 if (!strict_unused_block) {
3162 key = (st_data_t)cme->def->original_id;
3164 if (set_table_lookup(dup_check_table, key)) {
3174 key |= (st_data_t)(k1.b[i] ^ k2.b[
SIZEOF_VALUE-1-i]) << (8 * i);
3179 fprintf(stderr,
"pc:%p def:%p\n", pc, (
void *)cme->def);
3180 fprintf(stderr,
"key:%p\n", (
void *)key);
3184 if (set_insert(dup_check_table, key)) {
3189 VALUE name = rb_gen_method_name(cme->defined_class, rb_iseq_base_label(iseq));
3191 if (!
NIL_P(m_loc)) {
3192 rb_warn(
"the block passed to '%"PRIsVALUE
"' defined at %"PRIsVALUE
":%"PRIsVALUE
" may be ignored",
3196 rb_warn(
"the block may be ignored because '%"PRIsVALUE
"' does not use a block", name);
3203 const rb_iseq_t *iseq,
VALUE *argv,
int param_size,
int local_size)
3208 VM_ASSERT((vm_ci_argc(ci), 1));
3209 VM_ASSERT(vm_cc_cme(cc) != NULL);
3211 if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
3212 calling->block_handler != VM_BLOCK_HANDLER_NONE &&
3213 !(vm_ci_flag(calling->cd->ci) & (VM_CALL_OPT_SEND | VM_CALL_SUPER)))) {
3214 warn_unused_block(vm_cc_cme(cc), iseq, (
void *)CFP_PC(ec->cfp));
3217 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_KW_SPLAT))) {
3218 if (LIKELY(rb_simple_iseq_p(iseq))) {
3220 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3221 CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
3223 if (calling->argc != lead_num) {
3224 argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
3228 VM_ASSERT(cc == calling->cc);
3230 if (vm_call_iseq_optimizable_p(ci, cc)) {
3231 if ((ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) && ruby_vm_c_events_enabled == 0) {
3232 VM_ASSERT(ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF);
3233 vm_cc_bf_set(cc, (
void *)ISEQ_BODY(iseq)->iseq_encoded[1]);
3234 CC_SET_FASTPATH(cc, vm_call_single_noarg_leaf_builtin,
true);
3237 CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size),
true);
3242 else if (rb_iseq_only_optparam_p(iseq)) {
3245 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3246 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3248 CALLER_SETUP_ARG(cfp, calling, ci, lead_num + opt_num);
3249 const int argc = calling->argc;
3250 const int opt = argc - lead_num;
3252 if (opt < 0 || opt > opt_num) {
3253 argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
3256 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3257 CC_SET_FASTPATH(cc, vm_call_iseq_setup_normal_opt_start,
3258 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3259 vm_call_cacheable(ci, cc));
3262 CC_SET_FASTPATH(cc, vm_call_iseq_setup_tailcall_opt_start,
3263 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3264 vm_call_cacheable(ci, cc));
3268 VM_ASSERT((
int)ISEQ_BODY(iseq)->param.size == lead_num + opt_num);
3269 for (
int i=argc; i<lead_num + opt_num; i++) {
3272 return (
int)ISEQ_BODY(iseq)->param.opt_table[opt];
3274 else if (rb_iseq_only_kwparam_p(iseq) && !IS_ARGS_SPLAT(ci)) {
3275 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3276 const int argc = calling->argc;
3277 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3279 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
3282 if (argc - kw_arg->keyword_len == lead_num) {
3283 const int ci_kw_len = kw_arg->keyword_len;
3284 const VALUE *
const ci_keywords = kw_arg->keywords;
3286 MEMCPY(ci_kws, argv + lead_num,
VALUE, ci_kw_len);
3288 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3289 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3291 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
3292 vm_call_cacheable(ci, cc));
3297 else if (argc == lead_num) {
3299 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3300 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
3302 if (klocals[kw_param->num] ==
INT2FIX(0)) {
3304 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_nokwarg,
3305 vm_call_cacheable(ci, cc));
3331 if (ISEQ_BODY(iseq)->param.flags.forwardable) {
3332 bool can_fastpath =
true;
3334 if ((vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
3336 if (vm_ci_argc(ci) != vm_ci_argc(forward_cd->caller_ci)) {
3337 ci = vm_ci_new_runtime(
3344 ci = forward_cd->caller_ci;
3346 can_fastpath =
false;
3350 if (!vm_ci_markable(ci)) {
3351 ci = vm_ci_new_runtime(
3356 can_fastpath =
false;
3358 argv[param_size - 1] = (
VALUE)ci;
3359 CC_SET_FASTPATH(cc, vm_call_iseq_forwardable, can_fastpath);
3363 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_method);
3390 const VALUE * lep = VM_CF_LEP(cfp);
3396 if (VM_ENV_FLAGS(lep, VM_ENV_FLAG_ESCAPED)) {
3401 iseq = CFP_ISEQ(rb_vm_search_cf_from_ep(ec, cfp, lep));
3405 int local_size = ISEQ_BODY(iseq)->local_table_size + argc;
3407 const VALUE * from = lep - (local_size + VM_ENV_DATA_SIZE - 1);
3408 VALUE * to = cfp->sp - 1;
3412 CHECK_VM_STACK_OVERFLOW0(cfp, to,
RARRAY_LEN(splat));
3417 CHECK_VM_STACK_OVERFLOW0(cfp, to, argc);
3419 cfp->sp = to + argc;
3438 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3441 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3442 int param_size = ISEQ_BODY(iseq)->param.size;
3443 int local_size = ISEQ_BODY(iseq)->local_table_size;
3445 RUBY_ASSERT(!ISEQ_BODY(iseq)->param.flags.forwardable);
3447 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3448 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3454 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3457 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3458 int param_size = ISEQ_BODY(iseq)->param.size;
3459 int local_size = ISEQ_BODY(iseq)->local_table_size;
3461 RUBY_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3464 local_size = local_size + vm_ci_argc(calling->cd->ci);
3465 param_size = param_size + vm_ci_argc(calling->cd->ci);
3467 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3468 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3473 int opt_pc,
int param_size,
int local_size)
3478 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3479 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param_size, local_size);
3482 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3488 int opt_pc,
int param_size,
int local_size)
3490 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3491 VALUE *argv = cfp->sp - calling->argc;
3492 VALUE *sp = argv + param_size;
3493 cfp->sp = argv - 1 ;
3495 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling->recv,
3496 calling->block_handler, (
VALUE)me,
3497 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3498 local_size - param_size,
3499 ISEQ_BODY(iseq)->stack_max);
3508 VALUE *argv = cfp->sp - calling->argc;
3510 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3511 VALUE *src_argv = argv;
3512 VALUE *sp_orig, *sp;
3513 VALUE finish_flag = VM_FRAME_FINISHED_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
3515 if (VM_BH_FROM_CFP_P(calling->block_handler, cfp)) {
3516 struct rb_captured_block *dst_captured = VM_CFP_TO_CAPTURED_BLOCK(RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
3517 const struct rb_captured_block *src_captured = VM_BH_TO_CAPT_BLOCK(calling->block_handler);
3518 dst_captured->code.val = src_captured->code.val;
3519 if (VM_BH_ISEQ_BLOCK_P(calling->block_handler)) {
3520 calling->block_handler = VM_BH_FROM_ISEQ_BLOCK(dst_captured);
3523 calling->block_handler = VM_BH_FROM_IFUNC_BLOCK(dst_captured);
3527 vm_pop_frame(ec, cfp, cfp->ep);
3530 sp_orig = sp = cfp->sp;
3533 sp[0] = calling->recv;
3537 for (i=0; i < ISEQ_BODY(iseq)->param.size; i++) {
3538 *sp++ = src_argv[i];
3541 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL | finish_flag,
3542 calling->recv, calling->block_handler, (
VALUE)me,
3543 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3544 ISEQ_BODY(iseq)->local_table_size - ISEQ_BODY(iseq)->param.size,
3545 ISEQ_BODY(iseq)->stack_max);
3553ractor_unsafe_check(
void)
3555 if (!rb_ractor_main_p()) {
3556 rb_raise(rb_eRactorUnsafeError,
"ractor unsafe method called from not main ractor");
3563 ractor_unsafe_check();
3571 ractor_unsafe_check();
3573 return (*f)(argc, argv, recv);
3579 ractor_unsafe_check();
3587 ractor_unsafe_check();
3589 return (*f)(recv, argv[0]);
3595 ractor_unsafe_check();
3597 return (*f)(recv, argv[0], argv[1]);
3603 ractor_unsafe_check();
3605 return (*f)(recv, argv[0], argv[1], argv[2]);
3611 ractor_unsafe_check();
3613 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3619 ractor_unsafe_check();
3620 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3621 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3627 ractor_unsafe_check();
3628 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3629 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3635 ractor_unsafe_check();
3636 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3637 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3643 ractor_unsafe_check();
3644 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3645 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3651 ractor_unsafe_check();
3652 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3653 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3659 ractor_unsafe_check();
3660 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3661 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3667 ractor_unsafe_check();
3668 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3669 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]);
3675 ractor_unsafe_check();
3676 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3677 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]);
3683 ractor_unsafe_check();
3684 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3685 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]);
3691 ractor_unsafe_check();
3692 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3693 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]);
3699 ractor_unsafe_check();
3700 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3701 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]);
3715 return (*f)(argc, argv, recv);
3729 return (*f)(recv, argv[0]);
3736 return (*f)(recv, argv[0], argv[1]);
3743 return (*f)(recv, argv[0], argv[1], argv[2]);
3750 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3756 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3757 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3763 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3764 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3770 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3771 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3777 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3778 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3784 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3785 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3791 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3792 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3798 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3799 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]);
3805 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3806 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]);
3812 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3813 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]);
3819 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3820 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]);
3826 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3827 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]);
3833 const int ov_flags = RAISED_STACKOVERFLOW;
3834 if (LIKELY(reg_cfp == ec->cfp + 1))
return TRUE;
3835 if (rb_ec_raised_p(ec, ov_flags)) {
3836 rb_ec_raised_reset(ec, ov_flags);
3842#define CHECK_CFP_CONSISTENCY(func) \
3843 (LIKELY(vm_cfp_consistent_p(ec, reg_cfp)) ? (void)0 : \
3844 rb_bug(func ": cfp consistency error (%p, %p)", (void *)reg_cfp, (void *)(ec->cfp+1)))
3850#if VM_DEBUG_VERIFY_METHOD_CACHE
3851 switch (me->def->type) {
3852 case VM_METHOD_TYPE_CFUNC:
3853 case VM_METHOD_TYPE_NOTIMPLEMENTED:
3855# define METHOD_BUG(t) case VM_METHOD_TYPE_##t: rb_bug("wrong method type: " #t)
3857 METHOD_BUG(ATTRSET);
3859 METHOD_BUG(BMETHOD);
3862 METHOD_BUG(OPTIMIZED);
3863 METHOD_BUG(MISSING);
3864 METHOD_BUG(REFINED);
3868 rb_bug(
"wrong method type: %d", me->def->type);
3871 return UNALIGNED_MEMBER_PTR(me->def, body.cfunc);
3878 RB_DEBUG_COUNTER_INC(ccf_cfunc_with_frame);
3885 VALUE recv = calling->recv;
3886 VALUE block_handler = calling->block_handler;
3887 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3889 if (UNLIKELY(calling->kw_splat)) {
3890 frame_type |= VM_FRAME_FLAG_CFRAME_KW;
3893 VM_ASSERT(reg_cfp == ec->cfp);
3895 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id);
3898 vm_push_frame(ec, NULL, frame_type, recv,
3899 block_handler, (
VALUE)me,
3900 0, ec->cfp->sp, 0, 0);
3902 int len = cfunc->argc;
3905 reg_cfp->sp = stack_bottom;
3906 val = (*cfunc->invoker)(recv, argc, argv, cfunc->func);
3908 CHECK_CFP_CONSISTENCY(
"vm_call_cfunc");
3910 rb_vm_pop_frame(ec);
3912 VM_ASSERT(ec->cfp->sp == stack_bottom);
3914 EXEC_EVENT_HOOK(ec,
RUBY_EVENT_C_RETURN, recv, me->def->original_id, vm_ci_mid(ci), me->owner, val);
3915 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
3925 VM_ASSERT(cme->def->type == VM_METHOD_TYPE_CFUNC);
3927 VALUE *sp = ec->cfp->sp;
3928 VALUE recv = *(sp - recv_idx - 1);
3929 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3930 VALUE block_handler = VM_BLOCK_HANDLER_NONE;
3931#if VM_CHECK_MODE > 0
3933 *(GET_EC()->cfp->sp) =
Qfalse;
3935 vm_push_frame(ec, NULL, frame_type, recv, block_handler, (
VALUE)cme, 0, ec->cfp->sp, 0, 0);
3940rb_splat_or_kwargs_p(
const struct rb_callinfo *restrict ci)
3942 return IS_ARGS_SPLAT(ci) || IS_ARGS_KW_OR_KW_SPLAT(ci);
3948 int argc = calling->argc;
3949 VALUE *stack_bottom = reg_cfp->sp - argc - 1;
3950 VALUE *argv = &stack_bottom[1];
3952 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3959 RB_DEBUG_COUNTER_INC(ccf_cfunc_other);
3961 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
3963 if (UNLIKELY(argv_ary = calling->heap_argv)) {
3964 VM_ASSERT(!IS_ARGS_KEYWORD(ci));
3967 VALUE *stack_bottom = reg_cfp->sp - 2;
3969 VM_ASSERT(calling->argc == 1);
3973 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3976 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));
3978 return vm_call_cfunc_with_frame(ec, reg_cfp, calling);
3985 VALUE argv_ary = reg_cfp->sp[-1 - stack_offset];
3988 if (UNLIKELY(argc > VM_ARGC_STACK_MAX)) {
3989 return vm_call_cfunc_other(ec, reg_cfp, calling);
3993 calling->kw_splat = 0;
3995 VALUE *stack_bottom = reg_cfp->sp - 2 - stack_offset;
3996 VALUE *sp = stack_bottom;
3997 CHECK_VM_STACK_OVERFLOW(reg_cfp, argc);
3998 for(i = 0; i < argc; i++) {
4003 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, stack_bottom+1, stack_bottom);
4009 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat);
4010 VALUE argv_ary = reg_cfp->sp[-1];
4014 int argc_offset = 0;
4016 if (UNLIKELY(argc > 0 &&
4018 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS))) {
4020 return vm_call_cfunc_other(ec, reg_cfp, calling);
4024 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 0, argc_offset);
4030 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat_kw);
4031 VALUE keyword_hash = reg_cfp->sp[-1];
4034 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 1, 0);
4037 return vm_call_cfunc_other(ec, reg_cfp, calling);
4044 RB_DEBUG_COUNTER_INC(ccf_cfunc);
4046 if (IS_ARGS_SPLAT(ci) && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4047 if (!IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 1) {
4049 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat, TRUE);
4050 return vm_call_cfunc_only_splat(ec, reg_cfp, calling);
4052 if (IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 2) {
4054 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat_kw, TRUE);
4055 return vm_call_cfunc_only_splat_kw(ec, reg_cfp, calling);
4059 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_other, TRUE);
4060 return vm_call_cfunc_other(ec, reg_cfp, calling);
4067 RB_DEBUG_COUNTER_INC(ccf_ivar);
4069 VALUE ivar = vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE,
Qnil);
4076 RB_DEBUG_COUNTER_INC(ccf_attrset);
4077 VALUE val = *(cfp->sp - 1);
4079 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_cc_atomic_cache_read(cc));
4080 ID id = vm_cc_cme(cc)->def->body.attr.id;
4081 rb_check_frozen(obj);
4082 VALUE res = vm_setivar(obj, val, cache);
4090 res = vm_setivar_class(obj, val, cache);
4091 if (!UNDEF_P(res)) {
4098 res = vm_setivar_default(obj,
id, val, cache);
4099 if (!UNDEF_P(res)) {
4104 res = vm_setivar_slowpath_attr(obj,
id, val, cc);
4112 return vm_call_attrset_direct(ec, cfp, calling->cc, calling->recv);
4122 VALUE procv = cme->def->body.bmethod.proc;
4125 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4126 rb_raise(
rb_eRuntimeError,
"defined with an un-shareable Proc in a different Ractor");
4130 GetProcPtr(procv, proc);
4131 val = vm_invoke_bmethod(ec, proc, calling->recv, CALLING_ARGC(calling), argv, calling->kw_splat, calling->block_handler, vm_cc_cme(cc));
4141 RB_DEBUG_COUNTER_INC(ccf_iseq_bmethod);
4145 VALUE procv = cme->def->body.bmethod.proc;
4148 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4149 rb_raise(
rb_eRuntimeError,
"defined with an un-shareable Proc in a different Ractor");
4153 GetProcPtr(procv, proc);
4154 const struct rb_block *block = &proc->block;
4156 while (vm_block_type(block) == block_type_proc) {
4157 block = vm_proc_block(block->as.proc);
4159 VM_ASSERT(vm_block_type(block) == block_type_iseq);
4162 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
4163 VALUE *
const argv = cfp->sp - calling->argc;
4164 const int arg_size = ISEQ_BODY(iseq)->param.size;
4167 if (vm_ci_flag(calling->cd->ci) & VM_CALL_ARGS_SIMPLE) {
4168 opt_pc = vm_callee_setup_block_arg(ec, calling, calling->cd->ci, iseq, argv, arg_setup_method);
4171 opt_pc = setup_parameters_complex(ec, iseq, calling, calling->cd->ci, argv, arg_setup_method);
4176 vm_push_frame(ec, iseq,
4177 VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_BMETHOD | VM_FRAME_FLAG_LAMBDA,
4179 VM_GUARDED_PREV_EP(captured->ep),
4181 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
4183 ISEQ_BODY(iseq)->local_table_size - arg_size,
4184 ISEQ_BODY(iseq)->stack_max);
4192 RB_DEBUG_COUNTER_INC(ccf_noniseq_bmethod);
4196 CALLER_SETUP_ARG(cfp, calling, calling->cd->ci, ALLOW_HEAP_ARGV);
4197 if (UNLIKELY(calling->heap_argv)) {
4202 argc = calling->argc;
4205 cfp->sp += - argc - 1;
4208 return vm_call_bmethod_body(ec, calling, argv);
4214 RB_DEBUG_COUNTER_INC(ccf_bmethod);
4218 VALUE procv = cme->def->body.bmethod.proc;
4220 GetProcPtr(procv, proc);
4221 const struct rb_block *block = &proc->block;
4223 while (vm_block_type(block) == block_type_proc) {
4224 block = vm_proc_block(block->as.proc);
4226 if (vm_block_type(block) == block_type_iseq) {
4227 CC_SET_FASTPATH(cc, vm_call_iseq_bmethod, TRUE);
4228 return vm_call_iseq_bmethod(ec, cfp, calling);
4231 CC_SET_FASTPATH(cc, vm_call_noniseq_bmethod, TRUE);
4232 return vm_call_noniseq_bmethod(ec, cfp, calling);
4236rb_find_defined_class_by_owner(
VALUE current_class,
VALUE target_owner)
4238 VALUE klass = current_class;
4246 while (
RTEST(klass)) {
4248 if (owner == target_owner) {
4254 return current_class;
4263 if (orig_me->defined_class == 0) {
4264 VALUE defined_class = rb_find_defined_class_by_owner(me->defined_class, orig_me->owner);
4265 VM_ASSERT_TYPE(orig_me->owner,
T_MODULE);
4266 cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class);
4268 if (me->def->reference_count == 1) {
4269 RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme);
4273 rb_method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id);
4281 VM_ASSERT(callable_method_entry_p(cme));
4288 return aliased_callable_method_entry(me);
4294 calling->cc = &VM_CC_ON_STACK(
Qundef,
4297 aliased_callable_method_entry(vm_cc_cme(calling->cc)));
4299 return vm_call_method_each_type(ec, cfp, calling);
4302static enum method_missing_reason
4305 enum method_missing_reason stat = MISSING_NOENTRY;
4306 if (vm_ci_flag(ci) & VM_CALL_VCALL && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) stat |= MISSING_VCALL;
4307 if (vm_ci_flag(ci) & VM_CALL_FCALL) stat |= MISSING_FCALL;
4308 if (vm_ci_flag(ci) & VM_CALL_SUPER) stat |= MISSING_SUPER;
4318 ASSUME(calling->argc >= 0);
4320 enum method_missing_reason missing_reason = MISSING_NOENTRY;
4321 int argc = calling->argc;
4322 VALUE recv = calling->recv;
4325 flags |= VM_CALL_OPT_SEND;
4327 if (UNLIKELY(! mid)) {
4328 mid = idMethodMissing;
4329 missing_reason = ci_missing_reason(ci);
4330 ec->method_missing_reason = missing_reason;
4333 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4335 rb_ary_unshift(argv_ary, symbol);
4338 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4339 VALUE exc = rb_make_no_method_exception(
4361 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4364 argc = ++calling->argc;
4369 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4370 const VALUE *argv = STACK_ADDR_FROM_TOP(argc);
4371 VALUE exc = rb_make_no_method_exception(
4384 .ci = &VM_CI_ON_STACK(mid, flags, argc, vm_ci_kwarg(ci)),
4390 if (!(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4391 calling->cd = &new_fcd.cd;
4395 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4396 new_fcd.caller_ci = caller_ci;
4399 calling->cc = &VM_CC_ON_STACK(klass,
4401 { .method_missing_reason = missing_reason },
4402 rb_callable_method_entry_with_refinements(klass, mid, NULL));
4404 if (flags & VM_CALL_FCALL) {
4405 return vm_call_method(ec, reg_cfp, calling);
4409 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
4411 if (vm_cc_cme(cc) != NULL) {
4412 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
4413 case METHOD_VISI_PUBLIC:
4414 return vm_call_method_each_type(ec, reg_cfp, calling);
4415 case METHOD_VISI_PRIVATE:
4416 vm_cc_method_missing_reason_set(cc, MISSING_PRIVATE);
4418 case METHOD_VISI_PROTECTED:
4419 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
4422 VM_UNREACHABLE(vm_call_method);
4424 return vm_call_method_missing(ec, reg_cfp, calling);
4427 return vm_call_method_nome(ec, reg_cfp, calling);
4437 i = calling->argc - 1;
4439 if (calling->argc == 0) {
4440 rb_raise(rb_eArgError,
"no method name given");
4464 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4470 RB_DEBUG_COUNTER_INC(ccf_opt_send_complex);
4472 int flags = VM_CALL_FCALL;
4476 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
4477 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4479 flags |= VM_CALL_ARGS_SPLAT;
4480 if (calling->kw_splat) {
4481 VALUE last_hash = rb_ary_last(0, NULL, argv_ary);
4482 ((
struct RHash *)last_hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
4483 calling->kw_splat = 0;
4485 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4488 if (calling->kw_splat) flags |= VM_CALL_KW_SPLAT;
4489 return vm_call_opt_send0(ec, reg_cfp, calling, flags);
4495 RB_DEBUG_COUNTER_INC(ccf_opt_send_simple);
4496 return vm_call_opt_send0(ec, reg_cfp, calling, vm_ci_flag(calling->cd->ci) | VM_CALL_FCALL);
4502 RB_DEBUG_COUNTER_INC(ccf_opt_send);
4505 int flags = vm_ci_flag(ci);
4507 if (UNLIKELY((flags & VM_CALL_FORWARDING) || (!(flags & VM_CALL_ARGS_SIMPLE) &&
4508 ((calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
4509 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
4510 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc)))))) {
4511 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_complex, TRUE);
4512 return vm_call_opt_send_complex(ec, reg_cfp, calling);
4515 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_simple, TRUE);
4516 return vm_call_opt_send_simple(ec, reg_cfp, calling);
4521 const struct rb_callinfo *orig_ci,
enum method_missing_reason reason)
4523 RB_DEBUG_COUNTER_INC(ccf_method_missing);
4525 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
4526 unsigned int argc, flag;
4528 flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | vm_ci_flag(orig_ci);
4529 argc = ++calling->argc;
4532 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4533 vm_check_canary(ec, reg_cfp->sp);
4537 argv[0] =
ID2SYM(vm_ci_mid(orig_ci));
4540 ec->method_missing_reason = reason;
4544 .ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)),
4550 if (!(flag & VM_CALL_FORWARDING)) {
4551 calling->cd = &new_fcd.cd;
4555 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4556 new_fcd.caller_ci = caller_ci;
4560 calling->cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }},
4561 rb_callable_method_entry_without_refinements(
CLASS_OF(calling->recv), idMethodMissing, NULL));
4562 return vm_call_method(ec, reg_cfp, calling);
4568 return vm_call_method_missing_body(ec, reg_cfp, calling, calling->cd->ci, vm_cc_cmethod_missing_reason(calling->cc));
4579 return vm_call_method_nome(ec, cfp, calling);
4581 if (cme->def->type == VM_METHOD_TYPE_REFINED &&
4582 cme->def->body.refined.orig_me) {
4583 cme = refined_method_callable_without_refinement(cme);
4586 calling->cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }}, cme);
4588 return vm_call_method_each_type(ec, cfp, calling);
4592find_refinement(
VALUE refinements,
VALUE klass)
4594 if (
NIL_P(refinements)) {
4597 return rb_hash_lookup(refinements, klass);
4606 if (CFP_ISEQ(cfp) && !VM_FRAME_BMETHOD_P(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_BLOCK) {
4607 const rb_iseq_t *local_iseq = ISEQ_BODY(CFP_ISEQ(cfp))->local_iseq;
4610 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
4611 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
4615 }
while (CFP_ISEQ(cfp) != local_iseq && !VM_FRAME_BMETHOD_P(cfp));
4626 if (orig_me->defined_class == 0) {
4634 VM_ASSERT(callable_method_entry_p(cme));
4636 if (UNDEFINED_METHOD_ENTRY_P(cme)) {
4649module_refinement_iclass(
VALUE refinement_iclass,
VALUE defined_class)
4654 VALUE cache = RCLASS_MODULE_REFINEMENT_ICLASSES(defined_class);
4656 if (LIKELY(cache)) {
4657 module_ref_iclass = rb_wmap_lookup(cache, refinement_iclass);
4660 cache = rb_wmap_new_hidden();
4661 RCLASS_SET_MODULE_REFINEMENT_ICLASSES(defined_class, cache);
4664 if (UNDEF_P(module_ref_iclass)) {
4668 if (RICLASS_FOR_REFINEMENT_P(refinement_iclass_super)) {
4669 super = module_refinement_iclass(refinement_iclass_super, defined_class);
4672 super = defined_class;
4675 module_ref_iclass = rb_include_class_new(
RBASIC(refinement_iclass)->klass, super);
4676 RCLASS_SET_REFINED_CLASS(module_ref_iclass, RCLASS_REFINED_CLASS(refinement_iclass));
4677 rb_class_subclass_add(RCLASS_REFINED_CLASS(refinement_iclass), module_ref_iclass);
4678 rb_wmap_aset(cache, refinement_iclass, module_ref_iclass);
4682 return module_ref_iclass;
4686rb_vm_module_refinement_iclass(
VALUE refinement_iclass,
VALUE defined_class)
4688 return module_refinement_iclass(refinement_iclass, defined_class);
4695 refinement_iclass = module_refinement_iclass(refinement_iclass, cme->defined_class);
4697 return refinement_iclass;
4703 return refinement_iclass_for_cme(refinement_iclass, cme);
4709 ID mid = vm_ci_mid(calling->cd->ci);
4710 const rb_cref_t *cref = vm_get_cref(cfp->ep);
4714 for (; cref; cref = CREF_NEXT(cref)) {
4715 VALUE refinement = find_refinement(CREF_REFINEMENTS(cref), vm_cc_cme(cc)->owner);
4716 if (
NIL_P(refinement))
continue;
4718 refinement = refinement_iclass_for_cme(refinement, vm_cc_cme(cc));
4721 rb_callable_method_entry(refinement, mid);
4724 if (vm_cc_call(cc) == vm_call_super_method) {
4727 if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) {
4732 if (cme->def->type != VM_METHOD_TYPE_REFINED ||
4733 cme->def != ref_me->def) {
4736 if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
4745 if (vm_cc_cme(cc)->def->body.refined.orig_me) {
4746 return refined_method_callable_without_refinement(vm_cc_cme(cc));
4761 if (calling->cd->cc) {
4762 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);
4764 return vm_call_method(ec, cfp, calling);
4767 struct rb_callcache *ref_cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }}, ref_cme);
4768 calling->cc= ref_cc;
4769 return vm_call_method(ec, cfp, calling);
4773 return vm_call_method_nome(ec, cfp, calling);
4779NOINLINE(
static VALUE
4787 int argc = calling->argc;
4790 if (argc > 0)
MEMMOVE(&TOPN(argc), &TOPN(argc-1),
VALUE, argc);
4793 return vm_invoke_block(ec, reg_cfp, calling, ci,
false, block_handler);
4799 RB_DEBUG_COUNTER_INC(ccf_opt_call);
4802 VALUE procval = calling->recv;
4803 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, VM_BH_FROM_PROC(procval));
4809 RB_DEBUG_COUNTER_INC(ccf_opt_block_call);
4811 VALUE block_handler = VM_ENV_BLOCK_HANDLER(VM_CF_LEP(reg_cfp));
4814 enum ruby_basic_operators bop;
4815 switch (vm_ci_mid(ci)) {
4816 case idAREF: bop = BOP_AREF;
break;
4817 case idYield: bop = BOP_YIELD;
break;
4818 case idEqq: bop = BOP_EQQ;
break;
4819 default: bop = BOP_CALL;
break;
4822 if (BASIC_OP_UNREDEFINED_P(bop, PROC_REDEFINED_OP_FLAG)) {
4823 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, block_handler);
4826 calling->recv = rb_vm_bh_to_procval(ec, block_handler);
4827 calling->cc = rb_vm_search_method_slowpath(ci,
CLASS_OF(calling->recv));
4828 return vm_call_general(ec, reg_cfp, calling);
4835 VALUE recv = calling->recv;
4838 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4839 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_AREF);
4841 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4842 return RSTRUCT_GET_RAW(recv,
off);
4848 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aref);
4850 VALUE ret = vm_call_opt_struct_aref0(ec, calling);
4858 VALUE recv = calling->recv;
4861 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4862 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_ASET);
4864 rb_check_frozen(recv);
4866 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4867 RSTRUCT_SET_RAW(recv,
off, val);
4875 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aset);
4877 VALUE ret = vm_call_opt_struct_aset0(ec, calling, *(reg_cfp->sp - 1));
4885#define VM_CALL_METHOD_ATTR(var, func, nohook) \
4886 if (UNLIKELY(ruby_vm_c_events_enabled > 0)) { \
4887 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, calling->recv, vm_cc_cme(cc)->def->original_id, \
4888 vm_ci_mid(ci), vm_cc_cme(cc)->owner, Qundef); \
4890 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, calling->recv, vm_cc_cme(cc)->def->original_id, \
4891 vm_ci_mid(ci), vm_cc_cme(cc)->owner, (var)); \
4902 switch (vm_cc_cme(cc)->def->body.optimized.type) {
4903 case OPTIMIZED_METHOD_TYPE_SEND:
4904 CC_SET_FASTPATH(cc, vm_call_opt_send, TRUE);
4905 return vm_call_opt_send(ec, cfp, calling);
4906 case OPTIMIZED_METHOD_TYPE_CALL:
4907 CC_SET_FASTPATH(cc, vm_call_opt_call, TRUE);
4908 return vm_call_opt_call(ec, cfp, calling);
4909 case OPTIMIZED_METHOD_TYPE_BLOCK_CALL:
4910 CC_SET_FASTPATH(cc, vm_call_opt_block_call, TRUE);
4911 return vm_call_opt_block_call(ec, cfp, calling);
4912 case OPTIMIZED_METHOD_TYPE_STRUCT_AREF: {
4913 CALLER_SETUP_ARG(cfp, calling, ci, 0);
4917 VM_CALL_METHOD_ATTR(v,
4918 vm_call_opt_struct_aref(ec, cfp, calling),
4919 set_vm_cc_ivar(cc); \
4920 CC_SET_FASTPATH(cc, vm_call_opt_struct_aref, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4923 case OPTIMIZED_METHOD_TYPE_STRUCT_ASET: {
4924 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4928 VM_CALL_METHOD_ATTR(v,
4929 vm_call_opt_struct_aset(ec, cfp, calling),
4930 set_vm_cc_ivar(cc); \
4931 CC_SET_FASTPATH(cc, vm_call_opt_struct_aset, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4935 rb_bug(
"vm_call_method: unsupported optimized method type (%d)", vm_cc_cme(cc)->def->body.optimized.type);
4947 VM_ASSERT(! METHOD_ENTRY_INVALIDATED(cme));
4949 switch (cme->def->type) {
4950 case VM_METHOD_TYPE_ISEQ:
4951 if (ISEQ_BODY(def_iseq_ptr(cme->def))->param.flags.forwardable) {
4952 CC_SET_FASTPATH(cc, vm_call_iseq_fwd_setup, TRUE);
4953 return vm_call_iseq_fwd_setup(ec, cfp, calling);
4956 CC_SET_FASTPATH(cc, vm_call_iseq_setup, TRUE);
4957 return vm_call_iseq_setup(ec, cfp, calling);
4960 case VM_METHOD_TYPE_NOTIMPLEMENTED:
4961 case VM_METHOD_TYPE_CFUNC:
4962 CC_SET_FASTPATH(cc, vm_call_cfunc, TRUE);
4963 return vm_call_cfunc(ec, cfp, calling);
4965 case VM_METHOD_TYPE_ATTRSET:
4966 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4970 const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG | VM_CALL_FORWARDING);
4972 if (vm_cc_markable(cc)) {
4973 vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
4974 VM_CALL_METHOD_ATTR(v,
4975 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4976 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
4982 VM_CALLCACHE_UNMARKABLE |
4983 VM_CALLCACHE_ON_STACK,
4989 .value = IVAR_CACHE_INIT,
4994 VM_CALL_METHOD_ATTR(v,
4995 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4996 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
5000 case VM_METHOD_TYPE_IVAR:
5001 CALLER_SETUP_ARG(cfp, calling, ci, 0);
5003 vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
5004 const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING);
5005 VM_CALL_METHOD_ATTR(v,
5006 vm_call_ivar(ec, cfp, calling),
5007 CC_SET_FASTPATH(cc, vm_call_ivar, !(vm_ci_flag(ci) & ivar_mask)));
5010 case VM_METHOD_TYPE_MISSING:
5011 vm_cc_method_missing_reason_set(cc, 0);
5012 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
5013 return vm_call_method_missing(ec, cfp, calling);
5015 case VM_METHOD_TYPE_BMETHOD:
5016 CC_SET_FASTPATH(cc, vm_call_bmethod, TRUE);
5017 return vm_call_bmethod(ec, cfp, calling);
5019 case VM_METHOD_TYPE_ALIAS:
5020 CC_SET_FASTPATH(cc, vm_call_alias, TRUE);
5021 return vm_call_alias(ec, cfp, calling);
5023 case VM_METHOD_TYPE_OPTIMIZED:
5024 return vm_call_optimized(ec, cfp, calling, ci, cc);
5026 case VM_METHOD_TYPE_UNDEF:
5029 case VM_METHOD_TYPE_ZSUPER:
5030 return vm_call_zsuper(ec, cfp, calling, RCLASS_ORIGIN(vm_cc_cme(cc)->defined_class));
5032 case VM_METHOD_TYPE_REFINED:
5035 return vm_call_refined(ec, cfp, calling);
5038 rb_bug(
"vm_call_method: unsupported method type (%d)", vm_cc_cme(cc)->def->type);
5048 const int stat = ci_missing_reason(ci);
5050 if (vm_ci_mid(ci) == idMethodMissing) {
5051 if (UNLIKELY(calling->heap_argv)) {
5056 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
5057 vm_raise_method_missing(ec, calling->argc, argv, calling->recv, stat);
5061 return vm_call_method_missing_body(ec, cfp, calling, ci, stat);
5073 VALUE defined_class = me->defined_class;
5074 VALUE refined_class = RCLASS_REFINED_CLASS(defined_class);
5075 return NIL_P(refined_class) ? defined_class : refined_class;
5084 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
5086 if (vm_cc_cme(cc) != NULL) {
5087 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
5088 case METHOD_VISI_PUBLIC:
5089 return vm_call_method_each_type(ec, cfp, calling);
5091 case METHOD_VISI_PRIVATE:
5092 if (!(vm_ci_flag(ci) & VM_CALL_FCALL)) {
5093 enum method_missing_reason stat = MISSING_PRIVATE;
5094 if (vm_ci_flag(ci) & VM_CALL_VCALL) stat |= MISSING_VCALL;
5096 vm_cc_method_missing_reason_set(cc, stat);
5097 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
5098 return vm_call_method_missing(ec, cfp, calling);
5100 return vm_call_method_each_type(ec, cfp, calling);
5102 case METHOD_VISI_PROTECTED:
5103 if (!(vm_ci_flag(ci) & (VM_CALL_OPT_SEND | VM_CALL_FCALL))) {
5104 VALUE defined_class = vm_defined_class_for_protected_call(vm_cc_cme(cc));
5106 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
5107 return vm_call_method_missing(ec, cfp, calling);
5111 VM_ASSERT(vm_cc_cme(cc) != NULL);
5114 calling->cc = &cc_on_stack;
5115 return vm_call_method_each_type(ec, cfp, calling);
5118 return vm_call_method_each_type(ec, cfp, calling);
5121 rb_bug(
"unreachable");
5125 return vm_call_method_nome(ec, cfp, calling);
5132 RB_DEBUG_COUNTER_INC(ccf_general);
5133 return vm_call_method(ec, reg_cfp, calling);
5139 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
5140 VM_ASSERT(cc != vm_cc_empty());
5142 *(vm_call_handler *)&cc->call_ = vm_call_general;
5148 RB_DEBUG_COUNTER_INC(ccf_super_method);
5153 if (ec == NULL) rb_bug(
"unreachable");
5156 VM_ASSERT(vm_cc_call(calling->cc) == vm_call_super_method);
5157 return vm_call_method(ec, reg_cfp, calling);
5163vm_search_normal_superclass(
VALUE klass)
5165 if (RICLASS_FOR_REFINEMENT_P(klass)) {
5169 }
while (RICLASS_FOR_REFINEMENT_P(klass));
5174 klass =
RBASIC(klass)->klass;
5176 klass = RCLASS_ORIGIN(klass);
5180NORETURN(
static void vm_super_outside(
void));
5183vm_super_outside(
void)
5189empty_cc_for_super(
void)
5191 return &vm_empty_cc_for_super;
5197 VALUE current_defined_class;
5198 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
5205 current_defined_class = vm_defined_class_for_protected_call(me);
5208 iseq != method_entry_iseqptr(me) &&
5211 RCLASS_INCLUDER(current_defined_class) : current_defined_class;
5215 "self has wrong type to call super in this context: "
5216 "%"PRIsVALUE
" (expected %"PRIsVALUE
")",
5221 if (me->def->type == VM_METHOD_TYPE_BMETHOD && (vm_ci_flag(cd->ci) & VM_CALL_ZSUPER)) {
5223 "implicit argument passing of super from method defined"
5224 " by define_method() is not supported."
5225 " Specify all arguments explicitly.");
5228 ID mid = me->def->original_id;
5230 if (!vm_ci_markable(cd->ci)) {
5231 VM_FORCE_WRITE((
const VALUE *)&cd->ci->mid, (
VALUE)mid);
5235 cd->ci = vm_ci_new_runtime(mid,
5238 vm_ci_kwarg(cd->ci));
5245 VALUE klass = vm_search_normal_superclass(me->defined_class);
5249 cc = vm_cc_new(
Qundef, NULL, vm_call_method_missing, cc_type_super);
5253 cc = vm_search_method_fastpath(reg_cfp, cd, klass);
5257 if (cached_cme == NULL) {
5259 cd->cc = empty_cc_for_super();
5261 else if (cached_cme->called_id != mid) {
5264 cc = vm_cc_new(klass, cme, vm_call_super_method, cc_type_super);
5268 cd->cc = cc = empty_cc_for_super();
5272 switch (cached_cme->def->type) {
5274 case VM_METHOD_TYPE_REFINED:
5276 case VM_METHOD_TYPE_ATTRSET:
5277 case VM_METHOD_TYPE_IVAR:
5278 vm_cc_call_set(cc, vm_call_super_method);
5286 VM_ASSERT((vm_cc_cme(cc),
true));
5294block_proc_is_lambda(
const VALUE procval)
5299 GetProcPtr(procval, proc);
5300 return proc->header.is_lambda;
5310 VALUE self,
int argc,
const VALUE *argv,
int kw_splat,
VALUE block_handler,
5313 int is_lambda = FALSE;
5314 VALUE val, arg, blockarg;
5316 const struct vm_ifunc *ifunc = captured->code.ifunc;
5321 else if (argc == 0) {
5328 blockarg = rb_vm_bh_to_procval(ec, block_handler);
5330 frame_flag = VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME | (me ? VM_FRAME_FLAG_BMETHOD : 0);
5332 frame_flag |= VM_FRAME_FLAG_CFRAME_KW;
5335 vm_push_frame(ec, (
const rb_iseq_t *)captured->code.ifunc,
5338 VM_GUARDED_PREV_EP(captured->ep),
5340 0, ec->cfp->sp, 0, 0);
5341 val = (*ifunc->func)(arg, (
VALUE)ifunc->data, argc, argv, blockarg);
5342 rb_vm_pop_frame(ec);
5350 return vm_yield_with_cfunc(ec, captured, captured->self, argc, argv, 0, VM_BLOCK_HANDLER_NONE, NULL);
5356 VALUE passed_proc = rb_vm_bh_to_procval(ec, block_handler);
5358 if (!rb_box_available()) {
5359 return rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5371 box = current_box_on_cfp(ec, ruby_cfp);
5372 if (BOX_USER_P(box)) {
5375 ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ruby_cfp));
5379 if (!ruby_cfp || !box) {
5380 return rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5388 const rb_iseq_t *caller_iseq = CFP_ISEQ(ruby_cfp);
5389 VALUE name = rb_sprintf(
"block in %"PRIsVALUE, rb_iseq_label(caller_iseq));
5391 rb_iseq_path(caller_iseq), rb_iseq_realpath(caller_iseq),
5392 rb_vm_get_sourceline(ruby_cfp), caller_iseq, 0,
5393 ISEQ_TYPE_BLOCK, NULL,
Qnil);
5395 enum ruby_tag_type state;
5397 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_FINISH,
5398 ruby_cfp->self, VM_GUARDED_PREV_EP(ruby_cfp->ep),
5400 ISEQ_BODY(iseq)->iseq_encoded, reg_cfp->sp,
5401 ISEQ_BODY(iseq)->local_table_size, ISEQ_BODY(iseq)->stack_max);
5409 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
5410 val = rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5414 if (state != TAG_NONE) {
5416 EC_JUMP_TAG(ec, state);
5419 rb_vm_pop_frame(ec);
5430 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5432 for (i=0; i<
len && i<ISEQ_BODY(iseq)->param.lead_num; i++) {
5440vm_callee_setup_block_arg_arg0_check(
VALUE *argv)
5442 VALUE ary, arg0 = argv[0];
5447 VM_ASSERT(argv[0] == arg0);
5455 if (rb_simple_iseq_p(iseq)) {
5459 CALLER_SETUP_ARG(cfp, calling, ci, ISEQ_BODY(iseq)->param.lead_num);
5461 if (arg_setup_type == arg_setup_block &&
5462 calling->argc == 1 &&
5463 ISEQ_BODY(iseq)->param.flags.has_lead &&
5464 !ISEQ_BODY(iseq)->param.flags.ambiguous_param0 &&
5465 !
NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv))) {
5466 calling->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0);
5469 if (calling->argc != ISEQ_BODY(iseq)->param.lead_num) {
5470 if (arg_setup_type == arg_setup_block) {
5471 if (calling->argc < ISEQ_BODY(iseq)->param.lead_num) {
5473 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5474 for (i=calling->argc; i<ISEQ_BODY(iseq)->param.lead_num; i++) argv[i] =
Qnil;
5475 calling->argc = ISEQ_BODY(iseq)->param.lead_num;
5477 else if (calling->argc > ISEQ_BODY(iseq)->param.lead_num) {
5478 calling->argc = ISEQ_BODY(iseq)->param.lead_num;
5482 argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
5489 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_type);
5498 calling = &calling_entry;
5499 calling->argc = argc;
5500 calling->block_handler = block_handler;
5501 calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
5503 calling->heap_argv = 0;
5505 struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
5507 return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);
5518 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
5519 const int arg_size = ISEQ_BODY(iseq)->param.size;
5520 VALUE *
const rsp = GET_SP() - calling->argc;
5521 VALUE *
const argv = rsp;
5522 int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block);
5523 int frame_flag = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
5528 vm_push_frame(ec, iseq,
5531 VM_GUARDED_PREV_EP(captured->ep), (
VALUE)cref,
5532 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
5534 ISEQ_BODY(iseq)->local_table_size - arg_size, ISEQ_BODY(iseq)->stack_max);
5542 bool is_lambda,
VALUE block_handler)
5544 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, NULL);
5550 MAYBE_UNUSED(
bool is_lambda),
VALUE block_handler)
5552 VALUE symbol = VM_BH_TO_SYMBOL(block_handler);
5553 int flags = vm_ci_flag(ci);
5555 if (UNLIKELY(!(flags & VM_CALL_ARGS_SIMPLE) &&
5556 ((calling->argc == 0) ||
5557 (calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
5558 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
5559 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc))))) {
5560 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
5562 if (UNLIKELY(calling->heap_argv)) {
5563#if VM_ARGC_STACK_MAX < 0
5565 rb_raise(rb_eArgError,
"no receiver given");
5571 reg_cfp->sp[-1] = reg_cfp->sp[-2];
5572 reg_cfp->sp[-2] = calling->recv;
5573 flags |= VM_CALL_ARGS_SPLAT;
5576 if (calling->argc < 1) {
5577 rb_raise(rb_eArgError,
"no receiver given");
5579 calling->recv = TOPN(--calling->argc);
5581 if (calling->kw_splat) {
5582 flags |= VM_CALL_KW_SPLAT;
5586 if (calling->argc < 1) {
5587 rb_raise(rb_eArgError,
"no receiver given");
5589 calling->recv = TOPN(--calling->argc);
5592 return vm_call_symbol(ec, reg_cfp, calling, ci, symbol, flags);
5598 MAYBE_UNUSED(
bool is_lambda),
VALUE block_handler)
5603 CALLER_SETUP_ARG(ec->cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
5604 argc = calling->argc;
5605 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);
5611vm_block_to_block_handler(
const struct rb_block *block)
5613 switch (vm_block_type(block)) {
5614 case block_type_iseq:
5615 return VM_BH_FROM_ISEQ_BLOCK(&block->as.captured);
5616 case block_type_ifunc:
5617 return VM_BH_FROM_IFUNC_BLOCK(&block->as.captured);
5618 case block_type_symbol:
5619 return VM_BH_FROM_SYMBOL(block->as.symbol);
5620 case block_type_proc:
5621 return VM_BH_FROM_PROC(block->as.proc);
5623 VM_UNREACHABLE(vm_yield_with_proc);
5628vm_proc_to_block_handler(
VALUE procval)
5630 return vm_block_to_block_handler(vm_proc_block(procval));
5633NOINLINE(
static VALUE
5636 bool is_lambda,
VALUE block_handler,
VALUE refined_procval));
5640 bool is_lambda,
VALUE block_handler,
VALUE refined_procval)
5642 const rb_cref_t *cref = rb_proc_refinements_cref_for_call(refined_procval);
5643 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, cref);
5649 bool is_lambda,
VALUE block_handler)
5651 VALUE refined_procval = 0;
5653 while (vm_block_handler_type(block_handler) == block_handler_type_proc) {
5654 VALUE procval = VM_BH_TO_PROC(block_handler);
5656 GetProcPtr(procval, po);
5657 if (po->header.is_refined) refined_procval = procval;
5658 is_lambda = po->header.is_lambda;
5659 block_handler = vm_block_to_block_handler(&po->block);
5662 if (UNLIKELY(refined_procval) && vm_block_handler_type(block_handler) == block_handler_type_iseq) {
5664 return vm_invoke_proc_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler,
5668 return vm_invoke_block(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5674 bool is_lambda,
VALUE block_handler)
5678 bool is_lambda,
VALUE block_handler);
5680 switch (vm_block_handler_type(block_handler)) {
5681 case block_handler_type_iseq: func = vm_invoke_iseq_block;
break;
5682 case block_handler_type_ifunc: func = vm_invoke_ifunc_block;
break;
5683 case block_handler_type_proc: func = vm_invoke_proc_block;
break;
5684 case block_handler_type_symbol: func = vm_invoke_symbol_block;
break;
5685 default: rb_bug(
"vm_invoke_block: unreachable");
5688 return func(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5692vm_make_proc_with_iseq(
const rb_iseq_t *blockiseq)
5699 rb_bug(
"vm_make_proc_with_iseq: unreachable");
5702 captured = VM_CFP_TO_CAPTURED_BLOCK(cfp);
5703 captured->code.iseq = blockiseq;
5705 return rb_vm_make_proc(ec, captured,
rb_cProc);
5709vm_once_exec(
VALUE iseq)
5715#define RUNNING_THREAD_ONCE_DONE ((rb_thread_t *)0x1)
5731vm_once_wait_no_gvl(
void *ptr)
5738 running_th = rbimpl_atomic_ptr_load((
void **)&arg->is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
5739 if (running_th != NULL && running_th != RUNNING_THREAD_ONCE_DONE) {
5747vm_once_wait_ubf(
void *ptr)
5749 vm_once_broadcast((
rb_vm_t *)ptr);
5753vm_once_clear(
VALUE data)
5756 rbimpl_atomic_ptr_store((
volatile void **)&is->once.running_thread, NULL, RBIMPL_ATOMIC_RELEASE);
5757 vm_once_broadcast(GET_VM());
5769 args[0] = obj; args[1] =
Qfalse;
5771 if (!UNDEF_P(r) &&
RTEST(r)) {
5783 enum defined_type
type = (
enum defined_type)op_type;
5790 return rb_gvar_defined(
SYM2ID(obj));
5792 case DEFINED_CVAR: {
5793 const rb_cref_t *cref = vm_get_cref(GET_EP());
5794 klass = vm_get_cvar_base(cref, GET_CFP(), 0);
5799 case DEFINED_CONST_FROM: {
5800 bool allow_nil =
type == DEFINED_CONST;
5802 return vm_get_ev_const(ec, klass,
SYM2ID(obj), allow_nil,
true);
5807 return rb_ec_obj_respond_to(ec, v,
SYM2ID(obj), TRUE);
5809 case DEFINED_METHOD:{
5814 switch (METHOD_ENTRY_VISI(cme)) {
5815 case METHOD_VISI_PRIVATE:
5817 case METHOD_VISI_PROTECTED:
5821 case METHOD_VISI_PUBLIC:
5825 rb_bug(
"vm_defined: unreachable: %u", (
unsigned int)METHOD_ENTRY_VISI(cme));
5829 return check_respond_to_missing(obj, v);
5834 if (GET_BLOCK_HANDLER() != VM_BLOCK_HANDLER_NONE) {
5838 case DEFINED_ZSUPER:
5843 VALUE klass = vm_search_normal_superclass(me->defined_class);
5844 if (!klass)
return false;
5846 ID id = me->def->original_id;
5853 return RTEST(vm_backref_defined(ec, GET_LEP(),
FIX2INT(obj)));
5855 rb_bug(
"unimplemented defined? type (VM)");
5865 return vm_defined(ec, reg_cfp, op_type, obj, v);
5869vm_get_ep(
const VALUE *
const reg_ep, rb_num_t lv)
5872 const VALUE *ep = reg_ep;
5873 for (i = 0; i < lv; i++) {
5874 ep = GET_PREV_EP(ep);
5880vm_get_special_object(
const VALUE *
const reg_ep,
5881 enum vm_special_object_type
type)
5884 case VM_SPECIAL_OBJECT_VMCORE:
5885 return rb_mRubyVMFrozenCore;
5886 case VM_SPECIAL_OBJECT_CBASE:
5887 return vm_get_cbase(reg_ep);
5888 case VM_SPECIAL_OBJECT_CONST_BASE:
5889 return vm_get_const_base(reg_ep);
5891 rb_bug(
"putspecialobject insn: unknown value_type %d",
type);
5898rb_vm_get_special_object(
const VALUE *reg_ep,
enum vm_special_object_type
type)
5900 return vm_get_special_object(reg_ep,
type);
5906 const VALUE ary2 = ary2st;
5907 VALUE tmp1 = rb_check_to_array(ary1);
5908 VALUE tmp2 = rb_check_to_array(ary2);
5929 const VALUE ary2 = ary2st;
5931 if (
NIL_P(ary2))
return ary1;
5933 VALUE tmp2 = rb_check_to_array(ary2);
5948 return vm_concat_array(ary1, ary2st);
5952rb_vm_concat_to_array(
VALUE ary1,
VALUE ary2st)
5954 return vm_concat_to_array(ary1, ary2st);
5963 VALUE tmp = rb_check_to_array(ary);
5967 else if (
RTEST(flag)) {
5980 return vm_splat_array(flag, ary);
5986 enum vm_check_match_type
type = ((int)flag) & VM_CHECKMATCH_TYPE_MASK;
5988 if (flag & VM_CHECKMATCH_ARRAY) {
5992 for (i = 0; i < n; i++) {
5994 VALUE c = check_match(ec, v, target,
type);
6003 return check_match(ec, pattern, target,
type);
6010 return vm_check_match(ec, target, pattern, flag);
6014vm_check_keyword(lindex_t bits, lindex_t idx,
const VALUE *ep)
6016 const VALUE kw_bits = *(ep - bits);
6019 unsigned int b = (
unsigned int)
FIX2ULONG(kw_bits);
6020 if ((idx < VM_KW_SPECIFIED_BITS_MAX) && (b & (0x01 << idx)))
6024 VM_ASSERT(rb_set_p(kw_bits),
"%s", rb_obj_info(kw_bits));
6033 if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() ||
6034 RUBY_DTRACE_METHOD_RETURN_ENABLED() ||
6035 RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() ||
6036 RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) {
6040 RUBY_DTRACE_METHOD_ENTRY_HOOK(ec, 0, 0);
6043 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, 0, 0);
6046 RUBY_DTRACE_METHOD_RETURN_HOOK(ec, 0, 0);
6049 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, 0, 0);
6056vm_const_get_under(
ID id, rb_num_t flags,
VALUE cbase)
6061 else if (VM_DEFINECLASS_SCOPED_P(flags)) {
6062 return rb_public_const_get_at(cbase,
id);
6070vm_check_if_class(
ID id, rb_num_t flags,
VALUE super,
VALUE klass)
6075 else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) {
6080 "superclass mismatch for class %"PRIsVALUE
"",
6093vm_check_if_module(
ID id,
VALUE mod)
6112vm_declare_class(
ID id, rb_num_t flags,
VALUE cbase,
VALUE super)
6115 VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super :
rb_cObject;
6122vm_declare_module(
ID id,
VALUE cbase)
6128NORETURN(
static void unmatched_redefinition(
const char *
type,
VALUE cbase,
ID id,
VALUE old));
6132 VALUE name = rb_id2str(
id);
6133 VALUE message = rb_sprintf(
"%"PRIsVALUE
" is not a %s",
6135 VALUE location = rb_const_source_location_at(cbase,
id);
6136 if (!
NIL_P(location)) {
6137 rb_str_catf(message,
"\n%"PRIsVALUE
":%"PRIsVALUE
":"
6138 " previous definition of %"PRIsVALUE
" was here",
6145vm_define_class(
ID id, rb_num_t flags,
VALUE cbase,
VALUE super)
6149 if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) && !
RB_TYPE_P(super,
T_CLASS)) {
6151 "superclass must be an instance of Class (given an instance of %"PRIsVALUE
")",
6155 vm_check_if_namespace(cbase);
6160 if ((klass = vm_const_get_under(
id, flags, cbase)) != 0) {
6161 if (!vm_check_if_class(
id, flags, super, klass))
6162 unmatched_redefinition(
"class", cbase,
id, klass);
6166 return vm_declare_class(
id, flags, cbase, super);
6171vm_define_module(
ID id, rb_num_t flags,
VALUE cbase)
6175 vm_check_if_namespace(cbase);
6176 if ((mod = vm_const_get_under(
id, flags, cbase)) != 0) {
6177 if (!vm_check_if_module(
id, mod))
6178 unmatched_redefinition(
"module", cbase,
id, mod);
6182 return vm_declare_module(
id, cbase);
6187vm_find_or_create_class_by_id(
ID id,
6192 rb_vm_defineclass_type_t
type = VM_DEFINECLASS_TYPE(flags);
6195 case VM_DEFINECLASS_TYPE_CLASS:
6197 return vm_define_class(
id, flags, cbase, super);
6199 case VM_DEFINECLASS_TYPE_SINGLETON_CLASS:
6203 case VM_DEFINECLASS_TYPE_MODULE:
6205 return vm_define_module(
id, flags, cbase);
6208 rb_bug(
"unknown defineclass type: %d", (
int)
type);
6212static rb_method_visibility_t
6217 if (!vm_env_cref_by_cref(cfp->ep)) {
6218 return METHOD_VISI_PUBLIC;
6221 return CREF_SCOPE_VISI(vm_ec_cref(ec))->method_visi;
6230 if (!vm_env_cref_by_cref(cfp->ep)) {
6234 return CREF_SCOPE_VISI(vm_ec_cref(ec))->module_func;
6242 rb_method_visibility_t visi;
6247 visi = METHOD_VISI_PUBLIC;
6250 klass = CREF_CLASS_FOR_DEFINITION(cref);
6251 visi = vm_scope_visibility_get(ec);
6258 rb_add_method_iseq(klass,
id, (
const rb_iseq_t *)iseqval, cref, visi);
6261 !RCLASS_SINGLETON_P(klass) && !RCLASS_EXPECT_NO_IVAR(klass) &&
6263 RCLASS_SET_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (
const rb_iseq_t *)iseqval));
6266 if (!is_singleton && vm_scope_module_func_check(ec)) {
6268 rb_add_method_iseq(klass,
id, (
const rb_iseq_t *)iseqval, cref, METHOD_VISI_PUBLIC);
6277rb_vm_untag_block_handler(
VALUE block_handler)
6279 if (VM_BLOCK_HANDLER_NONE == block_handler)
return Qnil;
6281 switch (vm_block_handler_type(block_handler)) {
6282 case block_handler_type_iseq:
6283 case block_handler_type_ifunc: {
6285 return captured->code.val;
6287 case block_handler_type_proc:
6288 case block_handler_type_symbol:
6289 return block_handler;
6291 rb_bug(
"rb_vm_untag_block_handler: unreachable");
6298 return rb_vm_untag_block_handler(VM_CF_BLOCK_HANDLER(reg_cfp));
6307 VALUE block_handler = VM_CF_BLOCK_HANDLER(GET_CFP());
6309 if (block_handler == VM_BLOCK_HANDLER_NONE) {
6310 rb_vm_localjump_error(
"no block given (yield)",
Qnil, 0);
6313 return vm_invoke_block(ec, GET_CFP(), calling, ci,
false, block_handler);
6317enum method_explorer_type {
6319 mexp_search_invokeblock,
6326 enum method_explorer_type method_explorer));
6332 VALUE block_handler,
6333 enum method_explorer_type method_explorer
6338 int argc = vm_ci_argc(ci);
6339 VALUE recv = TOPN(argc);
6341 .block_handler = block_handler,
6342 .kw_splat = IS_ARGS_KW_SPLAT(ci) > 0,
6348 switch (method_explorer) {
6349 case mexp_search_method:
6350 calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd,
CLASS_OF(recv));
6351 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6353 case mexp_search_super:
6354 calling.cc = cc = vm_search_super_method(reg_cfp, cd, recv);
6355 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6357 case mexp_search_invokeblock:
6358 val = vm_invokeblock_i(ec, GET_CFP(), &calling);
6368 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq,
false);
6369 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6383 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq,
false, &adjusted_cd, &adjusted_ci);
6385 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
6387 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6388 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6399 VALUE bh = VM_BLOCK_HANDLER_NONE;
6400 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6410 struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
6413 vm_ci_kwarg(cd->ci));
6414 const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((
void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
6420 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq,
true);
6421 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
6423 if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
6424 rbimpl_atomic_ptr_store((
volatile void **)&cd->cc, (
void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
6440 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq,
true, &adjusted_cd, &adjusted_ci);
6442 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
6444 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6445 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6456 VALUE bh = VM_BLOCK_HANDLER_NONE;
6457 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
6485 if (check_method_basic_definition(cme)) {
6491 if (check_cfunc(cme, rb_mod_to_s)) {
6497 val = rb_mod_to_s(recv);
6503 if (check_cfunc(cme, rb_nil_to_s)) {
6504 return rb_nil_to_s(recv);
6508 if (check_cfunc(cme, rb_true_to_s)) {
6509 return rb_true_to_s(recv);
6513 if (check_cfunc(cme, rb_false_to_s)) {
6514 return rb_false_to_s(recv);
6518 if (check_cfunc(cme, rb_int_to_s)) {
6519 return rb_fix_to_s(recv);
6531 return vm_objtostring(reg_cfp, recv, cd);
6535vm_opt_ary_freeze(
VALUE ary,
int bop,
ID id)
6537 if (BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
6546vm_opt_hash_freeze(
VALUE hash,
int bop,
ID id)
6548 if (BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
6557vm_opt_str_freeze(
VALUE str,
int bop,
ID id)
6559 if (BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
6573 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6577 VALUE args[1] = {target};
6580 RUBY_DTRACE_CREATE_HOOK(ARRAY,
RARRAY_LEN(ary));
6583 return rb_vm_call_with_refinements(ec, dupary, idIncludeP, 1, args,
RB_NO_KEYWORDS);
6590 return vm_opt_duparray_include_p(ec, ary, target);
6596 if (OP_UNREDEFINED_P(MAX, ARRAY)) {
6597 if (array_len == 0) {
6601 VALUE result = *ptr;
6602 rb_snum_t i = array_len - 1;
6604 const VALUE v = *++ptr;
6605 if (OPTIMIZED_CMP(v, result) > 0) {
6620 return vm_opt_newarray_max(ec, array_len, ptr);
6626 if (OP_UNREDEFINED_P(MIN, ARRAY)) {
6627 if (array_len == 0) {
6631 VALUE result = *ptr;
6632 rb_snum_t i = array_len - 1;
6634 const VALUE v = *++ptr;
6635 if (OPTIMIZED_CMP(v, result) < 0) {
6650 return vm_opt_newarray_min(ec, array_len, ptr);
6657 if (OP_UNREDEFINED_P(HASH, ARRAY)) {
6658 return rb_ary_hash_values(array_len, ptr);
6668 return vm_opt_newarray_hash(ec, array_len, ptr);
6677 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6678 struct RArray fake_ary = {RBASIC_INIT};
6679 VALUE ary = rb_setup_fake_ary(&fake_ary,
ptr, array_len);
6683 VALUE args[1] = {target};
6691 return vm_opt_newarray_include_p(ec, array_len,
ptr, target);
6697 if (OP_UNREDEFINED_P(PACK, ARRAY)) {
6698 struct RArray fake_ary = {RBASIC_INIT};
6699 VALUE ary = rb_setup_fake_ary(&fake_ary,
ptr, array_len);
6700 return rb_ec_pack_ary(ec,
ary, fmt, (UNDEF_P(buffer) ?
Qnil : buffer));
6710 if (!UNDEF_P(buffer)) {
6711 args[1] = rb_hash_new_capa(1);
6712 rb_hash_aset(args[1],
ID2SYM(idBuffer), buffer);
6717 return rb_vm_call_with_refinements(ec,
rb_ary_new4(array_len,
ptr), idPack, argc, args, kw_splat);
6724 return vm_opt_newarray_pack_buffer(ec, array_len,
ptr, fmt, buffer);
6731vm_track_constant_cache(
ID id,
void *ic)
6734 struct rb_id_table *const_cache = &vm->constant_cache;
6735 VALUE lookup_result;
6738 if (rb_id_table_lookup(const_cache,
id, &lookup_result)) {
6742 ics = set_init_numtable();
6743 rb_id_table_insert(const_cache,
id, (
VALUE)ics);
6758 vm->inserting_constant_cache_id = id;
6760 set_insert(ics, (st_data_t)ic);
6762 vm->inserting_constant_cache_id = (
ID)0;
6769 for (
int i = 0; segments[i]; i++) {
6770 ID id = segments[i];
6771 if (
id == idNULL)
continue;
6772 vm_track_constant_cache(
id, ic);
6783 if ((flags & IMEMO_CONST_CACHE_SHAREABLE) || ractor_id == rb_ractor_id(GET_RACTOR())) {
6784 VM_ASSERT(ractor_incidental_shareable_p(flags & IMEMO_CONST_CACHE_SHAREABLE, value));
6786 return (ic_cref == NULL ||
6787 ic_cref == vm_get_cref(reg_ep));
6795 VM_ASSERT(IMEMO_TYPE_P(ice, imemo_constcache));
6796 return vm_inlined_ic_hit_p(ice->flags, ice->value, ice->ic_cref, ice->ractor_id, reg_ep);
6801rb_vm_ic_hit_p(
IC ic,
const VALUE *reg_ep)
6803 return ic->entry && vm_ic_hit_p(ic->entry, reg_ep);
6809 if (ruby_vm_const_missing_count > 0) {
6810 ruby_vm_const_missing_count = 0;
6817 ice->ic_cref = vm_get_const_key_cref(reg_ep);
6818 ice->ractor_id = rb_ractor_id(GET_RACTOR());
6822 ice->flags |= IMEMO_CONST_CACHE_SHAREABLE;
6826 unsigned pos = (unsigned)(pc - ISEQ_BODY(iseq)->iseq_encoded);
6827 rb_yjit_constant_ic_update(iseq, ic, pos);
6837 if (ice && vm_ic_hit_p(ice, GET_EP())) {
6844 VM_ASSERT(val == vm_get_ev_const_chain(ec, segments) || rb_multi_ractor_p());
6847 ruby_vm_constant_cache_misses++;
6848 val = vm_get_ev_const_chain(ec, segments);
6849 vm_ic_track_const_chain(GET_CFP(), ic, segments);
6852 vm_ic_update(CFP_ISEQ(GET_CFP()), ic, val, GET_EP(), CFP_PC(GET_CFP()) - 2);
6861rb_vm_once_done_value(
ISE is,
VALUE *result)
6863 rb_thread_t *running_th = rbimpl_atomic_ptr_load((
void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6864 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6865 *result = is->once.value;
6878 running_th = rbimpl_atomic_ptr_load((
void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6879 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6880 return is->once.value;
6882 else if (running_th == NULL) {
6884 enum ruby_tag_type state;
6885 if (rbimpl_atomic_ptr_cas((
void**)&is->once.running_thread, running_th, th, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED) != running_th) {
6889 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
6890 val = vm_once_exec((
VALUE)iseq);
6893 if (state != TAG_NONE) {
6894 vm_once_clear((
VALUE)is);
6895 EC_JUMP_TAG(ec, state);
6905 rbimpl_atomic_ptr_store((
volatile void**)&is->once.running_thread, RUNNING_THREAD_ONCE_DONE, RBIMPL_ATOMIC_RELEASE);
6906 vm_once_broadcast(rb_ec_vm_ptr(ec));
6909 else if (running_th == th) {
6911 return vm_once_exec((
VALUE)iseq);
6916 rb_nogvl(vm_once_wait_no_gvl, &arg, vm_once_wait_ubf, arg.vm,
6918 RUBY_VM_CHECK_INTS(ec);
6924vm_case_dispatch(CDHASH hash, OFFSET else_offset,
VALUE key)
6926 switch (OBJ_BUILTIN_TYPE(key)) {
6932 if (BASIC_OP_UNREDEFINED_P(BOP_EQQ,
6933 SYMBOL_REDEFINED_OP_FLAG |
6934 INTEGER_REDEFINED_OP_FLAG |
6935 FLOAT_REDEFINED_OP_FLAG |
6936 NIL_REDEFINED_OP_FLAG |
6937 TRUE_REDEFINED_OP_FLAG |
6938 FALSE_REDEFINED_OP_FLAG |
6939 STRING_REDEFINED_OP_FLAG)) {
6943 if (!isinf(kval) && modf(kval, &kval) == 0.0) {
6947 if (st_lookup(rb_imemo_cdhash_tbl(hash), key, &val)) {
6967 const ptrdiff_t nsp = VM_SP_CNT(ec, cfp->sp);
6968 const ptrdiff_t nbp = VM_SP_CNT(ec, bp);
6969 static const char stack_consistency_error[] =
6970 "Stack consistency error (sp: %"PRIdPTRDIFF
", bp: %"PRIdPTRDIFF
")";
6971#if defined RUBY_DEVEL
6972 VALUE mesg = rb_sprintf(stack_consistency_error, nsp, nbp);
6977 rb_bug(stack_consistency_error, nsp, nbp);
6984 if (FIXNUM_2_P(recv, obj) &&
6985 OP_UNREDEFINED_P(PLUS, INTEGER)) {
6986 return rb_fix_plus_fix(recv, obj);
6988 else if (FLONUM_2_P(recv, obj) &&
6989 OP_UNREDEFINED_P(PLUS, FLOAT)) {
6997 OP_UNREDEFINED_P(PLUS, FLOAT)) {
7002 OP_UNREDEFINED_P(PLUS, STRING)) {
7003 return rb_str_opt_plus(recv, obj);
7007 OP_UNREDEFINED_P(PLUS, ARRAY)) {
7018 if (FIXNUM_2_P(recv, obj) &&
7019 OP_UNREDEFINED_P(MINUS, INTEGER)) {
7020 return rb_fix_minus_fix(recv, obj);
7022 else if (FLONUM_2_P(recv, obj) &&
7023 OP_UNREDEFINED_P(MINUS, FLOAT)) {
7031 OP_UNREDEFINED_P(MINUS, FLOAT)) {
7042 if (FIXNUM_2_P(recv, obj) &&
7043 OP_UNREDEFINED_P(MULT, INTEGER)) {
7044 return rb_fix_mul_fix(recv, obj);
7046 else if (FLONUM_2_P(recv, obj) &&
7047 OP_UNREDEFINED_P(MULT, FLOAT)) {
7055 OP_UNREDEFINED_P(MULT, FLOAT)) {
7066 if (FIXNUM_2_P(recv, obj) &&
7067 OP_UNREDEFINED_P(DIV, INTEGER)) {
7068 return (
FIX2LONG(obj) == 0) ?
Qundef : rb_fix_div_fix(recv, obj);
7070 else if (FLONUM_2_P(recv, obj) &&
7071 OP_UNREDEFINED_P(DIV, FLOAT)) {
7072 return rb_flo_div_flo(recv, obj);
7079 OP_UNREDEFINED_P(DIV, FLOAT)) {
7080 return rb_flo_div_flo(recv, obj);
7090 if (FIXNUM_2_P(recv, obj) &&
7091 OP_UNREDEFINED_P(MOD, INTEGER)) {
7092 return (
FIX2LONG(obj) == 0) ?
Qundef : rb_fix_mod_fix(recv, obj);
7094 else if (FLONUM_2_P(recv, obj) &&
7095 OP_UNREDEFINED_P(MOD, FLOAT)) {
7103 OP_UNREDEFINED_P(MOD, FLOAT)) {
7114 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
7115 VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);
7117 if (!UNDEF_P(val)) {
7118 return RBOOL(!
RTEST(val));
7128 if (FIXNUM_2_P(recv, obj) &&
7129 OP_UNREDEFINED_P(LT, INTEGER)) {
7132 else if (FLONUM_2_P(recv, obj) &&
7133 OP_UNREDEFINED_P(LT, FLOAT)) {
7141 OP_UNREDEFINED_P(LT, FLOAT)) {
7152 if (FIXNUM_2_P(recv, obj) &&
7153 OP_UNREDEFINED_P(LE, INTEGER)) {
7156 else if (FLONUM_2_P(recv, obj) &&
7157 OP_UNREDEFINED_P(LE, FLOAT)) {
7165 OP_UNREDEFINED_P(LE, FLOAT)) {
7176 if (FIXNUM_2_P(recv, obj) &&
7177 OP_UNREDEFINED_P(GT, INTEGER)) {
7180 else if (FLONUM_2_P(recv, obj) &&
7181 OP_UNREDEFINED_P(GT, FLOAT)) {
7189 OP_UNREDEFINED_P(GT, FLOAT)) {
7200 if (FIXNUM_2_P(recv, obj) &&
7201 OP_UNREDEFINED_P(GE, INTEGER)) {
7204 else if (FLONUM_2_P(recv, obj) &&
7205 OP_UNREDEFINED_P(GE, FLOAT)) {
7213 OP_UNREDEFINED_P(GE, FLOAT)) {
7229 OP_UNREDEFINED_P(LTLT, STRING)) {
7238 OP_UNREDEFINED_P(LTLT, ARRAY)) {
7256 OP_UNREDEFINED_P(AND, INTEGER)) {
7267 if (FIXNUM_2_P(recv, obj) &&
7268 OP_UNREDEFINED_P(OR, INTEGER)) {
7280 if (FIXNUM_2_P(recv, obj) &&
7281 OP_UNREDEFINED_P(AREF, INTEGER)) {
7282 return rb_fix_aref(recv, obj);
7287 OP_UNREDEFINED_P(AREF, ARRAY)) {
7289 return rb_ary_entry_internal(recv,
FIX2LONG(obj));
7292 return rb_ary_aref1(recv, obj);
7296 OP_UNREDEFINED_P(AREF, HASH)) {
7297 return rb_hash_aref(recv, obj);
7311 OP_UNREDEFINED_P(ASET, ARRAY) &&
7317 OP_UNREDEFINED_P(ASET, HASH)) {
7318 rb_hash_aset(recv, obj, set);
7327vm_opt_length(
VALUE recv,
int bop)
7333 BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
7334 if (bop == BOP_EMPTY_P) {
7335 return LEN2NUM(RSTRING_LEN(recv));
7342 BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
7346 BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
7355vm_opt_empty_p(
VALUE recv)
7357 switch (vm_opt_length(recv, BOP_EMPTY_P)) {
7370 OP_UNREDEFINED_P(
NIL_P, NIL)) {
7373 else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
7389 case RSHIFT(~0UL, 1):
7392 return rb_uint2big(1UL << (SIZEOF_LONG * CHAR_BIT - 2));
7410vm_opt_succ(
VALUE recv)
7413 OP_UNREDEFINED_P(SUCC, INTEGER)) {
7414 return fix_succ(recv);
7420 OP_UNREDEFINED_P(SUCC, STRING)) {
7431 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
7432 return RBOOL(!
RTEST(recv));
7447 OP_UNREDEFINED_P(MATCH, STRING)) {
7451 OP_UNREDEFINED_P(MATCH, REGEXP)) {
7459#undef EQ_UNREDEFINED_P
7460#undef OP_UNREDEFINED_P
7472 VALUE self = GET_SELF();
7474 VM_ASSERT(rb_popcount64((uint64_t)event) == 1);
7476 if (local_hooks) local_hooks->running++;
7478 if (event & global_hooks->events) {
7481 vm_dtrace(event, ec);
7482 rb_exec_event_hook_orig(ec, global_hooks, event, self, 0, 0, 0 , val, 0);
7486 if (local_hooks) local_hooks->running--;
7487 if (local_hooks != NULL) {
7488 if (event & local_hooks->events) {
7491 rb_exec_event_hook_orig(ec, local_hooks, event, self, 0, 0, 0 , val, 0);
7501#define VM_TRACE_HOOK(target_event, val) do { \
7502 if ((pc_events & (target_event)) & enabled_flags) { \
7503 if (local_hooks_cnt > 0) local_hooks = rb_iseq_local_hooks(iseq, r, false); \
7504 vm_trace_hook(ec, reg_cfp, pc, pc_events, (target_event), global_hooks, local_hooks, (val)); \
7511 VM_ASSERT(VM_FRAME_RUBYFRAME_P(cfp));
7512 VM_ASSERT(ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_RESCUE);
7513 return cfp->ep[VM_ENV_INDEX_LAST_LVAR];
7519 const VALUE *pc = reg_cfp->pc;
7521 rb_event_flag_t enabled_flags = r->pub.hooks.events & ISEQ_TRACE_EVENTS;
7524 if (enabled_flags == 0 && rb_ractor_targeted_hooks_cnt(r) == 0) {
7528 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
7529 size_t pos = pc - ISEQ_BODY(iseq)->iseq_encoded;
7531 unsigned int local_hooks_cnt = iseq->aux.exec.local_hooks_cnt;
7533 if (RB_UNLIKELY(local_hooks_cnt > 0)) {
7535 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
7539 rb_event_flag_t iseq_local_events = local_hooks != NULL ? local_hooks->events : 0;
7543 unsigned int bmethod_hooks_cnt = 0;
7545 const bool bmethod_frame = VM_FRAME_BMETHOD_P(reg_cfp);
7546 enabled_flags |= iseq_local_events;
7548 VM_ASSERT((iseq_local_events & ~ISEQ_TRACE_EVENTS) == 0);
7550 if (bmethod_frame) {
7552 VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
7553 bmethod_def = me->def;
7554 bmethod_hooks_cnt = me->def->body.bmethod.local_hooks_cnt;
7555 if (RB_UNLIKELY(bmethod_hooks_cnt > 0)) {
7557 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)me->def, &val)) {
7560 if (bmethod_local_hooks) {
7561 bmethod_local_events = bmethod_local_hooks->events;
7566 if ((pc_events & enabled_flags) == 0 && !bmethod_frame) {
7570 rb_iseq_trace_set(iseq, vm_event_flags & ISEQ_TRACE_EVENTS);
7578 else if (ec->trace_arg != NULL) {
7586 rb_event_flag_t bmethod_events = ractor_events | bmethod_local_events;
7589 VALUE path = rb_iseq_path(iseq);
7590 VALUE label = rb_iseq_label(iseq);
7591 ruby_debug_printf(
"vm_trace>>%4d (%4x) - %.*s:%d %.*s\n",
7595 (
int)rb_iseq_line_no(iseq, pos),
7598 VM_ASSERT(reg_cfp->pc == pc);
7599 VM_ASSERT(pc_events != 0);
7609 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_LINE,
Qundef);
7610 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH,
Qundef);
7616 if (bmethod_hooks_cnt > 0) bmethod_local_hooks = rb_method_def_local_hooks(bmethod_def, r,
false);
7624#if VM_CHECK_MODE > 0
7625NORETURN( NOINLINE( COLDFUNC
7626void rb_vm_canary_is_found_dead(
enum ruby_vminsn_type i,
VALUE c)));
7629Init_vm_stack_canary(
void)
7632 int n = ruby_fill_random_bytes(&vm_stack_canary,
sizeof vm_stack_canary,
false);
7635 vm_stack_canary >>= 2;
7637 vm_stack_canary |= 0x01;
7639 vm_stack_canary_was_born =
true;
7644rb_vm_canary_is_found_dead(
enum ruby_vminsn_type i,
VALUE c)
7648 const char *insn = rb_insns_name(i);
7652 rb_bug(
"dead canary found at %s: %s", insn, str);
7656void Init_vm_stack_canary(
void) { }
7688 return (*(rb_invoke_funcptr0_t)funcptr)(ec, self);
7695 return (*(rb_invoke_funcptr1_t)funcptr)(ec, self, argv[0]);
7702 return (*(rb_invoke_funcptr2_t)funcptr)(ec, self, argv[0], argv[1]);
7709 return (*(rb_invoke_funcptr3_t)funcptr)(ec, self, argv[0], argv[1], argv[2]);
7716 return (*(rb_invoke_funcptr4_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3]);
7723 return (*(rb_invoke_funcptr5_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4]);
7730 return (*(rb_invoke_funcptr6_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
7737 return (*(rb_invoke_funcptr7_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
7744 return (*(rb_invoke_funcptr8_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
7750 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);
7751 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]);
7757 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);
7758 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]);
7764 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);
7765 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]);
7771 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);
7772 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]);
7778 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);
7779 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]);
7785 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);
7786 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]);
7792 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);
7793 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]);
7798static builtin_invoker
7799lookup_builtin_invoker(
int argc)
7801 static const builtin_invoker invokers[] = {
7820 return invokers[argc];
7826 const bool canary_p = ISEQ_BODY(CFP_ISEQ(reg_cfp))->builtin_attrs & BUILTIN_ATTR_LEAF;
7827 SETUP_CANARY(canary_p);
7828 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
7829 VALUE ret = (*lookup_builtin_invoker(bf->argc))(ec, reg_cfp->self, argv, func_ptr);
7830 CHECK_CANARY(canary_p, BIN(invokebuiltin));
7837 return invoke_bf(ec, cfp, bf, argv);
7844 fputs(
"vm_invoke_builtin_delegate: passing -> ", stderr);
7845 for (
int i=0; i<bf->argc; i++) {
7846 ruby_debug_printf(
":%s ", rb_id2name(ISEQ_BODY(CFP_ISEQ(cfp))->local_table[i+start_index]));
7848 ruby_debug_printf(
"\n" "%s %s(%d):%p\n", RUBY_FUNCTION_NAME_STRING, bf->name, bf->argc,
7849 (
void *)(uintptr_t)bf->func_ptr);
7852 if (bf->argc == 0) {
7853 return invoke_bf(ec, cfp, bf, NULL);
7856 const VALUE *argv = cfp->ep - ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
7857 return invoke_bf(ec, cfp, bf, argv);
7867 return cfp->ep[index];
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define RUBY_EVENT_END
Encountered an end of a class clause.
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
#define RUBY_EVENT_CLASS
Encountered a new class.
#define RUBY_EVENT_LINE
Encountered a new line.
#define RUBY_EVENT_RETURN
Encountered a return statement.
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
uint32_t rb_event_flag_t
Represents event(s).
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
static bool RB_FL_ABLE(VALUE obj)
Checks if the object is flaggable.
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
VALUE rb_module_new(void)
Creates a new, anonymous module.
VALUE rb_class_inherited(VALUE super, VALUE klass)
Calls Class::inherited.
VALUE rb_define_class_id(ID id, VALUE super)
This is a very badly designed API that creates an anonymous class.
#define TYPE(_)
Old name of rb_type.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define LEN2NUM
Old name of RB_LEN2NUM.
#define T_NIL
Old name of RUBY_T_NIL.
#define T_FLOAT
Old name of RUBY_T_FLOAT.
#define T_IMEMO
Old name of RUBY_T_IMEMO.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define SYM2ID
Old name of RB_SYM2ID.
#define CLASS_OF
Old name of rb_class_of.
#define T_NONE
Old name of RUBY_T_NONE.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define FIXABLE
Old name of RB_FIXABLE.
#define LONG2FIX
Old name of RB_INT2FIX.
#define FIX2INT
Old name of RB_FIX2INT.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define ASSUME
Old name of RBIMPL_ASSUME.
#define FIX2ULONG
Old name of RB_FIX2ULONG.
#define T_TRUE
Old name of RUBY_T_TRUE.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define T_HASH
Old name of RUBY_T_HASH.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define T_FALSE
Old name of RUBY_T_FALSE.
#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.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define T_OBJECT
Old name of RUBY_T_OBJECT.
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define DBL2NUM
Old name of rb_float_new.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define FL_TEST
Old name of RB_FL_TEST.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define FL_USHIFT
Old name of RUBY_FL_USHIFT.
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eFatal
fatal exception.
VALUE rb_eNoMethodError
NoMethodError exception.
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
void rb_error_frozen_object(VALUE frozen_obj)
Identical to rb_error_frozen(), except it takes arbitrary Ruby object instead of C's string.
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.
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
VALUE rb_cClass
Class class.
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_cRegexp
Regexp class.
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
VALUE rb_cHash
Hash class.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_cBasicObject
BasicObject class.
VALUE rb_cModule
Module class.
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
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.
VALUE rb_cFloat
Float class.
VALUE rb_cProc
Proc class.
VALUE rb_cString
String class.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
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_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
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.
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_plus(VALUE lhs, VALUE rhs)
Creates a new array, concatenating the former to the latter.
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(rb_len_t 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_cat(VALUE ary, const VALUE *train, rb_len_t len)
Destructively appends multiple elements at the end of the array.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
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,...
VALUE rb_reg_last_match(VALUE md)
This just returns the argument, stringified.
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
VALUE rb_reg_match_post(VALUE md)
The portion of the original string after the given match.
VALUE rb_reg_nth_defined(int n, VALUE md)
Identical to rb_reg_nth_match(), except it just returns Boolean.
VALUE rb_reg_match_pre(VALUE md)
The portion of the original string before the given match.
VALUE rb_reg_match_last(VALUE md)
The portion of the original string that captured at the very last.
bool rb_set_lookup(VALUE set, VALUE element)
Whether the set contains the given element.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
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.
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
#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.
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
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.
void rb_cvar_set(VALUE klass, ID name, VALUE val)
Assigns a value to a class variable.
VALUE rb_cvar_find(VALUE klass, ID name, VALUE *front)
Identical to rb_cvar_get(), except it takes additional "front" pointer.
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.
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
VALUE rb_autoload_load(VALUE space, ID name)
Kicks the autoload procedure as if it was "touched".
VALUE rb_mod_name(VALUE mod)
Queries the name of a module.
VALUE rb_const_get_at(VALUE space, ID name)
Identical to rb_const_defined_at(), except it returns the actual defined value.
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.
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
int rb_const_defined_at(VALUE space, ID name)
Identical to rb_const_defined(), except it doesn't look for parent classes.
VALUE rb_cvar_defined(VALUE klass, ID name)
Queries if the given class has the given class variable.
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
int rb_const_defined(VALUE space, ID name)
Queries if the constant is defined at the namespace.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
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.
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries the allocator function of a class.
int rb_method_boundp(VALUE klass, ID id, int ex)
Queries if the klass has this method.
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
int off
Offset inside of ptr.
int len
Length of the buffer.
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
#define RB_NOGVL_UBF_ASYNC_SAFE
Passing this flag to rb_nogvl() indicates that the passed UBF is async-signal-safe.
#define RB_NOGVL_INTR_FAIL
Passing this flag to rb_nogvl() prevents it from processing interrupts after the given function retur...
void * rb_nogvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int flags)
Identical to rb_thread_call_without_gvl(), except it additionally takes "flags" that change the behav...
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
static VALUE * RARRAY_PTR(VALUE ary)
Wild use of a C pointer.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RBASIC(obj)
Convenient casting macro.
#define RCLASS_SUPER
Just another name of rb_class_get_superclass.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RB_PASS_KEYWORDS
Pass keywords, final argument must be a hash of keywords.
#define RB_NO_KEYWORDS
Do not pass keywords.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define ANYARGS
Functions declared using this macro take arbitrary arguments, including void.
const VALUE ary[1]
Embedded elements.
const VALUE * ptr
Pointer to the C array that holds the elements of the array.
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Internal header for Ruby Box.
Internal header for Class.
rb_cref_t * cref
class reference, should be marked
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
IFUNC (Internal FUNCtion)
const VALUE cref_or_me
class reference or rb_method_entry_t
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
Waits for the passed condition variable to be signalled.
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.