YARV Instruction Set

Instruction Table

Category Opcode Name Operands
nop 0 nop
variable 1 getlocal idx
variable 2 setlocal idx
variable 3 getspecial key, type
variable 4 setspecial key
variable 5 getdynamic idx, level
variable 6 setdynamic idx, level
variable 7 getinstancevariable id
variable 8 setinstancevariable id
variable 9 getclassvariable id
variable 10 setclassvariable id
variable 11 getconstant id
variable 12 setconstant id
variable 13 getglobal entry
variable 14 setglobal entry
put 15 putnil
put 16 putself
put 17 putobject val
put 18 putstring str
put 19 concatstrings num
put 20 tostring
put 21 toregexp opt, cnt
put 22 newarray num
put 23 duparray ary
put 24 expandarray num, flag
put 25 concatarray
put 26 splatarray flag
put 27 checkincludearray flag
put 28 newhash num
put 29 newrange flag
stack 30 pop
stack 31 dup
stack 32 dupn n
stack 33 swap
stack 34 reput
stack 35 topn n
stack 36 setn n
stack 37 adjuststack n
setting 38 definemethod id, body, is_singleton
setting 39 alias v_p
setting 40 undef
setting 41 defined type, obj, needstr
setting 42 postexe blockiseq
setting 43 trace nf
class/module 44 defineclass id, class_iseq, define_type
method/iterator 45 send op_id, op_argc, blockiseq, op_flag, ic
method/iterator 46 invokesuper op_argc, blockiseq, op_flag
method/iterator 47 invokeblock num, flag
method/iterator 48 leave
method/iterator 49 finish
exception 50 throw throw_state
jump 51 jump dst
jump 52 branchif dst
jump 53 branchunless dst
optimize 54 getinlinecache ic, dst
optimize 55 onceinlinecache ic, dst
optimize 56 setinlinecache dst
optimize 57 opt_case_dispatch hash, else_offset
optimize 58 opt_checkenv
optimize 59 opt_plus
optimize 60 opt_minus
optimize 61 opt_mult
optimize 62 opt_div
optimize 63 opt_mod
optimize 64 opt_eq ic
optimize 65 opt_neq ic1, ic2
optimize 66 opt_lt
optimize 67 opt_le
optimize 68 opt_gt
optimize 69 opt_ge
optimize 70 opt_ltlt
optimize 71 opt_aref
optimize 72 opt_aset
optimize 73 opt_length
optimize 74 opt_succ
optimize 75 opt_not ic
optimize 76 opt_regexpmatch1 r
optimize 77 opt_regexpmatch2
optimize 78 opt_call_c_function funcptr
joke 79 bitblt
joke 80 answer

Detailed Description

opcode :0
category :nop
nop

Description

nop

Operands

Stack

BeforeAfter
=>

Source

    /* none */
opcode :1
category :variable
getlocal

Description

get local variable value (which is pointed by idx).

Operands

lindex_tidx

Stack

BeforeAfter
=>
VALUEval

Source

    val = *(GET_LFP() - idx);
opcode :2
category :variable
setlocal

Description

set local variable value (which is pointed by idx) as val.

Operands

lindex_tidx

Stack

BeforeAfter
VALUEval
=>

Source

    (*(GET_LFP() - idx)) = val;
opcode :3
category :variable
getspecial

Description

get special local variable ($~, $_, ..) value.

Operands

VALUEkey
rb_num_ttype

Stack

BeforeAfter
=>
VALUEval

Source

    val = vm_getspecial(th, GET_LFP(), key, type);
opcode :4
category :variable
setspecial

Description

set special local variable ($~, $_, ...) value as obj.

Operands

VALUEkey

Stack

BeforeAfter
VALUEobj
=>

Source

    lfp_svar_set(th, GET_LFP(), key, obj);
opcode :5
category :variable
getdynamic

Description

get block local variable(which is pointed by idx and level).

Operands

dindex_tidx
rb_num_tlevel

Stack

BeforeAfter
=>
VALUEval

Source

    int i;
    VALUE *dfp2 = GET_DFP();
    for (i = 0; i < level; i++) {
	dfp2 = GET_PREV_DFP(dfp2);
    }
    val = *(dfp2 - idx);
opcode :6
category :variable
setdynamic

Description

set block local variable(which is pointed by 'idx') as val.

Operands

dindex_tidx
rb_num_tlevel

Stack

BeforeAfter
VALUEval
=>

Source

    int i;
    VALUE *dfp2 = GET_DFP();
    for (i = 0; i < level; i++) {
	dfp2 = GET_PREV_DFP(dfp2);
    }
    *(dfp2 - idx) = val;
opcode :7
category :variable
getinstancevariable

Description

get instance variable id of obj.

Operands

IDid

Stack

BeforeAfter
=>
VALUEval

Source

    val = rb_ivar_get(GET_SELF(), id);
opcode :8
category :variable
setinstancevariable

Description

set instance variable id of obj as val.

Operands

IDid

Stack

BeforeAfter
VALUEval
=>

Source

    rb_ivar_set(GET_SELF(), id, val);
opcode :9
category :variable
getclassvariable

Description

get class variable id of klass as val.

Operands

IDid

Stack

BeforeAfter
=>
VALUEval

Source

    val = rb_cvar_get(vm_get_cvar_base(th, GET_ISEQ()), id);
opcode :10
category :variable
setclassvariable

Description

set class variable id of klass as val.

Operands

IDid

Stack

BeforeAfter
VALUEval
=>

Source

    rb_cvar_set(vm_get_cvar_base(th, GET_ISEQ()), id, val);
opcode :11
category :variable
getconstant

Description

Operands

IDid

Stack

BeforeAfter
VALUEklass
=>
VALUEval

Source

    val = vm_get_ev_const(th, GET_ISEQ(), klass, id, 0);
opcode :12
category :variable
setconstant

Description

Operands

IDid

Stack

BeforeAfter
VALUEklass
VALUEval
=>

Source

    if (klass == Qnil) {
	klass = vm_get_cbase(th);
    }
    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class/module to define constant");
    }

    switch (TYPE(klass)) {
      case T_CLASS:
      case T_MODULE:
	break;
      default: {
	volatile VALUE tmp = rb_obj_as_string(klass);
	rb_raise(rb_eTypeError, "%s is not a class/module",
		 RSTRING_PTR(tmp));
      }
    }

    rb_const_set(klass, id, val);
    INC_VM_STATE_VERSION();
opcode :13
category :variable
getglobal

Description

get global variable id.

Operands

GENTRYentry

Stack

BeforeAfter
=>
VALUEval

Source

    val = GET_GLOBAL(entry);
opcode :14
category :variable
setglobal

Description

set global variable id as val.

Operands

GENTRYentry

Stack

BeforeAfter
VALUEval
=>

Source

    SET_GLOBAL(entry, val);
opcode :15
category :put
putnil

Description

put nil to stack.

Operands

Stack

BeforeAfter
=>
VALUEval

Source

    val = Qnil;
opcode :16
category :put
putself

Description

put self.

Operands

Stack

BeforeAfter
=>
VALUEval

Source

    val = GET_SELF();
opcode :17
category :put
putobject

Description

put some object.

Operands

VALUEval

Stack

BeforeAfter
=>
VALUEval

Source

    /* */
opcode :18
category :put
putstring

Description

put string val. string will be copied.

Operands

VALUEstr

Stack

BeforeAfter
=>
VALUEval

Source

    val = rb_str_new3(str);
opcode :19
category :put
concatstrings

Description

put concatenate strings

Operands

rb_num_tnum

Stack

BeforeAfter
......
=>
VALUEval

Source

    int i;
    VALUE v;

    val = rb_str_new(0, 0);
    for (i = num - 1; i >= 0; i--) {
	v = TOPN(i);
	rb_str_append(val, v);
    }
    POPN(num);
opcode :20
category :put
tostring

Description

to_str

Operands

Stack

BeforeAfter
VALUEval
=>
VALUEval

Source

    val = rb_obj_as_string(val);
opcode :21
category :put
toregexp

Description

to Regexp

Operands

rb_num_topt
rb_num_tcnt

Stack

BeforeAfter
......
=>
VALUEval

Source

    VALUE rb_reg_new_ary(VALUE ary, int options);
    int i;
    VALUE ary = rb_ary_new2(cnt);
    RBASIC(ary)->klass = 0;
    for (i = 0; i < cnt; i++) {
        rb_ary_store(ary, cnt-i-1, TOPN(i));
    }
    POPN(cnt);
    val = rb_reg_new_ary(ary, opt);
opcode :22
category :put
newarray

Description

put new array.

Operands

rb_num_tnum

Stack

BeforeAfter
......
=>
VALUEval

Source

    val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
    POPN(num);
opcode :23
category :put
duparray

Description

dup array

Operands

VALUEary

Stack

BeforeAfter
=>
VALUEval

Source

    val = rb_ary_dup(ary);
opcode :24
category :put
expandarray

Description

expand array to num objects.

Operands

rb_num_tnum
rb_num_tflag

Stack

BeforeAfter
VALUEary
......
=>
......

Source

    vm_expandarray(GET_CFP(), ary, num, flag);
opcode :25
category :put
concatarray

Description

concat two arrays

Operands

Stack

BeforeAfter
VALUEary2st
VALUEary1
=>
VALUEary

Source

    VALUE ary2 = ary2st;
    VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, "Array", "to_a");
    VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, "Array", "to_a");

    if (NIL_P(tmp1)) {
	tmp1 = rb_ary_new3(1, ary1);
    }

    if (NIL_P(tmp2)) {
	tmp2 = rb_ary_new3(1, ary2);
    }

    if (tmp1 == ary1) {
	tmp1 = rb_ary_dup(ary1);
    }
    ary = rb_ary_concat(tmp1, tmp2);
opcode :26
category :put
splatarray

Description

splat array

Operands

VALUEflag

Stack

BeforeAfter
VALUEary
=>
VALUEobj

Source

    VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
    if (NIL_P(tmp)) {
	tmp = rb_ary_new3(1, ary);
    }
    obj = tmp;
opcode :27
category :put
checkincludearray

Description

check value is included in ary

Operands

VALUEflag

Stack

BeforeAfter
VALUEary
VALUEobj
=>
VALUEresult
VALUEobj

Source

    int i;
    result = Qfalse;

    if (TYPE(ary) != T_ARRAY) {
	ary = rb_Array(ary);
    }

    if (flag == Qtrue) {
	/* NODE_CASE */
	for (i = 0; i < RARRAY_LEN(ary); i++) {
	    /* TODO: fix me (use another method dispatch) */
	    if (RTEST(rb_funcall2(RARRAY_PTR(ary)[i], idEqq, 1, &obj))) {
		result = Qtrue;
		break;
	    }
	}
    }
    else {
	obj = Qfalse;
	/* NODE_WHEN */
	for (i = 0; i < RARRAY_LEN(ary); i++) {
	    if (RTEST(RARRAY_PTR(ary)[i])) {
		obj = result = Qtrue;
		break;
	    }
	}
    }
opcode :28
category :put
newhash

Description

put new Hash.

Operands

rb_num_tnum

Stack

BeforeAfter
......
=>
VALUEval

Source

    int i;
    VALUE k, v;
    val = rb_hash_new();

    for (i = num; i > 0; i -= 2) {
	v = TOPN(i - 2);
	k = TOPN(i - 1);
	rb_hash_aset(val, k, v);
    }
    POPN(num);
opcode :29
category :put
newrange

Description

put new Range object.(Range.new(low, high, flag))

Operands

rb_num_tflag

Stack

BeforeAfter
VALUEhigh
VALUElow
=>
VALUEval

Source

    val = rb_range_new(low, high, flag);
opcode :30
category :stack
pop

Description

pop from stack.

Operands

Stack

BeforeAfter
VALUEval
=>

Source

    val = val;
    /* none */
opcode :31
category :stack
dup

Description

duplicate stack top.

Operands

Stack

BeforeAfter
VALUEval
=>
VALUEval2
VALUEval1

Source

    val1 = val2 = val;
opcode :32
category :stack
dupn

Description

duplicate stack top n elements

Operands

rb_num_tn

Stack

BeforeAfter
......
=>
......

Source

    int i;
    VALUE *sp = STACK_ADDR_FROM_TOP(n);
    for (i = 0; i < n; i++) {
	GET_SP()[i] = sp[i];
    }
    INC_SP(n);
opcode :33
category :stack
swap

Description

swap top 2 vals

Operands

Stack

BeforeAfter
VALUEobj
VALUEval
=>
VALUEval
VALUEobj

Source

    /* none */
opcode :34
category :stack
reput

Description

for stack caching.

Operands

Stack

BeforeAfter
VALUEval
......
=>
VALUEval

Source

    /* none */
opcode :35
category :stack
topn

Description

get nth stack value from stack top

Operands

rb_num_tn

Stack

BeforeAfter
......
=>
VALUEval

Source

    val = TOPN(n);
opcode :36
category :stack
setn

Description

set Nth stack entry to stack top

Operands

rb_num_tn

Stack

BeforeAfter
VALUEval
......
=>
VALUEval

Source

    TOPN(n-1) = val;
opcode :37
category :stack
adjuststack

Description

empt current stack

Operands

rb_num_tn

Stack

BeforeAfter
......
=>
......

Source

    DEC_SP(n);
opcode :38
category :setting
definemethod

Description

define (singleton) method id as body

Operands

IDid
ISEQbody
rb_num_tis_singleton

Stack

BeforeAfter
VALUEobj
=>

Source

    vm_define_method(th, obj, id, body, is_singleton,
		     get_cref(GET_ISEQ(), GET_LFP()));
opcode :39
category :setting
alias

Description

make alias (if v_p is Qtrue, make valias)

Operands

VALUEv_p

Stack

BeforeAfter
VALUEsym2
VALUEsym1
=>

Source

    VALUE klass;

    if (v_p == Qtrue) {
	rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
    }
    else {
	klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
	rb_alias(klass, SYM2ID(sym1), SYM2ID(sym2));
    }
opcode :40
category :setting
undef

Description

undef

Operands

Stack

BeforeAfter
VALUEsym
=>

Source

    VALUE klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
    rb_undef(klass, SYM2ID(sym));
    INC_VM_STATE_VERSION();
opcode :41
category :setting
defined

Description

defined?

Operands

rb_num_ttype
VALUEobj
VALUEneedstr

Stack

BeforeAfter
VALUEv
=>
VALUEval

Source

    VALUE klass;
    char *expr_type = 0;
    val = Qnil;

    switch (type) {
      case DEFINED_IVAR:
	if (rb_ivar_defined(GET_SELF(), SYM2ID(obj))) {
	    expr_type = "instance-variable";
	}
	break;
      case DEFINED_IVAR2:
	klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
	break;
      case DEFINED_GVAR:
	if (rb_gvar_defined((struct global_entry *)(obj & ~1))) {
	    expr_type = "global-variable";
	}
	break;
      case DEFINED_CVAR:
	klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
	if (rb_cvar_defined(klass, SYM2ID(obj))) {
	    expr_type = "class variable";
	}
	break;
      case DEFINED_CONST:
	klass = v;
	if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) {
	    expr_type = "constant";
	}
	break;
      case DEFINED_FUNC:
	klass = CLASS_OF(v);
	if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
	    expr_type = "method";
	}
	break;
      case DEFINED_METHOD:{
	  VALUE klass = CLASS_OF(v);
	  NODE *method = (NODE *) rb_method_node(klass, SYM2ID(obj));

	  if (method) {
	      if (!(method->nd_noex & NOEX_PRIVATE)) {
		  if (!((method->nd_noex & NOEX_PROTECTED) &&
			!rb_obj_is_kind_of(GET_SELF(),
					   rb_class_real(klass)))) {
		      expr_type = "method";
		  }
	      }
	  }
	  break;
      }
      case DEFINED_YIELD:
	if (GET_BLOCK_PTR()) {
	    expr_type = "yield";
	}
	break;
      case DEFINED_ZSUPER:{
	  rb_iseq_t *ip = GET_ISEQ();
	  while (ip) {
	      if (ip->defined_method_id) {
		  break;
	      }
	      ip = ip->parent_iseq;
	  }
	  if (ip) {
	      VALUE klass = vm_search_normal_superclass(ip->klass, GET_SELF());
	      if (rb_method_boundp(klass, ip->defined_method_id, 0)) {
		  expr_type = "super";
	      }
	  }
	  break;
      }
      case DEFINED_REF:{
	  val = vm_getspecial(th, GET_LFP(), Qfalse, FIX2INT(obj));
	  if (val != Qnil) {
	      expr_type = "global-variable";
	  }
	  break;
      }
      default:
	rb_bug("unimplemented defined? type (VM)");
	break;
    }
    if (expr_type != 0) {
	if (needstr != Qfalse) {
	    val = rb_str_new2(expr_type);
	}
	else {
	    val = Qtrue;
	}
    }
opcode :42
category :setting
postexe

Description

END{}

Operands

ISEQblockiseq

Stack

BeforeAfter
=>

Source

    rb_block_t *blockptr;
    VALUE proc;
    extern void rb_call_end_proc(VALUE data);

    blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(GET_CFP());
    blockptr->iseq = blockiseq;
    blockptr->proc = 0;

    proc = vm_make_proc(th, GET_CFP(), blockptr);
    rb_set_end_proc(rb_call_end_proc, proc);
opcode :43
category :setting
trace

Description

trace

Operands

rb_num_tnf

Stack

BeforeAfter
=>

Source

    rb_event_flag_t flag = nf;
    EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
opcode :44
category :class/module
defineclass

Description

Operands

IDid
ISEQclass_iseq
rb_num_tdefine_type

Stack

BeforeAfter
VALUEsuper
VALUEcbase
=>
VALUEval

Source

    VALUE klass;

    switch ((int)define_type) {
      case 0:
	/* val is dummy.  classdef returns class scope value */

	if (super == Qnil) {
	    super = rb_cObject;
	}

	if (cbase == Qnil) {
	    cbase = vm_get_cbase(th);
	}

	vm_check_if_namespace(cbase);

	/* find klass */
	if (rb_const_defined_at(cbase, id)) {
	    /* already exist */
	    klass = rb_const_get_at(cbase, id);
	    if (TYPE(klass) != T_CLASS) {
		rb_raise(rb_eTypeError, "%s is not a class", rb_id2name(id));
	    }

	    if (super != rb_cObject) {
		VALUE tmp;
		tmp = rb_class_real(RCLASS_SUPER(klass));

		if (tmp != super) {
		    rb_raise(rb_eTypeError, "superclass mismatch for class %s",
			     rb_id2name(id));
		}
	    }
	}
	else {
	    /* new class declaration */
	    klass = rb_define_class_id(id, super);
	    rb_set_class_path(klass, cbase, rb_id2name(id));
	    rb_const_set(cbase, id, klass);
	    rb_class_inherited(super, klass);
	}
	break;
      case 1:
	/* val is dummy.  classdef returns class scope value */
	/* super is dummy */
	klass = rb_singleton_class(cbase);
	break;
      case 2:
	/* val is dummy.  classdef returns class scope value */
	/* super is dummy */
	if (cbase == Qnil) {
	    cbase = vm_get_cbase(th);
	}

	vm_check_if_namespace(cbase);

	/* find klass */
	if (rb_const_defined_at(cbase, id)) {
	    klass = rb_const_get_at(cbase, id);
	    /* already exist */
	    if (TYPE(klass) != T_MODULE) {
		rb_raise(rb_eTypeError, "%s is not a module", rb_id2name(id));
	    }
	}
	else {
	    /* new module declaration */
	    klass = rb_define_module_id(id);
	    rb_set_class_path(klass, cbase, rb_id2name(id));
	    rb_const_set(cbase, id, klass);
	}
	break;
      default:
	rb_bug("unknown defineclass type: %d", (int)define_type);
    }

    COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC));

    /* enter scope */
    vm_push_frame(th, class_iseq,
		  FRAME_MAGIC_CLASS, klass, (VALUE) GET_DFP() | 0x02,
		  class_iseq->iseq_encoded, GET_SP(), 0,
		  class_iseq->local_size);
    RESTORE_REGS();

    INC_VM_STATE_VERSION();
    NEXT_INSN();
opcode :45
category :method/iterator
send

Description

obj.send(id, args..) # args.size => num

Operands

IDop_id
rb_num_top_argc
ISEQblockiseq
rb_num_top_flag
ICic

Stack

BeforeAfter
......
=>
VALUEval

Source

    NODE *mn;
    VALUE recv, klass;
    rb_block_t *blockptr = 0;
    rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, op_argc,
				     (rb_iseq_t *)blockiseq, &blockptr);
    rb_num_t flag = op_flag;
    ID id = op_id;

    /* get receiver */
    recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
    klass = CLASS_OF(recv);
    mn = vm_method_search(id, klass, ic);

    /* send/funcall optimization */
    if (flag & VM_CALL_SEND_BIT) {
	vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass);
    }

    CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
opcode :46
category :method/iterator
invokesuper

Description

super(args) # args.size => num

Operands

rb_num_top_argc
ISEQblockiseq
rb_num_top_flag

Stack

BeforeAfter
......
=>
VALUEval

Source

    rb_block_t *blockptr = !(op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? GET_BLOCK_PTR() : 0;
    int num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr);
    VALUE recv, klass;
    NODE *mn;
    ID id;
    const VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;

    recv = GET_SELF();
    vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
    mn = rb_method_node(klass, id);

    CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
opcode :47
category :method/iterator
invokeblock

Description

yield(args) # args.size => num, flag shows expand argument or not

Operands

rb_num_tnum
rb_num_tflag

Stack

BeforeAfter
......
=>
VALUEval

Source

    val = vm_invoke_block(th, GET_CFP(), num, flag);
    if (val == Qundef) {
	RESTORE_REGS();
	NEXT_INSN();
    }
opcode :48
category :method/iterator
leave

Description

return from this scope.

Operands

Stack

BeforeAfter
VALUEval
=>
VALUEval

Source

    if (OPT_CHECKED_RUN) {
	if (reg_cfp->sp != reg_cfp->bp) {
	    rb_bug("Stack consistency error (sp: %d, bp: %d)",
		   VM_SP_CNT(th, reg_cfp->sp), VM_SP_CNT(th, reg_cfp->bp));
	}
    }

    RUBY_VM_CHECK_INTS();
    vm_pop_frame(th);
    RESTORE_REGS();
opcode :49
category :method/iterator
finish

Description

return from this vm loop

Operands

Stack

BeforeAfter
VALUEval
=>
VALUEval

Source

#if OPT_CALL_THREADED_CODE
    rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
#else
    th->cfp++;
    return val;
#endif
opcode :50
category :exception
throw

Description

longjump

Operands

rb_num_tthrow_state

Stack

BeforeAfter
VALUEthrowobj
=>
VALUEval

Source

    RUBY_VM_CHECK_INTS();
    val = vm_throw(th, GET_CFP(), throw_state, throwobj);
    THROW_EXCEPTION(val);
    /* unreachable */
opcode :51
category :jump
jump

Description

set PC to (PC + dst).

Operands

OFFSETdst

Stack

BeforeAfter
=>

Source

    RUBY_VM_CHECK_INTS();
    JUMP(dst);
opcode :52
category :jump
branchif

Description

if val is not false or nil, set PC to (PC + dst).

Operands

OFFSETdst

Stack

BeforeAfter
VALUEval
=>

Source

    if (RTEST(val)) {
	RUBY_VM_CHECK_INTS();
	JUMP(dst);
    }
opcode :53
category :jump
branchunless

Description

if val is false or nil, set PC to (PC + dst).

Operands

OFFSETdst

Stack

BeforeAfter
VALUEval
=>

Source

    if (!RTEST(val)) {
	RUBY_VM_CHECK_INTS();
	JUMP(dst);
    }
opcode :54
category :optimize
getinlinecache

Description

inline cache

Operands

ICic
OFFSETdst

Stack

BeforeAfter
=>
VALUEval

Source

    if (ic->ic_vmstat == GET_VM_STATE_VERSION()) {
	val = ic->ic_value;
	JUMP(dst);
    }
    else {
	/* none */
	val = Qnil;
    }
opcode :55
category :optimize
onceinlinecache

Description

inline cache (once)

Operands

ICic
OFFSETdst

Stack

BeforeAfter
=>
VALUEval

Source

    if (ic->ic_vmstat) {
	val = ic->ic_value;
	JUMP(dst);
    }
    else {
	/* none */
	val = Qnil;
    }
opcode :56
category :optimize
setinlinecache

Description

set inline cache

Operands

OFFSETdst

Stack

BeforeAfter
VALUEval
=>
VALUEval

Source

    IC ic = GET_CONST_INLINE_CACHE(dst);

    ic->ic_value = val;
    ic->ic_vmstat = GET_VM_STATE_VERSION();
opcode :57
category :optimize
opt_case_dispatch

Description

case dispatcher

Operands

CDHASHhash
OFFSETelse_offset

Stack

BeforeAfter
VALUEkey
......
=>

Source

    if (0) {
	/* TODO: if some === method is overrided */
    }
    else {
	VALUE val;
	if (st_lookup(RHASH_TBL(hash), key, &val)) {
	    JUMP(FIX2INT(val));
	}
	else {
	    JUMP(else_offset);
	}
    }
opcode :58
category :optimize
opt_checkenv

Description

check environment

Operands

Stack

BeforeAfter
=>

Source

    if (GET_CFP()->bp != GET_DFP() + 1) {
	VALUE *new_dfp = GET_CFP()->bp - 1;
	/* TODO: copy env and clean stack at creating env? */
	*new_dfp = *GET_DFP();
	SET_DFP(new_dfp);
    }
opcode :59
category :optimize
opt_plus

Description

optimized X+Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (0) {

    }
#if 1
    else if (FIXNUM_2_P(recv, obj) &&
	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
	/* fixnum + fixnum */
#ifndef LONG_LONG_VALUE
	val = (recv + (obj & (~1)));
	if ((~(recv ^ obj) & (recv ^ val)) &
	    ((VALUE)0x01 << ((sizeof(VALUE) * CHAR_BIT) - 1))) {
	    val = rb_big_plus(rb_int2big(FIX2LONG(recv)),
			      rb_int2big(FIX2LONG(obj)));
	}
#else
	long a, b, c;
	a = FIX2LONG(recv);
	b = FIX2LONG(obj);
	c = a + b;
	if (FIXABLE(c)) {
	    val = LONG2FIX(c);
	}
	else {
	    val = rb_big_plus(rb_int2big(a), rb_int2big(b));
	}
#endif
    }
#endif

    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
	if (0) {
	}
#if 1
	else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
		 HEAP_CLASS_OF(obj) == rb_cFloat &&
		 BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
	    val = DOUBLE2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
	}
#endif

#if 1
	else if (HEAP_CLASS_OF(recv) == rb_cString &&
		 HEAP_CLASS_OF(obj) == rb_cString &&
		 BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
	    val = rb_str_plus(recv, obj);
	}
#endif
#if 1
	else if (HEAP_CLASS_OF(recv) == rb_cArray &&
		 BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
	    val = rb_ary_plus(recv, obj);
	}
#endif
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idPLUS, recv);
    }
opcode :60
category :optimize
opt_minus

Description

optimized X-Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_MINUS)) {
	long a, b, c;

	a = FIX2LONG(recv);
	b = FIX2LONG(obj);
	c = a - b;

	if (FIXABLE(c)) {
	    val = LONG2FIX(c);
	}
	else {
	    val = rb_big_minus(rb_int2big(a), rb_int2big(b));
	}
    }
    else {
	/* other */
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idMINUS, recv);
    }
opcode :61
category :optimize
opt_mult

Description

optimized X*Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_MULT)) {
	long a, b, c;

	a = FIX2LONG(recv);
	if (a == 0) {
	    val = recv;
	}
	else {
	    b = FIX2LONG(obj);
	    c = a * b;

	    if (FIXABLE(c) && c / a == b) {
		val = LONG2FIX(c);
	    }
	    else {
		val = rb_big_mul(rb_int2big(a), rb_int2big(b));
	    }
	}
    }
    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
	if (0) {
	}
#if 1
	else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
		 HEAP_CLASS_OF(obj) == rb_cFloat  &&
		 BASIC_OP_UNREDEFINED_P(BOP_MULT)) {
	    val = DOUBLE2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
	}
#endif
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idMULT, recv);
    }
opcode :62
category :optimize
opt_div

Description

optimized X/Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_DIV)) {
	long x, y, div;

	x = FIX2LONG(recv);
	y = FIX2LONG(obj);
	{
	    /* copied from numeric.c#fixdivmod */
	    long mod;
	    if (y == 0)
		goto INSN_LABEL(normal_dispatch);
	    if (y < 0) {
		if (x < 0)
		    div = -x / -y;
		else
		    div = -(x / -y);
	    }
	    else {
		if (x < 0)
		    div = -(-x / y);
		else
		    div = x / y;
	    }
	    mod = x - div * y;
	    if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
		mod += y;
		div -= 1;
	    }
	}
	val = LONG2NUM(div);
    }
    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
	if (0) {
	}
#if 1
	else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
		 HEAP_CLASS_OF(obj) == rb_cFloat  &&
		 BASIC_OP_UNREDEFINED_P(BOP_DIV)) {
	    val = DOUBLE2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
	}
#endif
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idDIV, recv);
    }
opcode :63
category :optimize
opt_mod

Description

optimized X%Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_MOD)) {
	long x, y, mod;

	x = FIX2LONG(recv);
	y = FIX2LONG(obj);
	{
	    /* copied from numeric.c#fixdivmod */
	    long div;

	    if (y == 0)
		rb_num_zerodiv();
	    if (y < 0) {
		if (x < 0)
		    div = -x / -y;
		else
		    div = -(x / -y);
	    }
	    else {
		if (x < 0)
		    div = -(-x / y);
		else
		    div = x / y;
	    }
	    mod = x - div * y;
	    if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
		mod += y;
		div -= 1;
	    }
	}
	val = LONG2FIX(mod);
    }
    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
	if (0) {
	}
	else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
		 HEAP_CLASS_OF(obj) == rb_cFloat &&
		 BASIC_OP_UNREDEFINED_P(BOP_MOD)) {
	    double x = RFLOAT_VALUE(recv);
	    double y = RFLOAT_VALUE(obj);
	    double div, mod;

	    {
		double z;

		modf(x / y, &z);
		mod = x - z * y;
	    }

	    div = (x - mod) / y;
	    if (y * mod < 0) {
		mod += y;
		div -= 1.0;
	    }
	    val = DOUBLE2NUM(mod);
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idMOD, recv);
    }
opcode :64
category :optimize
opt_eq

Description

optimized X==Y.

Operands

ICic

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    val = opt_eq_func(recv, obj, ic);

    if (val == Qundef) {
	/* other */
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idEq, recv);
    }
opcode :65
category :optimize
opt_neq

Description

optimized X!=Y.

Operands

ICic1
ICic2

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
    NODE *mn = vm_method_search(idNeq, CLASS_OF(recv), ic1);
    val = Qundef;

    if (check_cfunc(mn, rb_obj_not_equal)) {
	val = opt_eq_func(recv, obj, ic2);

	if (val != Qundef) {
	    val = RTEST(val) ? Qfalse : Qtrue;
	}
    }

    if (val == Qundef) {
	/* other */
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idNeq, recv);
    }
opcode :66
category :optimize
opt_lt

Description

optimized X

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_LT)) {
	long a = FIX2LONG(recv), b = FIX2LONG(obj);

	if (a < b) {
	    val = Qtrue;
	}
	else {
	    val = Qfalse;
	}
    }
    else {
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idLT, recv);
    }
opcode :67
category :optimize
opt_le

Description

optimized X<=Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_LE)) {
	long a = FIX2LONG(recv), b = FIX2LONG(obj);

	if (a <= b) {
	    val = Qtrue;
	}
	else {
	    val = Qfalse;
	}
    }
    else {
	/* other */
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idLE, recv);
    }
opcode :68
category :optimize
opt_gt

Description

optimized X>Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_GT)) {
	long a = FIX2LONG(recv), b = FIX2LONG(obj);

	if (a > b) {
	    val = Qtrue;
	}
	else {
	    val = Qfalse;
	}
    }
    else {
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idGT, recv);
    }
opcode :69
category :optimize
opt_ge

Description

optimized X>=Y.

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (FIXNUM_2_P(recv, obj) &&
	BASIC_OP_UNREDEFINED_P(BOP_GE)) {
	long a = FIX2LONG(recv), b = FIX2LONG(obj);

	if (a >= b) {
	    val = Qtrue;
	}
	else {
	    val = Qfalse;
	}
    }
    else {
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idGE, recv);
    }
opcode :70
category :optimize
opt_ltlt

Description

<<

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (!SPECIAL_CONST_P(recv)) {
	if (0) {
	}
	else if (HEAP_CLASS_OF(recv) == rb_cString &&
		 BASIC_OP_UNREDEFINED_P(BOP_LTLT)) {
	    val = rb_str_concat(recv, obj);
	}
	else if (HEAP_CLASS_OF(recv) == rb_cArray &&
		 BASIC_OP_UNREDEFINED_P(BOP_LTLT)) {
	    val = rb_ary_push(recv, obj);
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idLTLT, recv);
    }
opcode :71
category :optimize
opt_aref

Description

[]

Operands

Stack

BeforeAfter
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (!SPECIAL_CONST_P(recv) && BASIC_OP_UNREDEFINED_P(BOP_AREF)) {
	if (HEAP_CLASS_OF(recv) == rb_cArray && FIXNUM_P(obj)) {
	    val = rb_ary_entry(recv, FIX2LONG(obj));
	}
	else if (HEAP_CLASS_OF(recv) == rb_cHash) {
	    val = rb_hash_aref(recv, obj);
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	CALL_SIMPLE_METHOD(1, idAREF, recv);
    }
opcode :72
category :optimize
opt_aset

Description

recv[obj] = set

Operands

Stack

BeforeAfter
VALUEset
VALUEobj
VALUErecv
=>
VALUEval

Source

    if (!SPECIAL_CONST_P(recv) &&
	BASIC_OP_UNREDEFINED_P(BOP_ASET)) {
	if (HEAP_CLASS_OF(recv) == rb_cArray && FIXNUM_P(obj)) {
	    rb_ary_store(recv, FIX2LONG(obj), set);
	    val = set;
	}
	else if (HEAP_CLASS_OF(recv) == rb_cHash) {
	    rb_hash_aset(recv, obj, set);
	    val = set;
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	PUSH(obj);
	PUSH(set);
	CALL_SIMPLE_METHOD(2, idASET, recv);
    }
opcode :73
category :optimize
opt_length

Description

optimized length

Operands

Stack

BeforeAfter
VALUErecv
=>
VALUEval

Source

    if (!SPECIAL_CONST_P(recv) &&
	BASIC_OP_UNREDEFINED_P(BOP_LENGTH)) {
	if (HEAP_CLASS_OF(recv) == rb_cString) {
	    val = rb_str_length(recv);
	}
	else if (HEAP_CLASS_OF(recv) == rb_cArray) {
	    val = LONG2NUM(RARRAY_LEN(recv));
	}
	else if (HEAP_CLASS_OF(recv) == rb_cHash) {
	    val = INT2FIX(RHASH_SIZE(recv));
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	CALL_SIMPLE_METHOD(0, idLength, recv);
    }
opcode :74
category :optimize
opt_succ

Description

optimized succ

Operands

Stack

BeforeAfter
VALUErecv
=>
VALUEval

Source

    if (SPECIAL_CONST_P(recv)) {
	if (FIXNUM_P(recv) &&
	    BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
	    const VALUE obj = INT2FIX(1);
	    /* fixnum + INT2FIX(1) */
	    val = (recv + (obj & (~1)));
	    if ((~(recv ^ obj) & (recv ^ val)) & ((unsigned long)LONG_MAX + 1)) {
		val = rb_big_plus(rb_int2big(FIX2LONG(recv)),
				  rb_int2big(FIX2LONG(obj)));
	    }
	}
	else {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    else {
	if (HEAP_CLASS_OF(recv) == rb_cString &&
	    BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
	    val = rb_str_succ(recv);
	}
	else if (HEAP_CLASS_OF(recv) == rb_cTime &&
		 BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
	    val = rb_time_succ(recv);
	}
	else
	  {
	    goto INSN_LABEL(normal_dispatch);
	}
    }
    if (0) {
      INSN_LABEL(normal_dispatch):
	PUSH(recv);
	CALL_SIMPLE_METHOD(0, idSucc, recv);
    }
opcode :75
category :optimize
opt_not

Description

optimized not

Operands

ICic

Stack

BeforeAfter
VALUErecv
=>
VALUEval

Source

    extern VALUE rb_obj_not(VALUE obj);
    NODE *mn = vm_method_search(idNot, CLASS_OF(recv), ic);

    if (check_cfunc(mn, rb_obj_not)) {
	val = RTEST(recv) ? Qfalse : Qtrue;
    }
    else {
	PUSH(recv);
	CALL_SIMPLE_METHOD(0, idNot, recv);
    }
opcode :76
category :optimize
opt_regexpmatch1

Description

optimized regexp match

Operands

VALUEr

Stack

BeforeAfter
VALUEobj
=>
VALUEval

Source

    val = rb_reg_match(r, obj);
opcode :77
category :optimize
opt_regexpmatch2

Description

optimized regexp match 2

Operands

Stack

BeforeAfter
VALUEobj1
VALUEobj2
=>
VALUEval

Source

    if (TYPE(obj2) == T_STRING) {
	val = rb_reg_match(obj1, obj2);
    }
    else {
	val = rb_funcall(obj2, idEqTilde, 1, obj1);
    }
opcode :78
category :optimize
opt_call_c_function

Description

call native compiled method

Operands

rb_insn_func_tfuncptr

Stack

BeforeAfter
=>

Source

    reg_cfp = (funcptr)(th, reg_cfp);

    if (reg_cfp == 0) {
	VALUE err = th->errinfo;
	th->errinfo = Qnil;
	THROW_EXCEPTION(err);
    }

    RESTORE_REGS();
    NEXT_INSN();
opcode :79
category :joke
bitblt

Description

BLT

Operands

Stack

BeforeAfter
=>
VALUEret

Source

    ret = rb_str_new2("a bit of bacon, lettuce and tomato");
opcode :80
category :joke
answer

Description

The Answer to Life, the Universe, and Everything

Operands

Stack

BeforeAfter
=>
VALUEret

Source

    ret = INT2FIX(42);