[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / insns.def
blob9c649904b882780daf9f835597ae581b10679c36
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 default:
981 rb_bug("unreachable");
985 /* super(args) # args.size => num */
986 DEFINE_INSN
987 invokesuper
988 (CALL_DATA cd, ISEQ blockiseq)
989 (...)
990 (VALUE val)
991 // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
992 // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
994 VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
995 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
996 JIT_EXEC(ec, val);
998 if (UNDEF_P(val)) {
999 RESTORE_REGS();
1000 NEXT_INSN();
1004 /* yield(args) */
1005 DEFINE_INSN
1006 invokeblock
1007 (CALL_DATA cd)
1008 (...)
1009 (VALUE val)
1010 // attr bool handles_sp = true;
1011 // attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci);
1012 // attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci);
1014 VALUE bh = VM_BLOCK_HANDLER_NONE;
1015 val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
1016 JIT_EXEC(ec, val);
1018 if (UNDEF_P(val)) {
1019 RESTORE_REGS();
1020 NEXT_INSN();
1024 /* return from this scope. */
1025 DEFINE_INSN
1026 leave
1028 (VALUE val)
1029 (VALUE val)
1030 /* This is super surprising but when leaving from a frame, we check
1031 * for interrupts. If any, that should be executed on top of the
1032 * current execution context. This is a method call. */
1033 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
1034 // attr bool handles_sp = true;
1036 if (OPT_CHECKED_RUN) {
1037 const VALUE *const bp = vm_base_ptr(GET_CFP());
1038 if (GET_SP() != bp) {
1039 vm_stack_consistency_error(ec, GET_CFP(), bp);
1043 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
1044 #if OPT_CALL_THREADED_CODE
1045 rb_ec_thread_ptr(ec)->retval = val;
1046 return 0;
1047 #else
1048 return val;
1049 #endif
1051 else {
1052 RESTORE_REGS();
1056 /**********************************************************/
1057 /* deal with control flow 3: exception */
1058 /**********************************************************/
1060 /* longjump */
1061 DEFINE_INSN
1062 throw
1063 (rb_num_t throw_state)
1064 (VALUE throwobj)
1065 (VALUE val)
1066 /* Same discussion as leave. */
1067 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
1069 val = vm_throw(ec, GET_CFP(), throw_state, throwobj);
1070 THROW_EXCEPTION(val);
1071 /* unreachable */
1074 /**********************************************************/
1075 /* deal with control flow 4: local jump */
1076 /**********************************************************/
1078 /* set PC to (PC + dst). */
1079 DEFINE_INSN
1080 jump
1081 (OFFSET dst)
1084 /* Same discussion as leave. */
1085 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1087 RUBY_VM_CHECK_INTS(ec);
1088 JUMP(dst);
1091 /* if val is not false or nil, set PC to (PC + dst). */
1092 DEFINE_INSN
1093 branchif
1094 (OFFSET dst)
1095 (VALUE val)
1097 /* Same discussion as jump. */
1098 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1100 if (RTEST(val)) {
1101 RUBY_VM_CHECK_INTS(ec);
1102 JUMP(dst);
1106 /* if val is false or nil, set PC to (PC + dst). */
1107 DEFINE_INSN
1108 branchunless
1109 (OFFSET dst)
1110 (VALUE val)
1112 /* Same discussion as jump. */
1113 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1115 if (!RTEST(val)) {
1116 RUBY_VM_CHECK_INTS(ec);
1117 JUMP(dst);
1121 /* if val is nil, set PC to (PC + dst). */
1122 DEFINE_INSN
1123 branchnil
1124 (OFFSET dst)
1125 (VALUE val)
1127 /* Same discussion as jump. */
1128 // attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
1130 if (NIL_P(val)) {
1131 RUBY_VM_CHECK_INTS(ec);
1132 JUMP(dst);
1136 /**********************************************************/
1137 /* for optimize */
1138 /**********************************************************/
1140 /* run iseq only once */
1141 DEFINE_INSN
1142 once
1143 (ISEQ iseq, ISE ise)
1145 (VALUE val)
1147 val = vm_once_dispatch(ec, iseq, ise);
1150 /* case dispatcher, jump by table if possible */
1151 DEFINE_INSN
1152 opt_case_dispatch
1153 (CDHASH hash, OFFSET else_offset)
1154 (..., VALUE key)
1156 // attr rb_snum_t sp_inc = -1;
1158 OFFSET dst = vm_case_dispatch(hash, else_offset, key);
1160 if (dst) {
1161 JUMP(dst);
1165 /** simple functions */
1167 /* optimized X+Y. */
1168 DEFINE_INSN
1169 opt_plus
1170 (CALL_DATA cd)
1171 (VALUE recv, VALUE obj)
1172 (VALUE val)
1174 val = vm_opt_plus(recv, obj);
1176 if (UNDEF_P(val)) {
1177 CALL_SIMPLE_METHOD();
1181 /* optimized X-Y. */
1182 DEFINE_INSN
1183 opt_minus
1184 (CALL_DATA cd)
1185 (VALUE recv, VALUE obj)
1186 (VALUE val)
1188 val = vm_opt_minus(recv, obj);
1190 if (UNDEF_P(val)) {
1191 CALL_SIMPLE_METHOD();
1195 /* optimized X*Y. */
1196 DEFINE_INSN
1197 opt_mult
1198 (CALL_DATA cd)
1199 (VALUE recv, VALUE obj)
1200 (VALUE val)
1202 val = vm_opt_mult(recv, obj);
1204 if (UNDEF_P(val)) {
1205 CALL_SIMPLE_METHOD();
1209 /* optimized X/Y. */
1210 DEFINE_INSN
1211 opt_div
1212 (CALL_DATA cd)
1213 (VALUE recv, VALUE obj)
1214 (VALUE val)
1215 /* In case of division by zero, it raises. Thus
1216 * ZeroDivisionError#initialize is called. */
1217 // attr bool leaf = false;
1219 val = vm_opt_div(recv, obj);
1221 if (UNDEF_P(val)) {
1222 CALL_SIMPLE_METHOD();
1226 /* optimized X%Y. */
1227 DEFINE_INSN
1228 opt_mod
1229 (CALL_DATA cd)
1230 (VALUE recv, VALUE obj)
1231 (VALUE val)
1232 /* Same discussion as opt_div. */
1233 // attr bool leaf = false;
1235 val = vm_opt_mod(recv, obj);
1237 if (UNDEF_P(val)) {
1238 CALL_SIMPLE_METHOD();
1242 /* optimized X==Y. */
1243 DEFINE_INSN
1244 opt_eq
1245 (CALL_DATA cd)
1246 (VALUE recv, VALUE obj)
1247 (VALUE val)
1249 val = opt_equality(GET_ISEQ(), recv, obj, cd);
1251 if (UNDEF_P(val)) {
1252 CALL_SIMPLE_METHOD();
1256 /* optimized X!=Y. */
1257 DEFINE_INSN
1258 opt_neq
1259 (CALL_DATA cd_eq, CALL_DATA cd)
1260 (VALUE recv, VALUE obj)
1261 (VALUE val)
1263 val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
1265 if (UNDEF_P(val)) {
1266 CALL_SIMPLE_METHOD();
1270 /* optimized X<Y. */
1271 DEFINE_INSN
1272 opt_lt
1273 (CALL_DATA cd)
1274 (VALUE recv, VALUE obj)
1275 (VALUE val)
1277 val = vm_opt_lt(recv, obj);
1279 if (UNDEF_P(val)) {
1280 CALL_SIMPLE_METHOD();
1284 /* optimized X<=Y. */
1285 DEFINE_INSN
1286 opt_le
1287 (CALL_DATA cd)
1288 (VALUE recv, VALUE obj)
1289 (VALUE val)
1291 val = vm_opt_le(recv, obj);
1293 if (UNDEF_P(val)) {
1294 CALL_SIMPLE_METHOD();
1298 /* optimized X>Y. */
1299 DEFINE_INSN
1300 opt_gt
1301 (CALL_DATA cd)
1302 (VALUE recv, VALUE obj)
1303 (VALUE val)
1305 val = vm_opt_gt(recv, obj);
1307 if (UNDEF_P(val)) {
1308 CALL_SIMPLE_METHOD();
1312 /* optimized X>=Y. */
1313 DEFINE_INSN
1314 opt_ge
1315 (CALL_DATA cd)
1316 (VALUE recv, VALUE obj)
1317 (VALUE val)
1319 val = vm_opt_ge(recv, obj);
1321 if (UNDEF_P(val)) {
1322 CALL_SIMPLE_METHOD();
1326 /* << */
1327 DEFINE_INSN
1328 opt_ltlt
1329 (CALL_DATA cd)
1330 (VALUE recv, VALUE obj)
1331 (VALUE val)
1332 /* This instruction can append an integer, as a codepoint, into a
1333 * string. Then what happens if that codepoint does not exist in the
1334 * string's encoding? Of course an exception. That's not a leaf. */
1335 // attr bool leaf = false; /* has "invalid codepoint" exception */
1337 val = vm_opt_ltlt(recv, obj);
1339 if (UNDEF_P(val)) {
1340 CALL_SIMPLE_METHOD();
1344 /* optimized X&Y. */
1345 DEFINE_INSN
1346 opt_and
1347 (CALL_DATA cd)
1348 (VALUE recv, VALUE obj)
1349 (VALUE val)
1351 val = vm_opt_and(recv, obj);
1353 if (UNDEF_P(val)) {
1354 CALL_SIMPLE_METHOD();
1358 /* optimized X|Y. */
1359 DEFINE_INSN
1360 opt_or
1361 (CALL_DATA cd)
1362 (VALUE recv, VALUE obj)
1363 (VALUE val)
1365 val = vm_opt_or(recv, obj);
1367 if (UNDEF_P(val)) {
1368 CALL_SIMPLE_METHOD();
1372 /* [] */
1373 DEFINE_INSN
1374 opt_aref
1375 (CALL_DATA cd)
1376 (VALUE recv, VALUE obj)
1377 (VALUE val)
1378 /* This is complicated. In case of hash, vm_opt_aref() resorts to
1379 * rb_hash_aref(). If `recv` has no `obj`, this function then yields
1380 * default_proc. This is a method call. So opt_aref is
1381 * (surprisingly) not leaf. */
1382 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1384 val = vm_opt_aref(recv, obj);
1386 if (UNDEF_P(val)) {
1387 CALL_SIMPLE_METHOD();
1391 /* recv[obj] = set */
1392 DEFINE_INSN
1393 opt_aset
1394 (CALL_DATA cd)
1395 (VALUE recv, VALUE obj, VALUE set)
1396 (VALUE val)
1397 /* This is another story than opt_aref. When vm_opt_aset() resorts
1398 * to rb_hash_aset(), which should call #hash for `obj`. */
1399 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1401 val = vm_opt_aset(recv, obj, set);
1403 if (UNDEF_P(val)) {
1404 CALL_SIMPLE_METHOD();
1408 /* recv[str] = set */
1409 DEFINE_INSN
1410 opt_aset_with
1411 (VALUE key, CALL_DATA cd)
1412 (VALUE recv, VALUE val)
1413 (VALUE val)
1414 /* Same discussion as opt_aset. */
1415 // attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
1417 VALUE tmp = vm_opt_aset_with(recv, key, val);
1419 if (!UNDEF_P(tmp)) {
1420 val = tmp;
1422 else {
1423 TOPN(0) = rb_str_resurrect(key);
1424 PUSH(val);
1425 CALL_SIMPLE_METHOD();
1429 /* recv[str] */
1430 DEFINE_INSN
1431 opt_aref_with
1432 (VALUE key, CALL_DATA cd)
1433 (VALUE recv)
1434 (VALUE val)
1435 /* Same discussion as opt_aref. */
1436 // attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
1438 val = vm_opt_aref_with(recv, key);
1440 if (UNDEF_P(val)) {
1441 PUSH(rb_str_resurrect(key));
1442 CALL_SIMPLE_METHOD();
1446 /* optimized length */
1447 DEFINE_INSN
1448 opt_length
1449 (CALL_DATA cd)
1450 (VALUE recv)
1451 (VALUE val)
1453 val = vm_opt_length(recv, BOP_LENGTH);
1455 if (UNDEF_P(val)) {
1456 CALL_SIMPLE_METHOD();
1460 /* optimized size */
1461 DEFINE_INSN
1462 opt_size
1463 (CALL_DATA cd)
1464 (VALUE recv)
1465 (VALUE val)
1467 val = vm_opt_length(recv, BOP_SIZE);
1469 if (UNDEF_P(val)) {
1470 CALL_SIMPLE_METHOD();
1474 /* optimized empty? */
1475 DEFINE_INSN
1476 opt_empty_p
1477 (CALL_DATA cd)
1478 (VALUE recv)
1479 (VALUE val)
1481 val = vm_opt_empty_p(recv);
1483 if (UNDEF_P(val)) {
1484 CALL_SIMPLE_METHOD();
1488 /* optimized succ */
1489 DEFINE_INSN
1490 opt_succ
1491 (CALL_DATA cd)
1492 (VALUE recv)
1493 (VALUE val)
1495 val = vm_opt_succ(recv);
1497 if (UNDEF_P(val)) {
1498 CALL_SIMPLE_METHOD();
1502 /* optimized not */
1503 DEFINE_INSN
1504 opt_not
1505 (CALL_DATA cd)
1506 (VALUE recv)
1507 (VALUE val)
1509 val = vm_opt_not(GET_ISEQ(), cd, recv);
1511 if (UNDEF_P(val)) {
1512 CALL_SIMPLE_METHOD();
1516 /* optimized regexp match 2 */
1517 DEFINE_INSN
1518 opt_regexpmatch2
1519 (CALL_DATA cd)
1520 (VALUE obj2, VALUE obj1)
1521 (VALUE val)
1522 // attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
1524 val = vm_opt_regexpmatch2(obj2, obj1);
1526 if (UNDEF_P(val)) {
1527 CALL_SIMPLE_METHOD();
1531 /* call specific function with args */
1532 DEFINE_INSN
1533 invokebuiltin
1534 (RB_BUILTIN bf)
1535 (...)
1536 (VALUE val)
1537 // attr bool leaf = false; /* anything can happen inside */
1538 // attr rb_snum_t sp_inc = 1 - bf->argc;
1540 val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
1543 /* call specific function with args (same parameters) */
1544 DEFINE_INSN
1545 opt_invokebuiltin_delegate
1546 (RB_BUILTIN bf, rb_num_t index)
1548 (VALUE val)
1549 // attr bool leaf = false; /* anything can happen inside */
1551 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1554 /* call specific function with args (same parameters) and leave */
1555 DEFINE_INSN
1556 opt_invokebuiltin_delegate_leave
1557 (RB_BUILTIN bf, rb_num_t index)
1559 (VALUE val)
1560 // attr bool leaf = false; /* anything can happen inside */
1562 val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
1564 /* leave fastpath */
1565 /* TracePoint/return fallbacks this insn to opt_invokebuiltin_delegate */
1566 if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
1567 #if OPT_CALL_THREADED_CODE
1568 rb_ec_thread_ptr(ec)->retval = val;
1569 return 0;
1570 #else
1571 return val;
1572 #endif
1574 else {
1575 RESTORE_REGS();
1579 /* BLT */
1580 DEFINE_INSN_IF(SUPPORT_JOKE)
1581 bitblt
1584 (VALUE ret)
1586 ret = rb_str_new2("a bit of bacon, lettuce and tomato");
1589 /* The Answer to Life, the Universe, and Everything */
1590 DEFINE_INSN_IF(SUPPORT_JOKE)
1591 answer
1594 (VALUE ret)
1596 ret = INT2FIX(42);