diff options
Diffstat (limited to 'src/vm.c')
-rw-r--r-- | src/vm.c | 418 |
1 files changed, 386 insertions, 32 deletions
@@ -5,12 +5,15 @@ | |||
5 | #include "compiler.c" | 5 | #include "compiler.c" |
6 | 6 | ||
7 | #define N_CONST 256 | 7 | #define N_CONST 256 |
8 | #define STACK_SIZE KB(64) | 8 | #define STACK_SIZE MB(4) |
9 | typedef struct VM { | 9 | typedef struct VM { |
10 | Chunk *main; | ||
10 | Chunk *chunk; | 11 | Chunk *chunk; |
11 | Constant regs[N_CONST]; | ||
12 | u8 stack[STACK_SIZE]; | 12 | u8 stack[STACK_SIZE]; |
13 | Instruction *ip; | 13 | Instruction *ip; |
14 | u8 *sp; | ||
15 | u64 *fp; | ||
16 | Constant *regs; | ||
14 | } VM; | 17 | } VM; |
15 | 18 | ||
16 | void | 19 | void |
@@ -18,8 +21,13 @@ vm_init(VM *vm, Chunk *chunk) { | |||
18 | assert(vm); | 21 | assert(vm); |
19 | assert(chunk); | 22 | assert(chunk); |
20 | assert(chunk->code); | 23 | assert(chunk->code); |
24 | vm->main = chunk; | ||
21 | vm->chunk = chunk; | 25 | vm->chunk = chunk; |
22 | vm->ip = vm->chunk->code; | 26 | vm->ip = vm->chunk->code; |
27 | vm->fp = (u64 *)vm->stack; | ||
28 | vm->sp = vm->stack + chunk->var_off; | ||
29 | vm->regs = (Constant *)vm->sp; | ||
30 | vm->sp += sizeof(Constant) * chunk->reg_idx; | ||
23 | } | 31 | } |
24 | 32 | ||
25 | #define OP_UNARY(OP, TYPE) \ | 33 | #define OP_UNARY(OP, TYPE) \ |
@@ -69,7 +77,7 @@ vm_run(VM *vm) { | |||
69 | #endif | 77 | #endif |
70 | 78 | ||
71 | switch (instruction.op) { | 79 | switch (instruction.op) { |
72 | case OP_LD64K: { | 80 | case OP_LDCONST: { |
73 | u8 dst = instruction.dst; | 81 | u8 dst = instruction.dst; |
74 | u8 src_a = instruction.a; | 82 | u8 src_a = instruction.a; |
75 | vm->regs[dst].i = vm->chunk->constants[src_a].i; | 83 | vm->regs[dst].i = vm->chunk->constants[src_a].i; |
@@ -77,6 +85,7 @@ vm_run(VM *vm) { | |||
77 | case OP_NOT: OP_UNARY(!, i) break; | 85 | case OP_NOT: OP_UNARY(!, i) break; |
78 | case OP_BITNOT: OP_UNARY(~, i) break; | 86 | case OP_BITNOT: OP_UNARY(~, i) break; |
79 | case OP_BITOR: OP_BINARY(|, i) break; | 87 | case OP_BITOR: OP_BINARY(|, i) break; |
88 | case OP_BITXOR: OP_BINARY(^, i) break; | ||
80 | case OP_BITAND: OP_BINARY(&, i) break; | 89 | case OP_BITAND: OP_BINARY(&, i) break; |
81 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; | 90 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; |
82 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; | 91 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; |
@@ -107,6 +116,7 @@ vm_run(VM *vm) { | |||
107 | case OP_NOTI: OP_UNARY_CONST(!, i) break; | 116 | case OP_NOTI: OP_UNARY_CONST(!, i) break; |
108 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; | 117 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; |
109 | case OP_BITORI: OP_BINARY_CONST(|, i) break; | 118 | case OP_BITORI: OP_BINARY_CONST(|, i) break; |
119 | case OP_BITXORI: OP_BINARY_CONST(^, i) break; | ||
110 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; | 120 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; |
111 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; | 121 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; |
112 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; | 122 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; |
@@ -134,61 +144,219 @@ vm_run(VM *vm) { | |||
134 | vm->regs[dst].f = | 144 | vm->regs[dst].f = |
135 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | 145 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); |
136 | } break; | 146 | } break; |
147 | case OP_STGVAR: { | ||
148 | u8 dst = instruction.dst; | ||
149 | u8 src = instruction.a; | ||
150 | Variable var = vm->main->vars[dst]; | ||
151 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
152 | *stack = vm->regs[src].i; | ||
153 | } break; | ||
154 | case OP_STGVARI: { | ||
155 | u8 dst = instruction.dst; | ||
156 | u8 src = instruction.a; | ||
157 | Variable var = vm->main->vars[dst]; | ||
158 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
159 | *stack = vm->chunk->constants[src].i; | ||
160 | } break; | ||
137 | case OP_LDGVAR: { | 161 | case OP_LDGVAR: { |
138 | u8 dst = instruction.dst; | 162 | u8 dst = instruction.dst; |
139 | u8 src = instruction.a; | 163 | u8 src = instruction.a; |
140 | Variable var = vm->chunk->vars[src]; | 164 | Variable var = vm->main->vars[src]; |
141 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 165 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
142 | vm->regs[dst].i = *stack; | 166 | vm->regs[dst].i = *stack; |
143 | } break; | 167 | } break; |
144 | case OP_STGVAR: { | 168 | case OP_LDGADDR: { |
145 | u8 dst = instruction.dst; | 169 | u8 dst = instruction.dst; |
146 | u8 src = instruction.a; | 170 | u8 src = instruction.a; |
147 | Variable var = vm->chunk->vars[dst]; | 171 | Variable var = vm->main->vars[src]; |
148 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 172 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
149 | *stack = vm->regs[src].i; | 173 | vm->regs[dst].ptr = (ptrsize)stack; |
150 | } break; | 174 | } break; |
151 | case OP_STGVARI: { | 175 | case OP_STLVAR: { |
152 | u8 dst = instruction.dst; | 176 | u8 dst = instruction.dst; |
153 | u8 src = instruction.a; | 177 | u8 src = instruction.a; |
154 | Variable var = vm->chunk->vars[dst]; | 178 | Variable var = vm->chunk->vars[dst]; |
155 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 179 | vm->fp[var.offset / 8] = vm->regs[src].i; |
156 | *stack = vm->chunk->constants[src].i; | ||
157 | } break; | 180 | } break; |
158 | case OP_JMPI: { | 181 | case OP_STLVARI: { |
159 | sz offset = vm->chunk->constants[instruction.dst].i; | 182 | u8 dst = instruction.dst; |
160 | vm->ip += offset - 1; | 183 | u8 src = instruction.a; |
184 | Variable var = vm->chunk->vars[dst]; | ||
185 | vm->fp[var.offset / 8] = vm->chunk->constants[src].i; | ||
186 | } break; | ||
187 | case OP_LDLVAR: { | ||
188 | u8 dst = instruction.dst; | ||
189 | u8 src = instruction.a; | ||
190 | Variable var = vm->chunk->vars[src]; | ||
191 | vm->regs[dst].i = vm->fp[var.offset / 8]; | ||
192 | } break; | ||
193 | case OP_LDLADDR: { | ||
194 | u8 dst = instruction.dst; | ||
195 | u8 src = instruction.a; | ||
196 | Variable var = vm->chunk->vars[src]; | ||
197 | vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8]; | ||
198 | } break; | ||
199 | case OP_LDSTR: { | ||
200 | u8 dst = instruction.dst; | ||
201 | u8 src = instruction.a; | ||
202 | Str *str = &vm->chunk->strings[src]; | ||
203 | vm->regs[dst].ptr = (ptrsize)str; | ||
204 | } break; | ||
205 | case OP_ST64I: { | ||
206 | sz value = vm->regs[instruction.dst].ptr; | ||
207 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
208 | sz offset = vm->chunk->constants[instruction.b].i; | ||
209 | addr[offset] = value; | ||
210 | } break; | ||
211 | case OP_ST64: { | ||
212 | sz value = vm->regs[instruction.dst].i; | ||
213 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
214 | sz offset = vm->regs[instruction.b].i; | ||
215 | addr[offset] = value; | ||
216 | } break; | ||
217 | case OP_ST16I: { | ||
218 | sz value = vm->regs[instruction.dst].ptr; | ||
219 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
220 | sz offset = vm->chunk->constants[instruction.b].i; | ||
221 | addr[offset] = value; | ||
222 | } break; | ||
223 | case OP_ST16: { | ||
224 | sz value = vm->regs[instruction.dst].i; | ||
225 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
226 | sz offset = vm->regs[instruction.b].i; | ||
227 | addr[offset] = value; | ||
228 | } break; | ||
229 | case OP_ST8I: { | ||
230 | sz value = vm->regs[instruction.dst].ptr; | ||
231 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
232 | sz offset = vm->chunk->constants[instruction.b].i; | ||
233 | addr[offset] = value; | ||
234 | } break; | ||
235 | case OP_ST8: { | ||
236 | sz value = vm->regs[instruction.dst].i; | ||
237 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
238 | sz offset = vm->regs[instruction.b].i; | ||
239 | addr[offset] = value; | ||
240 | } break; | ||
241 | case OP_ST32I: { | ||
242 | sz value = vm->regs[instruction.dst].ptr; | ||
243 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
244 | sz offset = vm->chunk->constants[instruction.b].i; | ||
245 | addr[offset] = value; | ||
246 | } break; | ||
247 | case OP_ST32: { | ||
248 | sz value = vm->regs[instruction.dst].i; | ||
249 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
250 | sz offset = vm->regs[instruction.b].i; | ||
251 | addr[offset] = value; | ||
252 | } break; | ||
253 | case OP_LD64I: { | ||
254 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
255 | sz offset = vm->chunk->constants[instruction.b].i; | ||
256 | vm->regs[instruction.dst].i = addr[offset]; | ||
257 | } break; | ||
258 | case OP_LD64: { | ||
259 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
260 | sz offset = vm->regs[instruction.b].i; | ||
261 | vm->regs[instruction.dst].i = addr[offset]; | ||
262 | } break; | ||
263 | case OP_LD32I: { | ||
264 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
265 | sz offset = vm->chunk->constants[instruction.b].i; | ||
266 | vm->regs[instruction.dst].i = addr[offset]; | ||
267 | } break; | ||
268 | case OP_LD32: { | ||
269 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
270 | sz offset = vm->regs[instruction.b].i; | ||
271 | vm->regs[instruction.dst].i = addr[offset]; | ||
272 | } break; | ||
273 | case OP_LD16I: { | ||
274 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
275 | sz offset = vm->chunk->constants[instruction.b].i; | ||
276 | vm->regs[instruction.dst].i = addr[offset]; | ||
277 | } break; | ||
278 | case OP_LD16: { | ||
279 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
280 | sz offset = vm->regs[instruction.b].i; | ||
281 | vm->regs[instruction.dst].i = addr[offset]; | ||
282 | } break; | ||
283 | case OP_LD8I: { | ||
284 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
285 | sz offset = vm->chunk->constants[instruction.b].i; | ||
286 | vm->regs[instruction.dst].i = addr[offset]; | ||
287 | } break; | ||
288 | case OP_LD8: { | ||
289 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
290 | sz offset = vm->regs[instruction.b].i; | ||
291 | vm->regs[instruction.dst].i = addr[offset]; | ||
292 | } break; | ||
293 | case OP_LD8K: { | ||
294 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
295 | vm->regs[instruction.dst].i = *addr; | ||
296 | } break; | ||
297 | case OP_LD16K: { | ||
298 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
299 | vm->regs[instruction.dst].i = *addr; | ||
300 | } break; | ||
301 | case OP_LD32K: { | ||
302 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
303 | vm->regs[instruction.dst].i = *addr; | ||
304 | } break; | ||
305 | case OP_LD64K: { | ||
306 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
307 | vm->regs[instruction.dst].i = *addr; | ||
308 | } break; | ||
309 | case OP_ST8K: { | ||
310 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
311 | *addr = vm->regs[instruction.dst].i; | ||
312 | } break; | ||
313 | case OP_ST16K: { | ||
314 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
315 | *addr = vm->regs[instruction.dst].i; | ||
316 | } break; | ||
317 | case OP_ST32K: { | ||
318 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
319 | *addr = vm->regs[instruction.dst].i; | ||
320 | } break; | ||
321 | case OP_ST64K: { | ||
322 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
323 | *addr = vm->regs[instruction.dst].i; | ||
324 | } break; | ||
325 | case OP_JMP: { | ||
326 | u8 dst = instruction.dst; | ||
327 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; | ||
328 | vm->ip = vm->chunk->code + pos; | ||
161 | } break; | 329 | } break; |
162 | case OP_JMPFI: { | 330 | case OP_JMPFI: { |
163 | bool cond = vm->chunk->constants[instruction.dst].i; | 331 | u8 dst = instruction.dst; |
164 | sz offset = vm->chunk->constants[instruction.a].i; | 332 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
333 | bool cond = vm->chunk->constants[instruction.a].i; | ||
165 | if (!cond) { | 334 | if (!cond) { |
166 | vm->ip += offset - 1; | 335 | vm->ip = vm->chunk->code + pos; |
167 | } | 336 | } |
168 | } break; | 337 | } break; |
169 | case OP_JMPTI: { | 338 | case OP_JMPTI: { |
170 | bool cond = vm->chunk->constants[instruction.dst].i; | 339 | u8 dst = instruction.dst; |
171 | sz offset = vm->chunk->constants[instruction.a].i; | 340 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
341 | bool cond = vm->chunk->constants[instruction.a].i; | ||
172 | if (cond) { | 342 | if (cond) { |
173 | vm->ip += offset - 1; | 343 | vm->ip = vm->chunk->code + pos; |
174 | } | 344 | } |
175 | } break; | 345 | } break; |
176 | case OP_JMP: { | ||
177 | sz offset = vm->chunk->constants[instruction.dst].i; | ||
178 | vm->ip += offset - 1; | ||
179 | } break; | ||
180 | case OP_JMPF: { | 346 | case OP_JMPF: { |
181 | bool cond = vm->regs[instruction.dst].i; | 347 | u8 dst = instruction.dst; |
182 | sz offset = vm->chunk->constants[instruction.a].i; | 348 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
349 | bool cond = vm->regs[instruction.a].i; | ||
183 | if (!cond) { | 350 | if (!cond) { |
184 | vm->ip += offset - 1; | 351 | vm->ip = vm->chunk->code + pos; |
185 | } | 352 | } |
186 | } break; | 353 | } break; |
187 | case OP_JMPT: { | 354 | case OP_JMPT: { |
188 | bool cond = vm->regs[instruction.dst].i; | 355 | u8 dst = instruction.dst; |
189 | sz offset = vm->chunk->constants[instruction.a].i; | 356 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
357 | bool cond = vm->regs[instruction.a].i; | ||
190 | if (cond) { | 358 | if (cond) { |
191 | vm->ip += offset - 1; | 359 | vm->ip = vm->chunk->code + pos; |
192 | } | 360 | } |
193 | } break; | 361 | } break; |
194 | case OP_MOV64: { | 362 | case OP_MOV64: { |
@@ -211,10 +379,196 @@ vm_run(VM *vm) { | |||
211 | u8 src = instruction.a; | 379 | u8 src = instruction.a; |
212 | vm->regs[dst].i = vm->regs[src].i & 0xFF; | 380 | vm->regs[dst].i = vm->regs[src].i & 0xFF; |
213 | } break; | 381 | } break; |
382 | case OP_PRINTS8: { | ||
383 | u8 idx = instruction.dst; | ||
384 | print("%d", vm->regs[idx].i & 0xFF); | ||
385 | } break; | ||
386 | case OP_PRINTS16: { | ||
387 | u8 idx = instruction.dst; | ||
388 | print("%d", vm->regs[idx].i & 0xFFFF); | ||
389 | } break; | ||
390 | case OP_PRINTS32: { | ||
391 | u8 idx = instruction.dst; | ||
392 | print("%d", vm->regs[idx].i & 0xFFFFFFFF); | ||
393 | } break; | ||
394 | case OP_PRINTS64: { | ||
395 | u8 idx = instruction.dst; | ||
396 | print("%d", vm->regs[idx].i); | ||
397 | } break; | ||
398 | case OP_PRINTU8: { | ||
399 | u8 idx = instruction.dst; | ||
400 | print("%x", vm->regs[idx].u & 0xFF); | ||
401 | } break; | ||
402 | case OP_PRINTU16: { | ||
403 | u8 idx = instruction.dst; | ||
404 | print("%x", vm->regs[idx].u & 0xFFFF); | ||
405 | } break; | ||
406 | case OP_PRINTU32: { | ||
407 | u8 idx = instruction.dst; | ||
408 | print("%x", vm->regs[idx].u & 0xFFFFFFFF); | ||
409 | } break; | ||
410 | case OP_PRINTU64: { | ||
411 | u8 idx = instruction.dst; | ||
412 | print("%x", vm->regs[idx].u); | ||
413 | } break; | ||
414 | case OP_PRINTS8I: { | ||
415 | u8 idx = instruction.dst; | ||
416 | print("%d", vm->chunk->constants[idx].i & 0xFF); | ||
417 | } break; | ||
418 | case OP_PRINTS16I: { | ||
419 | u8 idx = instruction.dst; | ||
420 | print("%d", vm->chunk->constants[idx].i & 0xFFFF); | ||
421 | } break; | ||
422 | case OP_PRINTS32I: { | ||
423 | u8 idx = instruction.dst; | ||
424 | print("%d", vm->chunk->constants[idx].i & 0xFFFFFFFF); | ||
425 | } break; | ||
426 | case OP_PRINTS64I: { | ||
427 | u8 idx = instruction.dst; | ||
428 | print("%d", vm->chunk->constants[idx].i); | ||
429 | } break; | ||
430 | case OP_PRINTU8I: { | ||
431 | u8 idx = instruction.dst; | ||
432 | print("%x", vm->chunk->constants[idx].u & 0xFF); | ||
433 | } break; | ||
434 | case OP_PRINTU16I: { | ||
435 | u8 idx = instruction.dst; | ||
436 | print("%x", vm->chunk->constants[idx].u & 0xFFFF); | ||
437 | } break; | ||
438 | case OP_PRINTU32I: { | ||
439 | u8 idx = instruction.dst; | ||
440 | print("%x", vm->chunk->constants[idx].u & 0xFFFFFFFF); | ||
441 | } break; | ||
442 | case OP_PRINTU64I: { | ||
443 | u8 idx = instruction.dst; | ||
444 | print("%x", vm->chunk->constants[idx].u); | ||
445 | } break; | ||
446 | case OP_PRINTBOOL: { | ||
447 | u8 idx = instruction.dst; | ||
448 | bool val = vm->regs[idx].i; | ||
449 | if (val) { | ||
450 | print("true"); | ||
451 | } else { | ||
452 | print("false"); | ||
453 | } | ||
454 | } break; | ||
455 | case OP_PRINTBOOLI: { | ||
456 | u8 idx = instruction.dst; | ||
457 | bool val = vm->chunk->constants[idx].i; | ||
458 | if (val) { | ||
459 | print("true"); | ||
460 | } else { | ||
461 | print("false"); | ||
462 | } | ||
463 | } break; | ||
464 | case OP_PRINTF64: { | ||
465 | u8 idx = instruction.dst; | ||
466 | printf("%f", vm->regs[idx].f); | ||
467 | } break; | ||
468 | case OP_PRINTF64I: { | ||
469 | u8 idx = instruction.dst; | ||
470 | printf("%f", vm->chunk->constants[idx].f); | ||
471 | } break; | ||
472 | case OP_PRINTSTR: { | ||
473 | u8 idx = instruction.dst; | ||
474 | Str *string = (Str *)vm->regs[idx].ptr; | ||
475 | print("%s", *string); | ||
476 | } break; | ||
477 | case OP_PRINTSTRI: { | ||
478 | u8 idx = instruction.dst; | ||
479 | Str string = vm->chunk->strings[idx]; | ||
480 | print("%s", string); | ||
481 | } break; | ||
482 | case OP_RESERVE: { | ||
483 | sz offset = vm->chunk->constants[instruction.dst].i; | ||
484 | vm->sp += offset; | ||
485 | } break; | ||
486 | case OP_PUSH: { | ||
487 | sz val = vm->regs[instruction.dst].i; | ||
488 | u64 *p = (u64 *)vm->sp; | ||
489 | *p = val; | ||
490 | vm->sp += sizeof(ptrsize); | ||
491 | } break; | ||
492 | case OP_PUSHI: { | ||
493 | sz val = vm->chunk->constants[instruction.dst].i; | ||
494 | u64 *p = (u64 *)vm->sp; | ||
495 | *p = val; | ||
496 | vm->sp += sizeof(ptrsize); | ||
497 | } break; | ||
498 | case OP_POP: { | ||
499 | vm->sp -= sizeof(ptrsize); | ||
500 | u64 *p = (u64 *)vm->sp; | ||
501 | vm->regs[instruction.dst].i = *p; | ||
502 | } break; | ||
503 | case OP_PUTRET: { | ||
504 | sz val = vm->regs[instruction.dst].i; | ||
505 | vm->fp[-1] = val; | ||
506 | } break; | ||
507 | case OP_PUTRETI: { | ||
508 | sz val = vm->chunk->constants[instruction.dst].i; | ||
509 | vm->fp[-1] = val; | ||
510 | } break; | ||
511 | case OP_CALL: { | ||
512 | u8 dst = instruction.dst; | ||
513 | Chunk *func = vm->main->functions[dst]; | ||
514 | |||
515 | ptrsize chunk_addr = (ptrsize)vm->chunk; | ||
516 | ptrsize ip_addr = (ptrsize)vm->ip; | ||
517 | ptrsize reg_addr = (ptrsize)vm->regs; | ||
518 | ptrsize old_fp = (ptrsize)vm->fp; | ||
519 | |||
520 | // Allocate space for the locals. | ||
521 | memset(vm->sp, 0, func->var_off - func->param_off); | ||
522 | vm->fp = (u64 *)(vm->sp - func->param_off); | ||
523 | vm->sp += func->var_off - func->param_off; | ||
524 | vm->chunk = func; | ||
525 | vm->ip = func->code; | ||
526 | vm->regs = (Constant *)vm->sp; | ||
527 | |||
528 | // Allocate registers. | ||
529 | vm->sp += sizeof(Constant) * func->reg_idx; | ||
530 | |||
531 | // Store memory addresses we need to return to this function. | ||
532 | u64 *p = (u64 *)vm->sp; | ||
533 | p[0] = chunk_addr; | ||
534 | p[1] = ip_addr; | ||
535 | p[2] = reg_addr; | ||
536 | p[3] = old_fp; | ||
537 | vm->sp += sizeof(ptrsize) * 4; | ||
538 | } break; | ||
539 | case OP_RECUR: { | ||
540 | vm->ip = vm->chunk->code; | ||
541 | } break; | ||
542 | case OP_RET: { | ||
543 | u64 *p = (u64 *)vm->sp; | ||
544 | ptrsize chunk_addr = p[-4]; | ||
545 | ptrsize ip_addr = p[-3]; | ||
546 | ptrsize reg_addr = p[-2]; | ||
547 | ptrsize old_fp = p[-1]; | ||
548 | vm->sp -= sizeof(ptrsize) * 4; | ||
549 | |||
550 | // Deallocate registers. | ||
551 | vm->sp -= sizeof(Constant) * vm->chunk->reg_idx; | ||
552 | |||
553 | // Deallocate locals. | ||
554 | vm->sp -= vm->chunk->var_off; | ||
555 | |||
556 | // Restore previous activation record. | ||
557 | vm->regs = (Constant *)reg_addr; | ||
558 | vm->ip = (Instruction *)ip_addr; | ||
559 | vm->chunk = (Chunk *)chunk_addr; | ||
560 | vm->fp = (u64 *)old_fp; | ||
561 | } break; | ||
214 | case OP_HALT: { | 562 | case OP_HALT: { |
215 | println("VM HALT (int) -> %d", vm->regs[instruction.dst]); | 563 | println("VM halt..."); |
216 | println("VM HALT (float) -> %f", vm->regs[instruction.dst]); | 564 | if (instruction.a != 0) { |
217 | println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); | 565 | println("Result:"); |
566 | Constant result = vm->regs[instruction.dst]; | ||
567 | printf("\tint -> %lld\n", result.i); | ||
568 | printf("\tfloat -> %.10e\n", result.f); | ||
569 | printf("\thex -> %llx\n", (u64)result.i); | ||
570 | println("\tbinary -> %b", result.i); | ||
571 | } | ||
218 | return; | 572 | return; |
219 | } | 573 | } |
220 | default: { | 574 | default: { |