summaryrefslogtreecommitdiffhomepage
path: root/doc/opcode.md
blob: fea0afafdf69bc01f0abedbd7aa6294267001351 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# The new bytecode

We will reimplement VM to use 8bit instruction code. By
bytecode, we mean real byte code. The whole purpose is
reducing the memory consumption of mruby VM.

# Instructions

Instructions are bytes. There can be 256 instructions. Currently we
have 94 instructions. Instructions can take 0 to 3 operands.

## operands

The size of operands can be either 8bits, 16bits or 24bits.
In the table.1 below, the second field describes the size (and
sign) of operands.

* B: 8bit
* sB: signed 8bit
* S: 16bit
* sS: signed 16bit
* W: 24bit

First two byte operands may be extended to 16bit. When those byte
operands are bigger than 256, the instruction will be prefixed by
`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand
is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit).

For instructions marked by `'`, `OP_EXT1` can be prefixed. For those
with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.

## table.1 Instruction Table

|Instruction Name |Operand type |Semantics        
|-----------------|-------------|-----------------
|OP_NOP           | -           |                 
|OP_MOVE"         |BB           |R(a) = R(b)      
|OP_LOADL"        |BB           |R(a) = Pool(b)   
|OP_LOADI"        |BsB          |R(a) = mrb_int(b)
|OP_LOADI_0'      |B            |R(a) = 0
|OP_LOADI_1'      |B            |R(a) = 1
|OP_LOADI_2'      |B            |R(a) = 2
|OP_LOADI_3'      |B            |R(a) = 3
|OP_LOADSYM"      |BB           |R(a) = Syms(b)
|OP_LOADNIL'      |B            |R(a) = nil
|OP_LOADSELF'     |B            |R(a) = self
|OP_LOADT'        |B            |R(a) = true
|OP_LOADF'        |B            |R(a) = false
|OP_GETGV"        |BB           |R(a) = getglobal(Syms(b))
|OP_SETGV"        |BB           |setglobal(Syms(b), R(a))
|OP_GETSV"        |BB           |R(a) = Special[b]
|OP_SETSV"        |BB           |Special[b] = R(a)
|OP_GETIV"        |BB           |R(a) = ivget(Syms(b))
|OP_SETIV"        |BB           |ivset(Syms(b),R(a))
|OP_GETCV"        |BB           |R(a) = cvget(Syms(b))
|OP_SETCV"        |BB           |cvset(Syms(b),R(a))
|OP_GETCONST"     |BB           |R(a) = constget(Syms(b))
|OP_SETCONST"     |BB           |constset(Syms(b),R(a))
|OP_GETMCNST"     |BB           |R(a) = R(a)::Syms(b)
|OP_SETMCNST"     |BB           |R(a+1)::Syms(b) = R(a)
|OP_GETUPVAR'     |BBB          |R(a) = uvget(b,c)
|OP_SETUPVAR'     |BBB          |uvset(b,c,R(a))
|OP_JMP           |S            |pc+=a
|OP_JMPIF'        |SB           |if R(b) pc+=a
|OP_JMPNOT'       |SB           |if !R(b) pc+=a
|OP_ONERR         |sS           |rescue_push(pc+a)
|OP_EXCEPT'       |B            |R(a) = exc
|OP_RESCUE"       |BB           |R(b) = R(a).isa?(R(b))
|OP_POPERR        |B            |a.times{rescue_pop()}
|OP_RAISE'        |B            |raise(R(a))
|OP_EPUSH'        |B            |ensure_push(SEQ[a])
|OP_EPOP          |B            |A.times{ensure_pop().call}
|OP_SENDV"        |BB           |R(a) = call(R(a),Syms(b),*R(a+1))
|OP_SENDVB"       |BB           |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2))
|OP_SEND"         |BBB          |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
|OP_SENDB"        |BBB          |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1))
|OP_CALL'         |B            |R(a) = self.call(frame.argc, frame.argv)
|OP_SUPER'        |BB           |R(a) = super(R(a+1),... ,R(a+b+1))
|OP_ARGARY'       |BS           |R(a) = argument array (16=5:1:5:1:4)
|OP_ENTER         |W            |arg setup according to flags (23=5:5:1:5:5:1:1)
|OP_KARG"         |BB           |R(a) = kdict[Syms(Bx)]                          # todo
|OP_KARG2"        |BB           |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b))       # todo
|OP_RETURN'       |B            |return R(a) (normal)
|OP_RETURN_BLK'   |B            |return R(a) (in-block return)
|OP_BREAK'        |B            |break R(a)
|OP_BLKPUSH'      |BS           |R(a) = block (16=5:1:5:1:4)
|OP_ADD"          |BB           |R(a) = R(a)+R(a+1) (Syms[b]=:+)
|OP_ADDI"         |BBB          |R(a) = R(a)+mrb_int(c) (Syms[b]=:+)
|OP_SUB"          |BB           |R(a) = R(a)-R(a+1) (Syms[b]=:-)
|OP_SUBI"         |BB           |R(a) = R(a)-C (Syms[b]=:-)
|OP_MUL"          |BB           |R(a) = R(a)*R(a+1) (Syms[b]=:*)
|OP_DIV"          |BB           |R(a) = R(a)/R(a+1) (Syms[b]=:/)
|OP_EQ"           |BB           |R(a) = R(a)==R(a+1) (Syms[b]=:==)
|OP_LT"           |BB           |R(a) = R(a)<R(a+1)  (Syms[b]=:<)
|OP_LE"           |BB           |R(a) = R(a)<=R(a+1) (Syms[b]=:<=)
|OP_GT"           |BB           |R(a) = R(a)>R(a+1)  (Syms[b]=:>)
|OP_GE"           |BB           |R(a) = R(a)>=R(a+1) (Syms[b]=:>=)
|OP_ARRAY'        |BB           |R(a) = ary_new(R(a),R(a+1)..R(a+b))
|OP_ARRAY2"       |BB           |R(a) = ary_new(R(b),R(b+1)..R(b+c))
|OP_ARYCAT'       |B            |ary_cat(R(a),R(a+1))
|OP_ARYPUSH'      |B            |ary_push(R(a),R(a+1))
|OP_AREF'         |BB           |R(a) = R(a)[b]
|OP_ASET'         |BB           |R(a)[b] = R(a+1)
|OP_APOST'        |BB           |*R(a),R(A+1)..R(A+C) = R(a)[B..]
|OP_STRING"       |BB           |R(a) = str_dup(Lit(b))
|OP_STRCAT'       |B            |str_cat(R(a),R(a+1))
|OP_HASH'         |BB           |R(a) = hash_new(R(a),R(a+1)..R(a+b))
|OP_HASHADD'      |BB           |R(a) = hash_push(R(a),R(a+1)..R(a+b))
|OP_LAMBDA"       |BB           |R(a) = lambda(SEQ[b],OP_L_LAMBDA)
|OP_BLOCK"        |BB           |R(a) = lambda(SEQ[b],OP_L_BLOCK)
|OP_METHOD"       |BB           |R(a) = lambda(SEQ[b],OP_L_METHOD)
|OP_RANGE_INC'    |B            |R(a) = range_new(R(a),R(a+1),FALSE)
|OP_RANGE_EXC'    |B            |R(a) = range_new(R(a),R(a+1),TRUE)
|OP_OCLASS'       |B            |R(a) = ::Object
|OP_CLASS"        |BB           |R(a) = newclass(R(a),Syms(b),R(a+1))
|OP_MODULE"       |BB           |R(a) = newmodule(R(a),Syms(b))
|OP_EXEC"         |BB           |R(a) = blockexec(R(a),SEQ[b])
|OP_DEF"          |BB           |R(a).newmethod(Syms(b),R(a+1))
|OP_ALIAS'        |B            |alias_method(R(a),R(a+1),R(a+2))
|OP_UNDEF"        |BB           |undef_method(R(a),Syms(b))
|OP_SCLASS'       |B            |R(a) = R(a).singleton_class
|OP_TCLASS'       |B            |R(a) = target_class
|OP_ERR'          |B            |raise(RuntimeError, Lit(Bx))
|OP_EXT1          |-            |make 1st operand 16bit
|OP_EXT2          |-            |make 2nd operand 16bit
|OP_EXT3          |-            |make 1st and 2nd operands 16bit
|OP_STOP          |-            |stop VM