aboutsummaryrefslogtreecommitdiffstats
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c262
1 files changed, 231 insertions, 31 deletions
diff --git a/src/vm.c b/src/vm.c
index 205c15a..0791706 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) \
@@ -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,121 @@ 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_LD64I: {
218 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
219 sz offset = vm->chunk->constants[instruction.b].i;
220 vm->regs[instruction.dst].i = addr[offset];
221 } break;
222 case OP_LD64: {
223 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
224 sz offset = vm->regs[instruction.b].i;
225 vm->regs[instruction.dst].i = addr[offset];
226 } break;
227 case OP_JMP: {
228 u8 dst = instruction.dst;
229 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
230 vm->ip = vm->chunk->code + pos;
161 } break; 231 } break;
162 case OP_JMPFI: { 232 case OP_JMPFI: {
163 bool cond = vm->chunk->constants[instruction.dst].i; 233 u8 dst = instruction.dst;
164 sz offset = vm->chunk->constants[instruction.a].i; 234 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
235 bool cond = vm->chunk->constants[instruction.a].i;
165 if (!cond) { 236 if (!cond) {
166 vm->ip += offset - 1; 237 vm->ip = vm->chunk->code + pos;
167 } 238 }
168 } break; 239 } break;
169 case OP_JMPTI: { 240 case OP_JMPTI: {
170 bool cond = vm->chunk->constants[instruction.dst].i; 241 u8 dst = instruction.dst;
171 sz offset = vm->chunk->constants[instruction.a].i; 242 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
243 bool cond = vm->chunk->constants[instruction.a].i;
172 if (cond) { 244 if (cond) {
173 vm->ip += offset - 1; 245 vm->ip = vm->chunk->code + pos;
174 } 246 }
175 } break; 247 } 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: { 248 case OP_JMPF: {
181 bool cond = vm->regs[instruction.dst].i; 249 u8 dst = instruction.dst;
182 sz offset = vm->chunk->constants[instruction.a].i; 250 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
251 bool cond = vm->regs[instruction.a].i;
183 if (!cond) { 252 if (!cond) {
184 vm->ip += offset - 1; 253 vm->ip = vm->chunk->code + pos;
185 } 254 }
186 } break; 255 } break;
187 case OP_JMPT: { 256 case OP_JMPT: {
188 bool cond = vm->regs[instruction.dst].i; 257 u8 dst = instruction.dst;
189 sz offset = vm->chunk->constants[instruction.a].i; 258 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
259 bool cond = vm->regs[instruction.a].i;
190 if (cond) { 260 if (cond) {
191 vm->ip += offset - 1; 261 vm->ip = vm->chunk->code + pos;
192 } 262 }
193 } break; 263 } break;
194 case OP_MOV64: { 264 case OP_MOV64: {
@@ -211,10 +281,140 @@ vm_run(VM *vm) {
211 u8 src = instruction.a; 281 u8 src = instruction.a;
212 vm->regs[dst].i = vm->regs[src].i & 0xFF; 282 vm->regs[dst].i = vm->regs[src].i & 0xFF;
213 } break; 283 } break;
284 case OP_PRINTS64: {
285 u8 idx = instruction.dst;
286 print("%d", vm->regs[idx].i);
287 } break;
288 case OP_PRINTS64I: {
289 u8 idx = instruction.dst;
290 print("%d", vm->chunk->constants[idx].i);
291 } break;
292 case OP_PRINTBOOL: {
293 u8 idx = instruction.dst;
294 bool val = vm->regs[idx].i;
295 if (val) {
296 print("true");
297 } else {
298 print("false");
299 }
300 } break;
301 case OP_PRINTBOOLI: {
302 u8 idx = instruction.dst;
303 bool val = vm->chunk->constants[idx].i;
304 if (val) {
305 print("true");
306 } else {
307 print("false");
308 }
309 } break;
310 case OP_PRINTF64: {
311 u8 idx = instruction.dst;
312 printf("%f", vm->regs[idx].f);
313 } break;
314 case OP_PRINTF64I: {
315 u8 idx = instruction.dst;
316 printf("%f", vm->chunk->constants[idx].f);
317 } break;
318 case OP_PRINTSTR: {
319 u8 idx = instruction.dst;
320 Str *string = (Str *)vm->regs[idx].ptr;
321 print("%s", *string);
322 } break;
323 case OP_PRINTSTRI: {
324 u8 idx = instruction.dst;
325 Str string = vm->chunk->strings[idx];
326 print("%s", string);
327 } break;
328 case OP_RESERVE: {
329 sz offset = vm->chunk->constants[instruction.dst].i;
330 vm->sp += offset;
331 } break;
332 case OP_PUSH: {
333 sz val = vm->regs[instruction.dst].i;
334 u64 *p = (u64 *)vm->sp;
335 *p = val;
336 vm->sp += sizeof(ptrsize);
337 } break;
338 case OP_PUSHI: {
339 sz val = vm->chunk->constants[instruction.dst].i;
340 u64 *p = (u64 *)vm->sp;
341 *p = val;
342 vm->sp += sizeof(ptrsize);
343 } break;
344 case OP_POP: {
345 vm->sp -= sizeof(ptrsize);
346 u64 *p = (u64 *)vm->sp;
347 vm->regs[instruction.dst].i = *p;
348 } break;
349 case OP_PUTRET: {
350 sz val = vm->regs[instruction.dst].i;
351 vm->fp[-1] = val;
352 } break;
353 case OP_PUTRETI: {
354 sz val = vm->chunk->constants[instruction.dst].i;
355 vm->fp[-1] = val;
356 } break;
357 case OP_CALL: {
358 u8 dst = instruction.dst;
359 Chunk *func = vm->main->functions[dst];
360
361 ptrsize chunk_addr = (ptrsize)vm->chunk;
362 ptrsize ip_addr = (ptrsize)vm->ip;
363 ptrsize reg_addr = (ptrsize)vm->regs;
364 ptrsize old_fp = (ptrsize)vm->fp;
365
366 // Allocate space for the locals.
367 memset(vm->sp, 0, func->var_off - func->param_off);
368 vm->fp = (u64 *)(vm->sp - func->param_off);
369 vm->sp += func->var_off - func->param_off;
370 vm->chunk = func;
371 vm->ip = func->code;
372 vm->regs = (Constant *)vm->sp;
373
374 // Allocate registers.
375 vm->sp += sizeof(Constant) * func->reg_idx;
376
377 // Store memory addresses we need to return to this function.
378 u64 *p = (u64 *)vm->sp;
379 p[0] = chunk_addr;
380 p[1] = ip_addr;
381 p[2] = reg_addr;
382 p[3] = old_fp;
383 vm->sp += sizeof(ptrsize) * 4;
384 } break;
385 case OP_RECUR: {
386 vm->ip = vm->chunk->code;
387 } break;
388 case OP_RET: {
389 u64 *p = (u64 *)vm->sp;
390 ptrsize chunk_addr = p[-4];
391 ptrsize ip_addr = p[-3];
392 ptrsize reg_addr = p[-2];
393 ptrsize old_fp = p[-1];
394 vm->sp -= sizeof(ptrsize) * 4;
395
396 // Deallocate registers.
397 vm->sp -= sizeof(Constant) * vm->chunk->reg_idx;
398
399 // Deallocate locals.
400 vm->sp -= vm->chunk->var_off;
401
402 // Restore previous activation record.
403 vm->regs = (Constant *)reg_addr;
404 vm->ip = (Instruction *)ip_addr;
405 vm->chunk = (Chunk *)chunk_addr;
406 vm->fp = (u64 *)old_fp;
407 } break;
214 case OP_HALT: { 408 case OP_HALT: {
215 println("VM HALT (int) -> %d", vm->regs[instruction.dst]); 409 println("VM halt...");
216 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 410 if (instruction.a != 0) {
217 println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); 411 println("Result:");
412 Constant result = vm->regs[instruction.dst];
413 printf("\tint -> %lld\n", result.i);
414 printf("\tfloat -> %.10e\n", result.f);
415 printf("\thex -> %llx\n", (u64)result.i);
416 println("\tbinary -> %b", result.i);
417 }
218 return; 418 return;
219 } 419 }
220 default: { 420 default: {