From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001
From: Jari Vetoniemi <jari.vetoniemi@indooratlas.com>
Date: Mon, 16 Mar 2020 18:49:26 +0900
Subject: Fresh start

---
 jni/ruby/insns.def | 2235 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2235 insertions(+)
 create mode 100644 jni/ruby/insns.def

(limited to 'jni/ruby/insns.def')

diff --git a/jni/ruby/insns.def b/jni/ruby/insns.def
new file mode 100644
index 0000000..eae0b8e
--- /dev/null
+++ b/jni/ruby/insns.def
@@ -0,0 +1,2235 @@
+/** ##skip -*- mode:c; style:ruby; coding: utf-8 -*-
+  insns.def - YARV instruction definitions
+
+  $Author: $
+  created at: 04/01/01 01:17:55 JST
+
+  Copyright (C) 2004-2007 Koichi Sasada
+*/
+
+/** ##skip
+  instruction comment
+  @c: category
+  @e: english description
+  @j: japanese description
+
+  instruction form:
+    DEFINE_INSN
+    instruction_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 (pointed by `idx' and `level').
+     'level' indicates the nesting depth from the current block.
+  @j level, idx で指定されたローカル変数の値をスタックに置く。
+     level はブロックのネストレベルで、何段上かを示す。
+ */
+DEFINE_INSN
+getlocal
+(lindex_t idx, rb_num_t level)
+()
+(VALUE val)
+{
+    int i, lev = (int)level;
+    VALUE *ep = GET_EP();
+
+    /* optimized insns generated for level == (0|1) in defs/opt_operand.def */
+    for (i = 0; i < lev; i++) {
+	ep = GET_PREV_EP(ep);
+    }
+    val = *(ep - idx);
+}
+
+/**
+  @c variable
+  @e Set a local variable (pointed to by 'idx') as val.
+     'level' indicates the nesting depth from the current block.
+  @j level, idx で指定されたローカル変数の値を val にする。
+     level はブロックのネストレベルで、何段上かを示す。
+ */
+DEFINE_INSN
+setlocal
+(lindex_t idx, rb_num_t level)
+(VALUE val)
+()
+{
+    int i, lev = (int)level;
+    VALUE *ep = GET_EP();
+
+    /* optimized insns generated for level == (0|1) in defs/opt_operand.def */
+    for (i = 0; i < lev; i++) {
+	ep = GET_PREV_EP(ep);
+    }
+    *(ep - idx) = val;
+}
+
+/**
+  @c variable
+  @e Get value of special local variable ($~, $_, ..).
+  @j 特殊なローカル変数（$~, $_, ...）の値を得る。
+ */
+DEFINE_INSN
+getspecial
+(rb_num_t key, rb_num_t type)
+()
+(VALUE val)
+{
+    val = vm_getspecial(th, GET_LEP(), key, type);
+}
+
+/**
+  @c variable
+  @e Set value of special local variable ($~, $_, ...) to obj.
+  @j 特別なローカル変数（$~, $_, ...）の値を設定する。
+ */
+DEFINE_INSN
+setspecial
+(rb_num_t key)
+(VALUE obj)
+()
+{
+    lep_svar_set(th, GET_LEP(), key, obj);
+}
+
+/**
+  @c variable
+  @e Get value of instance variable id of self.
+     If is_local is not 0, get value of class local variable.
+  @j self のインスタンス変数 id の値を得る。
+ */
+DEFINE_INSN
+getinstancevariable
+(ID id, IC ic)
+()
+(VALUE val)
+{
+    val = vm_getinstancevariable(GET_SELF(), id, ic);
+}
+
+/**
+  @c variable
+  @e Set value of instance variable id of self to val.
+     If is_local is not 0, set value of class local variable.
+  @j self のインスタンス変数 id を val にする。
+ */
+DEFINE_INSN
+setinstancevariable
+(ID id, IC ic)
+(VALUE val)
+()
+{
+    vm_setinstancevariable(GET_SELF(), id, val, ic);
+}
+
+/**
+  @c variable
+  @e Get value of class variable id of klass as val.
+  @j 現在のスコープのクラス変数 id の値を得る。
+ */
+DEFINE_INSN
+getclassvariable
+(ID id)
+()
+(VALUE val)
+{
+    NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+    val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
+}
+
+/**
+  @c variable
+  @e Set value of class variable id of klass as val.
+  @j klass のクラス変数 id を val にする。
+ */
+DEFINE_INSN
+setclassvariable
+(ID id)
+(VALUE val)
+()
+{
+    NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+    rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
+}
+
+/**
+  @c variable
+  @e
+   Get constant variable id. If klass is Qnil, constants
+   are searched in the current scope. If klass is Qfalse, constants
+   are searched as top level constants. Otherwise, get constant under klass
+   class or module.
+  @j 定数 id の値を得る。
+   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 cbase)
+()
+{
+    vm_check_if_namespace(cbase);
+    rb_const_set(cbase, id, val);
+}
+
+/**
+  @c variable
+  @e get global variable id.
+  @j グローバル変数 id の値を得る。
+ */
+DEFINE_INSN
+getglobal
+(GENTRY entry)
+()
+(VALUE val)
+{
+    val = GET_GLOBAL((VALUE)entry);
+}
+
+/**
+  @c variable
+  @e set global variable id as val.
+  @j グローバル変数 id の値を設定する。
+ */
+DEFINE_INSN
+setglobal
+(GENTRY entry)
+(VALUE val)
+()
+{
+    SET_GLOBAL((VALUE)entry, val);
+}
+
+
+/**********************************************************/
+/* deal with values                                       */
+/**********************************************************/
+
+/**
+  @c put
+  @e put nil to stack.
+  @j スタックに 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 オブジェクト val をスタックにプッシュする。
+     i.e. Fixnum, true, false, nil, and so on.
+ */
+DEFINE_INSN
+putobject
+(VALUE val)
+()
+(VALUE val)
+{
+    /* */
+}
+
+/**
+  @c put
+  @e put special object.  "value_type" is for expansion.
+  @j 特別なオブジェクト val をスタックにプッシュする。
+     オブジェクトの種類は value_type による．
+ */
+DEFINE_INSN
+putspecialobject
+(rb_num_t value_type)
+()
+(VALUE val)
+{
+    enum vm_special_object_type type = (enum vm_special_object_type)value_type;
+
+    switch (type) {
+      case VM_SPECIAL_OBJECT_VMCORE:
+	val = rb_mRubyVMFrozenCore;
+	break;
+      case VM_SPECIAL_OBJECT_CBASE:
+	val = vm_get_cbase(GET_ISEQ(), GET_EP());
+	break;
+      case VM_SPECIAL_OBJECT_CONST_BASE:
+	val = vm_get_const_base(GET_ISEQ(), GET_EP());
+	break;
+      default:
+	rb_bug("putspecialobject insn: unknown value_type");
+    }
+}
+
+/**
+  @c put
+  @e put iseq value.
+  @j put iseq value.
+ */
+DEFINE_INSN
+putiseq
+(ISEQ iseq)
+()
+(VALUE ret)
+{
+    ret = iseq->self;
+}
+
+/**
+  @c put
+  @e put string val. string will be copied.
+  @j 文字列をコピーしてスタックにプッシュする。
+ */
+DEFINE_INSN
+putstring
+(VALUE str)
+()
+(VALUE val)
+{
+    val = rb_str_resurrect(str);
+}
+
+/**
+  @c put
+  @e put concatenate strings
+  @j スタックトップの文字列を n 個連結し，結果をスタックにプッシュする。
+ */
+DEFINE_INSN
+concatstrings
+(rb_num_t num)
+(...)
+(VALUE val) // inc += 1 - num;
+{
+    rb_num_t i = num - 1;
+
+    val = rb_str_resurrect(TOPN(i));
+    while (i-- > 0) {
+	const VALUE 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 文字列 str を正規表現にコンパイルしてスタックにプッシュする。
+     コンパイル時，opt を正規表現のオプションとする。
+ */
+DEFINE_INSN
+toregexp
+(rb_num_t opt, rb_num_t cnt)
+(...)
+(VALUE val) // inc += 1 - cnt;
+{
+    VALUE rb_reg_new_ary(VALUE ary, int options);
+    rb_num_t i;
+    const VALUE ary = rb_ary_tmp_new(cnt);
+    for (i = 0; i < cnt; i++) {
+        rb_ary_store(ary, cnt-i-1, TOPN(i));
+    }
+    POPN(cnt);
+    val = rb_reg_new_ary(ary, (int)opt);
+    rb_ary_clear(ary);
+}
+
+/**
+  @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 配列 ary を dup してスタックにプッシュする。
+ */
+DEFINE_INSN
+duparray
+(VALUE ary)
+()
+(VALUE val)
+{
+    val = rb_ary_resurrect(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 += num - 1 + (flag & 1 ? 1 : 0);
+{
+    vm_expandarray(GET_CFP(), ary, num, (int)flag);
+}
+
+/**
+  @c put
+  @e concat two arrays
+  @j 二つの配列 ary1, ary2 を連結しスタックへプッシュする。
+ */
+DEFINE_INSN
+concatarray
+()
+(VALUE ary1, VALUE ary2st)
+(VALUE ary)
+{
+    const 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);
+}
+
+/**
+  @c put
+  @e splat array
+  @j 配列 ary に対して to_a を呼び出す。
+ */
+DEFINE_INSN
+splatarray
+(VALUE flag)
+(VALUE ary)
+(VALUE obj)
+{
+    VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
+    if (NIL_P(tmp)) {
+	tmp = rb_ary_new3(1, ary);
+    }
+    else if (RTEST(flag)) {
+	tmp = rb_ary_dup(tmp);
+    }
+    obj = tmp;
+}
+
+/**
+  @c put
+  @e put new Hash.
+  @j 新しいハッシュをスタックトップの n 個を初期値として生成する。
+     n はキーと値のペアなので 2 の倍数でなければならない。
+ */
+DEFINE_INSN
+newhash
+(rb_num_t num)
+(...)
+(VALUE val) // inc += 1 - num;
+{
+    rb_num_t i;
+
+    if(RUBY_DTRACE_HASH_CREATE_ENABLED()) {
+	RUBY_DTRACE_HASH_CREATE(num, rb_sourcefile(), rb_sourceline());
+    }
+
+    val = rb_hash_new();
+
+    for (i = num; i > 0; i -= 2) {
+	const VALUE v = TOPN(i - 2);
+	const VALUE 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, (int)flag);
+}
+
+/**********************************************************/
+/* deal with stack operation                              */
+/**********************************************************/
+
+/**
+  @c stack
+  @e pop from stack.
+  @j スタックから一つポップする。
+ */
+DEFINE_INSN
+pop
+()
+(VALUE val)
+()
+{
+    (void)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;
+{
+    rb_num_t 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 for stack caching.
+  @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
+adjuststack
+(rb_num_t n)
+(...)
+(...) // inc -= n
+{
+    DEC_SP(n);
+}
+
+
+/**********************************************************/
+/* deal with setting                                      */
+/**********************************************************/
+
+/**
+  @c setting
+  @e defined?
+  @j defined? を行う。
+ */
+DEFINE_INSN
+defined
+(rb_num_t op_type, VALUE obj, VALUE needstr)
+(VALUE v)
+(VALUE val)
+{
+    VALUE klass;
+    enum defined_type expr_type = 0;
+    enum defined_type type = (enum defined_type)op_type;
+
+    val = Qnil;
+
+    switch (type) {
+      case DEFINED_IVAR:
+	if (rb_ivar_defined(GET_SELF(), SYM2ID(obj))) {
+	    expr_type = DEFINED_IVAR;
+	}
+	break;
+      case DEFINED_IVAR2:
+	klass = vm_get_cbase(GET_ISEQ(), GET_EP());
+	break;
+      case DEFINED_GVAR:
+	if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) {
+	    expr_type = DEFINED_GVAR;
+	}
+	break;
+      case DEFINED_CVAR: {
+	NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+	klass = vm_get_cvar_base(cref, GET_CFP());
+	if (rb_cvar_defined(klass, SYM2ID(obj))) {
+	    expr_type = DEFINED_CVAR;
+	}
+	break;
+      }
+      case DEFINED_CONST:
+	klass = v;
+	if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) {
+	    expr_type = DEFINED_CONST;
+	}
+	break;
+      case DEFINED_FUNC:
+	klass = CLASS_OF(v);
+	if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
+	    expr_type = DEFINED_METHOD;
+	}
+	break;
+      case DEFINED_METHOD:{
+	VALUE klass = CLASS_OF(v);
+	const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
+
+	if (me) {
+	    if (!(me->flag & NOEX_PRIVATE)) {
+		if (!((me->flag & NOEX_PROTECTED) &&
+		      !rb_obj_is_kind_of(GET_SELF(),
+					 rb_class_real(klass)))) {
+		    expr_type = DEFINED_METHOD;
+		}
+	    }
+	}
+	{
+	    VALUE args[2];
+	    VALUE r;
+
+	    args[0] = obj; args[1] = Qfalse;
+	    r = rb_check_funcall(v, idRespond_to_missing, 2, args);
+	    if (r != Qundef && RTEST(r))
+		expr_type = DEFINED_METHOD;
+	}
+	break;
+      }
+      case DEFINED_YIELD:
+	if (GET_BLOCK_PTR()) {
+	    expr_type = DEFINED_YIELD;
+	}
+	break;
+      case DEFINED_ZSUPER:{
+	rb_call_info_t cit;
+	if (vm_search_superclass(GET_CFP(), GET_ISEQ(), Qnil, &cit) == 0) {
+	    VALUE klass = cit.klass;
+	    ID id = cit.mid;
+	    if (rb_method_boundp(klass, id, 0)) {
+		expr_type = DEFINED_ZSUPER;
+	    }
+	}
+	break;
+      }
+      case DEFINED_REF:{
+	val = vm_getspecial(th, GET_LEP(), Qfalse, FIX2INT(obj));
+	if (val != Qnil) {
+	    expr_type = DEFINED_GVAR;
+	}
+	break;
+      }
+      default:
+	rb_bug("unimplemented defined? type (VM)");
+	break;
+    }
+    if (expr_type != 0) {
+	if (needstr != Qfalse) {
+	    val = rb_iseq_defined_string(expr_type);
+	}
+	else {
+	    val = Qtrue;
+	}
+    }
+}
+
+/**
+  @c setting
+  @e check `target' matches `pattern'.
+     `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
+      VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
+      VM_CHECKMATCH_TYPE_CASE: check `patten === target'.
+      VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_op?(Module) && pattern == target'.
+     if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns.
+  @j see above comments.
+ */
+DEFINE_INSN
+checkmatch
+(rb_num_t flag)
+(VALUE target, VALUE pattern)
+(VALUE result)
+{
+    enum vm_check_match_type checkmatch_type =
+      (enum vm_check_match_type)(flag & VM_CHECKMATCH_TYPE_MASK);
+    result = Qfalse;
+
+    if (flag & VM_CHECKMATCH_ARRAY) {
+	int i;
+	for (i = 0; i < RARRAY_LEN(pattern); i++) {
+	    if (RTEST(check_match(RARRAY_AREF(pattern, i), target, checkmatch_type))) {
+		result = Qtrue;
+		break;
+	    }
+	}
+    }
+    else {
+	if (RTEST(check_match(pattern, target, checkmatch_type))) {
+	    result = Qtrue;
+	}
+    }
+}
+
+/**
+  @c setting
+  @e check keywords are specified or not.
+  @j キーワードが指定されているかどうかチェックする
+ */
+DEFINE_INSN
+checkkeyword
+(lindex_t kw_bits_index, rb_num_t keyword_index)
+()
+(VALUE ret)
+{
+    const VALUE *ep = GET_EP();
+    const VALUE kw_bits = *(ep - kw_bits_index);
+
+    if (FIXNUM_P(kw_bits)) {
+	int bits = FIX2INT(kw_bits);
+	ret = (bits & (0x01 << keyword_index)) ? Qfalse : Qtrue;
+    }
+    else {
+	assert(RB_TYPE_P(kw_bits, T_HASH));
+	ret = rb_hash_has_key(kw_bits, INT2FIX(keyword_index)) ? Qfalse : Qtrue;
+    }
+}
+
+/**
+  @c setting
+  @e trace
+  @j trace 用の命令。
+ */
+DEFINE_INSN
+trace
+(rb_num_t nf)
+()
+()
+{
+    rb_event_flag_t flag = (rb_event_flag_t)nf;
+
+    if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() ||
+        RUBY_DTRACE_METHOD_RETURN_ENABLED() ||
+        RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() ||
+        RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) {
+
+        switch(flag) {
+          case RUBY_EVENT_CALL:
+            RUBY_DTRACE_METHOD_ENTRY_HOOK(th, 0, 0);
+            break;
+          case RUBY_EVENT_C_CALL:
+            RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, 0, 0);
+            break;
+          case RUBY_EVENT_RETURN:
+            RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0);
+            break;
+          case RUBY_EVENT_C_RETURN:
+            RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, 0, 0);
+            break;
+        }
+    }
+
+    EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* id and klass are resolved at callee */,
+		    (flag & (RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN)) ? TOPN(0) : Qundef);
+}
+
+/**********************************************************/
+/* deal with control flow 1: class/module                 */
+/**********************************************************/
+
+/**
+  @c class/module
+  @e
+   enter class definition scope. if super is Qfalse, and class
+   "klass" is defined, it's redefine. otherwise, define "klass" class.
+  @j クラス定義スコープへ移行する。
+   もし super が Qfalse で klassクラスが定義されていれば再定義である。
+   そうでなければ、klass クラスを定義する。
+ */
+DEFINE_INSN
+defineclass
+(ID id, ISEQ class_iseq, rb_num_t flags)
+(VALUE cbase, VALUE super)
+(VALUE val)
+{
+    VALUE klass;
+    rb_vm_defineclass_type_t type = VM_DEFINECLASS_TYPE(flags);
+
+    switch (type) {
+      case VM_DEFINECLASS_TYPE_CLASS:
+	/* val is dummy.  classdef returns class scope value */
+
+	if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) &&
+	    !RB_TYPE_P(super, T_CLASS)) {
+	    rb_raise(rb_eTypeError, "superclass must be a Class (%s given)",
+		     rb_obj_classname(super));
+	}
+
+	if (super == Qnil) {
+	    super = rb_cObject;
+	}
+
+	vm_check_if_namespace(cbase);
+
+	/* find klass */
+	rb_autoload_load(cbase, id);
+	if ((klass = vm_search_const_defined_class(cbase, id)) != 0) {
+	    /* already exist */
+	    klass = VM_DEFINECLASS_SCOPED_P(flags) ?
+		rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id);
+	    if (!RB_TYPE_P(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_string(klass, cbase, rb_id2str(id));
+	    rb_const_set(cbase, id, klass);
+	    rb_class_inherited(super, klass);
+	}
+	break;
+      case VM_DEFINECLASS_TYPE_SINGLETON_CLASS:
+	/* val is dummy.  classdef returns class scope value */
+	/* super is dummy */
+	klass = rb_singleton_class(cbase);
+	break;
+      case VM_DEFINECLASS_TYPE_MODULE:
+	/* val is dummy.  classdef returns class scope value */
+	/* super is dummy */
+
+	vm_check_if_namespace(cbase);
+
+	/* find klass */
+	if ((klass = vm_search_const_defined_class(cbase, id)) != 0) {
+	    klass = VM_DEFINECLASS_SCOPED_P(flags) ?
+		rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id);
+	    /* already exist */
+	    if (!RB_TYPE_P(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_string(klass, cbase, rb_id2str(id));
+	    rb_const_set(cbase, id, klass);
+	}
+	break;
+      default:
+	rb_bug("unknown defineclass type: %d", (int)type);
+    }
+
+    COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC, NULL));
+
+    /* enter scope */
+    vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
+		  klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
+		  class_iseq->iseq_encoded, GET_SP(),
+		  class_iseq->local_size, 0, class_iseq->stack_max);
+    RESTORE_REGS();
+    NEXT_INSN();
+}
+
+
+/**********************************************************/
+/* deal with control flow 2: method/iterator              */
+/**********************************************************/
+
+/**
+  @c method/iterator
+  @e invoke method.
+  @j メソッド呼び出しを行う。ci に必要な情報が格納されている。
+ */
+DEFINE_INSN
+send
+(CALL_INFO ci)
+(...)
+(VALUE val) // inc += - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0));
+{
+    ci->argc = ci->orig_argc;
+    vm_caller_setup_arg_block(th, reg_cfp, ci, FALSE);
+    vm_search_method(ci, ci->recv = TOPN(ci->argc));
+    CALL_METHOD(ci);
+}
+
+DEFINE_INSN
+opt_str_freeze
+(VALUE str)
+()
+(VALUE val)
+{
+    if (BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
+	val = str;
+    }
+    else {
+	val = rb_funcall(rb_str_resurrect(str), idFreeze, 0);
+    }
+}
+
+/**
+  @c optimize
+  @e Invoke method without block
+  @j Invoke method without block
+ */
+DEFINE_INSN
+opt_send_without_block
+(CALL_INFO ci)
+(...)
+(VALUE val) // inc += -ci->orig_argc;
+{
+    ci->argc = ci->orig_argc;
+    vm_search_method(ci, ci->recv = TOPN(ci->argc));
+    CALL_METHOD(ci);
+}
+
+/**
+  @c method/iterator
+  @e super(args) # args.size => num
+  @j super を実行する。ci に必要な情報が格納されている。
+ */
+DEFINE_INSN
+invokesuper
+(CALL_INFO ci)
+(...)
+(VALUE val) // inc += - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0));
+{
+    ci->argc = ci->orig_argc;
+    vm_caller_setup_arg_block(th, reg_cfp, ci, TRUE);
+    ci->recv = GET_SELF();
+    vm_search_super_method(th, GET_CFP(), ci);
+    CALL_METHOD(ci);
+}
+
+/**
+  @c method/iterator
+  @e yield(args)
+  @j yield を実行する。
+ */
+DEFINE_INSN
+invokeblock
+(CALL_INFO ci)
+(...)
+(VALUE val)  // inc += 1 - ci->orig_argc;
+{
+    ci->argc = ci->orig_argc;
+    ci->blockptr = 0;
+    ci->recv = GET_SELF();
+    val = vm_invoke_block(th, GET_CFP(), ci);
+    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 != vm_base_ptr(reg_cfp)) {
+	    rb_bug("Stack consistency error (sp: %"PRIdPTRDIFF", bp: %"PRIdPTRDIFF")",
+		   VM_SP_CNT(th, reg_cfp->sp), VM_SP_CNT(th, vm_base_ptr(reg_cfp)));
+	}
+    }
+
+    RUBY_VM_CHECK_INTS(th);
+
+    if (UNLIKELY(VM_FRAME_TYPE_FINISH_P(GET_CFP()))) {
+	vm_pop_frame(th);
+
+#if OPT_CALL_THREADED_CODE
+	th->retval = val;
+	return 0;
+#else
+	return val;
+#endif
+    }
+    else {
+	vm_pop_frame(th);
+	RESTORE_REGS();
+    }
+}
+
+/**********************************************************/
+/* deal with control flow 3: exception                    */
+/**********************************************************/
+
+/**
+  @c exception
+  @e longjump
+  @j 大域ジャンプを行う。
+ */
+DEFINE_INSN
+throw
+(rb_num_t throw_state)
+(VALUE throwobj)
+(VALUE val)
+{
+    RUBY_VM_CHECK_INTS(th);
+    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(th);
+    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(th);
+	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(th);
+	JUMP(dst);
+    }
+}
+
+
+/**********************************************************/
+/* for optimize                                           */
+/**********************************************************/
+
+/**
+  @c optimize
+  @e push inline-cached value and go to dst if it is valid
+  @j インラインキャッシュが有効なら、値をスタックにプッシュして dst へジャンプする。
+ */
+DEFINE_INSN
+getinlinecache
+(OFFSET dst, IC ic)
+()
+(VALUE val)
+{
+    if (ic->ic_serial == GET_GLOBAL_CONSTANT_STATE()) {
+	val = ic->ic_value.value;
+	JUMP(dst);
+    }
+    else {
+	/* none */
+	val = Qnil;
+    }
+}
+
+/**
+  @c optimize
+  @e set inline cache
+  @j インラインキャッシュの値を設定する。
+ */
+DEFINE_INSN
+setinlinecache
+(IC ic)
+(VALUE val)
+(VALUE val)
+{
+    if (ic->ic_value.value == Qundef) {
+	rb_iseq_add_mark_object(GET_ISEQ(), val);
+    }
+    ic->ic_value.value = val;
+    ic->ic_serial = GET_GLOBAL_CONSTANT_STATE() - ruby_vm_const_missing_count;
+    ruby_vm_const_missing_count = 0;
+}
+
+/**
+  @c optimize
+  @e run iseq only once
+  @j once を実現する。
+ */
+DEFINE_INSN
+once
+(ISEQ iseq, IC ic)
+()
+(VALUE val)
+{
+    union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)ic;
+
+#define RUNNING_THREAD_ONCE_DONE ((rb_thread_t *)(0x1))
+  retry:
+    if (is->once.running_thread == RUNNING_THREAD_ONCE_DONE) {
+	val = is->once.value;
+    }
+    else if (is->once.running_thread == NULL) {
+	is->once.running_thread = th;
+	val = is->once.value = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is);
+	/* is->once.running_thread is cleared by vm_once_clear() */
+	is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */
+	rb_iseq_add_mark_object(GET_ISEQ(), val);
+    }
+    else if (is->once.running_thread == th) {
+	/* recursive once */
+	val = vm_once_exec((VALUE)iseq);
+    }
+    else {
+	/* waiting for finish */
+	RUBY_VM_CHECK_INTS(th);
+	rb_thread_schedule();
+	goto retry;
+    }
+}
+
+/**
+  @c optimize
+  @e case dispatcher, jump by table if possible
+  @j case 文で、可能なら表引きでジャンプする。
+ */
+DEFINE_INSN
+opt_case_dispatch
+(CDHASH hash, OFFSET else_offset)
+(..., VALUE key)
+() // inc += -1;
+{
+    switch(TYPE(key)) {
+      case T_FLOAT: {
+	double ival;
+	if (modf(RFLOAT_VALUE(key), &ival) == 0.0) {
+	    key = FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
+	}
+      }
+      case T_SYMBOL: /* fall through */
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_STRING:
+	if (BASIC_OP_UNREDEFINED_P(BOP_EQQ,
+				   SYMBOL_REDEFINED_OP_FLAG |
+				   FIXNUM_REDEFINED_OP_FLAG |
+				   BIGNUM_REDEFINED_OP_FLAG |
+				   STRING_REDEFINED_OP_FLAG)) {
+	    st_data_t val;
+	    if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) {
+		JUMP(FIX2INT((VALUE)val));
+	    }
+	    else {
+		JUMP(else_offset);
+	    }
+	    break;
+	}
+      default:
+	break;
+    }
+}
+
+/** simple functions */
+
+/**
+  @c optimize
+  @e optimized X+Y.
+  @j 最適化された X+Y。
+ */
+DEFINE_INSN
+opt_plus
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_PLUS,FIXNUM_REDEFINED_OP_FLAG)) {
+	/* 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
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) {
+	val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat &&
+	    BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
+	}
+	else if (RBASIC_CLASS(recv) == rb_cString && RBASIC_CLASS(obj) == rb_cString &&
+		 BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) {
+	    val = rb_str_plus(recv, obj);
+	}
+	else if (RBASIC_CLASS(recv) == rb_cArray &&
+		 BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) {
+	    val = rb_ary_plus(recv, obj);
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+	INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X-Y.
+  @j 最適化された X-Y。
+ */
+DEFINE_INSN
+opt_minus
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_MINUS, FIXNUM_REDEFINED_OP_FLAG)) {
+	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 if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) {
+	val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj));
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat  &&
+	    BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+	/* other */
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X*Y.
+  @j 最適化された X*Y。
+ */
+DEFINE_INSN
+opt_mult
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_MULT, FIXNUM_REDEFINED_OP_FLAG)) {
+	long a, b;
+
+	a = FIX2LONG(recv);
+	if (a == 0) {
+	    val = recv;
+	}
+	else {
+	    b = FIX2LONG(obj);
+            if (MUL_OVERFLOW_FIXNUM_P(a, b)) {
+		val = rb_big_mul(rb_int2big(a), rb_int2big(b));
+            }
+            else {
+		val = LONG2FIX(a * b);
+            }
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) {
+	val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat  &&
+	    BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X/Y.
+  @j 最適化された X/Y。
+ */
+DEFINE_INSN
+opt_div
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_DIV, FIXNUM_REDEFINED_OP_FLAG)) {
+	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 (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
+	val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat  &&
+	    BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X%Y.
+  @j 最適化された X%Y。
+ */
+DEFINE_INSN
+opt_mod
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_MOD, FIXNUM_REDEFINED_OP_FLAG )) {
+	long x, y;
+
+	x = FIX2LONG(recv);
+	y = FIX2LONG(obj);
+	if (x > 0 && y > 0) {
+	    val = LONG2FIX(x % y);
+	}
+	else {
+	    /* copied from numeric.c#fixdivmod */
+	    long div, 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 = LONG2FIX(mod);
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) {
+	val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat &&
+	    BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X==Y.
+  @j 最適化された X==Y。
+ */
+DEFINE_INSN
+opt_eq
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    val = opt_eq_func(recv, obj, ci);
+
+    if (val == Qundef) {
+	/* other */
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X!=Y.
+  @j 最適化された X!=Y。
+ */
+DEFINE_INSN
+opt_neq
+(CALL_INFO ci, CALL_INFO ci_eq)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
+    vm_search_method(ci, recv);
+    val = Qundef;
+
+    if (check_cfunc(ci->me, rb_obj_not_equal)) {
+	val = opt_eq_func(recv, obj, ci_eq);
+
+	if (val != Qundef) {
+	    val = RTEST(val) ? Qfalse : Qtrue;
+	}
+    }
+
+    if (val == Qundef) {
+	/* other */
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X<Y.
+  @j 最適化された X<Y。
+ */
+DEFINE_INSN
+opt_lt
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_LT, FIXNUM_REDEFINED_OP_FLAG)) {
+	SIGNED_VALUE a = recv, b = obj;
+
+	if (a < b) {
+	    val = Qtrue;
+	}
+	else {
+	    val = Qfalse;
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) {
+	/* flonum is not NaN */
+	val = RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat  &&
+	    BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = double_cmp_lt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X<=Y.
+  @j 最適化された X<=Y。
+ */
+DEFINE_INSN
+opt_le
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_LE, FIXNUM_REDEFINED_OP_FLAG)) {
+	SIGNED_VALUE a = recv, b = obj;
+
+	if (a <= b) {
+	    val = Qtrue;
+	}
+	else {
+	    val = Qfalse;
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) {
+	/* flonum is not NaN */
+	val = RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
+    }
+    else {
+	/* other */
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X>Y.
+  @j 最適化された X>Y。
+ */
+DEFINE_INSN
+opt_gt
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_GT, FIXNUM_REDEFINED_OP_FLAG)) {
+	SIGNED_VALUE a = recv, b = obj;
+
+	if (a > b) {
+	    val = Qtrue;
+	}
+	else {
+	    val = Qfalse;
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) {
+	/* flonum is not NaN */
+	val = RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
+    }
+    else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
+	if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat  &&
+	    BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) {
+	    val = double_cmp_gt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized X>=Y.
+  @j 最適化された X>=Y。
+ */
+DEFINE_INSN
+opt_ge
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+	BASIC_OP_UNREDEFINED_P(BOP_GE, FIXNUM_REDEFINED_OP_FLAG)) {
+	SIGNED_VALUE a = recv, b = obj;
+
+	if (a >= b) {
+	    val = Qtrue;
+	}
+	else {
+	    val = Qfalse;
+	}
+    }
+    else if (FLONUM_2_P(recv, obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) {
+	/* flonum is not NaN */
+	val = RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
+    }
+    else {
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e <<
+  @j 最適化された X<<Y。
+ */
+DEFINE_INSN
+opt_ltlt
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cString &&
+	    BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) {
+	    val = rb_str_concat(recv, obj);
+	}
+	else if (RBASIC_CLASS(recv) == rb_cArray &&
+		 BASIC_OP_UNREDEFINED_P(BOP_LTLT, ARRAY_REDEFINED_OP_FLAG)) {
+	    val = rb_ary_push(recv, obj);
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e []
+  @j 最適化された recv[obj]。
+ */
+DEFINE_INSN
+opt_aref
+(CALL_INFO ci)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_AREF, ARRAY_REDEFINED_OP_FLAG) && FIXNUM_P(obj)) {
+	    val = rb_ary_entry(recv, FIX2LONG(obj));
+	}
+	else if (RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG)) {
+	    val = rb_hash_aref(recv, obj);
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	PUSH(obj);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e recv[obj] = set
+  @j 最適化された recv[obj] = set。
+ */
+DEFINE_INSN
+opt_aset
+(CALL_INFO ci)
+(VALUE recv, VALUE obj, VALUE set)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_ASET, ARRAY_REDEFINED_OP_FLAG) && FIXNUM_P(obj)) {
+	    rb_ary_store(recv, FIX2LONG(obj), set);
+	    val = set;
+	}
+	else if (RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG)) {
+	    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(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e recv[str] = set
+  @j 最適化された recv[str] = set。
+ */
+DEFINE_INSN
+opt_aset_with
+(CALL_INFO ci, VALUE key)
+(VALUE recv, VALUE val)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG)) {
+	rb_hash_aset(recv, key, val);
+    }
+    else {
+	PUSH(recv);
+	PUSH(rb_str_resurrect(key));
+	PUSH(val);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e recv[str]
+  @j 最適化された recv[str]。
+ */
+DEFINE_INSN
+opt_aref_with
+(CALL_INFO ci, VALUE key)
+(VALUE recv)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG)) {
+	val = rb_hash_aref(recv, key);
+    }
+    else {
+	PUSH(recv);
+	PUSH(rb_str_resurrect(key));
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized length
+  @j 最適化された recv.length()。
+ */
+DEFINE_INSN
+opt_length
+(CALL_INFO ci)
+(VALUE recv)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cString &&
+	    BASIC_OP_UNREDEFINED_P(BOP_LENGTH, STRING_REDEFINED_OP_FLAG)) {
+	    val = rb_str_length(recv);
+	}
+	else if (RBASIC_CLASS(recv) == rb_cArray &&
+		 BASIC_OP_UNREDEFINED_P(BOP_LENGTH, ARRAY_REDEFINED_OP_FLAG)) {
+	    val = LONG2NUM(RARRAY_LEN(recv));
+	}
+	else if (RBASIC_CLASS(recv) == rb_cHash &&
+		 BASIC_OP_UNREDEFINED_P(BOP_LENGTH, HASH_REDEFINED_OP_FLAG)) {
+	    val = INT2FIX(RHASH_SIZE(recv));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized size
+  @j 最適化された recv.size()。
+ */
+DEFINE_INSN
+opt_size
+(CALL_INFO ci)
+(VALUE recv)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cString &&
+	    BASIC_OP_UNREDEFINED_P(BOP_SIZE, STRING_REDEFINED_OP_FLAG)) {
+	    val = rb_str_length(recv);
+	}
+	else if (RBASIC_CLASS(recv) == rb_cArray &&
+		 BASIC_OP_UNREDEFINED_P(BOP_SIZE, ARRAY_REDEFINED_OP_FLAG)) {
+	    val = LONG2NUM(RARRAY_LEN(recv));
+	}
+	else if (RBASIC_CLASS(recv) == rb_cHash &&
+		 BASIC_OP_UNREDEFINED_P(BOP_SIZE, HASH_REDEFINED_OP_FLAG)) {
+	    val = INT2FIX(RHASH_SIZE(recv));
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized empty?
+  @j 最適化された recv.empty?()。
+ */
+DEFINE_INSN
+opt_empty_p
+(CALL_INFO ci)
+(VALUE recv)
+(VALUE val)
+{
+    if (!SPECIAL_CONST_P(recv)) {
+	if (RBASIC_CLASS(recv) == rb_cString &&
+	    BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, STRING_REDEFINED_OP_FLAG)) {
+	    if (RSTRING_LEN(recv) == 0) val = Qtrue;
+	    else val = Qfalse;
+	}
+	else if (RBASIC_CLASS(recv) == rb_cArray &&
+		 BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, ARRAY_REDEFINED_OP_FLAG)) {
+	    if (RARRAY_LEN(recv) == 0) val = Qtrue;
+	    else val = Qfalse;
+	}
+	else if (RBASIC_CLASS(recv) == rb_cHash &&
+		 BASIC_OP_UNREDEFINED_P(BOP_EMPTY_P, HASH_REDEFINED_OP_FLAG)) {
+	    if (RHASH_EMPTY_P(recv)) val = Qtrue;
+	    else val = Qfalse;
+	}
+	else {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    else {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized succ
+  @j 最適化された recv.succ()。
+ */
+DEFINE_INSN
+opt_succ
+(CALL_INFO ci)
+(VALUE recv)
+(VALUE val)
+{
+    if (SPECIAL_CONST_P(recv)) {
+	if (FIXNUM_P(recv) &&
+	    BASIC_OP_UNREDEFINED_P(BOP_SUCC, FIXNUM_REDEFINED_OP_FLAG)) {
+	    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 (RBASIC_CLASS(recv) == rb_cString &&
+	    BASIC_OP_UNREDEFINED_P(BOP_SUCC, STRING_REDEFINED_OP_FLAG)) {
+	    val = rb_str_succ(recv);
+	}
+	else
+	  {
+	    goto INSN_LABEL(normal_dispatch);
+	}
+    }
+    if (0) {
+      INSN_LABEL(normal_dispatch):
+	PUSH(recv);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized not
+  @j 最適化された recv.!()。
+ */
+DEFINE_INSN
+opt_not
+(CALL_INFO ci)
+(VALUE recv)
+(VALUE val)
+{
+    extern VALUE rb_obj_not(VALUE obj);
+    vm_search_method(ci, recv);
+
+    if (check_cfunc(ci->me, rb_obj_not)) {
+	val = RTEST(recv) ? Qfalse : Qtrue;
+    }
+    else {
+	PUSH(recv);
+	CALL_SIMPLE_METHOD(recv);
+    }
+}
+
+
+/**
+  @c optimize
+  @e optimized regexp match
+  @j 最適化された正規表現マッチ。
+ */
+DEFINE_INSN
+opt_regexpmatch1
+(VALUE r)
+(VALUE obj)
+(VALUE val)
+{
+    if (BASIC_OP_UNREDEFINED_P(BOP_MATCH, REGEXP_REDEFINED_OP_FLAG)) {
+	val = rb_reg_match(r, obj);
+    }
+    else {
+	val = rb_funcall(r, idEqTilde, 1, obj);
+    }
+}
+
+/**
+  @c optimize
+  @e optimized regexp match 2
+  @j 最適化された正規表現マッチ 2
+ */
+DEFINE_INSN
+opt_regexpmatch2
+(CALL_INFO ci)
+(VALUE obj2, VALUE obj1)
+(VALUE val)
+{
+    if (CLASS_OF(obj2) == rb_cString &&
+	BASIC_OP_UNREDEFINED_P(BOP_MATCH, STRING_REDEFINED_OP_FLAG)) {
+	val = rb_reg_match(obj1, obj2);
+    }
+    else {
+	PUSH(obj2);
+	PUSH(obj1);
+	CALL_SIMPLE_METHOD(obj2);
+    }
+}
+
+/**
+  @c optimize
+  @e call native compiled method
+  @j ネイティブコンパイルしたメソッドを起動。
+ */
+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);
+}
+
-- 
cgit v1.2.3

