aboutsummaryrefslogtreecommitdiffstats
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c286
1 files changed, 271 insertions, 15 deletions
diff --git a/src/vm.c b/src/vm.c
index fac477a..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,36 +144,282 @@ 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;
137 case OP_LDVAR: { 147 case OP_STGVAR: {
138 u8 dst = instruction.dst; 148 u8 dst = instruction.dst;
139 u8 src = instruction.a; 149 u8 src = instruction.a;
140 println("dst: %d src: %d", dst, src); 150 Variable var = vm->main->vars[dst];
141 Variable var = vm->chunk->vars[src]; 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;
161 case OP_LDGVAR: {
162 u8 dst = instruction.dst;
163 u8 src = instruction.a;
164 Variable var = vm->main->vars[src];
142 s64 *stack = (s64 *)&vm->stack[var.offset]; 165 s64 *stack = (s64 *)&vm->stack[var.offset];
143 vm->regs[dst].i = *stack; 166 vm->regs[dst].i = *stack;
144 } break; 167 } break;
145 case OP_STVAR: { 168 case OP_LDGADDR: {
146 u8 dst = instruction.dst; 169 u8 dst = instruction.dst;
147 u8 src = instruction.a; 170 u8 src = instruction.a;
148 Variable var = vm->chunk->vars[dst]; 171 Variable var = vm->main->vars[src];
149 s64 *stack = (s64 *)&vm->stack[var.offset]; 172 s64 *stack = (s64 *)&vm->stack[var.offset];
150 *stack = vm->regs[src].i; 173 vm->regs[dst].ptr = (ptrsize)stack;
151 } break; 174 } break;
152 case OP_STVARI: { 175 case OP_STLVAR: {
153 u8 dst = instruction.dst; 176 u8 dst = instruction.dst;
154 u8 src = instruction.a; 177 u8 src = instruction.a;
155 Variable var = vm->chunk->vars[dst]; 178 Variable var = vm->chunk->vars[dst];
156 s64 *stack = (s64 *)&vm->stack[var.offset]; 179 vm->fp[var.offset / 8] = vm->regs[src].i;
157 *stack = vm->chunk->constants[src].i; 180 } break;
181 case OP_STLVARI: {
182 u8 dst = instruction.dst;
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;
231 } break;
232 case OP_JMPFI: {
233 u8 dst = instruction.dst;
234 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
235 bool cond = vm->chunk->constants[instruction.a].i;
236 if (!cond) {
237 vm->ip = vm->chunk->code + pos;
238 }
239 } break;
240 case OP_JMPTI: {
241 u8 dst = instruction.dst;
242 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
243 bool cond = vm->chunk->constants[instruction.a].i;
244 if (cond) {
245 vm->ip = vm->chunk->code + pos;
246 }
247 } break;
248 case OP_JMPF: {
249 u8 dst = instruction.dst;
250 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
251 bool cond = vm->regs[instruction.a].i;
252 if (!cond) {
253 vm->ip = vm->chunk->code + pos;
254 }
255 } break;
256 case OP_JMPT: {
257 u8 dst = instruction.dst;
258 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
259 bool cond = vm->regs[instruction.a].i;
260 if (cond) {
261 vm->ip = vm->chunk->code + pos;
262 }
263 } break;
264 case OP_MOV64: {
265 u8 dst = instruction.dst;
266 u8 src = instruction.a;
267 vm->regs[dst] = vm->regs[src];
268 } break;
269 case OP_MOV32: {
270 u8 dst = instruction.dst;
271 u8 src = instruction.a;
272 vm->regs[dst].i = vm->regs[src].i & 0xFFFFFFFF;
273 } break;
274 case OP_MOV16: {
275 u8 dst = instruction.dst;
276 u8 src = instruction.a;
277 vm->regs[dst].i = vm->regs[src].i & 0xFFFF;
278 } break;
279 case OP_MOV8: {
280 u8 dst = instruction.dst;
281 u8 src = instruction.a;
282 vm->regs[dst].i = vm->regs[src].i & 0xFF;
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;
158 } break; 407 } break;
159 case OP_HALT: { 408 case OP_HALT: {
160 println("VM HALT (int) -> %d", vm->regs[instruction.dst]); 409 println("VM halt...");
161 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 410 if (instruction.a != 0) {
162 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 }
163 return; 418 return;
164 } 419 }
165 default: { 420 default: {
166 eprintln("unimplemented OP code: %d", instruction.op); 421 // eprintln("unimplemented OP code: %d", instruction.op);
422 eprintln("unimplemented OP code: %s", op_str[instruction.op]);
167 return; 423 return;
168 } 424 }
169 } 425 }