summaryrefslogtreecommitdiff
path: root/insns.def
diff options
context:
space:
mode:
Diffstat (limited to 'insns.def')
-rw-r--r--insns.def882
1 files changed, 587 insertions, 295 deletions
diff --git a/insns.def b/insns.def
index c971026cf6..3ad378081a 100644
--- a/insns.def
+++ b/insns.def
@@ -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);
}
}
@@ -207,64 +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_internal() */
+// 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(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(vm_get_cref(GET_EP()), GET_CFP()), id, val);
+ vm_setclassvariable(GET_ISEQ(), GET_CFP(), id, val, ic);
}
-/* Get constant variable id. If klass is Qnil, constants
+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 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.
@@ -288,25 +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;
{
- struct rb_global_entry *gentry = (void *)entry;
- val = rb_gvar_get(gentry);
+ 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;
{
- struct rb_global_entry *gentry = (void *)entry;
- rb_gvar_set(gentry, val);
+ rb_gvar_set(gid, val);
}
/**********************************************************/
@@ -351,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;
@@ -360,12 +373,22 @@ putspecialobject
/* put string val. string will be copied. */
DEFINE_INSN
-putstring
+dupstring
+(VALUE str)
+()
+(VALUE val)
+{
+ val = rb_ec_str_resurrect(ec, str, false);
+}
+
+/* put chilled string val. string will be copied but frozen in the future. */
+DEFINE_INSN
+dupchilledstring
(VALUE str)
()
(VALUE val)
{
- val = rb_str_resurrect(str);
+ val = rb_ec_str_resurrect(ec, str, true);
}
/* put concatenate strings */
@@ -375,16 +398,17 @@ concatstrings
(...)
(VALUE val)
/* This instruction can concat UTF-8 and binary strings, resulting in
- * Encoding::CompatiblityError. */
+ * 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)
@@ -392,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.
*/
@@ -415,9 +429,7 @@ toregexp
// 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. */
@@ -438,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 */
@@ -477,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
()
@@ -494,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
@@ -505,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
@@ -516,10 +588,11 @@ 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();
}
}
@@ -586,7 +659,7 @@ swap
/* reverse stack top N order. */
DEFINE_INSN
-reverse
+opt_reverse
(rb_num_t n)
(...)
(...)
@@ -604,7 +677,7 @@ reverse
}
/* for stack caching. */
-DEFINE_INSN
+DEFINE_INSN_IF(STACK_CACHING)
reput
()
(..., VALUE val)
@@ -654,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
@@ -696,17 +787,7 @@ checktype
(VALUE val)
(VALUE ret)
{
- ret = (TYPE(val) == (int)type) ? Qtrue : Qfalse;
-}
-
-/* get method reference. */
-DEFINE_INSN
-methodref
-(ID id)
-(VALUE val)
-(VALUE ret)
-{
- ret = rb_obj_method(val, ID2SYM(id));
+ ret = RBOOL(TYPE(val) == (int)type);
}
/**********************************************************/
@@ -714,7 +795,7 @@ methodref
/**********************************************************/
/* 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
@@ -723,16 +804,23 @@ 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();
}
@@ -762,15 +850,45 @@ definesmethod
/* 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 = sp_inc_of_sendish(ci);
+// 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(), ci, blockiseq, false);
- val = vm_sendish(ec, GET_CFP(), ci, cc, bh, vm_search_method_wrap);
+ struct rb_forwarding_call_data adjusted_cd;
+ struct rb_callinfo adjusted_ci;
+
+ VALUE bh = vm_caller_setup_fwd_args(ec, GET_CFP(), cd, blockiseq, 0, &adjusted_cd, &adjusted_ci);
- if (val == Qundef) {
+ 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();
}
@@ -779,52 +897,164 @@ send
/* 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 = sp_inc_of_sendish(ci);
+// 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(), ci, cc, bh, vm_search_method_wrap);
+ val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
+ JIT_EXEC(ec, val);
- if (val == Qundef) {
+ 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;
+{
+ 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
@@ -833,34 +1063,89 @@ 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 = sp_inc_of_sendish(ci);
+// 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(), ci, blockiseq, true);
- val = vm_sendish(ec, GET_CFP(), ci, cc, bh, vm_search_super_method);
+ 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);
+
+ 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 (val == Qundef) {
+ if (UNDEF_P(val)) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -869,20 +1154,19 @@ invokesuper
/* yield(args) */
DEFINE_INSN
invokeblock
-(CALL_INFO ci)
+(CALL_DATA cd)
(...)
(VALUE val)
// attr bool handles_sp = true;
-// attr rb_snum_t sp_inc = sp_inc_of_invokeblock(ci);
+// 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;
{
- static struct rb_call_cache cc = {
- 0, 0, NULL, vm_invokeblock_i,
- };
-
VALUE bh = VM_BLOCK_HANDLER_NONE;
- val = vm_sendish(ec, GET_CFP(), ci, &cc, bh, vm_search_invokeblock);
+ val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
+ JIT_EXEC(ec, val);
- if (val == Qundef) {
+ if (UNDEF_P(val)) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -904,21 +1188,19 @@ leave
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();
}
}
@@ -935,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 */
@@ -968,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);
}
}
@@ -983,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);
}
}
@@ -998,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
@@ -1054,7 +1359,7 @@ opt_case_dispatch
OFFSET dst = vm_case_dispatch(hash, else_offset, key);
if (dst) {
- JUMP(dst);
+ JUMP(dst);
}
}
@@ -1063,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();
}
}
@@ -1080,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();
}
}
@@ -1094,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();
}
}
@@ -1108,16 +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();
}
}
@@ -1125,15 +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_mod. */
+/* 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();
}
}
@@ -1141,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();
}
}
@@ -1159,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();
}
}
@@ -1175,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();
}
}
@@ -1189,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();
}
}
@@ -1203,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();
}
}
@@ -1217,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();
}
}
@@ -1231,17 +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();
}
}
@@ -1249,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();
}
}
@@ -1263,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();
}
}
@@ -1277,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
@@ -1285,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();
}
}
@@ -1296,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();
}
}
@@ -1355,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();
}
}
@@ -1369,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();
}
}
@@ -1383,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();
}
}
@@ -1397,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();
}
}
@@ -1411,66 +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 = false; /* rb_reg_prepare_enc() may rb_raise() that calls rb_funcallv() */
-{
- 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
()
()
@@ -1480,7 +1772,7 @@ bitblt
}
/* The Answer to Life, the Universe, and Everything */
-DEFINE_INSN
+DEFINE_INSN_IF(SUPPORT_JOKE)
answer
()
()