ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /vm.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "dat.h" #include "fns.h" static VM *vm; static void _Noreturn usage(void) { fprint(2, "usage: apl/vm objfile\n"); exits("usage"); } static void initvm(void) { vm = mallocz(sizeof(VM), 1); } static void loadmod(char *file) { Biobuf *b = Bopen(file, OREAD); if(b == nil) sysfatal("open: %r"); Module *m = mallocz(sizeof(Module), 1); for(int n = 0; n < nelem(objparts); n++) objparts[n].read(m, b, 0); Bterm(b); vm->nmods++; vm->mods = realloc(vm->mods, vm->nmods * sizeof(*vm->mods)); vm->mods[vm->nmods-1] = m; } static void stackgrow(uvlong n) { vm->regs[RegSp].u64 += n; if(vm->regs[RegSp].u64 > nelem(vm->stack)) sysfatal("APL stack overflow"); } static uvlong findlabel(char *name) { Module *m = vm->mods[vm->regs[RegMod].u64]; for(int i = 0; i < m->nlabels; i++){ if(strcmp(name, m->labels[i].name) == 0) return m->labels[i].coffset; } sysfatal("Failed to find label %s", name); } static Word * getaddr(OpArg *a) { switch(a->tag){ case OAlabel: case OAnum1: case OAnum2: case OAnum4: case OAnum8: return (Word*)&a->u64; case OAreg: return &vm->regs[a->u64]; case OAlocal1: case OAlocal2: case OAlocal4: case OAlocal8: if((a->u64+1) > (vm->regs[RegSp].u64 - vm->regs[RegFp].u64)) sysfatal("Use of unallocated local: %%%ulld\n", a->u64); return &vm->stack[vm->regs[RegFp].u64+a->u64]; default: sysfatal("unhandled case in getaddr: %d", a->tag); } } static void interpret(void) { ParsedInstr instr; vm->regs[RegMod].u64 = 0; u8int *code = vm->mods[vm->regs[RegMod].u64]->code; vm->regs[RegIp].u64 = findlabel("main"); Word *src, *dst; u64int sp; for(;;){ decodeinstr(code + vm->regs[RegIp].u64, &instr, nil, 0); vm->regs[RegIp].u64 += instr.len; switch(instr.opcode){ case Onop: break; case Oexit: exits(nil); break; case Ocall: sp = vm->regs[RegSp].u64; stackgrow(Reg_save); memcpy(vm->stack+sp, vm->regs, Reg_save * sizeof(*vm->regs)); vm->regs[RegIp].u64 = instr.args[0].u64; vm->regs[RegFp].u64 = vm->regs[RegSp].u64; break; case Oreturn: if(vm->regs[RegFp].u64 == 0) sysfatal("APL stack underflow"); sp = vm->regs[RegFp].u64 - Reg_save; memcpy(vm->regs, vm->stack + sp, Reg_save * sizeof(*vm->regs)); vm->regs[RegSp].u64 = sp; break; case Omov: src = getaddr(&instr.args[0]); dst = getaddr(&instr.args[1]); memcpy(dst, src, sizeof(Word)); break; case Olocals: stackgrow(instr.args[0].s64); break; case Oscalnum: case Odisplay: default: sysfatal("missing case in interpret: %s", optab[instr.opcode].name); } } } void main(int argc, char *argv[]) { char *objfile; ARGBEGIN{ default: usage(); }ARGEND; if(argc != 1) usage(); objfile = *argv; initvm(); loadmod(objfile); interpret(); }