Tempfile document updated.
[ruby.git] / insns.def
blob3858ad3c6d66b4475ebddca9c70e529557fd0a8c
1 /* -*- C -*-
2 insns.def - YARV instruction definitions
4 $Author: $
5 created at: 04/01/01 01:17:55 JST
7 Copyright (C) 2004-2007 Koichi Sasada
8 Massive rewrite by @shyouhei in 2017.
9 */
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:
18 DEFINE_INSN
19 instruction_name
20 (type operand, type operand, ..)
21 (pop_values, ..)
22 (return values ..)
23 // attr type name contents..
25 .. // insn body
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.
59 /* nop */
60 DEFINE_INSN
61 nop
66 /* none */
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.
76 DEFINE_INSN
77 getlocal
78 (lindex_t idx, rb_num_t level)
80 (VALUE val)
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.
90 DEFINE_INSN
91 setlocal
92 (lindex_t idx, rb_num_t level)
93 (VALUE val)
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. */
102 DEFINE_INSN
103 getblockparam
104 (lindex_t idx, rb_num_t level)
106 (VALUE val)
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);
116 else {
117 val = *(ep - idx);
118 RB_DEBUG_COUNTER_INC(lvar_get);
119 (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0);
123 /* Set block parameter. */
124 DEFINE_INSN
125 setblockparam
126 (lindex_t idx, rb_num_t level)
127 (VALUE val)
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`.
143 DEFINE_INSN
144 getblockparamproxy
145 (lindex_t idx, rb_num_t level)
147 (VALUE val)
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);
155 if (block_handler) {
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;
160 break;
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);
167 default:
168 VM_UNREACHABLE(getblockparamproxy);
171 else {
172 val = Qnil;
173 INSN_LABEL(set):
174 vm_env_write(ep, -(int)idx, val);
175 VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM);
178 else {
179 val = *(ep - idx);
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 ($~, $_, ..). */
186 DEFINE_INSN
187 getspecial
188 (rb_num_t key, rb_num_t type)
190 (VALUE val)
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. */
198 DEFINE_INSN
199 setspecial
200 (rb_num_t key)
201 (VALUE obj)
204 lep_svar_set(ec, GET_LEP(), key, obj);
207 /* Get value of instance variable id of self. */
208 DEFINE_INSN
209 getinstancevariable
210 (ID id, IVC ic)
212 (VALUE val)
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. */
220 DEFINE_INSN
221 setinstancevariable
222 (ID id, IVC ic)
223 (VALUE 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. */
231 DEFINE_INSN
232 getclassvariable
233 (ID id, ICVARC ic)
235 (VALUE 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. */
244 DEFINE_INSN
245 setclassvariable
246 (ID id, ICVARC ic)
247 (VALUE 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);
256 DEFINE_INSN
257 opt_getconstant_path
258 (IC ic)
260 (VALUE val)
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
268 class or module.
270 DEFINE_INSN
271 getconstant
272 (ID id)
273 (VALUE klass, VALUE allow_nil)
274 (VALUE val)
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.
283 DEFINE_INSN
284 setconstant
285 (ID id)
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
291 * method calls. */
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. */
300 DEFINE_INSN
301 getglobal
302 (ID gid)
304 (VALUE val)
305 // attr bool leaf = false;
307 val = rb_gvar_get(gid);
310 /* set global variable id as val. */
311 DEFINE_INSN
312 setglobal
313 (ID gid)
314 (VALUE val)
316 // attr bool leaf = false;
318 rb_gvar_set(gid, val);
321 /**********************************************************/
322 /* deal with values */
323 /**********************************************************/
325 /* put nil to stack. */
326 DEFINE_INSN
327 putnil
330 (VALUE val)
332 val = Qnil;
335 /* put self. */
336 DEFINE_INSN
337 putself
340 (VALUE val)
342 val = GET_SELF();
345 /* put some object.
346 i.e. Fixnum, true, false, nil, and so on.
348 DEFINE_INSN
349 putobject
350 (VALUE val)
352 (VALUE val)
354 /* */
357 /* put special object. "value_type" is for expansion. */
358 DEFINE_INSN
359 putspecialobject
360 (rb_num_t value_type)
362 (VALUE val)
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. */
372 DEFINE_INSN
373 putstring
374 (VALUE str)
376 (VALUE val)
378 val = rb_ec_str_resurrect(ec, str, false);
381 /* put chilled string val. string will be copied but frozen in the future. */
382 DEFINE_INSN
383 putchilledstring
384 (VALUE str)
386 (VALUE val)
388 val = rb_ec_str_resurrect(ec, str, true);
391 /* put concatenate strings */
392 DEFINE_INSN
393 concatstrings
394 (rb_num_t num)
395 (...)
396 (VALUE val)
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. */
407 DEFINE_INSN
408 anytostring
410 (VALUE val, VALUE str)
411 (VALUE val)
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.
419 DEFINE_INSN
420 toregexp
421 (rb_num_t opt, rb_num_t cnt)
422 (...)
423 (VALUE val)
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);
431 rb_ary_clear(ary);
434 /* intern str to Symbol and push it. */
435 DEFINE_INSN
436 intern
438 (VALUE str)
439 (VALUE sym)
441 sym = rb_str_intern(str);
444 /* put new array initialized with num values on the stack. */
445 DEFINE_INSN
446 newarray
447 (rb_num_t num)
448 (...)
449 (VALUE val)
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.
460 DEFINE_INSN
461 newarraykwsplat
462 (rb_num_t num)
463 (...)
464 (VALUE val)
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));
470 else {
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).
478 DEFINE_INSN
479 pushtoarraykwsplat
481 (VALUE ary, VALUE hash)
482 (VALUE ary)
484 if (!RHASH_EMPTY_P(hash)) {
485 rb_ary_push(ary, hash);
489 /* dup array */
490 DEFINE_INSN
491 duparray
492 (VALUE ary)
494 (VALUE val)
496 RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
497 val = rb_ary_resurrect(ary);
500 /* dup hash */
501 DEFINE_INSN
502 duphash
503 (VALUE hash)
505 (VALUE val)
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?
520 DEFINE_INSN
521 expandarray
522 (rb_num_t num, rb_num_t flag)
523 (..., VALUE ary)
524 (...)
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.
535 DEFINE_INSN
536 concatarray
538 (VALUE ary1, VALUE ary2)
539 (VALUE ary)
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.
549 DEFINE_INSN
550 concattoarray
552 (VALUE ary1, VALUE ary2)
553 (VALUE ary)
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. */
560 DEFINE_INSN
561 pushtoarray
562 (rb_num_t num)
563 (...)
564 (VALUE val)
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 */
572 DEFINE_INSN
573 splatarray
574 (VALUE flag)
575 (VALUE ary)
576 (VALUE obj)
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 */
583 DEFINE_INSN
584 splatkw
586 (VALUE hash, VALUE block)
587 (VALUE obj, VALUE block)
588 // attr bool leaf = false; /* has rb_to_hash_type() */
590 if (NIL_P(hash)) {
591 obj = Qnil;
593 else {
594 obj = rb_to_hash_type(hash);
598 /* put new Hash from n elements. n must be an even number. */
599 DEFINE_INSN
600 newhash
601 (rb_num_t num)
602 (...)
603 (VALUE val)
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);
609 if (num) {
610 val = rb_hash_new_with_size(num / 2);
611 rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
613 else {
614 val = rb_hash_new();
618 /* put new Range object.(Range.new(low, high, flag)) */
619 DEFINE_INSN
620 newrange
621 (rb_num_t flag)
622 (VALUE low, VALUE high)
623 (VALUE val)
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. */
635 DEFINE_INSN
638 (VALUE val)
641 (void)val;
642 /* none */
645 /* duplicate stack top. */
646 DEFINE_INSN
649 (VALUE val)
650 (VALUE val1, VALUE val2)
652 val1 = val2 = val;
655 /* duplicate stack top n elements */
656 DEFINE_INSN
657 dupn
658 (rb_num_t n)
659 (...)
660 (...)
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 */
670 DEFINE_INSN
671 swap
673 (VALUE val, VALUE obj)
674 (VALUE obj, VALUE val)
676 /* none */
679 /* reverse stack top N order. */
680 DEFINE_INSN
681 opt_reverse
682 (rb_num_t n)
683 (...)
684 (...)
685 // attr rb_snum_t sp_inc = 0;
687 rb_num_t i;
688 VALUE *sp = STACK_ADDR_FROM_TOP(n);
690 for (i=0; i<n/2; i++) {
691 VALUE v0 = sp[i];
692 VALUE v1 = TOPN(i);
693 sp[i] = v1;
694 TOPN(i) = v0;
698 /* for stack caching. */
699 DEFINE_INSN_IF(STACK_CACHING)
700 reput
702 (..., VALUE val)
703 (VALUE val)
704 // attr rb_snum_t sp_inc = 0;
706 /* none */
709 /* get nth stack value from stack top */
710 DEFINE_INSN
711 topn
712 (rb_num_t n)
713 (...)
714 (VALUE val)
715 // attr rb_snum_t sp_inc = 1;
717 val = TOPN(n);
720 /* set Nth stack entry to stack top */
721 DEFINE_INSN
722 setn
723 (rb_num_t n)
724 (..., VALUE val)
725 (VALUE val)
726 // attr rb_snum_t sp_inc = 0;
728 TOPN(n) = val;
731 /* empty current stack */
732 DEFINE_INSN
733 adjuststack
734 (rb_num_t n)
735 (...)
736 (...)
737 // attr rb_snum_t sp_inc = -(rb_snum_t)n;
739 /* none */
742 /**********************************************************/
743 /* deal with setting */
744 /**********************************************************/
746 /* defined? */
747 DEFINE_INSN
748 defined
749 (rb_num_t op_type, VALUE obj, VALUE pushval)
750 (VALUE v)
751 (VALUE val)
752 // attr bool leaf = leafness_of_defined(op_type);
754 val = Qnil;
755 if (vm_defined(ec, GET_CFP(), op_type, obj, v)) {
756 val = pushval;
760 /* defined?(@foo) */
761 DEFINE_INSN
762 definedivar
763 (ID id, IVC ic, VALUE pushval)
765 (VALUE val)
766 // attr bool leaf = false;
768 val = Qnil;
769 if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) {
770 val = pushval;
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.
781 DEFINE_INSN
782 checkmatch
783 (rb_num_t flag)
784 (VALUE target, VALUE pattern)
785 (VALUE result)
786 // attr bool leaf = leafness_of_checkmatch(flag);
788 result = vm_check_match(ec, target, pattern, flag);
791 /* check keywords are specified or not. */
792 DEFINE_INSN
793 checkkeyword
794 (lindex_t kw_bits_index, lindex_t keyword_index)
796 (VALUE ret)
798 ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP());
801 /* check if val is type. */
802 DEFINE_INSN
803 checktype
804 (rb_num_t type)
805 (VALUE val)
806 (VALUE ret)
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.
818 DEFINE_INSN
819 defineclass
820 (ID id, ISEQ class_iseq, rb_num_t flags)
821 (VALUE cbase, VALUE super)
822 (VALUE val)
824 VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
826 rb_iseq_check(class_iseq);
828 /* enter scope */
829 vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
830 GET_BLOCK_HANDLER(),
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);
835 RESTORE_REGS();
836 NEXT_INSN();
839 DEFINE_INSN
840 definemethod
841 (ID id, ISEQ iseq)
845 vm_define_method(ec, Qnil, id, (VALUE)iseq, FALSE);
848 DEFINE_INSN
849 definesmethod
850 (ID id, ISEQ iseq)
851 (VALUE obj)
854 vm_define_method(ec, obj, id, (VALUE)iseq, TRUE);
857 /**********************************************************/
858 /* deal with control flow 2: method/iterator */
859 /**********************************************************/
861 /* invoke method. */
862 DEFINE_INSN
863 send
864 (CALL_DATA cd, ISEQ blockiseq)
865 (...)
866 (VALUE val)
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);
872 JIT_EXEC(ec, val);
874 if (UNDEF_P(val)) {
875 RESTORE_REGS();
876 NEXT_INSN();
880 /* Invoke method without block */
881 DEFINE_INSN
882 opt_send_without_block
883 (CALL_DATA cd)
884 (...)
885 (VALUE val)
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);
892 JIT_EXEC(ec, val);
894 if (UNDEF_P(val)) {
895 RESTORE_REGS();
896 NEXT_INSN();
900 /* Convert object to string using to_s or equivalent. */
901 DEFINE_INSN
902 objtostring
903 (CALL_DATA cd)
904 (VALUE recv)
905 (VALUE val)
906 // attr bool leaf = false;
908 val = vm_objtostring(GET_ISEQ(), recv, cd);
910 if (UNDEF_P(val)) {
911 CALL_SIMPLE_METHOD();
915 DEFINE_INSN
916 opt_str_freeze
917 (VALUE str, CALL_DATA cd)
919 (VALUE val)
921 val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze);
923 if (UNDEF_P(val)) {
924 PUSH(rb_str_resurrect(str));
925 CALL_SIMPLE_METHOD();
929 /* optimized nil? */
930 DEFINE_INSN
931 opt_nil_p
932 (CALL_DATA cd)
933 (VALUE recv)
934 (VALUE val)
936 val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
938 if (UNDEF_P(val)) {
939 CALL_SIMPLE_METHOD();
943 DEFINE_INSN
944 opt_str_uminus
945 (VALUE str, CALL_DATA cd)
947 (VALUE val)
949 val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus);
951 if (UNDEF_P(val)) {
952 PUSH(rb_str_resurrect(str));
953 CALL_SIMPLE_METHOD();
957 DEFINE_INSN
958 opt_newarray_send
959 (rb_num_t num, ID method)
960 (...)
961 (VALUE val)
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;
970 switch(method) {
971 case idHash:
972 val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num));
973 break;
974 case idMin:
975 val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
976 break;
977 case idMax:
978 val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
979 break;
980 case idPack:
981 val = rb_vm_opt_newarray_pack(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0));
982 break;
983 default:
984 rb_bug("unreachable");
988 /* super(args) # args.size => num */
989 DEFINE_INSN
990 invokesuper
991 (CALL_DATA cd, ISEQ blockiseq)
992 (...)
993 (VALUE val)
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);
999 JIT_EXEC(ec, val);
1001 if (UNDEF_P(val)) {
1002 RESTORE_REGS();
1003 NEXT_INSN();
1007 /* yield(args) */
1008 DEFINE_INSN
1009 invokeblock
1010 (CALL_DATA cd)
1011 (...)
1012 (VALUE val)
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);
1019 JIT_EXEC(ec, val);
1021 if (UNDEF_P(val)) {
1022 RESTORE_REGS();
1023 NEXT_INSN();
1027 /* return from this scope. */
1028 DEFINE_INSN
1029 leave
1031 (VALUE val)
1032 (VALUE val)
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;
1049 return 0;
1050 #else
1051 return val;
1052 #endif
1054 else {
1055 RESTORE_REGS();
1059 /**********************************************************/
1060 /* deal with control flow 3: exception */
1061 /**********************************************************/
1063 /* longjump */
1064 DEFINE_INSN
1065 throw
1066 (rb_num_t throw_state)
1067 (VALUE throwobj)
1068 (VALUE val)
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);
1074 /* unreachable */
1077 /**********************************************************/
1078 /* deal with control flow 4: local jump */
1079 /**********************************************************/
1081 /* set PC to (PC + dst). */
1082 DEFINE_INSN
1083 jump
1084 (OFFSET 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);
1091 JUMP(dst);
1094 /* if val is not false or nil, set PC to (PC + dst). */
1095 DEFINE_INSN
1096 branchif
1097 (OFFSET dst)
1098 (VALUE val)
1100 /* Same discussion as jump. */
1101 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1103 if (RTEST(val)) {
1104 RUBY_VM_CHECK_INTS(ec);
1105 JUMP(dst);
1109 /* if val is false or nil, set PC to (PC + dst). */
1110 DEFINE_INSN
1111 branchunless
1112 (OFFSET dst)
1113 (VALUE val)
1115 /* Same discussion as jump. */
1116 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1118 if (!RTEST(val)) {
1119 RUBY_VM_CHECK_INTS(ec);
1120 JUMP(dst);
1124 /* if val is nil, set PC to (PC + dst). */
1125 DEFINE_INSN
1126 branchnil
1127 (OFFSET dst)
1128 (VALUE val)
1130 /* Same discussion as jump. */
1131 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1133 if (NIL_P(val)) {
1134 RUBY_VM_CHECK_INTS(ec);
1135 JUMP(dst);
1139 /**********************************************************/
1140 /* for optimize */
1141 /**********************************************************/
1143 /* run iseq only once */
1144 DEFINE_INSN
1145 once
1146 (ISEQ iseq, ISE ise)
1148 (VALUE val)
1150 val = vm_once_dispatch(ec, iseq, ise);
1153 /* case dispatcher, jump by table if possible */
1154 DEFINE_INSN
1155 opt_case_dispatch
1156 (CDHASH hash, OFFSET else_offset)
1157 (..., VALUE key)
1159 // attr rb_snum_t sp_inc = -1;
1161 OFFSET dst = vm_case_dispatch(hash, else_offset, key);
1163 if (dst) {
1164 JUMP(dst);
1168 /** simple functions */
1170 /* optimized X+Y. */
1171 DEFINE_INSN
1172 opt_plus
1173 (CALL_DATA cd)
1174 (VALUE recv, VALUE obj)
1175 (VALUE val)
1177 val = vm_opt_plus(recv, obj);
1179 if (UNDEF_P(val)) {
1180 CALL_SIMPLE_METHOD();
1184 /* optimized X-Y. */
1185 DEFINE_INSN
1186 opt_minus
1187 (CALL_DATA cd)
1188 (VALUE recv, VALUE obj)
1189 (VALUE val)
1191 val = vm_opt_minus(recv, obj);
1193 if (UNDEF_P(val)) {
1194 CALL_SIMPLE_METHOD();
1198 /* optimized X*Y. */
1199 DEFINE_INSN
1200 opt_mult
1201 (CALL_DATA cd)
1202 (VALUE recv, VALUE obj)
1203 (VALUE val)
1205 val = vm_opt_mult(recv, obj);
1207 if (UNDEF_P(val)) {
1208 CALL_SIMPLE_METHOD();
1212 /* optimized X/Y. */
1213 DEFINE_INSN
1214 opt_div
1215 (CALL_DATA cd)
1216 (VALUE recv, VALUE obj)
1217 (VALUE val)
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);
1224 if (UNDEF_P(val)) {
1225 CALL_SIMPLE_METHOD();
1229 /* optimized X%Y. */
1230 DEFINE_INSN
1231 opt_mod
1232 (CALL_DATA cd)
1233 (VALUE recv, VALUE obj)
1234 (VALUE val)
1235 /* Same discussion as opt_div. */
1236 // attr bool leaf = false;
1238 val = vm_opt_mod(recv, obj);
1240 if (UNDEF_P(val)) {
1241 CALL_SIMPLE_METHOD();
1245 /* optimized X==Y. */
1246 DEFINE_INSN
1247 opt_eq
1248 (CALL_DATA cd)
1249 (VALUE recv, VALUE obj)
1250 (VALUE val)
1252 val = opt_equality(GET_ISEQ(), recv, obj, cd);
1254 if (UNDEF_P(val)) {
1255 CALL_SIMPLE_METHOD();
1259 /* optimized X!=Y. */
1260 DEFINE_INSN
1261 opt_neq
1262 (CALL_DATA cd_eq, CALL_DATA cd)
1263 (VALUE recv, VALUE obj)
1264 (VALUE val)
1266 val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
1268 if (UNDEF_P(val)) {
1269 CALL_SIMPLE_METHOD();
1273 /* optimized X<Y. */
1274 DEFINE_INSN
1275 opt_lt
1276 (CALL_DATA cd)
1277 (VALUE recv, VALUE obj)
1278 (VALUE val)
1280 val = vm_opt_lt(recv, obj);
1282 if (UNDEF_P(val)) {
1283 CALL_SIMPLE_METHOD();
1287 /* optimized X<=Y. */
1288 DEFINE_INSN
1289 opt_le
1290 (CALL_DATA cd)
1291 (VALUE recv, VALUE obj)
1292 (VALUE val)
1294 val = vm_opt_le(recv, obj);
1296 if (UNDEF_P(val)) {
1297 CALL_SIMPLE_METHOD();
1301 /* optimized X>Y. */
1302 DEFINE_INSN
1303 opt_gt
1304 (CALL_DATA cd)
1305 (VALUE recv, VALUE obj)
1306 (VALUE val)
1308 val = vm_opt_gt(recv, obj);
1310 if (UNDEF_P(val)) {
1311 CALL_SIMPLE_METHOD();
1315 /* optimized X>=Y. */
1316 DEFINE_INSN
1317 opt_ge
1318 (CALL_DATA cd)
1319 (VALUE recv, VALUE obj)
1320 (VALUE val)
1322 val = vm_opt_ge(recv, obj);
1324 if (UNDEF_P(val)) {
1325 CALL_SIMPLE_METHOD();
1329 /* << */
1330 DEFINE_INSN
1331 opt_ltlt
1332 (CALL_DATA cd)
1333 (VALUE recv, VALUE obj)
1334 (VALUE val)
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);
1342 if (UNDEF_P(val)) {
1343 CALL_SIMPLE_METHOD();
1347 /* optimized X&Y. */
1348 DEFINE_INSN
1349 opt_and
1350 (CALL_DATA cd)
1351 (VALUE recv, VALUE obj)
1352 (VALUE val)
1354 val = vm_opt_and(recv, obj);
1356 if (UNDEF_P(val)) {
1357 CALL_SIMPLE_METHOD();
1361 /* optimized X|Y. */
1362 DEFINE_INSN
1363 opt_or
1364 (CALL_DATA cd)
1365 (VALUE recv, VALUE obj)
1366 (VALUE val)
1368 val = vm_opt_or(recv, obj);
1370 if (UNDEF_P(val)) {
1371 CALL_SIMPLE_METHOD();
1375 /* [] */
1376 DEFINE_INSN
1377 opt_aref
1378 (CALL_DATA cd)
1379 (VALUE recv, VALUE obj)
1380 (VALUE val)
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);
1389 if (UNDEF_P(val)) {
1390 CALL_SIMPLE_METHOD();
1394 /* recv[obj] = set */
1395 DEFINE_INSN
1396 opt_aset
1397 (CALL_DATA cd)
1398 (VALUE recv, VALUE obj, VALUE set)
1399 (VALUE val)
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);
1406 if (UNDEF_P(val)) {
1407 CALL_SIMPLE_METHOD();
1411 /* recv[str] = set */
1412 DEFINE_INSN
1413 opt_aset_with
1414 (VALUE key, CALL_DATA cd)
1415 (VALUE recv, VALUE val)
1416 (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)) {
1423 val = tmp;
1425 else {
1426 TOPN(0) = rb_str_resurrect(key);
1427 PUSH(val);
1428 CALL_SIMPLE_METHOD();
1432 /* recv[str] */
1433 DEFINE_INSN
1434 opt_aref_with
1435 (VALUE key, CALL_DATA cd)
1436 (VALUE recv)
1437 (VALUE val)
1438 /* Same discussion as opt_aref. */
1439 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1441 val = vm_opt_aref_with(recv, key);
1443 if (UNDEF_P(val)) {
1444 PUSH(rb_str_resurrect(key));
1445 CALL_SIMPLE_METHOD();
1449 /* optimized length */
1450 DEFINE_INSN
1451 opt_length
1452 (CALL_DATA cd)
1453 (VALUE recv)
1454 (VALUE val)
1456 val = vm_opt_length(recv, BOP_LENGTH);
1458 if (UNDEF_P(val)) {
1459 CALL_SIMPLE_METHOD();
1463 /* optimized size */
1464 DEFINE_INSN
1465 opt_size
1466 (CALL_DATA cd)
1467 (VALUE recv)
1468 (VALUE val)
1470 val = vm_opt_length(recv, BOP_SIZE);
1472 if (UNDEF_P(val)) {
1473 CALL_SIMPLE_METHOD();
1477 /* optimized empty? */
1478 DEFINE_INSN
1479 opt_empty_p
1480 (CALL_DATA cd)
1481 (VALUE recv)
1482 (VALUE val)
1484 val = vm_opt_empty_p(recv);
1486 if (UNDEF_P(val)) {
1487 CALL_SIMPLE_METHOD();
1491 /* optimized succ */
1492 DEFINE_INSN
1493 opt_succ
1494 (CALL_DATA cd)
1495 (VALUE recv)
1496 (VALUE val)
1498 val = vm_opt_succ(recv);
1500 if (UNDEF_P(val)) {
1501 CALL_SIMPLE_METHOD();
1505 /* optimized not */
1506 DEFINE_INSN
1507 opt_not
1508 (CALL_DATA cd)
1509 (VALUE recv)
1510 (VALUE val)
1512 val = vm_opt_not(GET_ISEQ(), cd, recv);
1514 if (UNDEF_P(val)) {
1515 CALL_SIMPLE_METHOD();
1519 /* optimized regexp match 2 */
1520 DEFINE_INSN
1521 opt_regexpmatch2
1522 (CALL_DATA cd)
1523 (VALUE obj2, VALUE obj1)
1524 (VALUE val)
1525 // attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
1527 val = vm_opt_regexpmatch2(obj2, obj1);
1529 if (UNDEF_P(val)) {
1530 CALL_SIMPLE_METHOD();
1534 /* call specific function with args */
1535 DEFINE_INSN
1536 invokebuiltin
1537 (RB_BUILTIN bf)
1538 (...)
1539 (VALUE val)
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) */
1547 DEFINE_INSN
1548 opt_invokebuiltin_delegate
1549 (RB_BUILTIN bf, rb_num_t index)
1551 (VALUE val)
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 */
1558 DEFINE_INSN
1559 opt_invokebuiltin_delegate_leave
1560 (RB_BUILTIN bf, rb_num_t index)
1562 (VALUE val)
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;
1572 return 0;
1573 #else
1574 return val;
1575 #endif
1577 else {
1578 RESTORE_REGS();
1582 /* BLT */
1583 DEFINE_INSN_IF(SUPPORT_JOKE)
1584 bitblt
1587 (VALUE ret)
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)
1594 answer
1597 (VALUE ret)
1599 ret = INT2FIX(42);