diff options
Diffstat (limited to 'insns.def')
| -rw-r--r-- | insns.def | 968 |
1 files changed, 647 insertions, 321 deletions
@@ -1,4 +1,4 @@ -/* -*- mode:c; style:ruby; coding: utf-8 -*- +/* -*- C -*- insns.def - YARV instruction definitions $Author: $ @@ -109,14 +109,14 @@ getblockparam VM_ASSERT(VM_ENV_LOCAL_P(ep)); if (!VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)) { - val = rb_vm_bh_to_procval(ec, VM_ENV_BLOCK_HANDLER(ep)); - vm_env_write(ep, -(int)idx, val); - VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); + val = rb_vm_bh_to_procval(ec, VM_ENV_BLOCK_HANDLER(ep)); + vm_env_write(ep, -(int)idx, val); + VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); } else { - val = *(ep - idx); - RB_DEBUG_COUNTER_INC(lvar_get); - (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); + val = *(ep - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); } } @@ -145,40 +145,41 @@ getblockparamproxy (lindex_t idx, rb_num_t level) () (VALUE val) +// attr bool zjit_profile = true; { const VALUE *ep = vm_get_ep(GET_EP(), level); VM_ASSERT(VM_ENV_LOCAL_P(ep)); if (!VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)) { - VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep); - - if (block_handler) { - switch (vm_block_handler_type(block_handler)) { - case block_handler_type_iseq: - case block_handler_type_ifunc: - val = rb_block_param_proxy; - break; - case block_handler_type_symbol: - val = rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler)); - goto INSN_LABEL(set); - case block_handler_type_proc: - val = VM_BH_TO_PROC(block_handler); - goto INSN_LABEL(set); - default: - VM_UNREACHABLE(getblockparamproxy); - } - } - else { - val = Qnil; - INSN_LABEL(set): - vm_env_write(ep, -(int)idx, val); - VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); - } + VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep); + + if (block_handler) { + switch (vm_block_handler_type(block_handler)) { + case block_handler_type_iseq: + case block_handler_type_ifunc: + val = rb_block_param_proxy; + break; + case block_handler_type_symbol: + val = rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler)); + goto INSN_LABEL(set); + case block_handler_type_proc: + val = VM_BH_TO_PROC(block_handler); + goto INSN_LABEL(set); + default: + VM_UNREACHABLE(getblockparamproxy); + } + } + else { + val = Qnil; + INSN_LABEL(set): + vm_env_write(ep, -(int)idx, val); + VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); + } } else { - val = *(ep - idx); - RB_DEBUG_COUNTER_INC(lvar_get); - (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); + val = *(ep - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); } } @@ -188,6 +189,8 @@ getspecial (rb_num_t key, rb_num_t type) () (VALUE val) +/* `$~ = MatchData.allocate; $&` can raise. */ +// attr bool leaf = (type == 0) ? true : false; { val = vm_getspecial(ec, GET_LEP(), key, type); } @@ -205,63 +208,77 @@ setspecial /* Get value of instance variable id of self. */ DEFINE_INSN getinstancevariable -(ID id, IC ic) +(ID id, IVC ic) () (VALUE val) -/* "instance variable not initialized" warning can be hooked. */ -// attr bool leaf = false; /* has rb_warning() */ +/* Ractor crashes when it accesses class/module-level instances variables. */ +// attr bool leaf = false; /* has IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() */ +// attr bool zjit_profile = true; { - val = vm_getinstancevariable(GET_SELF(), id, ic); + val = vm_getinstancevariable(GET_ISEQ(), GET_SELF(), id, ic); } /* Set value of instance variable id of self to val. */ DEFINE_INSN setinstancevariable -(ID id, IC ic) +(ID id, IVC ic) (VALUE val) () +// attr bool leaf = false; /* has rb_check_frozen() */ +// attr bool zjit_profile = true; { - vm_setinstancevariable(GET_SELF(), id, val, ic); + vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic); } /* Get value of class variable id of klass as val. */ DEFINE_INSN getclassvariable -(ID id) +(ID id, ICVARC ic) () (VALUE val) /* "class variable access from toplevel" warning can be hooked. */ // attr bool leaf = false; /* has rb_warning() */ { - val = rb_cvar_get(vm_get_cvar_base(rb_vm_get_cref(GET_EP()), GET_CFP()), id); + rb_control_frame_t *cfp = GET_CFP(); + val = vm_getclassvariable(GET_ISEQ(), cfp, id, ic); } /* Set value of class variable id of klass as val. */ DEFINE_INSN setclassvariable -(ID id) +(ID id, ICVARC ic) (VALUE val) () /* "class variable access from toplevel" warning can be hooked. */ // attr bool leaf = false; /* has rb_warning() */ { vm_ensure_not_refinement_module(GET_SELF()); - rb_cvar_set(vm_get_cvar_base(rb_vm_get_cref(GET_EP()), GET_CFP()), id, val); + vm_setclassvariable(GET_ISEQ(), GET_CFP(), id, val, ic); +} + +DEFINE_INSN +opt_getconstant_path +(IC ic) +() +(VALUE val) +// attr bool leaf = false; /* may autoload or raise */ +{ + val = rb_vm_opt_getconstant_path(ec, GET_CFP(), ic); } -/* Get constant variable id. If klass is Qnil, constants +/* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants are searched in the current scope. Otherwise, get constant under klass class or module. */ DEFINE_INSN getconstant (ID id) -(VALUE klass) +(VALUE klass, VALUE allow_nil) (VALUE val) /* getconstant can kick autoload */ // attr bool leaf = false; /* has rb_autoload_load() */ { - val = vm_get_ev_const(ec, klass, id, 0); + val = vm_get_ev_const(ec, klass, id, allow_nil == Qtrue, 0); } /* Set constant variable id under cbase class or module. @@ -285,23 +302,23 @@ setconstant /* get global variable id. */ DEFINE_INSN getglobal -(GENTRY entry) +(ID gid) () (VALUE val) -// attr bool leaf = leafness_of_getglobal(entry); +// attr bool leaf = false; { - val = GET_GLOBAL((VALUE)entry); + val = rb_gvar_get(gid); } /* set global variable id as val. */ DEFINE_INSN setglobal -(GENTRY entry) +(ID gid) (VALUE val) () -// attr bool leaf = leafness_of_setglobal(entry); +// attr bool leaf = false; { - SET_GLOBAL((VALUE)entry, val); + rb_gvar_set(gid, val); } /**********************************************************/ @@ -346,6 +363,7 @@ putspecialobject (rb_num_t value_type) () (VALUE val) +// attr bool leaf = (value_type == VM_SPECIAL_OBJECT_VMCORE); /* others may raise when allocating singleton */ { enum vm_special_object_type type; @@ -353,25 +371,24 @@ putspecialobject val = vm_get_special_object(GET_EP(), type); } -/* put iseq value. */ +/* put string val. string will be copied. */ DEFINE_INSN -putiseq -(ISEQ iseq) +dupstring +(VALUE str) () -(VALUE ret) -// attr bool handles_sp = false; /* of course it doesn't */ +(VALUE val) { - ret = (VALUE)iseq; + val = rb_ec_str_resurrect(ec, str, false); } -/* put string val. string will be copied. */ +/* put chilled string val. string will be copied but frozen in the future. */ DEFINE_INSN -putstring +dupchilledstring (VALUE str) () (VALUE val) { - val = rb_str_resurrect(str); + val = rb_ec_str_resurrect(ec, str, true); } /* put concatenate strings */ @@ -380,14 +397,18 @@ concatstrings (rb_num_t num) (...) (VALUE val) +/* This instruction can concat UTF-8 and binary strings, resulting in + * Encoding::CompatibilityError. */ +// attr bool leaf = false; /* has rb_enc_cr_str_buf_cat() */ // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num; { val = rb_str_concat_literals(num, STACK_ADDR_FROM_TOP(num)); } -/* push the result of to_s. */ +/* Convert the result to string if not already a string. + This is used as a backup if to_s does not return a string. */ DEFINE_INSN -tostring +anytostring () (VALUE val, VALUE str) (VALUE val) @@ -395,16 +416,6 @@ tostring val = rb_obj_as_string_result(str, val); } -/* Freeze (dynamically) created strings. if debug_info is given, set it. */ -DEFINE_INSN -freezestring -(VALUE debug_info) -(VALUE str) -(VALUE str) -{ - vm_freezestring(str, debug_info); -} - /* compile str to Regexp and push it. opt is the option for the Regexp. */ @@ -413,14 +424,12 @@ toregexp (rb_num_t opt, rb_num_t cnt) (...) (VALUE val) -/* This instruction has StringValue(), which is a method call. But it - * seems that path is never covered. */ -// attr bool leaf = true; /* yes it is */ +/* This instruction can raise RegexpError, thus can call + * RegexpError#initialize */ +// attr bool leaf = false; // attr rb_snum_t sp_inc = 1 - (rb_snum_t)cnt; { - const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt)); - val = rb_reg_new_ary(ary, (int)opt); - rb_ary_clear(ary); + val = rb_reg_new_from_values(cnt, STACK_ADDR_FROM_TOP(cnt), (int)opt); } /* intern str to Symbol and push it. */ @@ -441,7 +450,21 @@ newarray (VALUE val) // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num; { - val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num)); + val = rb_ec_ary_new_from_values(ec, num, STACK_ADDR_FROM_TOP(num)); +} + +/* push hash onto array unless the hash is empty (as empty keyword + splats should be ignored). + */ +DEFINE_INSN +pushtoarraykwsplat +() +(VALUE ary, VALUE hash) +(VALUE ary) +{ + if (!RHASH_EMPTY_P(hash)) { + rb_ary_push(ary, hash); + } } /* dup array */ @@ -451,9 +474,21 @@ duparray () (VALUE val) { + RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary)); val = rb_ary_resurrect(ary); } +/* dup hash */ +DEFINE_INSN +duphash +(VALUE hash) +() +(VALUE val) +{ + RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1); + val = rb_hash_resurrect(hash); +} + /* if TOS is an array expand, expand it to num objects. if the number of the array is less than num, push nils to fill. if it is greater than num, exceeding elements are dropped. @@ -468,13 +503,16 @@ expandarray (rb_num_t num, rb_num_t flag) (..., VALUE ary) (...) +// attr bool handles_sp = true; // attr bool leaf = false; /* has rb_check_array_type() */ // attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0); { - vm_expandarray(GET_SP(), ary, num, (int)flag); + vm_expandarray(GET_CFP(), ary, num, (int)flag); } -/* concat two arrays */ +/* concat two arrays, without modifying first array. + * attempts to convert both objects to arrays using to_a. + */ DEFINE_INSN concatarray () @@ -485,6 +523,32 @@ concatarray ary = vm_concat_array(ary1, ary2); } +/* concat second array to first array. + * first argument must already be an array. + * attempts to convert second object to array using to_a. + */ +DEFINE_INSN +concattoarray +() +(VALUE ary1, VALUE ary2) +(VALUE ary) +// attr bool leaf = false; /* has rb_check_array_type() */ +{ + ary = vm_concat_to_array(ary1, ary2); +} + +/* push given number of objects to array directly before. */ +DEFINE_INSN +pushtoarray +(rb_num_t num) +(...) +(VALUE val) +// attr rb_snum_t sp_inc = -(rb_snum_t)num; +{ + const VALUE *objp = STACK_ADDR_FROM_TOP(num); + val = rb_ary_cat(*(objp-1), objp, num); +} + /* call to_a on array ary to splat */ DEFINE_INSN splatarray @@ -496,6 +560,23 @@ splatarray obj = vm_splat_array(flag, ary); } +/* call to_hash on hash to keyword splat before converting block */ +DEFINE_INSN +splatkw +() +(VALUE hash, VALUE block) +(VALUE obj, VALUE block) +// attr bool leaf = false; /* has rb_to_hash_type() */ +// attr bool zjit_profile = true; +{ + if (NIL_P(hash)) { + obj = Qnil; + } + else { + obj = rb_to_hash_type(hash); + } +} + /* put new Hash from n elements. n must be an even number. */ DEFINE_INSN newhash @@ -507,24 +588,12 @@ newhash { RUBY_DTRACE_CREATE_HOOK(HASH, num); - val = rb_hash_new_with_size(num / 2); - if (num) { - rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val); + val = rb_hash_new_with_bulk_insert(num, STACK_ADDR_FROM_TOP(num)); + } + else { + val = rb_hash_new(); } -} - -/* make new Hash object from (frozen) Array object */ -DEFINE_INSN -newhashfromarray -(rb_num_t num, VALUE ary) -() -(VALUE hash) -// attr bool leaf = false; /* rb_hash_bulk_insert() can call methods. */ -{ - VM_ASSERT(num * 2 == (rb_num_t)RARRAY_LEN(ary)); - hash = rb_hash_new_with_size(num); - rb_hash_bulk_insert(num * 2, RARRAY_CONST_PTR_TRANSIENT(ary), hash); } /* put new Range object.(Range.new(low, high, flag)) */ @@ -590,7 +659,7 @@ swap /* reverse stack top N order. */ DEFINE_INSN -reverse +opt_reverse (rb_num_t n) (...) (...) @@ -608,7 +677,7 @@ reverse } /* for stack caching. */ -DEFINE_INSN +DEFINE_INSN_IF(STACK_CACHING) reput () (..., VALUE val) @@ -658,19 +727,37 @@ adjuststack /* defined? */ DEFINE_INSN defined -(rb_num_t op_type, VALUE obj, VALUE needstr) +(rb_num_t op_type, VALUE obj, VALUE pushval) (VALUE v) (VALUE val) // attr bool leaf = leafness_of_defined(op_type); { - val = vm_defined(ec, GET_CFP(), op_type, obj, needstr, v); + val = Qnil; + if (vm_defined(ec, GET_CFP(), op_type, obj, v)) { + val = pushval; + } +} + +/* defined?(@foo) */ +DEFINE_INSN +definedivar +(ID id, IVC ic, VALUE pushval) +() +(VALUE val) +// attr bool leaf = false; +// attr bool zjit_profile = true; +{ + val = Qnil; + if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) { + val = pushval; + } } /* check `target' matches `pattern'. `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern. VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy. VM_CHECKMATCH_TYPE_CASE: check `patten === target'. - VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_op?(Module) && pattern === target'. + VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_of?(Module) && pattern === target'. if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns. */ DEFINE_INSN @@ -700,7 +787,7 @@ checktype (VALUE val) (VALUE ret) { - ret = (TYPE(val) == (int)type) ? Qtrue : Qfalse; + ret = RBOOL(TYPE(val) == (int)type); } /**********************************************************/ @@ -708,7 +795,7 @@ checktype /**********************************************************/ /* enter class definition scope. if super is Qfalse, and class - "klass" is defined, it's redefine. otherwise, define "klass" class. + "klass" is defined, it's redefined. Otherwise, define "klass" class. */ DEFINE_INSN defineclass @@ -717,20 +804,45 @@ defineclass (VALUE val) { VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super); + const rb_box_t *box = rb_current_box(); rb_iseq_check(class_iseq); + rb_cref_t *cref = vm_cref_push(ec, klass, NULL, FALSE, FALSE); + + if (VM_DEFINECLASS_DYNAMIC_CREF_P(flags)) { + CREF_DYNAMIC_SET(cref); + } + /* enter scope */ vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass, - GET_BLOCK_HANDLER(), - (VALUE)vm_cref_push(ec, klass, NULL, FALSE), - class_iseq->body->iseq_encoded, GET_SP(), - class_iseq->body->local_table_size, - class_iseq->body->stack_max); + GC_GUARDED_PTR(box), + (VALUE)cref, + ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(), + ISEQ_BODY(class_iseq)->local_table_size, + ISEQ_BODY(class_iseq)->stack_max); RESTORE_REGS(); NEXT_INSN(); } +DEFINE_INSN +definemethod +(ID id, ISEQ iseq) +() +() +{ + vm_define_method(ec, Qnil, id, (VALUE)iseq, FALSE); +} + +DEFINE_INSN +definesmethod +(ID id, ISEQ iseq) +(VALUE obj) +() +{ + vm_define_method(ec, obj, id, (VALUE)iseq, TRUE); +} + /**********************************************************/ /* deal with control flow 2: method/iterator */ /**********************************************************/ @@ -738,65 +850,211 @@ defineclass /* invoke method. */ DEFINE_INSN send -(CALL_INFO ci, CALL_CACHE cc, ISEQ blockiseq) +(CALL_DATA cd, ISEQ blockiseq) +(...) +(VALUE val) +// attr bool zjit_profile = true; +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); +{ + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false); + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + JIT_EXEC(ec, val); + + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + +/* invoke forward method. */ +DEFINE_INSN +sendforward +(CALL_DATA cd, ISEQ blockiseq) (...) (VALUE val) -// attr rb_snum_t sp_inc = - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0)); +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); { - struct rb_calling_info calling; + struct rb_forwarding_call_data adjusted_cd; + struct rb_callinfo adjusted_ci; - calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, ci, blockiseq, FALSE); - calling.recv = TOPN(calling.argc = ci->orig_argc); - vm_search_method(ci, cc, calling.recv); - CALL_METHOD(&calling, ci, cc); + VALUE bh = vm_caller_setup_fwd_args(ec, GET_CFP(), cd, blockiseq, 0, &adjusted_cd, &adjusted_ci); + + val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method); + JIT_EXEC(ec, val); + + if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) { + RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc); + } + + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); + } } /* Invoke method without block */ DEFINE_INSN opt_send_without_block -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (...) (VALUE val) +// attr bool zjit_profile = true; // attr bool handles_sp = true; -// attr rb_snum_t sp_inc = -ci->orig_argc; +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); +{ + VALUE bh = VM_BLOCK_HANDLER_NONE; + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + JIT_EXEC(ec, val); + + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + +/* Jump if "new" method has been defined by user */ +DEFINE_INSN +opt_new +(CALL_DATA cd, OFFSET dst) +() +() +// attr bool leaf = false; { - struct rb_calling_info calling; - calling.block_handler = VM_BLOCK_HANDLER_NONE; - vm_search_method(ci, cc, calling.recv = TOPN(calling.argc = ci->orig_argc)); - CALL_METHOD(&calling, ci, cc); + VALUE argc = vm_ci_argc(cd->ci); + VALUE val = TOPN(argc); + + // The bookkeeping slot should be empty. + RUBY_ASSERT(TOPN(argc + 1) == Qnil); + + if (vm_method_cfunc_is(GET_CFP(), cd, val, rb_class_new_instance_pass_kw)) { + RB_DEBUG_COUNTER_INC(opt_new_hit); + val = rb_obj_alloc(val); + TOPN(argc) = val; + TOPN(argc + 1) = val; + } + else { + RB_DEBUG_COUNTER_INC(opt_new_miss); + JUMP(dst); + } +} + +/* Convert object to string using to_s or equivalent. */ +DEFINE_INSN +objtostring +(CALL_DATA cd) +(VALUE recv) +(VALUE val) +// attr bool leaf = false; +// attr bool zjit_profile = true; +{ + val = vm_objtostring(GET_CFP(), recv, cd); + + if (UNDEF_P(val)) { + CALL_SIMPLE_METHOD(); + } +} + +DEFINE_INSN +opt_ary_freeze +(VALUE ary, CALL_DATA cd) +() +(VALUE val) +{ + val = vm_opt_ary_freeze(ary, BOP_FREEZE, idFreeze); + + if (UNDEF_P(val)) { + RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary)); + PUSH(rb_ary_resurrect(ary)); + CALL_SIMPLE_METHOD(); + } +} + +DEFINE_INSN +opt_hash_freeze +(VALUE hash, CALL_DATA cd) +() +(VALUE val) +{ + val = vm_opt_hash_freeze(hash, BOP_FREEZE, idFreeze); + + if (UNDEF_P(val)) { + RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1); + PUSH(rb_hash_resurrect(hash)); + CALL_SIMPLE_METHOD(); + } } DEFINE_INSN opt_str_freeze -(VALUE str, CALL_INFO ci, CALL_CACHE cc) +(VALUE str, CALL_DATA cd) () (VALUE val) { val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze); - if (val == Qundef) { + if (UNDEF_P(val)) { PUSH(rb_str_resurrect(str)); CALL_SIMPLE_METHOD(); } } +/* optimized nil? */ +DEFINE_INSN +opt_nil_p +(CALL_DATA cd) +(VALUE recv) +(VALUE val) +// attr bool zjit_profile = true; +{ + val = vm_opt_nil_p(GET_CFP(), cd, recv); + + if (UNDEF_P(val)) { + CALL_SIMPLE_METHOD(); + } +} + DEFINE_INSN opt_str_uminus -(VALUE str, CALL_INFO ci, CALL_CACHE cc) +(VALUE str, CALL_DATA cd) () (VALUE val) { val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus); - if (val == Qundef) { + if (UNDEF_P(val)) { PUSH(rb_str_resurrect(str)); CALL_SIMPLE_METHOD(); } } DEFINE_INSN -opt_newarray_max -(rb_num_t num) +opt_duparray_send +(VALUE ary, ID method, rb_num_t argc) +(...) +(VALUE val) +/* This instruction typically has no funcalls. But it may compare array + * contents to each other which may call methods when necessary. + * No way to detect such method calls beforehand. + * We must mark it as not leaf. */ +// attr bool leaf = false; /* has rb_funcall() */ +// attr rb_snum_t sp_inc = 1 - (rb_snum_t)argc; +// attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)argc; +{ + switch (method) { + case idIncludeP: + val = vm_opt_duparray_include_p(ec, ary, TOPN(0)); + break; + default: + rb_bug("unreachable"); + } +} + +DEFINE_INSN +opt_newarray_send +(rb_num_t num, rb_num_t method) (...) (VALUE val) /* This instruction typically has no funcalls. But it compares array @@ -805,62 +1063,112 @@ opt_newarray_max * cannot but mark it being not leaf. */ // attr bool leaf = false; /* has rb_funcall() */ // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num; -{ - val = vm_opt_newarray_max(num, STACK_ADDR_FROM_TOP(num)); +// attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)num; +{ + switch (method) { + case VM_OPT_NEWARRAY_SEND_HASH: + val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num)); + break; + case VM_OPT_NEWARRAY_SEND_MIN: + val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num)); + break; + case VM_OPT_NEWARRAY_SEND_MAX: + val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num)); + break; + case VM_OPT_NEWARRAY_SEND_INCLUDE_P: + val = vm_opt_newarray_include_p(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0)); + break; + case VM_OPT_NEWARRAY_SEND_PACK: + val = vm_opt_newarray_pack_buffer(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0), Qundef); + break; + case VM_OPT_NEWARRAY_SEND_PACK_BUFFER: + val = vm_opt_newarray_pack_buffer(ec, (long)num-2, STACK_ADDR_FROM_TOP(num), TOPN(1), TOPN(0)); + break; + default: + rb_bug("unreachable"); + } } +/* super(args) # args.size => num */ DEFINE_INSN -opt_newarray_min -(rb_num_t num) +invokesuper +(CALL_DATA cd, ISEQ blockiseq) (...) (VALUE val) -/* Same discussion as opt_newarray_max. */ -// attr bool leaf = false; /* has rb_funcall() */ -// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num; -{ - val = vm_opt_newarray_min(num, STACK_ADDR_FROM_TOP(num)); +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); +// attr bool zjit_profile = true; +{ + struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci), + vm_ci_flag(cd->ci), + vm_ci_argc(cd->ci), + vm_ci_kwarg(cd->ci)); + const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE); + struct rb_call_data adjusted_cd = { + .ci = &adjusted_ci, + .cc = original_cc, + }; + + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true); + val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super); + JIT_EXEC(ec, val); + + if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) { + rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE); + RB_OBJ_WRITTEN(GET_ISEQ(), Qundef, adjusted_cd.cc); + } + + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); + } } /* super(args) # args.size => num */ DEFINE_INSN -invokesuper -(CALL_INFO ci, CALL_CACHE cc, ISEQ blockiseq) +invokesuperforward +(CALL_DATA cd, ISEQ blockiseq) (...) (VALUE val) -// attr rb_snum_t sp_inc = - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0)); +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); { - struct rb_calling_info calling; + struct rb_forwarding_call_data adjusted_cd; + struct rb_callinfo adjusted_ci; + + VALUE bh = vm_caller_setup_fwd_args(ec, GET_CFP(), cd, blockiseq, 1, &adjusted_cd, &adjusted_ci); - calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, ci, blockiseq, TRUE); - calling.recv = TOPN(calling.argc = ci->orig_argc); - vm_search_super_method(ec, GET_CFP(), &calling, ci, cc); - CALL_METHOD(&calling, ci, cc); + val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super); + JIT_EXEC(ec, val); + + if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) { + RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc); + } + + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); + } } /* yield(args) */ DEFINE_INSN invokeblock -(CALL_INFO ci) +(CALL_DATA cd) (...) (VALUE val) // attr bool handles_sp = true; -// attr rb_snum_t sp_inc = 1 - ci->orig_argc; +// attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci); +// attr bool zjit_profile = true; { - struct rb_calling_info calling; - VALUE block_handler; + VALUE bh = VM_BLOCK_HANDLER_NONE; + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock); + JIT_EXEC(ec, val); - calling.argc = ci->orig_argc; - calling.block_handler = VM_BLOCK_HANDLER_NONE; - calling.recv = Qundef; /* should not be used */ - - block_handler = VM_CF_BLOCK_HANDLER(GET_CFP()); - if (block_handler == VM_BLOCK_HANDLER_NONE) { - rb_vm_localjump_error("no block given (yield)", Qnil, 0); - } - - val = vm_invoke_block(ec, GET_CFP(), &calling, ci, block_handler); - if (val == Qundef) { - EXEC_EC_CFP(val); + if (UNDEF_P(val)) { + RESTORE_REGS(); + NEXT_INSN(); } } @@ -877,24 +1185,22 @@ leave // attr bool handles_sp = true; { if (OPT_CHECKED_RUN) { - const VALUE *const bp = vm_base_ptr(reg_cfp); - if (reg_cfp->sp != bp) { - vm_stack_consistency_error(ec, reg_cfp, bp); - } + const VALUE *const bp = vm_base_ptr(GET_CFP()); + if (GET_SP() != bp) { + vm_stack_consistency_error(ec, GET_CFP(), bp); + } } - RUBY_VM_CHECK_INTS(ec); - if (vm_pop_frame(ec, GET_CFP(), GET_EP())) { #if OPT_CALL_THREADED_CODE - rb_ec_thread_ptr(ec)->retval = val; - return 0; + rb_ec_thread_ptr(ec)->retval = val; + return 0; #else - return val; + return val; #endif } else { - RESTORE_REGS(); + RESTORE_REGS(); } } @@ -911,7 +1217,6 @@ throw /* Same discussion as leave. */ // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */ { - RUBY_VM_CHECK_INTS(ec); val = vm_throw(ec, GET_CFP(), throw_state, throwobj); THROW_EXCEPTION(val); /* unreachable */ @@ -944,8 +1249,8 @@ branchif // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */ { if (RTEST(val)) { - RUBY_VM_CHECK_INTS(ec); - JUMP(dst); + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); } } @@ -959,8 +1264,8 @@ branchunless // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */ { if (!RTEST(val)) { - RUBY_VM_CHECK_INTS(ec); - JUMP(dst); + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); } } @@ -974,41 +1279,65 @@ branchnil // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */ { if (NIL_P(val)) { - RUBY_VM_CHECK_INTS(ec); - JUMP(dst); + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); } } -/**********************************************************/ -/* for optimize */ -/**********************************************************/ - -/* push inline-cached value and go to dst if it is valid */ +/* same as jump, but without interrupt check */ DEFINE_INSN -opt_getinlinecache -(OFFSET dst, IC ic) +jump_without_ints +(OFFSET dst) +() () +// attr bool leaf = true; +{ + JUMP(dst); +} + +/* same as branchif, but without interrupt check */ +DEFINE_INSN +branchif_without_ints +(OFFSET dst) (VALUE val) +() +// attr bool leaf = true; { - if (vm_ic_hit_p(ic, GET_EP())) { - val = ic->ic_value.value; - JUMP(dst); - } - else { - val = Qnil; + if (RTEST(val)) { + JUMP(dst); } } -/* set inline cache */ +/* same as branchunless, but without interrupt check */ DEFINE_INSN -opt_setinlinecache -(IC ic) +branchunless_without_ints +(OFFSET dst) (VALUE val) +() +// attr bool leaf = true; +{ + if (!RTEST(val)) { + JUMP(dst); + } +} + +/* same as branchnil, but without interrupt check */ +DEFINE_INSN +branchnil_without_ints +(OFFSET dst) (VALUE val) +() +// attr bool leaf = true; { - vm_ic_update(ic, val, GET_EP()); + if (NIL_P(val)) { + JUMP(dst); + } } +/**********************************************************/ +/* for optimize */ +/**********************************************************/ + /* run iseq only once */ DEFINE_INSN once @@ -1030,7 +1359,7 @@ opt_case_dispatch OFFSET dst = vm_case_dispatch(hash, else_offset, key); if (dst) { - JUMP(dst); + JUMP(dst); } } @@ -1039,16 +1368,14 @@ opt_case_dispatch /* optimized X+Y. */ DEFINE_INSN opt_plus -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) -/* Array + anything can be handled inside of opt_plus, and that - * anything is converted into array using #to_ary. */ -// attr bool leaf = false; /* has rb_to_array_type() */ +// attr bool zjit_profile = true; { val = vm_opt_plus(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1056,13 +1383,14 @@ opt_plus /* optimized X-Y. */ DEFINE_INSN opt_minus -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_minus(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1070,13 +1398,14 @@ opt_minus /* optimized X*Y. */ DEFINE_INSN opt_mult -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_mult(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1084,13 +1413,17 @@ opt_mult /* optimized X/Y. */ DEFINE_INSN opt_div -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +/* In case of division by zero, it raises. Thus + * ZeroDivisionError#initialize is called. */ +// attr bool leaf = false; +// attr bool zjit_profile = true; { val = vm_opt_div(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1098,13 +1431,16 @@ opt_div /* optimized X%Y. */ DEFINE_INSN opt_mod -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +/* Same discussion as opt_div. */ +// attr bool leaf = false; +// attr bool zjit_profile = true; { val = vm_opt_mod(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1112,17 +1448,14 @@ opt_mod /* optimized X==Y. */ DEFINE_INSN opt_eq -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) -/* This instruction can compare a string with non-string. This - * (somewhat) coerces the non-string into a string, via a method - * call. */ -// attr bool leaf = false; /* has rb_str_equal() */ +// attr bool zjit_profile = true; { - val = opt_eq_func(recv, obj, ci, cc); + val = opt_equality(GET_CFP(), recv, obj, cd); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1130,15 +1463,14 @@ opt_eq /* optimized X!=Y. */ DEFINE_INSN opt_neq -(CALL_INFO ci_eq, CALL_CACHE cc_eq, CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd_eq, CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) -/* Same discussion as opt_eq. */ -// attr bool leaf = false; /* has rb_str_equal() */ +// attr bool zjit_profile = true; { - val = vm_opt_neq(ci, cc, ci_eq, cc_eq, recv, obj); + val = vm_opt_neq(GET_CFP(), cd, cd_eq, recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1146,13 +1478,14 @@ opt_neq /* optimized X<Y. */ DEFINE_INSN opt_lt -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_lt(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1160,13 +1493,14 @@ opt_lt /* optimized X<=Y. */ DEFINE_INSN opt_le -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_le(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1174,13 +1508,14 @@ opt_le /* optimized X>Y. */ DEFINE_INSN opt_gt -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_gt(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1188,13 +1523,14 @@ opt_gt /* optimized X>=Y. */ DEFINE_INSN opt_ge -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_ge(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1202,13 +1538,18 @@ opt_ge /* << */ DEFINE_INSN opt_ltlt -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +/* This instruction can append an integer, as a codepoint, into a + * string. Then what happens if that codepoint does not exist in the + * string's encoding? Of course an exception. That's not a leaf. */ +// attr bool leaf = false; /* has "invalid codepoint" exception */ +// attr bool zjit_profile = true; { val = vm_opt_ltlt(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1216,13 +1557,14 @@ opt_ltlt /* optimized X&Y. */ DEFINE_INSN opt_and -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_and(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1230,13 +1572,14 @@ opt_and /* optimized X|Y. */ DEFINE_INSN opt_or -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_or(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1244,7 +1587,7 @@ opt_or /* [] */ DEFINE_INSN opt_aref -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj) (VALUE val) /* This is complicated. In case of hash, vm_opt_aref() resorts to @@ -1252,10 +1595,11 @@ opt_aref * default_proc. This is a method call. So opt_aref is * (surprisingly) not leaf. */ // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */ +// attr bool zjit_profile = true; { val = vm_opt_aref(recv, obj); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1263,58 +1607,17 @@ opt_aref /* recv[obj] = set */ DEFINE_INSN opt_aset -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv, VALUE obj, VALUE set) (VALUE val) /* This is another story than opt_aref. When vm_opt_aset() resorts * to rb_hash_aset(), which should call #hash for `obj`. */ // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */ +// attr bool zjit_profile = true; { val = vm_opt_aset(recv, obj, set); - if (val == Qundef) { - CALL_SIMPLE_METHOD(); - } -} - -/* recv[str] = set */ -DEFINE_INSN -opt_aset_with -(VALUE key, CALL_INFO ci, CALL_CACHE cc) -(VALUE recv, VALUE val) -(VALUE val) -/* Same discussion as opt_aset. */ -// attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */ -{ - VALUE tmp = vm_opt_aset_with(recv, key, val); - - if (tmp != Qundef) { - val = tmp; - } - else { -#ifndef MJIT_HEADER - TOPN(0) = rb_str_resurrect(key); - PUSH(val); -#endif - CALL_SIMPLE_METHOD(); - } -} - -/* recv[str] */ -DEFINE_INSN -opt_aref_with -(VALUE key, CALL_INFO ci, CALL_CACHE cc) -(VALUE recv) -(VALUE val) -/* Same discussion as opt_aref. */ -// attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */ -{ - val = vm_opt_aref_with(recv, key); - - if (val == Qundef) { -#ifndef MJIT_HEADER - PUSH(rb_str_resurrect(key)); -#endif + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1322,13 +1625,14 @@ opt_aref_with /* optimized length */ DEFINE_INSN opt_length -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_length(recv, BOP_LENGTH); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1336,13 +1640,14 @@ opt_length /* optimized size */ DEFINE_INSN opt_size -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_length(recv, BOP_SIZE); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1350,13 +1655,14 @@ opt_size /* optimized empty? */ DEFINE_INSN opt_empty_p -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_empty_p(recv); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1364,13 +1670,14 @@ opt_empty_p /* optimized succ */ DEFINE_INSN opt_succ -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_succ(recv); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } @@ -1378,65 +1685,84 @@ opt_succ /* optimized not */ DEFINE_INSN opt_not -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { - val = vm_opt_not(ci, cc, recv); + val = vm_opt_not(GET_CFP(), cd, recv); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } -/* optimized regexp match */ -DEFINE_INSN -opt_regexpmatch1 -(VALUE recv) -(VALUE obj) -(VALUE val) -// attr bool leaf = BASIC_OP_UNREDEFINED_P(BOP_MATCH, REGEXP_REDEFINED_OP_FLAG); -{ - val = vm_opt_regexpmatch1(recv, obj); -} - /* optimized regexp match 2 */ DEFINE_INSN opt_regexpmatch2 -(CALL_INFO ci, CALL_CACHE cc) +(CALL_DATA cd) (VALUE obj2, VALUE obj1) (VALUE val) +// attr bool leaf = false; /* match_at() has rb_thread_check_ints() */ +// attr bool zjit_profile = true; { val = vm_opt_regexpmatch2(obj2, obj1); - if (val == Qundef) { + if (UNDEF_P(val)) { CALL_SIMPLE_METHOD(); } } -/* call native compiled method */ +/* call specific function with args */ DEFINE_INSN -opt_call_c_function -(rb_insn_func_t funcptr) +invokebuiltin +(RB_BUILTIN bf) +(...) +(VALUE val) +// attr bool leaf = false; /* anything can happen inside */ +// attr rb_snum_t sp_inc = 1 - bf->argc; +{ + val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc)); +} + +/* call specific function with args (same parameters) */ +DEFINE_INSN +opt_invokebuiltin_delegate +(RB_BUILTIN bf, rb_num_t index) () +(VALUE val) +// attr bool leaf = false; /* anything can happen inside */ +{ + val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index); +} + +/* call specific function with args (same parameters) and leave */ +DEFINE_INSN +opt_invokebuiltin_delegate_leave +(RB_BUILTIN bf, rb_num_t index) () +(VALUE val) // attr bool leaf = false; /* anything can happen inside */ -// attr bool handles_sp = true; { - reg_cfp = (funcptr)(ec, reg_cfp); + val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index); - if (reg_cfp == 0) { - VALUE err = ec->errinfo; - ec->errinfo = Qnil; - THROW_EXCEPTION(err); + /* leave fastpath */ + /* TracePoint/return fallbacks this insn to opt_invokebuiltin_delegate */ + if (vm_pop_frame(ec, GET_CFP(), GET_EP())) { +#if OPT_CALL_THREADED_CODE + rb_ec_thread_ptr(ec)->retval = val; + return 0; +#else + return val; +#endif + } + else { + RESTORE_REGS(); } - - RESTORE_REGS(); - NEXT_INSN(); } /* BLT */ -DEFINE_INSN +DEFINE_INSN_IF(SUPPORT_JOKE) bitblt () () @@ -1446,7 +1772,7 @@ bitblt } /* The Answer to Life, the Universe, and Everything */ -DEFINE_INSN +DEFINE_INSN_IF(SUPPORT_JOKE) answer () () |
