aboutsummaryrefslogtreecommitdiffstats
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c418
1 files changed, 386 insertions, 32 deletions
diff --git a/src/vm.c b/src/vm.c
index 205c15a..ed69498 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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)
9typedef struct VM { 9typedef 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
16void 19void
@@ -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: {