summaryrefslogtreecommitdiff
path: root/insns.def
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
commita3e1b1ce7ed7e7ffac23015fc2fde56511b30681 (patch)
tree7b725552a9a4ded93849ca2faab1b257f7761790 /insns.def
parent3e7566d8fb5138bb9cd647e5fdefc54fc9803509 (diff)
* Merge YARV
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'insns.def')
-rw-r--r--insns.def2390
1 files changed, 2390 insertions, 0 deletions
diff --git a/insns.def b/insns.def
new file mode 100644
index 0000000000..99e35a7190
--- /dev/null
+++ b/insns.def
@@ -0,0 +1,2390 @@
+/** ##skip
+ -*-c-*-
+ 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
+(num_t idx, num_t type)
+()
+(VALUE val)
+{
+ if (type == 0) {
+ VALUE *pv = lfp_svar(GET_LFP(), idx);
+ val = *pv;
+ }
+ else {
+ VALUE backref = *lfp_svar(GET_LFP(), 1);
+ if (type & 0x01) {
+ switch (type >> 1) {
+ case '&':
+ val = rb_reg_last_match(backref);
+ break;
+ case '`':
+ val = rb_reg_match_pre(backref);
+ break;
+ case '\'':
+ val = rb_reg_match_post(backref);
+ break;
+ case '+':
+ val = rb_reg_match_last(backref);
+ break;
+ default:
+ rb_bug("unexpected back-ref");
+ }
+ }
+ else {
+ val = rb_reg_nth_match(type >> 1, backref);
+ }
+ }
+}
+
+/**
+ @c variable
+ @e set special local variables
+ @j 特別なローカル変数を設定する
+ */
+DEFINE_INSN
+setspecial
+(num_t idx)
+(VALUE obj)
+()
+{
+ VALUE *pv = lfp_svar(GET_LFP(), idx);
+ *pv = 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, 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, 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.
+ @j obj のインスタンス変数 id を得る。
+ */
+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.
+ @j obj のインスタンス変数を val にする。
+ */
+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 = eval_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 declp)
+(VALUE val)
+()
+{
+ VALUE klass = eval_get_cvar_base(th, GET_ISEQ());
+
+ if (declp == Qtrue && RTEST(ruby_verbose) && FL_TEST(klass, FL_SINGLETON)) {
+ rb_warn("declaring singleton class variable");
+ }
+ rb_cvar_set(klass, id, val, declp);
+}
+
+/**
+ @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 = eval_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 = th_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:
+ rb_raise(rb_eTypeError, "%s is not a class/module",
+ RSTRING_PTR(rb_obj_as_string(klass)));
+ }
+
+ 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 Qundef. DO NOT USE in NORMAL RUBY PROGRAM
+ @j put Qundef.
+ */
+DEFINE_INSN
+putundef
+()
+()
+(VALUE val)
+{
+ val = Qundef;
+}
+
+/**
+ @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 val)
+()
+(VALUE val)
+{
+ val = rb_str_new3(val);
+}
+
+/**
+ @c put
+ @e put concatenate strings
+ @j 文字列を連結して置く。
+ */
+DEFINE_INSN
+concatstrings
+(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
+(num_t flag)
+(VALUE str)
+(VALUE val)
+{
+ val = rb_reg_new(RSTRING_PTR(str), RSTRING_LEN(str), flag);
+}
+
+/**
+ @c put
+ @e put new array.
+ @j 新しい配列をスタック上の num 個の値で初期化して置く。
+ */
+DEFINE_INSN
+newarray
+(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 が真なら、残り要素の配列を積む
+ */
+DEFINE_INSN
+expandarray
+(num_t num, num_t flag)
+(..., VALUE ary)
+(...) // inc += (num > 0) ? num - 1 + (flag ? 1 : 0) : num + 1 - (flag ? 1 : 0);
+{
+ int i;
+ if ((long)num >= 0) {
+ int len;
+ if (TYPE(ary) != T_ARRAY) {
+ ary = rb_ary_to_ary(ary);
+ }
+ len = RARRAY_LEN(ary);
+ for (i = 0; i < len && i < num; i++) {
+ PUSH(RARRAY_PTR(ary)[i]);
+ }
+ for (; i < num; i++) {
+ PUSH(Qnil);
+ }
+ if (flag) {
+ if (len > num) {
+ PUSH(rb_ary_new4(len - num, &RARRAY_PTR(ary)[num]));
+ }
+ else {
+ PUSH(rb_ary_new());
+ }
+ }
+ }
+ else {
+ long holdnum = -num;
+ VALUE val;
+
+ val = rb_ary_new4(holdnum, STACK_ADDR_FROM_TOP(holdnum));
+ if (CLASS_OF(ary) == rb_cArray) {
+ val = rb_ary_concat(val, ary);
+ }
+ else {
+ rb_ary_push(val, ary);
+ }
+ POPN(holdnum);
+ PUSH(val);
+ }
+}
+
+/**
+ @c put
+ @e concat two arrays
+ @j 二つの配列をとってきてくっつける
+ */
+DEFINE_INSN
+concatarray
+()
+(VALUE ary1, VALUE ary2st)
+(VALUE ary)
+{
+ VALUE ary2 = ary2st;
+
+ if (ary2 == Qnil) {
+ ary = ary1;
+ }
+ else {
+ 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;
+
+ if (0) {
+ if (flag == Qfalse) {
+ /* NODE_SPLAT */
+ obj = rb_Array(ary);
+ }
+ else {
+ /* NODE_SVALUE */
+ if (RARRAY_LEN(ary) == 0) {
+ obj = Qnil;
+ }
+ else if (RARRAY_LEN(ary) == 1) {
+ obj = RARRAY_PTR(ary)[0];
+ }
+ else {
+ obj = ary;
+ }
+ }
+ }
+}
+
+/**
+ @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
+(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
+(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
+(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
+(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
+(num_t n)
+(..., VALUE val)
+(VALUE val) // inc += 0
+{
+ GET_SP()[-n] = 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, num_t is_singleton)
+(VALUE obj)
+()
+{
+ eval_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
+(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_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 (eval_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:{
+ yarv_iseq_t *ip = GET_ISEQ();
+ while (ip) {
+ if (ip->defined_method_id) {
+ break;
+ }
+ ip = ip->parent_iseq;
+ }
+ if (ip) {
+ VALUE klass = eval_search_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_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)
+()
+()
+{
+ yarv_block_t *blockptr;
+ VALUE proc;
+
+ blockptr = GET_BLOCK_PTR_IN_CFP(GET_CFP());
+ blockptr->iseq = blockiseq;
+ blockptr->proc = 0;
+
+ proc = th_make_proc(th, GET_CFP(), blockptr);
+ rb_set_end_proc(call_yarv_end_proc, proc);
+}
+
+/**
+ @c setting
+ @e trace
+ @j trace
+ */
+DEFINE_INSN
+trace
+(num_t flag, VALUE args)
+()
+()
+{
+ /* TODO: trace instruction design */
+ if (th->vm->trace_flag & flag) {
+ /* */
+ args = Qnil;
+ }
+}
+
+/**********************************************************/
+/* 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, num_t define_type)
+(VALUE cbase, VALUE super)
+(VALUE val)
+{
+ VALUE klass;
+
+ if (define_type == 0) {
+ /* val is dummy. classdef returns class scope value */
+
+ if (super == Qnil) {
+ super = rb_cObject;
+ }
+ if (cbase == Qnil) {
+ cbase = th_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);
+ }
+ }
+ else if (define_type == 1) {
+ /* val is dummy. classdef returns class scope value */
+ /* super is dummy */
+ klass = rb_singleton_class(cbase);
+ }
+ else if (define_type == 2) {
+ /* val is dummy. classdef returns class scope value */
+ /* super is dummy */
+ if (cbase == Qnil) {
+ cbase = th_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);
+ }
+ }
+ else {
+ rb_bug("unknown defineclass type: %d", define_type);
+ }
+
+ COPY_CREF(klass_iseq->cref_stack, th_cref_push(th, klass, NOEX_PUBLIC));
+
+ /* enter scope */
+ 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 id, num_t op_argc, ISEQ blockiseq, num_t op_flag, IC ic)
+(...)
+(VALUE val) // inc += - (op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
+{
+ NODE *mn;
+ VALUE recv;
+ VALUE klass;
+ yarv_block_t *blockptr = 0;
+ num_t num = op_argc;
+ num_t flag = op_flag;
+
+ macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq);
+ recv = TOPN(num);
+ klass = CLASS_OF(recv);
+
+ mn = eval_method_search(id, klass, ic);
+
+#if CURRENT_INSN_send || CURRENT_INSN_send_SC_xx_ax
+#if !YARV_AOT_COMPILED
+ if (0) {
+ if (0) {
+ LABEL_IS_SC(start_init_in_send_for_opt_1):
+ num = 1;
+ recv = TOPN(1);
+ }
+ else if (0) {
+ LABEL_IS_SC(start_init_in_send_for_opt_2):
+ num = 2;
+ recv = TOPN(2);
+ }
+ flag = 0;
+ id = tmp_id;
+ klass = CLASS_OF(recv);
+ blockptr = 0;
+ mn = rb_method_node(klass, id);
+ }
+ if (0) {
+ LABEL_IS_SC(start_init_in_super):
+ {
+ yarv_iseq_t *iseq = GET_ISEQ();
+ yarv_iseq_t *ip = iseq;
+
+ num = tmp_num;
+ flag = VM_CALL_FCALL_BIT;
+ recv = GET_SELF();
+
+ while (ip && !ip->klass) {
+ ip = ip->parent_iseq;
+ }
+
+ if (ip == 0) {
+ rb_raise(rb_eNoMethodError, "super called outside of method");
+ }
+
+ id = ip->defined_method_id;
+
+ if (ip != ip->local_iseq) {
+ /* defined by method_defined() */
+ yarv_control_frame_t *lcfp = GET_CFP();
+
+ while (lcfp->iseq != ip) {
+ VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
+ while (1) {
+ lcfp = YARV_PREVIOUS_CONTROL_FRAME(lcfp);
+ if (lcfp->dfp == tdfp) {
+ break;
+ }
+ }
+ }
+
+ /* dirty hack */
+ id = (ID) ((VALUE *)(lcfp+1)->block_iseq)[0];
+ klass = ((VALUE *)(lcfp+1)->block_iseq)[1];
+
+ if (TOPN(num) == Qfalse) {
+ /* for ZSUPER */
+ int i;
+ POPN(num);
+ num = ip->argc;
+ for (i = 0; i < ip->argc; i++) {
+ PUSH(lcfp->dfp[i - ip->local_size]);
+ }
+ }
+ }
+ klass = eval_search_super_klass(ip->klass, recv);
+ flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
+ blockptr = tmp_blockptr;
+ mn = rb_method_node(klass, id);
+ }
+ }
+ LABEL_IS_SC(start_method_dispatch):
+#endif
+#endif
+ macro_eval_invoke_method(recv, klass, id, num, mn, blockptr);
+ YARV_CHECK_INTS();
+}
+
+/**
+ @c method/iterator
+ @e super(args) # args.size => num
+ @j super(args) # args.size => num
+ */
+DEFINE_INSN
+invokesuper
+(num_t op_argc, ISEQ blockiseq, num_t flag)
+(...)
+(VALUE val) // inc += - op_argc;
+{
+#if YARV_AOT_COMPILED
+ /* TODO: */
+ rb_bug("...");
+#else
+ tmp_num = op_argc;
+ tmp_blockptr = 0;
+ macro_eval_setup_send_arguments(tmp_num, tmp_blockptr, flag, blockiseq);
+ if (!tmp_blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) {
+ tmp_blockptr = GET_BLOCK_PTR();
+ }
+ goto LABEL_IS_SC(start_init_in_super);
+#endif
+}
+
+/**
+ @c method/iterator
+ @e yield(args) # args.size => num, flag shows expand argument or not
+ @j yield(args) # args.size => num
+ */
+DEFINE_INSN
+invokeblock
+(num_t num, num_t flag)
+(...)
+(VALUE val) // inc += 1 - num;
+{
+ yarv_block_t *block = GET_BLOCK_PTR();
+ yarv_iseq_t *iseq;
+ int argc = num;
+
+ if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) {
+ th_localjump_error("no block given (yield)", Qnil, 0);
+ }
+ iseq = block->iseq;
+
+ if (BUILTIN_TYPE(iseq) != T_NODE) {
+ if (flag & VM_CALL_ARGS_SPLAT_BIT) {
+ VALUE ary = TOPN(0);
+ if (CLASS_OF(ary) != rb_cArray) {
+ /* not a [BUG] */
+ }
+ else {
+ VALUE *ptr = RARRAY_PTR(ary);
+ VALUE *dst = GET_SP() - 1;
+ int i, len = RARRAY_LEN(ary);
+ for (i = 0; i < len; i++) {
+ dst[i] = ptr[i];
+ }
+ argc += i - 1;
+ INC_SP(i - 1);
+ }
+ }
+
+ INC_SP(-argc);
+ argc = th_yield_setup_args(iseq, argc, GET_SP());
+ INC_SP(argc);
+
+ push_frame(th, iseq,
+ FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
+ iseq->iseq_encoded, GET_SP(), block->lfp,
+ iseq->local_size - argc);
+
+ reg_cfp->sp -= argc;
+ RESTORE_REGS();
+ NEXT_INSN();
+ /* unreachable */
+ }
+ else {
+ val = th_invoke_yield_cfunc(th, block, block->self,
+ num, STACK_ADDR_FROM_TOP(num));
+ POPN(num);
+ }
+}
+
+/**
+ @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: %p, bp: %p)",
+ reg_cfp->sp, reg_cfp->bp);
+ }
+ }
+
+ YARV_CHECK_INTS();
+ pop_frame(th);
+ RESTORE_REGS();
+}
+
+/**
+ @c method/iterator
+ @e return from this vm loop
+ @j VM loop から抜ける
+ */
+DEFINE_INSN
+finish
+()
+(VALUE val)
+(VALUE val)
+{
+ th->cfp++;
+ return val;
+}
+
+/**********************************************************/
+/* deal with control flow 3: exception */
+/**********************************************************/
+
+/**
+ @c exception
+ @e longjump
+ @j longjump
+ */
+DEFINE_INSN
+throw
+(num_t throw_state)
+(VALUE throwobj)
+(VALUE val)
+{
+ num_t state = throw_state & 0xff;
+ num_t flag = throw_state & 0x8000;
+ num_t level = throw_state >> 16;
+ val = Qnil; /* dummy */
+
+ if (state != 0) {
+ VALUE *pt;
+ int i;
+ if (flag != 0) {
+ if (throw_state & 0x4000) {
+ pt = (void *)1;
+ }
+ else {
+ pt = 0;
+ }
+ }
+ else {
+ if (state == TAG_BREAK || state == TAG_RETRY) {
+ pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
+ for (i = 0; i < level; i++) {
+ pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
+ }
+ }
+ else if (state == TAG_RETURN) {
+ yarv_control_frame_t *cfp = GET_CFP();
+ int is_orphan = 1;
+ VALUE *dfp = GET_DFP();
+
+ /* check orphan */
+ while ((VALUE *) cfp < th->stack + th->stack_size) {
+ if (GET_LFP() == cfp->lfp) {
+ is_orphan = 0;
+ break;
+ }
+ else if (dfp == cfp->dfp) {
+ /* return from lambda{} */
+ if (cfp->magic == FRAME_MAGIC_LAMBDA) {
+ is_orphan = 0;
+ break;
+ }
+ dfp = GC_GUARDED_PTR_REF(*cfp->dfp);
+ }
+ cfp++;
+ }
+ if (is_orphan) {
+ th_localjump_error("unexpected return", throwobj,
+ TAG_RETURN);
+ }
+
+ /* set current lfp */
+ pt = GET_LFP();
+ }
+ else {
+ rb_bug("isns(throw): unsupport thorw type");
+ }
+ }
+ th->state = state;
+ return (VALUE) NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
+ }
+ else {
+ /* continue throw */
+ VALUE err = throwobj;
+
+ if (FIXNUM_P(err)) {
+ th->state = FIX2INT(err);
+ }
+ else if (SYMBOL_P(err)) {
+ th->state = TAG_THROW;
+ }
+ else if (BUILTIN_TYPE(err) == T_NODE) {
+ th->state = GET_THROWOBJ_STATE(err);
+ }
+ else {
+ th->state = FIX2INT(rb_ivar_get(err, idThrowState));
+ }
+ return err;
+ }
+ /* 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)
+()
+()
+{
+ YARV_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)) {
+ YARV_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)) {
+ YARV_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 = (IC) * (GET_PC() + dst + 1);
+
+ 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 */
+ val = (recv + (obj & (~1)));
+ if ((~(recv ^ obj) & (recv ^ val)) &
+ ((VALUE)0x01 << ((sizeof(VALUE) * CHAR_BIT) - 1))) {
+ val = rb_big_plus(rb_int2big(FIX2INT(recv)),
+ rb_int2big(FIX2INT(obj)));
+ }
+ }
+#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):
+
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idPLUS, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idPLUS;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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;
+ val = LONG2FIX(c);
+
+ if (FIX2LONG(val) != c) {
+ val = rb_big_minus(rb_int2big(a), rb_int2big(b));
+ }
+ }
+ else {
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idMINUS, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idMINUS;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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;
+ val = LONG2FIX(c);
+
+ if (FIX2LONG(val) != c || c / a != b) {
+ 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):
+
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idMULT, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idMULT;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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 = LONG2FIX(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):
+
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idDIV, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idDIV;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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;
+
+ /* copied from numeric.c#flodivmod */
+#if 0 && defined(HAVE_FMOD) && !__x86_64__ /* temporary */
+ mod = fmod(x, y);
+ printf("-- %f %% %f = %f\n", x, y, mod);
+#else
+ {
+ double z;
+
+ modf(x / y, &z);
+ mod = x - z * y;
+ }
+#endif
+ 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):
+
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idMOD, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idMOD;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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 */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idEq, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idEq;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+
+/**
+ @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 {
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idLT, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idLT;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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 */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idLE, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idLE;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @c optimize
+ @e <<
+ @j <<
+ */
+DEFINE_INSN
+opt_ltlt
+()
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+ if (0) {
+ }
+ 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):
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idLTLT, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idLTLT;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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):
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idAREF, 1, obj);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ tmp_id = idAREF;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_1);
+#endif
+ }
+}
+
+/**
+ @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):
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idASET, 2, obj, set);
+#else
+ PUSH(recv);
+ PUSH(obj);
+ PUSH(set);
+ tmp_id = idASET;
+ goto LABEL_IS_SC(start_init_in_send_for_opt_2);
+#endif
+ }
+}
+
+/**
+ @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):
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idLength, 0);
+#else
+ val = rb_funcall(recv, idLength, 0);
+#endif
+ }
+}
+
+/**
+ @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)) & 0x80000000) {
+ val = rb_big_plus(rb_int2big(INT2FIX(recv)),
+ rb_int2big(INT2FIX(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):
+ /* other */
+#ifdef YARV_AOT_COMPILED
+ val = rb_funcall(recv, idSucc, 0);
+#else
+ val = rb_funcall(recv, idSucc, 0);
+#endif
+ }
+}
+
+/**
+ @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_native_compiled
+()
+()
+()
+{
+#if __GNUC__ && OPT_USE_JIT_COMPILE
+ yarv_iseq_t *iseq = GET_ISEQ();
+ void *label = (void *)iseq->jit_compiled;
+
+ breakpoint();
+ SET_PC(iseq->iseq_orig);
+ goto *label;
+#else
+ rb_bug("opt_call_native_compiled is not supported");
+#endif
+}
+
+/**
+ @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);
+}
+