YARV Instruction Set
Instruction Table
Category |
Opcode |
Name |
Operands |
nop |
0 |
nop
|
|
variable |
1 |
getlocal
|
idx
|
variable |
2 |
setlocal
|
idx
|
variable |
3 |
getspecial
|
key, type
|
variable |
4 |
setspecial
|
key
|
variable |
5 |
getdynamic
|
idx, level
|
variable |
6 |
setdynamic
|
idx, level
|
variable |
7 |
getinstancevariable
|
id
|
variable |
8 |
setinstancevariable
|
id
|
variable |
9 |
getclassvariable
|
id
|
variable |
10 |
setclassvariable
|
id
|
variable |
11 |
getconstant
|
id
|
variable |
12 |
setconstant
|
id
|
variable |
13 |
getglobal
|
entry
|
variable |
14 |
setglobal
|
entry
|
put |
15 |
putnil
|
|
put |
16 |
putself
|
|
put |
17 |
putobject
|
val
|
put |
18 |
putstring
|
str
|
put |
19 |
concatstrings
|
num
|
put |
20 |
tostring
|
|
put |
21 |
toregexp
|
opt, cnt
|
put |
22 |
newarray
|
num
|
put |
23 |
duparray
|
ary
|
put |
24 |
expandarray
|
num, flag
|
put |
25 |
concatarray
|
|
put |
26 |
splatarray
|
flag
|
put |
27 |
checkincludearray
|
flag
|
put |
28 |
newhash
|
num
|
put |
29 |
newrange
|
flag
|
stack |
30 |
pop
|
|
stack |
31 |
dup
|
|
stack |
32 |
dupn
|
n
|
stack |
33 |
swap
|
|
stack |
34 |
reput
|
|
stack |
35 |
topn
|
n
|
stack |
36 |
setn
|
n
|
stack |
37 |
adjuststack
|
n
|
setting |
38 |
definemethod
|
id, body, is_singleton
|
setting |
39 |
alias
|
v_p
|
setting |
40 |
undef
|
|
setting |
41 |
defined
|
type, obj, needstr
|
setting |
42 |
postexe
|
blockiseq
|
setting |
43 |
trace
|
nf
|
class/module |
44 |
defineclass
|
id, class_iseq, define_type
|
method/iterator |
45 |
send
|
op_id, op_argc, blockiseq, op_flag, ic
|
method/iterator |
46 |
invokesuper
|
op_argc, blockiseq, op_flag
|
method/iterator |
47 |
invokeblock
|
num, flag
|
method/iterator |
48 |
leave
|
|
method/iterator |
49 |
finish
|
|
exception |
50 |
throw
|
throw_state
|
jump |
51 |
jump
|
dst
|
jump |
52 |
branchif
|
dst
|
jump |
53 |
branchunless
|
dst
|
optimize |
54 |
getinlinecache
|
ic, dst
|
optimize |
55 |
onceinlinecache
|
ic, dst
|
optimize |
56 |
setinlinecache
|
dst
|
optimize |
57 |
opt_case_dispatch
|
hash, else_offset
|
optimize |
58 |
opt_checkenv
|
|
optimize |
59 |
opt_plus
|
|
optimize |
60 |
opt_minus
|
|
optimize |
61 |
opt_mult
|
|
optimize |
62 |
opt_div
|
|
optimize |
63 |
opt_mod
|
|
optimize |
64 |
opt_eq
|
ic
|
optimize |
65 |
opt_neq
|
ic1, ic2
|
optimize |
66 |
opt_lt
|
|
optimize |
67 |
opt_le
|
|
optimize |
68 |
opt_gt
|
|
optimize |
69 |
opt_ge
|
|
optimize |
70 |
opt_ltlt
|
|
optimize |
71 |
opt_aref
|
|
optimize |
72 |
opt_aset
|
|
optimize |
73 |
opt_length
|
|
optimize |
74 |
opt_succ
|
|
optimize |
75 |
opt_not
|
ic
|
optimize |
76 |
opt_regexpmatch1
|
r
|
optimize |
77 |
opt_regexpmatch2
|
|
optimize |
78 |
opt_call_c_function
|
funcptr
|
joke |
79 |
bitblt
|
|
joke |
80 |
answer
|
|
Detailed Description
Description
nop
Operands
Stack
Source
/* none */
opcode : | 1 |
category : | variable |
Description
get local variable value (which is pointed by idx).
Operands
Stack
Source
val = *(GET_LFP() - idx);
opcode : | 2 |
category : | variable |
Description
set local variable value (which is pointed by idx) as val.
Operands
Stack
Source
(*(GET_LFP() - idx)) = val;
opcode : | 3 |
category : | variable |
Description
get special local variable ($~, $_, ..) value.
Operands
Stack
Source
val = vm_getspecial(th, GET_LFP(), key, type);
opcode : | 4 |
category : | variable |
Description
set special local variable ($~, $_, ...) value as obj.
Operands
Stack
Source
lfp_svar_set(th, GET_LFP(), key, obj);
opcode : | 5 |
category : | variable |
Description
get block local variable(which is pointed by idx and level).
Operands
dindex_t | idx |
rb_num_t | level |
Stack
Source
int i;
VALUE *dfp2 = GET_DFP();
for (i = 0; i < level; i++) {
dfp2 = GET_PREV_DFP(dfp2);
}
val = *(dfp2 - idx);
opcode : | 6 |
category : | variable |
Description
set block local variable(which is pointed by 'idx') as val.
Operands
dindex_t | idx |
rb_num_t | level |
Stack
Source
int i;
VALUE *dfp2 = GET_DFP();
for (i = 0; i < level; i++) {
dfp2 = GET_PREV_DFP(dfp2);
}
*(dfp2 - idx) = val;
opcode : | 7 |
category : | variable |
Description
get instance variable id of obj.
Operands
Stack
Source
val = rb_ivar_get(GET_SELF(), id);
opcode : | 8 |
category : | variable |
Description
set instance variable id of obj as val.
Operands
Stack
Source
rb_ivar_set(GET_SELF(), id, val);
opcode : | 9 |
category : | variable |
Description
get class variable id of klass as val.
Operands
Stack
Source
val = rb_cvar_get(vm_get_cvar_base(th, GET_ISEQ()), id);
opcode : | 10 |
category : | variable |
Description
set class variable id of klass as val.
Operands
Stack
Source
rb_cvar_set(vm_get_cvar_base(th, GET_ISEQ()), id, val);
opcode : | 11 |
category : | variable |
Description
Operands
Stack
Source
val = vm_get_ev_const(th, GET_ISEQ(), klass, id, 0);
opcode : | 12 |
category : | variable |
Description
Operands
Stack
Source
if (klass == Qnil) {
klass = vm_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: {
volatile VALUE tmp = rb_obj_as_string(klass);
rb_raise(rb_eTypeError, "%s is not a class/module",
RSTRING_PTR(tmp));
}
}
rb_const_set(klass, id, val);
INC_VM_STATE_VERSION();
opcode : | 13 |
category : | variable |
Description
get global variable id.
Operands
Stack
Source
val = GET_GLOBAL(entry);
opcode : | 14 |
category : | variable |
Description
set global variable id as val.
Operands
Stack
Source
SET_GLOBAL(entry, val);
Description
put nil to stack.
Operands
Stack
Source
val = Qnil;
Description
put self.
Operands
Stack
Source
val = GET_SELF();
Description
put some object.
Operands
Stack
Source
/* */
Description
put string val. string will be copied.
Operands
Stack
Source
val = rb_str_new3(str);
Description
put concatenate strings
Operands
Stack
Source
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);
Description
to_str
Operands
Stack
Source
val = rb_obj_as_string(val);
Description
to Regexp
Operands
Stack
Source
VALUE rb_reg_new_ary(VALUE ary, int options);
int i;
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);
Description
put new array.
Operands
Stack
Source
val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
POPN(num);
Description
dup array
Operands
Stack
Source
val = rb_ary_dup(ary);
Description
expand array to num objects.
Operands
Stack
Source
vm_expandarray(GET_CFP(), ary, num, flag);
Description
concat two arrays
Operands
Stack
Source
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);
Description
splat array
Operands
Stack
Source
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
if (NIL_P(tmp)) {
tmp = rb_ary_new3(1, ary);
}
obj = tmp;
Description
check value is included in ary
Operands
Stack
Source
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;
}
}
}
Description
put new Hash.
Operands
Stack
Source
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);
Description
put new Range object.(Range.new(low, high, flag))
Operands
Stack
Source
val = rb_range_new(low, high, flag);
opcode : | 30 |
category : | stack |
Description
pop from stack.
Operands
Stack
Source
val = val;
/* none */
opcode : | 31 |
category : | stack |
Description
duplicate stack top.
Operands
Stack
Source
val1 = val2 = val;
opcode : | 32 |
category : | stack |
Description
duplicate stack top n elements
Operands
Stack
Source
int i;
VALUE *sp = STACK_ADDR_FROM_TOP(n);
for (i = 0; i < n; i++) {
GET_SP()[i] = sp[i];
}
INC_SP(n);
opcode : | 33 |
category : | stack |
Description
swap top 2 vals
Operands
Stack
Source
/* none */
opcode : | 34 |
category : | stack |
Description
for stack caching.
Operands
Stack
Source
/* none */
opcode : | 35 |
category : | stack |
Description
get nth stack value from stack top
Operands
Stack
Source
val = TOPN(n);
opcode : | 36 |
category : | stack |
Description
set Nth stack entry to stack top
Operands
Stack
Source
TOPN(n-1) = val;
opcode : | 37 |
category : | stack |
Description
empt current stack
Operands
Stack
Source
DEC_SP(n);
opcode : | 38 |
category : | setting |
Description
define (singleton) method id as body
Operands
ID | id |
ISEQ | body |
rb_num_t | is_singleton |
Stack
Source
vm_define_method(th, obj, id, body, is_singleton,
get_cref(GET_ISEQ(), GET_LFP()));
opcode : | 39 |
category : | setting |
Description
make alias (if v_p is Qtrue, make valias)
Operands
Stack
Source
VALUE klass;
if (v_p == Qtrue) {
rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
}
else {
klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
rb_alias(klass, SYM2ID(sym1), SYM2ID(sym2));
}
opcode : | 40 |
category : | setting |
Description
undef
Operands
Stack
Source
VALUE klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
rb_undef(klass, SYM2ID(sym));
INC_VM_STATE_VERSION();
opcode : | 41 |
category : | setting |
Description
defined?
Operands
rb_num_t | type |
VALUE | obj |
VALUE | needstr |
Stack
Source
VALUE klass;
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 = get_cref(GET_ISEQ(), GET_LFP())->nd_clss;
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 (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;
}
}
opcode : | 42 |
category : | setting |
Description
END{}
Operands
Stack
Source
rb_block_t *blockptr;
VALUE proc;
extern void rb_call_end_proc(VALUE data);
blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(GET_CFP());
blockptr->iseq = blockiseq;
blockptr->proc = 0;
proc = vm_make_proc(th, GET_CFP(), blockptr);
rb_set_end_proc(rb_call_end_proc, proc);
opcode : | 43 |
category : | setting |
Description
trace
Operands
Stack
Source
rb_event_flag_t flag = nf;
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
opcode : | 44 |
category : | class/module |
Description
Operands
ID | id |
ISEQ | class_iseq |
rb_num_t | define_type |
Stack
Source
VALUE klass;
switch ((int)define_type) {
case 0:
/* val is dummy. classdef returns class scope value */
if (super == Qnil) {
super = rb_cObject;
}
if (cbase == Qnil) {
cbase = vm_get_cbase(th);
}
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 */
if (cbase == Qnil) {
cbase = vm_get_cbase(th);
}
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,
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();
opcode : | 45 |
category : | method/iterator |
Description
obj.send(id, args..) # args.size => num
Operands
ID | op_id |
rb_num_t | op_argc |
ISEQ | blockiseq |
rb_num_t | op_flag |
IC | ic |
Stack
Source
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);
opcode : | 46 |
category : | method/iterator |
Description
super(args) # args.size => num
Operands
rb_num_t | op_argc |
ISEQ | blockiseq |
rb_num_t | op_flag |
Stack
Source
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);
opcode : | 47 |
category : | method/iterator |
Description
yield(args) # args.size => num, flag shows expand argument or not
Operands
Stack
Source
val = vm_invoke_block(th, GET_CFP(), num, flag);
if (val == Qundef) {
RESTORE_REGS();
NEXT_INSN();
}
opcode : | 48 |
category : | method/iterator |
Description
return from this scope.
Operands
Stack
Source
if (OPT_CHECKED_RUN) {
if (reg_cfp->sp != reg_cfp->bp) {
rb_bug("Stack consistency error (sp: %d, bp: %d)",
VM_SP_CNT(th, reg_cfp->sp), VM_SP_CNT(th, reg_cfp->bp));
}
}
RUBY_VM_CHECK_INTS();
vm_pop_frame(th);
RESTORE_REGS();
opcode : | 49 |
category : | method/iterator |
Description
return from this vm loop
Operands
Stack
Source
#if OPT_CALL_THREADED_CODE
rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
#else
th->cfp++;
return val;
#endif
opcode : | 50 |
category : | exception |
Description
longjump
Operands
Stack
Source
RUBY_VM_CHECK_INTS();
val = vm_throw(th, GET_CFP(), throw_state, throwobj);
THROW_EXCEPTION(val);
/* unreachable */
opcode : | 51 |
category : | jump |
Description
set PC to (PC + dst).
Operands
Stack
Source
RUBY_VM_CHECK_INTS();
JUMP(dst);
opcode : | 52 |
category : | jump |
Description
if val is not false or nil, set PC to (PC + dst).
Operands
Stack
Source
if (RTEST(val)) {
RUBY_VM_CHECK_INTS();
JUMP(dst);
}
opcode : | 53 |
category : | jump |
Description
if val is false or nil, set PC to (PC + dst).
Operands
Stack
Source
if (!RTEST(val)) {
RUBY_VM_CHECK_INTS();
JUMP(dst);
}
opcode : | 54 |
category : | optimize |
Description
inline cache
Operands
Stack
Source
if (ic->ic_vmstat == GET_VM_STATE_VERSION()) {
val = ic->ic_value;
JUMP(dst);
}
else {
/* none */
val = Qnil;
}
opcode : | 55 |
category : | optimize |
Description
inline cache (once)
Operands
Stack
Source
if (ic->ic_vmstat) {
val = ic->ic_value;
JUMP(dst);
}
else {
/* none */
val = Qnil;
}
opcode : | 56 |
category : | optimize |
Description
set inline cache
Operands
Stack
Source
IC ic = GET_CONST_INLINE_CACHE(dst);
ic->ic_value = val;
ic->ic_vmstat = GET_VM_STATE_VERSION();
opcode : | 57 |
category : | optimize |
Description
case dispatcher
Operands
CDHASH | hash |
OFFSET | else_offset |
Stack
Source
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);
}
}
opcode : | 58 |
category : | optimize |
Description
check environment
Operands
Stack
Source
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);
}
opcode : | 59 |
category : | optimize |
Description
optimized X+Y.
Operands
Stack
Source
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);
}
opcode : | 60 |
category : | optimize |
Description
optimized X-Y.
Operands
Stack
Source
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);
}
opcode : | 61 |
category : | optimize |
Description
optimized X*Y.
Operands
Stack
Source
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);
}
opcode : | 62 |
category : | optimize |
Description
optimized X/Y.
Operands
Stack
Source
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);
}
opcode : | 63 |
category : | optimize |
Description
optimized X%Y.
Operands
Stack
Source
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);
}
opcode : | 64 |
category : | optimize |
Description
optimized X==Y.
Operands
Stack
Source
val = opt_eq_func(recv, obj, ic);
if (val == Qundef) {
/* other */
PUSH(recv);
PUSH(obj);
CALL_SIMPLE_METHOD(1, idEq, recv);
}
opcode : | 65 |
category : | optimize |
Description
optimized X!=Y.
Operands
Stack
Source
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);
}
opcode : | 66 |
category : | optimize |
Description
optimized X
Operands
Stack
Source
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 {
PUSH(recv);
PUSH(obj);
CALL_SIMPLE_METHOD(1, idLT, recv);
}
opcode : | 67 |
category : | optimize |
Description
optimized X<=Y.
Operands
Stack
Source
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 */
PUSH(recv);
PUSH(obj);
CALL_SIMPLE_METHOD(1, idLE, recv);
}
opcode : | 68 |
category : | optimize |
Description
optimized X>Y.
Operands
Stack
Source
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GT)) {
long a = FIX2LONG(recv), b = FIX2LONG(obj);
if (a > b) {
val = Qtrue;
}
else {
val = Qfalse;
}
}
else {
PUSH(recv);
PUSH(obj);
CALL_SIMPLE_METHOD(1, idGT, recv);
}
opcode : | 69 |
category : | optimize |
Description
optimized X>=Y.
Operands
Stack
Source
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GE)) {
long a = FIX2LONG(recv), b = FIX2LONG(obj);
if (a >= b) {
val = Qtrue;
}
else {
val = Qfalse;
}
}
else {
PUSH(recv);
PUSH(obj);
CALL_SIMPLE_METHOD(1, idGE, recv);
}
opcode : | 70 |
category : | optimize |
Description
<<
Operands
Stack
Source
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);
}
opcode : | 71 |
category : | optimize |
Description
[]
Operands
Stack
Source
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);
}
opcode : | 72 |
category : | optimize |
Description
recv[obj] = set
Operands
Stack
Before | | After |
VALUE | set |
VALUE | obj |
VALUE | recv |
|
=> |
|
Source
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);
}
opcode : | 73 |
category : | optimize |
Description
optimized length
Operands
Stack
Source
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);
}
opcode : | 74 |
category : | optimize |
Description
optimized succ
Operands
Stack
Source
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);
}
opcode : | 75 |
category : | optimize |
Description
optimized not
Operands
Stack
Source
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);
}
opcode : | 76 |
category : | optimize |
Description
optimized regexp match
Operands
Stack
Source
val = rb_reg_match(r, obj);
opcode : | 77 |
category : | optimize |
Description
optimized regexp match 2
Operands
Stack
Source
if (TYPE(obj2) == T_STRING) {
val = rb_reg_match(obj1, obj2);
}
else {
val = rb_funcall(obj2, idEqTilde, 1, obj1);
}
opcode : | 78 |
category : | optimize |
Description
call native compiled method
Operands
Stack
Source
reg_cfp = (funcptr)(th, reg_cfp);
if (reg_cfp == 0) {
VALUE err = th->errinfo;
th->errinfo = Qnil;
THROW_EXCEPTION(err);
}
RESTORE_REGS();
NEXT_INSN();
opcode : | 79 |
category : | joke |
Description
BLT
Operands
Stack
Source
ret = rb_str_new2("a bit of bacon, lettuce and tomato");
opcode : | 80 |
category : | joke |
Description
The Answer to Life, the Universe, and Everything
Operands
Stack
Source
ret = INT2FIX(42);