mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
9a61579c16
* include/ruby/ruby.h: add RUBY_EVENT_COVERAGE event. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17785 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2051 lines
36 KiB
C
2051 lines
36 KiB
C
/** ##skip -*- mode:c; style:ruby -*-
|
||
insns.def - YARV instruction definitions
|
||
|
||
$Author: $
|
||
created at: 04/01/01 01:17:55 JST
|
||
|
||
Copyright (C) 2004-2007 Koichi Sasada
|
||
*/
|
||
|
||
/** ##skip
|
||
instruction comment
|
||
@c: category
|
||
@e: english description
|
||
@j: japanese description
|
||
|
||
instruction form:
|
||
DEFINE_INSN
|
||
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 value (which is pointed by idx).
|
||
@j idx で指定されたローカル変数をスタックに置く。
|
||
*/
|
||
DEFINE_INSN
|
||
getlocal
|
||
(lindex_t idx)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = *(GET_LFP() - idx);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e set local variable value (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 ($~, $_, ..) value.
|
||
@j 特殊なローカル変数($~, $_, ...)の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getspecial
|
||
(VALUE key, rb_num_t type)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = vm_getspecial(th, GET_LFP(), key, type);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e set special local variable ($~, $_, ...) value as obj.
|
||
@j 特別なローカル変数($~, $_, ...)の値をを設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setspecial
|
||
(VALUE key)
|
||
(VALUE obj)
|
||
()
|
||
{
|
||
lfp_svar_set(th, GET_LFP(), key, obj);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e get block local variable(which is pointed by idx and level).
|
||
level means nest level of block, and specify how above this variable.
|
||
@j level, idx で指定されたブロックローカル変数の値をスタックに置く。
|
||
level はブロックのネストレベルで、何段上かを示す。
|
||
*/
|
||
DEFINE_INSN
|
||
getdynamic
|
||
(dindex_t idx, rb_num_t level)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
int i;
|
||
VALUE *dfp2 = GET_DFP();
|
||
for (i = 0; i < level; i++) {
|
||
dfp2 = GET_PREV_DFP(dfp2);
|
||
}
|
||
val = *(dfp2 - idx);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e set block local variable(which is pointed by 'idx') as val.
|
||
level means nest level of block, and specify how above this variable.
|
||
@j level, idx で指定されたブロックローカル変数の値を val にする。
|
||
level はブロックのネストレベルで、何段上かを示す。
|
||
*/
|
||
DEFINE_INSN
|
||
setdynamic
|
||
(dindex_t idx, rb_num_t level)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
int i;
|
||
VALUE *dfp2 = GET_DFP();
|
||
for (i = 0; i < level; i++) {
|
||
dfp2 = GET_PREV_DFP(dfp2);
|
||
}
|
||
*(dfp2 - idx) = val;
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e get instance variable id of obj.
|
||
if is_local is not 0, search as class local variable.
|
||
@j self のインスタンス変数 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.
|
||
if is_local is not 0, search as class local variable.
|
||
@j self のインスタンス変数 id を 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 現在のスコープのクラス変数 id の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getclassvariable
|
||
(ID id)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
val = rb_cvar_get(vm_get_cvar_base(cref), id);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e set class variable id of klass as val.
|
||
@j klass のクラス変数 id を val にする。
|
||
*/
|
||
DEFINE_INSN
|
||
setclassvariable
|
||
(ID id)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
rb_cvar_set(vm_get_cvar_base(cref), id, val);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e
|
||
get constant variable id. if klass is Qnil, constant
|
||
are searched in current scope. if klass is Qfalse, constant as
|
||
top level constant. otherwise, get constant under klass
|
||
class or module.
|
||
@j 定数 id の値を得る。
|
||
klass が Qnil なら、そのスコープで得られる定数の値を得る。
|
||
Qfalse なら、トップレベルスコープを得る。
|
||
それ以外なら、klass クラスの下の定数を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getconstant
|
||
(ID id)
|
||
(VALUE klass)
|
||
(VALUE val)
|
||
{
|
||
val = vm_get_ev_const(th, GET_ISEQ(), klass, id, 0);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e
|
||
set constant variable id. if klass is Qfalse, constant
|
||
is able to access in this scope. if klass is Qnil, set
|
||
top level constant. otherwise, set constant under klass
|
||
class or module.
|
||
|
||
@j 定数 id の値を val にする。
|
||
klass が Qfalse なら、そのスコープで得られる定数 id の値を設定する。
|
||
Qnil なら、トップレベルスコープの値を設定する。
|
||
それ以外なら、klass クラスの下の定数を設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setconstant
|
||
(ID id)
|
||
(VALUE val, VALUE cbase)
|
||
()
|
||
{
|
||
vm_check_if_namespace(cbase);
|
||
rb_const_set(cbase, id, val);
|
||
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 to stack.
|
||
@j スタックに nil をプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putnil
|
||
()
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = Qnil;
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put self.
|
||
@j スタックに self をプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putself
|
||
()
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = GET_SELF();
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put some object.
|
||
i.e. Fixnum, true, false, nil, and so on.
|
||
@j オブジェクト val をスタックにプッシュする。
|
||
i.e. Fixnum, true, false, nil, and so on.
|
||
*/
|
||
DEFINE_INSN
|
||
putobject
|
||
(VALUE val)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
/* */
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put special object. "value_type" is for expansion.
|
||
@j 特別なオブジェクト val をスタックにプッシュする。
|
||
オブジェクトの種類は value_type による.
|
||
*/
|
||
DEFINE_INSN
|
||
putspecialobject
|
||
(rb_num_t value_type)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
switch (value_type) {
|
||
case VM_SPECIAL_OBJECT_VMCORE:
|
||
val = rb_mRubyVMFrozenCore;
|
||
break;
|
||
case VM_SPECIAL_OBJECT_CBASE:
|
||
val = vm_get_cbase(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
break;
|
||
default:
|
||
rb_bug("putspecialobject insn: unknown value_type");
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put iseq value.
|
||
@j put iseq value.
|
||
*/
|
||
DEFINE_INSN
|
||
putiseq
|
||
(ISEQ iseq)
|
||
()
|
||
(VALUE ret)
|
||
{
|
||
ret = iseq->self;
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put string val. string will be copied.
|
||
@j 文字列ををコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putstring
|
||
(VALUE str)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = rb_str_new3(str);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put concatenate strings
|
||
@j スタックトップの文字列を n 個連結し,結果をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
concatstrings
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
int i;
|
||
|
||
val = rb_str_new(0, 0);
|
||
for (i = num - 1; i >= 0; i--) {
|
||
const VALUE v = TOPN(i);
|
||
rb_str_append(val, v);
|
||
}
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e to_str
|
||
@j to_str の結果をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
tostring
|
||
()
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
val = rb_obj_as_string(val);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e to Regexp
|
||
@j 文字列 str を正規表現にコンパイルしてスタックにプッシュする。
|
||
コンパイル時,opt を正規表現のオプションとする。
|
||
*/
|
||
DEFINE_INSN
|
||
toregexp
|
||
(rb_num_t opt, rb_num_t cnt)
|
||
(...)
|
||
(VALUE val) // inc += 1 - cnt;
|
||
{
|
||
VALUE rb_reg_new_ary(VALUE ary, int options);
|
||
int i;
|
||
const VALUE ary = rb_ary_new2(cnt);
|
||
RBASIC(ary)->klass = 0;
|
||
for (i = 0; i < cnt; i++) {
|
||
rb_ary_store(ary, cnt-i-1, TOPN(i));
|
||
}
|
||
POPN(cnt);
|
||
val = rb_reg_new_ary(ary, opt);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put new array.
|
||
@j 新しい配列をスタック上の num 個の値で初期化して生成しプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
newarray
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e dup array
|
||
@j 配列 ary を dup してスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
duparray
|
||
(VALUE ary)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = rb_ary_dup(ary);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e expand array to num objects.
|
||
@j スタックトップのオブジェクトが配列であれば、それを展開する。
|
||
配列オブジェクトの要素数が num以下ならば、代わりに nil を積む。num以上なら、
|
||
num以上の要素は切り捨てる。
|
||
配列オブジェクトでなければ、num - 1 個の nil を積む。
|
||
もし flag が真なら、残り要素の配列を積む
|
||
flag: 0x01 - 最後を配列に
|
||
flag: 0x02 - postarg 用
|
||
flag: 0x04 - reverse?
|
||
*/
|
||
DEFINE_INSN
|
||
expandarray
|
||
(rb_num_t num, rb_num_t flag)
|
||
(..., VALUE ary)
|
||
(...) // inc += num - 1 + (flag & 1 ? 1 : 0);
|
||
{
|
||
vm_expandarray(GET_CFP(), ary, num, flag);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e concat two arrays
|
||
@j 二つの配列 ary1, ary2 を連結しスタックへプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
concatarray
|
||
()
|
||
(VALUE ary1, VALUE ary2st)
|
||
(VALUE ary)
|
||
{
|
||
const VALUE ary2 = ary2st;
|
||
VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, "Array", "to_a");
|
||
VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, "Array", "to_a");
|
||
|
||
if (NIL_P(tmp1)) {
|
||
tmp1 = rb_ary_new3(1, ary1);
|
||
}
|
||
|
||
if (NIL_P(tmp2)) {
|
||
tmp2 = rb_ary_new3(1, ary2);
|
||
}
|
||
|
||
if (tmp1 == ary1) {
|
||
tmp1 = rb_ary_dup(ary1);
|
||
}
|
||
ary = rb_ary_concat(tmp1, tmp2);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e splat array
|
||
@j 配列 ary に対して to_a を呼び出す。
|
||
*/
|
||
DEFINE_INSN
|
||
splatarray
|
||
(VALUE flag)
|
||
(VALUE ary)
|
||
(VALUE obj)
|
||
{
|
||
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
|
||
if (NIL_P(tmp)) {
|
||
tmp = rb_ary_new3(1, ary);
|
||
}
|
||
obj = tmp;
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e check value is included in ary
|
||
@j 配列 ary に要素 obj が入っているかどうかチェック。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 新しいハッシュをスタックトップの n 個を初期値として生成する。
|
||
n はキーと値のペアなので 2 の倍数でなければならない。
|
||
*/
|
||
DEFINE_INSN
|
||
newhash
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
int i;
|
||
val = rb_hash_new();
|
||
|
||
for (i = num; i > 0; i -= 2) {
|
||
const VALUE v = TOPN(i - 2);
|
||
const VALUE k = TOPN(i - 1);
|
||
rb_hash_aset(val, k, v);
|
||
}
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put new Range object.(Range.new(low, high, flag))
|
||
@j Range.new(low, high, flag) のようなオブジェクトを生成しスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
newrange
|
||
(rb_num_t flag)
|
||
(VALUE low, VALUE high)
|
||
(VALUE val)
|
||
{
|
||
val = rb_range_new(low, high, flag);
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with stack operation */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c stack
|
||
@e pop from stack.
|
||
@j スタックから一つポップする。
|
||
*/
|
||
DEFINE_INSN
|
||
pop
|
||
()
|
||
(VALUE val)
|
||
()
|
||
{
|
||
val = val;
|
||
/* none */
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e duplicate stack top.
|
||
@j スタックトップをコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
dup
|
||
()
|
||
(VALUE val)
|
||
(VALUE val1, VALUE val2)
|
||
{
|
||
val1 = val2 = val;
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e duplicate stack top n elements
|
||
@j スタックトップの n 個をコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
dupn
|
||
(rb_num_t n)
|
||
(...)
|
||
(...) // inc += n;
|
||
{
|
||
int i;
|
||
VALUE *sp = STACK_ADDR_FROM_TOP(n);
|
||
for (i = 0; i < n; i++) {
|
||
GET_SP()[i] = sp[i];
|
||
}
|
||
INC_SP(n);
|
||
}
|
||
|
||
|
||
/**
|
||
@c stack
|
||
@e swap top 2 vals
|
||
@j スタックトップの 2 つの値を交換する。
|
||
*/
|
||
DEFINE_INSN
|
||
swap
|
||
()
|
||
(VALUE val, VALUE obj)
|
||
(VALUE obj, VALUE val)
|
||
{
|
||
/* none */
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e for stack caching.
|
||
@j スタックキャッシングの状態を調整するために必要な命令。
|
||
*/
|
||
DEFINE_INSN
|
||
reput
|
||
()
|
||
(..., VALUE val)
|
||
(VALUE val) // inc += 0;
|
||
{
|
||
/* none */
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e get nth stack value from stack top
|
||
@j スタックトップから n 個目をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
topn
|
||
(rb_num_t n)
|
||
(...)
|
||
(VALUE val) // inc += 1;
|
||
{
|
||
val = TOPN(n);
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e set Nth stack entry to stack top
|
||
@j スタックトップの値を n 個目のスタックにコピー
|
||
*/
|
||
DEFINE_INSN
|
||
setn
|
||
(rb_num_t n)
|
||
(..., VALUE val)
|
||
(VALUE val) // inc += 0
|
||
{
|
||
TOPN(n-1) = val;
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e empt current stack
|
||
@j current stack を空にする。
|
||
*/
|
||
DEFINE_INSN
|
||
adjuststack
|
||
(rb_num_t n)
|
||
(...)
|
||
(...) // inc -= n
|
||
{
|
||
DEC_SP(n);
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* deal with setting */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c setting
|
||
@e defined?
|
||
@j defined? を行う。
|
||
*/
|
||
DEFINE_INSN
|
||
defined
|
||
(rb_num_t type, VALUE obj, VALUE needstr)
|
||
(VALUE v)
|
||
(VALUE val)
|
||
{
|
||
VALUE klass;
|
||
const char *expr_type = 0;
|
||
val = Qnil;
|
||
|
||
switch (type) {
|
||
case DEFINED_IVAR:
|
||
if (rb_ivar_defined(GET_SELF(), SYM2ID(obj))) {
|
||
expr_type = "instance-variable";
|
||
}
|
||
break;
|
||
case DEFINED_IVAR2:
|
||
klass = vm_get_cbase(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
break;
|
||
case DEFINED_GVAR:
|
||
if (rb_gvar_defined((struct global_entry *)(obj & ~1))) {
|
||
expr_type = "global-variable";
|
||
}
|
||
break;
|
||
case DEFINED_CVAR:
|
||
klass = vm_get_cbase(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
if (rb_cvar_defined(klass, SYM2ID(obj))) {
|
||
expr_type = "class variable";
|
||
}
|
||
break;
|
||
case DEFINED_CONST:
|
||
klass = v;
|
||
if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) {
|
||
expr_type = "constant";
|
||
}
|
||
break;
|
||
case DEFINED_FUNC:
|
||
klass = CLASS_OF(v);
|
||
if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
|
||
expr_type = "method";
|
||
}
|
||
break;
|
||
case DEFINED_METHOD:{
|
||
VALUE klass = CLASS_OF(v);
|
||
NODE *method = (NODE *) rb_method_node(klass, SYM2ID(obj));
|
||
|
||
if (method) {
|
||
if (!(method->nd_noex & NOEX_PRIVATE)) {
|
||
if (!((method->nd_noex & NOEX_PROTECTED) &&
|
||
!rb_obj_is_kind_of(GET_SELF(),
|
||
rb_class_real(klass)))) {
|
||
expr_type = "method";
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case DEFINED_YIELD:
|
||
if (GET_BLOCK_PTR()) {
|
||
expr_type = "yield";
|
||
}
|
||
break;
|
||
case DEFINED_ZSUPER:{
|
||
rb_iseq_t *ip = GET_ISEQ();
|
||
while (ip) {
|
||
if (ip->defined_method_id) {
|
||
break;
|
||
}
|
||
ip = ip->parent_iseq;
|
||
}
|
||
if (ip) {
|
||
VALUE klass = vm_search_normal_superclass(ip->klass, GET_SELF());
|
||
if (rb_method_boundp(klass, ip->defined_method_id, 0)) {
|
||
expr_type = "super";
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case DEFINED_REF:{
|
||
val = vm_getspecial(th, GET_LFP(), Qfalse, FIX2INT(obj));
|
||
if (val != Qnil) {
|
||
expr_type = "global-variable";
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
rb_bug("unimplemented defined? type (VM)");
|
||
break;
|
||
}
|
||
if (expr_type != 0) {
|
||
if (needstr != Qfalse) {
|
||
val = rb_str_new2(expr_type);
|
||
}
|
||
else {
|
||
val = Qtrue;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c setting
|
||
@e trace
|
||
@j trace 用の命令。
|
||
*/
|
||
DEFINE_INSN
|
||
trace
|
||
(rb_num_t nf)
|
||
()
|
||
()
|
||
{
|
||
rb_event_flag_t flag = nf;
|
||
|
||
if (flag == RUBY_EVENT_COVERAGE) {
|
||
VALUE coverage = GET_ISEQ()->coverage;
|
||
if (coverage) {
|
||
long line = vm_get_sourceline(GET_CFP()) - 1;
|
||
long count;
|
||
if (RARRAY_PTR(coverage)[line] == Qnil) {
|
||
rb_bug("bug");
|
||
}
|
||
count = FIX2LONG(RARRAY_PTR(coverage)[line]) + 1;
|
||
if (POSFIXABLE(count)) {
|
||
RARRAY_PTR(coverage)[line] = LONG2FIX(count);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
|
||
}
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 1: class/module */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c class/module
|
||
@e
|
||
enter class definition scope. if super is Qfalse, and clsas
|
||
"klass" is defined, it's redefine. otherwise, define "klass" class.
|
||
@j クラス定義スコープへ移行する。
|
||
もし super が Qfalse で klassクラスが定義されていれば再定義である。
|
||
そうでなければ、klass クラスを定義する。
|
||
*/
|
||
DEFINE_INSN
|
||
defineclass
|
||
(ID id, ISEQ class_iseq, rb_num_t define_type)
|
||
(VALUE cbase, VALUE super)
|
||
(VALUE val)
|
||
{
|
||
VALUE klass;
|
||
|
||
switch ((int)define_type) {
|
||
case 0:
|
||
/* val is dummy. classdef returns class scope value */
|
||
|
||
if (super == Qnil) {
|
||
super = rb_cObject;
|
||
}
|
||
|
||
vm_check_if_namespace(cbase);
|
||
|
||
/* find klass */
|
||
if (rb_const_defined_at(cbase, id)) {
|
||
/* already exist */
|
||
klass = rb_const_get_at(cbase, id);
|
||
if (TYPE(klass) != T_CLASS) {
|
||
rb_raise(rb_eTypeError, "%s is not a class", rb_id2name(id));
|
||
}
|
||
|
||
if (super != rb_cObject) {
|
||
VALUE tmp;
|
||
tmp = rb_class_real(RCLASS_SUPER(klass));
|
||
|
||
if (tmp != super) {
|
||
rb_raise(rb_eTypeError, "superclass mismatch for class %s",
|
||
rb_id2name(id));
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
/* new class declaration */
|
||
klass = rb_define_class_id(id, super);
|
||
rb_set_class_path(klass, cbase, rb_id2name(id));
|
||
rb_const_set(cbase, id, klass);
|
||
rb_class_inherited(super, klass);
|
||
}
|
||
break;
|
||
case 1:
|
||
/* val is dummy. classdef returns class scope value */
|
||
/* super is dummy */
|
||
klass = rb_singleton_class(cbase);
|
||
break;
|
||
case 2:
|
||
/* val is dummy. classdef returns class scope value */
|
||
/* super is dummy */
|
||
|
||
vm_check_if_namespace(cbase);
|
||
|
||
/* find klass */
|
||
if (rb_const_defined_at(cbase, id)) {
|
||
klass = rb_const_get_at(cbase, id);
|
||
/* already exist */
|
||
if (TYPE(klass) != T_MODULE) {
|
||
rb_raise(rb_eTypeError, "%s is not a module", rb_id2name(id));
|
||
}
|
||
}
|
||
else {
|
||
/* new module declaration */
|
||
klass = rb_define_module_id(id);
|
||
rb_set_class_path(klass, cbase, rb_id2name(id));
|
||
rb_const_set(cbase, id, klass);
|
||
}
|
||
break;
|
||
default:
|
||
rb_bug("unknown defineclass type: %d", (int)define_type);
|
||
}
|
||
|
||
COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC));
|
||
|
||
/* enter scope */
|
||
vm_push_frame(th, class_iseq,
|
||
VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_DFP() | 0x02,
|
||
class_iseq->iseq_encoded, GET_SP(), 0,
|
||
class_iseq->local_size);
|
||
RESTORE_REGS();
|
||
|
||
INC_VM_STATE_VERSION();
|
||
NEXT_INSN();
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 2: method/iterator */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e obj.send(id, args..) # args.size => num
|
||
@j メソッド呼び出しを行う。
|
||
obj.send(id, args..) # args.size => num
|
||
flag & VM_CALL_ARGS_SPLAT_BIT != 0 -> splat last arg
|
||
flag & VM_CALL_ARGS_BLOCKARG_BIT != 0 -> Proc as Block
|
||
flag & VM_CALL_FCALL_BIT != 0 -> FCALL ( func() )
|
||
flag & VM_CALL_VCALL_BIT != 0 -> VCALL ( func )
|
||
...
|
||
*/
|
||
DEFINE_INSN
|
||
send
|
||
(ID op_id, rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag, IC ic)
|
||
(...)
|
||
(VALUE val) // inc += - (op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||
{
|
||
NODE *mn;
|
||
VALUE recv, klass;
|
||
rb_block_t *blockptr = 0;
|
||
rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, op_argc,
|
||
(rb_iseq_t *)blockiseq, &blockptr);
|
||
rb_num_t flag = op_flag;
|
||
ID id = op_id;
|
||
|
||
/* get receiver */
|
||
recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
|
||
klass = CLASS_OF(recv);
|
||
mn = vm_method_search(id, klass, ic);
|
||
|
||
/* send/funcall optimization */
|
||
if (flag & VM_CALL_SEND_BIT) {
|
||
vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass);
|
||
}
|
||
|
||
CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e super(args) # args.size => num
|
||
@j super を実行する。
|
||
super(args) # args.size => num
|
||
flag 等オペランドの意味は send と同じ。
|
||
*/
|
||
DEFINE_INSN
|
||
invokesuper
|
||
(rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag)
|
||
(...)
|
||
(VALUE val) // inc += - (op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||
{
|
||
rb_block_t *blockptr = !(op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? GET_BLOCK_PTR() : 0;
|
||
int num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr);
|
||
VALUE recv, klass;
|
||
NODE *mn;
|
||
ID id;
|
||
const VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||
|
||
recv = GET_SELF();
|
||
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
||
mn = rb_method_node(klass, id);
|
||
|
||
CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e yield(args) # args.size => num, flag shows expand argument or not
|
||
@j yield を実行する。
|
||
yield(args) # args.size => num
|
||
*/
|
||
DEFINE_INSN
|
||
invokeblock
|
||
(rb_num_t num, rb_num_t flag)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = vm_invoke_block(th, GET_CFP(), num, flag);
|
||
if (val == Qundef) {
|
||
RESTORE_REGS();
|
||
NEXT_INSN();
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e return from this scope.
|
||
@j このスコープから抜ける。
|
||
*/
|
||
DEFINE_INSN
|
||
leave
|
||
()
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
if (OPT_CHECKED_RUN) {
|
||
if (reg_cfp->sp != reg_cfp->bp) {
|
||
rb_bug("Stack consistency error (sp: %td, bp: %td)",
|
||
VM_SP_CNT(th, reg_cfp->sp), VM_SP_CNT(th, reg_cfp->bp));
|
||
}
|
||
}
|
||
|
||
RUBY_VM_CHECK_INTS();
|
||
vm_pop_frame(th);
|
||
RESTORE_REGS();
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e return from this vm loop
|
||
@j VM loop から抜ける。
|
||
*/
|
||
DEFINE_INSN
|
||
finish
|
||
()
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
#if OPT_CALL_THREADED_CODE
|
||
rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
|
||
#else
|
||
th->cfp++;
|
||
return val;
|
||
#endif
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 3: exception */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c exception
|
||
@e longjump
|
||
@j 大域ジャンプを行う。
|
||
*/
|
||
DEFINE_INSN
|
||
throw
|
||
(rb_num_t throw_state)
|
||
(VALUE throwobj)
|
||
(VALUE val)
|
||
{
|
||
RUBY_VM_CHECK_INTS();
|
||
val = vm_throw(th, GET_CFP(), throw_state, throwobj);
|
||
THROW_EXCEPTION(val);
|
||
/* unreachable */
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 4: local jump */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c jump
|
||
@e set PC to (PC + dst).
|
||
@j PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
jump
|
||
(OFFSET dst)
|
||
()
|
||
()
|
||
{
|
||
RUBY_VM_CHECK_INTS();
|
||
JUMP(dst);
|
||
}
|
||
|
||
/**
|
||
@c jump
|
||
@e if val is not false or nil, set PC to (PC + dst).
|
||
@j もし val が false か nil でなければ、PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
branchif
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
if (RTEST(val)) {
|
||
RUBY_VM_CHECK_INTS();
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c jump
|
||
@e if val is false or nil, set PC to (PC + dst).
|
||
@j もし val が false か nil ならば、PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
branchunless
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
if (!RTEST(val)) {
|
||
RUBY_VM_CHECK_INTS();
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* for optimize */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c optimize
|
||
@e inline cache
|
||
@j インラインキャッシュが有効なら、値をスタックにプッシュして dst へジャンプする。
|
||
*/
|
||
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 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 インラインキャッシュの値を設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setinlinecache
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
IC ic = GET_CONST_INLINE_CACHE(dst);
|
||
|
||
ic->ic_value = val;
|
||
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e case dispatcher
|
||
@j case 文で、可能なら表引きでジャンプする。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_case_dispatch
|
||
(CDHASH hash, OFFSET else_offset)
|
||
(..., VALUE key)
|
||
() // inc += -1;
|
||
{
|
||
if (0) {
|
||
/* TODO: if some === method is overrided */
|
||
}
|
||
else {
|
||
VALUE val;
|
||
if (st_lookup(RHASH_TBL(hash), key, &val)) {
|
||
JUMP(FIX2INT(val));
|
||
}
|
||
else {
|
||
JUMP(else_offset);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e check environment
|
||
@j 将来の拡張用。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_checkenv
|
||
()
|
||
()
|
||
()
|
||
{
|
||
if (GET_CFP()->bp != GET_DFP() + 1) {
|
||
VALUE *new_dfp = GET_CFP()->bp - 1;
|
||
/* TODO: copy env and clean stack at creating env? */
|
||
*new_dfp = *GET_DFP();
|
||
SET_DFP(new_dfp);
|
||
}
|
||
}
|
||
|
||
|
||
/** simple functions */
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X+Y.
|
||
@j 最適化された X+Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_plus
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (0) {
|
||
|
||
}
|
||
#if 1
|
||
else if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
|
||
/* fixnum + fixnum */
|
||
#ifndef LONG_LONG_VALUE
|
||
val = (recv + (obj & (~1)));
|
||
if ((~(recv ^ obj) & (recv ^ val)) &
|
||
((VALUE)0x01 << ((sizeof(VALUE) * CHAR_BIT) - 1))) {
|
||
val = rb_big_plus(rb_int2big(FIX2LONG(recv)),
|
||
rb_int2big(FIX2LONG(obj)));
|
||
}
|
||
#else
|
||
long a, b, c;
|
||
a = FIX2LONG(recv);
|
||
b = FIX2LONG(obj);
|
||
c = a + b;
|
||
if (FIXABLE(c)) {
|
||
val = LONG2FIX(c);
|
||
}
|
||
else {
|
||
val = rb_big_plus(rb_int2big(a), rb_int2big(b));
|
||
}
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
|
||
if (0) {
|
||
}
|
||
#if 1
|
||
else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
|
||
HEAP_CLASS_OF(obj) == rb_cFloat &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
|
||
val = DOUBLE2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
|
||
}
|
||
#endif
|
||
|
||
#if 1
|
||
else if (HEAP_CLASS_OF(recv) == rb_cString &&
|
||
HEAP_CLASS_OF(obj) == rb_cString &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
|
||
val = rb_str_plus(recv, obj);
|
||
}
|
||
#endif
|
||
#if 1
|
||
else if (HEAP_CLASS_OF(recv) == rb_cArray &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
|
||
val = rb_ary_plus(recv, obj);
|
||
}
|
||
#endif
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idPLUS, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X-Y.
|
||
@j 最適化された X-Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_minus
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_MINUS)) {
|
||
long a, b, c;
|
||
|
||
a = FIX2LONG(recv);
|
||
b = FIX2LONG(obj);
|
||
c = a - b;
|
||
|
||
if (FIXABLE(c)) {
|
||
val = LONG2FIX(c);
|
||
}
|
||
else {
|
||
val = rb_big_minus(rb_int2big(a), rb_int2big(b));
|
||
}
|
||
}
|
||
else {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idMINUS, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X*Y.
|
||
@j 最適化された X*Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_mult
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_MULT)) {
|
||
long a, b, c;
|
||
|
||
a = FIX2LONG(recv);
|
||
if (a == 0) {
|
||
val = recv;
|
||
}
|
||
else {
|
||
b = FIX2LONG(obj);
|
||
c = a * b;
|
||
|
||
if (FIXABLE(c) && c / a == b) {
|
||
val = LONG2FIX(c);
|
||
}
|
||
else {
|
||
val = rb_big_mul(rb_int2big(a), rb_int2big(b));
|
||
}
|
||
}
|
||
}
|
||
else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
|
||
if (0) {
|
||
}
|
||
#if 1
|
||
else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
|
||
HEAP_CLASS_OF(obj) == rb_cFloat &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_MULT)) {
|
||
val = DOUBLE2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
|
||
}
|
||
#endif
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idMULT, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@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)
|
||
goto INSN_LABEL(normal_dispatch);
|
||
if (y < 0) {
|
||
if (x < 0)
|
||
div = -x / -y;
|
||
else
|
||
div = -(x / -y);
|
||
}
|
||
else {
|
||
if (x < 0)
|
||
div = -(-x / y);
|
||
else
|
||
div = x / y;
|
||
}
|
||
mod = x - div * y;
|
||
if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
|
||
mod += y;
|
||
div -= 1;
|
||
}
|
||
}
|
||
val = LONG2NUM(div);
|
||
}
|
||
else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
|
||
if (0) {
|
||
}
|
||
#if 1
|
||
else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
|
||
HEAP_CLASS_OF(obj) == rb_cFloat &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_DIV)) {
|
||
val = DOUBLE2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
|
||
}
|
||
#endif
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idDIV, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@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_VALUE(recv);
|
||
double y = RFLOAT_VALUE(obj);
|
||
double div, mod;
|
||
|
||
{
|
||
double z;
|
||
|
||
modf(x / y, &z);
|
||
mod = x - z * y;
|
||
}
|
||
|
||
div = (x - mod) / y;
|
||
if (y * mod < 0) {
|
||
mod += y;
|
||
div -= 1.0;
|
||
}
|
||
val = DOUBLE2NUM(mod);
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idMOD, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X==Y.
|
||
@j 最適化された X==Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_eq
|
||
(IC ic)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = opt_eq_func(recv, obj, ic);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idEq, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X!=Y.
|
||
@j 最適化された X!=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_neq
|
||
(IC ic1, IC ic2)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
|
||
NODE *mn = vm_method_search(idNeq, CLASS_OF(recv), ic1);
|
||
val = Qundef;
|
||
|
||
if (check_cfunc(mn, rb_obj_not_equal)) {
|
||
val = opt_eq_func(recv, obj, ic2);
|
||
|
||
if (val != Qundef) {
|
||
val = RTEST(val) ? Qfalse : Qtrue;
|
||
}
|
||
}
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idNeq, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@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)) {
|
||
SIGNED_VALUE a = recv, b = obj;
|
||
|
||
if (a < b) {
|
||
val = Qtrue;
|
||
}
|
||
else {
|
||
val = Qfalse;
|
||
}
|
||
}
|
||
else {
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idLT, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X<=Y.
|
||
@j 最適化された X<=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_le
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_LE)) {
|
||
SIGNED_VALUE a = recv, b = obj;
|
||
|
||
if (a <= b) {
|
||
val = Qtrue;
|
||
}
|
||
else {
|
||
val = Qfalse;
|
||
}
|
||
}
|
||
else {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idLE, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X>Y.
|
||
@j 最適化された X>Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_gt
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_GT)) {
|
||
SIGNED_VALUE a = recv, b = obj;
|
||
|
||
if (a > b) {
|
||
val = Qtrue;
|
||
}
|
||
else {
|
||
val = Qfalse;
|
||
}
|
||
}
|
||
else {
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idGT, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X>=Y.
|
||
@j 最適化された X>=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_ge
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (FIXNUM_2_P(recv, obj) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_GE)) {
|
||
SIGNED_VALUE a = recv, b = obj;
|
||
|
||
if (a >= b) {
|
||
val = Qtrue;
|
||
}
|
||
else {
|
||
val = Qfalse;
|
||
}
|
||
}
|
||
else {
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idGE, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e <<
|
||
@j 最適化された X<<Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_ltlt
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (!SPECIAL_CONST_P(recv)) {
|
||
if (0) {
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cString &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_LTLT)) {
|
||
val = rb_str_concat(recv, obj);
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cArray &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_LTLT)) {
|
||
val = rb_ary_push(recv, obj);
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idLTLT, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e []
|
||
@j 最適化された recv[obj]。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aref
|
||
()
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
if (!SPECIAL_CONST_P(recv) && BASIC_OP_UNREDEFINED_P(BOP_AREF)) {
|
||
if (HEAP_CLASS_OF(recv) == rb_cArray && FIXNUM_P(obj)) {
|
||
val = rb_ary_entry(recv, FIX2LONG(obj));
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cHash) {
|
||
val = rb_hash_aref(recv, obj);
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(1, idAREF, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e recv[obj] = set
|
||
@j 最適化された recv[obj] = set。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aset
|
||
()
|
||
(VALUE recv, VALUE obj, VALUE set)
|
||
(VALUE val)
|
||
{
|
||
if (!SPECIAL_CONST_P(recv) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_ASET)) {
|
||
if (HEAP_CLASS_OF(recv) == rb_cArray && FIXNUM_P(obj)) {
|
||
rb_ary_store(recv, FIX2LONG(obj), set);
|
||
val = set;
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cHash) {
|
||
rb_hash_aset(recv, obj, set);
|
||
val = set;
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
PUSH(set);
|
||
CALL_SIMPLE_METHOD(2, idASET, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized length
|
||
@j 最適化された recv.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_cString) {
|
||
val = rb_str_length(recv);
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cArray) {
|
||
val = LONG2NUM(RARRAY_LEN(recv));
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cHash) {
|
||
val = INT2FIX(RHASH_SIZE(recv));
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(0, idLength, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized succ
|
||
@j 最適化された recv.succ()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_succ
|
||
()
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
if (SPECIAL_CONST_P(recv)) {
|
||
if (FIXNUM_P(recv) &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
|
||
const VALUE obj = INT2FIX(1);
|
||
/* fixnum + INT2FIX(1) */
|
||
val = (recv + (obj & (~1)));
|
||
if ((~(recv ^ obj) & (recv ^ val)) & ((unsigned long)LONG_MAX + 1)) {
|
||
val = rb_big_plus(rb_int2big(FIX2LONG(recv)),
|
||
rb_int2big(FIX2LONG(obj)));
|
||
}
|
||
}
|
||
else {
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
else {
|
||
if (HEAP_CLASS_OF(recv) == rb_cString &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
|
||
val = rb_str_succ(recv);
|
||
}
|
||
else if (HEAP_CLASS_OF(recv) == rb_cTime &&
|
||
BASIC_OP_UNREDEFINED_P(BOP_SUCC)) {
|
||
val = rb_time_succ(recv);
|
||
}
|
||
else
|
||
{
|
||
goto INSN_LABEL(normal_dispatch);
|
||
}
|
||
}
|
||
if (0) {
|
||
INSN_LABEL(normal_dispatch):
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(0, idSucc, recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized not
|
||
@j 最適化された recv.!()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_not
|
||
(IC ic)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not(VALUE obj);
|
||
NODE *mn = vm_method_search(idNot, CLASS_OF(recv), ic);
|
||
|
||
if (check_cfunc(mn, rb_obj_not)) {
|
||
val = RTEST(recv) ? Qfalse : Qtrue;
|
||
}
|
||
else {
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(0, idNot, recv);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
@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 ネイティブコンパイルしたメソッドを起動。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_call_c_function
|
||
(rb_insn_func_t funcptr)
|
||
()
|
||
()
|
||
{
|
||
reg_cfp = (funcptr)(th, reg_cfp);
|
||
|
||
if (reg_cfp == 0) {
|
||
VALUE err = th->errinfo;
|
||
th->errinfo = Qnil;
|
||
THROW_EXCEPTION(err);
|
||
}
|
||
|
||
RESTORE_REGS();
|
||
NEXT_INSN();
|
||
}
|
||
|
||
/**
|
||
@c joke
|
||
@e BLT
|
||
@j BLT
|
||
*/
|
||
DEFINE_INSN
|
||
bitblt
|
||
()
|
||
()
|
||
(VALUE ret)
|
||
{
|
||
ret = rb_str_new2("a bit of bacon, lettuce and tomato");
|
||
}
|
||
|
||
/**
|
||
@c joke
|
||
@e The Answer to Life, the Universe, and Everything
|
||
@j 人生、宇宙、すべての答え。
|
||
*/
|
||
DEFINE_INSN
|
||
answer
|
||
()
|
||
()
|
||
(VALUE ret)
|
||
{
|
||
ret = INT2FIX(42);
|
||
}
|
||
|