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 (! (iseq = GET_ISEQ())) {
271 else if (LIKELY(sp[0] != vm_stack_canary)) {
280 const VALUE *orig = rb_iseq_original_iseq(iseq);
281 const VALUE iseqw = rb_iseqw_new(iseq);
283 const char *stri = rb_str_to_cstr(inspection);
284 const VALUE disasm = rb_iseq_disasm(iseq);
285 const char *strd = rb_str_to_cstr(disasm);
286 const ptrdiff_t pos = previous_insn_index(iseq, GET_PC());
287 const enum ruby_vminsn_type insn = (
enum ruby_vminsn_type)orig[pos];
288 const char *name = insn_name(insn);
294 "We are killing the stack canary set by %s, "
295 "at %s@pc=%"PRIdPTR
"\n"
296 "watch out the C stack trace.\n"
298 name, stri, pos, strd);
299 rb_bug(
"see above.");
301#define vm_check_canary(ec, sp) rb_vm_check_canary(ec, sp)
304#define vm_check_canary(ec, sp)
305#define vm_check_frame(a, b, c, d)
310vm_push_frame_debug_counter_inc(
317 RB_DEBUG_COUNTER_INC(frame_push);
319 if (RUBY_VM_END_CONTROL_FRAME(ec) != prev_cfp) {
320 const bool curr = VM_FRAME_RUBYFRAME_P(reg_cfp);
321 const bool prev = VM_FRAME_RUBYFRAME_P(prev_cfp);
324 RB_DEBUG_COUNTER_INC(frame_R2R);
327 RB_DEBUG_COUNTER_INC(frame_R2C);
332 RB_DEBUG_COUNTER_INC(frame_C2R);
335 RB_DEBUG_COUNTER_INC(frame_C2C);
340 switch (
type & VM_FRAME_MAGIC_MASK) {
341 case VM_FRAME_MAGIC_METHOD: RB_DEBUG_COUNTER_INC(frame_push_method);
return;
342 case VM_FRAME_MAGIC_BLOCK: RB_DEBUG_COUNTER_INC(frame_push_block);
return;
343 case VM_FRAME_MAGIC_CLASS: RB_DEBUG_COUNTER_INC(frame_push_class);
return;
344 case VM_FRAME_MAGIC_TOP: RB_DEBUG_COUNTER_INC(frame_push_top);
return;
345 case VM_FRAME_MAGIC_CFUNC: RB_DEBUG_COUNTER_INC(frame_push_cfunc);
return;
346 case VM_FRAME_MAGIC_IFUNC: RB_DEBUG_COUNTER_INC(frame_push_ifunc);
return;
347 case VM_FRAME_MAGIC_EVAL: RB_DEBUG_COUNTER_INC(frame_push_eval);
return;
348 case VM_FRAME_MAGIC_RESCUE: RB_DEBUG_COUNTER_INC(frame_push_rescue);
return;
349 case VM_FRAME_MAGIC_DUMMY: RB_DEBUG_COUNTER_INC(frame_push_dummy);
return;
352 rb_bug(
"unreachable");
355#define vm_push_frame_debug_counter_inc(ec, cfp, t)
360rb_vm_stack_canary(
void)
363 return vm_stack_canary;
369STATIC_ASSERT(VM_ENV_DATA_INDEX_ME_CREF, VM_ENV_DATA_INDEX_ME_CREF == -2);
370STATIC_ASSERT(VM_ENV_DATA_INDEX_SPECVAL, VM_ENV_DATA_INDEX_SPECVAL == -1);
371STATIC_ASSERT(VM_ENV_DATA_INDEX_FLAGS, VM_ENV_DATA_INDEX_FLAGS == -0);
387 vm_check_frame(
type, specval, cref_or_me, iseq);
388 VM_ASSERT(local_size >= 0);
391 CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + stack_max);
392 vm_check_canary(ec, sp);
397 for (
int i=0; i < local_size; i++) {
424 #if defined HAVE_DECL_ATOMIC_SIGNAL_FENCE && HAVE_DECL_ATOMIC_SIGNAL_FENCE
425 atomic_signal_fence(memory_order_seq_cst);
433 vm_push_frame_debug_counter_inc(ec, cfp,
type);
441 if (VMDEBUG == 2) SDR();
443 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
450 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
452 if (VMDEBUG == 2) SDR();
454 RUBY_VM_CHECK_INTS(ec);
455 ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
457 return flags & VM_FRAME_FLAG_FINISH;
463 vm_pop_frame(ec, ec->cfp, ec->cfp->ep);
471 rb_iseq_t *dmy_iseq = rb_iseq_alloc_with_dummy_path(fname);
475 VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
477 VM_BLOCK_HANDLER_NONE,
484 return (
VALUE)dmy_iseq;
489rb_arity_error_new(
int argc,
int min,
int max)
491 VALUE err_mess = rb_sprintf(
"wrong number of arguments (given %d, expected %d", argc, min);
499 rb_str_catf(err_mess,
"..%d", max);
506rb_error_arity(
int argc,
int min,
int max)
513NOINLINE(
static void vm_env_write_slowpath(
const VALUE *ep,
int index,
VALUE v));
516vm_env_write_slowpath(
const VALUE *ep,
int index,
VALUE v)
518 const VALUE envval = VM_ENV_ENVVAL(ep);
525 rb_gc_writebarrier(envval, v);
527 VM_FORCE_WRITE(&ep[index], v);
531 rb_gc_writebarrier_remember(envval);
532 VM_FORCE_WRITE(&ep[index], v);
533 VM_ENV_FLAGS_UNSET(ep, VM_ENV_FLAG_WB_REQUIRED);
535 RB_DEBUG_COUNTER_INC(lvar_set_slowpath);
540vm_env_write(
const VALUE *ep,
int index,
VALUE v)
542 VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
543 if (LIKELY((flags & VM_ENV_FLAG_WB_REQUIRED) == 0)) {
544 VM_STACK_ENV_WRITE(ep, index, v);
547 vm_env_write_slowpath(ep, index, v);
552rb_vm_env_write(
const VALUE *ep,
int index,
VALUE v)
554 vm_env_write(ep, index, v);
560 if (block_handler == VM_BLOCK_HANDLER_NONE) {
564 switch (vm_block_handler_type(block_handler)) {
565 case block_handler_type_iseq:
566 case block_handler_type_ifunc:
567 return rb_vm_make_proc(ec, VM_BH_TO_CAPT_BLOCK(block_handler),
rb_cProc);
568 case block_handler_type_symbol:
569 return rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler));
570 case block_handler_type_proc:
571 return VM_BH_TO_PROC(block_handler);
573 VM_UNREACHABLE(rb_vm_bh_to_procval);
582vm_svar_valid_p(
VALUE svar)
585 switch (imemo_type(svar)) {
594 rb_bug(
"vm_svar_valid_p: unknown type: %s", rb_obj_info(svar));
605 if (!lep)
return false;
606 if (ec == NULL)
return true;
607 if (ec->root_lep == lep)
return false;
611 if (
FIXNUM_P(lep[VM_ENV_DATA_INDEX_FLAGS]) &&
612 VM_ENV_ESCAPED_P(lep) &&
624 if (lep_svar_in_env_p(ec, lep)) {
625 svar = lep[VM_ENV_DATA_INDEX_ME_CREF];
628 svar = ec->root_svar;
631 VM_ASSERT(svar ==
Qfalse || vm_svar_valid_p(svar));
639 VM_ASSERT(vm_svar_valid_p((
VALUE)svar));
641 if (lep_svar_in_env_p(ec, lep)) {
642 vm_env_write(lep, VM_ENV_DATA_INDEX_ME_CREF, (
VALUE)svar);
645 RB_OBJ_WRITE(rb_ec_thread_ptr(ec)->self, &ec->root_svar, svar);
652 const struct vm_svar *svar = lep_svar(ec, lep);
657 case VM_SVAR_LASTLINE:
658 return svar->lastline;
659 case VM_SVAR_BACKREF:
660 return svar->backref;
662 const VALUE ary = svar->others;
677 struct vm_svar *svar = IMEMO_NEW(
struct vm_svar, imemo_svar, obj);
688 struct vm_svar *svar = lep_svar(ec, lep);
691 lep_svar_write(ec, lep, svar = svar_new((
VALUE)svar));
695 case VM_SVAR_LASTLINE:
698 case VM_SVAR_BACKREF:
702 VALUE ary = svar->others;
718 val = lep_svar_get(ec, lep, key);
721 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
738 rb_bug(
"unexpected back-ref");
751 VALUE backref = lep_svar_get(ec, lep, VM_SVAR_BACKREF);
761 return rb_reg_last_defined(backref);
763 rb_bug(
"unexpected back-ref");
767 nth = (int)(
type >> 1);
774check_method_entry(
VALUE obj,
int can_be_svar)
776 if (obj ==
Qfalse)
return NULL;
779 if (!
RB_TYPE_P(obj,
T_IMEMO)) rb_bug(
"check_method_entry: unknown type: %s", rb_obj_info(obj));
782 switch (imemo_type(obj)) {
793 rb_bug(
"check_method_entry: svar should not be there:");
800env_method_entry_unchecked(
VALUE obj,
int can_be_svar)
802 if (obj ==
Qfalse)
return NULL;
804 switch (imemo_type(obj)) {
821 const VALUE *ep = cfp->ep;
824 while (!VM_ENV_LOCAL_P(ep)) {
825 if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return me;
826 ep = VM_ENV_PREV_EP(ep);
829 return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
835 const VALUE *ep = cfp->ep;
838 while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) {
839 if ((me = env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return me;
840 ep = VM_ENV_PREV_EP_UNCHECKED(ep);
843 return env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
849 switch (me->def->type) {
850 case VM_METHOD_TYPE_ISEQ:
851 return me->def->body.iseq.
iseqptr;
860 switch (me->def->type) {
861 case VM_METHOD_TYPE_ISEQ:
862 return me->def->body.iseq.
cref;
868#if VM_CHECK_MODE == 0
872check_cref(
VALUE obj,
int can_be_svar)
874 if (obj ==
Qfalse)
return NULL;
877 if (!
RB_TYPE_P(obj,
T_IMEMO)) rb_bug(
"check_cref: unknown type: %s", rb_obj_info(obj));
880 switch (imemo_type(obj)) {
891 rb_bug(
"check_method_entry: svar should not be there:");
898vm_env_cref(
const VALUE *ep)
902 while (!VM_ENV_LOCAL_P(ep)) {
903 if ((cref = check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL)
return cref;
904 ep = VM_ENV_PREV_EP(ep);
907 return check_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
911is_cref(
const VALUE v,
int can_be_svar)
914 switch (imemo_type(v)) {
927vm_env_cref_by_cref(
const VALUE *ep)
929 while (!VM_ENV_LOCAL_P(ep)) {
930 if (is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE))
return TRUE;
931 ep = VM_ENV_PREV_EP(ep);
933 return is_cref(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
937cref_replace_with_duplicated_cref_each_frame(
const VALUE *vptr,
int can_be_svar,
VALUE parent)
939 const VALUE v = *vptr;
943 switch (imemo_type(v)) {
946 new_cref = rb_vm_cref_dup(cref);
951 VM_FORCE_WRITE(vptr, (
VALUE)new_cref);
956 return cref_replace_with_duplicated_cref_each_frame(&((
struct vm_svar *)v)->
cref_or_me, FALSE, v);
960 rb_bug(
"cref_replace_with_duplicated_cref_each_frame: unreachable");
969vm_cref_replace_with_duplicated_cref(
const VALUE *ep)
971 if (vm_env_cref_by_cref(ep)) {
975 while (!VM_ENV_LOCAL_P(ep)) {
976 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) :
Qfalse;
977 if ((cref = cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE, envval)) != NULL) {
980 ep = VM_ENV_PREV_EP(ep);
982 envval = VM_ENV_ESCAPED_P(ep) ? VM_ENV_ENVVAL(ep) :
Qfalse;
983 return cref_replace_with_duplicated_cref_each_frame(&ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE, envval);
986 rb_bug(
"vm_cref_dup: unreachable");
991vm_get_cref(
const VALUE *ep)
999 rb_bug(
"vm_get_cref: unreachable");
1004rb_vm_get_cref(
const VALUE *ep)
1006 return vm_get_cref(ep);
1017 return vm_get_cref(cfp->ep);
1021vm_get_const_key_cref(
const VALUE *ep)
1023 const rb_cref_t *cref = vm_get_cref(ep);
1027 if (CREF_DYNAMIC(cref)) {
1030 cref = CREF_NEXT(cref);
1043 prev_cref = vm_env_cref(ep);
1049 prev_cref = vm_env_cref(cfp->ep);
1053 return vm_cref_new(klass, METHOD_VISI_PUBLIC, FALSE, prev_cref, pushed_by_eval, singleton);
1057vm_get_cbase(
const VALUE *ep)
1059 const rb_cref_t *cref = vm_get_cref(ep);
1061 return CREF_CLASS_FOR_DEFINITION(cref);
1065vm_get_const_base(
const VALUE *ep)
1067 const rb_cref_t *cref = vm_get_cref(ep);
1070 if (!CREF_PUSHED_BY_EVAL(cref)) {
1071 return CREF_CLASS_FOR_DEFINITION(cref);
1073 cref = CREF_NEXT(cref);
1080vm_check_if_namespace(
VALUE klass)
1083 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a class/module", klass);
1088vm_ensure_not_refinement_module(
VALUE self)
1091 rb_warn(
"not defined at the refinement, but at the outer class/module");
1107 if (
NIL_P(orig_klass) && allow_nil) {
1109 const rb_cref_t *root_cref = vm_get_cref(ec->cfp->ep);
1113 while (root_cref && CREF_PUSHED_BY_EVAL(root_cref)) {
1114 root_cref = CREF_NEXT(root_cref);
1117 while (cref && CREF_NEXT(cref)) {
1118 if (CREF_PUSHED_BY_EVAL(cref)) {
1122 klass = CREF_CLASS(cref);
1124 cref = CREF_NEXT(cref);
1126 if (!
NIL_P(klass)) {
1130 if ((ce = rb_const_lookup(klass,
id))) {
1131 rb_const_warn_if_deprecated(ce, klass,
id);
1134 if (am == klass)
break;
1136 if (is_defined)
return 1;
1137 if (rb_autoloading_value(klass,
id, &av, NULL))
return av;
1139 goto search_continue;
1146 if (UNLIKELY(!rb_class_owned_p(klass))) {
1148 rb_raise(rb_eRactorIsolationError,
1149 "can not access non-shareable objects in constant %"PRIsVALUE
"::%"PRIsVALUE
" of a class/module created by another Ractor.",
rb_class_path(klass), rb_id2str(
id));
1160 if (root_cref && !
NIL_P(CREF_CLASS(root_cref))) {
1161 klass = vm_get_iclass(ec->cfp, CREF_CLASS(root_cref));
1175 vm_check_if_namespace(orig_klass);
1177 return rb_public_const_defined_from(orig_klass,
id);
1180 return rb_public_const_get_from(orig_klass,
id);
1188 return vm_get_ev_const(ec, orig_klass,
id, allow_nil ==
Qtrue, 0);
1196 int allow_nil = TRUE;
1197 if (segments[0] == idNULL) {
1202 while (segments[idx]) {
1203 ID id = segments[idx++];
1204 val = vm_get_ev_const(ec, val,
id, allow_nil, 0);
1217 rb_bug(
"vm_get_cvar_base: no cref");
1220 while (CREF_NEXT(cref) &&
1221 (
NIL_P(CREF_CLASS(cref)) || RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
1222 CREF_PUSHED_BY_EVAL(cref) || CREF_SINGLETON(cref))) {
1223 cref = CREF_NEXT(cref);
1225 if (top_level_raise && !CREF_NEXT(cref)) {
1229 klass = vm_get_iclass(cfp, CREF_CLASS(cref));
1237#define ractor_incidental_shareable_p(cond, val) \
1238 (!(cond) || rb_ractor_shareable_p(val))
1239#define ractor_object_incidental_shareable_p(obj, val) \
1240 ractor_incidental_shareable_p(rb_ractor_shareable_p(obj), val)
1249 return default_value;
1254 fields_obj = ROBJECT_FIELDS_OBJ(obj);
1259 if (UNLIKELY(!rb_class_owned_p(obj))) {
1267 if (default_value ==
Qundef) {
1275 fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1279 fields_obj = rb_obj_fields(obj,
id);
1283 return default_value;
1288 shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj);
1289 VALUE *ivar_list = rb_imemo_fields_ptr(fields_obj);
1291 rb_getivar_cache cache = rb_getivar_cache_unpack(vm_cache_attr_index_atomic_read(is_attr, ic, cc));
1293 if (LIKELY(cache.shape_offset == shape_id)) {
1294 if (cache.index == ATTR_INDEX_NOT_SET) {
1295 return default_value;
1298 val = ivar_list[cache.index];
1299#if USE_DEBUG_COUNTER
1300 RB_DEBUG_COUNTER_INC(ivar_get_ic_hit);
1303 RB_DEBUG_COUNTER_INC(ivar_get_obj_hit);
1309#if USE_DEBUG_COUNTER
1311 if (cache.shape_offset != INVALID_SHAPE_ID) {
1312 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set);
1315 RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_unset);
1319 if (cache.shape_offset != INVALID_SHAPE_ID) {
1320 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set);
1323 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_unset);
1326 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1329 RB_DEBUG_COUNTER_INC(ivar_get_obj_miss);
1333 if (UNLIKELY(rb_shape_complex_p(shape_id))) {
1337 RUBY_ASSERT(table == rb_imemo_fields_complex_tbl(fields_obj));
1339 if (!st_lookup(table,
id, &val)) {
1340 val = default_value;
1344 shape_id_t previous_cached_offset = cache.shape_offset;
1345 if (rb_shape_get_iv_index_with_hint(shape_id,
id, &cache.index, &cache.shape_offset)) {
1346 if (cache.shape_offset != previous_cached_offset) {
1347 RUBY_ASSERT(!rb_shape_complex_p(cache.shape_offset));
1348 RUBY_ASSERT(cache.shape_offset != INVALID_SHAPE_ID);
1350 uint64_t packed_cache = rb_getivar_cache_pack(cache.shape_offset, cache.index);
1351 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1354 if (cache.index == ATTR_INDEX_NOT_SET) {
1355 val = default_value;
1359 val = ivar_list[cache.index];
1364 vm_cache_attr_index_set(is_attr, ic, cc, rb_getivar_cache_pack(shape_id, ATTR_INDEX_NOT_SET));
1365 val = default_value;
1370 if (!UNDEF_P(default_value)) {
1378 RB_DEBUG_COUNTER_INC(ivar_get_ic_miss);
1381 return rb_attr_get(obj,
id);
1396 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
1398 rb_check_ivar_modifiable(obj);
1400 shape_id_t previous_shape_id = RBASIC_SHAPE_ID(obj);
1401 attr_index_t index = rb_ivar_set_index(obj,
id, val);
1402 shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj);
1404 if (!rb_shape_complex_p(next_shape_id)) {
1405 uint64_t packed_cache = rb_setivar_cache_pack(RSHAPE_OFFSET(previous_shape_id), RSHAPE_OFFSET(next_shape_id), index);
1406 vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
1409 RB_DEBUG_COUNTER_INC(ivar_set_obj_miss);
1419 return vm_setivar_slowpath(obj,
id, val, iseq, ic, NULL,
false);
1425 return vm_setivar_slowpath(obj,
id, val, NULL, NULL, cc,
true);
1432 if (UNLIKELY(!rb_class_owned_p(obj))) {
1436 VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
1437 if (UNLIKELY(!fields_obj)) {
1441 shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
1442 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1443 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1447 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1449 if (shape_id != dest_shape_id) {
1450 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1451 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1454 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1463 VALUE fields_obj = rb_obj_fields(obj,
id);
1464 if (UNLIKELY(!fields_obj)) {
1468 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1469 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, RBASIC_SHAPE_ID(fields_obj), cache);
1470 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1474 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1476 if (shape_id != dest_shape_id) {
1477 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1478 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1481 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1495 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1496 shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, shape_id, cache);
1497 if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
1501 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
1502 RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
1503 if (shape_id != dest_shape_id) {
1504 RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
1505 if (fields_obj != obj) {
1506 RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
1510 RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
1511 RB_DEBUG_COUNTER_INC(ivar_set_obj_hit);
1517 RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject);
1529 VALUE defined_class = 0;
1533 defined_class =
RBASIC(defined_class)->klass;
1536 VALUE rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
1538 rb_bug(
"the cvc table should be set");
1542 if (!rb_marked_id_table_lookup(rb_cvc_tbl,
id, &ent_data)) {
1543 rb_bug(
"should have cvar cache entry");
1548 ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
1561 cref = vm_get_cref(GET_EP());
1565 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1566 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1567 RB_DEBUG_COUNTER_INC(cvar_read_inline_hit);
1569 VALUE v = rb_ivar_lookup(ic->entry->class_value,
id,
Qundef);
1575 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1577 return update_classvariable_cache(iseq, klass,
id, cref, ic);
1583 return vm_getclassvariable(iseq, cfp,
id, ic);
1590 cref = vm_get_cref(GET_EP());
1593 if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE() && ic->entry->cref == cref &&
1594 LIKELY(rb_class_owned_p(ic->entry->class_value))) {
1595 RB_DEBUG_COUNTER_INC(cvar_write_inline_hit);
1597 rb_class_ivar_set(ic->entry->class_value,
id, val);
1601 VALUE klass = vm_get_cvar_base(cref, reg_cfp, 1);
1605 update_classvariable_cache(iseq, klass,
id, cref, ic);
1611 vm_setclassvariable(iseq, cfp,
id, val, ic);
1618 return vm_getivar(obj,
id, iseq, ic, NULL, FALSE,
Qnil);
1629 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_ic_atomic_cache_read(ic));
1630 if (UNLIKELY(UNDEF_P(vm_setivar(obj, val, cache)))) {
1636 if (!UNDEF_P(vm_setivar_class(obj, val, cache))) {
1641 if (!UNDEF_P(vm_setivar_default(obj,
id, val, cache))) {
1645 vm_setivar_slowpath_ivar(obj,
id, val, iseq, ic);
1652 vm_setinstancevariable(iseq, obj,
id, val, ic);
1658 return vm_getinstancevariable(iseq, obj,
id, ic);
1667 ec->tag->state = RUBY_TAG_FATAL;
1670 ec->tag->state = TAG_THROW;
1672 else if (THROW_DATA_P(err)) {
1673 ec->tag->state = THROW_DATA_STATE((
struct vm_throw_data *)err);
1676 ec->tag->state = TAG_RAISE;
1683 const int flag,
const VALUE throwobj)
1691 else if (state == TAG_BREAK) {
1693 const VALUE *ep = GET_EP();
1694 const rb_iseq_t *base_iseq = GET_ISEQ();
1695 escape_cfp = reg_cfp;
1697 while (ISEQ_BODY(base_iseq)->
type != ISEQ_TYPE_BLOCK) {
1698 if (ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_CLASS) {
1699 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1700 ep = escape_cfp->ep;
1701 base_iseq = CFP_ISEQ(escape_cfp);
1704 ep = VM_ENV_PREV_EP(ep);
1705 base_iseq = ISEQ_BODY(base_iseq)->parent_iseq;
1706 escape_cfp = rb_vm_search_cf_from_ep(ec, escape_cfp, ep);
1707 VM_ASSERT(CFP_ISEQ(escape_cfp) == base_iseq);
1711 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1717 ep = VM_ENV_PREV_EP(ep);
1719 while (escape_cfp < eocfp) {
1720 if (escape_cfp->ep == ep) {
1721 const rb_iseq_t *
const iseq = CFP_ISEQ(escape_cfp);
1722 const VALUE epc = CFP_PC(escape_cfp) - ISEQ_BODY(iseq)->iseq_encoded;
1727 for (i=0; i < ct->size; i++) {
1729 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1731 if (entry->type == CATCH_TYPE_BREAK &&
1732 entry->iseq == base_iseq &&
1733 entry->start < epc && entry->end >= epc) {
1734 if (entry->cont == epc) {
1743 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1748 rb_vm_localjump_error(
"break from proc-closure", throwobj, TAG_BREAK);
1751 else if (state == TAG_RETRY) {
1752 const VALUE *ep = VM_ENV_PREV_EP(GET_EP());
1754 escape_cfp = rb_vm_search_cf_from_ep(ec, reg_cfp, ep);
1756 else if (state == TAG_RETURN) {
1757 const VALUE *current_ep = GET_EP();
1758 const VALUE *target_ep = NULL, *target_lep, *ep = current_ep;
1759 int in_class_frame = 0;
1761 escape_cfp = reg_cfp;
1764 while (!VM_ENV_LOCAL_P(ep)) {
1765 if (VM_ENV_FLAGS(ep, VM_FRAME_FLAG_LAMBDA) && target_ep == NULL) {
1768 ep = VM_ENV_PREV_EP(ep);
1772 while (escape_cfp < eocfp) {
1773 const VALUE *lep = VM_CF_LEP(escape_cfp);
1779 if (lep == target_lep &&
1780 VM_FRAME_RUBYFRAME_P(escape_cfp) &&
1781 ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_CLASS) {
1786 if (lep == target_lep) {
1787 if (VM_FRAME_LAMBDA_P(escape_cfp)) {
1789 if (in_class_frame) {
1794 const VALUE *tep = current_ep;
1796 while (target_lep != tep) {
1797 if (escape_cfp->ep == tep) {
1799 if (tep == target_ep) {
1803 goto unexpected_return;
1806 tep = VM_ENV_PREV_EP(tep);
1810 else if (VM_FRAME_RUBYFRAME_P(escape_cfp)) {
1811 switch (ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type) {
1813 case ISEQ_TYPE_MAIN:
1815 if (in_class_frame)
goto unexpected_return;
1816 if (target_ep == NULL) {
1820 goto unexpected_return;
1824 case ISEQ_TYPE_EVAL: {
1825 const rb_iseq_t *is = CFP_ISEQ(escape_cfp);
1826 enum rb_iseq_type t = ISEQ_BODY(is)->type;
1827 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE || t == ISEQ_TYPE_EVAL) {
1828 if (!(is = ISEQ_BODY(is)->parent_iseq))
break;
1829 t = ISEQ_BODY(is)->type;
1831 toplevel = t == ISEQ_TYPE_TOP || t == ISEQ_TYPE_MAIN;
1834 case ISEQ_TYPE_CLASS:
1843 if (escape_cfp->ep == target_lep && ISEQ_BODY(CFP_ISEQ(escape_cfp))->
type == ISEQ_TYPE_METHOD) {
1844 if (target_ep == NULL) {
1848 goto unexpected_return;
1852 escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
1855 rb_vm_localjump_error(
"unexpected return", throwobj, TAG_RETURN);
1861 rb_bug(
"isns(throw): unsupported throw type");
1864 ec->tag->state = state;
1865 return (
VALUE)THROW_DATA_NEW(throwobj, escape_cfp, state);
1870 rb_num_t throw_state,
VALUE throwobj)
1872 const int state = (int)(throw_state & VM_THROW_STATE_MASK);
1873 const int flag = (int)(throw_state & VM_THROW_NO_ESCAPE_FLAG);
1876 return vm_throw_start(ec, reg_cfp, state, flag, throwobj);
1879 return vm_throw_continue(ec, throwobj);
1887 return vm_throw(ec, reg_cfp, throw_state, throwobj);
1896 VALUE val = vm_throw(ec, reg_cfp, throw_state, throwobj);
1901 enum ruby_tag_type state = ec->tag->state;
1903 EC_JUMP_TAG(ec, state);
1911 int is_splat = flag & 0x01;
1914 const VALUE obj = ary;
1926 if (num + is_splat == 0) {
1929 else if (flag & 0x02) {
1934 for (i = 0; i < num -
len; i++) {
1939 for (j = 0; i < num; i++, j++) {
1961 for (; i < num -
len; i++) {
1965 for (rb_num_t j = 0; i < num; i++, j++) {
1966 *cfp->sp++ = ptr[
len - j - 1];
1970 for (rb_num_t j = 0; j < num; j++) {
1971 *cfp->sp++ = ptr[num - j - 1];
1986 int initial_capa = 2;
1988#if VM_CHECK_MODE > 0
1989 ccs->debug_sig = ~(
VALUE)ccs;
1991 ccs->capa = initial_capa;
1996 rb_managed_id_table_insert(cc_tbl, mid, (
VALUE)ccs);
2004 if (! vm_cc_markable(cc)) {
2008 if (UNLIKELY(ccs->len == ccs->capa)) {
2011 ccs = ruby_xrealloc(ccs, vm_ccs_alloc_size(ccs->capa));
2012#if VM_CHECK_MODE > 0
2013 ccs->debug_sig = ~(
VALUE)ccs;
2016 rb_managed_id_table_insert(cc_tbl, mid, (
VALUE)ccs);
2018 VM_ASSERT(ccs->len < ccs->capa);
2021 const int pos = ccs->len++;
2022 ccs->entries[pos].argc = vm_ci_argc(ci);
2023 ccs->entries[pos].flag = (
unsigned short)vm_ci_flag(ci);
2024 ccs->entries[pos].kw_len = (
unsigned short)(kwarg ? kwarg->keyword_len : 0);
2027 if (RB_DEBUG_COUNTER_SETMAX(ccs_maxlen, ccs->len)) {
2033#if VM_CHECK_MODE > 0
2037 ruby_debug_printf(
"ccs:%p (%d,%d)\n", (
void *)ccs, ccs->len, ccs->capa);
2038 for (
int i=0; i<ccs->len; i++) {
2039 ruby_debug_printf(
"CCS CI ID:flag:%x argc:%u kw_len:%u\n",
2040 ccs->entries[i].flag,
2041 ccs->entries[i].argc,
2042 ccs->entries[i].kw_len);
2043 rp(ccs->entries[i].cc);
2050 VM_ASSERT(vm_ccs_p(ccs));
2051 VM_ASSERT(ccs->len <= ccs->capa);
2053 for (
int i=0; i<ccs->len; i++) {
2056 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2057 VM_ASSERT(vm_cc_class_check(cc, klass));
2058 VM_ASSERT(vm_cc_check_cme(cc, ccs->cme));
2059 VM_ASSERT(!vm_cc_super_p(cc));
2060 VM_ASSERT(!vm_cc_refinement_p(cc));
2071 ASSERT_vm_locking();
2073 if (rb_multi_ractor_p()) {
2074 if (RCLASS_WRITABLE_CC_TBL(klass) != cc_tbl) {
2081 rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj);
2084 if (!ccs || !METHOD_ENTRY_INVALIDATED(ccs->cme)) {
2089 VALUE new_table = rb_vm_cc_table_dup(cc_tbl);
2090 rb_vm_cc_table_delete(new_table, mid);
2091 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), new_table);
2094 rb_vm_cc_table_delete(cc_tbl, mid);
2101 ASSERT_vm_locking();
2103 RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
2107 VM_ASSERT(cme == NULL || IMEMO_TYPE_P(cme, imemo_ment));
2111 VM_ASSERT(vm_cc_cme(&vm_empty_cc) == NULL);
2112 return &vm_empty_cc;
2115 VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
2116 const VALUE original_cc_table = cc_tbl;
2119 cc_tbl = rb_vm_cc_table_create(1);
2121 else if (rb_multi_ractor_p()) {
2122 cc_tbl = rb_vm_cc_table_dup(cc_tbl);
2125 VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
2134 if (UNLIKELY(rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj))) {
2139 ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
2143 cme = rb_check_overloaded_cme(cme, ci);
2145 const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
2146 vm_ccs_push(cc_tbl, mid, ccs, ci, cc);
2148 VM_ASSERT(vm_cc_cme(cc) != NULL);
2149 VM_ASSERT(cme->called_id == mid);
2150 VM_ASSERT(vm_cc_cme(cc)->called_id == mid);
2152 if (original_cc_table != cc_tbl) {
2153 RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), cc_tbl);
2165 cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
2173 if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj)) {
2175 const int ccs_len = ccs->len;
2177 if (UNLIKELY(METHOD_ENTRY_INVALIDATED(ccs->cme))) {
2179 vm_evict_cc(klass, cc_tbl, mid);
2184 VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
2193 unsigned int argc = vm_ci_argc(ci);
2194 unsigned int flag = vm_ci_flag(ci);
2195 unsigned int kw_len = kwarg ? kwarg->keyword_len : 0;
2197 for (
int i=0; i<ccs_len; i++) {
2198 unsigned int ccs_ci_argc = ccs->entries[i].argc;
2199 unsigned int ccs_ci_flag = ccs->entries[i].flag;
2200 unsigned int ccs_ci_kw_len = ccs->entries[i].kw_len;
2201 const struct rb_callcache *ccs_cc = ccs->entries[i].cc;
2203 VM_ASSERT(IMEMO_TYPE_P(ccs_cc, imemo_callcache));
2205 if (ccs_ci_argc == argc && ccs_ci_flag == flag && ccs_ci_kw_len == kw_len) {
2206 RB_DEBUG_COUNTER_INC(cc_found_in_ccs);
2208 VM_ASSERT(vm_cc_cme(ccs_cc)->called_id == mid);
2209 VM_ASSERT(ccs_cc->klass == klass);
2210 VM_ASSERT(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(ccs_cc)));
2226 const ID mid = vm_ci_mid(ci);
2228 const struct rb_callcache *cc = vm_lookup_cc(klass, ci, mid);
2234 if (rb_multi_ractor_p()) {
2237 cc = vm_lookup_cc(klass, ci, mid);
2241 cc = vm_populate_cc(klass, ci, mid);
2261 rb_bug(
"attempted to search method '%s' on a garbage collected object",
2262 rb_id2name(vm_ci_mid(ci)));
2267 cc = vm_search_cc(klass, ci);
2270 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
2271 VM_ASSERT(cc == vm_cc_empty() || cc->klass == klass);
2272 VM_ASSERT(cc == vm_cc_empty() || callable_method_entry_p(vm_cc_cme(cc)));
2273 VM_ASSERT(cc == vm_cc_empty() || !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)));
2274 VM_ASSERT(cc == vm_cc_empty() || vm_cc_cme(cc)->called_id == vm_ci_mid(ci));
2279#if VM_CHECK_MODE > 0
2284 return cd >= body->call_data && cd < body->call_data + body->ci_size;
2291#if USE_DEBUG_COUNTER
2296 const struct rb_callcache *cc = rb_vm_search_method_slowpath(cd->ci, klass);
2299#if OPT_INLINE_METHOD_CACHE
2303 if (cd_owner && cc != empty_cc) {
2306 VM_ASSERT(!vm_ci_markable(cd->ci) ||
2307 vm_cd_owned_by_iseq_p(cd, (
const rb_iseq_t *)cd_owner));
2311#if USE_DEBUG_COUNTER
2312 if (!old_cc || old_cc == empty_cc) {
2314 RB_DEBUG_COUNTER_INC(mc_inline_miss_empty);
2316 else if (old_cc == cc) {
2317 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cc);
2319 else if (old_cme == new_cme) {
2320 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_cme);
2322 else if (old_cme && new_cme && old_cme->def == new_cme->def) {
2323 RB_DEBUG_COUNTER_INC(mc_inline_miss_same_def);
2326 RB_DEBUG_COUNTER_INC(mc_inline_miss_diff);
2331 if (new_cme) VM_ASSERT(new_cme->called_id == vm_ci_mid(cd->ci));
2342#if OPT_INLINE_METHOD_CACHE
2343 if (LIKELY(vm_cc_class_check(cc, klass))) {
2344 if (LIKELY(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)))) {
2345 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
2346 RB_DEBUG_COUNTER_INC(mc_inline_hit);
2347 VM_ASSERT(vm_cc_cme(cc) == NULL ||
2348 (vm_ci_flag(cd->ci) & VM_CALL_SUPER) ||
2349 vm_cc_cme(cc)->called_id == vm_ci_mid(cd->ci));
2353 RB_DEBUG_COUNTER_INC(mc_inline_miss_invalidated);
2356 RB_DEBUG_COUNTER_INC(mc_inline_miss_klass);
2368 if (vm_cc_hit_p(cc, cd, klass)) {
2372 return vm_search_method_slowpath0((
VALUE)CFP_ISEQ(reg_cfp), cd, klass);
2379 VM_ASSERT(klass !=
Qfalse);
2382 const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
2383 return vm_cc_cme(cc);
2393 if (!vm_cc_hit_p(cc, cd, klass)) {
2394 cc = vm_search_method_slowpath0(cd_owner, cd, klass);
2396 return vm_cc_cme(cc);
2399#if __has_attribute(transparent_union)
2412 VALUE (*f10)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2413 VALUE (*f11)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2414 VALUE (*f12)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2415 VALUE (*f13)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2416 VALUE (*f14)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2417 VALUE (*f15)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE);
2420# define make_cfunc_type(f) (cfunc_type){.anyargs = (VALUE (*)(ANYARGS))(f)}
2423# define make_cfunc_type(f) (cfunc_type)(f)
2433 VM_ASSERT(IMEMO_TYPE_P(me, imemo_ment));
2434 VM_ASSERT(callable_method_entry_p(me));
2436 if (me->def->type != VM_METHOD_TYPE_CFUNC) {
2440#if __has_attribute(transparent_union)
2441 return me->def->body.cfunc.func == func.anyargs;
2443 return me->def->body.cfunc.func == func;
2452 return me && METHOD_ENTRY_BASIC(me);
2458 VM_ASSERT(reg_cfp != NULL);
2460 return check_cfunc(cme, func);
2466 return check_cfunc(me, func);
2473 return check_cfunc(cme, func);
2476#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
2477#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))
2479#define OP_UNREDEFINED_P(op, t) BASIC_OP_UNREDEFINED_P(BOP_##op, t##_REDEFINED_OP_FLAG)
2480#define EQ_UNREDEFINED_P(t) OP_UNREDEFINED_P(EQ, t)
2512opt_equality_specialized(
VALUE recv,
VALUE obj)
2514 if (FIXNUM_2_P(recv, obj) && EQ_UNREDEFINED_P(INTEGER)) {
2515 goto compare_by_identity;
2517 else if (FLONUM_2_P(recv, obj) && EQ_UNREDEFINED_P(FLOAT)) {
2518 goto compare_by_identity;
2521 goto compare_by_identity;
2530 return RBOOL(a == b);
2537 return rb_str_eql_internal(obj, recv);
2542 compare_by_identity:
2543 return RBOOL(recv == obj);
2549 VM_ASSERT(reg_cfp != NULL);
2551 VALUE val = opt_equality_specialized(recv, obj);
2552 if (!UNDEF_P(val))
return val;
2554 if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
2558 return RBOOL(recv == obj);
2563NOINLINE(
static VALUE opt_equality_by_mid_slowpath(
VALUE recv,
VALUE obj,
ID mid));
2566opt_equality_by_mid_slowpath(
VALUE recv,
VALUE obj,
ID mid)
2568 const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, &VM_CI_ON_STACK(mid, 0, 1, NULL));
2570 if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) {
2571 return RBOOL(recv == obj);
2581 VALUE val = opt_equality_specialized(recv, obj);
2582 if (!UNDEF_P(val)) {
2586 return opt_equality_by_mid_slowpath(recv, obj, mid);
2593 return opt_equality_by_mid(obj1, obj2, idEq);
2599 return opt_equality_by_mid(obj1, obj2, idEqlP);
2609 case VM_CHECKMATCH_TYPE_WHEN:
2611 case VM_CHECKMATCH_TYPE_RESCUE:
2613 rb_raise(
rb_eTypeError,
"class or module required for rescue clause");
2616 case VM_CHECKMATCH_TYPE_CASE: {
2617 return rb_vm_call_with_refinements(ec, pattern, idEqq, 1, &target,
RB_NO_KEYWORDS);
2620 rb_bug(
"check_match: unreachable");
2626double_cmp_lt(
double a,
double b)
2628 return RBOOL(a < b);
2632double_cmp_le(
double a,
double b)
2634 return RBOOL(a <= b);
2638double_cmp_gt(
double a,
double b)
2640 return RBOOL(a > b);
2644double_cmp_ge(
double a,
double b)
2646 return RBOOL(a >= b);
2650static inline VALUE *
2655 if (CFP_ISEQ(cfp) && VM_FRAME_RUBYFRAME_P(cfp)) {
2656 VALUE *bp = prev_cfp->sp + ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size + VM_ENV_DATA_SIZE;
2658 if (ISEQ_BODY(CFP_ISEQ(cfp))->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
2659 int lts = ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size;
2660 int params = ISEQ_BODY(CFP_ISEQ(cfp))->param.size;
2663 bp += vm_ci_argc(ci);
2666 if (ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
2670#if VM_DEBUG_BP_CHECK
2671 if (bp != cfp->bp_check) {
2672 ruby_debug_printf(
"bp_check: %ld, bp: %ld\n",
2673 (
long)(cfp->bp_check - GET_EC()->vm_stack),
2674 (
long)(bp - GET_EC()->vm_stack));
2675 rb_bug(
"vm_base_ptr: unreachable");
2688 return vm_base_ptr(cfp);
2703static vm_call_handler vm_call_iseq_setup_func(
const struct rb_callinfo *ci,
const int param_size,
const int local_size);
2708 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_tailcall_0start);
2710 return vm_call_iseq_setup_tailcall(ec, cfp, calling, 0);
2716 RB_DEBUG_COUNTER_INC(ccf_iseq_setup_0start);
2719 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
2720 int param = ISEQ_BODY(iseq)->param.size;
2721 int local = ISEQ_BODY(iseq)->local_table_size;
2722 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
2728 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2729 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2730 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2731 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2732 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2733 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2734 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2735 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2736 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2740rb_iseq_only_optparam_p(
const rb_iseq_t *iseq)
2742 return ISEQ_BODY(iseq)->param.flags.has_opt == TRUE &&
2743 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2744 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2745 ISEQ_BODY(iseq)->param.flags.has_kw == FALSE &&
2746 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2747 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
2748 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2749 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2750 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2754rb_iseq_only_kwparam_p(
const rb_iseq_t *iseq)
2756 return ISEQ_BODY(iseq)->param.flags.has_opt == FALSE &&
2757 ISEQ_BODY(iseq)->param.flags.has_rest == FALSE &&
2758 ISEQ_BODY(iseq)->param.flags.has_post == FALSE &&
2759 ISEQ_BODY(iseq)->param.flags.has_kw == TRUE &&
2760 ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
2761 ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
2762 ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
2763 ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
2766#define ALLOW_HEAP_ARGV (-2)
2767#define ALLOW_HEAP_ARGV_KEEP_KWSPLAT (-3)
2772 vm_check_canary(GET_EC(), cfp->sp);
2778 int argc = calling->argc;
2780 if (UNLIKELY(max_args <= ALLOW_HEAP_ARGV && len + argc > VM_ARGC_STACK_MAX)) {
2784 VALUE *argv = cfp->sp - argc;
2788 cfp->sp -= argc - 1;
2789 cfp->sp[-1] = argv_ary;
2791 calling->heap_argv = argv_ary;
2797 if (max_args >= 0 &&
len + argc > max_args) {
2805 calling->argc +=
len - (max_args - argc + 1);
2806 len = max_args - argc + 1;
2815 calling->heap_argv = 0;
2817 CHECK_VM_STACK_OVERFLOW(cfp,
len);
2819 for (i = 0; i <
len; i++) {
2820 *cfp->sp++ = ptr[i];
2832 const VALUE *
const passed_keywords = vm_ci_kwarg(ci)->keywords;
2833 const int kw_len = vm_ci_kwarg(ci)->keyword_len;
2834 const VALUE h = rb_hash_new_capa(kw_len);
2835 VALUE *sp = cfp->sp;
2838 for (i=0; i<kw_len; i++) {
2839 rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
2843 cfp->sp -= kw_len - 1;
2844 calling->argc -= kw_len - 1;
2845 calling->kw_splat = 1;
2849vm_caller_setup_keyword_hash(
const struct rb_callinfo *ci,
VALUE keyword_hash)
2852 if (keyword_hash !=
Qnil) {
2854 keyword_hash = rb_hash_dup(rb_to_hash_type(keyword_hash));
2857 else if (!IS_ARGS_KW_SPLAT_MUT(ci) && !
RHASH_EMPTY_P(keyword_hash)) {
2863 keyword_hash = rb_hash_dup(keyword_hash);
2865 return keyword_hash;
2871 const struct rb_callinfo *restrict ci,
int max_args)
2873 if (UNLIKELY(IS_ARGS_SPLAT(ci))) {
2874 if (IS_ARGS_KW_SPLAT(ci)) {
2876 VM_ASSERT(calling->kw_splat == 1);
2880 VALUE ary = cfp->sp[0];
2881 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[1]);
2884 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args))
return;
2888 if (UNLIKELY(calling->heap_argv)) {
2890 ((
struct RHash *)kwh)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
2891 if (max_args != ALLOW_HEAP_ARGV_KEEP_KWSPLAT) {
2892 calling->kw_splat = 0;
2900 VM_ASSERT(calling->kw_splat == 1);
2904 calling->kw_splat = 0;
2909 VM_ASSERT(calling->kw_splat == 0);
2913 VALUE ary = cfp->sp[0];
2915 if (vm_caller_setup_arg_splat(cfp, calling, ary, max_args)) {
2920 VALUE last_hash, argv_ary;
2921 if (UNLIKELY(argv_ary = calling->heap_argv)) {
2922 if (!IS_ARGS_KEYWORD(ci) &&
2925 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2930 calling->kw_splat = 1;
2936 if (!IS_ARGS_KEYWORD(ci) &&
2937 calling->argc > 0 &&
2939 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
2946 cfp->sp[-1] = rb_hash_dup(last_hash);
2947 calling->kw_splat = 1;
2953 else if (UNLIKELY(IS_ARGS_KW_SPLAT(ci))) {
2955 VM_ASSERT(calling->kw_splat == 1);
2956 VALUE kwh = vm_caller_setup_keyword_hash(ci, cfp->sp[-1]);
2961 calling->kw_splat = 0;
2967 else if (UNLIKELY(IS_ARGS_KEYWORD(ci))) {
2969 VM_ASSERT(calling->kw_splat == 0);
2975 vm_caller_setup_arg_kw(cfp, calling, ci);
2979#define USE_OPT_HIST 0
2982#define OPT_HIST_MAX 64
2983static int opt_hist[OPT_HIST_MAX+1];
2987opt_hist_show_results_at_exit(
void)
2989 for (
int i=0; i<OPT_HIST_MAX; i++) {
2990 ruby_debug_printf(
"opt_hist\t%d\t%d\n", i, opt_hist[i]);
3000 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3001 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3002 const int opt = calling->argc - lead_num;
3003 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3004 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3005 const int param = ISEQ_BODY(iseq)->param.size;
3006 const int local = ISEQ_BODY(iseq)->local_table_size;
3007 const int delta = opt_num - opt;
3009 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3012 if (opt_pc < OPT_HIST_MAX) {
3016 opt_hist[OPT_HIST_MAX]++;
3020 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param - delta, local);
3028 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3029 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3030 const int opt = calling->argc - lead_num;
3031 const int opt_pc = (int)ISEQ_BODY(iseq)->param.opt_table[opt];
3033 RB_DEBUG_COUNTER_INC(ccf_iseq_opt);
3036 if (opt_pc < OPT_HIST_MAX) {
3040 opt_hist[OPT_HIST_MAX]++;
3044 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3049 VALUE *
const passed_values,
const int passed_keyword_len,
const VALUE *
const passed_keywords,
3050 VALUE *
const locals);
3057 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3058 int param_size = ISEQ_BODY(iseq)->param.size;
3059 int local_size = ISEQ_BODY(iseq)->local_table_size;
3062 VM_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3064 local_size = local_size + vm_ci_argc(calling->cd->ci);
3065 param_size = param_size + vm_ci_argc(calling->cd->ci);
3067 cfp->sp[0] = (
VALUE)calling->cd->ci;
3069 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param_size, local_size);
3079 VM_ASSERT(vm_ci_flag(ci) & VM_CALL_KWARG);
3080 RB_DEBUG_COUNTER_INC(ccf_iseq_kw1);
3082 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3083 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3085 const int ci_kw_len = kw_arg->keyword_len;
3086 const VALUE *
const ci_keywords = kw_arg->keywords;
3087 VALUE *argv = cfp->sp - calling->argc;
3088 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3089 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3091 MEMCPY(ci_kws, argv + lead_num,
VALUE, ci_kw_len);
3092 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3094 int param = ISEQ_BODY(iseq)->param.size;
3095 int local = ISEQ_BODY(iseq)->local_table_size;
3096 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3103 const struct rb_callinfo *MAYBE_UNUSED(ci) = calling->cd->ci;
3106 VM_ASSERT((vm_ci_flag(ci) & VM_CALL_KWARG) == 0);
3107 RB_DEBUG_COUNTER_INC(ccf_iseq_kw2);
3109 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3110 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3111 VALUE *
const argv = cfp->sp - calling->argc;
3112 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3115 for (i=0; i<kw_param->num; i++) {
3116 klocals[i] = kw_param->default_values[i];
3123 int param = ISEQ_BODY(iseq)->param.size;
3124 int local = ISEQ_BODY(iseq)->local_table_size;
3125 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), 0, param, local);
3135 cfp->sp -= (calling->argc + 1);
3136 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
3137 return builtin_invoker0(ec, calling->recv, NULL, func_ptr);
3146 set_table *dup_check_table = &vm->unused_block_warning_table;
3156 .v = (
VALUE)cme->def,
3160 if (!strict_unused_block) {
3161 key = (st_data_t)cme->def->original_id;
3163 if (set_table_lookup(dup_check_table, key)) {
3173 key |= (st_data_t)(k1.b[i] ^ k2.b[
SIZEOF_VALUE-1-i]) << (8 * i);
3178 fprintf(stderr,
"pc:%p def:%p\n", pc, (
void *)cme->def);
3179 fprintf(stderr,
"key:%p\n", (
void *)key);
3183 if (set_insert(dup_check_table, key)) {
3188 VALUE name = rb_gen_method_name(cme->defined_class, rb_iseq_base_label(iseq));
3190 if (!
NIL_P(m_loc)) {
3191 rb_warn(
"the block passed to '%"PRIsVALUE
"' defined at %"PRIsVALUE
":%"PRIsVALUE
" may be ignored",
3195 rb_warn(
"the block may be ignored because '%"PRIsVALUE
"' does not use a block", name);
3202 const rb_iseq_t *iseq,
VALUE *argv,
int param_size,
int local_size)
3207 VM_ASSERT((vm_ci_argc(ci), 1));
3208 VM_ASSERT(vm_cc_cme(cc) != NULL);
3210 if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
3211 calling->block_handler != VM_BLOCK_HANDLER_NONE &&
3212 !(vm_ci_flag(calling->cd->ci) & (VM_CALL_OPT_SEND | VM_CALL_SUPER)))) {
3213 warn_unused_block(vm_cc_cme(cc), iseq, (
void *)CFP_PC(ec->cfp));
3216 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_KW_SPLAT))) {
3217 if (LIKELY(rb_simple_iseq_p(iseq))) {
3219 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3220 CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
3222 if (calling->argc != lead_num) {
3223 argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
3227 VM_ASSERT(cc == calling->cc);
3229 if (vm_call_iseq_optimizable_p(ci, cc)) {
3230 if ((ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) && ruby_vm_c_events_enabled == 0) {
3231 VM_ASSERT(ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF);
3232 vm_cc_bf_set(cc, (
void *)ISEQ_BODY(iseq)->iseq_encoded[1]);
3233 CC_SET_FASTPATH(cc, vm_call_single_noarg_leaf_builtin,
true);
3236 CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size),
true);
3241 else if (rb_iseq_only_optparam_p(iseq)) {
3244 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3245 const int opt_num = ISEQ_BODY(iseq)->param.opt_num;
3247 CALLER_SETUP_ARG(cfp, calling, ci, lead_num + opt_num);
3248 const int argc = calling->argc;
3249 const int opt = argc - lead_num;
3251 if (opt < 0 || opt > opt_num) {
3252 argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
3255 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3256 CC_SET_FASTPATH(cc, vm_call_iseq_setup_normal_opt_start,
3257 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3258 vm_call_cacheable(ci, cc));
3261 CC_SET_FASTPATH(cc, vm_call_iseq_setup_tailcall_opt_start,
3262 !IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
3263 vm_call_cacheable(ci, cc));
3267 VM_ASSERT((
int)ISEQ_BODY(iseq)->param.size == lead_num + opt_num);
3268 for (
int i=argc; i<lead_num + opt_num; i++) {
3271 return (
int)ISEQ_BODY(iseq)->param.opt_table[opt];
3273 else if (rb_iseq_only_kwparam_p(iseq) && !IS_ARGS_SPLAT(ci)) {
3274 const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
3275 const int argc = calling->argc;
3276 const struct rb_iseq_param_keyword *kw_param = ISEQ_BODY(iseq)->param.keyword;
3278 if (vm_ci_flag(ci) & VM_CALL_KWARG) {
3281 if (argc - kw_arg->keyword_len == lead_num) {
3282 const int ci_kw_len = kw_arg->keyword_len;
3283 const VALUE *
const ci_keywords = kw_arg->keywords;
3285 MEMCPY(ci_kws, argv + lead_num,
VALUE, ci_kw_len);
3287 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3288 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
3290 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
3291 vm_call_cacheable(ci, cc));
3296 else if (argc == lead_num) {
3298 VALUE *
const klocals = argv + kw_param->bits_start - kw_param->num;
3299 args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
3301 if (klocals[kw_param->num] ==
INT2FIX(0)) {
3303 CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_nokwarg,
3304 vm_call_cacheable(ci, cc));
3330 if (ISEQ_BODY(iseq)->param.flags.forwardable) {
3331 bool can_fastpath =
true;
3333 if ((vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
3335 if (vm_ci_argc(ci) != vm_ci_argc(forward_cd->caller_ci)) {
3336 ci = vm_ci_new_runtime(
3343 ci = forward_cd->caller_ci;
3345 can_fastpath =
false;
3349 if (!vm_ci_markable(ci)) {
3350 ci = vm_ci_new_runtime(
3355 can_fastpath =
false;
3357 argv[param_size - 1] = (
VALUE)ci;
3358 CC_SET_FASTPATH(cc, vm_call_iseq_forwardable, can_fastpath);
3362 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_method);
3389 const VALUE * lep = VM_CF_LEP(cfp);
3395 if (VM_ENV_FLAGS(lep, VM_ENV_FLAG_ESCAPED)) {
3400 iseq = CFP_ISEQ(rb_vm_search_cf_from_ep(ec, cfp, lep));
3404 int local_size = ISEQ_BODY(iseq)->local_table_size + argc;
3406 const VALUE * from = lep - (local_size + VM_ENV_DATA_SIZE - 1);
3407 VALUE * to = cfp->sp - 1;
3411 CHECK_VM_STACK_OVERFLOW0(cfp, to,
RARRAY_LEN(splat));
3416 CHECK_VM_STACK_OVERFLOW0(cfp, to, argc);
3418 cfp->sp = to + argc;
3437 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3440 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3441 int param_size = ISEQ_BODY(iseq)->param.size;
3442 int local_size = ISEQ_BODY(iseq)->local_table_size;
3444 RUBY_ASSERT(!ISEQ_BODY(iseq)->param.flags.forwardable);
3446 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3447 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3453 RB_DEBUG_COUNTER_INC(ccf_iseq_setup);
3456 const rb_iseq_t *iseq = def_iseq_ptr(vm_cc_cme(cc)->def);
3457 int param_size = ISEQ_BODY(iseq)->param.size;
3458 int local_size = ISEQ_BODY(iseq)->local_table_size;
3460 RUBY_ASSERT(ISEQ_BODY(iseq)->param.flags.forwardable);
3463 local_size = local_size + vm_ci_argc(calling->cd->ci);
3464 param_size = param_size + vm_ci_argc(calling->cd->ci);
3466 const int opt_pc = vm_callee_setup_arg(ec, calling, iseq, cfp->sp - calling->argc, param_size, local_size);
3467 return vm_call_iseq_setup_2(ec, cfp, calling, opt_pc, param_size, local_size);
3472 int opt_pc,
int param_size,
int local_size)
3477 if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
3478 return vm_call_iseq_setup_normal(ec, cfp, calling, vm_cc_cme(cc), opt_pc, param_size, local_size);
3481 return vm_call_iseq_setup_tailcall(ec, cfp, calling, opt_pc);
3487 int opt_pc,
int param_size,
int local_size)
3489 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3490 VALUE *argv = cfp->sp - calling->argc;
3491 VALUE *sp = argv + param_size;
3492 cfp->sp = argv - 1 ;
3494 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling->recv,
3495 calling->block_handler, (
VALUE)me,
3496 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3497 local_size - param_size,
3498 ISEQ_BODY(iseq)->stack_max);
3507 VALUE *argv = cfp->sp - calling->argc;
3509 const rb_iseq_t *iseq = def_iseq_ptr(me->def);
3510 VALUE *src_argv = argv;
3511 VALUE *sp_orig, *sp;
3512 VALUE finish_flag = VM_FRAME_FINISHED_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
3514 if (VM_BH_FROM_CFP_P(calling->block_handler, cfp)) {
3515 struct rb_captured_block *dst_captured = VM_CFP_TO_CAPTURED_BLOCK(RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
3516 const struct rb_captured_block *src_captured = VM_BH_TO_CAPT_BLOCK(calling->block_handler);
3517 dst_captured->code.val = src_captured->code.val;
3518 if (VM_BH_ISEQ_BLOCK_P(calling->block_handler)) {
3519 calling->block_handler = VM_BH_FROM_ISEQ_BLOCK(dst_captured);
3522 calling->block_handler = VM_BH_FROM_IFUNC_BLOCK(dst_captured);
3526 vm_pop_frame(ec, cfp, cfp->ep);
3529 sp_orig = sp = cfp->sp;
3532 sp[0] = calling->recv;
3536 for (i=0; i < ISEQ_BODY(iseq)->param.size; i++) {
3537 *sp++ = src_argv[i];
3540 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL | finish_flag,
3541 calling->recv, calling->block_handler, (
VALUE)me,
3542 ISEQ_BODY(iseq)->iseq_encoded + opt_pc, sp,
3543 ISEQ_BODY(iseq)->local_table_size - ISEQ_BODY(iseq)->param.size,
3544 ISEQ_BODY(iseq)->stack_max);
3552ractor_unsafe_check(
void)
3554 if (!rb_ractor_main_p()) {
3555 rb_raise(rb_eRactorUnsafeError,
"ractor unsafe method called from not main ractor");
3562 ractor_unsafe_check();
3570 ractor_unsafe_check();
3572 return (*f)(argc, argv, recv);
3578 ractor_unsafe_check();
3586 ractor_unsafe_check();
3588 return (*f)(recv, argv[0]);
3594 ractor_unsafe_check();
3596 return (*f)(recv, argv[0], argv[1]);
3602 ractor_unsafe_check();
3604 return (*f)(recv, argv[0], argv[1], argv[2]);
3610 ractor_unsafe_check();
3612 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3618 ractor_unsafe_check();
3619 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3620 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3626 ractor_unsafe_check();
3627 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3628 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3634 ractor_unsafe_check();
3635 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3636 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3642 ractor_unsafe_check();
3643 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3644 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3650 ractor_unsafe_check();
3651 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3652 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3658 ractor_unsafe_check();
3659 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;
3660 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3666 ractor_unsafe_check();
3667 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;
3668 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
3674 ractor_unsafe_check();
3675 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;
3676 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
3682 ractor_unsafe_check();
3683 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;
3684 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
3690 ractor_unsafe_check();
3691 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;
3692 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
3698 ractor_unsafe_check();
3699 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;
3700 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
3714 return (*f)(argc, argv, recv);
3728 return (*f)(recv, argv[0]);
3735 return (*f)(recv, argv[0], argv[1]);
3742 return (*f)(recv, argv[0], argv[1], argv[2]);
3749 return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
3755 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3756 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
3762 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3763 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
3769 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3770 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
3776 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3777 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
3783 VALUE(*f)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE) = (
VALUE(*)(
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE,
VALUE))func;
3784 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
3790 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;
3791 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
3797 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;
3798 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
3804 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;
3805 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
3811 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;
3812 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
3818 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;
3819 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
3825 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;
3826 return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
3832 const int ov_flags = RAISED_STACKOVERFLOW;
3833 if (LIKELY(reg_cfp == ec->cfp + 1))
return TRUE;
3834 if (rb_ec_raised_p(ec, ov_flags)) {
3835 rb_ec_raised_reset(ec, ov_flags);
3841#define CHECK_CFP_CONSISTENCY(func) \
3842 (LIKELY(vm_cfp_consistent_p(ec, reg_cfp)) ? (void)0 : \
3843 rb_bug(func ": cfp consistency error (%p, %p)", (void *)reg_cfp, (void *)(ec->cfp+1)))
3849#if VM_DEBUG_VERIFY_METHOD_CACHE
3850 switch (me->def->type) {
3851 case VM_METHOD_TYPE_CFUNC:
3852 case VM_METHOD_TYPE_NOTIMPLEMENTED:
3854# define METHOD_BUG(t) case VM_METHOD_TYPE_##t: rb_bug("wrong method type: " #t)
3856 METHOD_BUG(ATTRSET);
3858 METHOD_BUG(BMETHOD);
3861 METHOD_BUG(OPTIMIZED);
3862 METHOD_BUG(MISSING);
3863 METHOD_BUG(REFINED);
3867 rb_bug(
"wrong method type: %d", me->def->type);
3870 return UNALIGNED_MEMBER_PTR(me->def, body.cfunc);
3877 RB_DEBUG_COUNTER_INC(ccf_cfunc_with_frame);
3884 VALUE recv = calling->recv;
3885 VALUE block_handler = calling->block_handler;
3886 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3888 if (UNLIKELY(calling->kw_splat)) {
3889 frame_type |= VM_FRAME_FLAG_CFRAME_KW;
3892 VM_ASSERT(reg_cfp == ec->cfp);
3894 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id);
3897 vm_push_frame(ec, NULL, frame_type, recv,
3898 block_handler, (
VALUE)me,
3899 0, ec->cfp->sp, 0, 0);
3901 int len = cfunc->argc;
3904 reg_cfp->sp = stack_bottom;
3905 val = (*cfunc->invoker)(recv, argc, argv, cfunc->func);
3907 CHECK_CFP_CONSISTENCY(
"vm_call_cfunc");
3909 rb_vm_pop_frame(ec);
3911 VM_ASSERT(ec->cfp->sp == stack_bottom);
3913 EXEC_EVENT_HOOK(ec,
RUBY_EVENT_C_RETURN, recv, me->def->original_id, vm_ci_mid(ci), me->owner, val);
3914 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
3924 VM_ASSERT(cme->def->type == VM_METHOD_TYPE_CFUNC);
3926 VALUE *sp = ec->cfp->sp;
3927 VALUE recv = *(sp - recv_idx - 1);
3928 VALUE frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
3929 VALUE block_handler = VM_BLOCK_HANDLER_NONE;
3930#if VM_CHECK_MODE > 0
3932 *(GET_EC()->cfp->sp) =
Qfalse;
3934 vm_push_frame(ec, NULL, frame_type, recv, block_handler, (
VALUE)cme, 0, ec->cfp->sp, 0, 0);
3939rb_splat_or_kwargs_p(
const struct rb_callinfo *restrict ci)
3941 return IS_ARGS_SPLAT(ci) || IS_ARGS_KW_OR_KW_SPLAT(ci);
3947 int argc = calling->argc;
3948 VALUE *stack_bottom = reg_cfp->sp - argc - 1;
3949 VALUE *argv = &stack_bottom[1];
3951 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3958 RB_DEBUG_COUNTER_INC(ccf_cfunc_other);
3960 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
3962 if (UNLIKELY(argv_ary = calling->heap_argv)) {
3963 VM_ASSERT(!IS_ARGS_KEYWORD(ci));
3966 VALUE *stack_bottom = reg_cfp->sp - 2;
3968 VM_ASSERT(calling->argc == 1);
3972 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, argv, stack_bottom);
3975 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_with_frame, !rb_splat_or_kwargs_p(ci) && !calling->kw_splat && !(vm_ci_flag(ci) & VM_CALL_FORWARDING));
3977 return vm_call_cfunc_with_frame(ec, reg_cfp, calling);
3984 VALUE argv_ary = reg_cfp->sp[-1 - stack_offset];
3987 if (UNLIKELY(argc > VM_ARGC_STACK_MAX)) {
3988 return vm_call_cfunc_other(ec, reg_cfp, calling);
3992 calling->kw_splat = 0;
3994 VALUE *stack_bottom = reg_cfp->sp - 2 - stack_offset;
3995 VALUE *sp = stack_bottom;
3996 CHECK_VM_STACK_OVERFLOW(reg_cfp, argc);
3997 for(i = 0; i < argc; i++) {
4002 return vm_call_cfunc_with_frame_(ec, reg_cfp, calling, argc, stack_bottom+1, stack_bottom);
4008 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat);
4009 VALUE argv_ary = reg_cfp->sp[-1];
4013 int argc_offset = 0;
4015 if (UNLIKELY(argc > 0 &&
4017 (((
struct RHash *)last_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS))) {
4019 return vm_call_cfunc_other(ec, reg_cfp, calling);
4023 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 0, argc_offset);
4029 RB_DEBUG_COUNTER_INC(ccf_cfunc_only_splat_kw);
4030 VALUE keyword_hash = reg_cfp->sp[-1];
4033 return vm_call_cfunc_array_argv(ec, reg_cfp, calling, 1, 0);
4036 return vm_call_cfunc_other(ec, reg_cfp, calling);
4043 RB_DEBUG_COUNTER_INC(ccf_cfunc);
4045 if (IS_ARGS_SPLAT(ci) && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4046 if (!IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 1) {
4048 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat, TRUE);
4049 return vm_call_cfunc_only_splat(ec, reg_cfp, calling);
4051 if (IS_ARGS_KW_SPLAT(ci) && vm_ci_argc(ci) == 2) {
4053 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_only_splat_kw, TRUE);
4054 return vm_call_cfunc_only_splat_kw(ec, reg_cfp, calling);
4058 CC_SET_FASTPATH(calling->cc, vm_call_cfunc_other, TRUE);
4059 return vm_call_cfunc_other(ec, reg_cfp, calling);
4066 RB_DEBUG_COUNTER_INC(ccf_ivar);
4068 VALUE ivar = vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE,
Qnil);
4075 RB_DEBUG_COUNTER_INC(ccf_attrset);
4076 VALUE val = *(cfp->sp - 1);
4078 rb_setivar_cache cache = rb_setivar_cache_unpack(vm_cc_atomic_cache_read(cc));
4079 ID id = vm_cc_cme(cc)->def->body.attr.id;
4080 rb_check_frozen(obj);
4081 VALUE res = vm_setivar(obj, val, cache);
4089 res = vm_setivar_class(obj, val, cache);
4090 if (!UNDEF_P(res)) {
4097 res = vm_setivar_default(obj,
id, val, cache);
4098 if (!UNDEF_P(res)) {
4103 res = vm_setivar_slowpath_attr(obj,
id, val, cc);
4111 return vm_call_attrset_direct(ec, cfp, calling->cc, calling->recv);
4121 VALUE procv = cme->def->body.bmethod.proc;
4124 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4125 rb_raise(
rb_eRuntimeError,
"defined with an un-shareable Proc in a different Ractor");
4129 GetProcPtr(procv, proc);
4130 val = vm_invoke_bmethod(ec, proc, calling->recv, CALLING_ARGC(calling), argv, calling->kw_splat, calling->block_handler, vm_cc_cme(cc));
4140 RB_DEBUG_COUNTER_INC(ccf_iseq_bmethod);
4144 VALUE procv = cme->def->body.bmethod.proc;
4147 cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
4148 rb_raise(
rb_eRuntimeError,
"defined with an un-shareable Proc in a different Ractor");
4152 GetProcPtr(procv, proc);
4153 const struct rb_block *block = &proc->block;
4155 while (vm_block_type(block) == block_type_proc) {
4156 block = vm_proc_block(block->as.proc);
4158 VM_ASSERT(vm_block_type(block) == block_type_iseq);
4161 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
4162 VALUE *
const argv = cfp->sp - calling->argc;
4163 const int arg_size = ISEQ_BODY(iseq)->param.size;
4166 if (vm_ci_flag(calling->cd->ci) & VM_CALL_ARGS_SIMPLE) {
4167 opt_pc = vm_callee_setup_block_arg(ec, calling, calling->cd->ci, iseq, argv, arg_setup_method);
4170 opt_pc = setup_parameters_complex(ec, iseq, calling, calling->cd->ci, argv, arg_setup_method);
4175 vm_push_frame(ec, iseq,
4176 VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_BMETHOD | VM_FRAME_FLAG_LAMBDA,
4178 VM_GUARDED_PREV_EP(captured->ep),
4180 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
4182 ISEQ_BODY(iseq)->local_table_size - arg_size,
4183 ISEQ_BODY(iseq)->stack_max);
4191 RB_DEBUG_COUNTER_INC(ccf_noniseq_bmethod);
4195 CALLER_SETUP_ARG(cfp, calling, calling->cd->ci, ALLOW_HEAP_ARGV);
4196 if (UNLIKELY(calling->heap_argv)) {
4201 argc = calling->argc;
4204 cfp->sp += - argc - 1;
4207 return vm_call_bmethod_body(ec, calling, argv);
4213 RB_DEBUG_COUNTER_INC(ccf_bmethod);
4217 VALUE procv = cme->def->body.bmethod.proc;
4219 GetProcPtr(procv, proc);
4220 const struct rb_block *block = &proc->block;
4222 while (vm_block_type(block) == block_type_proc) {
4223 block = vm_proc_block(block->as.proc);
4225 if (vm_block_type(block) == block_type_iseq) {
4226 CC_SET_FASTPATH(cc, vm_call_iseq_bmethod, TRUE);
4227 return vm_call_iseq_bmethod(ec, cfp, calling);
4230 CC_SET_FASTPATH(cc, vm_call_noniseq_bmethod, TRUE);
4231 return vm_call_noniseq_bmethod(ec, cfp, calling);
4235rb_find_defined_class_by_owner(
VALUE current_class,
VALUE target_owner)
4237 VALUE klass = current_class;
4245 while (
RTEST(klass)) {
4247 if (owner == target_owner) {
4253 return current_class;
4262 if (orig_me->defined_class == 0) {
4263 VALUE defined_class = rb_find_defined_class_by_owner(me->defined_class, orig_me->owner);
4264 VM_ASSERT_TYPE(orig_me->owner,
T_MODULE);
4265 cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class);
4267 if (me->def->reference_count == 1) {
4268 RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme);
4272 rb_method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id);
4280 VM_ASSERT(callable_method_entry_p(cme));
4287 return aliased_callable_method_entry(me);
4293 calling->cc = &VM_CC_ON_STACK(
Qundef,
4296 aliased_callable_method_entry(vm_cc_cme(calling->cc)));
4298 return vm_call_method_each_type(ec, cfp, calling);
4301static enum method_missing_reason
4304 enum method_missing_reason stat = MISSING_NOENTRY;
4305 if (vm_ci_flag(ci) & VM_CALL_VCALL && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) stat |= MISSING_VCALL;
4306 if (vm_ci_flag(ci) & VM_CALL_FCALL) stat |= MISSING_FCALL;
4307 if (vm_ci_flag(ci) & VM_CALL_SUPER) stat |= MISSING_SUPER;
4317 ASSUME(calling->argc >= 0);
4319 enum method_missing_reason missing_reason = MISSING_NOENTRY;
4320 int argc = calling->argc;
4321 VALUE recv = calling->recv;
4324 flags |= VM_CALL_OPT_SEND;
4326 if (UNLIKELY(! mid)) {
4327 mid = idMethodMissing;
4328 missing_reason = ci_missing_reason(ci);
4329 ec->method_missing_reason = missing_reason;
4332 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4334 rb_ary_unshift(argv_ary, symbol);
4337 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4338 VALUE exc = rb_make_no_method_exception(
4360 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4363 argc = ++calling->argc;
4368 int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL);
4369 const VALUE *argv = STACK_ADDR_FROM_TOP(argc);
4370 VALUE exc = rb_make_no_method_exception(
4383 .ci = &VM_CI_ON_STACK(mid, flags, argc, vm_ci_kwarg(ci)),
4389 if (!(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
4390 calling->cd = &new_fcd.cd;
4394 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4395 new_fcd.caller_ci = caller_ci;
4398 calling->cc = &VM_CC_ON_STACK(klass,
4400 { .method_missing_reason = missing_reason },
4401 rb_callable_method_entry_with_refinements(klass, mid, NULL));
4403 if (flags & VM_CALL_FCALL) {
4404 return vm_call_method(ec, reg_cfp, calling);
4408 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
4410 if (vm_cc_cme(cc) != NULL) {
4411 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
4412 case METHOD_VISI_PUBLIC:
4413 return vm_call_method_each_type(ec, reg_cfp, calling);
4414 case METHOD_VISI_PRIVATE:
4415 vm_cc_method_missing_reason_set(cc, MISSING_PRIVATE);
4417 case METHOD_VISI_PROTECTED:
4418 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
4421 VM_UNREACHABLE(vm_call_method);
4423 return vm_call_method_missing(ec, reg_cfp, calling);
4426 return vm_call_method_nome(ec, reg_cfp, calling);
4436 i = calling->argc - 1;
4438 if (calling->argc == 0) {
4439 rb_raise(rb_eArgError,
"no method name given");
4463 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4469 RB_DEBUG_COUNTER_INC(ccf_opt_send_complex);
4471 int flags = VM_CALL_FCALL;
4475 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
4476 if (UNLIKELY(argv_ary = calling->heap_argv)) {
4478 flags |= VM_CALL_ARGS_SPLAT;
4479 if (calling->kw_splat) {
4480 VALUE last_hash = rb_ary_last(0, NULL, argv_ary);
4481 ((
struct RHash *)last_hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
4482 calling->kw_splat = 0;
4484 return vm_call_symbol(ec, reg_cfp, calling, ci, sym, flags);
4487 if (calling->kw_splat) flags |= VM_CALL_KW_SPLAT;
4488 return vm_call_opt_send0(ec, reg_cfp, calling, flags);
4494 RB_DEBUG_COUNTER_INC(ccf_opt_send_simple);
4495 return vm_call_opt_send0(ec, reg_cfp, calling, vm_ci_flag(calling->cd->ci) | VM_CALL_FCALL);
4501 RB_DEBUG_COUNTER_INC(ccf_opt_send);
4504 int flags = vm_ci_flag(ci);
4506 if (UNLIKELY((flags & VM_CALL_FORWARDING) || (!(flags & VM_CALL_ARGS_SIMPLE) &&
4507 ((calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
4508 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
4509 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc)))))) {
4510 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_complex, TRUE);
4511 return vm_call_opt_send_complex(ec, reg_cfp, calling);
4514 CC_SET_FASTPATH(calling->cc, vm_call_opt_send_simple, TRUE);
4515 return vm_call_opt_send_simple(ec, reg_cfp, calling);
4520 const struct rb_callinfo *orig_ci,
enum method_missing_reason reason)
4522 RB_DEBUG_COUNTER_INC(ccf_method_missing);
4524 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
4525 unsigned int argc, flag;
4527 flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | vm_ci_flag(orig_ci);
4528 argc = ++calling->argc;
4531 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
4532 vm_check_canary(ec, reg_cfp->sp);
4536 argv[0] =
ID2SYM(vm_ci_mid(orig_ci));
4539 ec->method_missing_reason = reason;
4543 .ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)),
4549 if (!(flag & VM_CALL_FORWARDING)) {
4550 calling->cd = &new_fcd.cd;
4554 VM_ASSERT((vm_ci_argc(caller_ci), 1));
4555 new_fcd.caller_ci = caller_ci;
4559 calling->cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }},
4560 rb_callable_method_entry_without_refinements(
CLASS_OF(calling->recv), idMethodMissing, NULL));
4561 return vm_call_method(ec, reg_cfp, calling);
4567 return vm_call_method_missing_body(ec, reg_cfp, calling, calling->cd->ci, vm_cc_cmethod_missing_reason(calling->cc));
4578 return vm_call_method_nome(ec, cfp, calling);
4580 if (cme->def->type == VM_METHOD_TYPE_REFINED &&
4581 cme->def->body.refined.orig_me) {
4582 cme = refined_method_callable_without_refinement(cme);
4585 calling->cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }}, cme);
4587 return vm_call_method_each_type(ec, cfp, calling);
4591find_refinement(
VALUE refinements,
VALUE klass)
4593 if (
NIL_P(refinements)) {
4596 return rb_hash_lookup(refinements, klass);
4605 if (CFP_ISEQ(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_BLOCK) {
4606 const rb_iseq_t *local_iseq = ISEQ_BODY(CFP_ISEQ(cfp))->local_iseq;
4609 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
4610 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
4614 }
while (CFP_ISEQ(cfp) != local_iseq);
4625 if (orig_me->defined_class == 0) {
4633 VM_ASSERT(callable_method_entry_p(cme));
4635 if (UNDEFINED_METHOD_ENTRY_P(cme)) {
4645 ID mid = vm_ci_mid(calling->cd->ci);
4646 const rb_cref_t *cref = vm_get_cref(cfp->ep);
4650 for (; cref; cref = CREF_NEXT(cref)) {
4651 const VALUE refinement = find_refinement(CREF_REFINEMENTS(cref), vm_cc_cme(cc)->owner);
4652 if (
NIL_P(refinement))
continue;
4655 rb_callable_method_entry(refinement, mid);
4658 if (vm_cc_call(cc) == vm_call_super_method) {
4661 if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) {
4666 if (cme->def->type != VM_METHOD_TYPE_REFINED ||
4667 cme->def != ref_me->def) {
4670 if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
4679 if (vm_cc_cme(cc)->def->body.refined.orig_me) {
4680 return refined_method_callable_without_refinement(vm_cc_cme(cc));
4695 if (calling->cd->cc) {
4696 const struct rb_callcache *cc = calling->cc = vm_cc_new(vm_cc_cme(calling->cc)->defined_class, ref_cme, vm_call_general, cc_type_refinement);
4698 return vm_call_method(ec, cfp, calling);
4701 struct rb_callcache *ref_cc = &VM_CC_ON_STACK(
Qundef, vm_call_general, {{ 0 }}, ref_cme);
4702 calling->cc= ref_cc;
4703 return vm_call_method(ec, cfp, calling);
4707 return vm_call_method_nome(ec, cfp, calling);
4713NOINLINE(
static VALUE
4721 int argc = calling->argc;
4724 if (argc > 0)
MEMMOVE(&TOPN(argc), &TOPN(argc-1),
VALUE, argc);
4727 return vm_invoke_block(ec, reg_cfp, calling, ci,
false, block_handler);
4733 RB_DEBUG_COUNTER_INC(ccf_opt_call);
4736 VALUE procval = calling->recv;
4737 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, VM_BH_FROM_PROC(procval));
4743 RB_DEBUG_COUNTER_INC(ccf_opt_block_call);
4745 VALUE block_handler = VM_ENV_BLOCK_HANDLER(VM_CF_LEP(reg_cfp));
4748 enum ruby_basic_operators bop;
4749 switch (vm_ci_mid(ci)) {
4750 case idAREF: bop = BOP_AREF;
break;
4751 case idYield: bop = BOP_YIELD;
break;
4752 case idEqq: bop = BOP_EQQ;
break;
4753 default: bop = BOP_CALL;
break;
4756 if (BASIC_OP_UNREDEFINED_P(bop, PROC_REDEFINED_OP_FLAG)) {
4757 return vm_invoke_block_opt_call(ec, reg_cfp, calling, ci, block_handler);
4760 calling->recv = rb_vm_bh_to_procval(ec, block_handler);
4761 calling->cc = rb_vm_search_method_slowpath(ci,
CLASS_OF(calling->recv));
4762 return vm_call_general(ec, reg_cfp, calling);
4769 VALUE recv = calling->recv;
4772 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4773 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_AREF);
4775 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4776 return RSTRUCT_GET_RAW(recv,
off);
4782 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aref);
4784 VALUE ret = vm_call_opt_struct_aref0(ec, calling);
4792 VALUE recv = calling->recv;
4795 VM_ASSERT(vm_cc_cme(calling->cc)->def->type == VM_METHOD_TYPE_OPTIMIZED);
4796 VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_ASET);
4798 rb_check_frozen(recv);
4800 const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
4801 RSTRUCT_SET_RAW(recv,
off, val);
4809 RB_DEBUG_COUNTER_INC(ccf_opt_struct_aset);
4811 VALUE ret = vm_call_opt_struct_aset0(ec, calling, *(reg_cfp->sp - 1));
4819#define VM_CALL_METHOD_ATTR(var, func, nohook) \
4820 if (UNLIKELY(ruby_vm_c_events_enabled > 0)) { \
4821 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, calling->recv, vm_cc_cme(cc)->def->original_id, \
4822 vm_ci_mid(ci), vm_cc_cme(cc)->owner, Qundef); \
4824 EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, calling->recv, vm_cc_cme(cc)->def->original_id, \
4825 vm_ci_mid(ci), vm_cc_cme(cc)->owner, (var)); \
4836 switch (vm_cc_cme(cc)->def->body.optimized.type) {
4837 case OPTIMIZED_METHOD_TYPE_SEND:
4838 CC_SET_FASTPATH(cc, vm_call_opt_send, TRUE);
4839 return vm_call_opt_send(ec, cfp, calling);
4840 case OPTIMIZED_METHOD_TYPE_CALL:
4841 CC_SET_FASTPATH(cc, vm_call_opt_call, TRUE);
4842 return vm_call_opt_call(ec, cfp, calling);
4843 case OPTIMIZED_METHOD_TYPE_BLOCK_CALL:
4844 CC_SET_FASTPATH(cc, vm_call_opt_block_call, TRUE);
4845 return vm_call_opt_block_call(ec, cfp, calling);
4846 case OPTIMIZED_METHOD_TYPE_STRUCT_AREF: {
4847 CALLER_SETUP_ARG(cfp, calling, ci, 0);
4851 VM_CALL_METHOD_ATTR(v,
4852 vm_call_opt_struct_aref(ec, cfp, calling),
4853 set_vm_cc_ivar(cc); \
4854 CC_SET_FASTPATH(cc, vm_call_opt_struct_aref, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4857 case OPTIMIZED_METHOD_TYPE_STRUCT_ASET: {
4858 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4862 VM_CALL_METHOD_ATTR(v,
4863 vm_call_opt_struct_aset(ec, cfp, calling),
4864 set_vm_cc_ivar(cc); \
4865 CC_SET_FASTPATH(cc, vm_call_opt_struct_aset, (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)))
4869 rb_bug(
"vm_call_method: unsupported optimized method type (%d)", vm_cc_cme(cc)->def->body.optimized.type);
4881 VM_ASSERT(! METHOD_ENTRY_INVALIDATED(cme));
4883 switch (cme->def->type) {
4884 case VM_METHOD_TYPE_ISEQ:
4885 if (ISEQ_BODY(def_iseq_ptr(cme->def))->param.flags.forwardable) {
4886 CC_SET_FASTPATH(cc, vm_call_iseq_fwd_setup, TRUE);
4887 return vm_call_iseq_fwd_setup(ec, cfp, calling);
4890 CC_SET_FASTPATH(cc, vm_call_iseq_setup, TRUE);
4891 return vm_call_iseq_setup(ec, cfp, calling);
4894 case VM_METHOD_TYPE_NOTIMPLEMENTED:
4895 case VM_METHOD_TYPE_CFUNC:
4896 CC_SET_FASTPATH(cc, vm_call_cfunc, TRUE);
4897 return vm_call_cfunc(ec, cfp, calling);
4899 case VM_METHOD_TYPE_ATTRSET:
4900 CALLER_SETUP_ARG(cfp, calling, ci, 1);
4904 const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG | VM_CALL_FORWARDING);
4906 if (vm_cc_markable(cc)) {
4907 vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
4908 VM_CALL_METHOD_ATTR(v,
4909 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4910 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
4916 VM_CALLCACHE_UNMARKABLE |
4917 VM_CALLCACHE_ON_STACK,
4923 .value = IVAR_CACHE_INIT,
4928 VM_CALL_METHOD_ATTR(v,
4929 vm_call_attrset_direct(ec, cfp, cc, calling->recv),
4930 CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
4934 case VM_METHOD_TYPE_IVAR:
4935 CALLER_SETUP_ARG(cfp, calling, ci, 0);
4937 vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
4938 const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING);
4939 VM_CALL_METHOD_ATTR(v,
4940 vm_call_ivar(ec, cfp, calling),
4941 CC_SET_FASTPATH(cc, vm_call_ivar, !(vm_ci_flag(ci) & ivar_mask)));
4944 case VM_METHOD_TYPE_MISSING:
4945 vm_cc_method_missing_reason_set(cc, 0);
4946 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
4947 return vm_call_method_missing(ec, cfp, calling);
4949 case VM_METHOD_TYPE_BMETHOD:
4950 CC_SET_FASTPATH(cc, vm_call_bmethod, TRUE);
4951 return vm_call_bmethod(ec, cfp, calling);
4953 case VM_METHOD_TYPE_ALIAS:
4954 CC_SET_FASTPATH(cc, vm_call_alias, TRUE);
4955 return vm_call_alias(ec, cfp, calling);
4957 case VM_METHOD_TYPE_OPTIMIZED:
4958 return vm_call_optimized(ec, cfp, calling, ci, cc);
4960 case VM_METHOD_TYPE_UNDEF:
4963 case VM_METHOD_TYPE_ZSUPER:
4964 return vm_call_zsuper(ec, cfp, calling, RCLASS_ORIGIN(vm_cc_cme(cc)->defined_class));
4966 case VM_METHOD_TYPE_REFINED:
4969 return vm_call_refined(ec, cfp, calling);
4972 rb_bug(
"vm_call_method: unsupported method type (%d)", vm_cc_cme(cc)->def->type);
4982 const int stat = ci_missing_reason(ci);
4984 if (vm_ci_mid(ci) == idMethodMissing) {
4985 if (UNLIKELY(calling->heap_argv)) {
4990 VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
4991 vm_raise_method_missing(ec, calling->argc, argv, calling->recv, stat);
4995 return vm_call_method_missing_body(ec, cfp, calling, ci, stat);
5007 VALUE defined_class = me->defined_class;
5008 VALUE refined_class = RCLASS_REFINED_CLASS(defined_class);
5009 return NIL_P(refined_class) ? defined_class : refined_class;
5018 VM_ASSERT(callable_method_entry_p(vm_cc_cme(cc)));
5020 if (vm_cc_cme(cc) != NULL) {
5021 switch (METHOD_ENTRY_VISI(vm_cc_cme(cc))) {
5022 case METHOD_VISI_PUBLIC:
5023 return vm_call_method_each_type(ec, cfp, calling);
5025 case METHOD_VISI_PRIVATE:
5026 if (!(vm_ci_flag(ci) & VM_CALL_FCALL)) {
5027 enum method_missing_reason stat = MISSING_PRIVATE;
5028 if (vm_ci_flag(ci) & VM_CALL_VCALL) stat |= MISSING_VCALL;
5030 vm_cc_method_missing_reason_set(cc, stat);
5031 CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE);
5032 return vm_call_method_missing(ec, cfp, calling);
5034 return vm_call_method_each_type(ec, cfp, calling);
5036 case METHOD_VISI_PROTECTED:
5037 if (!(vm_ci_flag(ci) & (VM_CALL_OPT_SEND | VM_CALL_FCALL))) {
5038 VALUE defined_class = vm_defined_class_for_protected_call(vm_cc_cme(cc));
5040 vm_cc_method_missing_reason_set(cc, MISSING_PROTECTED);
5041 return vm_call_method_missing(ec, cfp, calling);
5045 VM_ASSERT(vm_cc_cme(cc) != NULL);
5048 calling->cc = &cc_on_stack;
5049 return vm_call_method_each_type(ec, cfp, calling);
5052 return vm_call_method_each_type(ec, cfp, calling);
5055 rb_bug(
"unreachable");
5059 return vm_call_method_nome(ec, cfp, calling);
5066 RB_DEBUG_COUNTER_INC(ccf_general);
5067 return vm_call_method(ec, reg_cfp, calling);
5073 VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
5074 VM_ASSERT(cc != vm_cc_empty());
5076 *(vm_call_handler *)&cc->call_ = vm_call_general;
5082 RB_DEBUG_COUNTER_INC(ccf_super_method);
5087 if (ec == NULL) rb_bug(
"unreachable");
5090 VM_ASSERT(vm_cc_call(calling->cc) == vm_call_super_method);
5091 return vm_call_method(ec, reg_cfp, calling);
5097vm_search_normal_superclass(
VALUE klass)
5099 if (RICLASS_FOR_REFINEMENT_P(klass)) {
5100 klass =
RBASIC(klass)->klass;
5102 klass = RCLASS_ORIGIN(klass);
5106NORETURN(
static void vm_super_outside(
void));
5109vm_super_outside(
void)
5115empty_cc_for_super(
void)
5117 return &vm_empty_cc_for_super;
5123 VALUE current_defined_class;
5124 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
5131 current_defined_class = vm_defined_class_for_protected_call(me);
5134 iseq != method_entry_iseqptr(me) &&
5137 RCLASS_INCLUDER(current_defined_class) : current_defined_class;
5141 "self has wrong type to call super in this context: "
5142 "%"PRIsVALUE
" (expected %"PRIsVALUE
")",
5147 if (me->def->type == VM_METHOD_TYPE_BMETHOD && (vm_ci_flag(cd->ci) & VM_CALL_ZSUPER)) {
5149 "implicit argument passing of super from method defined"
5150 " by define_method() is not supported."
5151 " Specify all arguments explicitly.");
5154 ID mid = me->def->original_id;
5156 if (!vm_ci_markable(cd->ci)) {
5157 VM_FORCE_WRITE((
const VALUE *)&cd->ci->mid, (
VALUE)mid);
5161 cd->ci = vm_ci_new_runtime(mid,
5164 vm_ci_kwarg(cd->ci));
5171 VALUE klass = vm_search_normal_superclass(me->defined_class);
5175 cc = vm_cc_new(
Qundef, NULL, vm_call_method_missing, cc_type_super);
5180 RCLASS_INCLUDER(me->defined_class) == 0) {
5182 "super in a method in a module that has been refined and that is called via super"
5183 " from a refinement method is not supported.");
5186 cc = vm_search_method_fastpath(reg_cfp, cd, klass);
5190 if (cached_cme == NULL) {
5192 cd->cc = empty_cc_for_super();
5194 else if (cached_cme->called_id != mid) {
5197 cc = vm_cc_new(klass, cme, vm_call_super_method, cc_type_super);
5201 cd->cc = cc = empty_cc_for_super();
5205 switch (cached_cme->def->type) {
5207 case VM_METHOD_TYPE_REFINED:
5209 case VM_METHOD_TYPE_ATTRSET:
5210 case VM_METHOD_TYPE_IVAR:
5211 vm_cc_call_set(cc, vm_call_super_method);
5219 VM_ASSERT((vm_cc_cme(cc),
true));
5227block_proc_is_lambda(
const VALUE procval)
5232 GetProcPtr(procval, proc);
5233 return proc->header.is_lambda;
5243 VALUE self,
int argc,
const VALUE *argv,
int kw_splat,
VALUE block_handler,
5246 int is_lambda = FALSE;
5247 VALUE val, arg, blockarg;
5249 const struct vm_ifunc *ifunc = captured->code.ifunc;
5254 else if (argc == 0) {
5261 blockarg = rb_vm_bh_to_procval(ec, block_handler);
5263 frame_flag = VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME | (me ? VM_FRAME_FLAG_BMETHOD : 0);
5265 frame_flag |= VM_FRAME_FLAG_CFRAME_KW;
5268 vm_push_frame(ec, (
const rb_iseq_t *)captured->code.ifunc,
5271 VM_GUARDED_PREV_EP(captured->ep),
5273 0, ec->cfp->sp, 0, 0);
5274 val = (*ifunc->func)(arg, (
VALUE)ifunc->data, argc, argv, blockarg);
5275 rb_vm_pop_frame(ec);
5283 return vm_yield_with_cfunc(ec, captured, captured->self, argc, argv, 0, VM_BLOCK_HANDLER_NONE, NULL);
5289 VALUE passed_proc = rb_vm_bh_to_procval(ec, block_handler);
5291 if (!rb_box_available()) {
5292 return rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5304 box = current_box_on_cfp(ec, ruby_cfp);
5305 if (BOX_USER_P(box)) {
5308 ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ruby_cfp));
5312 if (!ruby_cfp || !box) {
5313 return rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5321 const rb_iseq_t *caller_iseq = CFP_ISEQ(ruby_cfp);
5322 VALUE name = rb_sprintf(
"block in %"PRIsVALUE, rb_iseq_label(caller_iseq));
5324 rb_iseq_path(caller_iseq), rb_iseq_realpath(caller_iseq),
5325 rb_vm_get_sourceline(ruby_cfp), caller_iseq, 0,
5326 ISEQ_TYPE_BLOCK, NULL,
Qnil);
5328 enum ruby_tag_type state;
5330 vm_push_frame(ec, iseq, VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_FINISH,
5331 ruby_cfp->self, VM_GUARDED_PREV_EP(ruby_cfp->ep),
5333 ISEQ_BODY(iseq)->iseq_encoded, reg_cfp->sp,
5334 ISEQ_BODY(iseq)->local_table_size, ISEQ_BODY(iseq)->stack_max);
5342 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
5343 val = rb_sym_proc_call(
SYM2ID(symbol), argc, argv, kw_splat, passed_proc);
5347 if (state != TAG_NONE) {
5349 EC_JUMP_TAG(ec, state);
5352 rb_vm_pop_frame(ec);
5363 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5365 for (i=0; i<
len && i<ISEQ_BODY(iseq)->param.lead_num; i++) {
5373vm_callee_setup_block_arg_arg0_check(
VALUE *argv)
5375 VALUE ary, arg0 = argv[0];
5380 VM_ASSERT(argv[0] == arg0);
5388 if (rb_simple_iseq_p(iseq)) {
5392 CALLER_SETUP_ARG(cfp, calling, ci, ISEQ_BODY(iseq)->param.lead_num);
5394 if (arg_setup_type == arg_setup_block &&
5395 calling->argc == 1 &&
5396 ISEQ_BODY(iseq)->param.flags.has_lead &&
5397 !ISEQ_BODY(iseq)->param.flags.ambiguous_param0 &&
5398 !
NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv))) {
5399 calling->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0);
5402 if (calling->argc != ISEQ_BODY(iseq)->param.lead_num) {
5403 if (arg_setup_type == arg_setup_block) {
5404 if (calling->argc < ISEQ_BODY(iseq)->param.lead_num) {
5406 CHECK_VM_STACK_OVERFLOW(cfp, ISEQ_BODY(iseq)->param.lead_num);
5407 for (i=calling->argc; i<ISEQ_BODY(iseq)->param.lead_num; i++) argv[i] =
Qnil;
5408 calling->argc = ISEQ_BODY(iseq)->param.lead_num;
5410 else if (calling->argc > ISEQ_BODY(iseq)->param.lead_num) {
5411 calling->argc = ISEQ_BODY(iseq)->param.lead_num;
5415 argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
5422 return setup_parameters_complex(ec, iseq, calling, ci, argv, arg_setup_type);
5431 calling = &calling_entry;
5432 calling->argc = argc;
5433 calling->block_handler = block_handler;
5434 calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
5436 calling->heap_argv = 0;
5438 struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
5440 return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);
5451 const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
5452 const int arg_size = ISEQ_BODY(iseq)->param.size;
5453 VALUE *
const rsp = GET_SP() - calling->argc;
5454 VALUE *
const argv = rsp;
5455 int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block);
5456 int frame_flag = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
5461 vm_push_frame(ec, iseq,
5464 VM_GUARDED_PREV_EP(captured->ep), (
VALUE)cref,
5465 ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
5467 ISEQ_BODY(iseq)->local_table_size - arg_size, ISEQ_BODY(iseq)->stack_max);
5475 bool is_lambda,
VALUE block_handler)
5477 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, NULL);
5483 MAYBE_UNUSED(
bool is_lambda),
VALUE block_handler)
5485 VALUE symbol = VM_BH_TO_SYMBOL(block_handler);
5486 int flags = vm_ci_flag(ci);
5488 if (UNLIKELY(!(flags & VM_CALL_ARGS_SIMPLE) &&
5489 ((calling->argc == 0) ||
5490 (calling->argc == 1 && (flags & (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT))) ||
5491 (calling->argc == 2 && (flags & VM_CALL_ARGS_SPLAT) && (flags & VM_CALL_KW_SPLAT)) ||
5492 ((flags & VM_CALL_KWARG) && (vm_ci_kwarg(ci)->keyword_len == calling->argc))))) {
5493 CALLER_SETUP_ARG(reg_cfp, calling, ci, ALLOW_HEAP_ARGV);
5495 if (UNLIKELY(calling->heap_argv)) {
5496#if VM_ARGC_STACK_MAX < 0
5498 rb_raise(rb_eArgError,
"no receiver given");
5504 reg_cfp->sp[-1] = reg_cfp->sp[-2];
5505 reg_cfp->sp[-2] = calling->recv;
5506 flags |= VM_CALL_ARGS_SPLAT;
5509 if (calling->argc < 1) {
5510 rb_raise(rb_eArgError,
"no receiver given");
5512 calling->recv = TOPN(--calling->argc);
5514 if (calling->kw_splat) {
5515 flags |= VM_CALL_KW_SPLAT;
5519 if (calling->argc < 1) {
5520 rb_raise(rb_eArgError,
"no receiver given");
5522 calling->recv = TOPN(--calling->argc);
5525 return vm_call_symbol(ec, reg_cfp, calling, ci, symbol, flags);
5531 MAYBE_UNUSED(
bool is_lambda),
VALUE block_handler)
5536 CALLER_SETUP_ARG(ec->cfp, calling, ci, ALLOW_HEAP_ARGV_KEEP_KWSPLAT);
5537 argc = calling->argc;
5538 val = vm_yield_with_cfunc(ec, captured, captured->self, CALLING_ARGC(calling), calling->heap_argv ?
RARRAY_CONST_PTR(calling->heap_argv) : STACK_ADDR_FROM_TOP(argc), calling->kw_splat, calling->block_handler, NULL);
5544vm_block_to_block_handler(
const struct rb_block *block)
5546 switch (vm_block_type(block)) {
5547 case block_type_iseq:
5548 return VM_BH_FROM_ISEQ_BLOCK(&block->as.captured);
5549 case block_type_ifunc:
5550 return VM_BH_FROM_IFUNC_BLOCK(&block->as.captured);
5551 case block_type_symbol:
5552 return VM_BH_FROM_SYMBOL(block->as.symbol);
5553 case block_type_proc:
5554 return VM_BH_FROM_PROC(block->as.proc);
5556 VM_UNREACHABLE(vm_yield_with_proc);
5561vm_proc_to_block_handler(
VALUE procval)
5563 return vm_block_to_block_handler(vm_proc_block(procval));
5566NOINLINE(
static VALUE
5569 bool is_lambda,
VALUE block_handler,
VALUE refined_procval));
5573 bool is_lambda,
VALUE block_handler,
VALUE refined_procval)
5575 const rb_cref_t *cref = rb_proc_refinements_cref_for_call(refined_procval);
5576 return vm_invoke_iseq_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler, cref);
5582 bool is_lambda,
VALUE block_handler)
5584 VALUE refined_procval = 0;
5586 while (vm_block_handler_type(block_handler) == block_handler_type_proc) {
5587 VALUE procval = VM_BH_TO_PROC(block_handler);
5589 GetProcPtr(procval, po);
5590 if (po->header.is_refined) refined_procval = procval;
5591 is_lambda = po->header.is_lambda;
5592 block_handler = vm_block_to_block_handler(&po->block);
5595 if (UNLIKELY(refined_procval) && vm_block_handler_type(block_handler) == block_handler_type_iseq) {
5597 return vm_invoke_proc_block_with_cref(ec, reg_cfp, calling, ci, is_lambda, block_handler,
5601 return vm_invoke_block(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5607 bool is_lambda,
VALUE block_handler)
5611 bool is_lambda,
VALUE block_handler);
5613 switch (vm_block_handler_type(block_handler)) {
5614 case block_handler_type_iseq: func = vm_invoke_iseq_block;
break;
5615 case block_handler_type_ifunc: func = vm_invoke_ifunc_block;
break;
5616 case block_handler_type_proc: func = vm_invoke_proc_block;
break;
5617 case block_handler_type_symbol: func = vm_invoke_symbol_block;
break;
5618 default: rb_bug(
"vm_invoke_block: unreachable");
5621 return func(ec, reg_cfp, calling, ci, is_lambda, block_handler);
5625vm_make_proc_with_iseq(
const rb_iseq_t *blockiseq)
5632 rb_bug(
"vm_make_proc_with_iseq: unreachable");
5635 captured = VM_CFP_TO_CAPTURED_BLOCK(cfp);
5636 captured->code.iseq = blockiseq;
5638 return rb_vm_make_proc(ec, captured,
rb_cProc);
5642vm_once_exec(
VALUE iseq)
5648#define RUNNING_THREAD_ONCE_DONE ((rb_thread_t *)0x1)
5664vm_once_wait_no_gvl(
void *ptr)
5671 running_th = rbimpl_atomic_ptr_load((
void **)&arg->is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
5672 if (running_th != NULL && running_th != RUNNING_THREAD_ONCE_DONE) {
5680vm_once_wait_ubf(
void *ptr)
5682 vm_once_broadcast((
rb_vm_t *)ptr);
5686vm_once_clear(
VALUE data)
5689 rbimpl_atomic_ptr_store((
volatile void **)&is->once.running_thread, NULL, RBIMPL_ATOMIC_RELEASE);
5690 vm_once_broadcast(GET_VM());
5702 args[0] = obj; args[1] =
Qfalse;
5704 if (!UNDEF_P(r) &&
RTEST(r)) {
5716 enum defined_type
type = (
enum defined_type)op_type;
5723 return rb_gvar_defined(
SYM2ID(obj));
5725 case DEFINED_CVAR: {
5726 const rb_cref_t *cref = vm_get_cref(GET_EP());
5727 klass = vm_get_cvar_base(cref, GET_CFP(), 0);
5732 case DEFINED_CONST_FROM: {
5733 bool allow_nil =
type == DEFINED_CONST;
5735 return vm_get_ev_const(ec, klass,
SYM2ID(obj), allow_nil,
true);
5740 return rb_ec_obj_respond_to(ec, v,
SYM2ID(obj), TRUE);
5742 case DEFINED_METHOD:{
5747 switch (METHOD_ENTRY_VISI(cme)) {
5748 case METHOD_VISI_PRIVATE:
5750 case METHOD_VISI_PROTECTED:
5754 case METHOD_VISI_PUBLIC:
5758 rb_bug(
"vm_defined: unreachable: %u", (
unsigned int)METHOD_ENTRY_VISI(cme));
5762 return check_respond_to_missing(obj, v);
5767 if (GET_BLOCK_HANDLER() != VM_BLOCK_HANDLER_NONE) {
5771 case DEFINED_ZSUPER:
5776 VALUE klass = vm_search_normal_superclass(me->defined_class);
5777 if (!klass)
return false;
5779 ID id = me->def->original_id;
5786 return RTEST(vm_backref_defined(ec, GET_LEP(),
FIX2INT(obj)));
5788 rb_bug(
"unimplemented defined? type (VM)");
5798 return vm_defined(ec, reg_cfp, op_type, obj, v);
5802vm_get_ep(
const VALUE *
const reg_ep, rb_num_t lv)
5805 const VALUE *ep = reg_ep;
5806 for (i = 0; i < lv; i++) {
5807 ep = GET_PREV_EP(ep);
5813vm_get_special_object(
const VALUE *
const reg_ep,
5814 enum vm_special_object_type
type)
5817 case VM_SPECIAL_OBJECT_VMCORE:
5818 return rb_mRubyVMFrozenCore;
5819 case VM_SPECIAL_OBJECT_CBASE:
5820 return vm_get_cbase(reg_ep);
5821 case VM_SPECIAL_OBJECT_CONST_BASE:
5822 return vm_get_const_base(reg_ep);
5824 rb_bug(
"putspecialobject insn: unknown value_type %d",
type);
5831rb_vm_get_special_object(
const VALUE *reg_ep,
enum vm_special_object_type
type)
5833 return vm_get_special_object(reg_ep,
type);
5839 const VALUE ary2 = ary2st;
5840 VALUE tmp1 = rb_check_to_array(ary1);
5841 VALUE tmp2 = rb_check_to_array(ary2);
5862 const VALUE ary2 = ary2st;
5864 if (
NIL_P(ary2))
return ary1;
5866 VALUE tmp2 = rb_check_to_array(ary2);
5881 return vm_concat_array(ary1, ary2st);
5885rb_vm_concat_to_array(
VALUE ary1,
VALUE ary2st)
5887 return vm_concat_to_array(ary1, ary2st);
5896 VALUE tmp = rb_check_to_array(ary);
5900 else if (
RTEST(flag)) {
5913 return vm_splat_array(flag, ary);
5919 enum vm_check_match_type
type = ((int)flag) & VM_CHECKMATCH_TYPE_MASK;
5921 if (flag & VM_CHECKMATCH_ARRAY) {
5925 for (i = 0; i < n; i++) {
5927 VALUE c = check_match(ec, v, target,
type);
5936 return check_match(ec, pattern, target,
type);
5943 return vm_check_match(ec, target, pattern, flag);
5947vm_check_keyword(lindex_t bits, lindex_t idx,
const VALUE *ep)
5949 const VALUE kw_bits = *(ep - bits);
5952 unsigned int b = (
unsigned int)
FIX2ULONG(kw_bits);
5953 if ((idx < VM_KW_SPECIFIED_BITS_MAX) && (b & (0x01 << idx)))
5957 VM_ASSERT(rb_set_p(kw_bits),
"%s", rb_obj_info(kw_bits));
5966 if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() ||
5967 RUBY_DTRACE_METHOD_RETURN_ENABLED() ||
5968 RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() ||
5969 RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) {
5973 RUBY_DTRACE_METHOD_ENTRY_HOOK(ec, 0, 0);
5976 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, 0, 0);
5979 RUBY_DTRACE_METHOD_RETURN_HOOK(ec, 0, 0);
5982 RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, 0, 0);
5989vm_const_get_under(
ID id, rb_num_t flags,
VALUE cbase)
5994 else if (VM_DEFINECLASS_SCOPED_P(flags)) {
5995 return rb_public_const_get_at(cbase,
id);
6003vm_check_if_class(
ID id, rb_num_t flags,
VALUE super,
VALUE klass)
6008 else if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags)) {
6013 "superclass mismatch for class %"PRIsVALUE
"",
6026vm_check_if_module(
ID id,
VALUE mod)
6045vm_declare_class(
ID id, rb_num_t flags,
VALUE cbase,
VALUE super)
6048 VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super :
rb_cObject;
6055vm_declare_module(
ID id,
VALUE cbase)
6061NORETURN(
static void unmatched_redefinition(
const char *
type,
VALUE cbase,
ID id,
VALUE old));
6065 VALUE name = rb_id2str(
id);
6066 VALUE message = rb_sprintf(
"%"PRIsVALUE
" is not a %s",
6068 VALUE location = rb_const_source_location_at(cbase,
id);
6069 if (!
NIL_P(location)) {
6070 rb_str_catf(message,
"\n%"PRIsVALUE
":%"PRIsVALUE
":"
6071 " previous definition of %"PRIsVALUE
" was here",
6078vm_define_class(
ID id, rb_num_t flags,
VALUE cbase,
VALUE super)
6082 if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) && !
RB_TYPE_P(super,
T_CLASS)) {
6084 "superclass must be an instance of Class (given an instance of %"PRIsVALUE
")",
6088 vm_check_if_namespace(cbase);
6093 if ((klass = vm_const_get_under(
id, flags, cbase)) != 0) {
6094 if (!vm_check_if_class(
id, flags, super, klass))
6095 unmatched_redefinition(
"class", cbase,
id, klass);
6099 return vm_declare_class(
id, flags, cbase, super);
6104vm_define_module(
ID id, rb_num_t flags,
VALUE cbase)
6108 vm_check_if_namespace(cbase);
6109 if ((mod = vm_const_get_under(
id, flags, cbase)) != 0) {
6110 if (!vm_check_if_module(
id, mod))
6111 unmatched_redefinition(
"module", cbase,
id, mod);
6115 return vm_declare_module(
id, cbase);
6120vm_find_or_create_class_by_id(
ID id,
6125 rb_vm_defineclass_type_t
type = VM_DEFINECLASS_TYPE(flags);
6128 case VM_DEFINECLASS_TYPE_CLASS:
6130 return vm_define_class(
id, flags, cbase, super);
6132 case VM_DEFINECLASS_TYPE_SINGLETON_CLASS:
6136 case VM_DEFINECLASS_TYPE_MODULE:
6138 return vm_define_module(
id, flags, cbase);
6141 rb_bug(
"unknown defineclass type: %d", (
int)
type);
6145static rb_method_visibility_t
6150 if (!vm_env_cref_by_cref(cfp->ep)) {
6151 return METHOD_VISI_PUBLIC;
6154 return CREF_SCOPE_VISI(vm_ec_cref(ec))->method_visi;
6163 if (!vm_env_cref_by_cref(cfp->ep)) {
6167 return CREF_SCOPE_VISI(vm_ec_cref(ec))->module_func;
6175 rb_method_visibility_t visi;
6180 visi = METHOD_VISI_PUBLIC;
6183 klass = CREF_CLASS_FOR_DEFINITION(cref);
6184 visi = vm_scope_visibility_get(ec);
6191 rb_add_method_iseq(klass,
id, (
const rb_iseq_t *)iseqval, cref, visi);
6194 !RCLASS_SINGLETON_P(klass) && !RCLASS_EXPECT_NO_IVAR(klass) &&
6196 RCLASS_SET_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (
const rb_iseq_t *)iseqval));
6199 if (!is_singleton && vm_scope_module_func_check(ec)) {
6201 rb_add_method_iseq(klass,
id, (
const rb_iseq_t *)iseqval, cref, METHOD_VISI_PUBLIC);
6210rb_vm_untag_block_handler(
VALUE block_handler)
6212 if (VM_BLOCK_HANDLER_NONE == block_handler)
return Qnil;
6214 switch (vm_block_handler_type(block_handler)) {
6215 case block_handler_type_iseq:
6216 case block_handler_type_ifunc: {
6218 return captured->code.val;
6220 case block_handler_type_proc:
6221 case block_handler_type_symbol:
6222 return block_handler;
6224 rb_bug(
"rb_vm_untag_block_handler: unreachable");
6231 return rb_vm_untag_block_handler(VM_CF_BLOCK_HANDLER(reg_cfp));
6240 VALUE block_handler = VM_CF_BLOCK_HANDLER(GET_CFP());
6242 if (block_handler == VM_BLOCK_HANDLER_NONE) {
6243 rb_vm_localjump_error(
"no block given (yield)",
Qnil, 0);
6246 return vm_invoke_block(ec, GET_CFP(), calling, ci,
false, block_handler);
6250enum method_explorer_type {
6252 mexp_search_invokeblock,
6259 enum method_explorer_type method_explorer));
6265 VALUE block_handler,
6266 enum method_explorer_type method_explorer
6271 int argc = vm_ci_argc(ci);
6272 VALUE recv = TOPN(argc);
6274 .block_handler = block_handler,
6275 .kw_splat = IS_ARGS_KW_SPLAT(ci) > 0,
6281 switch (method_explorer) {
6282 case mexp_search_method:
6283 calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd,
CLASS_OF(recv));
6284 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6286 case mexp_search_super:
6287 calling.cc = cc = vm_search_super_method(reg_cfp, cd, recv);
6288 val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
6290 case mexp_search_invokeblock:
6291 val = vm_invokeblock_i(ec, GET_CFP(), &calling);
6301 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq,
false);
6302 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6316 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq,
false, &adjusted_cd, &adjusted_ci);
6318 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
6320 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6321 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6332 VALUE bh = VM_BLOCK_HANDLER_NONE;
6333 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
6343 struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
6346 vm_ci_kwarg(cd->ci));
6347 const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((
void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
6353 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq,
true);
6354 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
6356 if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
6357 rbimpl_atomic_ptr_store((
volatile void **)&cd->cc, (
void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
6373 VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq,
true, &adjusted_cd, &adjusted_ci);
6375 VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
6377 if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
6378 RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
6389 VALUE bh = VM_BLOCK_HANDLER_NONE;
6390 VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
6418 if (check_method_basic_definition(cme)) {
6424 if (check_cfunc(cme, rb_mod_to_s)) {
6430 val = rb_mod_to_s(recv);
6436 if (check_cfunc(cme, rb_nil_to_s)) {
6437 return rb_nil_to_s(recv);
6441 if (check_cfunc(cme, rb_true_to_s)) {
6442 return rb_true_to_s(recv);
6446 if (check_cfunc(cme, rb_false_to_s)) {
6447 return rb_false_to_s(recv);
6451 if (check_cfunc(cme, rb_int_to_s)) {
6452 return rb_fix_to_s(recv);
6464 return vm_objtostring(reg_cfp, recv, cd);
6468vm_opt_ary_freeze(
VALUE ary,
int bop,
ID id)
6470 if (BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
6479vm_opt_hash_freeze(
VALUE hash,
int bop,
ID id)
6481 if (BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
6490vm_opt_str_freeze(
VALUE str,
int bop,
ID id)
6492 if (BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
6506 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6510 VALUE args[1] = {target};
6513 RUBY_DTRACE_CREATE_HOOK(ARRAY,
RARRAY_LEN(ary));
6516 return rb_vm_call_with_refinements(ec, dupary, idIncludeP, 1, args,
RB_NO_KEYWORDS);
6523 return vm_opt_duparray_include_p(ec, ary, target);
6529 if (OP_UNREDEFINED_P(MAX, ARRAY)) {
6530 if (array_len == 0) {
6534 VALUE result = *ptr;
6535 rb_snum_t i = array_len - 1;
6537 const VALUE v = *++ptr;
6538 if (OPTIMIZED_CMP(v, result) > 0) {
6553 return vm_opt_newarray_max(ec, array_len, ptr);
6559 if (OP_UNREDEFINED_P(MIN, ARRAY)) {
6560 if (array_len == 0) {
6564 VALUE result = *ptr;
6565 rb_snum_t i = array_len - 1;
6567 const VALUE v = *++ptr;
6568 if (OPTIMIZED_CMP(v, result) < 0) {
6583 return vm_opt_newarray_min(ec, array_len, ptr);
6590 if (OP_UNREDEFINED_P(HASH, ARRAY)) {
6591 return rb_ary_hash_values(array_len, ptr);
6601 return vm_opt_newarray_hash(ec, array_len, ptr);
6610 if (OP_UNREDEFINED_P(INCLUDE_P, ARRAY)) {
6611 struct RArray fake_ary = {RBASIC_INIT};
6612 VALUE ary = rb_setup_fake_ary(&fake_ary,
ptr, array_len);
6616 VALUE args[1] = {target};
6624 return vm_opt_newarray_include_p(ec, array_len,
ptr, target);
6630 if (OP_UNREDEFINED_P(PACK, ARRAY)) {
6631 struct RArray fake_ary = {RBASIC_INIT};
6632 VALUE ary = rb_setup_fake_ary(&fake_ary,
ptr, array_len);
6633 return rb_ec_pack_ary(ec,
ary, fmt, (UNDEF_P(buffer) ?
Qnil : buffer));
6643 if (!UNDEF_P(buffer)) {
6644 args[1] = rb_hash_new_capa(1);
6645 rb_hash_aset(args[1],
ID2SYM(idBuffer), buffer);
6650 return rb_vm_call_with_refinements(ec,
rb_ary_new4(array_len,
ptr), idPack, argc, args, kw_splat);
6657 return vm_opt_newarray_pack_buffer(ec, array_len,
ptr, fmt, buffer);
6664vm_track_constant_cache(
ID id,
void *ic)
6667 struct rb_id_table *const_cache = &vm->constant_cache;
6668 VALUE lookup_result;
6671 if (rb_id_table_lookup(const_cache,
id, &lookup_result)) {
6675 ics = set_init_numtable();
6676 rb_id_table_insert(const_cache,
id, (
VALUE)ics);
6691 vm->inserting_constant_cache_id = id;
6693 set_insert(ics, (st_data_t)ic);
6695 vm->inserting_constant_cache_id = (
ID)0;
6702 for (
int i = 0; segments[i]; i++) {
6703 ID id = segments[i];
6704 if (
id == idNULL)
continue;
6705 vm_track_constant_cache(
id, ic);
6716 if ((flags & IMEMO_CONST_CACHE_SHAREABLE) || ractor_id == rb_ractor_id(GET_RACTOR())) {
6717 VM_ASSERT(ractor_incidental_shareable_p(flags & IMEMO_CONST_CACHE_SHAREABLE, value));
6719 return (ic_cref == NULL ||
6720 ic_cref == vm_get_cref(reg_ep));
6728 VM_ASSERT(IMEMO_TYPE_P(ice, imemo_constcache));
6729 return vm_inlined_ic_hit_p(ice->flags, ice->value, ice->ic_cref, ice->ractor_id, reg_ep);
6734rb_vm_ic_hit_p(
IC ic,
const VALUE *reg_ep)
6736 return ic->entry && vm_ic_hit_p(ic->entry, reg_ep);
6742 if (ruby_vm_const_missing_count > 0) {
6743 ruby_vm_const_missing_count = 0;
6750 ice->ic_cref = vm_get_const_key_cref(reg_ep);
6751 ice->ractor_id = rb_ractor_id(GET_RACTOR());
6755 ice->flags |= IMEMO_CONST_CACHE_SHAREABLE;
6759 unsigned pos = (unsigned)(pc - ISEQ_BODY(iseq)->iseq_encoded);
6760 rb_yjit_constant_ic_update(iseq, ic, pos);
6770 if (ice && vm_ic_hit_p(ice, GET_EP())) {
6777 VM_ASSERT(val == vm_get_ev_const_chain(ec, segments) || rb_multi_ractor_p());
6780 ruby_vm_constant_cache_misses++;
6781 val = vm_get_ev_const_chain(ec, segments);
6782 vm_ic_track_const_chain(GET_CFP(), ic, segments);
6785 vm_ic_update(CFP_ISEQ(GET_CFP()), ic, val, GET_EP(), CFP_PC(GET_CFP()) - 2);
6794rb_vm_once_done_value(
ISE is,
VALUE *result)
6796 rb_thread_t *running_th = rbimpl_atomic_ptr_load((
void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6797 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6798 *result = is->once.value;
6811 running_th = rbimpl_atomic_ptr_load((
void**)&is->once.running_thread, RBIMPL_ATOMIC_ACQUIRE);
6812 if (running_th == RUNNING_THREAD_ONCE_DONE) {
6813 return is->once.value;
6815 else if (running_th == NULL) {
6817 enum ruby_tag_type state;
6818 if (rbimpl_atomic_ptr_cas((
void**)&is->once.running_thread, running_th, th, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED) != running_th) {
6822 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
6823 val = vm_once_exec((
VALUE)iseq);
6826 if (state != TAG_NONE) {
6827 vm_once_clear((
VALUE)is);
6828 EC_JUMP_TAG(ec, state);
6838 rbimpl_atomic_ptr_store((
volatile void**)&is->once.running_thread, RUNNING_THREAD_ONCE_DONE, RBIMPL_ATOMIC_RELEASE);
6839 vm_once_broadcast(rb_ec_vm_ptr(ec));
6842 else if (running_th == th) {
6844 return vm_once_exec((
VALUE)iseq);
6849 rb_nogvl(vm_once_wait_no_gvl, &arg, vm_once_wait_ubf, arg.vm,
6851 RUBY_VM_CHECK_INTS(ec);
6857vm_case_dispatch(CDHASH hash, OFFSET else_offset,
VALUE key)
6859 switch (OBJ_BUILTIN_TYPE(key)) {
6865 if (BASIC_OP_UNREDEFINED_P(BOP_EQQ,
6866 SYMBOL_REDEFINED_OP_FLAG |
6867 INTEGER_REDEFINED_OP_FLAG |
6868 FLOAT_REDEFINED_OP_FLAG |
6869 NIL_REDEFINED_OP_FLAG |
6870 TRUE_REDEFINED_OP_FLAG |
6871 FALSE_REDEFINED_OP_FLAG |
6872 STRING_REDEFINED_OP_FLAG)) {
6876 if (!isinf(kval) && modf(kval, &kval) == 0.0) {
6880 if (st_lookup(rb_imemo_cdhash_tbl(hash), key, &val)) {
6900 const ptrdiff_t nsp = VM_SP_CNT(ec, cfp->sp);
6901 const ptrdiff_t nbp = VM_SP_CNT(ec, bp);
6902 static const char stack_consistency_error[] =
6903 "Stack consistency error (sp: %"PRIdPTRDIFF
", bp: %"PRIdPTRDIFF
")";
6904#if defined RUBY_DEVEL
6905 VALUE mesg = rb_sprintf(stack_consistency_error, nsp, nbp);
6910 rb_bug(stack_consistency_error, nsp, nbp);
6917 if (FIXNUM_2_P(recv, obj) &&
6918 OP_UNREDEFINED_P(PLUS, INTEGER)) {
6919 return rb_fix_plus_fix(recv, obj);
6921 else if (FLONUM_2_P(recv, obj) &&
6922 OP_UNREDEFINED_P(PLUS, FLOAT)) {
6930 OP_UNREDEFINED_P(PLUS, FLOAT)) {
6935 OP_UNREDEFINED_P(PLUS, STRING)) {
6936 return rb_str_opt_plus(recv, obj);
6940 OP_UNREDEFINED_P(PLUS, ARRAY)) {
6951 if (FIXNUM_2_P(recv, obj) &&
6952 OP_UNREDEFINED_P(MINUS, INTEGER)) {
6953 return rb_fix_minus_fix(recv, obj);
6955 else if (FLONUM_2_P(recv, obj) &&
6956 OP_UNREDEFINED_P(MINUS, FLOAT)) {
6964 OP_UNREDEFINED_P(MINUS, FLOAT)) {
6975 if (FIXNUM_2_P(recv, obj) &&
6976 OP_UNREDEFINED_P(MULT, INTEGER)) {
6977 return rb_fix_mul_fix(recv, obj);
6979 else if (FLONUM_2_P(recv, obj) &&
6980 OP_UNREDEFINED_P(MULT, FLOAT)) {
6988 OP_UNREDEFINED_P(MULT, FLOAT)) {
6999 if (FIXNUM_2_P(recv, obj) &&
7000 OP_UNREDEFINED_P(DIV, INTEGER)) {
7001 return (
FIX2LONG(obj) == 0) ?
Qundef : rb_fix_div_fix(recv, obj);
7003 else if (FLONUM_2_P(recv, obj) &&
7004 OP_UNREDEFINED_P(DIV, FLOAT)) {
7005 return rb_flo_div_flo(recv, obj);
7012 OP_UNREDEFINED_P(DIV, FLOAT)) {
7013 return rb_flo_div_flo(recv, obj);
7023 if (FIXNUM_2_P(recv, obj) &&
7024 OP_UNREDEFINED_P(MOD, INTEGER)) {
7025 return (
FIX2LONG(obj) == 0) ?
Qundef : rb_fix_mod_fix(recv, obj);
7027 else if (FLONUM_2_P(recv, obj) &&
7028 OP_UNREDEFINED_P(MOD, FLOAT)) {
7036 OP_UNREDEFINED_P(MOD, FLOAT)) {
7047 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
7048 VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);
7050 if (!UNDEF_P(val)) {
7051 return RBOOL(!
RTEST(val));
7061 if (FIXNUM_2_P(recv, obj) &&
7062 OP_UNREDEFINED_P(LT, INTEGER)) {
7065 else if (FLONUM_2_P(recv, obj) &&
7066 OP_UNREDEFINED_P(LT, FLOAT)) {
7074 OP_UNREDEFINED_P(LT, FLOAT)) {
7085 if (FIXNUM_2_P(recv, obj) &&
7086 OP_UNREDEFINED_P(LE, INTEGER)) {
7089 else if (FLONUM_2_P(recv, obj) &&
7090 OP_UNREDEFINED_P(LE, FLOAT)) {
7098 OP_UNREDEFINED_P(LE, FLOAT)) {
7109 if (FIXNUM_2_P(recv, obj) &&
7110 OP_UNREDEFINED_P(GT, INTEGER)) {
7113 else if (FLONUM_2_P(recv, obj) &&
7114 OP_UNREDEFINED_P(GT, FLOAT)) {
7122 OP_UNREDEFINED_P(GT, FLOAT)) {
7133 if (FIXNUM_2_P(recv, obj) &&
7134 OP_UNREDEFINED_P(GE, INTEGER)) {
7137 else if (FLONUM_2_P(recv, obj) &&
7138 OP_UNREDEFINED_P(GE, FLOAT)) {
7146 OP_UNREDEFINED_P(GE, FLOAT)) {
7162 OP_UNREDEFINED_P(LTLT, STRING)) {
7171 OP_UNREDEFINED_P(LTLT, ARRAY)) {
7189 OP_UNREDEFINED_P(AND, INTEGER)) {
7200 if (FIXNUM_2_P(recv, obj) &&
7201 OP_UNREDEFINED_P(OR, INTEGER)) {
7213 if (FIXNUM_2_P(recv, obj) &&
7214 OP_UNREDEFINED_P(AREF, INTEGER)) {
7215 return rb_fix_aref(recv, obj);
7220 OP_UNREDEFINED_P(AREF, ARRAY)) {
7222 return rb_ary_entry_internal(recv,
FIX2LONG(obj));
7225 return rb_ary_aref1(recv, obj);
7229 OP_UNREDEFINED_P(AREF, HASH)) {
7230 return rb_hash_aref(recv, obj);
7244 OP_UNREDEFINED_P(ASET, ARRAY) &&
7250 OP_UNREDEFINED_P(ASET, HASH)) {
7251 rb_hash_aset(recv, obj, set);
7260vm_opt_length(
VALUE recv,
int bop)
7266 BASIC_OP_UNREDEFINED_P(bop, STRING_REDEFINED_OP_FLAG)) {
7267 if (bop == BOP_EMPTY_P) {
7268 return LONG2NUM(RSTRING_LEN(recv));
7275 BASIC_OP_UNREDEFINED_P(bop, ARRAY_REDEFINED_OP_FLAG)) {
7279 BASIC_OP_UNREDEFINED_P(bop, HASH_REDEFINED_OP_FLAG)) {
7288vm_opt_empty_p(
VALUE recv)
7290 switch (vm_opt_length(recv, BOP_EMPTY_P)) {
7303 OP_UNREDEFINED_P(
NIL_P, NIL)) {
7306 else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
7322 case RSHIFT(~0UL, 1):
7325 return rb_uint2big(1UL << (SIZEOF_LONG * CHAR_BIT - 2));
7343vm_opt_succ(
VALUE recv)
7346 OP_UNREDEFINED_P(SUCC, INTEGER)) {
7347 return fix_succ(recv);
7353 OP_UNREDEFINED_P(SUCC, STRING)) {
7364 if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
7365 return RBOOL(!
RTEST(recv));
7380 OP_UNREDEFINED_P(MATCH, STRING)) {
7384 OP_UNREDEFINED_P(MATCH, REGEXP)) {
7392#undef EQ_UNREDEFINED_P
7393#undef OP_UNREDEFINED_P
7405 VALUE self = GET_SELF();
7407 VM_ASSERT(rb_popcount64((uint64_t)event) == 1);
7409 if (local_hooks) local_hooks->running++;
7411 if (event & global_hooks->events) {
7414 vm_dtrace(event, ec);
7415 rb_exec_event_hook_orig(ec, global_hooks, event, self, 0, 0, 0 , val, 0);
7419 if (local_hooks) local_hooks->running--;
7420 if (local_hooks != NULL) {
7421 if (event & local_hooks->events) {
7424 rb_exec_event_hook_orig(ec, local_hooks, event, self, 0, 0, 0 , val, 0);
7434#define VM_TRACE_HOOK(target_event, val) do { \
7435 if ((pc_events & (target_event)) & enabled_flags) { \
7436 if (local_hooks_cnt > 0) local_hooks = rb_iseq_local_hooks(iseq, r, false); \
7437 vm_trace_hook(ec, reg_cfp, pc, pc_events, (target_event), global_hooks, local_hooks, (val)); \
7444 VM_ASSERT(VM_FRAME_RUBYFRAME_P(cfp));
7445 VM_ASSERT(ISEQ_BODY(CFP_ISEQ(cfp))->
type == ISEQ_TYPE_RESCUE);
7446 return cfp->ep[VM_ENV_INDEX_LAST_LVAR];
7452 const VALUE *pc = reg_cfp->pc;
7454 rb_event_flag_t enabled_flags = r->pub.hooks.events & ISEQ_TRACE_EVENTS;
7457 if (enabled_flags == 0 && rb_ractor_targeted_hooks_cnt(r) == 0) {
7461 const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
7462 size_t pos = pc - ISEQ_BODY(iseq)->iseq_encoded;
7464 unsigned int local_hooks_cnt = iseq->aux.exec.local_hooks_cnt;
7466 if (RB_UNLIKELY(local_hooks_cnt > 0)) {
7468 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
7472 rb_event_flag_t iseq_local_events = local_hooks != NULL ? local_hooks->events : 0;
7476 unsigned int bmethod_hooks_cnt = 0;
7478 const bool bmethod_frame = VM_FRAME_BMETHOD_P(reg_cfp);
7479 enabled_flags |= iseq_local_events;
7481 VM_ASSERT((iseq_local_events & ~ISEQ_TRACE_EVENTS) == 0);
7483 if (bmethod_frame) {
7485 VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
7486 bmethod_def = me->def;
7487 bmethod_hooks_cnt = me->def->body.bmethod.local_hooks_cnt;
7488 if (RB_UNLIKELY(bmethod_hooks_cnt > 0)) {
7490 if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)me->def, &val)) {
7493 if (bmethod_local_hooks) {
7494 bmethod_local_events = bmethod_local_hooks->events;
7499 if ((pc_events & enabled_flags) == 0 && !bmethod_frame) {
7503 rb_iseq_trace_set(iseq, vm_event_flags & ISEQ_TRACE_EVENTS);
7511 else if (ec->trace_arg != NULL) {
7519 rb_event_flag_t bmethod_events = ractor_events | bmethod_local_events;
7522 VALUE path = rb_iseq_path(iseq);
7523 VALUE label = rb_iseq_label(iseq);
7524 ruby_debug_printf(
"vm_trace>>%4d (%4x) - %.*s:%d %.*s\n",
7528 (
int)rb_iseq_line_no(iseq, pos),
7531 VM_ASSERT(reg_cfp->pc == pc);
7532 VM_ASSERT(pc_events != 0);
7542 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_LINE,
Qundef);
7543 VM_TRACE_HOOK(RUBY_EVENT_COVERAGE_BRANCH,
Qundef);
7549 if (bmethod_hooks_cnt > 0) bmethod_local_hooks = rb_method_def_local_hooks(bmethod_def, r,
false);
7557#if VM_CHECK_MODE > 0
7558NORETURN( NOINLINE( COLDFUNC
7559void rb_vm_canary_is_found_dead(
enum ruby_vminsn_type i,
VALUE c)));
7562Init_vm_stack_canary(
void)
7565 int n = ruby_fill_random_bytes(&vm_stack_canary,
sizeof vm_stack_canary,
false);
7566 vm_stack_canary |= 0x01;
7568 vm_stack_canary_was_born =
true;
7573rb_vm_canary_is_found_dead(
enum ruby_vminsn_type i,
VALUE c)
7577 const char *insn = rb_insns_name(i);
7581 rb_bug(
"dead canary found at %s: %s", insn, str);
7585void Init_vm_stack_canary(
void) { }
7617 return (*(rb_invoke_funcptr0_t)funcptr)(ec, self);
7624 return (*(rb_invoke_funcptr1_t)funcptr)(ec, self, argv[0]);
7631 return (*(rb_invoke_funcptr2_t)funcptr)(ec, self, argv[0], argv[1]);
7638 return (*(rb_invoke_funcptr3_t)funcptr)(ec, self, argv[0], argv[1], argv[2]);
7645 return (*(rb_invoke_funcptr4_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3]);
7652 return (*(rb_invoke_funcptr5_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4]);
7659 return (*(rb_invoke_funcptr6_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
7666 return (*(rb_invoke_funcptr7_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
7673 return (*(rb_invoke_funcptr8_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
7679 typedef VALUE (*rb_invoke_funcptr9_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9);
7680 return (*(rb_invoke_funcptr9_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
7686 typedef VALUE (*rb_invoke_funcptr10_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10);
7687 return (*(rb_invoke_funcptr10_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
7693 typedef VALUE (*rb_invoke_funcptr11_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10,
VALUE v11);
7694 return (*(rb_invoke_funcptr11_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
7700 typedef VALUE (*rb_invoke_funcptr12_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10,
VALUE v11,
VALUE v12);
7701 return (*(rb_invoke_funcptr12_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
7707 typedef VALUE (*rb_invoke_funcptr13_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10,
VALUE v11,
VALUE v12,
VALUE v13);
7708 return (*(rb_invoke_funcptr13_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
7714 typedef VALUE (*rb_invoke_funcptr14_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10,
VALUE v11,
VALUE v12,
VALUE v13,
VALUE v14);
7715 return (*(rb_invoke_funcptr14_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
7721 typedef VALUE (*rb_invoke_funcptr15_t)(
rb_execution_context_t *ec,
VALUE self,
VALUE v1,
VALUE v2,
VALUE v3,
VALUE v4,
VALUE v5,
VALUE v6,
VALUE v7,
VALUE v8,
VALUE v9,
VALUE v10,
VALUE v11,
VALUE v12,
VALUE v13,
VALUE v14,
VALUE v15);
7722 return (*(rb_invoke_funcptr15_t)funcptr)(ec, self, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
7727static builtin_invoker
7728lookup_builtin_invoker(
int argc)
7730 static const builtin_invoker invokers[] = {
7749 return invokers[argc];
7755 const bool canary_p = ISEQ_BODY(CFP_ISEQ(reg_cfp))->builtin_attrs & BUILTIN_ATTR_LEAF;
7756 SETUP_CANARY(canary_p);
7757 rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
7758 VALUE ret = (*lookup_builtin_invoker(bf->argc))(ec, reg_cfp->self, argv, func_ptr);
7759 CHECK_CANARY(canary_p, BIN(invokebuiltin));
7766 return invoke_bf(ec, cfp, bf, argv);
7773 fputs(
"vm_invoke_builtin_delegate: passing -> ", stderr);
7774 for (
int i=0; i<bf->argc; i++) {
7775 ruby_debug_printf(
":%s ", rb_id2name(ISEQ_BODY(CFP_ISEQ(cfp))->local_table[i+start_index]));
7777 ruby_debug_printf(
"\n" "%s %s(%d):%p\n", RUBY_FUNCTION_NAME_STRING, bf->name, bf->argc,
7778 (
void *)(uintptr_t)bf->func_ptr);
7781 if (bf->argc == 0) {
7782 return invoke_bf(ec, cfp, bf, NULL);
7785 const VALUE *argv = cfp->ep - ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
7786 return invoke_bf(ec, cfp, bf, argv);
7796 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 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 LONG2NUM
Old name of RB_LONG2NUM.
#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_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_includes(VALUE ary, VALUE elem)
Queries if the passed array has the passed entry.
VALUE rb_ary_plus(VALUE lhs, VALUE rhs)
Creates a new array, concatenating the former to the latter.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
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.
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.