* 2022-01-18 [ci skip]
[ruby-80x24.org.git] / insns.def
blob30b7c626d73eba547c945480cb12e682380675eb
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, IVC 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, (ICVARC)ic);
243 /* Set value of class variable id of klass as val. */
244 DEFINE_INSN
245 setclassvariable
246 (ID id, IVC 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, (ICVARC)ic);
256 /* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants
257 are searched in the current scope. Otherwise, get constant under klass
258 class or module.
260 DEFINE_INSN
261 getconstant
262 (ID id)
263 (VALUE klass, VALUE allow_nil)
264 (VALUE val)
265 /* getconstant can kick autoload */
266 // attr bool leaf = false; /* has rb_autoload_load() */
268 val = vm_get_ev_const(ec, klass, id, allow_nil == Qtrue, 0);
271 /* Set constant variable id under cbase class or module.
273 DEFINE_INSN
274 setconstant
275 (ID id)
276 (VALUE val, VALUE cbase)
278 /* Assigning an object to a constant is basically a leaf operation.
279 * The problem is, assigning a Module instance to a constant _names_
280 * that module. Naming involves string manipulations, which are
281 * method calls. */
282 // attr bool leaf = false; /* has StringValue() */
284 vm_check_if_namespace(cbase);
285 vm_ensure_not_refinement_module(GET_SELF());
286 rb_const_set(cbase, id, val);
289 /* get global variable id. */
290 DEFINE_INSN
291 getglobal
292 (ID gid)
294 (VALUE val)
295 // attr bool leaf = false;
297 val = rb_gvar_get(gid);
300 /* set global variable id as val. */
301 DEFINE_INSN
302 setglobal
303 (ID gid)
304 (VALUE val)
306 // attr bool leaf = false;
308 rb_gvar_set(gid, val);
311 /**********************************************************/
312 /* deal with values */
313 /**********************************************************/
315 /* put nil to stack. */
316 DEFINE_INSN
317 putnil
320 (VALUE val)
322 val = Qnil;
325 /* put self. */
326 DEFINE_INSN
327 putself
330 (VALUE val)
332 val = GET_SELF();
335 /* put some object.
336 i.e. Fixnum, true, false, nil, and so on.
338 DEFINE_INSN
339 putobject
340 (VALUE val)
342 (VALUE val)
344 /* */
347 /* put special object. "value_type" is for expansion. */
348 DEFINE_INSN
349 putspecialobject
350 (rb_num_t value_type)
352 (VALUE val)
353 // attr bool leaf = (value_type == VM_SPECIAL_OBJECT_VMCORE); /* others may raise when allocating singleton */
355 enum vm_special_object_type type;
357 type = (enum vm_special_object_type)value_type;
358 val = vm_get_special_object(GET_EP(), type);
361 /* put string val. string will be copied. */
362 DEFINE_INSN
363 putstring
364 (VALUE str)
366 (VALUE val)
368 val = rb_ec_str_resurrect(ec, str);
371 /* put concatenate strings */
372 DEFINE_INSN
373 concatstrings
374 (rb_num_t num)
375 (...)
376 (VALUE val)
377 /* This instruction can concat UTF-8 and binary strings, resulting in
378 * Encoding::CompatibilityError. */
379 // attr bool leaf = false; /* has rb_enc_cr_str_buf_cat() */
380 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
382 val = rb_str_concat_literals(num, STACK_ADDR_FROM_TOP(num));
385 /* Convert the result to string if not already a string.
386 This is used as a backup if to_s does not return a string. */
387 DEFINE_INSN
388 anytostring
390 (VALUE val, VALUE str)
391 (VALUE val)
393 val = rb_obj_as_string_result(str, val);
396 /* compile str to Regexp and push it.
397 opt is the option for the Regexp.
399 DEFINE_INSN
400 toregexp
401 (rb_num_t opt, rb_num_t cnt)
402 (...)
403 (VALUE val)
404 /* This instruction can raise RegexpError, thus can call
405 * RegexpError#initialize */
406 // attr bool leaf = false;
407 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)cnt;
409 const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt));
410 val = rb_reg_new_ary(ary, (int)opt);
411 rb_ary_clear(ary);
414 /* intern str to Symbol and push it. */
415 DEFINE_INSN
416 intern
418 (VALUE str)
419 (VALUE sym)
421 sym = rb_str_intern(str);
424 /* put new array initialized with num values on the stack. */
425 DEFINE_INSN
426 newarray
427 (rb_num_t num)
428 (...)
429 (VALUE val)
430 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
432 val = rb_ec_ary_new_from_values(ec, num, STACK_ADDR_FROM_TOP(num));
435 /* put new array initialized with num values on the stack. There
436 should be at least one element on the stack, and the top element
437 should be a hash. If the top element is empty, it is not
438 included in the array.
440 DEFINE_INSN
441 newarraykwsplat
442 (rb_num_t num)
443 (...)
444 (VALUE val)
445 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
447 if (RHASH_EMPTY_P(*STACK_ADDR_FROM_TOP(1))) {
448 val = rb_ary_new4(num-1, STACK_ADDR_FROM_TOP(num));
450 else {
451 val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
455 /* dup array */
456 DEFINE_INSN
457 duparray
458 (VALUE ary)
460 (VALUE val)
462 RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
463 val = rb_ary_resurrect(ary);
466 /* dup hash */
467 DEFINE_INSN
468 duphash
469 (VALUE hash)
471 (VALUE val)
473 RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1);
474 val = rb_hash_resurrect(hash);
477 /* if TOS is an array expand, expand it to num objects.
478 if the number of the array is less than num, push nils to fill.
479 if it is greater than num, exceeding elements are dropped.
480 unless TOS is an array, push num - 1 nils.
481 if flags is non-zero, push the array of the rest elements.
482 flag: 0x01 - rest args array
483 flag: 0x02 - for postarg
484 flag: 0x04 - reverse?
486 DEFINE_INSN
487 expandarray
488 (rb_num_t num, rb_num_t flag)
489 (..., VALUE ary)
490 (...)
491 // attr bool leaf = false; /* has rb_check_array_type() */
492 // attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
494 vm_expandarray(GET_SP(), ary, num, (int)flag);
497 /* concat two arrays */
498 DEFINE_INSN
499 concatarray
501 (VALUE ary1, VALUE ary2)
502 (VALUE ary)
503 // attr bool leaf = false; /* has rb_check_array_type() */
505 ary = vm_concat_array(ary1, ary2);
508 /* call to_a on array ary to splat */
509 DEFINE_INSN
510 splatarray
511 (VALUE flag)
512 (VALUE ary)
513 (VALUE obj)
514 // attr bool leaf = false; /* has rb_check_array_type() */
516 obj = vm_splat_array(flag, ary);
519 /* put new Hash from n elements. n must be an even number. */
520 DEFINE_INSN
521 newhash
522 (rb_num_t num)
523 (...)
524 (VALUE val)
525 // attr bool leaf = false; /* has rb_hash_key_str() */
526 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
528 RUBY_DTRACE_CREATE_HOOK(HASH, num);
530 if (num) {
531 val = rb_hash_new_with_size(num / 2);
532 rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
534 else {
535 val = rb_hash_new();
539 /* put new Range object.(Range.new(low, high, flag)) */
540 DEFINE_INSN
541 newrange
542 (rb_num_t flag)
543 (VALUE low, VALUE high)
544 (VALUE val)
545 /* rb_range_new() exercises "bad value for range" check. */
546 // attr bool leaf = false; /* see also: range.c:range_init() */
548 val = rb_range_new(low, high, (int)flag);
551 /**********************************************************/
552 /* deal with stack operation */
553 /**********************************************************/
555 /* pop from stack. */
556 DEFINE_INSN
559 (VALUE val)
562 (void)val;
563 /* none */
566 /* duplicate stack top. */
567 DEFINE_INSN
570 (VALUE val)
571 (VALUE val1, VALUE val2)
573 val1 = val2 = val;
576 /* duplicate stack top n elements */
577 DEFINE_INSN
578 dupn
579 (rb_num_t n)
580 (...)
581 (...)
582 // attr rb_snum_t sp_inc = n;
584 void *dst = GET_SP();
585 void *src = STACK_ADDR_FROM_TOP(n);
587 MEMCPY(dst, src, VALUE, n);
590 /* swap top 2 vals */
591 DEFINE_INSN
592 swap
594 (VALUE val, VALUE obj)
595 (VALUE obj, VALUE val)
597 /* none */
600 /* for stack caching. */
601 DEFINE_INSN_IF(STACK_CACHING)
602 reput
604 (..., VALUE val)
605 (VALUE val)
606 // attr rb_snum_t sp_inc = 0;
608 /* none */
611 /* get nth stack value from stack top */
612 DEFINE_INSN
613 topn
614 (rb_num_t n)
615 (...)
616 (VALUE val)
617 // attr rb_snum_t sp_inc = 1;
619 val = TOPN(n);
622 /* set Nth stack entry to stack top */
623 DEFINE_INSN
624 setn
625 (rb_num_t n)
626 (..., VALUE val)
627 (VALUE val)
628 // attr rb_snum_t sp_inc = 0;
630 TOPN(n) = val;
633 /* empty current stack */
634 DEFINE_INSN
635 adjuststack
636 (rb_num_t n)
637 (...)
638 (...)
639 // attr rb_snum_t sp_inc = -(rb_snum_t)n;
641 /* none */
644 /**********************************************************/
645 /* deal with setting */
646 /**********************************************************/
648 /* defined? */
649 DEFINE_INSN
650 defined
651 (rb_num_t op_type, VALUE obj, VALUE pushval)
652 (VALUE v)
653 (VALUE val)
654 // attr bool leaf = leafness_of_defined(op_type);
656 val = Qnil;
657 if (vm_defined(ec, GET_CFP(), op_type, obj, v)) {
658 val = pushval;
662 /* check `target' matches `pattern'.
663 `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
664 VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
665 VM_CHECKMATCH_TYPE_CASE: check `patten === target'.
666 VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_of?(Module) && pattern === target'.
667 if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns.
669 DEFINE_INSN
670 checkmatch
671 (rb_num_t flag)
672 (VALUE target, VALUE pattern)
673 (VALUE result)
674 // attr bool leaf = leafness_of_checkmatch(flag);
676 result = vm_check_match(ec, target, pattern, flag);
679 /* check keywords are specified or not. */
680 DEFINE_INSN
681 checkkeyword
682 (lindex_t kw_bits_index, lindex_t keyword_index)
684 (VALUE ret)
686 ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP());
689 /* check if val is type. */
690 DEFINE_INSN
691 checktype
692 (rb_num_t type)
693 (VALUE val)
694 (VALUE ret)
696 ret = RBOOL(TYPE(val) == (int)type);
699 /**********************************************************/
700 /* deal with control flow 1: class/module */
701 /**********************************************************/
703 /* enter class definition scope. if super is Qfalse, and class
704 "klass" is defined, it's redefined. Otherwise, define "klass" class.
706 DEFINE_INSN
707 defineclass
708 (ID id, ISEQ class_iseq, rb_num_t flags)
709 (VALUE cbase, VALUE super)
710 (VALUE val)
712 VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
714 rb_iseq_check(class_iseq);
716 /* enter scope */
717 vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
718 GET_BLOCK_HANDLER(),
719 (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE),
720 class_iseq->body->iseq_encoded, GET_SP(),
721 class_iseq->body->local_table_size,
722 class_iseq->body->stack_max);
723 RESTORE_REGS();
724 NEXT_INSN();
727 DEFINE_INSN
728 definemethod
729 (ID id, ISEQ iseq)
733 vm_define_method(ec, Qnil, id, (VALUE)iseq, FALSE);
736 DEFINE_INSN
737 definesmethod
738 (ID id, ISEQ iseq)
739 (VALUE obj)
742 vm_define_method(ec, obj, id, (VALUE)iseq, TRUE);
745 /**********************************************************/
746 /* deal with control flow 2: method/iterator */
747 /**********************************************************/
749 /* invoke method. */
750 DEFINE_INSN
751 send
752 (CALL_DATA cd, ISEQ blockiseq)
753 (...)
754 (VALUE val)
755 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
756 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
758 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
759 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
761 if (val == Qundef) {
762 RESTORE_REGS();
763 NEXT_INSN();
767 /* Invoke method without block */
768 DEFINE_INSN
769 opt_send_without_block
770 (CALL_DATA cd)
771 (...)
772 (VALUE val)
773 // attr bool handles_sp = true;
774 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
775 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
777 VALUE bh = VM_BLOCK_HANDLER_NONE;
778 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
780 if (val == Qundef) {
781 RESTORE_REGS();
782 NEXT_INSN();
786 /* Convert object to string using to_s or equivalent. */
787 DEFINE_INSN
788 objtostring
789 (CALL_DATA cd)
790 (VALUE recv)
791 (VALUE val)
792 // attr bool leaf = false;
794 val = vm_objtostring(GET_ISEQ(), recv, cd);
796 if (val == Qundef) {
797 CALL_SIMPLE_METHOD();
801 DEFINE_INSN
802 opt_str_freeze
803 (VALUE str, CALL_DATA cd)
805 (VALUE val)
807 val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze);
809 if (val == Qundef) {
810 PUSH(rb_str_resurrect(str));
811 CALL_SIMPLE_METHOD();
815 /* optimized nil? */
816 DEFINE_INSN
817 opt_nil_p
818 (CALL_DATA cd)
819 (VALUE recv)
820 (VALUE val)
822 val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
824 if (val == Qundef) {
825 CALL_SIMPLE_METHOD();
829 DEFINE_INSN
830 opt_str_uminus
831 (VALUE str, CALL_DATA cd)
833 (VALUE val)
835 val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus);
837 if (val == Qundef) {
838 PUSH(rb_str_resurrect(str));
839 CALL_SIMPLE_METHOD();
843 DEFINE_INSN
844 opt_newarray_max
845 (rb_num_t num)
846 (...)
847 (VALUE val)
848 /* This instruction typically has no funcalls. But it compares array
849 * contents each other by nature. That part could call methods when
850 * necessary. No way to detect such method calls beforehand. We
851 * cannot but mark it being not leaf. */
852 // attr bool leaf = false; /* has rb_funcall() */
853 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
855 val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
858 DEFINE_INSN
859 opt_newarray_min
860 (rb_num_t num)
861 (...)
862 (VALUE val)
863 /* Same discussion as opt_newarray_max. */
864 // attr bool leaf = false; /* has rb_funcall() */
865 // attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
867 val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
870 /* super(args) # args.size => num */
871 DEFINE_INSN
872 invokesuper
873 (CALL_DATA cd, ISEQ blockiseq)
874 (...)
875 (VALUE val)
876 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
877 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
879 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
880 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
882 if (val == Qundef) {
883 RESTORE_REGS();
884 NEXT_INSN();
888 /* yield(args) */
889 DEFINE_INSN
890 invokeblock
891 (CALL_DATA cd)
892 (...)
893 (VALUE val)
894 // attr bool handles_sp = true;
895 // attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci);
896 // attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci);
898 VALUE bh = VM_BLOCK_HANDLER_NONE;
899 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
901 if (val == Qundef) {
902 RESTORE_REGS();
903 NEXT_INSN();
907 /* return from this scope. */
908 DEFINE_INSN
909 leave
911 (VALUE val)
912 (VALUE val)
913 /* This is super surprising but when leaving from a frame, we check
914 * for interrupts. If any, that should be executed on top of the
915 * current execution context. This is a method call. */
916 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
917 // attr bool handles_sp = true;
919 if (OPT_CHECKED_RUN) {
920 const VALUE *const bp = vm_base_ptr(GET_CFP());
921 if (GET_SP() != bp) {
922 vm_stack_consistency_error(ec, GET_CFP(), bp);
926 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
927 #if OPT_CALL_THREADED_CODE
928 rb_ec_thread_ptr(ec)->retval = val;
929 return 0;
930 #else
931 return val;
932 #endif
934 else {
935 RESTORE_REGS();
939 /**********************************************************/
940 /* deal with control flow 3: exception */
941 /**********************************************************/
943 /* longjump */
944 DEFINE_INSN
945 throw
946 (rb_num_t throw_state)
947 (VALUE throwobj)
948 (VALUE val)
949 /* Same discussion as leave. */
950 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
952 val = vm_throw(ec, GET_CFP(), throw_state, throwobj);
953 THROW_EXCEPTION(val);
954 /* unreachable */
957 /**********************************************************/
958 /* deal with control flow 4: local jump */
959 /**********************************************************/
961 /* set PC to (PC + dst). */
962 DEFINE_INSN
963 jump
964 (OFFSET dst)
967 /* Same discussion as leave. */
968 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
970 RUBY_VM_CHECK_INTS(ec);
971 JUMP(dst);
974 /* if val is not false or nil, set PC to (PC + dst). */
975 DEFINE_INSN
976 branchif
977 (OFFSET dst)
978 (VALUE val)
980 /* Same discussion as jump. */
981 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
983 if (RTEST(val)) {
984 RUBY_VM_CHECK_INTS(ec);
985 JUMP(dst);
989 /* if val is false or nil, set PC to (PC + dst). */
990 DEFINE_INSN
991 branchunless
992 (OFFSET dst)
993 (VALUE val)
995 /* Same discussion as jump. */
996 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
998 if (!RTEST(val)) {
999 RUBY_VM_CHECK_INTS(ec);
1000 JUMP(dst);
1004 /* if val is nil, set PC to (PC + dst). */
1005 DEFINE_INSN
1006 branchnil
1007 (OFFSET dst)
1008 (VALUE val)
1010 /* Same discussion as jump. */
1011 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1013 if (NIL_P(val)) {
1014 RUBY_VM_CHECK_INTS(ec);
1015 JUMP(dst);
1019 /**********************************************************/
1020 /* for optimize */
1021 /**********************************************************/
1023 /* push inline-cached value and go to dst if it is valid */
1024 DEFINE_INSN
1025 opt_getinlinecache
1026 (OFFSET dst, IC ic)
1028 (VALUE val)
1030 struct iseq_inline_constant_cache_entry *ice = ic->entry;
1031 if (ice && vm_ic_hit_p(ice, GET_EP())) {
1032 val = ice->value;
1033 JUMP(dst);
1035 else {
1036 val = Qnil;
1040 /* set inline cache */
1041 DEFINE_INSN
1042 opt_setinlinecache
1043 (IC ic)
1044 (VALUE val)
1045 (VALUE val)
1046 // attr bool leaf = false;
1048 vm_ic_update(GET_ISEQ(), ic, val, GET_EP());
1051 /* run iseq only once */
1052 DEFINE_INSN
1053 once
1054 (ISEQ iseq, ISE ise)
1056 (VALUE val)
1058 val = vm_once_dispatch(ec, iseq, ise);
1061 /* case dispatcher, jump by table if possible */
1062 DEFINE_INSN
1063 opt_case_dispatch
1064 (CDHASH hash, OFFSET else_offset)
1065 (..., VALUE key)
1067 // attr rb_snum_t sp_inc = -1;
1069 OFFSET dst = vm_case_dispatch(hash, else_offset, key);
1071 if (dst) {
1072 JUMP(dst);
1076 /** simple functions */
1078 /* optimized X+Y. */
1079 DEFINE_INSN
1080 opt_plus
1081 (CALL_DATA cd)
1082 (VALUE recv, VALUE obj)
1083 (VALUE val)
1085 val = vm_opt_plus(recv, obj);
1087 if (val == Qundef) {
1088 CALL_SIMPLE_METHOD();
1092 /* optimized X-Y. */
1093 DEFINE_INSN
1094 opt_minus
1095 (CALL_DATA cd)
1096 (VALUE recv, VALUE obj)
1097 (VALUE val)
1099 val = vm_opt_minus(recv, obj);
1101 if (val == Qundef) {
1102 CALL_SIMPLE_METHOD();
1106 /* optimized X*Y. */
1107 DEFINE_INSN
1108 opt_mult
1109 (CALL_DATA cd)
1110 (VALUE recv, VALUE obj)
1111 (VALUE val)
1113 val = vm_opt_mult(recv, obj);
1115 if (val == Qundef) {
1116 CALL_SIMPLE_METHOD();
1120 /* optimized X/Y. */
1121 DEFINE_INSN
1122 opt_div
1123 (CALL_DATA cd)
1124 (VALUE recv, VALUE obj)
1125 (VALUE val)
1126 /* In case of division by zero, it raises. Thus
1127 * ZeroDivisionError#initialize is called. */
1128 // attr bool leaf = false;
1130 val = vm_opt_div(recv, obj);
1132 if (val == Qundef) {
1133 CALL_SIMPLE_METHOD();
1137 /* optimized X%Y. */
1138 DEFINE_INSN
1139 opt_mod
1140 (CALL_DATA cd)
1141 (VALUE recv, VALUE obj)
1142 (VALUE val)
1143 /* Same discussion as opt_div. */
1144 // attr bool leaf = false;
1146 val = vm_opt_mod(recv, obj);
1148 if (val == Qundef) {
1149 CALL_SIMPLE_METHOD();
1153 /* optimized X==Y. */
1154 DEFINE_INSN
1155 opt_eq
1156 (CALL_DATA cd)
1157 (VALUE recv, VALUE obj)
1158 (VALUE val)
1160 val = opt_equality(GET_ISEQ(), recv, obj, cd);
1162 if (val == Qundef) {
1163 CALL_SIMPLE_METHOD();
1167 /* optimized X!=Y. */
1168 DEFINE_INSN
1169 opt_neq
1170 (CALL_DATA cd_eq, CALL_DATA cd)
1171 (VALUE recv, VALUE obj)
1172 (VALUE val)
1174 val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
1176 if (val == Qundef) {
1177 CALL_SIMPLE_METHOD();
1181 /* optimized X<Y. */
1182 DEFINE_INSN
1183 opt_lt
1184 (CALL_DATA cd)
1185 (VALUE recv, VALUE obj)
1186 (VALUE val)
1188 val = vm_opt_lt(recv, obj);
1190 if (val == Qundef) {
1191 CALL_SIMPLE_METHOD();
1195 /* optimized X<=Y. */
1196 DEFINE_INSN
1197 opt_le
1198 (CALL_DATA cd)
1199 (VALUE recv, VALUE obj)
1200 (VALUE val)
1202 val = vm_opt_le(recv, obj);
1204 if (val == Qundef) {
1205 CALL_SIMPLE_METHOD();
1209 /* optimized X>Y. */
1210 DEFINE_INSN
1211 opt_gt
1212 (CALL_DATA cd)
1213 (VALUE recv, VALUE obj)
1214 (VALUE val)
1216 val = vm_opt_gt(recv, obj);
1218 if (val == Qundef) {
1219 CALL_SIMPLE_METHOD();
1223 /* optimized X>=Y. */
1224 DEFINE_INSN
1225 opt_ge
1226 (CALL_DATA cd)
1227 (VALUE recv, VALUE obj)
1228 (VALUE val)
1230 val = vm_opt_ge(recv, obj);
1232 if (val == Qundef) {
1233 CALL_SIMPLE_METHOD();
1237 /* << */
1238 DEFINE_INSN
1239 opt_ltlt
1240 (CALL_DATA cd)
1241 (VALUE recv, VALUE obj)
1242 (VALUE val)
1243 /* This instruction can append an integer, as a codepoint, into a
1244 * string. Then what happens if that codepoint does not exist in the
1245 * string's encoding? Of course an exception. That's not a leaf. */
1246 // attr bool leaf = false; /* has "invalid codepoint" exception */
1248 val = vm_opt_ltlt(recv, obj);
1250 if (val == Qundef) {
1251 CALL_SIMPLE_METHOD();
1255 /* optimized X&Y. */
1256 DEFINE_INSN
1257 opt_and
1258 (CALL_DATA cd)
1259 (VALUE recv, VALUE obj)
1260 (VALUE val)
1262 val = vm_opt_and(recv, obj);
1264 if (val == Qundef) {
1265 CALL_SIMPLE_METHOD();
1269 /* optimized X|Y. */
1270 DEFINE_INSN
1271 opt_or
1272 (CALL_DATA cd)
1273 (VALUE recv, VALUE obj)
1274 (VALUE val)
1276 val = vm_opt_or(recv, obj);
1278 if (val == Qundef) {
1279 CALL_SIMPLE_METHOD();
1283 /* [] */
1284 DEFINE_INSN
1285 opt_aref
1286 (CALL_DATA cd)
1287 (VALUE recv, VALUE obj)
1288 (VALUE val)
1289 /* This is complicated. In case of hash, vm_opt_aref() resorts to
1290 * rb_hash_aref(). If `recv` has no `obj`, this function then yields
1291 * default_proc. This is a method call. So opt_aref is
1292 * (surprisingly) not leaf. */
1293 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1295 val = vm_opt_aref(recv, obj);
1297 if (val == Qundef) {
1298 CALL_SIMPLE_METHOD();
1302 /* recv[obj] = set */
1303 DEFINE_INSN
1304 opt_aset
1305 (CALL_DATA cd)
1306 (VALUE recv, VALUE obj, VALUE set)
1307 (VALUE val)
1308 /* This is another story than opt_aref. When vm_opt_aset() resorts
1309 * to rb_hash_aset(), which should call #hash for `obj`. */
1310 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1312 val = vm_opt_aset(recv, obj, set);
1314 if (val == Qundef) {
1315 CALL_SIMPLE_METHOD();
1319 /* recv[str] = set */
1320 DEFINE_INSN
1321 opt_aset_with
1322 (VALUE key, CALL_DATA cd)
1323 (VALUE recv, VALUE val)
1324 (VALUE val)
1325 /* Same discussion as opt_aset. */
1326 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1328 VALUE tmp = vm_opt_aset_with(recv, key, val);
1330 if (tmp != Qundef) {
1331 val = tmp;
1333 else {
1334 #ifndef MJIT_HEADER
1335 TOPN(0) = rb_str_resurrect(key);
1336 PUSH(val);
1337 #endif
1338 CALL_SIMPLE_METHOD();
1342 /* recv[str] */
1343 DEFINE_INSN
1344 opt_aref_with
1345 (VALUE key, CALL_DATA cd)
1346 (VALUE recv)
1347 (VALUE val)
1348 /* Same discussion as opt_aref. */
1349 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1351 val = vm_opt_aref_with(recv, key);
1353 if (val == Qundef) {
1354 #ifndef MJIT_HEADER
1355 PUSH(rb_str_resurrect(key));
1356 #endif
1357 CALL_SIMPLE_METHOD();
1361 /* optimized length */
1362 DEFINE_INSN
1363 opt_length
1364 (CALL_DATA cd)
1365 (VALUE recv)
1366 (VALUE val)
1368 val = vm_opt_length(recv, BOP_LENGTH);
1370 if (val == Qundef) {
1371 CALL_SIMPLE_METHOD();
1375 /* optimized size */
1376 DEFINE_INSN
1377 opt_size
1378 (CALL_DATA cd)
1379 (VALUE recv)
1380 (VALUE val)
1382 val = vm_opt_length(recv, BOP_SIZE);
1384 if (val == Qundef) {
1385 CALL_SIMPLE_METHOD();
1389 /* optimized empty? */
1390 DEFINE_INSN
1391 opt_empty_p
1392 (CALL_DATA cd)
1393 (VALUE recv)
1394 (VALUE val)
1396 val = vm_opt_empty_p(recv);
1398 if (val == Qundef) {
1399 CALL_SIMPLE_METHOD();
1403 /* optimized succ */
1404 DEFINE_INSN
1405 opt_succ
1406 (CALL_DATA cd)
1407 (VALUE recv)
1408 (VALUE val)
1410 val = vm_opt_succ(recv);
1412 if (val == Qundef) {
1413 CALL_SIMPLE_METHOD();
1417 /* optimized not */
1418 DEFINE_INSN
1419 opt_not
1420 (CALL_DATA cd)
1421 (VALUE recv)
1422 (VALUE val)
1424 val = vm_opt_not(GET_ISEQ(), cd, recv);
1426 if (val == Qundef) {
1427 CALL_SIMPLE_METHOD();
1431 /* optimized regexp match 2 */
1432 DEFINE_INSN
1433 opt_regexpmatch2
1434 (CALL_DATA cd)
1435 (VALUE obj2, VALUE obj1)
1436 (VALUE val)
1437 // attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
1439 val = vm_opt_regexpmatch2(obj2, obj1);
1441 if (val == Qundef) {
1442 CALL_SIMPLE_METHOD();
1446 /* call native compiled method */
1447 DEFINE_INSN_IF(SUPPORT_CALL_C_FUNCTION)
1448 opt_call_c_function
1449 (rb_insn_func_t funcptr)
1452 // attr bool leaf = false; /* anything can happen inside */
1453 // attr bool handles_sp = true;
1455 reg_cfp = (funcptr)(ec, reg_cfp);
1457 if (reg_cfp == 0) {
1458 VALUE err = ec->errinfo;
1459 ec->errinfo = Qnil;
1460 THROW_EXCEPTION(err);
1463 RESTORE_REGS();
1464 NEXT_INSN();
1467 /* call specific function with args */
1468 DEFINE_INSN
1469 invokebuiltin
1470 (RB_BUILTIN bf)
1471 (...)
1472 (VALUE val)
1473 // attr bool leaf = false; /* anything can happen inside */
1474 // attr rb_snum_t sp_inc = 1 - bf->argc;
1476 val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
1479 /* call specific function with args (same parameters) */
1480 DEFINE_INSN
1481 opt_invokebuiltin_delegate
1482 (RB_BUILTIN bf, rb_num_t index)
1484 (VALUE val)
1485 // attr bool leaf = false; /* anything can happen inside */
1487 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1490 /* call specific function with args (same parameters) and leave */
1491 DEFINE_INSN
1492 opt_invokebuiltin_delegate_leave
1493 (RB_BUILTIN bf, rb_num_t index)
1495 (VALUE val)
1496 // attr bool leaf = false; /* anything can happen inside */
1498 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1500 /* leave fastpath */
1501 /* TracePoint/return fallbacks this insn to opt_invokebuiltin_delegate */
1502 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
1503 #if OPT_CALL_THREADED_CODE
1504 rb_ec_thread_ptr(ec)->retval = val;
1505 return 0;
1506 #else
1507 return val;
1508 #endif
1510 else {
1511 RESTORE_REGS();
1515 /* BLT */
1516 DEFINE_INSN_IF(SUPPORT_JOKE)
1517 bitblt
1520 (VALUE ret)
1522 ret = rb_str_new2("a bit of bacon, lettuce and tomato");
1525 /* The Answer to Life, the Universe, and Everything */
1526 DEFINE_INSN_IF(SUPPORT_JOKE)
1527 answer
1530 (VALUE ret)
1532 ret = INT2FIX(42);