2 insns.def
- YARV instruction definitions
5 created at
: 04/01/01 01:17:55 JST
7 Copyright (C
) 2004-2007 Koichi Sasada
8 Massive rewrite by @shyouhei in
2017.
11 /* Some comments about this file
's contents:
13 - The new format aims to be editable by C editor of your choice;
14 your mileage might vary of course.
16 - Each instructions are in following format:
20 (type operand, type operand, ..)
23 // attr type name contents..
28 - Unlike the old format which was line-oriented, you can now place
29 newlines and comments at liberal positions.
31 - `DEFINE_INSN` is a keyword.
33 - An instruction name must be a valid C identifier.
35 - Operands, pop values, return values are series of either variable
36 declarations, keyword `void`, or keyword `...`. They are much
37 like C function declarations.
39 - Attribute pragmas are optional, and can include arbitrary C
40 expressions. You can write anything there but as of writing,
41 supported attributes are:
43 * sp_inc: Used to dynamically calculate sp increase in
44 `insn_stack_increase`.
46 * handles_sp: If it is true, VM deals with sp in the insn.
47 Default is if the instruction takes ISEQ operand or not.
49 * leaf: indicates that the instruction is "leaf" i.e. it does
50 not introduce new stack frame on top of it.
51 If an instruction handles sp, that can never be a leaf.
53 - Attributes can access operands, but not stack (push/pop) variables.
55 - An instruction's body is a pure C block
, copied verbatimly into
56 the generated C source code.
69 /**********************************************************/
70 /* deal with variables
*/
71 /**********************************************************/
73 /* Get local
variable (pointed by `idx
' and `level').
74 'level' indicates the nesting depth from the current block.
78 (lindex_t idx
, rb_num_t level
)
82 val
= *(vm_get_ep(GET_EP(), level
) - idx
);
83 RB_DEBUG_COUNTER_INC(lvar_get
);
84 (void
)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic
, level
> 0);
87 /* Set a local
variable (pointed to by
'idx') as val.
88 'level' indicates the nesting depth from the current block.
92 (lindex_t idx
, rb_num_t level
)
96 vm_env_write(vm_get_ep(GET_EP(), level
), -(int
)idx
, val
);
97 RB_DEBUG_COUNTER_INC(lvar_set
);
98 (void
)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic
, level
> 0);
101 /* Get a block parameter.
*/
104 (lindex_t idx
, rb_num_t level
)
108 const VALUE
*ep
= vm_get_ep(GET_EP(), level
);
109 VM_ASSERT(VM_ENV_LOCAL_P(ep
));
111 if (!VM_ENV_FLAGS(ep
, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM
)) {
112 val
= rb_vm_bh_to_procval(ec
, VM_ENV_BLOCK_HANDLER(ep
));
113 vm_env_write(ep
, -(int
)idx
, val
);
114 VM_ENV_FLAGS_SET(ep
, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM
);
118 RB_DEBUG_COUNTER_INC(lvar_get
);
119 (void
)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic
, level
> 0);
123 /* Set block parameter.
*/
126 (lindex_t idx
, rb_num_t level
)
130 const VALUE
*ep
= vm_get_ep(GET_EP(), level
);
131 VM_ASSERT(VM_ENV_LOCAL_P(ep
));
133 vm_env_write(ep
, -(int
)idx
, val
);
134 RB_DEBUG_COUNTER_INC(lvar_set
);
135 (void
)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic
, level
> 0);
137 VM_ENV_FLAGS_SET(ep
, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM
);
140 /* Get special proxy object which only responds to `call` method if the block parameter
141 represents a iseq
/ifunc block. Otherwise
, same as `getblockparam`.
145 (lindex_t idx
, rb_num_t level
)
149 const VALUE
*ep
= vm_get_ep(GET_EP(), level
);
150 VM_ASSERT(VM_ENV_LOCAL_P(ep
));
152 if (!VM_ENV_FLAGS(ep
, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM
)) {
153 VALUE block_handler
= VM_ENV_BLOCK_HANDLER(ep
);
156 switch (vm_block_handler_type(block_handler
)) {
157 case block_handler_type_iseq
:
158 case block_handler_type_ifunc
:
159 val
= rb_block_param_proxy
;
161 case block_handler_type_symbol
:
162 val
= rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler
));
163 goto
INSN_LABEL(set
);
164 case block_handler_type_proc
:
165 val
= VM_BH_TO_PROC(block_handler
);
166 goto
INSN_LABEL(set
);
168 VM_UNREACHABLE(getblockparamproxy
);
174 vm_env_write(ep
, -(int
)idx
, val
);
175 VM_ENV_FLAGS_SET(ep
, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM
);
180 RB_DEBUG_COUNTER_INC(lvar_get
);
181 (void
)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic
, level
> 0);
185 /* Get value of special local
variable ($~
, $_
, ..
).
*/
188 (rb_num_t key
, rb_num_t type
)
191 /* `$~
= MatchData.allocate
; $
&` can raise.
*/
192 // attr bool leaf
= (type
== 0) ? true
: false
;
194 val
= vm_getspecial(ec
, GET_LEP(), key
, type
);
197 /* Set value of special local
variable ($~
, $_
, ...
) to obj.
*/
204 lep_svar_set(ec
, GET_LEP(), key
, obj
);
207 /* Get value of instance variable id of self.
*/
213 /* Ractor crashes when it accesses class
/module
-level instances variables.
*/
214 // attr bool leaf
= false
; /* has
IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() */
216 val
= vm_getinstancevariable(GET_ISEQ(), GET_SELF(), id
, ic
);
219 /* Set value of instance variable id of self to val.
*/
225 // attr bool leaf
= false
; /* has
rb_check_frozen_internal() */
227 vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id
, val
, ic
);
230 /* Get value of class variable id of klass as val.
*/
236 /* "class variable access from toplevel" warning can be hooked.
*/
237 // attr bool leaf
= false
; /* has
rb_warning() */
239 rb_control_frame_t
*cfp
= GET_CFP();
240 val
= vm_getclassvariable(GET_ISEQ(), cfp
, id
, ic
);
243 /* Set value of class variable id of klass as val.
*/
249 /* "class variable access from toplevel" warning can be hooked.
*/
250 // attr bool leaf
= false
; /* has
rb_warning() */
252 vm_ensure_not_refinement_module(GET_SELF());
253 vm_setclassvariable(GET_ISEQ(), GET_CFP(), id
, val
, ic
);
261 // attr bool leaf
= false
; /* may autoload or raise
*/
263 val
= rb_vm_opt_getconstant_path(ec
, GET_CFP(), ic
);
266 /* Get constant variable id. If klass is Qnil and allow_nil is Qtrue
, constants
267 are searched in the current scope. Otherwise
, get constant under klass
273 (VALUE klass
, VALUE allow_nil
)
275 /* getconstant can kick autoload
*/
276 // attr bool leaf
= false
; /* has
rb_autoload_load() */
278 val
= vm_get_ev_const(ec
, klass
, id
, allow_nil
== Qtrue
, 0);
281 /* Set constant variable id under cbase class or module.
286 (VALUE val
, VALUE cbase
)
288 /* Assigning an object to a constant is basically a leaf operation.
289 * The problem is
, assigning a Module instance to a constant _names_
290 * that module. Naming involves string manipulations
, which are
292 // attr bool leaf
= false
; /* has
StringValue() */
294 vm_check_if_namespace(cbase
);
295 vm_ensure_not_refinement_module(GET_SELF());
296 rb_const_set(cbase
, id
, val
);
299 /* get global variable id.
*/
305 // attr bool leaf
= false
;
307 val
= rb_gvar_get(gid
);
310 /* set global variable id as val.
*/
316 // attr bool leaf
= false
;
318 rb_gvar_set(gid
, val
);
321 /**********************************************************/
322 /* deal with values
*/
323 /**********************************************************/
325 /* put nil to stack.
*/
346 i.e. Fixnum
, true
, false
, nil
, and so on.
357 /* put special object.
"value_type" is for expansion.
*/
360 (rb_num_t value_type
)
363 // attr bool leaf
= (value_type
== VM_SPECIAL_OBJECT_VMCORE
); /* others may raise when allocating singleton
*/
365 enum vm_special_object_type type
;
367 type
= (enum vm_special_object_type
)value_type
;
368 val
= vm_get_special_object(GET_EP(), type
);
371 /* put string val. string will be copied.
*/
378 val
= rb_ec_str_resurrect(ec
, str
, false
);
381 /* put chilled string val. string will be copied but frozen in the future.
*/
388 val
= rb_ec_str_resurrect(ec
, str
, true
);
391 /* put concatenate strings
*/
397 /* This instruction can concat UTF
-8 and binary strings
, resulting in
398 * Encoding
::CompatibilityError.
*/
399 // attr bool leaf
= false
; /* has
rb_enc_cr_str_buf_cat() */
400 // attr rb_snum_t sp_inc
= 1 - (rb_snum_t
)num
;
402 val
= rb_str_concat_literals(num
, STACK_ADDR_FROM_TOP(num
));
405 /* Convert the result to string if not already a string.
406 This is used as a backup if to_s does not return a string.
*/
410 (VALUE val
, VALUE str
)
413 val
= rb_obj_as_string_result(str
, val
);
416 /* compile str to Regexp and push it.
417 opt is the option for the Regexp.
421 (rb_num_t opt
, rb_num_t cnt
)
424 /* This instruction can raise RegexpError
, thus can call
425 * RegexpError#initialize
*/
426 // attr bool leaf
= false
;
427 // attr rb_snum_t sp_inc
= 1 - (rb_snum_t
)cnt
;
429 const VALUE ary
= rb_ary_tmp_new_from_values(0, cnt
, STACK_ADDR_FROM_TOP(cnt
));
430 val
= rb_reg_new_ary(ary
, (int
)opt
);
434 /* intern str to Symbol and push it.
*/
441 sym
= rb_str_intern(str
);
444 /* put new array initialized with num values on the stack.
*/
450 // attr rb_snum_t sp_inc
= 1 - (rb_snum_t
)num
;
452 val
= rb_ec_ary_new_from_values(ec
, num
, STACK_ADDR_FROM_TOP(num
));
455 /* put new array initialized with num values on the stack. There
456 should be at least one element on the stack
, and the top element
457 should be a hash. If the top element is empty
, it is not
458 included in the array.
465 // attr rb_snum_t sp_inc
= 1 - (rb_snum_t
)num
;
467 if (RHASH_EMPTY_P(*STACK_ADDR_FROM_TOP(1))) {
468 val = rb_ary_new4(num-1, STACK_ADDR_FROM_TOP(num));
471 val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
475 /* push hash onto array unless the hash is empty (as empty keyword
476 splats should be ignored).
481 (VALUE ary, VALUE hash)
484 if (!RHASH_EMPTY_P(hash)) {
485 rb_ary_push(ary, hash);
496 RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
497 val = rb_ary_resurrect(ary);
507 RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1);
508 val = rb_hash_resurrect(hash);
511 /* if TOS is an array expand, expand it to num objects.
512 if the number of the array is less than num, push nils to fill.
513 if it is greater than num, exceeding elements are dropped.
514 unless TOS is an array, push num - 1 nils.
515 if flags is non-zero, push the array of the rest elements.
516 flag: 0x01 - rest args array
517 flag: 0x02 - for postarg
518 flag: 0x04 - reverse?
522 (rb_num_t num, rb_num_t flag)
525 // attr bool handles_sp = true;
526 // attr bool leaf = false; /* has rb_check_array_type() */
527 // attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
529 vm_expandarray(GET_CFP(), ary, num, (int)flag);
532 /* concat two arrays, without modifying first array.
533 * attempts to convert both objects to arrays using to_a.
538 (VALUE ary1, VALUE ary2)
540 // attr bool leaf = false; /* has rb_check_array_type() */
542 ary = vm_concat_array(ary1, ary2);
545 /* concat second array to first array.
546 * first argument must already be an array.
547 * attempts to convert second object to array using to_a.
552 (VALUE ary1, VALUE ary2)
554 // attr bool leaf = false; /* has rb_check_array_type() */
556 ary = vm_concat_to_array(ary1, ary2);
559 /* push given number of objects to array directly before. */
565 // attr rb_snum_t sp_inc = -(rb_snum_t)num;
567 const VALUE *objp = STACK_ADDR_FROM_TOP(num);
568 val = rb_ary_cat(*(objp-1), objp, num);
571 /* call to_a on array ary to splat */
577 // attr bool leaf = false; /* has rb_check_array_type() */
579 obj = vm_splat_array(flag, ary);
582 /* call to_hash on hash to keyword splat before converting block */
586 (VALUE hash, VALUE block)
587 (VALUE obj, VALUE block)
588 // attr bool leaf = false; /* has rb_to_hash_type() */
594 obj = rb_to_hash_type(hash);
598 /* put new Hash from n elements. n must be an even number. */
604 // attr bool leaf = false; /* has rb_hash_key_str() */
605 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
607 RUBY_DTRACE_CREATE_HOOK(HASH, num);
610 val = rb_hash_new_with_size(num / 2);
611 rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
618 /* put new Range object.(Range.new(low, high, flag)) */
622 (VALUE low, VALUE high)
624 /* rb_range_new() exercises "bad value for range" check. */
625 // attr bool leaf = false; /* see also: range.c:range_init() */
627 val = rb_range_new(low, high, (int)flag);
630 /**********************************************************/
631 /* deal with stack operation */
632 /**********************************************************/
634 /* pop from stack. */
645 /* duplicate stack top. */
650 (VALUE val1, VALUE val2)
655 /* duplicate stack top n elements */
661 // attr rb_snum_t sp_inc = n;
663 void *dst = GET_SP();
664 void *src = STACK_ADDR_FROM_TOP(n);
666 MEMCPY(dst, src, VALUE, n);
669 /* swap top 2 vals */
673 (VALUE val, VALUE obj)
674 (VALUE obj, VALUE val)
679 /* reverse stack top N order. */
685 // attr rb_snum_t sp_inc = 0;
688 VALUE *sp = STACK_ADDR_FROM_TOP(n);
690 for (i=0; i<n/2; i++) {
698 /* for stack caching. */
699 DEFINE_INSN_IF(STACK_CACHING)
704 // attr rb_snum_t sp_inc = 0;
709 /* get nth stack value from stack top */
715 // attr rb_snum_t sp_inc = 1;
720 /* set Nth stack entry to stack top */
726 // attr rb_snum_t sp_inc = 0;
731 /* empty current stack */
737 // attr rb_snum_t sp_inc = -(rb_snum_t)n;
742 /**********************************************************/
743 /* deal with setting */
744 /**********************************************************/
749 (rb_num_t op_type, VALUE obj, VALUE pushval)
752 // attr bool leaf = leafness_of_defined(op_type);
755 if (vm_defined(ec, GET_CFP(), op_type, obj, v)) {
763 (ID id, IVC ic, VALUE pushval)
766 // attr bool leaf = false;
769 if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) {
774 /* check `target' matches `pattern'.
775 `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
776 VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
777 VM_CHECKMATCH_TYPE_CASE: check `patten === target'.
778 VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_of?(Module) && pattern === target'.
779 if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns.
784 (VALUE target, VALUE pattern)
786 // attr bool leaf = leafness_of_checkmatch(flag);
788 result = vm_check_match(ec, target, pattern, flag);
791 /* check keywords are specified or not. */
794 (lindex_t kw_bits_index, lindex_t keyword_index)
798 ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP());
801 /* check if val is type. */
808 ret = RBOOL(TYPE(val) == (int)type);
811 /**********************************************************/
812 /* deal with control flow 1: class/module */
813 /**********************************************************/
815 /* enter class definition scope. if super is Qfalse, and class
816 "klass" is defined, it's redefined. Otherwise, define "klass" class.
820 (ID id, ISEQ class_iseq, rb_num_t flags)
821 (VALUE cbase, VALUE super)
824 VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
826 rb_iseq_check(class_iseq);
829 vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
831 (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE),
832 ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(),
833 ISEQ_BODY(class_iseq)->local_table_size,
834 ISEQ_BODY(class_iseq)->stack_max);
845 vm_define_method(ec, Qnil, id, (VALUE)iseq, FALSE);
854 vm_define_method(ec, obj, id, (VALUE)iseq, TRUE);
857 /**********************************************************/
858 /* deal with control flow 2: method/iterator */
859 /**********************************************************/
864 (CALL_DATA cd, ISEQ blockiseq)
867 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
868 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
870 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
871 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
880 /* Invoke method without block */
882 opt_send_without_block
886 // attr bool handles_sp = true;
887 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
888 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
890 VALUE bh = VM_BLOCK_HANDLER_NONE;
891 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
900 /* Convert object to string using to_s or equivalent. */
906 // attr bool leaf = false;
908 val = vm_objtostring(GET_ISEQ(), recv, cd);
911 CALL_SIMPLE_METHOD();
917 (VALUE str, CALL_DATA cd)
921 val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze);
924 PUSH(rb_str_resurrect(str));
925 CALL_SIMPLE_METHOD();
936 val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
939 CALL_SIMPLE_METHOD();
945 (VALUE str, CALL_DATA cd)
949 val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus);
952 PUSH(rb_str_resurrect(str));
953 CALL_SIMPLE_METHOD();
959 (rb_num_t num, ID method)
962 /* This instruction typically has no funcalls. But it compares array
963 * contents each other by nature. That part could call methods when
964 * necessary. No way to detect such method calls beforehand. We
965 * cannot but mark it being not leaf. */
966 // attr bool leaf = false; /* has rb_funcall() */
967 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
968 // attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)num;
972 val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num));
975 val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
978 val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
981 val = rb_vm_opt_newarray_pack(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0));
984 rb_bug("unreachable");
988 /* super(args) # args.size => num */
991 (CALL_DATA cd, ISEQ blockiseq)
994 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
995 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
997 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
998 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
1013 // attr bool handles_sp = true;
1014 // attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci);
1015 // attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci);
1017 VALUE bh = VM_BLOCK_HANDLER_NONE;
1018 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
1027 /* return from this scope. */
1033 /* This is super surprising but when leaving from a frame, we check
1034 * for interrupts. If any, that should be executed on top of the
1035 * current execution context. This is a method call. */
1036 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
1037 // attr bool handles_sp = true;
1039 if (OPT_CHECKED_RUN) {
1040 const VALUE *const bp = vm_base_ptr(GET_CFP());
1041 if (GET_SP() != bp) {
1042 vm_stack_consistency_error(ec, GET_CFP(), bp);
1046 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
1047 #if OPT_CALL_THREADED_CODE
1048 rb_ec_thread_ptr(ec)->retval = val;
1059 /**********************************************************/
1060 /* deal with control flow 3: exception */
1061 /**********************************************************/
1066 (rb_num_t throw_state)
1069 /* Same discussion as leave. */
1070 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
1072 val = vm_throw(ec, GET_CFP(), throw_state, throwobj);
1073 THROW_EXCEPTION(val);
1077 /**********************************************************/
1078 /* deal with control flow 4: local jump */
1079 /**********************************************************/
1081 /* set PC to (PC + dst). */
1087 /* Same discussion as leave. */
1088 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1090 RUBY_VM_CHECK_INTS(ec);
1094 /* if val is not false or nil, set PC to (PC + dst). */
1100 /* Same discussion as jump. */
1101 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1104 RUBY_VM_CHECK_INTS(ec);
1109 /* if val is false or nil, set PC to (PC + dst). */
1115 /* Same discussion as jump. */
1116 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1119 RUBY_VM_CHECK_INTS(ec);
1124 /* if val is nil, set PC to (PC + dst). */
1130 /* Same discussion as jump. */
1131 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1134 RUBY_VM_CHECK_INTS(ec);
1139 /**********************************************************/
1141 /**********************************************************/
1143 /* run iseq only once */
1146 (ISEQ iseq, ISE ise)
1150 val = vm_once_dispatch(ec, iseq, ise);
1153 /* case dispatcher, jump by table if possible */
1156 (CDHASH hash, OFFSET else_offset)
1159 // attr rb_snum_t sp_inc = -1;
1161 OFFSET dst = vm_case_dispatch(hash, else_offset, key);
1168 /** simple functions */
1170 /* optimized X+Y. */
1174 (VALUE recv, VALUE obj)
1177 val = vm_opt_plus(recv, obj);
1180 CALL_SIMPLE_METHOD();
1184 /* optimized X-Y. */
1188 (VALUE recv, VALUE obj)
1191 val = vm_opt_minus(recv, obj);
1194 CALL_SIMPLE_METHOD();
1198 /* optimized X*Y. */
1202 (VALUE recv, VALUE obj)
1205 val = vm_opt_mult(recv, obj);
1208 CALL_SIMPLE_METHOD();
1212 /* optimized X/Y. */
1216 (VALUE recv, VALUE obj)
1218 /* In case of division by zero, it raises. Thus
1219 * ZeroDivisionError#initialize is called. */
1220 // attr bool leaf = false;
1222 val = vm_opt_div(recv, obj);
1225 CALL_SIMPLE_METHOD();
1229 /* optimized X%Y. */
1233 (VALUE recv, VALUE obj)
1235 /* Same discussion as opt_div. */
1236 // attr bool leaf = false;
1238 val = vm_opt_mod(recv, obj);
1241 CALL_SIMPLE_METHOD();
1245 /* optimized X==Y. */
1249 (VALUE recv, VALUE obj)
1252 val = opt_equality(GET_ISEQ(), recv, obj, cd);
1255 CALL_SIMPLE_METHOD();
1259 /* optimized X!=Y. */
1262 (CALL_DATA cd_eq, CALL_DATA cd)
1263 (VALUE recv, VALUE obj)
1266 val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
1269 CALL_SIMPLE_METHOD();
1273 /* optimized X<Y. */
1277 (VALUE recv, VALUE obj)
1280 val = vm_opt_lt(recv, obj);
1283 CALL_SIMPLE_METHOD();
1287 /* optimized X<=Y. */
1291 (VALUE recv, VALUE obj)
1294 val = vm_opt_le(recv, obj);
1297 CALL_SIMPLE_METHOD();
1301 /* optimized X>Y. */
1305 (VALUE recv, VALUE obj)
1308 val = vm_opt_gt(recv, obj);
1311 CALL_SIMPLE_METHOD();
1315 /* optimized X>=Y. */
1319 (VALUE recv, VALUE obj)
1322 val = vm_opt_ge(recv, obj);
1325 CALL_SIMPLE_METHOD();
1333 (VALUE recv, VALUE obj)
1335 /* This instruction can append an integer, as a codepoint, into a
1336 * string. Then what happens if that codepoint does not exist in the
1337 * string's encoding? Of course an exception. That's not a leaf. */
1338 // attr bool leaf = false; /* has "invalid codepoint" exception */
1340 val = vm_opt_ltlt(recv, obj);
1343 CALL_SIMPLE_METHOD();
1347 /* optimized X&Y. */
1351 (VALUE recv, VALUE obj)
1354 val = vm_opt_and(recv, obj);
1357 CALL_SIMPLE_METHOD();
1361 /* optimized X|Y. */
1365 (VALUE recv, VALUE obj)
1368 val = vm_opt_or(recv, obj);
1371 CALL_SIMPLE_METHOD();
1379 (VALUE recv, VALUE obj)
1381 /* This is complicated. In case of hash, vm_opt_aref() resorts to
1382 * rb_hash_aref(). If `recv` has no `obj`, this function then yields
1383 * default_proc. This is a method call. So opt_aref is
1384 * (surprisingly) not leaf. */
1385 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1387 val = vm_opt_aref(recv, obj);
1390 CALL_SIMPLE_METHOD();
1394 /* recv[obj] = set */
1398 (VALUE recv, VALUE obj, VALUE set)
1400 /* This is another story than opt_aref. When vm_opt_aset() resorts
1401 * to rb_hash_aset(), which should call #hash for `obj`. */
1402 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1404 val = vm_opt_aset(recv, obj, set);
1407 CALL_SIMPLE_METHOD();
1411 /* recv[str] = set */
1414 (VALUE key, CALL_DATA cd)
1415 (VALUE recv, VALUE val)
1417 /* Same discussion as opt_aset. */
1418 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1420 VALUE tmp = vm_opt_aset_with(recv, key, val);
1422 if (!UNDEF_P(tmp)) {
1426 TOPN(0) = rb_str_resurrect(key);
1428 CALL_SIMPLE_METHOD();
1435 (VALUE key, CALL_DATA cd)
1438 /* Same discussion as opt_aref. */
1439 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1441 val = vm_opt_aref_with(recv, key);
1444 PUSH(rb_str_resurrect(key));
1445 CALL_SIMPLE_METHOD();
1449 /* optimized length */
1456 val = vm_opt_length(recv, BOP_LENGTH);
1459 CALL_SIMPLE_METHOD();
1463 /* optimized size */
1470 val = vm_opt_length(recv, BOP_SIZE);
1473 CALL_SIMPLE_METHOD();
1477 /* optimized empty? */
1484 val = vm_opt_empty_p(recv);
1487 CALL_SIMPLE_METHOD();
1491 /* optimized succ */
1498 val = vm_opt_succ(recv);
1501 CALL_SIMPLE_METHOD();
1512 val = vm_opt_not(GET_ISEQ(), cd, recv);
1515 CALL_SIMPLE_METHOD();
1519 /* optimized regexp match 2 */
1523 (VALUE obj2, VALUE obj1)
1525 // attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
1527 val = vm_opt_regexpmatch2(obj2, obj1);
1530 CALL_SIMPLE_METHOD();
1534 /* call specific function with args */
1540 // attr bool leaf = false; /* anything can happen inside */
1541 // attr rb_snum_t sp_inc = 1 - bf->argc;
1543 val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
1546 /* call specific function with args (same parameters) */
1548 opt_invokebuiltin_delegate
1549 (RB_BUILTIN bf, rb_num_t index)
1552 // attr bool leaf = false; /* anything can happen inside */
1554 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1557 /* call specific function with args (same parameters) and leave */
1559 opt_invokebuiltin_delegate_leave
1560 (RB_BUILTIN bf, rb_num_t index)
1563 // attr bool leaf = false; /* anything can happen inside */
1565 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1567 /* leave fastpath */
1568 /* TracePoint/return fallbacks this insn to opt_invokebuiltin_delegate */
1569 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
1570 #if OPT_CALL_THREADED_CODE
1571 rb_ec_thread_ptr(ec)->retval = val;
1583 DEFINE_INSN_IF(SUPPORT_JOKE)
1589 ret = rb_str_new2("a bit of bacon, lettuce and tomato");
1592 /* The Answer to Life, the Universe, and Everything */
1593 DEFINE_INSN_IF(SUPPORT_JOKE)