mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	causes performance problem. Try vm1_swap benchmark. [ruby-dev:31522] * insns.def, insnhelper.ci: move process body of expandarray insn to vm_expandarray(). * bootstraptest/test_knownbug.rb, bootstraptest/test_massign.rb: move a solved test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			2103 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2103 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** ##skip -*- mode:c; style:ruby -*-
 | 
						|
  insns.def - YARV instruction definitions
 | 
						|
 | 
						|
  $Author: $
 | 
						|
  $Date: $
 | 
						|
  created at: 04/01/01 01:17:55 JST
 | 
						|
 | 
						|
  Copyright (C) 2004-2006 Koichi Sasada
 | 
						|
*/
 | 
						|
 | 
						|
/** ##skip
 | 
						|
  instruction comment
 | 
						|
  @c: category
 | 
						|
  @e: english description
 | 
						|
  @j: japanese description
 | 
						|
 | 
						|
  instruction form:
 | 
						|
    DEFINE_INSN
 | 
						|
    instrunction_name
 | 
						|
    (instruction_operands, ..)
 | 
						|
    (pop_values, ..)
 | 
						|
    (return value)
 | 
						|
    {
 | 
						|
       .. // insn body
 | 
						|
    }
 | 
						|
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  @c nop
 | 
						|
  @e nop
 | 
						|
  @j nop
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
nop
 | 
						|
()
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    /* none */
 | 
						|
}
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with variables                                    */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get local variable(which is pointed by idx).
 | 
						|
  @j idx で指定されたローカル変数をスタックに置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getlocal
 | 
						|
(lindex_t idx)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = *(GET_LFP() - idx);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get local variable (which is pointed by idx) as val.
 | 
						|
  @j idx で指定されたローカル変数を val にする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setlocal
 | 
						|
(lindex_t idx)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    (*(GET_LFP() - idx)) = val;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get special local variable ($~, $_, ..)
 | 
						|
  @j 特殊なローカル変数の値を得る
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getspecial
 | 
						|
(VALUE key, rb_num_t type)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = vm_getspecial(th, GET_LFP(), key, type);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e set special local variables
 | 
						|
  @j 特別なローカル変数を設定する
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setspecial
 | 
						|
(VALUE key)
 | 
						|
(VALUE obj)
 | 
						|
()
 | 
						|
{
 | 
						|
    lfp_svar_set(th, GET_LFP(), key, obj);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get block local variable(which is pointed by idx and level).
 | 
						|
     level means nest level of block, and specify how above this variable.
 | 
						|
  @j level, idx で指定されたブロックローカル変数の値をスタックに置く。
 | 
						|
     level はブロックのネストレベルで、何段上かを示す。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getdynamic
 | 
						|
(dindex_t idx, rb_num_t level)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    VALUE *dfp2 = GET_DFP();
 | 
						|
    for (i = 0; i < level; i++) {
 | 
						|
	dfp2 = GET_PREV_DFP(dfp2);
 | 
						|
    }
 | 
						|
    val = *(dfp2 - idx);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e set block local variable(which is pointed by 'idx') as val.
 | 
						|
     level means nest level of block, and specify how above this variable.
 | 
						|
  @j level, idx で指定されたブロックローカル変数の値を val にする。
 | 
						|
     level はブロックのネストレベルで、何段上かを示す。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setdynamic
 | 
						|
(dindex_t idx, rb_num_t level)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    VALUE *dfp2 = GET_DFP();
 | 
						|
    for (i = 0; i < level; i++) {
 | 
						|
	dfp2 = GET_PREV_DFP(dfp2);
 | 
						|
    }
 | 
						|
    *(dfp2 - idx) = val;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get instance variable id of obj.
 | 
						|
     if is_local is not 0, search as class local variable.
 | 
						|
  @j obj のインスタンス変数 id を得る。
 | 
						|
     もし is_local が !0 ならクラスローカル変数を得る
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getinstancevariable
 | 
						|
(ID id)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_ivar_get(GET_SELF(), id);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e set instance variable id of obj as val.
 | 
						|
     if is_local is not 0, search as class local variable.
 | 
						|
  @j obj のインスタンス変数を val にする。
 | 
						|
     もし is_local が !0 ならクラスローカル変数を得る
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setinstancevariable
 | 
						|
(ID id)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    rb_ivar_set(GET_SELF(), id, val);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get class variable id of klass as val.
 | 
						|
  @j klass のクラス変数 id を得る。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getclassvariable
 | 
						|
(ID id)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    VALUE klass = vm_get_cvar_base(th, GET_ISEQ());
 | 
						|
    val = rb_cvar_get(klass, id);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e set class variable id of klass as val.
 | 
						|
  @j klass のクラス変数 id を val にする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setclassvariable
 | 
						|
(ID id)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    rb_cvar_set(vm_get_cvar_base(th, GET_ISEQ()), id, val);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e
 | 
						|
   get constant variable id. if klass is Qnil, constant
 | 
						|
   are searched in current scope. if klass is Qfalse, constant as
 | 
						|
   top level constant. otherwise, get constant under klass
 | 
						|
   class or module.
 | 
						|
  @j
 | 
						|
   定数を得る。klass が Qnil なら、そのスコープで得られ
 | 
						|
   る定数を得る。Qfalse なら、トップレベルスコープを得る。
 | 
						|
   それ以外なら、klass クラスの下の定数を得る。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getconstant
 | 
						|
(ID id)
 | 
						|
(VALUE klass)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = vm_get_ev_const(th, GET_ISEQ(), klass, id, 0);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e
 | 
						|
   set constant variable id. if klass is Qfalse, constant
 | 
						|
   is able to access in this scope. if klass is Qnil, set
 | 
						|
   top level constant. otherwise, set constant under klass
 | 
						|
   class or module.
 | 
						|
 | 
						|
  @j
 | 
						|
   定数 id を val にする。klass が Qfalse なら、そのスコープ
 | 
						|
   で得られる定数を設定 id を設定する。Qnil なら、トップレベ
 | 
						|
   ルスコープを設定、それ以外なら、klass クラスの下の定数を
 | 
						|
   設定する。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setconstant
 | 
						|
(ID id)
 | 
						|
(VALUE val, VALUE klass)
 | 
						|
()
 | 
						|
{
 | 
						|
    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();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e get global variable id.
 | 
						|
  @j グローバル変数 id を得る。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getglobal
 | 
						|
(GENTRY entry)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = GET_GLOBAL(entry);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c variable
 | 
						|
  @e set global variable id as val.
 | 
						|
  @j グローバル変数 id を得る。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setglobal
 | 
						|
(GENTRY entry)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    SET_GLOBAL(entry, val);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with values                                       */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put nil
 | 
						|
  @j put nil
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
putnil
 | 
						|
()
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put self.
 | 
						|
  @j self を置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
putself
 | 
						|
()
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = GET_SELF();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put some object.
 | 
						|
     i.e. Fixnum, true, false, nil, and so on.
 | 
						|
  @j オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
putobject
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    /* */
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put string val. string will be copied.
 | 
						|
  @j 文字列を置く。文字列はコピーしとく。
 | 
						|
 */
 | 
						|
 | 
						|
DEFINE_INSN
 | 
						|
putstring
 | 
						|
(VALUE str)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_str_new3(str);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put concatenate strings
 | 
						|
  @j 文字列を連結して置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
concatstrings
 | 
						|
(rb_num_t num)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += 1 - num;
 | 
						|
{
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e to_str
 | 
						|
  @j to_str
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
tostring
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_obj_as_string(val);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e to Regexp
 | 
						|
  @j to Regexp
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
toregexp
 | 
						|
(rb_num_t flag)
 | 
						|
(VALUE str)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    volatile VALUE tmp = str; /* for GC */
 | 
						|
    val = rb_reg_new(RSTRING_PTR(str), RSTRING_LEN(str), flag);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put new array.
 | 
						|
  @j 新しい配列をスタック上の num 個の値で初期化して置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
newarray
 | 
						|
(rb_num_t num)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += 1 - num;
 | 
						|
{
 | 
						|
    val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
 | 
						|
    POPN(num);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e dup array
 | 
						|
  @j 配列を dup してスタックに置く
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
duparray
 | 
						|
(VALUE ary)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_ary_dup(ary);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e expand array to num objects.
 | 
						|
  @j スタックトップのオブジェクトが配列であれば、それを展開する。
 | 
						|
     配列オブジェクトの要素数が num以下ならば、代わりに nil を積む。num以上なら、
 | 
						|
     num以上の要素は切り捨てる。
 | 
						|
     配列オブジェクトでなければ、num - 1 個の nil を積む。
 | 
						|
     もし flag が真なら、残り要素の配列を積む
 | 
						|
     flag: 0x01 - 最後を配列に
 | 
						|
     flag: 0x02 - postarg 用
 | 
						|
     flag: 0x04 - reverse?
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
expandarray
 | 
						|
(rb_num_t num, rb_num_t flag)
 | 
						|
(..., VALUE ary)
 | 
						|
(...) // inc += flag == 0x02 ? num : ((num > 0) ? num - 1 + (flag ? 1 : 0) : num + 1 - (flag ? 1 : 0));
 | 
						|
{
 | 
						|
    vm_expandarray(GET_CFP(), ary, num, flag);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e concat two arrays
 | 
						|
  @j 二つの配列をとってきてくっつける
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
concatarray
 | 
						|
()
 | 
						|
(VALUE ary1, VALUE ary2st)
 | 
						|
(VALUE ary)
 | 
						|
{
 | 
						|
    VALUE ary2 = ary2st;
 | 
						|
    VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, "Array", "to_splat");
 | 
						|
    VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, "Array", "to_splat");
 | 
						|
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e splat array
 | 
						|
  @j splat array
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
splatarray
 | 
						|
(VALUE flag)
 | 
						|
(VALUE ary)
 | 
						|
(VALUE obj)
 | 
						|
{
 | 
						|
    VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat");
 | 
						|
    if (NIL_P(tmp)) {
 | 
						|
	tmp = rb_ary_new3(1, ary);
 | 
						|
    }
 | 
						|
    obj = tmp;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e check value is included in ary
 | 
						|
  @j 配列に要素が入っているかどうかチェック。case/when で使う
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
checkincludearray
 | 
						|
(VALUE flag)
 | 
						|
(VALUE obj, VALUE ary)
 | 
						|
(VALUE obj, VALUE result)
 | 
						|
{
 | 
						|
    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;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put new Hash.
 | 
						|
  @j Hash.new
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
newhash
 | 
						|
(rb_num_t num)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += 1 - num;
 | 
						|
{
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put new Range object.(Range.new(low, high, flag))
 | 
						|
  @j Range.new(low, high, flag) のようなオブジェクトを置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
newrange
 | 
						|
(rb_num_t flag)
 | 
						|
(VALUE low, VALUE high)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_range_new(low, high, flag);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c put
 | 
						|
  @e put !val.
 | 
						|
  @j !val であるオブジェクトを置く。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
putnot
 | 
						|
()
 | 
						|
(VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (RTEST(obj)) {
 | 
						|
	val = Qfalse;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	val = Qtrue;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with stack operation                              */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e pop from stack.
 | 
						|
  @j スタックから一つポップする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
pop
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    val = val;
 | 
						|
    /* none */
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e duplicate stack top.
 | 
						|
  @j スタックトップをコピーしてスタックにおく
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
dup
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
(VALUE val1, VALUE val2)
 | 
						|
{
 | 
						|
    val1 = val2 = val;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e duplicate stack top n elements
 | 
						|
  @j スタックトップから n 個をコピーしてスタックにおく
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
dupn
 | 
						|
(rb_num_t n)
 | 
						|
(...)
 | 
						|
(...) // inc += n;
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    VALUE *sp = STACK_ADDR_FROM_TOP(n);
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
	GET_SP()[i] = sp[i];
 | 
						|
    }
 | 
						|
    INC_SP(n);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e swap top 2 vals
 | 
						|
  @j スタックトップの2つを交換する。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
swap
 | 
						|
()
 | 
						|
(VALUE val, VALUE obj)
 | 
						|
(VALUE obj, VALUE val)
 | 
						|
{
 | 
						|
    /* none */
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e
 | 
						|
  @j
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
reput
 | 
						|
()
 | 
						|
(..., VALUE val)
 | 
						|
(VALUE val) // inc += 0;
 | 
						|
{
 | 
						|
    /* none */
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e get nth stack value from stack top
 | 
						|
  @j スタックトップから n 個目をスタックトップにコピー
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
topn
 | 
						|
(rb_num_t n)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += 1;
 | 
						|
{
 | 
						|
    val = TOPN(n);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e set Nth stack entry to stack top
 | 
						|
  @j スタックトップの値を n 個目のスタックにコピー
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setn
 | 
						|
(rb_num_t n)
 | 
						|
(..., VALUE val)
 | 
						|
(VALUE val) // inc += 0
 | 
						|
{
 | 
						|
    TOPN(n-1) = val;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c stack
 | 
						|
  @e empt current stack
 | 
						|
  @j current stack を空にする
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
emptstack
 | 
						|
()
 | 
						|
(...)
 | 
						|
(...) // inc = 0; depth = 0;
 | 
						|
{
 | 
						|
    SET_SP(GET_CFP()->bp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with setting                                      */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e define (singleton) method id as body
 | 
						|
  @j (特異)メソッド m を body として定義する。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
definemethod
 | 
						|
(ID id, ISEQ body, rb_num_t is_singleton)
 | 
						|
(VALUE obj)
 | 
						|
()
 | 
						|
{
 | 
						|
    vm_define_method(th, obj, id, body, is_singleton,
 | 
						|
		     get_cref(GET_ISEQ(), GET_LFP()));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e make alias (if v_p is Qtrue, make valias)
 | 
						|
  @j alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
alias
 | 
						|
(VALUE v_p, ID id1, ID id2)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    VALUE klass;
 | 
						|
 | 
						|
    if (v_p == Qtrue) {
 | 
						|
	rb_alias_variable(id1, id2);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
 | 
						|
	rb_alias(klass, id1, id2);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e undef
 | 
						|
  @j undef
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
undef
 | 
						|
(ID id)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    VALUE klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
 | 
						|
    rb_undef(klass, id);
 | 
						|
    INC_VM_STATE_VERSION();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e defined?
 | 
						|
  @j defined?
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
defined
 | 
						|
(rb_num_t type, VALUE obj, VALUE needstr)
 | 
						|
(VALUE v)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    VALUE klass;
 | 
						|
    char *expr_type = 0;
 | 
						|
    char buf[0x10];
 | 
						|
    
 | 
						|
    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_super_klass(ip->klass, GET_SELF());
 | 
						|
	      if (rb_method_boundp(klass, ip->defined_method_id, 0)) {
 | 
						|
		  expr_type = "super";
 | 
						|
	      }
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
      }
 | 
						|
      case DEFINED_REF:{
 | 
						|
	  int nth = FIX2INT(obj);
 | 
						|
	  VALUE backref = lfp_svar_get(th, GET_LFP(), 1);
 | 
						|
	  
 | 
						|
	  if (rb_reg_nth_match(nth, backref) != Qnil) {
 | 
						|
	      snprintf(buf, 0x10, "$%d", nth);
 | 
						|
	      expr_type = buf;
 | 
						|
	  }
 | 
						|
	  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;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e END{}
 | 
						|
  @j END{}
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
postexe
 | 
						|
(ISEQ blockiseq)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    rb_block_t *blockptr;
 | 
						|
    VALUE proc;
 | 
						|
 | 
						|
    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(call_end_proc, proc);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c setting
 | 
						|
  @e trace
 | 
						|
  @j trace
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
trace
 | 
						|
(rb_num_t nf)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    rb_event_flag_t flag = nf;
 | 
						|
    EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
 | 
						|
}
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with control flow 1: class/module                 */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c class/module
 | 
						|
  @e
 | 
						|
   enter class definition scope. if super is Qfalse, and clsas
 | 
						|
   "klass" is defined, it's redefine. otherwise, define "klass" class.
 | 
						|
  @j
 | 
						|
   クラス定義スコープへ移行する。もし super が Qfalse で klassクラスが
 | 
						|
   定義されていれば、再定義である。そうでなければ、klass クラスを定義する。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
defineclass
 | 
						|
(ID id, ISEQ klass_iseq, rb_num_t define_type)
 | 
						|
(VALUE cbase, VALUE super)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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(klass)->super);
 | 
						|
 | 
						|
		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);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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(klass_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC));
 | 
						|
 | 
						|
    /* enter scope */
 | 
						|
    vm_push_frame(th, klass_iseq,
 | 
						|
		  FRAME_MAGIC_CLASS, klass, (VALUE) GET_DFP() | 0x02,
 | 
						|
		  klass_iseq->iseq_encoded, GET_SP(), 0,
 | 
						|
		  klass_iseq->local_size);
 | 
						|
    RESTORE_REGS();
 | 
						|
 | 
						|
    INC_VM_STATE_VERSION();
 | 
						|
    NEXT_INSN();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with control flow 2: method/iterator              */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c method/iterator
 | 
						|
  @e obj.send(id, args..) # args.size => num
 | 
						|
  @j obj.send(id, args..) # args.size => num
 | 
						|
  flag & VM_CALL_ARGS_SPLAT_BIT    != 0 -> splat last arg
 | 
						|
  flag & VM_CALL_ARGS_BLOCKARG_BIT != 0 -> Proc as Block
 | 
						|
  flag & VM_CALL_FCALL_BIT         != 0 -> FCALL ( func() )
 | 
						|
  flag & VM_CALL_VCALL_BIT         != 0 -> VCALL ( func   )
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
send
 | 
						|
(ID op_id, rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag, IC ic)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += - (op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
 | 
						|
{
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c method/iterator
 | 
						|
  @e super(args) # args.size => num
 | 
						|
  @j super(args) # args.size => num
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
invokesuper
 | 
						|
(rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag)
 | 
						|
(...)
 | 
						|
(VALUE val) // inc += - op_argc;
 | 
						|
{
 | 
						|
    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_super_klass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
 | 
						|
    mn = rb_method_node(klass, id);
 | 
						|
 | 
						|
    CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c method/iterator
 | 
						|
  @e yield(args) # args.size => num, flag shows expand argument or not
 | 
						|
  @j yield(args) # args.size => num
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
invokeblock
 | 
						|
(rb_num_t num, rb_num_t flag)
 | 
						|
(...)
 | 
						|
(VALUE val)  // inc += 1 - num;
 | 
						|
{
 | 
						|
    val = vm_invoke_block(th, GET_CFP(), num, flag);
 | 
						|
    if (val == Qundef) {
 | 
						|
	RESTORE_REGS();
 | 
						|
	NEXT_INSN();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c method/iterator
 | 
						|
  @e return from this scope.
 | 
						|
  @j このスコープから抜ける。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
leave
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c method/iterator
 | 
						|
  @e return from this vm loop
 | 
						|
  @j VM loop から抜ける
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
finish
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
#if OPT_CALL_THREADED_CODE
 | 
						|
    rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
 | 
						|
#else
 | 
						|
    th->cfp++;
 | 
						|
    return val;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with control flow 3: exception                    */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c exception
 | 
						|
  @e longjump
 | 
						|
  @j longjump
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
throw
 | 
						|
(rb_num_t throw_state)
 | 
						|
(VALUE throwobj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    RUBY_VM_CHECK_INTS();
 | 
						|
    val = vm_throw(th, GET_CFP(), throw_state, throwobj);
 | 
						|
    THROW_EXCEPTION(val);
 | 
						|
    /* unreachable */
 | 
						|
}
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* deal with control flow 4: local jump                   */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c jump
 | 
						|
  @e set PC to (PC + dst).
 | 
						|
  @j PC を (PC + dst) にする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
jump
 | 
						|
(OFFSET dst)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    RUBY_VM_CHECK_INTS();
 | 
						|
    JUMP(dst);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c jump
 | 
						|
  @e if val is not false or nil, set PC to (PC + dst).
 | 
						|
  @j もし val が false か nil でなければ、PC を (PC + dst) にする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
branchif
 | 
						|
(OFFSET dst)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    if (RTEST(val)) {
 | 
						|
	RUBY_VM_CHECK_INTS();
 | 
						|
	JUMP(dst);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c jump
 | 
						|
  @e if val is false or nil, set PC to (PC + dst).
 | 
						|
  @j もし val が false か nil ならば、PC を (PC + dst) にする。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
branchunless
 | 
						|
(OFFSET dst)
 | 
						|
(VALUE val)
 | 
						|
()
 | 
						|
{
 | 
						|
    if (!RTEST(val)) {
 | 
						|
	RUBY_VM_CHECK_INTS();
 | 
						|
	JUMP(dst);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/* for optimize                                           */
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e inline cache
 | 
						|
  @j inline cache
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
getinlinecache
 | 
						|
(IC ic, OFFSET dst)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (ic->ic_vmstat == GET_VM_STATE_VERSION()) {
 | 
						|
	val = ic->ic_value;
 | 
						|
	JUMP(dst);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	/* none */
 | 
						|
	val = Qnil;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e inline cache (once)
 | 
						|
  @j inline cache (once)
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
onceinlinecache
 | 
						|
(IC ic, OFFSET dst)
 | 
						|
()
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (ic->ic_vmstat) {
 | 
						|
	val = ic->ic_value;
 | 
						|
	JUMP(dst);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	/* none */
 | 
						|
	val = Qnil;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e set inline cache
 | 
						|
  @j set inline cahce
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
setinlinecache
 | 
						|
(OFFSET dst)
 | 
						|
(VALUE val)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    IC ic = GET_CONST_INLINE_CACHE(dst);
 | 
						|
 | 
						|
    ic->ic_value = val;
 | 
						|
    ic->ic_vmstat = GET_VM_STATE_VERSION();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e case dispatcher
 | 
						|
  @j case dispatcher
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_case_dispatch
 | 
						|
(CDHASH hash, OFFSET else_offset)
 | 
						|
(..., VALUE key)
 | 
						|
() // inc += -1;
 | 
						|
{
 | 
						|
    if (0) {
 | 
						|
	/* if some === method is overrided */
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	VALUE val;
 | 
						|
	if (st_lookup(RHASH(hash)->tbl, key, &val)) {
 | 
						|
	    JUMP(FIX2INT(val));
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    JUMP(else_offset);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e check environment
 | 
						|
  @j check environment
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_checkenv
 | 
						|
()
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** simple functions */
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X+Y.
 | 
						|
  @j 最適化された X+Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_plus
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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 = rb_float_new(RFLOAT(recv)->value + RFLOAT(obj)->value);
 | 
						|
	}
 | 
						|
#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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X-Y.
 | 
						|
  @j 最適化された X-Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_minus
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X*Y.
 | 
						|
  @j 最適化された X*Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_mult
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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 = rb_float_new(RFLOAT(recv)->value * RFLOAT(obj)->value);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else {
 | 
						|
	    goto INSN_LABEL(normal_dispatch);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      INSN_LABEL(normal_dispatch):
 | 
						|
	PUSH(recv);
 | 
						|
	PUSH(obj);
 | 
						|
	CALL_SIMPLE_METHOD(1, idMULT, recv);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X/Y.
 | 
						|
  @j 最適化された X/Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_div
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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)
 | 
						|
		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 = 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 = rb_float_new(RFLOAT(recv)->value / RFLOAT(obj)->value);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	else {
 | 
						|
	    goto INSN_LABEL(normal_dispatch);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      INSN_LABEL(normal_dispatch):
 | 
						|
	PUSH(recv);
 | 
						|
	PUSH(obj);
 | 
						|
	CALL_SIMPLE_METHOD(1, idDIV, recv);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X%Y.
 | 
						|
  @j 最適化された X%Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_mod
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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(recv)->value;
 | 
						|
	    double y = RFLOAT(obj)->value;
 | 
						|
	    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 = rb_float_new(mod);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    goto INSN_LABEL(normal_dispatch);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      INSN_LABEL(normal_dispatch):
 | 
						|
	PUSH(recv);
 | 
						|
	PUSH(obj);
 | 
						|
	CALL_SIMPLE_METHOD(1, idMOD, recv);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X==Y.
 | 
						|
  @j 最適化された X==Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_eq
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (FIXNUM_2_P(recv, obj) &&
 | 
						|
	BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
 | 
						|
	long a = FIX2LONG(recv), b = FIX2LONG(obj);
 | 
						|
 | 
						|
	if (a == b) {
 | 
						|
	    val = Qtrue;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    val = Qfalse;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    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_EQ)) {
 | 
						|
	    double a = RFLOAT(recv)->value;
 | 
						|
	    double b = RFLOAT(obj)->value;
 | 
						|
 | 
						|
	    if (isnan(a) || isnan(b)) {
 | 
						|
		val = Qfalse;
 | 
						|
	    }
 | 
						|
	    else if (a == b) {
 | 
						|
		val = Qtrue;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		val = Qfalse;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else if (HEAP_CLASS_OF(recv) == rb_cString &&
 | 
						|
		 HEAP_CLASS_OF(obj) == rb_cString &&
 | 
						|
		 BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
 | 
						|
 | 
						|
	    VALUE str1 = recv;
 | 
						|
	    VALUE str2 = obj;
 | 
						|
	    if (str1 == str2) {
 | 
						|
		val = Qtrue;
 | 
						|
	    }
 | 
						|
	    else if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
 | 
						|
		     rb_memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2),
 | 
						|
			       RSTRING_LEN(str1)) == 0) {
 | 
						|
		val = Qtrue;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		val = Qfalse;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    goto INSN_LABEL(normal_dispatch);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      INSN_LABEL(normal_dispatch):
 | 
						|
	/* other */
 | 
						|
	PUSH(recv);
 | 
						|
	PUSH(obj);
 | 
						|
	CALL_SIMPLE_METHOD(1, idEq, recv);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X<Y.
 | 
						|
  @j 最適化された X<Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_lt
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X<=Y.
 | 
						|
  @j 最適化された X<=Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_le
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X>Y.
 | 
						|
  @j 最適化された X>Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_gt
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized X>=Y.
 | 
						|
  @j 最適化された X>=Y。
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_ge
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e <<
 | 
						|
  @j <<
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_ltlt
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e []
 | 
						|
  @j []
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_aref
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e recv[obj] = set
 | 
						|
  @j recv[obj] = set
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_aset
 | 
						|
()
 | 
						|
(VALUE recv, VALUE obj, VALUE set)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized length
 | 
						|
  @j optimized length
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_length
 | 
						|
()
 | 
						|
(VALUE recv)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (!SPECIAL_CONST_P(recv) &&
 | 
						|
	BASIC_OP_UNREDEFINED_P(BOP_LENGTH)) {
 | 
						|
	if (HEAP_CLASS_OF(recv) == rb_cArray) {
 | 
						|
	    val = LONG2NUM(RARRAY_LEN(recv));
 | 
						|
	}
 | 
						|
	else if (HEAP_CLASS_OF(recv) == rb_cString) {
 | 
						|
	    val = LONG2NUM(RSTRING_LEN(recv));
 | 
						|
	}
 | 
						|
	else if (HEAP_CLASS_OF(recv) == rb_cHash) {
 | 
						|
	    val = INT2FIX(RHASH(recv)->tbl->num_entries);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    goto INSN_LABEL(normal_dispatch);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      INSN_LABEL(normal_dispatch):
 | 
						|
	PUSH(recv);
 | 
						|
	CALL_SIMPLE_METHOD(0, idLength, recv);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized succ
 | 
						|
  @j optimized succ
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_succ
 | 
						|
()
 | 
						|
(VALUE recv)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized regexp match
 | 
						|
  @j 最適化された正規表現マッチ
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_regexpmatch1
 | 
						|
(VALUE r)
 | 
						|
(VALUE obj)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    val = rb_reg_match(r, obj);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e optimized regexp match 2
 | 
						|
  @j 最適化された正規表現マッチ 2
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_regexpmatch2
 | 
						|
()
 | 
						|
(VALUE obj2, VALUE obj1)
 | 
						|
(VALUE val)
 | 
						|
{
 | 
						|
    if (TYPE(obj2) == T_STRING) {
 | 
						|
	val = rb_reg_match(obj1, obj2);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	val = rb_funcall(obj2, idEqTilde, 1, obj1);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c optimize
 | 
						|
  @e call native compiled method
 | 
						|
  @j ネイティブコンパイルしたメソッドを kick
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
opt_call_c_function
 | 
						|
(rb_insn_func_t funcptr)
 | 
						|
()
 | 
						|
()
 | 
						|
{
 | 
						|
    reg_cfp = (funcptr)(th, reg_cfp);
 | 
						|
 | 
						|
    if (reg_cfp == 0) {
 | 
						|
	VALUE err = th->errinfo;
 | 
						|
	th->errinfo = Qnil;
 | 
						|
	THROW_EXCEPTION(err);
 | 
						|
    }
 | 
						|
 | 
						|
    RESTORE_REGS();
 | 
						|
    NEXT_INSN();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c joke
 | 
						|
  @e BLT
 | 
						|
  @j BLT
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
bitblt
 | 
						|
()
 | 
						|
()
 | 
						|
(VALUE ret)
 | 
						|
{
 | 
						|
    ret = rb_str_new2("a bit of bacon, lettuce and tomato");
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  @c joke
 | 
						|
  @e The Answer to Life, the Universe, and Everything
 | 
						|
  @j 人生、宇宙、すべての答え
 | 
						|
 */
 | 
						|
DEFINE_INSN
 | 
						|
answer
 | 
						|
()
 | 
						|
()
 | 
						|
(VALUE ret)
 | 
						|
{
 | 
						|
    ret = INT2FIX(42);
 | 
						|
}
 | 
						|
 |