Пример #1
0
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();
}
Пример #2
0
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);
}