зеркало из https://github.com/github/ruby.git
1622 строки
29 KiB
C
1622 строки
29 KiB
C
/** ##skip -*- mode:c; style:ruby; coding: utf-8 -*-
|
||
insns.def - YARV instruction definitions
|
||
|
||
$Author: $
|
||
created at: 04/01/01 01:17:55 JST
|
||
|
||
Copyright (C) 2004-2007 Koichi Sasada
|
||
*/
|
||
|
||
/** ##skip
|
||
instruction comment
|
||
@c: category
|
||
@e: english description
|
||
@j: japanese description
|
||
|
||
instruction form:
|
||
DEFINE_INSN
|
||
instruction_name
|
||
(instruction_operands, ..)
|
||
(pop_values, ..)
|
||
(return value)
|
||
{
|
||
.. // insn body
|
||
}
|
||
|
||
*/
|
||
|
||
|
||
/**
|
||
@c nop
|
||
@e nop
|
||
@j nop
|
||
*/
|
||
DEFINE_INSN
|
||
nop
|
||
()
|
||
()
|
||
()
|
||
{
|
||
/* none */
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with variables */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c variable
|
||
@e Get local variable (pointed by `idx' and `level').
|
||
'level' indicates the nesting depth from the current block.
|
||
@j level, idx で指定されたローカル変数の値をスタックに置く。
|
||
level はブロックのネストレベルで、何段上かを示す。
|
||
*/
|
||
DEFINE_INSN
|
||
getlocal
|
||
(lindex_t idx, rb_num_t level)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = *(vm_get_ep(GET_EP(), level) - idx);
|
||
RB_DEBUG_COUNTER_INC(lvar_get);
|
||
(void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Set a local variable (pointed to by 'idx') as val.
|
||
'level' indicates the nesting depth from the current block.
|
||
@j level, idx で指定されたローカル変数の値を val にする。
|
||
level はブロックのネストレベルで、何段上かを示す。
|
||
*/
|
||
DEFINE_INSN
|
||
setlocal
|
||
(lindex_t idx, rb_num_t level)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
vm_env_write(vm_get_ep(GET_EP(), level), -(int)idx, val);
|
||
RB_DEBUG_COUNTER_INC(lvar_set);
|
||
(void)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic, level > 0);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Get value of special local variable ($~, $_, ..).
|
||
@j 特殊なローカル変数($~, $_, ...)の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getspecial
|
||
(rb_num_t key, rb_num_t type)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = vm_getspecial(th, GET_LEP(), key, type);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Set value of special local variable ($~, $_, ...) to obj.
|
||
@j 特別なローカル変数($~, $_, ...)の値を設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setspecial
|
||
(rb_num_t key)
|
||
(VALUE obj)
|
||
()
|
||
{
|
||
lep_svar_set(th, GET_LEP(), key, obj);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Get value of instance variable id of self.
|
||
@j self のインスタンス変数 id の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getinstancevariable
|
||
(ID id, IC ic)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = vm_getinstancevariable(GET_SELF(), id, ic);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Set value of instance variable id of self to val.
|
||
@j self のインスタンス変数 id を val にする。
|
||
*/
|
||
DEFINE_INSN
|
||
setinstancevariable
|
||
(ID id, IC ic)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
vm_setinstancevariable(GET_SELF(), id, val, ic);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Get value of class variable id of klass as val.
|
||
@j 現在のスコープのクラス変数 id の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getclassvariable
|
||
(ID id)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = rb_cvar_get(vm_get_cvar_base(rb_vm_get_cref(GET_EP()), GET_CFP()), id);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e Set value of class variable id of klass as val.
|
||
@j klass のクラス変数 id を val にする。
|
||
*/
|
||
DEFINE_INSN
|
||
setclassvariable
|
||
(ID id)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
vm_ensure_not_refinement_module(GET_SELF());
|
||
rb_cvar_set(vm_get_cvar_base(rb_vm_get_cref(GET_EP()), GET_CFP()), id, val);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e
|
||
Get constant variable id. If klass is Qnil, constants
|
||
are searched in the current scope. If klass is Qfalse, constants
|
||
are searched as top level constants. Otherwise, get constant under klass
|
||
class or module.
|
||
@j 定数 id の値を得る。
|
||
klass が Qnil なら、そのスコープで得られる定数の値を得る。
|
||
Qfalse なら、トップレベルスコープを得る。
|
||
それ以外なら、klass クラスの下の定数を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getconstant
|
||
(ID id)
|
||
(VALUE klass)
|
||
(VALUE val)
|
||
{
|
||
val = vm_get_ev_const(th, 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);
|
||
vm_ensure_not_refinement_module(GET_SELF());
|
||
rb_const_set(cbase, id, val);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e get global variable id.
|
||
@j グローバル変数 id の値を得る。
|
||
*/
|
||
DEFINE_INSN
|
||
getglobal
|
||
(GENTRY entry)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = GET_GLOBAL((VALUE)entry);
|
||
}
|
||
|
||
/**
|
||
@c variable
|
||
@e set global variable id as val.
|
||
@j グローバル変数 id の値を設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setglobal
|
||
(GENTRY entry)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
SET_GLOBAL((VALUE)entry, val);
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* deal with values */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c put
|
||
@e put nil to stack.
|
||
@j スタックに nil をプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putnil
|
||
()
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = Qnil;
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put self.
|
||
@j スタックに self をプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putself
|
||
()
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = GET_SELF();
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put some object.
|
||
i.e. Fixnum, true, false, nil, and so on.
|
||
@j オブジェクト val をスタックにプッシュする。
|
||
i.e. Fixnum, true, false, nil, and so on.
|
||
*/
|
||
DEFINE_INSN
|
||
putobject
|
||
(VALUE val)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
/* */
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put special object. "value_type" is for expansion.
|
||
@j 特別なオブジェクト val をスタックにプッシュする。
|
||
オブジェクトの種類は value_type による.
|
||
*/
|
||
DEFINE_INSN
|
||
putspecialobject
|
||
(rb_num_t value_type)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
enum vm_special_object_type type;
|
||
|
||
type = (enum vm_special_object_type)value_type;
|
||
val = vm_get_special_object(GET_EP(), type);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put iseq value.
|
||
@j iseq をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putiseq
|
||
(ISEQ iseq)
|
||
()
|
||
(VALUE ret)
|
||
{
|
||
ret = (VALUE)iseq;
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put string val. string will be copied.
|
||
@j 文字列をコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
putstring
|
||
(VALUE str)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = rb_str_resurrect(str);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put concatenate strings
|
||
@j スタックトップの文字列を n 個連結し,結果をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
concatstrings
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = rb_str_concat_literals(num, STACK_ADDR_FROM_TOP(num));
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e push the result of to_s.
|
||
@j to_s の結果をスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
tostring
|
||
()
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
val = rb_obj_as_string(val);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e Freeze (dynamically) created strings. if debug_info is given, set it.
|
||
@j (埋め込み)文字列を freeze する。もし、debug_info が与えられていれば、それを設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
freezestring
|
||
(VALUE debug_info)
|
||
(VALUE str)
|
||
(VALUE str)
|
||
{
|
||
vm_freezestring(str, debug_info);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e compile str to Regexp and push it.
|
||
opt is the option for the 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);
|
||
VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *);
|
||
const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt));
|
||
POPN(cnt);
|
||
val = rb_reg_new_ary(ary, (int)opt);
|
||
rb_ary_clear(ary);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put new array initialized with num values on the stack.
|
||
@j 新しい配列をスタック上の num 個の値で初期化して生成しプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
newarray
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e dup array
|
||
@j 配列 ary を dup してスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
duparray
|
||
(VALUE ary)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = rb_ary_resurrect(ary);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e if TOS is an array expand, expand it to num objects.
|
||
if the number of the array is less than num, push nils to fill.
|
||
if it is greater than num, exceeding elements are dropped.
|
||
unless TOS is an array, push num - 1 nils.
|
||
if flags is non-zero, push the array of the rest elements.
|
||
flag: 0x01 - rest args array
|
||
flag: 0x02 - for postarg
|
||
flag: 0x04 - reverse?
|
||
@j スタックトップのオブジェクトが配列であれば、それを展開する。
|
||
配列オブジェクトの要素数が num以下ならば、代わりに nil を積む。num以上なら、
|
||
num以上の要素は切り捨てる。
|
||
配列オブジェクトでなければ、num - 1 個の nil を積む。
|
||
もし flag が真なら、残り要素の配列を積む
|
||
flag: 0x01 - 最後を配列に
|
||
flag: 0x02 - postarg 用
|
||
flag: 0x04 - reverse?
|
||
*/
|
||
DEFINE_INSN
|
||
expandarray
|
||
(rb_num_t num, rb_num_t flag)
|
||
(..., VALUE ary)
|
||
(...) // inc += num - 1 + (flag & 1 ? 1 : 0);
|
||
{
|
||
vm_expandarray(GET_CFP(), ary, num, (int)flag);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e concat two arrays
|
||
@j 二つの配列 ary1, ary2 を連結しスタックへプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
concatarray
|
||
()
|
||
(VALUE ary1, VALUE ary2)
|
||
(VALUE ary)
|
||
{
|
||
ary = vm_concat_array(ary1, ary2);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e call to_a on array ary to splat
|
||
@j splat のために配列 ary に対して to_a を呼び出す。
|
||
*/
|
||
DEFINE_INSN
|
||
splatarray
|
||
(VALUE flag)
|
||
(VALUE ary)
|
||
(VALUE obj)
|
||
{
|
||
obj = vm_splat_array(flag, ary);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put new Hash from n elements. n must be an even number.
|
||
@j 新しいハッシュをスタックトップの n 個を初期値として生成する。
|
||
n はキーと値のペアなので 2 の倍数でなければならない。
|
||
*/
|
||
DEFINE_INSN
|
||
newhash
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
RUBY_DTRACE_CREATE_HOOK(HASH, num);
|
||
|
||
val = rb_hash_new_with_size(num / 2);
|
||
|
||
if (num) {
|
||
rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
|
||
}
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c put
|
||
@e put new Range object.(Range.new(low, high, flag))
|
||
@j Range.new(low, high, flag) のようなオブジェクトを生成しスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
newrange
|
||
(rb_num_t flag)
|
||
(VALUE low, VALUE high)
|
||
(VALUE val)
|
||
{
|
||
val = rb_range_new(low, high, (int)flag);
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with stack operation */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c stack
|
||
@e pop from stack.
|
||
@j スタックから一つポップする。
|
||
*/
|
||
DEFINE_INSN
|
||
pop
|
||
()
|
||
(VALUE val)
|
||
()
|
||
{
|
||
(void)val;
|
||
/* none */
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e duplicate stack top.
|
||
@j スタックトップをコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
dup
|
||
()
|
||
(VALUE val)
|
||
(VALUE val1, VALUE val2)
|
||
{
|
||
val1 = val2 = val;
|
||
}
|
||
|
||
/**
|
||
@c stack
|
||
@e duplicate stack top n elements
|
||
@j スタックトップの n 個をコピーしてスタックにプッシュする。
|
||
*/
|
||
DEFINE_INSN
|
||
dupn
|
||
(rb_num_t n)
|
||
(...)
|
||
(...) // inc += n;
|
||
{
|
||
void *dst = GET_SP();
|
||
void *src = STACK_ADDR_FROM_TOP(n);
|
||
|
||
INC_SP(n); /* alloca */
|
||
MEMCPY(dst, src, VALUE, 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 reverse stack top N order.
|
||
@j スタックトップの n 個の値を逆転する。
|
||
*/
|
||
DEFINE_INSN
|
||
reverse
|
||
(rb_num_t n)
|
||
(...)
|
||
(...) // inc += 0;
|
||
{
|
||
rb_num_t i;
|
||
VALUE *sp = STACK_ADDR_FROM_TOP(n);
|
||
|
||
for (i=0; i<n/2; i++) {
|
||
VALUE v0 = sp[i];
|
||
VALUE v1 = TOPN(i);
|
||
sp[i] = v1;
|
||
TOPN(i) = v0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
@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 empty current stack
|
||
@j current stack を空にする。
|
||
*/
|
||
DEFINE_INSN
|
||
adjuststack
|
||
(rb_num_t n)
|
||
(...)
|
||
(...) // inc -= n
|
||
{
|
||
DEC_SP(n);
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* deal with setting */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c setting
|
||
@e defined?
|
||
@j defined? を行う。
|
||
*/
|
||
DEFINE_INSN
|
||
defined
|
||
(rb_num_t op_type, VALUE obj, VALUE needstr)
|
||
(VALUE v)
|
||
(VALUE val)
|
||
{
|
||
val = vm_defined(th, GET_CFP(), op_type, obj, needstr, v);
|
||
}
|
||
|
||
/**
|
||
@c setting
|
||
@e check `target' matches `pattern'.
|
||
`flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
|
||
VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
|
||
VM_CHECKMATCH_TYPE_CASE: check `patten === target'.
|
||
VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_op?(Module) && pattern == target'.
|
||
if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns.
|
||
@j see above comments.
|
||
*/
|
||
DEFINE_INSN
|
||
checkmatch
|
||
(rb_num_t flag)
|
||
(VALUE target, VALUE pattern)
|
||
(VALUE result)
|
||
{
|
||
result = vm_check_match(target, pattern, flag);
|
||
}
|
||
|
||
/**
|
||
@c setting
|
||
@e check keywords are specified or not.
|
||
@j キーワードが指定されているかどうかチェックする
|
||
*/
|
||
DEFINE_INSN
|
||
checkkeyword
|
||
(lindex_t kw_bits_index, rb_num_t keyword_index)
|
||
()
|
||
(VALUE ret)
|
||
{
|
||
ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP());
|
||
}
|
||
|
||
/**
|
||
@c setting
|
||
@e trace
|
||
@j trace 用の命令。
|
||
*/
|
||
DEFINE_INSN
|
||
trace
|
||
(rb_num_t nf)
|
||
()
|
||
()
|
||
{
|
||
rb_event_flag_t flag = (rb_event_flag_t)nf;
|
||
|
||
vm_dtrace(flag, th);
|
||
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0, 0 /* id and klass are resolved at callee */,
|
||
(flag & (RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN)) ? TOPN(0) : Qundef);
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 1: class/module */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c class/module
|
||
@e
|
||
enter class definition scope. if super is Qfalse, and class
|
||
"klass" is defined, it's redefine. otherwise, define "klass" class.
|
||
@j クラス定義スコープへ移行する。
|
||
もし super が Qfalse で klassクラスが定義されていれば再定義である。
|
||
そうでなければ、klass クラスを定義する。
|
||
*/
|
||
DEFINE_INSN
|
||
defineclass
|
||
(ID id, ISEQ class_iseq, rb_num_t flags)
|
||
(VALUE cbase, VALUE super)
|
||
(VALUE val)
|
||
{
|
||
VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
|
||
|
||
rb_iseq_check(class_iseq);
|
||
|
||
/* enter scope */
|
||
vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
|
||
GET_BLOCK_HANDLER(),
|
||
(VALUE)vm_cref_push(th, klass, NULL, FALSE),
|
||
class_iseq->body->iseq_encoded, GET_SP(),
|
||
class_iseq->body->local_table_size,
|
||
class_iseq->body->stack_max);
|
||
RESTORE_REGS();
|
||
NEXT_INSN();
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 2: method/iterator */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e invoke method.
|
||
@j メソッド呼び出しを行う。ci に必要な情報が格納されている。
|
||
*/
|
||
DEFINE_INSN
|
||
send
|
||
(CALL_INFO ci, CALL_CACHE cc, ISEQ blockiseq)
|
||
(...)
|
||
(VALUE val) // inc += - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0));
|
||
{
|
||
struct rb_calling_info calling;
|
||
|
||
vm_caller_setup_arg_block(th, reg_cfp, &calling, ci, blockiseq, FALSE);
|
||
vm_search_method(ci, cc, calling.recv = TOPN(calling.argc = ci->orig_argc));
|
||
CALL_METHOD(&calling, ci, cc);
|
||
}
|
||
|
||
DEFINE_INSN
|
||
opt_str_freeze
|
||
(VALUE str)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
if (BASIC_OP_UNREDEFINED_P(BOP_FREEZE, STRING_REDEFINED_OP_FLAG)) {
|
||
val = str;
|
||
}
|
||
else {
|
||
val = rb_funcall(rb_str_resurrect(str), idFreeze, 0);
|
||
}
|
||
}
|
||
|
||
DEFINE_INSN
|
||
opt_str_uminus
|
||
(VALUE str)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
if (BASIC_OP_UNREDEFINED_P(BOP_UMINUS, STRING_REDEFINED_OP_FLAG)) {
|
||
val = str;
|
||
}
|
||
else {
|
||
val = rb_funcall(rb_str_resurrect(str), idUMinus, 0);
|
||
}
|
||
}
|
||
|
||
DEFINE_INSN
|
||
opt_newarray_max
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = vm_opt_newarray_max(num, STACK_ADDR_FROM_TOP(num));
|
||
POPN(num);
|
||
}
|
||
|
||
DEFINE_INSN
|
||
opt_newarray_min
|
||
(rb_num_t num)
|
||
(...)
|
||
(VALUE val) // inc += 1 - num;
|
||
{
|
||
val = vm_opt_newarray_min(num, STACK_ADDR_FROM_TOP(num));
|
||
POPN(num);
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e Invoke method without block
|
||
@j ブロックなしでメソッド呼び出しを行う。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_send_without_block
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(...)
|
||
(VALUE val) // inc += -ci->orig_argc;
|
||
{
|
||
struct rb_calling_info calling;
|
||
calling.block_handler = VM_BLOCK_HANDLER_NONE;
|
||
vm_search_method(ci, cc, calling.recv = TOPN(calling.argc = ci->orig_argc));
|
||
CALL_METHOD(&calling, ci, cc);
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e super(args) # args.size => num
|
||
@j super を実行する。ci に必要な情報が格納されている。
|
||
*/
|
||
DEFINE_INSN
|
||
invokesuper
|
||
(CALL_INFO ci, CALL_CACHE cc, ISEQ blockiseq)
|
||
(...)
|
||
(VALUE val) // inc += - (int)(ci->orig_argc + ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0));
|
||
{
|
||
struct rb_calling_info calling;
|
||
calling.argc = ci->orig_argc;
|
||
|
||
vm_caller_setup_arg_block(th, reg_cfp, &calling, ci, blockiseq, TRUE);
|
||
calling.recv = GET_SELF();
|
||
vm_search_super_method(th, GET_CFP(), &calling, ci, cc);
|
||
CALL_METHOD(&calling, ci, cc);
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e yield(args)
|
||
@j yield を実行する。
|
||
*/
|
||
DEFINE_INSN
|
||
invokeblock
|
||
(CALL_INFO ci)
|
||
(...)
|
||
(VALUE val) // inc += 1 - ci->orig_argc;
|
||
{
|
||
struct rb_calling_info calling;
|
||
calling.argc = ci->orig_argc;
|
||
calling.block_handler = VM_BLOCK_HANDLER_NONE;
|
||
calling.recv = GET_SELF();
|
||
|
||
val = vm_invoke_block(th, GET_CFP(), &calling, ci);
|
||
if (val == Qundef) {
|
||
RESTORE_REGS();
|
||
NEXT_INSN();
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c method/iterator
|
||
@e return from this scope.
|
||
@j このスコープから抜ける。
|
||
*/
|
||
DEFINE_INSN
|
||
leave
|
||
()
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
if (OPT_CHECKED_RUN) {
|
||
const VALUE *const bp = vm_base_ptr(reg_cfp);
|
||
if (reg_cfp->sp != bp) {
|
||
vm_stack_consistency_error(th, reg_cfp, bp);
|
||
}
|
||
}
|
||
|
||
RUBY_VM_CHECK_INTS(th);
|
||
|
||
if (vm_pop_frame(th, GET_CFP(), GET_EP())) {
|
||
#if OPT_CALL_THREADED_CODE
|
||
th->retval = val;
|
||
return 0;
|
||
#else
|
||
return val;
|
||
#endif
|
||
}
|
||
else {
|
||
RESTORE_REGS();
|
||
}
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 3: exception */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c exception
|
||
@e longjump
|
||
@j 大域ジャンプを行う。
|
||
*/
|
||
DEFINE_INSN
|
||
throw
|
||
(rb_num_t throw_state)
|
||
(VALUE throwobj)
|
||
(VALUE val)
|
||
{
|
||
RUBY_VM_CHECK_INTS(th);
|
||
val = vm_throw(th, GET_CFP(), throw_state, throwobj);
|
||
THROW_EXCEPTION(val);
|
||
/* unreachable */
|
||
}
|
||
|
||
/**********************************************************/
|
||
/* deal with control flow 4: local jump */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c jump
|
||
@e set PC to (PC + dst).
|
||
@j PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
jump
|
||
(OFFSET dst)
|
||
()
|
||
()
|
||
{
|
||
RUBY_VM_CHECK_INTS(th);
|
||
JUMP(dst);
|
||
}
|
||
|
||
/**
|
||
@c jump
|
||
@e if val is not false or nil, set PC to (PC + dst).
|
||
@j もし val が false か nil でなければ、PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
branchif
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
if (RTEST(val)) {
|
||
RUBY_VM_CHECK_INTS(th);
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c jump
|
||
@e if val is false or nil, set PC to (PC + dst).
|
||
@j もし val が false か nil ならば、PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
branchunless
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
if (!RTEST(val)) {
|
||
RUBY_VM_CHECK_INTS(th);
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c jump
|
||
@e if val is nil, set PC to (PC + dst).
|
||
@j もし val が nil ならば、PC を (PC + dst) にする。
|
||
*/
|
||
DEFINE_INSN
|
||
branchnil
|
||
(OFFSET dst)
|
||
(VALUE val)
|
||
()
|
||
{
|
||
if (NIL_P(val)) {
|
||
RUBY_VM_CHECK_INTS(th);
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
|
||
/**********************************************************/
|
||
/* for optimize */
|
||
/**********************************************************/
|
||
|
||
/**
|
||
@c optimize
|
||
@e push inline-cached value and go to dst if it is valid
|
||
@j インラインキャッシュが有効なら、値をスタックにプッシュして dst へジャンプする。
|
||
*/
|
||
DEFINE_INSN
|
||
getinlinecache
|
||
(OFFSET dst, IC ic)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = vm_ic_hit_p(ic, GET_EP());
|
||
if (val != Qnil) {
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e set inline cache
|
||
@j インラインキャッシュの値を設定する。
|
||
*/
|
||
DEFINE_INSN
|
||
setinlinecache
|
||
(IC ic)
|
||
(VALUE val)
|
||
(VALUE val)
|
||
{
|
||
vm_ic_update(ic, val, GET_EP());
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e run iseq only once
|
||
@j once を実現する。
|
||
*/
|
||
DEFINE_INSN
|
||
once
|
||
(ISEQ iseq, IC ic)
|
||
()
|
||
(VALUE val)
|
||
{
|
||
val = vm_once_dispatch(iseq, ic, th);
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e case dispatcher, jump by table if possible
|
||
@j case 文で、可能なら表引きでジャンプする。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_case_dispatch
|
||
(CDHASH hash, OFFSET else_offset)
|
||
(..., VALUE key)
|
||
() // inc += -1;
|
||
{
|
||
OFFSET dst = vm_case_dispatch(hash, else_offset, key);
|
||
|
||
if (dst) {
|
||
JUMP(dst);
|
||
}
|
||
}
|
||
|
||
/** simple functions */
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X+Y.
|
||
@j 最適化された X+Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_plus
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_plus(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X-Y.
|
||
@j 最適化された X-Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_minus
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_minus(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X*Y.
|
||
@j 最適化された X*Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_mult
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_mult(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X/Y.
|
||
@j 最適化された X/Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_div
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_div(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X%Y.
|
||
@j 最適化された X%Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_mod
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_mod(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X==Y.
|
||
@j 最適化された X==Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_eq
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = opt_eq_func(recv, obj, ci, cc);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X!=Y.
|
||
@j 最適化された X!=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_neq
|
||
(CALL_INFO ci, CALL_CACHE cc, CALL_INFO ci_eq, CALL_CACHE cc_eq)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_neq(ci, cc, ci_eq, cc_eq, recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X<Y.
|
||
@j 最適化された X<Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_lt
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_lt(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X<=Y.
|
||
@j 最適化された X<=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_le
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_le(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X>Y.
|
||
@j 最適化された X>Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_gt
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_gt(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized X>=Y.
|
||
@j 最適化された X>=Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_ge
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_ge(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e <<
|
||
@j 最適化された X<<Y。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_ltlt
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_ltlt(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e []
|
||
@j 最適化された recv[obj]。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aref
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_aref(recv, obj);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e recv[obj] = set
|
||
@j 最適化された recv[obj] = set。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aset
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv, VALUE obj, VALUE set)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_aset(recv, obj, set);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(obj);
|
||
PUSH(set);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e recv[str] = set
|
||
@j 最適化された recv[str] = set。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aset_with
|
||
(CALL_INFO ci, CALL_CACHE cc, VALUE key)
|
||
(VALUE recv, VALUE val)
|
||
(VALUE val)
|
||
{
|
||
VALUE tmp = vm_opt_aset_with(recv, key, val);
|
||
|
||
if (tmp != Qundef) {
|
||
val = tmp;
|
||
}
|
||
else {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(rb_str_resurrect(key));
|
||
PUSH(val);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e recv[str]
|
||
@j 最適化された recv[str]。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_aref_with
|
||
(CALL_INFO ci, CALL_CACHE cc, VALUE key)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_aref_with(recv, key);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
PUSH(rb_str_resurrect(key));
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized length
|
||
@j 最適化された recv.length()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_length
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_length(recv, BOP_LENGTH);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized size
|
||
@j 最適化された recv.size()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_size
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_length(recv, BOP_SIZE);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized empty?
|
||
@j 最適化された recv.empty?()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_empty_p
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_empty_p(recv);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized succ
|
||
@j 最適化された recv.succ()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_succ
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_succ(recv);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized not
|
||
@j 最適化された recv.!()。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_not
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE recv)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_not(ci, cc, recv);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(recv);
|
||
CALL_SIMPLE_METHOD(recv);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized regexp match
|
||
@j 最適化された正規表現マッチ。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_regexpmatch1
|
||
(VALUE recv)
|
||
(VALUE obj)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_regexpmatch1(recv, obj);
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e optimized regexp match 2
|
||
@j 最適化された正規表現マッチ 2
|
||
*/
|
||
DEFINE_INSN
|
||
opt_regexpmatch2
|
||
(CALL_INFO ci, CALL_CACHE cc)
|
||
(VALUE obj2, VALUE obj1)
|
||
(VALUE val)
|
||
{
|
||
val = vm_opt_regexpmatch2(obj2, obj1);
|
||
|
||
if (val == Qundef) {
|
||
/* other */
|
||
PUSH(obj2);
|
||
PUSH(obj1);
|
||
CALL_SIMPLE_METHOD(obj2);
|
||
}
|
||
}
|
||
|
||
/**
|
||
@c optimize
|
||
@e call native compiled method
|
||
@j ネイティブコンパイルしたメソッドを起動。
|
||
*/
|
||
DEFINE_INSN
|
||
opt_call_c_function
|
||
(rb_insn_func_t funcptr)
|
||
()
|
||
()
|
||
{
|
||
reg_cfp = (funcptr)(th, reg_cfp);
|
||
|
||
if (reg_cfp == 0) {
|
||
VALUE err = th->ec.errinfo;
|
||
th->ec.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);
|
||
}
|
||
|