|
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@230
|
46 |
// Aliases for JUMP, that automatically leave LR regions. |
|
dvander@230
|
47 |
OPDEF(OP_BREAK, "break", 5, 0, 0) |
|
dvander@230
|
48 |
OPDEF(OP_CONTINUE, "continue", 5, 0, 0) |
|
dvander@230
|
49 |
|
|
dvander@0
|
50 |
// Gets or sets the value of a local variable onto the stack. The local |
|
dvander@0
|
51 |
// variable is given by an immediate index. |
|
dvander@195
|
52 |
OPDEF(OP_GETLOCAL, "getlocal", 5, 0, 1) |
|
dvander@195
|
53 |
OPDEF(OP_SETLOCAL, "setlocal", 5, 1, 1) |
|
dvander@0
|
54 |
|
|
dvander@0
|
55 |
// Stack transitions for these binary operators: |
|
dvander@0
|
56 |
// rhs = pop() |
|
dvander@0
|
57 |
// lhs = pop() |
|
dvander@0
|
58 |
// push(lhs OP rhs) |
|
dvander@195
|
59 |
OPDEF(OP_ADD, "add", 1, 2, 1) |
|
dvander@195
|
60 |
OPDEF(OP_SUB, "sub", 1, 2, 1) |
|
dvander@195
|
61 |
OPDEF(OP_MUL, "mul", 1, 2, 1) |
|
dvander@195
|
62 |
OPDEF(OP_DIV, "div", 1, 2, 1) |
|
dvander@195
|
63 |
OPDEF(OP_MOD, "mod", 1, 2, 1) |
|
dvander@0
|
64 |
|
|
dvander@195
|
65 |
OPDEF(OP_LT, "lt", 1, 2, 1) |
|
dvander@195
|
66 |
OPDEF(OP_LE, "le", 1, 2, 1) |
|
dvander@195
|
67 |
OPDEF(OP_GE, "ge", 1, 2, 1) |
|
dvander@195
|
68 |
OPDEF(OP_GT, "gt", 1, 2, 1) |
|
dvander@195
|
69 |
OPDEF(OP_EQ, "eq", 1, 2, 1) |
|
dvander@195
|
70 |
OPDEF(OP_NE, "ne", 1, 2, 1) |
|
dvander@74
|
71 |
|
|
dvander@195
|
72 |
OPDEF(OP_NOT, "not", 1, 1, 1) |
|
dvander@195
|
73 |
OPDEF(OP_NEG, "neg", 1, 1, 1) |
|
dvander@79
|
74 |
|
|
dvander@195
|
75 |
OPDEF(OP_POP, "pop", 1, 1, 0) |
|
dvander@0
|
76 |
|
|
dvander@72
|
77 |
// Unconditional terminator placed at the end of code. If a function returns |
|
dvander@72
|
78 |
// void, this acts as a RETURNVOID. Otherwise, it must be unreachable. |
|
dvander@195
|
79 |
OPDEF(OP_STOP, "stop", 1, 0, 0) |
|
dvander@0
|
80 |
|
|
dvander@73
|
81 |
// Call a function with N arguments. The target function must be the last item |
|
dvander@73
|
82 |
// on the stack. |
|
dvander@195
|
83 |
OPDEF(OP_CALL, "call", 1, -1, 1) |
|
dvander@0
|
84 |
|
|
dvander@0
|
85 |
// Similar to GET/LOCAL, except for arguments. |
|
dvander@195
|
86 |
OPDEF(OP_GETARG, "getarg", 5, 0, 1) |
|
dvander@195
|
87 |
OPDEF(OP_SETARG, "setarg", 5, 1, 1) |
|
dvander@0
|
88 |
|
|
dvander@185
|
89 |
// Allocates either: |
|
dvander@185
|
90 |
// A fixed array, |
|
dvander@185
|
91 |
// A 0-length dynamic array, or |
|
dvander@185
|
92 |
// A dynamic array whose size is specified on the stack. |
|
dvander@185
|
93 |
// |
|
dvander@185
|
94 |
// The HeapTenure is stored as a byte following the pc. The ArrayMap to use |
|
dvander@185
|
95 |
// is specified as an index into the script's object table. |
|
dvander@157
|
96 |
// |
|
dvander@157
|
97 |
// Format: |
|
dvander@182
|
98 |
// [u8 op] [u8 tenure] [u32 index] |
|
dvander@195
|
99 |
OPDEF(OP_NEWFIXED, "newfixed", 6, 0, 1) |
|
dvander@195
|
100 |
OPDEF(OP_NEWEMPTY, "newempty", 6, 0, 1) |
|
dvander@195
|
101 |
OPDEF(OP_NEWSIZED, "newsized", 6, -1, 1) |
|
dvander@157
|
102 |
|
|
dvander@236
|
103 |
// Creates a duplicate copy of an array. This is a deep clone, rather than |
|
dvander@236
|
104 |
// COPYARRAY, which is shallow. |
|
dvander@234
|
105 |
OPDEF(OP_DUPARRAY, "duparray", 1, 1, 1) |
|
dvander@234
|
106 |
|
|
dvander@157
|
107 |
// Performs an array-to-array assignment. |
|
dvander@157
|
108 |
// Left = pop() |
|
dvander@157
|
109 |
// Right = pop() |
|
dvander@157
|
110 |
// copy(Left, Right) |
|
dvander@157
|
111 |
// push(Left) |
|
dvander@236
|
112 |
OPDEF(OP_COPYARRAY, "copyarray", 1, 2, 1) |
|
dvander@157
|
113 |
|
|
dvander@0
|
114 |
// Reads or writes an integer element to an unsafe array. |
|
dvander@0
|
115 |
// index = pop() |
|
dvander@0
|
116 |
// ref = pop() |
|
dvander@0
|
117 |
// ref[index] |
|
dvander@0
|
118 |
// |
|
dvander@195
|
119 |
OPDEF(OP_GETELEM, "getelem", 1, 2, 1) |
|
dvander@195
|
120 |
OPDEF(OP_SETELEM, "setelem", 1, 3, 1) |
|
dvander@0
|
121 |
|
|
dvander@4
|
122 |
// Pushes a 32-bit IEEE-754 floating point immediate onto the stack. |
|
dvander@195
|
123 |
OPDEF(OP_FLOAT, "float", 5, 0, 1) |
|
dvander@4
|
124 |
|
|
dvander@4
|
125 |
// Converts an integer to a 32-bit IEEE-754 floating point immediate. |
|
dvander@195
|
126 |
OPDEF(OP_CVT_I2F, "cvt.i2f", 1, 1, 1) |
|
dvander@208
|
127 |
OPDEF(OP_CVT_I2B, "cvt.i2b", 1, 1, 1) |
|
dvander@4
|
128 |
|
|
dvander@4
|
129 |
// Stack transitions for these binary operators: |
|
dvander@4
|
130 |
// rhs = pop() |
|
dvander@4
|
131 |
// lhs = pop() |
|
dvander@4
|
132 |
// push(lhs OP rhs) |
|
dvander@195
|
133 |
OPDEF(OP_ADD_F, "add.f", 1, 2, 1) |
|
dvander@195
|
134 |
OPDEF(OP_SUB_F, "sub.f", 1, 2, 1) |
|
dvander@195
|
135 |
OPDEF(OP_MUL_F, "mul.f", 1, 2, 1) |
|
dvander@195
|
136 |
OPDEF(OP_DIV_F, "div.f", 1, 2, 1) |
|
dvander@74
|
137 |
|
|
dvander@195
|
138 |
OPDEF(OP_LT_F, "lt.f", 1, 2, 1) |
|
dvander@195
|
139 |
OPDEF(OP_LE_F, "le.f", 1, 2, 1) |
|
dvander@195
|
140 |
OPDEF(OP_GE_F, "ge.f", 1, 2, 1) |
|
dvander@195
|
141 |
OPDEF(OP_GT_F, "gt.f", 1, 2, 1) |
|
dvander@195
|
142 |
OPDEF(OP_EQ_F, "eq.f", 1, 2, 1) |
|
dvander@195
|
143 |
OPDEF(OP_NE_F, "ne.f", 1, 2, 1) |
|
dvander@79
|
144 |
|
|
dvander@195
|
145 |
OPDEF(OP_NOT_F, "not.f", 1, 1, 1) |
|
dvander@195
|
146 |
OPDEF(OP_NEG_F, "neg.f", 1, 1, 1) |
|
dvander@4
|
147 |
|
|
dvander@8
|
148 |
// Bitwise operators. |
|
dvander@195
|
149 |
OPDEF(OP_SHL, "shl", 1, 2, 1) |
|
dvander@195
|
150 |
OPDEF(OP_SHR, "shr", 1, 2, 1) |
|
dvander@195
|
151 |
OPDEF(OP_USHR, "ushr", 1, 2, 1) |
|
dvander@195
|
152 |
OPDEF(OP_BITAND, "bitand", 1, 2, 1) |
|
dvander@195
|
153 |
OPDEF(OP_BITOR, "bitor", 1, 2, 1) |
|
dvander@195
|
154 |
OPDEF(OP_BITXOR, "bitxor", 1, 2, 1) |
|
dvander@195
|
155 |
OPDEF(OP_BITNOT, "bitnot", 1, 1, 1) |
|
dvander@12
|
156 |
|
|
dvander@12
|
157 |
// Saves or restores the position of the LIFO heap to/from a local slot. |
|
dvander@195
|
158 |
OPDEF(OP_SAVELIFO, "savelifo", 5, 0, 0) |
|
dvander@195
|
159 |
OPDEF(OP_UNWINDLIFO, "unwindlifo", 5, 0, 0) |
|
dvander@14
|
160 |
|
|
dvander@14
|
161 |
// Composes a variable reference to a stack slot or argument. |
|
dvander@195
|
162 |
OPDEF(OP_VARREF_LIFO, "varref.lifo", 5, 0, 1) |
|
dvander@195
|
163 |
OPDEF(OP_ARGREF_LIFO, "argref.lifo", 5, 0, 1) |
|
dvander@195
|
164 |
OPDEF(OP_SLOTREF_LIFO, "slotref.lifo", 1, 1, 1) |
|
dvander@195
|
165 |
OPDEF(OP_GETREF_I, "getref.i", 1, 1, 1) |
|
dvander@195
|
166 |
OPDEF(OP_SETREF_I, "setref.i", 1, 2, 1) |
|
dvander@195
|
167 |
OPDEF(OP_GETREF_F, "getref.f", 1, 1, 1) |
|
dvander@195
|
168 |
OPDEF(OP_SETREF_F, "setref.f", 1, 2, 1) |
|
dvander@21
|
169 |
|
|
dvander@21
|
170 |
// Pushes an object reference onto the stack. |
|
dvander@195
|
171 |
OPDEF(OP_OBJECT, "object", 5, 0, 1) |
|
dvander@22
|
172 |
|
|
dvander@22
|
173 |
// Duplicates the top item on the stack. |
|
dvander@195
|
174 |
OPDEF(OP_DUP, "dup", 1, 1, 2) |
|
dvander@22
|
175 |
|
|
dvander@22
|
176 |
// Duplicates the top two items on the stack. |
|
dvander@195
|
177 |
OPDEF(OP_DUP2, "dup2", 1, 2, 4) |
|
dvander@23
|
178 |
|
|
dvander@23
|
179 |
// Swaps the two items at the top of the stack. |
|
dvander@195
|
180 |
OPDEF(OP_SWAP, "swap", 1, 2, 2) |
|
dvander@23
|
181 |
|
|
dvander@23
|
182 |
// Roll operation is the same as Forth. It steals a value on the stack, |
|
dvander@23
|
183 |
// shifting all stack values down, and then places the stolen value back at |
|
dvander@23
|
184 |
// the top of the stack. |
|
dvander@23
|
185 |
// |
|
dvander@23
|
186 |
// p = sp[-3] |
|
dvander@23
|
187 |
// sp[-3] = sp[-2] |
|
dvander@23
|
188 |
// sp[-2] = sp[-1] |
|
dvander@23
|
189 |
// sp[-1] = p |
|
dvander@195
|
190 |
OPDEF(OP_ROLL3, "roll3", 1, 3, 3) |
|
dvander@23
|
191 |
|
|
dvander@23
|
192 |
// Pick operation is the same as Forth. It pushes a copy of a slot at a |
|
dvander@23
|
193 |
// specific depth. |
|
dvander@23
|
194 |
// |
|
dvander@23
|
195 |
// push(sp[-n]) |
|
dvander@195
|
196 |
OPDEF(OP_PICK2, "pick2", 1, 2, 3) |
|
dvander@195
|
197 |
OPDEF(OP_PICK3, "pick3", 1, 3, 4) |
|
dvander@68
|
198 |
|
|
dvander@68
|
199 |
// Calls a native function. During the course of calling a native, arguments |
|
dvander@68
|
200 |
// on the stack are re-pushed to match the cell-based native calling |
|
dvander@68
|
201 |
// convention expected by ISourcePawnEngine. |
|
dvander@68
|
202 |
// |
|
dvander@68
|
203 |
// Unlike the normal CALL instruction, natives take truly variadic arguments |
|
dvander@195
|
204 |
// and so we must specify the number of arguments. |
|
dvander@68
|
205 |
// |
|
dvander@195
|
206 |
// [u8 Opcode] [u32 ArgCount] |
|
dvander@68
|
207 |
// |
|
dvander@195
|
208 |
OPDEF(OP_CALLNATIVE, "callnative", 5, -1, 1) |
|
dvander@72
|
209 |
|
|
dvander@72
|
210 |
// Returns from a function that does return a value. |
|
dvander@195
|
211 |
OPDEF(OP_RETURNVOID, "returnvoid", 1, 0, 0) |
|
dvander@73
|
212 |
|
|
dvander@195
|
213 |
// Opcodes for accessing an environment slot in the global scope. The index |
|
dvander@195
|
214 |
// maps into the code object's string table, and represents the name of the |
|
dvander@195
|
215 |
// global variable. |
|
dvander@195
|
216 |
OPDEF(OP_SETGLOBAL, "setglobal", 5, 1, 1) |
|
dvander@195
|
217 |
OPDEF(OP_GETGLOBAL, "getglobal", 5, 0, 1) |
|
dvander@142
|
218 |
|
|
dvander@245
|
219 |
// Reinterpret casts from one 32-bit POD type to another. The new type pointer |
|
dvander@245
|
220 |
// is encoded into the object table, for the JITs' type flow. |
|
dvander@245
|
221 |
OPDEF(OP_BITCAST, "BITCAST", 5, 1, 1) |
|
dvander@142
|
222 |
|
|
dvander@143
|
223 |
// Pushes a boolean value. |
|
dvander@195
|
224 |
OPDEF(OP_TRUE, "true", 1, 0, 1) |
|
dvander@195
|
225 |
OPDEF(OP_FALSE, "false", 1, 0, 1) |
|
dvander@143
|
226 |
|
|
dvander@147
|
227 |
// Allocate a struct. The HeapTenure is stored as a byte following pc. The |
|
dvander@147
|
228 |
// StructMap to use is specified as an index into the script's Map table. |
|
dvander@147
|
229 |
// |
|
dvander@147
|
230 |
// Format: |
|
dvander@182
|
231 |
// [u8 op] [u8 tenure] [u32 index] |
|
dvander@195
|
232 |
OPDEF(OP_NEWSTRUCT, "newstruct", 6, 0, 1) |
|
dvander@147
|
233 |
|
|
dvander@152
|
234 |
// Performs a struct-to-struct assignment. |
|
dvander@152
|
235 |
// Left = pop() |
|
dvander@152
|
236 |
// Right = pop() |
|
dvander@152
|
237 |
// copy(Left, Right) |
|
dvander@152
|
238 |
// push(Left) |
|
dvander@195
|
239 |
OPDEF(OP_COPYSTRUCT, "structcopy", 1, 2, 1) |
|
dvander@152
|
240 |
|
|
dvander@157
|
241 |
// Sets or gets a property in a struct. The index of the field is specified as |
|
dvander@157
|
242 |
// a 32-bit integer. Note that these opcodes follow a new style of deriving |
|
dvander@157
|
243 |
// their types at runtime. |
|
dvander@195
|
244 |
OPDEF(OP_GETFIELD, "getfield", 5, 1, 1) |
|
dvander@195
|
245 |
OPDEF(OP_SETFIELD, "setfield", 5, 2, 1) |
|
dvander@164
|
246 |
|
|
dvander@172
|
247 |
// Table-based jump. |
|
dvander@172
|
248 |
// [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...] |
|
dvander@195
|
249 |
OPDEF(OP_TABLESWITCH, "tableswitch", 9, 1, 0) |
|
dvander@172
|
250 |
|
|
dvander@195
|
251 |
OPDEF(OP_SIZEOF, "sizeof", 1, 1, 1) |
|
dvander@194
|
252 |
|
|
dvander@195
|
253 |
// Registers a function as a publicly exported name. |
|
dvander@230
|
254 |
OPDEF(OP_PUBLIC, "public", 1, 1, 0) |
|
dvander@230
|
255 |
|
|
dvander@230
|
256 |
// Enter and leave loop bodies. This is to track positions in the LIFO stack. |
|
dvander@230
|
257 |
// This is only used for the outermost scope inside loop bodies. BREAK and |
|
dvander@230
|
258 |
// CONTINUE implicitly perform a LEAVELOOP. |
|
dvander@230
|
259 |
// |
|
dvander@230
|
260 |
// If the second byte to ENTERLOOP is 0, then no LIFO region is needed. |
|
dvander@230
|
261 |
OPDEF(OP_ENTERLOOP, "enterloop", 2, 0, 0) |
|
dvander@247
|
262 |
OPDEF(OP_LEAVELOOP, "leaveloop", 1, 0, 0) |
|
dvander@247
|
263 |
|
|
dvander@247
|
264 |
// Create a new dependent array. The type to use is encoded as an index. |
|
dvander@247
|
265 |
// index = POP() |
|
dvander@247
|
266 |
// base = POP() |
|
dvander@247
|
267 |
// PUSH(array) |
|
dvander@247
|
268 |
OPDEF(OP_DEPARRAY, "deparray", 5, 2, 1) |