2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module gaem
.runner
.opcodes
is aliced
;
21 // ////////////////////////////////////////////////////////////////////////// //
24 skip
, // skip current instruction; it usually has 3-byte payload
26 copy
, // copy regs; dest: dest reg; op0: first reg to copy; op1: number of regs to copy (0: no copy, lol)
53 plit
, // dest becomes pool slot val (val: 2 bytes) -- load value from pool slot; if val is 0xffff, next instruction is skip
54 ilit
, // dest becomes ilit val (val: short) -- load small integer literal
55 xlit
, // dest becomes integer(!) val (val: short) -- load small integer literal
57 jump
, // addr: 3 bytes
58 xtrue
, // dest is reg to check; skip next instruction if dest is "gml true" (i.e. fabs(v) >= 0.5`)
59 xfalse
, // dest is reg to check; skip next instruction if dest is "gml false" (i.e. fabs(v) >= 0.5`)
61 call, // dest is result; op0: call frame (see below); op1: number of args
64 // int scriptid (after op1+3 slots)
65 // note that there should be no used registers after those (as that will be used as new function frame regs)
67 enter, // dest: number of arguments used; op0: number of stack slots used (including result and args); op1: number of locals
68 // any function will ALWAYS starts with this
70 ret, // dest is retvalue; it is copied to reg0; other stack items are discarded
72 fval
, // load field value; op0: obj id; op1: int! reg (field id)
73 i1val
, // load indexed value; op0: varref; op1: index
74 i2val
, // load indexed value; op0: varref; op1: first index; (op1+1): second index
76 // ref+store will be replaced with this
77 lstore
, // store value *from* dest into local slot; op0: slot number
78 fstore
, // store value *from* dest into field; op0: obj id; op1: int! reg (field id); can create fields
79 i1store
, // store value *from* dest into indexed reference; op0: varref; op1: index; can create arrays
80 i2store
, // store value *from* dest into indexed reference; op0: varref; op1: first index; (op1+1): second index; can create arrays
82 // `with` is done by copying `self` to another reg, execute the code and restore `self`
84 siter
, // start instance iterator; dest: iterid; op0: objid or instid
85 // this is special: it will skip next instruction if iteration has at least one item
86 // next instruction is always jump, which skips the loop
87 niter
, // dest is iterreg; do jump (pc is the same as in jump) if iteration is NOT complete
88 kiter
, // kill iterator, should be called to prevent memory leaks
90 // so return from `with` should call kiter for all created iterators first
92 // possible iterator management: preallocate slots for each non-overlapped "with";
93 // let VM to free all iterators from those slots on function exit
95 lirint
, // dest = lrint(op0): do lrint() (or another fast float->int conversion)
97 // as we are using refloads only in the last stage of assignment, they can create values
98 // there "ref" opcodes will be never seen in the final compiled code
99 // the compiler will change 'em to the corresponding stores
100 lref
, // load slot reference to dest; op0: slot number
101 fref
, // load field reference; op0: obj id; op1: int! reg (field id); can create fields
102 i1ref
, // load indexed reference; op0: varref; op1: index; can create arrays
103 i2ref
, // load indexed reference; op0: varref; op1: first index; (op1+1): second index; can create arrays
104 //rstore, // store to op0-varref from op1
108 // ////////////////////////////////////////////////////////////////////////// //
109 ubyte opCode (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
&0xff); }
110 ubyte opDest (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>8)&0xff); }
111 ubyte opOp0 (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>16)&0xff); }
112 ubyte opOp1 (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>24)&0xff); }
113 short opILit (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(short)((op
>>16)&0xffff); }
114 uint op3Byte (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
>>8); }
115 uint op2Byte (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
>>16); }
117 uint opMakeILit (ubyte op
, byte dest
, short val
) pure nothrow @safe @nogc { pragma(inline
, true); return ((val
<<16)|
((dest
&0xff)<<8)|op
); }
118 uint opMake3Byte (ubyte op
, uint val
) pure nothrow @safe @nogc { pragma(inline
, true); assert(val
<= 0xffffff); return (val
<<8)|op
; }
121 // ////////////////////////////////////////////////////////////////////////// //
122 private import std
.stdio
: File
;
124 // returns instruction size
125 uint dumpInstr (File fo
, uint pc
, const(uint)[] code
) {
126 fo
.writef("%08X: ", pc
);
127 if (pc
== 0 || pc
>= code
.length
) {
128 fo
.writeln("<INVALID>");
131 auto atp
= opargs
[code
[pc
].opCode
];
132 if (atp
== OpArgs
.None
) {
133 fo
.writefln("%s", cast(Op
)code
[pc
].opCode
);
136 fo
.writef("%-8s", cast(Op
)code
[pc
].opCode
);
137 switch (atp
) with (OpArgs
) {
138 case Dest
: fo
.writefln("dest:%s", code
[pc
].opDest
); break;
139 case DestOp0
: fo
.writefln("dest:%s, op0:%s", code
[pc
].opDest
, code
[pc
].opOp0
); break;
140 case DestOp0Op1
: fo
.writefln("dest:%s, op0:%s, op1:%s", code
[pc
].opDest
, code
[pc
].opOp0
, code
[pc
].opOp1
); break;
141 case Dest2Bytes
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].op2Byte
); break;
142 case Dest3Bytes
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].op3Byte
); break;
143 case DestInt
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].opILit
); break;
144 case DestJump
: fo
.writefln("0x%08x", code
[pc
].op3Byte
); break;
145 case DestCall
: fo
.writefln("dest:%s; frame:%s; args:%s", code
[pc
].opDest
, code
[pc
].opOp0
, code
[pc
].opOp1
); break;
146 case Op0Op1
: fo
.writefln("op0:%s, op1:%s", code
[pc
].opOp0
, code
[pc
].opOp1
); break;
153 // ////////////////////////////////////////////////////////////////////////// //
169 __gshared
immutable OpArgs
[ubyte] opargs
;
172 shared static this () {
173 with(OpArgs
) opargs
= [
177 Op
.lnot
: DestOp0
, //: lognot
212 Op
.enter: DestOp0Op1
,
216 Op
.lstore
: DestOp0Op1
, // store value *from* dest into local slot; op0: slot number
217 Op
.fstore
: DestOp0Op1
, // store value *from* dest into field; op0: obj id; op1: int! reg (field id); can create fields
218 Op
.i1store
: DestOp0Op1
, // store value *from* dest into indexed reference; op0: varref; op1: index; can create arrays
219 Op
.i2store
: DestOp0Op1
, // store value *from* dest into indexed reference; op0: varref; op1: first index; (op1+1): second index; can create arrays
223 Op
.i1val
: DestOp0Op1
,
224 Op
.i2val
: DestOp0Op1
,
227 Op
.i1ref
: DestOp0Op1
,
228 Op
.i2ref
: DestOp0Op1
,
230 //Op.rstore: DestOp0,
236 Op
.lirint
: DestOp0
, // dest = lrint(op0): do lrint() (or another fast float->int conversion)