diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-01-16 08:52:22 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-01-16 08:52:22 +0000 |
commit | ca46eab09073c2d91bb21939b32aa6d767dafa36 (patch) | |
tree | 122e56e2986b002a91d2f32531da056bf1eed7f3 /insns.def | |
parent | 5078c85782efc2d1245377d9a49c71eedd40c170 (diff) | |
download | ruby-ca46eab09073c2d91bb21939b32aa6d767dafa36.tar.gz |
* vm.c (eval_search_super_klass): rename to search_super_klass() and
use it by th_call_super().
* insns.def: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11540 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'insns.def')
-rw-r--r-- | insns.def | 4848 |
1 files changed, 2424 insertions, 2424 deletions
@@ -1,2424 +1,2424 @@ -/** ##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 op_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;
- ID id = op_id;
-
- macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq);
-
- if (flag & VM_CALL_FCALL_BIT) {
- /* method(...) */
- recv = GET_SELF();
- }
- else {
- /* recv.method(...) */
- recv = TOPN(num);
- }
-
- klass = CLASS_OF(recv);
-
- mn = eval_method_search(id, klass, ic);
-
- if ((flag & VM_CALL_SEND_BIT) && mn && nd_type(mn->nd_body) == NODE_CFUNC) {
- NODE *node = mn->nd_body;
- extern VALUE rb_f_funcall(int argc, VALUE *argv, VALUE recv);
- extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
-
- if (node->nd_cfnc == rb_f_funcall || node->nd_cfnc == rb_f_send) {
- int i;
- VALUE sym = TOPN(num - 1);
- id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
-
- /* shift arguments */
- for (i=1; i<num; i++) {
- GET_SP()[-num+i-1] = GET_SP()[(-num+i-1)+1];
- }
-
- mn = rb_method_node(klass, id);
-
- num -= 1;
- INC_SP(-1);
- }
-
- if (node->nd_cfnc == rb_f_funcall) {
- flag |= VM_CALL_FCALL_BIT;
- }
- }
-
-#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 (!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);
-}
-
+/** ##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 = 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 op_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; + ID id = op_id; + + macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq); + + if (flag & VM_CALL_FCALL_BIT) { + /* method(...) */ + recv = GET_SELF(); + } + else { + /* recv.method(...) */ + recv = TOPN(num); + } + + klass = CLASS_OF(recv); + + mn = eval_method_search(id, klass, ic); + + if ((flag & VM_CALL_SEND_BIT) && mn && nd_type(mn->nd_body) == NODE_CFUNC) { + NODE *node = mn->nd_body; + extern VALUE rb_f_funcall(int argc, VALUE *argv, VALUE recv); + extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); + + if (node->nd_cfnc == rb_f_funcall || node->nd_cfnc == rb_f_send) { + int i; + VALUE sym = TOPN(num - 1); + id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); + + /* shift arguments */ + for (i=1; i<num; i++) { + GET_SP()[-num+i-1] = GET_SP()[(-num+i-1)+1]; + } + + mn = rb_method_node(klass, id); + + num -= 1; + INC_SP(-1); + } + + if (node->nd_cfnc == rb_f_funcall) { + flag |= VM_CALL_FCALL_BIT; + } + } + +#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 = 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 (!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); +} + |