void vm_exec(VM *vm, bool trace) { int a = 0; int i = 0; bool b1, b2; float f,g; char* c; PVector_ptr vptr,r,l; int x, y; Activation_Record *frame; Function_metadata *const main = vm_function(vm, "main"); vm_call(vm, main); // Define VM registers (C compiler probably ignores 'register' nowadays // but it's good documentation in this case. Keep as locals for // convenience but write them back to the vm object after each decode/execute. register addr32 ip = vm->ip; register int sp = vm->sp; register int fp = vm->fp; const byte *code = vm->code; element *stack = vm->stack; int opcode = code[ip]; while (opcode != HALT && ip < vm->code_size ) { if (trace) vm_print_instr(vm, ip); ip++; switch (opcode) { case IADD: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].i = x + y; break; case ISUB: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].i = x - y; break; case IMUL: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].i = x * y; break; case IDIV: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; if (y ==0 ) { zero_division_error(); break; } stack[sp].i = x / y; break; case FADD: validate_stack_address(sp-1); f = stack[sp--].f; g = stack[sp].f; stack[sp].f = g + f; break; case FSUB: validate_stack_address(sp-1); f = stack[sp--].f; g = stack[sp].f; stack[sp].f = g - f; break; case FMUL: validate_stack_address(sp-1); f = stack[sp--].f; g = stack[sp].f; stack[sp].f = g * f; break; case FDIV: validate_stack_address(sp-1); f = stack[sp--].f; g = stack[sp].f; if (f == 0) { zero_division_error(); break; } stack[sp].f = g / f; break; case VADD: validate_stack_address(sp-1); r = stack[sp--].vptr; l = stack[sp].vptr; vptr = Vector_add(l,r); stack[sp].vptr = vptr; break; case VADDI: validate_stack_address(sp-1); i = stack[sp--].i; vptr = stack[sp].vptr; vptr = Vector_add(vptr,Vector_from_int(i,vptr.vector->length)); stack[sp].vptr = vptr; break; case VADDF: validate_stack_address(sp-1); f = stack[sp--].f; vptr = stack[sp].vptr; vptr = Vector_add(vptr,Vector_from_float(f,vptr.vector->length)); stack[sp].vptr = vptr; break; case VSUB: validate_stack_address(sp-1); r = stack[sp--].vptr; l = stack[sp].vptr; vptr = Vector_sub(l,r); stack[sp].vptr = vptr; break; case VSUBI: validate_stack_address(sp-1); i = stack[sp--].i; vptr = stack[sp].vptr; vptr = Vector_sub(vptr,Vector_from_int(i,vptr.vector->length)); stack[sp].vptr = vptr; break; case VSUBF: validate_stack_address(sp-1); f = stack[sp--].f; vptr = stack[sp].vptr; vptr = Vector_sub(vptr,Vector_from_float(f,vptr.vector->length)); stack[sp].vptr = vptr; break; case VMUL: validate_stack_address(sp-1); r = stack[sp--].vptr; l = stack[sp].vptr; vptr = Vector_mul(l,r); stack[sp].vptr = vptr; break; case VMULI: validate_stack_address(sp-1); i = stack[sp--].i; vptr = stack[sp].vptr; vptr = Vector_mul(vptr,Vector_from_int(i,vptr.vector->length)); stack[sp].vptr = vptr; break; case VMULF: validate_stack_address(sp-1); f = stack[sp--].f; vptr = stack[sp].vptr; vptr = Vector_mul(vptr,Vector_from_float(f,vptr.vector->length)); stack[sp].vptr = vptr; break; case VDIV: validate_stack_address(sp-1); r = stack[sp--].vptr; l = stack[sp].vptr; vptr = Vector_div(l,r); stack[sp].vptr = vptr; break; case VDIVI: validate_stack_address(sp-1); i = stack[sp--].i; if (i == 0) { zero_division_error(); break; } vptr = stack[sp].vptr; vptr = Vector_div(vptr,Vector_from_int(i,vptr.vector->length)); stack[sp].vptr = vptr; break; case VDIVF: validate_stack_address(sp-1); f = stack[sp--].f; if (f == 0) { zero_division_error(); break; } vptr = stack[sp].vptr; vptr = Vector_div(vptr,Vector_from_float(f,vptr.vector->length)); stack[sp].vptr = vptr; break; case SADD: validate_stack_address(sp-1); char * right = stack[sp--].s; stack[sp].s = String_add(String_new(stack[sp].s),String_new(right))->str; break; case OR : validate_stack_address(sp-1); b2 = stack[sp--].b; b1 = stack[sp].b; stack[sp].b = b1 || b2; break; case AND : validate_stack_address(sp-1); b2 = stack[sp--].b; b1 = stack[sp].b; stack[sp].b = b1 && b2; break; case INEG: validate_stack_address(sp); stack[sp].i = -stack[sp].i; break; case FNEG: validate_stack_address(sp); stack[sp].f = -stack[sp].f; break; case NOT: validate_stack_address(sp); stack[sp].b = !stack[sp].b; break; case I2F: validate_stack_address(sp); stack[sp].f = stack[sp].i; break; case I2S: validate_stack_address(sp); stack[sp].s = String_from_int(stack[sp].i)->str; break; case F2I: validate_stack_address(sp); stack[sp].i = (int)stack[sp].f; break; case F2S: validate_stack_address(sp); stack[sp].s = String_from_float((float)stack[sp].f)->str; break; case V2S: validate_stack_address(sp); vptr = stack[sp].vptr; stack[sp].s = String_from_vector(vptr)->str; break; case IEQ: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x == y; break; case INEQ: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x != y; break; case ILT: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x < y; break; case ILE: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x <= y; break; case IGT: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x > y; break; case IGE: validate_stack_address(sp-1); y = stack[sp--].i; x = stack[sp].i; stack[sp].b = x >= y; break; case FEQ: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f == g; break; case FNEQ: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f != g; break; case FLT: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f < g; break; case FLE: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f <= g; break; case FGT: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f > g; break; case FGE: validate_stack_address(sp-1); g = stack[sp--].f; f = stack[sp].f; stack[sp].b = f >= g; break; case SEQ: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_eq(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case SNEQ: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_neq(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case SGT: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_gt(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case SGE: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_ge(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case SLT: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_lt(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case SLE: validate_stack_address(sp-1); c = stack[sp--].s; b1 = String_le(String_new(stack[sp--].s),String_new(c)); stack[++sp].b = b1; break; case VEQ: validate_stack_address(sp-1); l = stack[sp--].vptr; r = stack[sp--].vptr; b1 = Vector_eq(l,r); stack[++sp].b = b1; break; case VNEQ: validate_stack_address(sp-1); l = stack[sp--].vptr; r = stack[sp--].vptr; b1 = Vector_neq(l,r); stack[++sp].b = b1; break; case BR: ip += int16(code,ip) - 1; break; case BRF: validate_stack_address(sp); if ( !stack[sp--].b ) { int offset = int16(code,ip); ip += offset - 1; } else { ip += 2; } break; case ICONST: stack[++sp].i = int32(code,ip); ip += 4; break; case FCONST: stack[++sp].f = float32(code,ip); ip += 4; break; case SCONST : i = int16(code,ip); ip += 2; stack[++sp].s = vm->strings[i]; break; case ILOAD: i = int16(code,ip); ip += 2; stack[++sp].i = vm->call_stack[vm->callsp].locals[i].i; break; case FLOAD: i = int16(code,ip); ip += 2; stack[++sp].f = vm->call_stack[vm->callsp].locals[i].f; break; case VLOAD: i = int16(code,ip); ip += 2; stack[++sp].vptr = vm->call_stack[vm->callsp].locals[i].vptr; break; case SLOAD: i = int16(code,ip); ip += 2; stack[++sp].s = vm->call_stack[vm->callsp].locals[i].s; break; case STORE: i = int16(code,ip); ip += 2; vm->call_stack[vm->callsp].locals[i] = stack[sp--]; // untyped store; it'll just copy all bits break; case VECTOR: i = stack[sp--].i; validate_stack_address(sp-i+1); double *data = (double*)malloc(i*sizeof(double)); for (int j = i-1; j >= 0;j--) { data[j] = stack[sp--].f; } vptr = Vector_new(data,i); stack[++sp].vptr = vptr; break; case VLOAD_INDEX: i = stack[sp--].i; vptr = stack[sp--].vptr; vm->stack[++sp].f = ith(vptr, i-1); break; case STORE_INDEX: f = stack[sp--].f; i = stack[sp--].i; vptr = stack[sp--].vptr; set_ith(vptr, i-1, f); break; case SLOAD_INDEX: i = stack[sp--].i; if (i-1 >= strlen(stack[sp].s)) { fprintf(stderr, "StringIndexOutOfRange: %d\n",(int)strlen(stack[sp].s)); break; } c = String_from_char(stack[sp--].s[i-1])->str; stack[++sp].s = c; break; case PUSH_DFLT_RETV: i = *&vm->call_stack[vm->callsp].func->return_type; sp = push_default_value(i, sp, stack); break; case POP: sp--; break; case CALL: a = int16(code,ip); // load index of function from code memory WRITE_BACK_REGISTERS(vm); // (ip has been updated) vm_call(vm, &vm->functions[a]); LOAD_REGISTERS(vm); break; case RET: frame = &vm->call_stack[vm->callsp--]; ip = frame->retaddr; break; case IPRINT: validate_stack_address(sp); printf("%d\n", stack[sp--].i); break; case FPRINT: validate_stack_address(sp); printf("%1.2f\n", stack[sp--].f); break; case BPRINT: validate_stack_address(sp); printf("%d\n", stack[sp--].b); break; case SPRINT: validate_stack_address(sp); printf("%s\n", stack[sp--].s); break; case VPRINT: validate_stack_address(sp); print_vector(stack[sp--].vptr); break; case VLEN: vptr = stack[sp--].vptr; i = Vector_len(vptr); stack[++sp].i = i; break; case SLEN: c = stack[sp--].s; i = String_len(String_new(c)); stack[++sp].i = i; break; case GC_START: vm->call_stack[vm->callsp].save_gc_roots = gc_num_roots(); break; case GC_END: gc_set_num_roots(vm->call_stack[vm->callsp].save_gc_roots); break; case SROOT: gc_add_root((void **)&stack[sp].s); break; case VROOT: gc_add_root((void **)&stack[sp].vptr); break; case COPY_VECTOR: if (vm->call_stack[vm->callsp].locals[i].vptr.vector != NULL) { stack[sp].vptr = Vector_copy(vm->call_stack[vm->callsp].locals[i].vptr); } else if (stack[sp].vptr.vector != NULL) { stack[sp].vptr = Vector_copy(stack[sp].vptr); } else { fprintf(stderr, "Vector reference cannot be found\n"); } break; case NOP : break; default: printf("invalid opcode: %d at ip=%d\n", opcode, (ip - 1)); exit(1); } WRITE_BACK_REGISTERS(vm); if (trace) vm_print_stack(vm); opcode = code[ip]; } if (trace) vm_print_instr(vm, ip); if (trace) vm_print_stack(vm); gc_check(); }
void vm_exec(VM *vm, int startip, bool trace) { // registers int ip; // instruction pointer register int sp; // stack pointer register int callsp; // call stack pointer register int a = 0; int b = 0; int addr = 0; int offset = 0; ip = startip; sp = -1; callsp = -1; int opcode = vm->code[ip]; while (opcode != HALT && ip < vm->code_size) { if (trace) vm_print_instr(vm->code, ip); ip++; //jump to next instruction or to operand switch (opcode) { case IADD: b = vm->stack[sp--]; // 2nd opnd at top of stack a = vm->stack[sp--]; // 1st opnd 1 below top vm->stack[++sp] = a + b; // push result break; case ISUB: b = vm->stack[sp--]; a = vm->stack[sp--]; vm->stack[++sp] = a - b; break; case IMUL: b = vm->stack[sp--]; a = vm->stack[sp--]; vm->stack[++sp] = a * b; break; case ILT: b = vm->stack[sp--]; a = vm->stack[sp--]; vm->stack[++sp] = (a < b) ? true : false; break; case IEQ: b = vm->stack[sp--]; a = vm->stack[sp--]; vm->stack[++sp] = (a == b) ? true : false; break; case BR: ip = vm->code[ip]; break; case BRT: addr = vm->code[ip++]; if (vm->stack[sp--] == true) ip = addr; break; case BRF: addr = vm->code[ip++]; if (vm->stack[sp--] == false) ip = addr; break; case ICONST: vm->stack[++sp] = vm->code[ip++]; // push operand break; case LOAD: // load local or arg; 1st local is fp+1, args are fp-3, fp-4, fp-5, ... offset = vm->code[ip++]; vm->stack[++sp] = vm->call_stack[callsp].locals[offset]; break; case GLOAD: // load from global memory addr = vm->code[ip++]; vm->stack[++sp] = vm->globals[addr]; break; case STORE: offset = vm->code[ip++]; vm->call_stack[callsp].locals[offset] = vm->stack[sp--]; break; case GSTORE: addr = vm->code[ip++]; vm->globals[addr] = vm->stack[sp--]; break; case PRINT: printf("%d\n", vm->stack[sp--]); break; case POP: --sp; break; case CALL: // expects all args on stack addr = vm->code[ip++]; // index of target function int nargs = vm->code[ip++]; // how many args got pushed int nlocals = vm->code[ip++]; // how many locals to allocate ++callsp; // bump stack pointer to reveal space for this call vm_context_init(&vm->call_stack[callsp], ip, nargs+nlocals); // copy args into new context for (int i=0; i<nargs; i++) { vm->call_stack[callsp].locals[i] = vm->stack[sp-i]; } sp -= nargs; ip = addr; // jump to function break; case RET: ip = vm->call_stack[callsp].returnip; callsp--; // pop context break; default: printf("invalid opcode: %d at ip=%d\n", opcode, (ip - 1)); exit(1); } if (trace) vm_print_stack(vm->stack, sp); opcode = vm->code[ip]; } if (trace) vm_print_data(vm->globals, vm->nglobals); }