|
dvander@4116
|
1 |
// vim: set ts=8 sts=2 sw=2 tw=99 et: |
|
dvander@4116
|
2 |
// |
|
dvander@4116
|
3 |
// This file is part of SourcePawn. |
|
dvander@4116
|
4 |
// |
|
dvander@4116
|
5 |
// SourcePawn is free software: you can redistribute it and/or modify |
|
dvander@4116
|
6 |
// it under the terms of the GNU General Public License as published by |
|
dvander@4116
|
7 |
// the Free Software Foundation, either version 3 of the License, or |
|
dvander@4116
|
8 |
// (at your option) any later version. |
|
dvander@4116
|
9 |
// |
|
dvander@4116
|
10 |
// SourcePawn is distributed in the hope that it will be useful, |
|
dvander@4116
|
11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
dvander@4116
|
12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
dvander@4116
|
13 |
// GNU General Public License for more details. |
|
dvander@4116
|
14 |
// |
|
dvander@4116
|
15 |
// You should have received a copy of the GNU General Public License |
|
dvander@4116
|
16 |
// along with SourcePawn. If not, see <http://www.gnu.org/licenses/>. |
|
dvander@4116
|
17 |
#include <limits.h> |
|
dvander@4116
|
18 |
#include <string.h> |
|
dvander@4116
|
19 |
#include "interpreter.h" |
|
dvander@4116
|
20 |
#include "opcodes.h" |
|
dvander@4116
|
21 |
#include "watchdog_timer.h" |
|
dvander@4116
|
22 |
|
|
dvander@4116
|
23 |
#define STACK_MARGIN 64 |
|
dvander@4116
|
24 |
|
|
dvander@4116
|
25 |
using namespace SourcePawn; |
|
dvander@4116
|
26 |
|
|
dvander@4116
|
27 |
static inline bool |
|
dvander@4116
|
28 |
IsValidOffset(uint32_t cip) |
|
dvander@4116
|
29 |
{ |
|
dvander@4116
|
30 |
return cip % 4 == 0; |
|
dvander@4116
|
31 |
} |
|
dvander@4116
|
32 |
|
|
dvander@4116
|
33 |
static inline cell_t |
|
dvander@4116
|
34 |
Read(const sp_plugin_t *plugin, cell_t offset) |
|
dvander@4116
|
35 |
{ |
|
dvander@4116
|
36 |
return *reinterpret_cast<cell_t *>(plugin->memory + offset); |
|
dvander@4116
|
37 |
} |
|
dvander@4116
|
38 |
|
|
dvander@4116
|
39 |
static inline void |
|
dvander@4116
|
40 |
Write(const sp_plugin_t *plugin, cell_t offset, cell_t value) |
|
dvander@4116
|
41 |
{ |
|
dvander@4116
|
42 |
*reinterpret_cast<cell_t *>(plugin->memory + offset) = value; |
|
dvander@4116
|
43 |
} |
|
dvander@4116
|
44 |
|
|
dvander@4116
|
45 |
static inline cell_t * |
|
dvander@4116
|
46 |
Jump(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t target) |
|
dvander@4116
|
47 |
{ |
|
dvander@4116
|
48 |
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) { |
|
dvander@4116
|
49 |
ctx->err = SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
50 |
return NULL; |
|
dvander@4116
|
51 |
} |
|
dvander@4116
|
52 |
|
|
dvander@4116
|
53 |
return reinterpret_cast<cell_t *>(plugin->pcode + target); |
|
dvander@4116
|
54 |
} |
|
dvander@4116
|
55 |
|
|
dvander@4116
|
56 |
static inline cell_t * |
|
dvander@4116
|
57 |
JumpTarget(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *cip, bool cond) |
|
dvander@4116
|
58 |
{ |
|
dvander@4116
|
59 |
if (!cond) |
|
dvander@4116
|
60 |
return cip + 1; |
|
dvander@4116
|
61 |
|
|
dvander@4116
|
62 |
cell_t target = *cip; |
|
dvander@4116
|
63 |
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) { |
|
dvander@4116
|
64 |
ctx->err = SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
65 |
return NULL; |
|
dvander@4116
|
66 |
} |
|
dvander@4116
|
67 |
|
|
dvander@4116
|
68 |
cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target); |
|
dvander@4116
|
69 |
if (next < cip && !g_WatchdogTimer.HandleInterrupt()) { |
|
dvander@4116
|
70 |
ctx->err = SP_ERROR_TIMEOUT; |
|
dvander@4116
|
71 |
return NULL; |
|
dvander@4116
|
72 |
} |
|
dvander@4116
|
73 |
|
|
dvander@4116
|
74 |
return next; |
|
dvander@4116
|
75 |
} |
|
dvander@4116
|
76 |
|
|
dvander@4116
|
77 |
static inline bool |
|
dvander@4116
|
78 |
CheckAddress(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *stk, cell_t addr) |
|
dvander@4116
|
79 |
{ |
|
dvander@4116
|
80 |
if (uint32_t(addr) >= plugin->mem_size) { |
|
dvander@4116
|
81 |
ctx->err = SP_ERROR_MEMACCESS; |
|
dvander@4116
|
82 |
return false; |
|
dvander@4116
|
83 |
} |
|
dvander@4116
|
84 |
|
|
dvander@4116
|
85 |
if (addr < ctx->hp) |
|
dvander@4116
|
86 |
return true; |
|
dvander@4116
|
87 |
|
|
dvander@4116
|
88 |
if (reinterpret_cast<cell_t *>(plugin->memory + addr) < stk) { |
|
dvander@4116
|
89 |
ctx->err = SP_ERROR_MEMACCESS; |
|
dvander@4116
|
90 |
return false; |
|
dvander@4116
|
91 |
} |
|
dvander@4116
|
92 |
|
|
dvander@4116
|
93 |
return true; |
|
dvander@4116
|
94 |
} |
|
dvander@4116
|
95 |
|
|
dvander@4116
|
96 |
int |
|
dvander@4116
|
97 |
PopTrackerAndSetHeap(BaseRuntime *rt) |
|
dvander@4116
|
98 |
{ |
|
dvander@4116
|
99 |
sp_context_t *ctx = rt->GetBaseContext()->GetCtx(); |
|
dvander@4116
|
100 |
tracker_t *trk = ctx->tracker; |
|
dvander@4116
|
101 |
assert(trk->pCur > trk->pBase); |
|
dvander@4116
|
102 |
|
|
dvander@4116
|
103 |
trk->pCur--; |
|
dvander@4116
|
104 |
if (trk->pCur < trk->pBase) |
|
dvander@4116
|
105 |
return SP_ERROR_TRACKER_BOUNDS; |
|
dvander@4116
|
106 |
|
|
dvander@4116
|
107 |
ucell_t amt = *trk->pCur; |
|
dvander@4116
|
108 |
if (amt > (ctx->hp - rt->plugin()->data_size)) |
|
dvander@4116
|
109 |
return SP_ERROR_HEAPMIN; |
|
dvander@4116
|
110 |
|
|
dvander@4116
|
111 |
ctx->hp -= amt; |
|
dvander@4116
|
112 |
return SP_ERROR_NONE; |
|
dvander@4116
|
113 |
} |
|
dvander@4116
|
114 |
|
|
dvander@4116
|
115 |
int |
|
dvander@4116
|
116 |
PushTracker(sp_context_t *ctx, size_t amount) |
|
dvander@4116
|
117 |
{ |
|
dvander@4116
|
118 |
tracker_t *trk = ctx->tracker; |
|
dvander@4116
|
119 |
|
|
dvander@4116
|
120 |
if ((size_t)(trk->pCur - trk->pBase) >= trk->size) |
|
dvander@4116
|
121 |
return SP_ERROR_TRACKER_BOUNDS; |
|
dvander@4116
|
122 |
|
|
dvander@4116
|
123 |
if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) { |
|
dvander@4116
|
124 |
size_t disp = trk->size - 1; |
|
dvander@4116
|
125 |
trk->size *= 2; |
|
dvander@4116
|
126 |
trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t)); |
|
dvander@4116
|
127 |
|
|
dvander@4116
|
128 |
if (!trk->pBase) |
|
dvander@4116
|
129 |
return SP_ERROR_TRACKER_BOUNDS; |
|
dvander@4116
|
130 |
|
|
dvander@4116
|
131 |
trk->pCur = trk->pBase + disp; |
|
dvander@4116
|
132 |
} |
|
dvander@4116
|
133 |
|
|
dvander@4116
|
134 |
*trk->pCur++ = amount; |
|
dvander@4116
|
135 |
return SP_ERROR_NONE; |
|
dvander@4116
|
136 |
} |
|
dvander@4116
|
137 |
|
|
dvander@4116
|
138 |
cell_t |
|
dvander@4116
|
139 |
NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) |
|
dvander@4116
|
140 |
{ |
|
dvander@4116
|
141 |
cell_t save_sp = ctx->sp; |
|
dvander@4116
|
142 |
cell_t save_hp = ctx->hp; |
|
dvander@4116
|
143 |
|
|
dvander@4116
|
144 |
ctx->n_idx = native_idx; |
|
dvander@4116
|
145 |
|
|
dvander@4116
|
146 |
sp_native_t *native = &ctx->plugin->natives[native_idx]; |
|
dvander@4116
|
147 |
|
|
dvander@4116
|
148 |
if (native->status == SP_NATIVE_UNBOUND) { |
|
dvander@4116
|
149 |
ctx->n_err = SP_ERROR_INVALID_NATIVE; |
|
dvander@4116
|
150 |
return 0; |
|
dvander@4116
|
151 |
} |
|
dvander@4116
|
152 |
|
|
dvander@4116
|
153 |
cell_t result = native->pfn(ctx->basecx, params); |
|
dvander@4116
|
154 |
|
|
dvander@4116
|
155 |
if (ctx->n_err != SP_ERROR_NONE) |
|
dvander@4116
|
156 |
return result; |
|
dvander@4116
|
157 |
|
|
dvander@4116
|
158 |
if (save_sp != ctx->sp) { |
|
dvander@4116
|
159 |
ctx->n_err = SP_ERROR_STACKLEAK; |
|
dvander@4116
|
160 |
return result; |
|
dvander@4116
|
161 |
} |
|
dvander@4116
|
162 |
if (save_hp != ctx->hp) { |
|
dvander@4116
|
163 |
ctx->n_err = SP_ERROR_HEAPLEAK; |
|
dvander@4116
|
164 |
return result; |
|
dvander@4116
|
165 |
} |
|
dvander@4116
|
166 |
|
|
dvander@4116
|
167 |
return result; |
|
dvander@4116
|
168 |
} |
|
dvander@4116
|
169 |
|
|
kyle@4358
|
170 |
cell_t |
|
kyle@4358
|
171 |
BoundNativeCallback(sp_context_t *ctx, SPVM_NATIVE_FUNC pfn, cell_t *params) |
|
kyle@4358
|
172 |
{ |
|
kyle@4358
|
173 |
cell_t save_sp = ctx->sp; |
|
kyle@4358
|
174 |
cell_t save_hp = ctx->hp; |
|
kyle@4358
|
175 |
|
|
kyle@4358
|
176 |
cell_t result = pfn(ctx->basecx, params); |
|
kyle@4358
|
177 |
|
|
kyle@4358
|
178 |
if (ctx->n_err != SP_ERROR_NONE) |
|
kyle@4358
|
179 |
return result; |
|
kyle@4358
|
180 |
|
|
kyle@4358
|
181 |
if (save_sp != ctx->sp) { |
|
kyle@4358
|
182 |
ctx->n_err = SP_ERROR_STACKLEAK; |
|
kyle@4358
|
183 |
return result; |
|
kyle@4358
|
184 |
} |
|
kyle@4358
|
185 |
if (save_hp != ctx->hp) { |
|
kyle@4358
|
186 |
ctx->n_err = SP_ERROR_HEAPLEAK; |
|
kyle@4358
|
187 |
return result; |
|
kyle@4358
|
188 |
} |
|
kyle@4358
|
189 |
|
|
kyle@4358
|
190 |
return result; |
|
kyle@4358
|
191 |
} |
|
kyle@4358
|
192 |
|
|
dvander@4116
|
193 |
static inline bool |
|
dvander@4116
|
194 |
GenerateArray(BaseRuntime *rt, sp_context_t *ctx, cell_t dims, cell_t *stk, bool autozero) |
|
dvander@4116
|
195 |
{ |
|
dvander@4116
|
196 |
if (dims == 1) { |
|
dvander@4116
|
197 |
uint32_t size = *stk; |
|
dvander@4116
|
198 |
if (size == 0 || !ke::IsUint32MultiplySafe(size, 4)) { |
|
dvander@4116
|
199 |
ctx->err = SP_ERROR_ARRAY_TOO_BIG; |
|
dvander@4116
|
200 |
return false; |
|
dvander@4116
|
201 |
} |
|
dvander@4116
|
202 |
*stk = ctx->hp; |
|
dvander@4116
|
203 |
|
|
dvander@4116
|
204 |
uint32_t bytes = size * 4; |
|
dvander@4116
|
205 |
|
|
dvander@4116
|
206 |
ctx->hp += bytes; |
|
dvander@4116
|
207 |
if (uintptr_t(ctx->plugin->memory + ctx->hp) >= uintptr_t(stk)) { |
|
dvander@4116
|
208 |
ctx->err = SP_ERROR_HEAPLOW; |
|
dvander@4116
|
209 |
return false; |
|
dvander@4116
|
210 |
} |
|
dvander@4116
|
211 |
|
|
dvander@4116
|
212 |
if ((ctx->err = PushTracker(ctx, bytes)) != SP_ERROR_NONE) |
|
dvander@4116
|
213 |
return false; |
|
dvander@4116
|
214 |
|
|
dvander@4116
|
215 |
if (autozero) |
|
dvander@4116
|
216 |
memset(ctx->plugin->memory + ctx->hp, 0, bytes); |
|
dvander@4116
|
217 |
|
|
dvander@4116
|
218 |
return true; |
|
dvander@4116
|
219 |
} |
|
dvander@4116
|
220 |
|
|
dvander@4116
|
221 |
if ((ctx->err = GenerateFullArray(rt, dims, stk, autozero)) != SP_ERROR_NONE) |
|
dvander@4116
|
222 |
return false; |
|
dvander@4116
|
223 |
|
|
dvander@4116
|
224 |
return true; |
|
dvander@4116
|
225 |
} |
|
dvander@4116
|
226 |
|
|
dvander@4116
|
227 |
int |
|
dvander@4116
|
228 |
Interpret(BaseRuntime *rt, uint32_t aCodeStart, cell_t *rval) |
|
dvander@4116
|
229 |
{ |
|
dvander@4116
|
230 |
const sp_plugin_t *plugin = rt->plugin(); |
|
dvander@4116
|
231 |
cell_t *code = reinterpret_cast<cell_t *>(plugin->pcode); |
|
dvander@4116
|
232 |
cell_t *codeend = reinterpret_cast<cell_t *>(plugin->pcode + plugin->pcode_size); |
|
dvander@4116
|
233 |
|
|
dvander@4116
|
234 |
if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size) |
|
dvander@4116
|
235 |
return SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
236 |
|
|
dvander@4116
|
237 |
sp_context_t *ctx = rt->GetBaseContext()->GetCtx(); |
|
dvander@4116
|
238 |
ctx->err = SP_ERROR_NONE; |
|
dvander@4116
|
239 |
|
|
dvander@4116
|
240 |
// Save the original frm. BaseContext won't, and if we error, we won't hit |
|
dvander@4116
|
241 |
// the stack unwinding code. |
|
dvander@4116
|
242 |
cell_t orig_frm = ctx->frm; |
|
dvander@4116
|
243 |
|
|
dvander@4116
|
244 |
cell_t pri = 0; |
|
dvander@4116
|
245 |
cell_t alt = 0; |
|
dvander@4116
|
246 |
cell_t *cip = code + (aCodeStart / 4); |
|
dvander@4116
|
247 |
cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp); |
|
dvander@4116
|
248 |
|
|
dvander@4116
|
249 |
for (;;) { |
|
dvander@4116
|
250 |
if (cip >= codeend) { |
|
dvander@4116
|
251 |
ctx->err = SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
252 |
goto error; |
|
dvander@4116
|
253 |
} |
|
dvander@4116
|
254 |
|
|
dvander@4116
|
255 |
#if 0 |
|
dvander@4116
|
256 |
SpewOpcode(plugin, reinterpret_cast<cell_t *>(plugin->pcode + aCodeStart), cip); |
|
dvander@4116
|
257 |
#endif |
|
dvander@4116
|
258 |
|
|
dvander@4116
|
259 |
OPCODE op = (OPCODE)*cip++; |
|
dvander@4116
|
260 |
|
|
dvander@4116
|
261 |
switch (op) { |
|
dvander@4116
|
262 |
case OP_MOVE_PRI: |
|
dvander@4116
|
263 |
pri = alt; |
|
dvander@4116
|
264 |
break; |
|
dvander@4116
|
265 |
case OP_MOVE_ALT: |
|
dvander@4116
|
266 |
alt = pri; |
|
dvander@4116
|
267 |
break; |
|
dvander@4116
|
268 |
|
|
dvander@4116
|
269 |
case OP_XCHG: |
|
dvander@4116
|
270 |
{ |
|
dvander@4116
|
271 |
cell_t tmp = pri; |
|
dvander@4116
|
272 |
pri = alt; |
|
dvander@4116
|
273 |
alt = tmp; |
|
dvander@4116
|
274 |
break; |
|
dvander@4116
|
275 |
} |
|
dvander@4116
|
276 |
|
|
dvander@4116
|
277 |
case OP_ZERO: |
|
dvander@4116
|
278 |
Write(plugin, *cip++, 0); |
|
dvander@4116
|
279 |
break; |
|
dvander@4116
|
280 |
|
|
dvander@4116
|
281 |
case OP_ZERO_S: |
|
dvander@4156
|
282 |
Write(plugin, ctx->frm + *cip++, 0); |
|
dvander@4116
|
283 |
break; |
|
dvander@4116
|
284 |
|
|
dvander@4116
|
285 |
case OP_PUSH_PRI: |
|
dvander@4116
|
286 |
*--stk = pri; |
|
dvander@4116
|
287 |
break; |
|
dvander@4116
|
288 |
case OP_PUSH_ALT: |
|
dvander@4116
|
289 |
*--stk = alt; |
|
dvander@4116
|
290 |
break; |
|
dvander@4116
|
291 |
|
|
dvander@4116
|
292 |
case OP_PUSH_C: |
|
dvander@4116
|
293 |
case OP_PUSH2_C: |
|
dvander@4116
|
294 |
case OP_PUSH3_C: |
|
dvander@4116
|
295 |
case OP_PUSH4_C: |
|
dvander@4116
|
296 |
case OP_PUSH5_C: |
|
dvander@4116
|
297 |
{ |
|
dvander@4116
|
298 |
int n = 1; |
|
dvander@4116
|
299 |
if (op >= OP_PUSH2_C) |
|
dvander@4116
|
300 |
n = ((op - OP_PUSH2_C) / 4) + 2; |
|
dvander@4116
|
301 |
|
|
dvander@4116
|
302 |
int i = 1; |
|
dvander@4116
|
303 |
do { |
|
dvander@4116
|
304 |
*--stk = *cip++; |
|
dvander@4116
|
305 |
} while (i++ < n); |
|
dvander@4116
|
306 |
break; |
|
dvander@4116
|
307 |
} |
|
dvander@4116
|
308 |
|
|
dvander@4116
|
309 |
case OP_PUSH_ADR: |
|
dvander@4116
|
310 |
case OP_PUSH2_ADR: |
|
dvander@4116
|
311 |
case OP_PUSH3_ADR: |
|
dvander@4116
|
312 |
case OP_PUSH4_ADR: |
|
dvander@4116
|
313 |
case OP_PUSH5_ADR: |
|
dvander@4116
|
314 |
{ |
|
dvander@4116
|
315 |
int n = 1; |
|
dvander@4116
|
316 |
if (op >= OP_PUSH2_ADR) |
|
dvander@4116
|
317 |
n = ((op - OP_PUSH2_ADR) / 4) + 2; |
|
dvander@4116
|
318 |
|
|
dvander@4116
|
319 |
int i = 1; |
|
dvander@4116
|
320 |
|
|
dvander@4116
|
321 |
do { |
|
dvander@4116
|
322 |
cell_t addr = ctx->frm + *cip++; |
|
dvander@4116
|
323 |
*--stk = addr; |
|
dvander@4116
|
324 |
} while (i++ < n); |
|
dvander@4116
|
325 |
break; |
|
dvander@4116
|
326 |
} |
|
dvander@4116
|
327 |
|
|
dvander@4116
|
328 |
case OP_PUSH_S: |
|
dvander@4116
|
329 |
case OP_PUSH2_S: |
|
dvander@4116
|
330 |
case OP_PUSH3_S: |
|
dvander@4116
|
331 |
case OP_PUSH4_S: |
|
dvander@4116
|
332 |
case OP_PUSH5_S: |
|
dvander@4116
|
333 |
{ |
|
dvander@4116
|
334 |
int n = 1; |
|
dvander@4116
|
335 |
if (op >= OP_PUSH2_S) |
|
dvander@4116
|
336 |
n = ((op - OP_PUSH2_S) / 4) + 2; |
|
dvander@4116
|
337 |
|
|
dvander@4116
|
338 |
int i = 1; |
|
dvander@4116
|
339 |
do { |
|
dvander@4116
|
340 |
cell_t value = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
341 |
*--stk = value; |
|
dvander@4116
|
342 |
} while (i++ < n); |
|
dvander@4116
|
343 |
break; |
|
dvander@4116
|
344 |
} |
|
dvander@4116
|
345 |
|
|
dvander@4116
|
346 |
case OP_PUSH: |
|
dvander@4116
|
347 |
case OP_PUSH2: |
|
dvander@4116
|
348 |
case OP_PUSH3: |
|
dvander@4116
|
349 |
case OP_PUSH4: |
|
dvander@4116
|
350 |
case OP_PUSH5: |
|
dvander@4116
|
351 |
{ |
|
dvander@4116
|
352 |
int n = 1; |
|
dvander@4116
|
353 |
if (op >= OP_PUSH2) |
|
dvander@4116
|
354 |
n = ((op - OP_PUSH2) / 4) + 2; |
|
dvander@4116
|
355 |
|
|
dvander@4116
|
356 |
int i = 1; |
|
dvander@4116
|
357 |
do { |
|
dvander@4116
|
358 |
cell_t value = Read(plugin, *cip++); |
|
dvander@4116
|
359 |
*--stk = value; |
|
dvander@4116
|
360 |
} while (i++ < n); |
|
dvander@4116
|
361 |
break; |
|
dvander@4116
|
362 |
} |
|
dvander@4116
|
363 |
|
|
dvander@4116
|
364 |
case OP_ZERO_PRI: |
|
dvander@4116
|
365 |
pri = 0; |
|
dvander@4116
|
366 |
break; |
|
dvander@4116
|
367 |
case OP_ZERO_ALT: |
|
dvander@4116
|
368 |
alt = 0; |
|
dvander@4116
|
369 |
break; |
|
dvander@4116
|
370 |
|
|
dvander@4116
|
371 |
case OP_ADD: |
|
dvander@4116
|
372 |
pri += alt; |
|
dvander@4116
|
373 |
break; |
|
dvander@4116
|
374 |
|
|
dvander@4116
|
375 |
case OP_SUB: |
|
dvander@4116
|
376 |
pri -= alt; |
|
dvander@4116
|
377 |
break; |
|
dvander@4116
|
378 |
|
|
dvander@4116
|
379 |
case OP_SUB_ALT: |
|
dvander@4116
|
380 |
pri = alt - pri; |
|
dvander@4116
|
381 |
break; |
|
dvander@4116
|
382 |
|
|
dvander@4116
|
383 |
case OP_PROC: |
|
dvander@4116
|
384 |
{ |
|
dvander@4116
|
385 |
*--stk = ctx->frm; |
|
dvander@4116
|
386 |
*--stk = 0; |
|
dvander@4116
|
387 |
ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory); |
|
dvander@4116
|
388 |
break; |
|
dvander@4116
|
389 |
} |
|
dvander@4116
|
390 |
|
|
dvander@4116
|
391 |
case OP_IDXADDR_B: |
|
dvander@4116
|
392 |
pri <<= *cip++; |
|
dvander@4116
|
393 |
pri += alt; |
|
dvander@4116
|
394 |
break; |
|
dvander@4116
|
395 |
|
|
dvander@4116
|
396 |
case OP_SHL: |
|
dvander@4116
|
397 |
pri <<= alt; |
|
dvander@4116
|
398 |
break; |
|
dvander@4116
|
399 |
|
|
dvander@4116
|
400 |
case OP_SHR: |
|
dvander@4116
|
401 |
pri = unsigned(pri) >> unsigned(alt); |
|
dvander@4116
|
402 |
break; |
|
dvander@4116
|
403 |
|
|
dvander@4116
|
404 |
case OP_SSHR: |
|
dvander@4116
|
405 |
pri >>= alt; |
|
dvander@4116
|
406 |
break; |
|
dvander@4116
|
407 |
|
|
dvander@4116
|
408 |
case OP_SHL_C_PRI: |
|
dvander@4116
|
409 |
pri <<= *cip++; |
|
dvander@4116
|
410 |
break; |
|
dvander@4116
|
411 |
case OP_SHL_C_ALT: |
|
dvander@4116
|
412 |
alt <<= *cip++; |
|
dvander@4116
|
413 |
break; |
|
dvander@4116
|
414 |
|
|
dvander@4116
|
415 |
case OP_SHR_C_PRI: |
|
dvander@4116
|
416 |
pri >>= *cip++; |
|
dvander@4116
|
417 |
break; |
|
dvander@4116
|
418 |
case OP_SHR_C_ALT: |
|
dvander@4116
|
419 |
alt >>= *cip++; |
|
dvander@4116
|
420 |
break; |
|
dvander@4116
|
421 |
|
|
dvander@4116
|
422 |
case OP_SMUL: |
|
dvander@4116
|
423 |
pri *= alt; |
|
dvander@4116
|
424 |
break; |
|
dvander@4116
|
425 |
|
|
dvander@4116
|
426 |
case OP_NOT: |
|
dvander@4116
|
427 |
pri = pri ? 0 : 1; |
|
dvander@4116
|
428 |
break; |
|
dvander@4116
|
429 |
|
|
dvander@4116
|
430 |
case OP_NEG: |
|
dvander@4116
|
431 |
pri = -pri; |
|
dvander@4116
|
432 |
break; |
|
dvander@4116
|
433 |
|
|
dvander@4116
|
434 |
case OP_XOR: |
|
dvander@4116
|
435 |
pri ^= alt; |
|
dvander@4116
|
436 |
break; |
|
dvander@4116
|
437 |
|
|
dvander@4116
|
438 |
case OP_OR: |
|
dvander@4116
|
439 |
pri |= alt; |
|
dvander@4116
|
440 |
break; |
|
dvander@4116
|
441 |
|
|
dvander@4116
|
442 |
case OP_AND: |
|
dvander@4116
|
443 |
pri &= alt; |
|
dvander@4116
|
444 |
break; |
|
dvander@4116
|
445 |
|
|
dvander@4116
|
446 |
case OP_INVERT: |
|
dvander@4116
|
447 |
pri = ~pri; |
|
dvander@4116
|
448 |
break; |
|
dvander@4116
|
449 |
|
|
dvander@4116
|
450 |
case OP_ADD_C: |
|
dvander@4116
|
451 |
pri += *cip++; |
|
dvander@4116
|
452 |
break; |
|
dvander@4116
|
453 |
|
|
dvander@4116
|
454 |
case OP_SMUL_C: |
|
dvander@4116
|
455 |
pri *= *cip++; |
|
dvander@4116
|
456 |
break; |
|
dvander@4116
|
457 |
|
|
dvander@4116
|
458 |
case OP_EQ: |
|
dvander@4116
|
459 |
pri = pri == alt; |
|
dvander@4116
|
460 |
break; |
|
dvander@4116
|
461 |
|
|
dvander@4116
|
462 |
case OP_NEQ: |
|
dvander@4116
|
463 |
pri = pri != alt; |
|
dvander@4116
|
464 |
break; |
|
dvander@4116
|
465 |
|
|
dvander@4116
|
466 |
case OP_SLESS: |
|
dvander@4116
|
467 |
pri = pri < alt; |
|
dvander@4116
|
468 |
break; |
|
dvander@4116
|
469 |
|
|
dvander@4116
|
470 |
case OP_SLEQ: |
|
dvander@4116
|
471 |
pri = pri <= alt; |
|
dvander@4116
|
472 |
break; |
|
dvander@4116
|
473 |
|
|
dvander@4116
|
474 |
case OP_SGRTR: |
|
dvander@4116
|
475 |
pri = pri > alt; |
|
dvander@4116
|
476 |
break; |
|
dvander@4116
|
477 |
|
|
dvander@4116
|
478 |
case OP_SGEQ: |
|
dvander@4116
|
479 |
pri = pri >= alt; |
|
dvander@4116
|
480 |
break; |
|
dvander@4116
|
481 |
|
|
dvander@4116
|
482 |
case OP_EQ_C_PRI: |
|
dvander@4116
|
483 |
pri = pri == *cip++; |
|
dvander@4116
|
484 |
break; |
|
dvander@4116
|
485 |
case OP_EQ_C_ALT: |
|
dvander@4116
|
486 |
pri = alt == *cip++; |
|
dvander@4116
|
487 |
break; |
|
dvander@4116
|
488 |
|
|
dvander@4116
|
489 |
case OP_INC_PRI: |
|
dvander@4116
|
490 |
pri++; |
|
dvander@4116
|
491 |
break; |
|
dvander@4116
|
492 |
case OP_INC_ALT: |
|
dvander@4116
|
493 |
alt++; |
|
dvander@4116
|
494 |
break; |
|
dvander@4116
|
495 |
|
|
dvander@4116
|
496 |
case OP_INC: |
|
dvander@4116
|
497 |
{ |
|
dvander@4116
|
498 |
cell_t offset = *cip++; |
|
dvander@4116
|
499 |
Write(plugin, offset, Read(plugin, offset) + 1); |
|
dvander@4116
|
500 |
break; |
|
dvander@4116
|
501 |
} |
|
dvander@4116
|
502 |
|
|
dvander@4116
|
503 |
case OP_INC_S: |
|
dvander@4116
|
504 |
{ |
|
dvander@4116
|
505 |
cell_t offset = *cip++; |
|
dvander@4116
|
506 |
cell_t value = Read(plugin, ctx->frm + offset); |
|
dvander@4116
|
507 |
Write(plugin, ctx->frm + offset, value + 1); |
|
dvander@4116
|
508 |
break; |
|
dvander@4116
|
509 |
} |
|
dvander@4116
|
510 |
|
|
dvander@4116
|
511 |
case OP_INC_I: |
|
dvander@4116
|
512 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
513 |
goto error; |
|
dvander@4116
|
514 |
Write(plugin, pri, Read(plugin, pri) + 1); |
|
dvander@4116
|
515 |
break; |
|
dvander@4116
|
516 |
|
|
dvander@4116
|
517 |
case OP_DEC_PRI: |
|
dvander@4116
|
518 |
pri--; |
|
dvander@4116
|
519 |
break; |
|
dvander@4116
|
520 |
case OP_DEC_ALT: |
|
dvander@4116
|
521 |
alt--; |
|
dvander@4116
|
522 |
break; |
|
dvander@4116
|
523 |
|
|
dvander@4116
|
524 |
case OP_DEC: |
|
dvander@4116
|
525 |
{ |
|
dvander@4116
|
526 |
cell_t offset = *cip++; |
|
dvander@4116
|
527 |
Write(plugin, offset, Read(plugin, offset) - 1); |
|
dvander@4116
|
528 |
break; |
|
dvander@4116
|
529 |
} |
|
dvander@4116
|
530 |
|
|
dvander@4116
|
531 |
case OP_DEC_S: |
|
dvander@4116
|
532 |
{ |
|
dvander@4116
|
533 |
cell_t offset = *cip++; |
|
dvander@4116
|
534 |
cell_t value = Read(plugin, ctx->frm + offset); |
|
dvander@4116
|
535 |
Write(plugin, ctx->frm + offset, value - 1); |
|
dvander@4116
|
536 |
break; |
|
dvander@4116
|
537 |
} |
|
dvander@4116
|
538 |
|
|
dvander@4116
|
539 |
case OP_DEC_I: |
|
dvander@4116
|
540 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
541 |
goto error; |
|
dvander@4116
|
542 |
Write(plugin, pri, Read(plugin, pri) - 1); |
|
dvander@4116
|
543 |
break; |
|
dvander@4116
|
544 |
|
|
dvander@4116
|
545 |
case OP_LOAD_PRI: |
|
dvander@4116
|
546 |
pri = Read(plugin, *cip++); |
|
dvander@4116
|
547 |
break; |
|
dvander@4116
|
548 |
case OP_LOAD_ALT: |
|
dvander@4116
|
549 |
alt = Read(plugin, *cip++); |
|
dvander@4116
|
550 |
break; |
|
dvander@4116
|
551 |
|
|
dvander@4116
|
552 |
case OP_LOAD_S_PRI: |
|
dvander@4116
|
553 |
pri = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
554 |
break; |
|
dvander@4116
|
555 |
case OP_LOAD_S_ALT: |
|
dvander@4116
|
556 |
alt = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
557 |
break; |
|
dvander@4116
|
558 |
|
|
dvander@4116
|
559 |
case OP_LOAD_S_BOTH: |
|
dvander@4116
|
560 |
pri = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
561 |
alt = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
562 |
break; |
|
dvander@4116
|
563 |
|
|
dvander@4116
|
564 |
case OP_LREF_S_PRI: |
|
dvander@4116
|
565 |
{ |
|
dvander@4116
|
566 |
pri = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
567 |
pri = Read(plugin, pri); |
|
dvander@4116
|
568 |
break; |
|
dvander@4116
|
569 |
} |
|
dvander@4116
|
570 |
|
|
dvander@4116
|
571 |
case OP_LREF_S_ALT: |
|
dvander@4116
|
572 |
{ |
|
dvander@4116
|
573 |
alt = Read(plugin, ctx->frm + *cip++); |
|
dvander@4116
|
574 |
alt = Read(plugin, alt); |
|
dvander@4116
|
575 |
break; |
|
dvander@4116
|
576 |
} |
|
dvander@4116
|
577 |
|
|
dvander@4116
|
578 |
case OP_CONST_PRI: |
|
dvander@4116
|
579 |
pri = *cip++; |
|
dvander@4116
|
580 |
break; |
|
dvander@4116
|
581 |
case OP_CONST_ALT: |
|
dvander@4116
|
582 |
alt = *cip++; |
|
dvander@4116
|
583 |
break; |
|
dvander@4116
|
584 |
|
|
dvander@4116
|
585 |
case OP_ADDR_PRI: |
|
dvander@4116
|
586 |
pri = ctx->frm + *cip++; |
|
dvander@4116
|
587 |
break; |
|
dvander@4116
|
588 |
case OP_ADDR_ALT: |
|
dvander@4116
|
589 |
alt = ctx->frm + *cip++; |
|
dvander@4116
|
590 |
break; |
|
dvander@4116
|
591 |
|
|
dvander@4116
|
592 |
case OP_STOR_PRI: |
|
dvander@4116
|
593 |
Write(plugin, *cip++, pri); |
|
dvander@4116
|
594 |
break; |
|
dvander@4116
|
595 |
case OP_STOR_ALT: |
|
dvander@4116
|
596 |
Write(plugin, *cip++, alt); |
|
dvander@4116
|
597 |
break; |
|
dvander@4116
|
598 |
|
|
dvander@4116
|
599 |
case OP_STOR_S_PRI: |
|
dvander@4116
|
600 |
Write(plugin, ctx->frm + *cip++, pri); |
|
dvander@4116
|
601 |
break; |
|
dvander@4116
|
602 |
case OP_STOR_S_ALT: |
|
dvander@4116
|
603 |
Write(plugin, ctx->frm +*cip++, alt); |
|
dvander@4116
|
604 |
break; |
|
dvander@4116
|
605 |
|
|
dvander@4116
|
606 |
case OP_IDXADDR: |
|
dvander@4116
|
607 |
pri = alt + pri * 4; |
|
dvander@4116
|
608 |
break; |
|
dvander@4116
|
609 |
|
|
dvander@4116
|
610 |
case OP_SREF_S_PRI: |
|
dvander@4116
|
611 |
{ |
|
dvander@4116
|
612 |
cell_t offset = *cip++; |
|
dvander@4116
|
613 |
cell_t addr = Read(plugin, ctx->frm + offset); |
|
dvander@4116
|
614 |
Write(plugin, addr, pri); |
|
dvander@4116
|
615 |
break; |
|
dvander@4116
|
616 |
} |
|
dvander@4116
|
617 |
|
|
dvander@4116
|
618 |
case OP_SREF_S_ALT: |
|
dvander@4116
|
619 |
{ |
|
dvander@4116
|
620 |
cell_t offset = *cip++; |
|
dvander@4116
|
621 |
cell_t addr = Read(plugin, ctx->frm + offset); |
|
dvander@4116
|
622 |
Write(plugin, addr, alt); |
|
dvander@4116
|
623 |
break; |
|
dvander@4116
|
624 |
} |
|
dvander@4116
|
625 |
|
|
dvander@4116
|
626 |
case OP_POP_PRI: |
|
dvander@4116
|
627 |
pri = *stk++; |
|
dvander@4116
|
628 |
break; |
|
dvander@4116
|
629 |
case OP_POP_ALT: |
|
dvander@4116
|
630 |
alt = *stk++; |
|
dvander@4116
|
631 |
break; |
|
dvander@4116
|
632 |
|
|
dvander@4116
|
633 |
case OP_SWAP_PRI: |
|
dvander@4116
|
634 |
case OP_SWAP_ALT: |
|
dvander@4116
|
635 |
{ |
|
dvander@4116
|
636 |
cell_t reg = (op == OP_SREF_S_PRI) ? pri : alt; |
|
dvander@4116
|
637 |
cell_t temp = *stk; |
|
dvander@4116
|
638 |
*stk = reg; |
|
dvander@4116
|
639 |
reg = temp; |
|
dvander@4116
|
640 |
break; |
|
dvander@4116
|
641 |
} |
|
dvander@4116
|
642 |
|
|
dvander@4116
|
643 |
case OP_LIDX: |
|
dvander@4116
|
644 |
pri = alt + pri * 4; |
|
dvander@4116
|
645 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
646 |
goto error; |
|
dvander@4116
|
647 |
pri = Read(plugin, pri); |
|
dvander@4116
|
648 |
break; |
|
dvander@4116
|
649 |
|
|
dvander@4116
|
650 |
case OP_LIDX_B: |
|
dvander@4116
|
651 |
{ |
|
dvander@4116
|
652 |
cell_t val = *cip++; |
|
dvander@4116
|
653 |
pri = alt + (pri << val); |
|
dvander@4116
|
654 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
655 |
goto error; |
|
dvander@4116
|
656 |
pri = Read(plugin, pri); |
|
dvander@4116
|
657 |
break; |
|
dvander@4116
|
658 |
} |
|
dvander@4116
|
659 |
|
|
dvander@4116
|
660 |
case OP_CONST: |
|
dvander@4116
|
661 |
{ |
|
dvander@4116
|
662 |
cell_t offset = *cip++; |
|
dvander@4116
|
663 |
cell_t value = *cip++; |
|
dvander@4116
|
664 |
Write(plugin, offset, value); |
|
dvander@4116
|
665 |
break; |
|
dvander@4116
|
666 |
} |
|
dvander@4116
|
667 |
|
|
dvander@4116
|
668 |
case OP_CONST_S: |
|
dvander@4116
|
669 |
{ |
|
dvander@4116
|
670 |
cell_t offset = *cip++; |
|
dvander@4116
|
671 |
cell_t value = *cip++; |
|
dvander@4116
|
672 |
Write(plugin, ctx->frm + offset, value); |
|
dvander@4116
|
673 |
break; |
|
dvander@4116
|
674 |
} |
|
dvander@4116
|
675 |
|
|
dvander@4116
|
676 |
case OP_LOAD_I: |
|
dvander@4116
|
677 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
678 |
goto error; |
|
dvander@4116
|
679 |
pri = Read(plugin, pri); |
|
dvander@4116
|
680 |
break; |
|
dvander@4116
|
681 |
|
|
dvander@4116
|
682 |
case OP_STOR_I: |
|
dvander@4116
|
683 |
if (!CheckAddress(plugin, ctx, stk, alt)) |
|
dvander@4116
|
684 |
goto error; |
|
dvander@4116
|
685 |
Write(plugin, alt, pri); |
|
dvander@4116
|
686 |
break; |
|
dvander@4116
|
687 |
|
|
dvander@4116
|
688 |
case OP_SDIV: |
|
dvander@4116
|
689 |
case OP_SDIV_ALT: |
|
dvander@4116
|
690 |
{ |
|
dvander@4116
|
691 |
cell_t dividend = (op == OP_SDIV) ? pri : alt; |
|
dvander@4116
|
692 |
cell_t divisor = (op == OP_SDIV) ? alt : pri; |
|
dvander@4116
|
693 |
if (divisor == 0) { |
|
dvander@4116
|
694 |
ctx->err = SP_ERROR_DIVIDE_BY_ZERO; |
|
dvander@4116
|
695 |
goto error; |
|
dvander@4116
|
696 |
} |
|
dvander@4116
|
697 |
if (dividend == INT_MIN && divisor == -1) { |
|
dvander@4116
|
698 |
ctx->err = SP_ERROR_INTEGER_OVERFLOW; |
|
dvander@4116
|
699 |
goto error; |
|
dvander@4116
|
700 |
} |
|
dvander@4116
|
701 |
pri = dividend / divisor; |
|
dvander@4116
|
702 |
alt = dividend % divisor; |
|
dvander@4116
|
703 |
break; |
|
dvander@4116
|
704 |
} |
|
dvander@4116
|
705 |
|
|
dvander@4116
|
706 |
case OP_LODB_I: |
|
dvander@4116
|
707 |
{ |
|
dvander@4116
|
708 |
cell_t val = *cip++; |
|
dvander@4116
|
709 |
if (!CheckAddress(plugin, ctx, stk, pri)) |
|
dvander@4116
|
710 |
goto error; |
|
dvander@4116
|
711 |
pri = Read(plugin, pri); |
|
dvander@4116
|
712 |
if (val == 1) |
|
dvander@4116
|
713 |
pri &= 0xff; |
|
dvander@4116
|
714 |
else if (val == 2) |
|
dvander@4116
|
715 |
pri &= 0xffff; |
|
dvander@4116
|
716 |
break; |
|
dvander@4116
|
717 |
} |
|
dvander@4116
|
718 |
|
|
dvander@4116
|
719 |
case OP_STRB_I: |
|
dvander@4116
|
720 |
{ |
|
dvander@4116
|
721 |
cell_t val = *cip++; |
|
dvander@4116
|
722 |
if (!CheckAddress(plugin, ctx, stk, alt)) |
|
dvander@4116
|
723 |
goto error; |
|
dvander@4116
|
724 |
if (val == 1) |
|
dvander@4116
|
725 |
*reinterpret_cast<int8_t *>(plugin->memory + alt) = pri; |
|
dvander@4116
|
726 |
else if (val == 2) |
|
dvander@4116
|
727 |
*reinterpret_cast<int16_t *>(plugin->memory + alt) = pri; |
|
dvander@4116
|
728 |
else if (val == 4) |
|
dvander@4116
|
729 |
*reinterpret_cast<int32_t *>(plugin->memory + alt) = pri; |
|
dvander@4116
|
730 |
break; |
|
dvander@4116
|
731 |
} |
|
dvander@4116
|
732 |
|
|
dvander@4116
|
733 |
case OP_RETN: |
|
dvander@4116
|
734 |
{ |
|
dvander@4116
|
735 |
stk++; |
|
dvander@4116
|
736 |
ctx->frm = *stk++; |
|
dvander@4116
|
737 |
stk += *stk + 1; |
|
dvander@4116
|
738 |
*rval = pri; |
|
dvander@4116
|
739 |
ctx->err = SP_ERROR_NONE; |
|
dvander@4116
|
740 |
goto done; |
|
dvander@4116
|
741 |
} |
|
dvander@4116
|
742 |
|
|
dvander@4116
|
743 |
case OP_MOVS: |
|
dvander@4116
|
744 |
{ |
|
dvander@4116
|
745 |
uint8_t *src = plugin->memory + pri; |
|
dvander@4116
|
746 |
uint8_t *dest = plugin->memory + alt; |
|
dvander@4116
|
747 |
memcpy(dest, src, *cip++); |
|
dvander@4116
|
748 |
break; |
|
dvander@4116
|
749 |
} |
|
dvander@4116
|
750 |
|
|
dvander@4116
|
751 |
case OP_FILL: |
|
dvander@4116
|
752 |
{ |
|
dvander@4116
|
753 |
uint8_t *dest = plugin->memory + alt; |
|
dvander@4116
|
754 |
memset(dest, pri, *cip++); |
|
dvander@4116
|
755 |
break; |
|
dvander@4116
|
756 |
} |
|
dvander@4116
|
757 |
|
|
dvander@4116
|
758 |
case OP_STRADJUST_PRI: |
|
dvander@4116
|
759 |
pri += 4; |
|
dvander@4116
|
760 |
pri >>= 2; |
|
dvander@4116
|
761 |
break; |
|
dvander@4116
|
762 |
|
|
dvander@4116
|
763 |
case OP_STACK: |
|
dvander@4116
|
764 |
{ |
|
dvander@4116
|
765 |
cell_t amount = *cip++; |
|
dvander@4116
|
766 |
if (!IsValidOffset(amount)) { |
|
dvander@4116
|
767 |
ctx->err = SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
768 |
goto error; |
|
dvander@4116
|
769 |
} |
|
dvander@4116
|
770 |
|
|
dvander@4116
|
771 |
stk += amount / 4; |
|
dvander@4116
|
772 |
if (amount > 0) { |
|
dvander@4116
|
773 |
if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) { |
|
dvander@4116
|
774 |
ctx->err = SP_ERROR_STACKMIN; |
|
dvander@4116
|
775 |
goto error; |
|
dvander@4116
|
776 |
} |
|
dvander@4116
|
777 |
} else { |
|
dvander@4116
|
778 |
if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) { |
|
dvander@4116
|
779 |
ctx->err = SP_ERROR_STACKLOW; |
|
dvander@4116
|
780 |
goto error; |
|
dvander@4116
|
781 |
} |
|
dvander@4116
|
782 |
} |
|
dvander@4116
|
783 |
break; |
|
dvander@4116
|
784 |
} |
|
dvander@4116
|
785 |
|
|
dvander@4116
|
786 |
case OP_HEAP: |
|
dvander@4116
|
787 |
{ |
|
dvander@4116
|
788 |
cell_t amount = *cip++; |
|
dvander@4116
|
789 |
|
|
dvander@4116
|
790 |
alt = ctx->hp; |
|
dvander@4116
|
791 |
ctx->hp += amount; |
|
dvander@4116
|
792 |
|
|
dvander@4116
|
793 |
if (amount > 0) { |
|
dvander@4116
|
794 |
if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) { |
|
dvander@4116
|
795 |
ctx->err = SP_ERROR_HEAPLOW; |
|
dvander@4116
|
796 |
goto error; |
|
dvander@4116
|
797 |
} |
|
dvander@4116
|
798 |
} else { |
|
dvander@4116
|
799 |
if (uint32_t(ctx->hp) < plugin->data_size) { |
|
dvander@4116
|
800 |
ctx->err = SP_ERROR_HEAPMIN; |
|
dvander@4116
|
801 |
goto error; |
|
dvander@4116
|
802 |
} |
|
dvander@4116
|
803 |
} |
|
dvander@4116
|
804 |
break; |
|
dvander@4116
|
805 |
} |
|
dvander@4116
|
806 |
|
|
dvander@4116
|
807 |
case OP_JUMP: |
|
dvander@4116
|
808 |
if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL) |
|
dvander@4116
|
809 |
goto error; |
|
dvander@4116
|
810 |
break; |
|
dvander@4116
|
811 |
|
|
dvander@4116
|
812 |
case OP_JZER: |
|
dvander@4116
|
813 |
if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL) |
|
dvander@4116
|
814 |
goto error; |
|
dvander@4116
|
815 |
break; |
|
dvander@4116
|
816 |
case OP_JNZ: |
|
dvander@4116
|
817 |
if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL) |
|
dvander@4116
|
818 |
goto error; |
|
dvander@4116
|
819 |
break; |
|
dvander@4116
|
820 |
|
|
dvander@4116
|
821 |
case OP_JEQ: |
|
dvander@4116
|
822 |
if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL) |
|
dvander@4116
|
823 |
goto error; |
|
dvander@4116
|
824 |
break; |
|
dvander@4116
|
825 |
case OP_JNEQ: |
|
dvander@4116
|
826 |
if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL) |
|
dvander@4116
|
827 |
goto error; |
|
dvander@4116
|
828 |
break; |
|
dvander@4116
|
829 |
case OP_JSLESS: |
|
dvander@4116
|
830 |
if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL) |
|
dvander@4116
|
831 |
goto error; |
|
dvander@4116
|
832 |
break; |
|
dvander@4116
|
833 |
case OP_JSLEQ: |
|
dvander@4116
|
834 |
if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL) |
|
dvander@4116
|
835 |
goto error; |
|
dvander@4116
|
836 |
break; |
|
dvander@4116
|
837 |
case OP_JSGRTR: |
|
dvander@4116
|
838 |
if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL) |
|
dvander@4116
|
839 |
goto error; |
|
dvander@4116
|
840 |
break; |
|
dvander@4116
|
841 |
case OP_JSGEQ: |
|
dvander@4116
|
842 |
if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL) |
|
dvander@4116
|
843 |
goto error; |
|
dvander@4116
|
844 |
break; |
|
dvander@4116
|
845 |
|
|
dvander@4116
|
846 |
case OP_TRACKER_PUSH_C: |
|
dvander@4116
|
847 |
{ |
|
dvander@4116
|
848 |
cell_t amount = *cip++; |
|
dvander@4116
|
849 |
int error = PushTracker(ctx, amount * 4); |
|
dvander@4116
|
850 |
if (error != SP_ERROR_NONE) { |
|
dvander@4116
|
851 |
ctx->err = error; |
|
dvander@4116
|
852 |
goto error; |
|
dvander@4116
|
853 |
} |
|
dvander@4116
|
854 |
break; |
|
dvander@4116
|
855 |
} |
|
dvander@4116
|
856 |
|
|
dvander@4116
|
857 |
case OP_TRACKER_POP_SETHEAP: |
|
dvander@4116
|
858 |
{ |
|
dvander@4116
|
859 |
int error = PopTrackerAndSetHeap(rt); |
|
dvander@4116
|
860 |
if (error != SP_ERROR_NONE) { |
|
dvander@4116
|
861 |
ctx->err = error; |
|
dvander@4116
|
862 |
goto error; |
|
dvander@4116
|
863 |
} |
|
dvander@4116
|
864 |
break; |
|
dvander@4116
|
865 |
} |
|
dvander@4116
|
866 |
|
|
dvander@4116
|
867 |
case OP_BREAK: |
|
dvander@4116
|
868 |
ctx->cip = uintptr_t(cip - 1) - uintptr_t(plugin->pcode); |
|
dvander@4116
|
869 |
break; |
|
dvander@4116
|
870 |
|
|
dvander@4116
|
871 |
case OP_BOUNDS: |
|
dvander@4116
|
872 |
{ |
|
dvander@4116
|
873 |
cell_t value = *cip++; |
|
dvander@4116
|
874 |
if (uint32_t(pri) > uint32_t(value)) { |
|
dvander@4116
|
875 |
ctx->err = SP_ERROR_ARRAY_BOUNDS; |
|
dvander@4116
|
876 |
goto error; |
|
dvander@4116
|
877 |
} |
|
dvander@4116
|
878 |
break; |
|
dvander@4116
|
879 |
} |
|
dvander@4116
|
880 |
|
|
dvander@4116
|
881 |
case OP_CALL: |
|
dvander@4116
|
882 |
{ |
|
dvander@4116
|
883 |
cell_t offset = *cip++; |
|
dvander@4116
|
884 |
|
|
dvander@4116
|
885 |
if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) { |
|
dvander@4116
|
886 |
ctx->err = SP_ERROR_INSTRUCTION_PARAM; |
|
dvander@4116
|
887 |
goto error; |
|
dvander@4116
|
888 |
} |
|
dvander@4116
|
889 |
|
|
dvander@4116
|
890 |
if (ctx->rp >= SP_MAX_RETURN_STACK) { |
|
dvander@4116
|
891 |
ctx->err = SP_ERROR_STACKLOW; |
|
dvander@4116
|
892 |
goto error; |
|
dvander@4116
|
893 |
} |
|
dvander@4116
|
894 |
|
|
dvander@4116
|
895 |
// For debugging. |
|
dvander@4116
|
896 |
uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode); |
|
dvander@4116
|
897 |
ctx->rstk_cips[ctx->rp++] = rcip; |
|
dvander@4116
|
898 |
ctx->cip = offset; |
|
dvander@4116
|
899 |
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory); |
|
dvander@4116
|
900 |
|
|
dvander@4116
|
901 |
int err = Interpret(rt, offset, &pri); |
|
dvander@4116
|
902 |
|
|
dvander@4116
|
903 |
stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp); |
|
dvander@4116
|
904 |
ctx->cip = rcip; |
|
dvander@4116
|
905 |
ctx->rp--; |
|
dvander@4116
|
906 |
|
|
dvander@4116
|
907 |
if (err != SP_ERROR_NONE) |
|
dvander@4116
|
908 |
goto error; |
|
dvander@4116
|
909 |
break; |
|
dvander@4116
|
910 |
} |
|
dvander@4116
|
911 |
|
|
dvander@4116
|
912 |
case OP_GENARRAY: |
|
dvander@4116
|
913 |
case OP_GENARRAY_Z: |
|
dvander@4116
|
914 |
{ |
|
dvander@4116
|
915 |
cell_t val = *cip++; |
|
dvander@4116
|
916 |
if (!GenerateArray(rt, ctx, val, stk, op == OP_GENARRAY_Z)) |
|
dvander@4116
|
917 |
goto error; |
|
dvander@4116
|
918 |
|
|
dvander@4116
|
919 |
stk += (val - 1) * 4; |
|
dvander@4116
|
920 |
break; |
|
dvander@4116
|
921 |
} |
|
dvander@4116
|
922 |
|
|
dvander@4116
|
923 |
case OP_SYSREQ_C: |
|
dvander@4116
|
924 |
case OP_SYSREQ_N: |
|
dvander@4116
|
925 |
{ |
|
dvander@4116
|
926 |
uint32_t native_index = *cip++; |
|
dvander@4116
|
927 |
|
|
dvander@4116
|
928 |
if (native_index >= plugin->num_natives) { |
|
dvander@4116
|
929 |
ctx->err = SP_ERROR_INSTRUCTION_PARAM; |
|
dvander@4116
|
930 |
goto error; |
|
dvander@4116
|
931 |
} |
|
dvander@4116
|
932 |
|
|
dvander@4116
|
933 |
uint32_t num_params; |
|
dvander@4116
|
934 |
if (op == OP_SYSREQ_N) { |
|
dvander@4116
|
935 |
num_params = *cip++; |
|
dvander@4116
|
936 |
*--stk = num_params; |
|
dvander@4116
|
937 |
} |
|
dvander@4116
|
938 |
|
|
dvander@4116
|
939 |
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory); |
|
dvander@4116
|
940 |
pri = NativeCallback(ctx, native_index, stk); |
|
dvander@4116
|
941 |
if (ctx->n_err != SP_ERROR_NONE) { |
|
dvander@4116
|
942 |
ctx->err = ctx->n_err; |
|
dvander@4116
|
943 |
goto error; |
|
dvander@4116
|
944 |
} |
|
dvander@4116
|
945 |
|
|
dvander@4116
|
946 |
if (op == OP_SYSREQ_N) |
|
dvander@4116
|
947 |
stk += num_params + 1; |
|
dvander@4116
|
948 |
break; |
|
dvander@4116
|
949 |
} |
|
dvander@4116
|
950 |
|
|
dvander@4116
|
951 |
case OP_SWITCH: |
|
dvander@4116
|
952 |
{ |
|
dvander@4116
|
953 |
cell_t offset = *cip++; |
|
dvander@4116
|
954 |
cell_t *table = reinterpret_cast<cell_t *>(plugin->pcode + offset + sizeof(cell_t)); |
|
dvander@4116
|
955 |
|
|
dvander@4116
|
956 |
size_t ncases = *table++; |
|
dvander@4116
|
957 |
cell_t target = *table++; // default case |
|
dvander@4116
|
958 |
|
|
dvander@4116
|
959 |
for (size_t i = 0; i < ncases; i++) { |
|
dvander@4116
|
960 |
if (table[i * 2] == pri) { |
|
dvander@4116
|
961 |
target = table[i * 2 + 1]; |
|
dvander@4116
|
962 |
break; |
|
dvander@4116
|
963 |
} |
|
dvander@4116
|
964 |
} |
|
dvander@4116
|
965 |
|
|
dvander@4116
|
966 |
if ((cip = Jump(plugin, ctx, target)) == NULL) |
|
dvander@4116
|
967 |
goto error; |
|
dvander@4116
|
968 |
break; |
|
dvander@4116
|
969 |
} |
|
dvander@4116
|
970 |
|
|
dvander@4116
|
971 |
default: |
|
dvander@4116
|
972 |
{ |
|
dvander@4116
|
973 |
ctx->err = SP_ERROR_INVALID_INSTRUCTION; |
|
dvander@4116
|
974 |
goto error; |
|
dvander@4116
|
975 |
} |
|
dvander@4116
|
976 |
} // switch |
|
dvander@4116
|
977 |
} |
|
dvander@4116
|
978 |
|
|
dvander@4116
|
979 |
done: |
|
dvander@4116
|
980 |
assert(orig_frm == ctx->frm); |
|
dvander@4116
|
981 |
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory); |
|
dvander@4116
|
982 |
return ctx->err; |
|
dvander@4116
|
983 |
|
|
dvander@4116
|
984 |
error: |
|
dvander@4116
|
985 |
ctx->frm = orig_frm; |
|
dvander@4116
|
986 |
goto done; |
|
dvander@4116
|
987 |
} |
|
dvander@4116
|
988 |
|