|
dvander@47
|
1 |
/* vim: set ts=4 sw=4 tw=99 et: |
|
dvander@47
|
2 |
* |
|
dvander@0
|
3 |
* Copyright (C) 2012 David Anderson |
|
dvander@0
|
4 |
* |
|
dvander@0
|
5 |
* This file is part of JITCraft. |
|
dvander@0
|
6 |
* |
|
dvander@0
|
7 |
* JITCraft is free software: you can redistribute it and/or modify it under |
|
dvander@0
|
8 |
* the terms of the GNU General Public License as published by the Free |
|
dvander@0
|
9 |
* Software Foundation, either version 3 of the License, or (at your option) |
|
dvander@0
|
10 |
* any later version. |
|
dvander@0
|
11 |
* |
|
dvander@0
|
12 |
* Foobar is distributed in the hope that it will be useful, but WITHOUT ANY |
|
dvander@0
|
13 |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
dvander@0
|
14 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|
dvander@0
|
15 |
* |
|
dvander@0
|
16 |
* You should have received a copy of the GNU General Public License along with |
|
dvander@0
|
17 |
* JITCraft. If not, see http://www.gnu.org/licenses/. |
|
dvander@0
|
18 |
*/ |
|
dvander@0
|
19 |
// Opcode macros: |
|
dvander@195
|
20 |
// NAME TEXT LENGTH USES DEFS |
|
dvander@0
|
21 |
// |
|
dvander@0
|
22 |
// Type suffixes: |
|
dvander@0
|
23 |
// I = 32-bit integer |
|
dvander@19
|
24 |
// F = 32-bit IEEE-754 float |
|
dvander@19
|
25 |
// O = object reference |
|
dvander@0
|
26 |
|
|
dvander@0
|
27 |
// No operation. |
|
dvander@195
|
28 |
OPDEF(OP_NOP, "nop", 1, 0, 0) |
|
dvander@0
|
29 |
|
|
dvander@0
|
30 |
// Pushes a signed integer immediate onto the stack. |
|
dvander@195
|
31 |
OPDEF(OP_INT, "int", 5, 0, 1) |
|
dvander@0
|
32 |
|
|
dvander@0
|
33 |
// Returns from the current routine, propagating the value at the top of the |
|
dvander@0
|
34 |
// stack to the caller. |
|
dvander@195
|
35 |
OPDEF(OP_RETURN, "return", 1, 1, 0) |
|
dvander@0
|
36 |
|
|
dvander@0
|
37 |
// value = pop() |
|
dvander@0
|
38 |
// if (value == [true, false]) |
|
dvander@0
|
39 |
// goto target |
|
dvander@195
|
40 |
OPDEF(OP_JT, "jt", 5, 1, 0) |
|
dvander@195
|
41 |
OPDEF(OP_JF, "jf", 5, 1, 0) |
|
dvander@74
|
42 |
|
|
dvander@0
|
43 |
// Unconditional jump. |
|
dvander@195
|
44 |
OPDEF(OP_JUMP, "jump", 5, 0, 0) |
|
dvander@0
|
45 |
|
|
dvander@0
|
46 |
// Gets or sets the value of a local variable onto the stack. The local |
|
dvander@0
|
47 |
// variable is given by an immediate index. |
|
dvander@195
|
48 |
OPDEF(OP_GETLOCAL, "getlocal", 5, 0, 1) |
|
dvander@195
|
49 |
OPDEF(OP_SETLOCAL, "setlocal", 5, 1, 1) |
|
dvander@0
|
50 |
|
|
dvander@0
|
51 |
// Stack transitions for these binary operators: |
|
dvander@0
|
52 |
// rhs = pop() |
|
dvander@0
|
53 |
// lhs = pop() |
|
dvander@0
|
54 |
// push(lhs OP rhs) |
|
dvander@195
|
55 |
OPDEF(OP_ADD, "add", 1, 2, 1) |
|
dvander@195
|
56 |
OPDEF(OP_SUB, "sub", 1, 2, 1) |
|
dvander@195
|
57 |
OPDEF(OP_MUL, "mul", 1, 2, 1) |
|
dvander@195
|
58 |
OPDEF(OP_DIV, "div", 1, 2, 1) |
|
dvander@195
|
59 |
OPDEF(OP_MOD, "mod", 1, 2, 1) |
|
dvander@0
|
60 |
|
|
dvander@195
|
61 |
OPDEF(OP_LT, "lt", 1, 2, 1) |
|
dvander@195
|
62 |
OPDEF(OP_LE, "le", 1, 2, 1) |
|
dvander@195
|
63 |
OPDEF(OP_GE, "ge", 1, 2, 1) |
|
dvander@195
|
64 |
OPDEF(OP_GT, "gt", 1, 2, 1) |
|
dvander@195
|
65 |
OPDEF(OP_EQ, "eq", 1, 2, 1) |
|
dvander@195
|
66 |
OPDEF(OP_NE, "ne", 1, 2, 1) |
|
dvander@74
|
67 |
|
|
dvander@195
|
68 |
OPDEF(OP_NOT, "not", 1, 1, 1) |
|
dvander@195
|
69 |
OPDEF(OP_NEG, "neg", 1, 1, 1) |
|
dvander@79
|
70 |
|
|
dvander@195
|
71 |
OPDEF(OP_POP, "pop", 1, 1, 0) |
|
dvander@0
|
72 |
|
|
dvander@72
|
73 |
// Unconditional terminator placed at the end of code. If a function returns |
|
dvander@72
|
74 |
// void, this acts as a RETURNVOID. Otherwise, it must be unreachable. |
|
dvander@195
|
75 |
OPDEF(OP_STOP, "stop", 1, 0, 0) |
|
dvander@0
|
76 |
|
|
dvander@73
|
77 |
// Call a function with N arguments. The target function must be the last item |
|
dvander@73
|
78 |
// on the stack. |
|
dvander@195
|
79 |
OPDEF(OP_CALL, "call", 1, -1, 1) |
|
dvander@0
|
80 |
|
|
dvander@0
|
81 |
// Similar to GET/LOCAL, except for arguments. |
|
dvander@195
|
82 |
OPDEF(OP_GETARG, "getarg", 5, 0, 1) |
|
dvander@195
|
83 |
OPDEF(OP_SETARG, "setarg", 5, 1, 1) |
|
dvander@0
|
84 |
|
|
dvander@185
|
85 |
// Allocates either: |
|
dvander@185
|
86 |
// A fixed array, |
|
dvander@185
|
87 |
// A 0-length dynamic array, or |
|
dvander@185
|
88 |
// A dynamic array whose size is specified on the stack. |
|
dvander@185
|
89 |
// |
|
dvander@185
|
90 |
// The HeapTenure is stored as a byte following the pc. The ArrayMap to use |
|
dvander@185
|
91 |
// is specified as an index into the script's object table. |
|
dvander@157
|
92 |
// |
|
dvander@157
|
93 |
// Format: |
|
dvander@182
|
94 |
// [u8 op] [u8 tenure] [u32 index] |
|
dvander@195
|
95 |
OPDEF(OP_NEWFIXED, "newfixed", 6, 0, 1) |
|
dvander@195
|
96 |
OPDEF(OP_NEWEMPTY, "newempty", 6, 0, 1) |
|
dvander@195
|
97 |
OPDEF(OP_NEWSIZED, "newsized", 6, -1, 1) |
|
dvander@157
|
98 |
|
|
dvander@157
|
99 |
// Performs an array-to-array assignment. |
|
dvander@157
|
100 |
// Left = pop() |
|
dvander@157
|
101 |
// Right = pop() |
|
dvander@157
|
102 |
// copy(Left, Right) |
|
dvander@157
|
103 |
// push(Left) |
|
dvander@195
|
104 |
OPDEF(OP_COPYARRAY, "arraycopy", 1, 2, 1) |
|
dvander@157
|
105 |
|
|
dvander@0
|
106 |
// Reads or writes an integer element to an unsafe array. |
|
dvander@0
|
107 |
// index = pop() |
|
dvander@0
|
108 |
// ref = pop() |
|
dvander@0
|
109 |
// ref[index] |
|
dvander@0
|
110 |
// |
|
dvander@195
|
111 |
OPDEF(OP_GETELEM, "getelem", 1, 2, 1) |
|
dvander@195
|
112 |
OPDEF(OP_SETELEM, "setelem", 1, 3, 1) |
|
dvander@0
|
113 |
|
|
dvander@4
|
114 |
// Pushes a 32-bit IEEE-754 floating point immediate onto the stack. |
|
dvander@195
|
115 |
OPDEF(OP_FLOAT, "float", 5, 0, 1) |
|
dvander@4
|
116 |
|
|
dvander@4
|
117 |
// Converts an integer to a 32-bit IEEE-754 floating point immediate. |
|
dvander@195
|
118 |
OPDEF(OP_CVT_I2F, "cvt.i2f", 1, 1, 1) |
|
dvander@208
|
119 |
OPDEF(OP_CVT_I2B, "cvt.i2b", 1, 1, 1) |
|
dvander@4
|
120 |
|
|
dvander@4
|
121 |
// Stack transitions for these binary operators: |
|
dvander@4
|
122 |
// rhs = pop() |
|
dvander@4
|
123 |
// lhs = pop() |
|
dvander@4
|
124 |
// push(lhs OP rhs) |
|
dvander@195
|
125 |
OPDEF(OP_ADD_F, "add.f", 1, 2, 1) |
|
dvander@195
|
126 |
OPDEF(OP_SUB_F, "sub.f", 1, 2, 1) |
|
dvander@195
|
127 |
OPDEF(OP_MUL_F, "mul.f", 1, 2, 1) |
|
dvander@195
|
128 |
OPDEF(OP_DIV_F, "div.f", 1, 2, 1) |
|
dvander@74
|
129 |
|
|
dvander@195
|
130 |
OPDEF(OP_LT_F, "lt.f", 1, 2, 1) |
|
dvander@195
|
131 |
OPDEF(OP_LE_F, "le.f", 1, 2, 1) |
|
dvander@195
|
132 |
OPDEF(OP_GE_F, "ge.f", 1, 2, 1) |
|
dvander@195
|
133 |
OPDEF(OP_GT_F, "gt.f", 1, 2, 1) |
|
dvander@195
|
134 |
OPDEF(OP_EQ_F, "eq.f", 1, 2, 1) |
|
dvander@195
|
135 |
OPDEF(OP_NE_F, "ne.f", 1, 2, 1) |
|
dvander@79
|
136 |
|
|
dvander@195
|
137 |
OPDEF(OP_NOT_F, "not.f", 1, 1, 1) |
|
dvander@195
|
138 |
OPDEF(OP_NEG_F, "neg.f", 1, 1, 1) |
|
dvander@4
|
139 |
|
|
dvander@8
|
140 |
// Bitwise operators. |
|
dvander@195
|
141 |
OPDEF(OP_SHL, "shl", 1, 2, 1) |
|
dvander@195
|
142 |
OPDEF(OP_SHR, "shr", 1, 2, 1) |
|
dvander@195
|
143 |
OPDEF(OP_USHR, "ushr", 1, 2, 1) |
|
dvander@195
|
144 |
OPDEF(OP_BITAND, "bitand", 1, 2, 1) |
|
dvander@195
|
145 |
OPDEF(OP_BITOR, "bitor", 1, 2, 1) |
|
dvander@195
|
146 |
OPDEF(OP_BITXOR, "bitxor", 1, 2, 1) |
|
dvander@195
|
147 |
OPDEF(OP_BITNOT, "bitnot", 1, 1, 1) |
|
dvander@12
|
148 |
|
|
dvander@12
|
149 |
// Saves or restores the position of the LIFO heap to/from a local slot. |
|
dvander@195
|
150 |
OPDEF(OP_SAVELIFO, "savelifo", 5, 0, 0) |
|
dvander@195
|
151 |
OPDEF(OP_UNWINDLIFO, "unwindlifo", 5, 0, 0) |
|
dvander@14
|
152 |
|
|
dvander@14
|
153 |
// Composes a variable reference to a stack slot or argument. |
|
dvander@195
|
154 |
OPDEF(OP_VARREF_LIFO, "varref.lifo", 5, 0, 1) |
|
dvander@195
|
155 |
OPDEF(OP_ARGREF_LIFO, "argref.lifo", 5, 0, 1) |
|
dvander@195
|
156 |
OPDEF(OP_SLOTREF_LIFO, "slotref.lifo", 1, 1, 1) |
|
dvander@195
|
157 |
OPDEF(OP_GETREF_I, "getref.i", 1, 1, 1) |
|
dvander@195
|
158 |
OPDEF(OP_SETREF_I, "setref.i", 1, 2, 1) |
|
dvander@195
|
159 |
OPDEF(OP_GETREF_F, "getref.f", 1, 1, 1) |
|
dvander@195
|
160 |
OPDEF(OP_SETREF_F, "setref.f", 1, 2, 1) |
|
dvander@21
|
161 |
|
|
dvander@21
|
162 |
// Pushes an object reference onto the stack. |
|
dvander@195
|
163 |
OPDEF(OP_OBJECT, "object", 5, 0, 1) |
|
dvander@22
|
164 |
|
|
dvander@22
|
165 |
// Duplicates the top item on the stack. |
|
dvander@195
|
166 |
OPDEF(OP_DUP, "dup", 1, 1, 2) |
|
dvander@22
|
167 |
|
|
dvander@22
|
168 |
// Duplicates the top two items on the stack. |
|
dvander@195
|
169 |
OPDEF(OP_DUP2, "dup2", 1, 2, 4) |
|
dvander@23
|
170 |
|
|
dvander@23
|
171 |
// Swaps the two items at the top of the stack. |
|
dvander@195
|
172 |
OPDEF(OP_SWAP, "swap", 1, 2, 2) |
|
dvander@23
|
173 |
|
|
dvander@23
|
174 |
// Roll operation is the same as Forth. It steals a value on the stack, |
|
dvander@23
|
175 |
// shifting all stack values down, and then places the stolen value back at |
|
dvander@23
|
176 |
// the top of the stack. |
|
dvander@23
|
177 |
// |
|
dvander@23
|
178 |
// p = sp[-3] |
|
dvander@23
|
179 |
// sp[-3] = sp[-2] |
|
dvander@23
|
180 |
// sp[-2] = sp[-1] |
|
dvander@23
|
181 |
// sp[-1] = p |
|
dvander@195
|
182 |
OPDEF(OP_ROLL3, "roll3", 1, 3, 3) |
|
dvander@23
|
183 |
|
|
dvander@23
|
184 |
// Pick operation is the same as Forth. It pushes a copy of a slot at a |
|
dvander@23
|
185 |
// specific depth. |
|
dvander@23
|
186 |
// |
|
dvander@23
|
187 |
// push(sp[-n]) |
|
dvander@195
|
188 |
OPDEF(OP_PICK2, "pick2", 1, 2, 3) |
|
dvander@195
|
189 |
OPDEF(OP_PICK3, "pick3", 1, 3, 4) |
|
dvander@68
|
190 |
|
|
dvander@68
|
191 |
// Calls a native function. During the course of calling a native, arguments |
|
dvander@68
|
192 |
// on the stack are re-pushed to match the cell-based native calling |
|
dvander@68
|
193 |
// convention expected by ISourcePawnEngine. |
|
dvander@68
|
194 |
// |
|
dvander@68
|
195 |
// Unlike the normal CALL instruction, natives take truly variadic arguments |
|
dvander@195
|
196 |
// and so we must specify the number of arguments. |
|
dvander@68
|
197 |
// |
|
dvander@195
|
198 |
// [u8 Opcode] [u32 ArgCount] |
|
dvander@68
|
199 |
// |
|
dvander@195
|
200 |
OPDEF(OP_CALLNATIVE, "callnative", 5, -1, 1) |
|
dvander@72
|
201 |
|
|
dvander@72
|
202 |
// Returns from a function that does return a value. |
|
dvander@195
|
203 |
OPDEF(OP_RETURNVOID, "returnvoid", 1, 0, 0) |
|
dvander@73
|
204 |
|
|
dvander@195
|
205 |
// Opcodes for accessing an environment slot in the global scope. The index |
|
dvander@195
|
206 |
// maps into the code object's string table, and represents the name of the |
|
dvander@195
|
207 |
// global variable. |
|
dvander@195
|
208 |
OPDEF(OP_SETGLOBAL, "setglobal", 5, 1, 1) |
|
dvander@195
|
209 |
OPDEF(OP_GETGLOBAL, "getglobal", 5, 0, 1) |
|
dvander@142
|
210 |
|
|
dvander@142
|
211 |
// Reinterprets a 32-bit integer as a float, or vice-versa. |
|
dvander@195
|
212 |
OPDEF(OP_BITS_I2F, "bits.i2f", 1, 1, 1) |
|
dvander@195
|
213 |
OPDEF(OP_BITS_F2I, "bits.f2i", 1, 1, 1) |
|
dvander@142
|
214 |
|
|
dvander@143
|
215 |
// Pushes a boolean value. |
|
dvander@195
|
216 |
OPDEF(OP_TRUE, "true", 1, 0, 1) |
|
dvander@195
|
217 |
OPDEF(OP_FALSE, "false", 1, 0, 1) |
|
dvander@143
|
218 |
|
|
dvander@147
|
219 |
// Allocate a struct. The HeapTenure is stored as a byte following pc. The |
|
dvander@147
|
220 |
// StructMap to use is specified as an index into the script's Map table. |
|
dvander@147
|
221 |
// |
|
dvander@147
|
222 |
// Format: |
|
dvander@182
|
223 |
// [u8 op] [u8 tenure] [u32 index] |
|
dvander@195
|
224 |
OPDEF(OP_NEWSTRUCT, "newstruct", 6, 0, 1) |
|
dvander@147
|
225 |
|
|
dvander@152
|
226 |
// Performs a struct-to-struct assignment. |
|
dvander@152
|
227 |
// Left = pop() |
|
dvander@152
|
228 |
// Right = pop() |
|
dvander@152
|
229 |
// copy(Left, Right) |
|
dvander@152
|
230 |
// push(Left) |
|
dvander@195
|
231 |
OPDEF(OP_COPYSTRUCT, "structcopy", 1, 2, 1) |
|
dvander@152
|
232 |
|
|
dvander@157
|
233 |
// Sets or gets a property in a struct. The index of the field is specified as |
|
dvander@157
|
234 |
// a 32-bit integer. Note that these opcodes follow a new style of deriving |
|
dvander@157
|
235 |
// their types at runtime. |
|
dvander@195
|
236 |
OPDEF(OP_GETFIELD, "getfield", 5, 1, 1) |
|
dvander@195
|
237 |
OPDEF(OP_SETFIELD, "setfield", 5, 2, 1) |
|
dvander@164
|
238 |
|
|
dvander@172
|
239 |
// Table-based jump. |
|
dvander@172
|
240 |
// [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...] |
|
dvander@195
|
241 |
OPDEF(OP_TABLESWITCH, "tableswitch", 9, 1, 0) |
|
dvander@172
|
242 |
|
|
dvander@195
|
243 |
OPDEF(OP_SIZEOF, "sizeof", 1, 1, 1) |
|
dvander@194
|
244 |
|
|
dvander@195
|
245 |
// Registers a function as a publicly exported name. |
|
dvander@195
|
246 |
OPDEF(OP_PUBLIC, "public", 1, 1, 0) |