public VM(Chunk p_chunk) { IP = 0; parallelVM = false; main = p_chunk.MainFunctionUnit("main"); instructions = new InstructionStack(callStackSize, main, out instructionsCache); stack = new Stack(callStackSize); variables = new Memory <Unit>(); upValues = new Memory <UpValueUnit>(); registeredUpValues = new UpValueEnv(variables); data = p_chunk.GetData; Prelude = p_chunk.Prelude; globals = new Memory <Unit>(); Intrinsics = p_chunk.Prelude.intrinsics; foreach (IntrinsicUnit v in Intrinsics) { // lock(globals) // not needed because this vm initialization does not run in parallel globals.Add(new Unit(v)); } foreach (KeyValuePair <string, TableUnit> entry in p_chunk.Prelude.tables) { // lock(globals) // not needed because this vm initialization does not run in parallel globals.Add(new Unit(entry.Value)); } LoadedModules = new Dictionary <string, int>(); modules = new List <ModuleUnit>(); vmPool = new Stack <VM>(); }
public FunctionUnit MainFunctionUnit(string p_name) { FunctionUnit this_function_unit = new FunctionUnit(p_name, ModuleName); this_function_unit.Set(0, Body, ChunkPosition, 0); return(this_function_unit); }
public override bool Equals(object p_other) { Type other_type = p_other.GetType(); if (other_type == typeof(Unit)) { if (((Unit)p_other).Type == UnitType.Function) { FunctionUnit other_val_func = (FunctionUnit)((Unit)(p_other)).heapUnitValue; if (other_val_func.Name == this.Name && other_val_func.Module == this.Module) { return(true); } } } if (other_type == typeof(FunctionUnit)) { FunctionUnit other_val_func = p_other as FunctionUnit; if (other_val_func.Name == this.Name && other_val_func.Module == this.Module) { return(true); } } return(false); }
private VM( FunctionUnit p_main, List <Unit> p_data, Memory <Unit> p_globals, Library p_Prelude, Dictionary <string, int> p_LoadedModules, List <ModuleUnit> p_modules, Stack <VM> p_vmPool, bool p_parallelVM) { main = p_main; data = p_data; globals = p_globals; Prelude = p_Prelude; LoadedModules = p_LoadedModules; modules = p_modules; vmPool = p_vmPool; IP = 0; parallelVM = p_parallelVM; instructions = new InstructionStack(callStackSize, main, out instructionsCache); stack = new Stack(callStackSize); variables = new Memory <Unit>(); upValues = new Memory <UpValueUnit>(); registeredUpValues = new UpValueEnv(variables); }
public void PushFunction(FunctionUnit p_function, int p_env, out List <Instruction> p_instructionsCache) { currentInstructionsIndex++; funCallEnv[currentInstructionsIndex] = p_env; functions[currentInstructionsIndex] = p_function; p_instructionsCache = ExecutingInstructions; }
public Unit CallFunction(Unit p_callable, List <Unit> p_args = null) { UnitType this_type = p_callable.Type; if (p_args != null) { for (int i = p_args.Count - 1; i >= 0; i--) { stack.Push(p_args[i]); } } Operand before_call_IP = IP; if (this_type == UnitType.Function) { instructions.PushRET((Operand)(main.Body.Count - 1)); FunctionUnit this_func = (FunctionUnit)(p_callable.heapUnitValue); instructions.PushFunction(this_func, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Closure) { instructions.PushRET((Operand)(main.Body.Count - 1)); ClosureUnit this_closure = (ClosureUnit)(p_callable.heapUnitValue); upValues.PushEnv(); foreach (UpValueUnit u in this_closure.UpValues) { upValues.Add(u); } instructions.PushFunction(this_closure.Function, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Intrinsic) { IntrinsicUnit this_intrinsic = (IntrinsicUnit)(p_callable.heapUnitValue); Unit intrinsic_result = this_intrinsic.Function(this); stack.top -= this_intrinsic.Arity; return(intrinsic_result); } VMResult result = Run(); IP = before_call_IP; if (result.status == VMResultType.OK) { return(result.value); } return(new Unit(UnitType.Null)); }
public InstructionStack(int p_callStackSize, FunctionUnit p_main, out List <Instruction> p_instructionsCache) { functions = new FunctionUnit[p_callStackSize]; returnAddress = new Operand[2 * p_callStackSize]; funCallEnv = new int[p_callStackSize]; returnAddressTop = 0; currentInstructionsIndex = 0; PushRET((Operand)(p_main.Body.Count - 1)); functions[currentInstructionsIndex] = p_main; p_instructionsCache = ExecutingInstructions; }
private VMResult Run() { Instruction instruction; while (true) { instruction = instructionsCache[IP]; switch (instruction.opCode) { case OpCode.POP: IP++; stack.Pop(); break; case OpCode.DUP: IP++; stack.Push(stack.Peek()); break; case OpCode.LOAD_DATA: IP++; stack.Push(data[instruction.opA]); break; case OpCode.LOAD_VARIABLE: IP++; stack.Push(variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB))); break; case OpCode.LOAD_GLOBAL: IP++; if (parallelVM == true) { lock (globals.Get(instruction.opA).heapUnitValue) // needed because global may be loaded from parallel functions stack.Push(globals.Get(instruction.opA)); } else { stack.Push(globals.Get(instruction.opA)); } break; case OpCode.LOAD_IMPORTED_GLOBAL: IP++; stack.Push(modules[instruction.opB].GetGlobal(instruction.opA)); break; case OpCode.LOAD_IMPORTED_DATA: IP++; stack.Push(modules[instruction.opB].GetData(instruction.opA)); break; case OpCode.LOAD_UPVALUE: IP++; if (parallelVM == true) { lock (upValues.GetAt(instruction.opA)) // needed because upvalue may be loaded from parallel functions stack.Push(upValues.GetAt(instruction.opA).UpValue); } else { stack.Push(upValues.GetAt(instruction.opA).UpValue); } break; case OpCode.LOAD_NIL: IP++; stack.Push(new Unit(UnitType.Null)); break; case OpCode.LOAD_TRUE: IP++; stack.Push(new Unit(true)); break; case OpCode.LOAD_FALSE: IP++; stack.Push(new Unit(false)); break; case OpCode.LOAD_INTRINSIC: IP++; stack.Push(new Unit(Intrinsics[instruction.opA])); break; case OpCode.DECLARE_VARIABLE: IP++; variables.Add(stack.Pop()); break; case OpCode.DECLARE_GLOBAL: IP++; // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(stack.Pop()); break; case OpCode.DECLARE_FUNCTION: { IP++; Operand env = instruction.opA; Operand is_function_expression = instruction.opB; Operand new_fun_address = instruction.opC; Unit this_callable = data[new_fun_address]; if (this_callable.Type == UnitType.Function) { if (is_function_expression == 0) { if (env == 0) // Global { // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(this_callable); } else { variables.Add(this_callable); } } else { stack.Push(this_callable); } } else { ClosureUnit this_closure = (ClosureUnit)(this_callable.heapUnitValue); // new upvalues List <UpValueUnit> new_upValues = new List <UpValueUnit>(); foreach (UpValueUnit u in this_closure.UpValues) { // here we convert env from shift based to absolute based UpValueUnit new_upvalue = registeredUpValues.Get(u.Address, CalculateEnvShiftUpVal(u.Env)); new_upValues.Add(new_upvalue); } ClosureUnit new_closure = new ClosureUnit(this_closure.Function, new_upValues); Unit new_closure_unit = new Unit(new_closure); if (is_function_expression == 0) { if (env == 0) // yes they exist! { // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(new_closure_unit); } else { variables.Add(new_closure_unit); } } else { stack.Push(new_closure_unit); } } break; } case OpCode.ASSIGN_VARIABLE: { IP++; Unit old_value = variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB)); Unit result; switch (instruction.opC) { case ASSIGN: variables.SetAt(stack.Peek(), instruction.opA, CalculateEnvShift(instruction.opB)); break; case ADDITION_ASSIGN: result = old_value + stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case SUBTRACTION_ASSIGN: result = old_value - stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case MULTIPLICATION_ASSIGN: result = old_value * stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case DIVISION_ASSIGN: result = old_value / stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; default: throw new Exception("Unknown operator"); } break; } case OpCode.ASSIGN_GLOBAL: { IP++; Operand address = instruction.opA; Operand op = instruction.opB; Unit new_value = stack.Peek(); if (parallelVM == true) { switch (op) { case ASSIGN: lock (globals.Get(address).heapUnitValue) globals.Set(new_value, address); break; case ADDITION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) + new_value; globals.Set(result, address); } break; case SUBTRACTION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) - new_value; globals.Set(result, address); } break; case MULTIPLICATION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) * new_value; globals.Set(result, address); } break; case DIVISION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) / new_value; globals.Set(result, address); } break; default: throw new Exception("Unknown operator"); } } else { Unit result; switch (op) { case ASSIGN: globals.Set(new_value, address); break; case ADDITION_ASSIGN: result = globals.Get(address) + new_value; globals.Set(result, address); break; case SUBTRACTION_ASSIGN: result = globals.Get(address) - new_value; globals.Set(result, address); break; case MULTIPLICATION_ASSIGN: result = globals.Get(address) * new_value; globals.Set(result, address); break; case DIVISION_ASSIGN: result = globals.Get(address) / new_value; globals.Set(result, address); break; default: throw new Exception("Unknown operator"); } } break; } case OpCode.ASSIGN_IMPORTED_GLOBAL: IP++; modules[instruction.opB].SetOpGlobal(stack.Peek(), instruction.opC, instruction.opA); break; case OpCode.ASSIGN_UPVALUE: IP++; if (parallelVM == true) { UpValueUnit this_upValue; this_upValue = upValues.GetAt(instruction.opA); switch (instruction.opB) { case ASSIGN: lock (this_upValue) this_upValue.UpValue = stack.Peek(); break; case ADDITION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue + stack.Peek(); break; case SUBTRACTION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue - stack.Peek(); break; case MULTIPLICATION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue *stack.Peek(); break; case DIVISION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue / stack.Peek(); break; default: throw new Exception("Unknown operator"); } } else { UpValueUnit this_upValue = upValues.GetAt(instruction.opA); switch (instruction.opB) { case ASSIGN: this_upValue.UpValue = stack.Peek(); break; case ADDITION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue + stack.Peek(); break; case SUBTRACTION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue - stack.Peek(); break; case MULTIPLICATION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue * stack.Peek(); break; case DIVISION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue / stack.Peek(); break; default: throw new Exception("Unknown operator"); } } break; case OpCode.GET: { IP++; Operand indexes_counter = instruction.opA; Unit[] indexes = new Unit[indexes_counter]; for (int i = indexes_counter - 1; i >= 0; i--) { indexes[i] = stack.Pop(); } Unit value = stack.Pop(); foreach (Unit v in indexes) { value = (value.heapUnitValue).Get(v); } stack.Push(value); break; } case OpCode.SET: { IP++; Operand indexes_counter = instruction.opA; Operand op = instruction.opB; Unit[] indexes = new Unit[indexes_counter]; for (int i = indexes_counter - 1; i >= 0; i--) { indexes[i] = stack.Pop(); } Unit this_table = stack.Pop(); for (int i = 0; i < indexes_counter - 1; i++) { Unit v = indexes[i]; this_table = (this_table.heapUnitValue).Get(v); } Unit new_value = stack.Peek(); Unit index = indexes[indexes_counter - 1]; UnitType index_type = indexes[indexes_counter - 1].Type; if (op == ASSIGN) { ((this_table.heapUnitValue)).Set(index, new_value); } else if (parallelVM == true) { Unit old_value; Unit result; switch (op) { case ADDITION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value + new_value; (this_table.heapUnitValue).Set(index, result); } break; case SUBTRACTION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value - new_value; (this_table.heapUnitValue).Set(index, result); } break; case MULTIPLICATION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value * new_value; (this_table.heapUnitValue).Set(index, result); } break; case DIVISION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value / new_value; (this_table.heapUnitValue).Set(index, result); } break; default: throw new Exception("Unknown operator"); } } else { Unit old_value = (this_table.heapUnitValue).Get(index); Unit result; switch (op) { case ADDITION_ASSIGN: result = old_value + new_value; break; case SUBTRACTION_ASSIGN: result = old_value - new_value; break; case MULTIPLICATION_ASSIGN: result = old_value * new_value; break; case DIVISION_ASSIGN: result = old_value / new_value; break; default: throw new Exception("Unknown operator"); } (this_table.heapUnitValue).Set(index, result); } break; } case OpCode.JUMP: IP += instruction.opA; break; case OpCode.JUMP_IF_NOT_TRUE: if (stack.Pop().ToBool() == false) { IP += instruction.opA; } else { IP++; } break; case OpCode.JUMP_BACK: IP -= instruction.opA; break; case OpCode.OPEN_ENV: IP++; EnvPush(); break; case OpCode.CLOSE_ENV: IP++; EnvPop(); break; case OpCode.RETURN: IP = instructions.PopRET(); break; case OpCode.RETURN_SET: instructions.PushRET((Operand)(instruction.opA + IP)); IP++; break; case OpCode.ADD: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() + opB); break; } case OpCode.APPEND: { IP++; Unit opB = stack.Pop(); string result = stack.Pop().ToString() + opB.ToString(); stack.Push(new Unit(result)); break; } case OpCode.SUBTRACT: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() - opB); break; } case OpCode.MULTIPLY: IP++; stack.Push(stack.Pop() * stack.Pop()); break; case OpCode.DIVIDE: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() / opB); break; } case OpCode.NEGATE: IP++; stack.Push(-stack.Pop()); break; case OpCode.INCREMENT: IP++; stack.Push(stack.Pop() + 1); break; case OpCode.DECREMENT: IP++; stack.Push(stack.Pop() - 1); break; case OpCode.EQUALS: IP++; stack.Push(new Unit(stack.Pop().Equals(stack.Pop()))); break; case OpCode.NOT_EQUALS: IP++; stack.Push(new Unit(!stack.Pop().Equals(stack.Pop()))); break; case OpCode.GREATER_EQUALS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue <= stack.Pop().floatValue)); break; case OpCode.LESS_EQUALS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue >= stack.Pop().floatValue)); break; case OpCode.GREATER: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue < stack.Pop().floatValue)); break; case OpCode.LESS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue > stack.Pop().floatValue)); break; case OpCode.NOT: IP++; stack.Push(new Unit(!stack.Pop().ToBool())); break; case OpCode.AND: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() && opB.ToBool())); break; } case OpCode.OR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() || opB.ToBool())); break; } case OpCode.XOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() ^ opB.ToBool())); break; } case OpCode.NAND: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() && opB.ToBool()))); break; } case OpCode.NOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() || opB.ToBool()))); break; } case OpCode.XNOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() ^ opB.ToBool()))); break; } case OpCode.CLOSE_CLOSURE: upValues.PopEnv(); EnvSet(instructions.TargetEnv); IP = instructions.PopFunction(out instructionsCache); break; case OpCode.CLOSE_FUNCTION: EnvSet(instructions.TargetEnv); IP = instructions.PopFunction(out instructionsCache); break; case OpCode.NEW_TABLE: { IP++; TableUnit new_table = new TableUnit(null); int n_table = instruction.opA; for (int i = 0; i < n_table; i++) { Unit val = stack.Pop(); Unit key = stack.Pop(); new_table.Map.Add(key, val); } stack.Push(new Unit(new_table)); break; } case OpCode.NEW_LIST: { IP++; ListUnit new_list = new ListUnit(null); int n_table = instruction.opA; for (int i = 0; i < n_table; i++) { Unit val = stack.Pop(); new_list.Elements.Add(val); } stack.Push(new Unit(new_list)); break; } case OpCode.CALL: { IP++; Unit this_callable = stack.Pop(); UnitType this_type = this_callable.Type; if (this_type == UnitType.Function) { FunctionUnit this_func = (FunctionUnit)this_callable.heapUnitValue; instructions.PushRET(IP); instructions.PushFunction(this_func, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Closure) { ClosureUnit this_closure = (ClosureUnit)this_callable.heapUnitValue; upValues.PushEnv(); foreach (UpValueUnit u in this_closure.UpValues) { upValues.Add(u); } instructions.PushRET(IP); instructions.PushFunction(this_closure.Function, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Intrinsic) { IntrinsicUnit this_intrinsic = (IntrinsicUnit)this_callable.heapUnitValue; Unit result = this_intrinsic.Function(this); stack.top -= this_intrinsic.Arity; stack.Push(result); } else { Error("Trying to call a " + this_callable.Type); return(new VMResult(VMResultType.OK, new Unit(UnitType.Null))); } break; } case OpCode.PUSH_STASH: IP++; stack.PushStash(); break; case OpCode.POP_STASH: IP++; stack.PopStash(); break; case OpCode.EXIT: if (stack.top > 0) { return(new VMResult(VMResultType.OK, stack.Pop())); } return(new VMResult(VMResultType.OK, new Unit(UnitType.Null))); default: Error("Unkown OpCode: " + instruction.opCode); return(new VMResult(VMResultType.ERROR, new Unit(UnitType.Null))); } } }
public ClosureUnit(FunctionUnit p_Function, List <UpValueUnit> p_UpValues) { Function = p_Function; UpValues = p_UpValues; }
private void CompileFunction(string p_name, FunctionExpressionNode p_node, bool p_isGlobal) { FunctionUnit new_function = new FunctionUnit(p_name, moduleName); Operand this_address = (Operand)AddData(new_function); if (p_node.Type != NodeType.FUNCTION_DECLARATION) { Add(OpCode.DECLARE_FUNCTION, 0, 1, this_address, p_node.PositionData); } else { if (p_isGlobal) { Add(OpCode.DECLARE_FUNCTION, 0, 0, this_address, p_node.PositionData);// zero for gloabal } else { Add(OpCode.DECLARE_FUNCTION, 1, 0, this_address, p_node.PositionData);// one for current env } } // body int function_start = instructionCounter; // env env.Add(new List <string>()); Add(OpCode.OPEN_ENV, p_node.PositionData); //Add funStartEnv funStartEnv.Push(env.Count - 1); int exit_instruction_address = instructionCounter; Add(OpCode.RETURN_SET, 0, p_node.PositionData); Operand arity = 0; if (p_node.Parameters != null) { foreach (string p in p_node.Parameters) { SetVar(p);// it is always local Add(OpCode.DECLARE_VARIABLE, p_node.PositionData); arity++; } } upvalueStack.Push(new List <Variable>()); foreach (Node n in p_node.Body) { ChunkIt(n); } bool is_closure = false; if (upvalueStack.Peek().Count != 0) { is_closure = true; List <Variable> this_variables = upvalueStack.Pop(); List <UpValueUnit> new_upvalues = new List <UpValueUnit>(); foreach (Variable v in this_variables) { new_upvalues.Add(new UpValueUnit((Operand)v.address, (Operand)v.envIndex)); } ClosureUnit new_closure = new ClosureUnit(new_function, new_upvalues); chunk.SwapDataLiteral(this_address, new Unit(new_closure)); } else { upvalueStack.Pop(); } // fix the exit address chunk.FixInstruction(exit_instruction_address, null, (Operand)(instructionCounter - exit_instruction_address), null, null); if (is_closure == true) { Add(OpCode.CLOSE_CLOSURE, p_node.PositionData); } else { Add(OpCode.CLOSE_FUNCTION, p_node.PositionData); } new_function.Set( arity, chunk.Slice(function_start, instructionCounter), chunk.ChunkPosition.Slice(function_start, instructionCounter), (Operand)function_start); instructionCounter = function_start; //Console.WriteLine("Removed env"); env.RemoveAt(env.Count - 1); //pop fun start env funStartEnv.Pop(); }
private int AddData(FunctionUnit p_function) { dataLiterals.Add(p_function); chunk.AddData(new Unit(p_function)); return(dataLiterals.Count - 1); }