// instructionPointer is the location to jump after the frame is popped! internal void PushFrame(ExecutionContext context, uint instructionPointer, int registerCount) { var frame = new ExecutionFrame(this, instructionPointer, context, registerCount); frames.Push(frame); this.CurrentFrame = frame; }
public override ExecutionState Execute(ExecutionFrame frame, Stack <VMObject> stack) { while (_state == ExecutionState.Running) { this.Step(frame, stack); } return(_state); }
internal uint PopFrame() { Throw.If(frames.Count < 2, "Not enough frames available"); frames.Pop(); var instructionPointer = CurrentFrame.Offset; this.CurrentFrame = frames.Peek(); this.CurrentContext = CurrentFrame.Context; return(instructionPointer); }
public uint PopFrame() { Throw.If(frames.Count < 2, "Not enough frames available"); var oldFrame = frames.Pop(); var instructionPointer = CurrentFrame.Offset; this.CurrentFrame = frames.Peek(); SetCurrentContext(CurrentFrame.Context); return(instructionPointer); }
public void Step(ExecutionFrame frame, Stack <VMObject> stack) { try { var opcode = (Opcode)Read8(); frame.VM.ValidateOpcode(opcode); switch (opcode) { case Opcode.NOP: { break; } // args: byte src_reg, byte dest_reg case Opcode.MOVE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); frame.Registers[dst] = frame.Registers[src]; break; } // args: byte src_reg, byte dest_reg case Opcode.COPY: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); frame.Registers[dst].Copy(frame.Registers[src]); break; } // args: byte dst_reg, byte type, var length, var data_bytes case Opcode.LOAD: { var dst = Read8(); var type = (VMType)Read8(); var len = (int)ReadVar(0xFFFF); Expect(dst < frame.Registers.Length); var bytes = ReadBytes(len); frame.Registers[dst].SetValue(bytes, type); break; } // args: byte src_reg, dst_reg, byte type case Opcode.CAST: { var src = Read8(); var dst = Read8(); var type = (VMType)Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src]; val = VMObject.CastTo(val, type); frame.Registers[dst] = val; break; } // args: byte src_reg case Opcode.PUSH: { var src = Read8(); Expect(src < frame.Registers.Length); var val = frame.Registers[src]; var temp = new VMObject(); temp.Copy(val); stack.Push(temp); break; } // args: byte dest_reg case Opcode.POP: { var dst = Read8(); Expect(stack.Count > 0); Expect(dst < frame.Registers.Length); frame.Registers[dst] = stack.Pop(); break; } // args: byte src_reg, byte dest_reg case Opcode.SWAP: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var temp = frame.Registers[src]; frame.Registers[src] = frame.Registers[dst]; frame.Registers[dst] = temp; break; } // args: ushort offset, byte regCount case Opcode.CALL: { var count = Read8(); var ofs = Read16(); Expect(ofs < this.Script.Length); Expect(count >= 1); Expect(count <= VirtualMachine.MaxRegisterCount); frame.VM.PushFrame(this, InstructionPointer, count); InstructionPointer = ofs; break; } // args: byte srcReg case Opcode.EXTCALL: using (var m = new ProfileMarker("EXTCALL")) { var src = Read8(); Expect(src < frame.Registers.Length); var method = frame.Registers[src].AsString(); var state = frame.VM.ExecuteInterop(method); if (state != ExecutionState.Running) { throw new VMException(frame.VM, "VM extcall failed: " + method); } break; } // args: ushort offset, byte src_reg // NOTE: JMP only has offset arg, not the rest case Opcode.JMP: case Opcode.JMPIF: case Opcode.JMPNOT: { bool shouldJump; if (opcode == Opcode.JMP) { shouldJump = true; } else { var src = Read8(); Expect(src < frame.Registers.Length); shouldJump = frame.Registers[src].AsBool(); if (opcode == Opcode.JMPNOT) { shouldJump = !shouldJump; } } var newPos = (short)Read16(); Expect(newPos >= 0); Expect(newPos < this.Script.Length); if (shouldJump) { InstructionPointer = (uint)newPos; } break; } // args: var length, var bytes case Opcode.THROW: { var len = (int)ReadVar(1024); if (len > 0) { var bytes = ReadBytes(len); } SetState(ExecutionState.Fault); return; } // args: none case Opcode.RET: { if (frame.VM.frames.Count > 1) { var temp = frame.VM.PeekFrame(); if (temp.Context == this) { InstructionPointer = frame.VM.PopFrame(); //Expect(InstructionPointer == this.Script.Length); } else { SetState(ExecutionState.Halt); } } else { SetState(ExecutionState.Halt); } return; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.CAT: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length); Expect(srcB < frame.Registers.Length); Expect(dst < frame.Registers.Length); var A = frame.Registers[srcA]; var B = frame.Registers[srcB]; if (!A.IsEmpty) { if (B.IsEmpty) { frame.Registers[dst].Copy(A); } else { var bytesA = A.AsByteArray(); var bytesB = B.AsByteArray(); var result = new byte[bytesA.Length + bytesB.Length]; Array.Copy(bytesA, result, bytesA.Length); Array.Copy(bytesB, 0, result, bytesA.Length, bytesB.Length); Expect(A.Type == B.Type); VMType type = A.Type; frame.Registers[dst].SetValue(result, type); } } else { if (B.IsEmpty) { frame.Registers[dst] = new VMObject(); } else { frame.Registers[dst].Copy(B); } } break; } case Opcode.SUBSTR: { throw new NotImplementedException(); } // args: byte src_reg, byte dest_reg, var length case Opcode.LEFT: { var src = Read8(); var dst = Read8(); var len = (int)ReadVar(0xFFFF); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var src_array = frame.Registers[src].AsByteArray(); Expect(len <= src_array.Length); var result = new byte[len]; Array.Copy(src_array, result, len); frame.Registers[dst].SetValue(result, VMType.Bytes); break; } // args: byte src_reg, byte dest_reg, byte length case Opcode.RIGHT: { var src = Read8(); var dst = Read8(); var len = (int)ReadVar(0xFFFF); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var src_array = frame.Registers[src].AsByteArray(); Expect(len <= src_array.Length); var ofs = src_array.Length - len; var result = new byte[len]; Array.Copy(src_array, ofs, result, 0, len); frame.Registers[dst].SetValue(result, VMType.Bytes); break; } // args: byte src_reg, byte dest_reg case Opcode.SIZE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var src_array = frame.Registers[src].AsByteArray(); frame.Registers[dst].SetValue(src_array.Length); break; } // args: byte src_reg, byte dest_reg case Opcode.COUNT: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src]; int count; switch (val.Type) { case VMType.Struct: { var children = val.GetChildren(); count = children.Count; break; } default: count = 1; break; } frame.Registers[dst].SetValue(count); break; } // args: byte src_reg, byte dest_reg case Opcode.NOT: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src].AsBool(); frame.Registers[dst].SetValue(!val); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.AND: case Opcode.OR: case Opcode.XOR: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length); Expect(srcB < frame.Registers.Length); Expect(dst < frame.Registers.Length); var a = frame.Registers[srcA].AsBool(); var b = frame.Registers[srcB].AsBool(); bool result; switch (opcode) { case Opcode.AND: result = (a && b); break; case Opcode.OR: result = (a || b); break; case Opcode.XOR: result = (a ^ b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.EQUAL: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length); Expect(srcB < frame.Registers.Length); Expect(dst < frame.Registers.Length); var a = frame.Registers[srcA]; var b = frame.Registers[srcB]; var result = a.Equals(b); frame.Registers[dst].SetValue(result); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.LT: case Opcode.GT: case Opcode.LTE: case Opcode.GTE: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length); Expect(srcB < frame.Registers.Length); Expect(dst < frame.Registers.Length); var a = frame.Registers[srcA].AsNumber(); var b = frame.Registers[srcB].AsNumber(); bool result; switch (opcode) { case Opcode.LT: result = (a < b); break; case Opcode.GT: result = (a > b); break; case Opcode.LTE: result = (a <= b); break; case Opcode.GTE: result = (a >= b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } // args: byte reg case Opcode.INC: { var dst = Read8(); Expect(dst < frame.Registers.Length); var val = frame.Registers[dst].AsNumber(); frame.Registers[dst].SetValue(val + 1); break; } // args: byte reg case Opcode.DEC: { var dst = Read8(); Expect(dst < frame.Registers.Length); var val = frame.Registers[dst].AsNumber(); frame.Registers[dst].SetValue(val - 1); break; } // args: byte src_reg, byte dest_reg case Opcode.SIGN: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src].AsNumber(); if (val == 0) { frame.Registers[dst].SetValue(BigInteger.Zero); } else { frame.Registers[dst].SetValue(val < 0 ? -1 : 1); } break; } // args: byte src_reg, byte dest_reg case Opcode.NEGATE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src].AsNumber(); frame.Registers[dst].SetValue(-val); break; } // args: byte src_reg, byte dest_reg case Opcode.ABS: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var val = frame.Registers[src].AsNumber(); frame.Registers[dst].SetValue(val < 0 ? -val : val); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.ADD: case Opcode.SUB: case Opcode.MUL: case Opcode.DIV: case Opcode.MOD: case Opcode.SHR: case Opcode.SHL: case Opcode.MIN: case Opcode.MAX: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length); Expect(srcB < frame.Registers.Length); Expect(dst < frame.Registers.Length); var a = frame.Registers[srcA].AsNumber(); var b = frame.Registers[srcB].AsNumber(); BigInteger result; switch (opcode) { case Opcode.ADD: result = a + b; break; case Opcode.SUB: result = a - b; break; case Opcode.MUL: result = a * b; break; case Opcode.DIV: result = a / b; break; case Opcode.MOD: result = a % b; break; case Opcode.SHR: result = a >> (int)b; break; case Opcode.SHL: result = a << (int)b; break; case Opcode.MIN: result = a < b ? a : b; break; case Opcode.MAX: result = a > b ? a : b; break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } // args: byte src_reg, byte dest_reg, byte key case Opcode.PUT: { var src = Read8(); var dst = Read8(); var keyReg = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); Expect(keyReg < frame.Registers.Length); var key = frame.Registers[keyReg]; var value = frame.Registers[src]; frame.Registers[dst].SetKey(key, value); break; } // args: byte src_reg, byte dest_reg, byte key case Opcode.GET: { var src = Read8(); var dst = Read8(); var keyReg = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); Expect(keyReg < frame.Registers.Length); var key = frame.Registers[keyReg]; var val = frame.Registers[src].GetKey(key); frame.Registers[dst] = val; break; } // args: byte dest_reg case Opcode.THIS: { var dst = Read8(); Expect(dst < frame.Registers.Length); frame.Registers[dst].SetValue(this); break; } // args: byte dest_reg, var key case Opcode.CTX: using (var m = new ProfileMarker("CTX")) { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length); Expect(dst < frame.Registers.Length); var contextName = frame.Registers[src].AsString(); ExecutionContext context = frame.VM.FindContext(contextName); if (context == null) { throw new VMException(frame.VM, $"VM ctx instruction failed: could not find context with name '{contextName}'"); } frame.Registers[dst].SetValue(context); break; } // args: byte src_reg case Opcode.SWITCH: using (var m = new ProfileMarker("SWITCH")) { var src = Read8(); Expect(src < frame.Registers.Length); var context = frame.Registers[src].AsInterop <ExecutionContext>(); _state = frame.VM.SwitchContext(context, InstructionPointer); if (_state == ExecutionState.Halt) { _state = ExecutionState.Running; frame.VM.PopFrame(); } else { throw new VMException(frame.VM, $"VM switch instruction failed: execution state did not halt"); } break; } default: { throw new VMException(frame.VM, $"Unknown VM opcode: {(int)opcode}"); } } } catch (Exception ex) { if (ex is TargetInvocationException) { ex = ((TargetInvocationException)ex).InnerException; } Trace.WriteLine(ex.ToString()); SetState(ExecutionState.Fault); if (!(ex is VMException)) { ex = new VMException(frame.VM, ex.Message); } if (frame.VM.ThrowOnFault) // enable this when debugging difficult stuff in the VM, should not be activated for production code { throw ex; } } }
public void Step(ref ExecutionFrame frame, Stack <VMObject> stack) { try { opcode = (Opcode)Read8(); frame.VM.ValidateOpcode(opcode); switch (opcode) { case Opcode.NOP: { break; } // args: byte src_reg, byte dest_reg case Opcode.MOVE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); frame.Registers[dst] = frame.Registers[src]; frame.Registers[src] = new VMObject(); break; } // args: byte src_reg, byte dest_reg case Opcode.COPY: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); frame.Registers[dst].Copy(frame.Registers[src]); break; } // args: byte dst_reg, byte type, var length, var data_bytes case Opcode.LOAD: { var dst = Read8(); var type = (VMType)Read8(); var len = (int)ReadVar(0xFFFF); Expect(dst < frame.Registers.Length, "invalid dst register"); var bytes = ReadBytes(len); frame.Registers[dst].SetValue(bytes, type); break; } // args: byte src_reg, dst_reg, byte type case Opcode.CAST: { var src = Read8(); var dst = Read8(); var type = (VMType)Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src]; val = VMObject.CastTo(val, type); frame.Registers[dst] = val; break; } // args: byte src_reg case Opcode.PUSH: { var src = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); var val = frame.Registers[src]; var temp = new VMObject(); temp.Copy(val); stack.Push(temp); break; } // args: byte dest_reg case Opcode.POP: { var dst = Read8(); Expect(stack.Count > 0, "stack is empty"); Expect(dst < frame.Registers.Length, "invalid dst register"); frame.Registers[dst] = stack.Pop(); break; } // args: byte src_reg, byte dest_reg case Opcode.SWAP: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var temp = frame.Registers[src]; frame.Registers[src] = frame.Registers[dst]; frame.Registers[dst] = temp; break; } // args: ushort offset, byte regCount case Opcode.CALL: { var count = Read8(); var ofs = Read16(); Expect(ofs < this.Script.Length, "invalid jump offset"); Expect(count >= 1, "at least 1 register required"); Expect(count <= VirtualMachine.MaxRegisterCount, "invalid register allocs"); frame.VM.PushFrame(this, InstructionPointer, count); frame = frame.VM.CurrentFrame; InstructionPointer = ofs; break; } // args: byte srcReg case Opcode.EXTCALL: using (var m = new ProfileMarker("EXTCALL")) { var src = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); var method = frame.Registers[src].AsString(); var state = frame.VM.ExecuteInterop(method); if (state != ExecutionState.Running) { throw new VMException(frame.VM, "VM extcall failed: " + method); } break; } // args: ushort offset, byte src_reg // NOTE: JMP only has offset arg, not the rest case Opcode.JMP: case Opcode.JMPIF: case Opcode.JMPNOT: { bool shouldJump; if (opcode == Opcode.JMP) { shouldJump = true; } else { var src = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); shouldJump = frame.Registers[src].AsBool(); if (opcode == Opcode.JMPNOT) { shouldJump = !shouldJump; } } var newPos = (short)Read16(); Expect(newPos >= 0, "jump offset can't be negative value"); Expect(newPos < this.Script.Length, "trying to jump outside of script bounds"); if (shouldJump) { InstructionPointer = (uint)newPos; } break; } // args: var length, var bytes case Opcode.THROW: { var src = Read8(); Expect(src < frame.Registers.Length, "invalid exception register"); var exception = frame.Registers[src]; var exceptionMessage = exception.AsString(); throw new VMException(frame.VM, exceptionMessage); } // args: none case Opcode.RET: { if (frame.VM.frames.Count > 1) { var temp = frame.VM.PeekFrame(); if (temp.Context.Name == this.Name) { InstructionPointer = frame.VM.PopFrame(); frame = frame.VM.CurrentFrame; } else { SetState(ExecutionState.Halt); } } else { SetState(ExecutionState.Halt); } return; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.CAT: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length, "invalid srcA register"); Expect(srcB < frame.Registers.Length, "invalid srcB register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var A = frame.Registers[srcA]; var B = frame.Registers[srcB]; if (!A.IsEmpty) { if (B.IsEmpty) { frame.Registers[dst].Copy(A); } else { if (A.Type != B.Type) { throw new VMException(frame.VM, "Invalid cast during concat opcode"); } var bytesA = A.AsByteArray(); var bytesB = B.AsByteArray(); var result = new byte[bytesA.Length + bytesB.Length]; Array.Copy(bytesA, result, bytesA.Length); Array.Copy(bytesB, 0, result, bytesA.Length, bytesB.Length); VMType type = A.Type; frame.Registers[dst].SetValue(result, type); } } else { if (B.IsEmpty) { frame.Registers[dst] = new VMObject(); } else { frame.Registers[dst].Copy(B); } } break; } case Opcode.SUBSTR: { throw new NotImplementedException(); } // args: byte src_reg, byte dest_reg, var length case Opcode.LEFT: { var src = Read8(); var dst = Read8(); var len = (int)ReadVar(0xFFFF); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var src_array = frame.Registers[src].AsByteArray(); Expect(len <= src_array.Length, "invalid length"); var result = new byte[len]; Array.Copy(src_array, result, len); frame.Registers[dst].SetValue(result, VMType.Bytes); break; } // args: byte src_reg, byte dest_reg, byte length case Opcode.RIGHT: { var src = Read8(); var dst = Read8(); var len = (int)ReadVar(0xFFFF); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var src_array = frame.Registers[src].AsByteArray(); Expect(len <= src_array.Length, "invalid length register"); var ofs = src_array.Length - len; var result = new byte[len]; Array.Copy(src_array, ofs, result, 0, len); frame.Registers[dst].SetValue(result, VMType.Bytes); break; } // args: byte src_reg, byte dest_reg case Opcode.SIZE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); int size; var src_val = frame.Registers[src]; switch (src_val.Type) { case VMType.String: size = src_val.AsString().Length; break; case VMType.Timestamp: case VMType.Number: case VMType.Enum: case VMType.Bool: size = 1; break; case VMType.None: size = 0; break; default: var src_array = src_val.AsByteArray(); size = src_array.Length; break; } frame.Registers[dst].SetValue(size); break; } // args: byte src_reg, byte dest_reg case Opcode.COUNT: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src]; int count; switch (val.Type) { case VMType.Struct: { var children = val.GetChildren(); count = children.Count; break; } default: count = 1; break; } frame.Registers[dst].SetValue(count); break; } // args: byte src_reg, byte dest_reg case Opcode.NOT: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src].AsBool(); frame.Registers[dst].SetValue(!val); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.AND: case Opcode.OR: case Opcode.XOR: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length, "invalid srcA register"); Expect(srcB < frame.Registers.Length, "invalid srcB register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var valA = frame.Registers[srcA]; var valB = frame.Registers[srcB]; switch (valA.Type) { case VMType.Bool: { Expect(valB.Type == VMType.Bool, $"expected {valA.Type} for logical op"); var a = valA.AsBool(); var b = valB.AsBool(); bool result; switch (opcode) { case Opcode.AND: result = (a && b); break; case Opcode.OR: result = (a || b); break; case Opcode.XOR: result = (a ^ b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } case VMType.Enum: { Expect(valB.Type == VMType.Enum, $"expected {valA.Type} for flag op"); var numA = valA.AsNumber(); var numB = valB.AsNumber(); Expect(numA.GetBitLength() <= 32, "too many bits"); Expect(numB.GetBitLength() <= 32, "too many bits"); var a = (uint)numA; var b = (uint)numB; if (opcode != Opcode.AND) { SetState(ExecutionState.Fault); } bool result = (a & b) != 0; frame.Registers[dst].SetValue(result); break; } case VMType.Number: { Expect(valB.Type == VMType.Number, $"expected {valA.Type} for logical op"); var numA = valA.AsNumber(); var numB = valB.AsNumber(); Expect(numA.GetBitLength() <= 64, "too many bits"); Expect(numB.GetBitLength() <= 64, "too many bits"); var a = (long)numA; var b = (long)numB; BigInteger result; switch (opcode) { case Opcode.AND: result = (a & b); break; case Opcode.OR: result = (a | b); break; case Opcode.XOR: result = (a ^ b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } default: throw new VMException(frame.VM, "logical op unsupported for type " + valA.Type); } break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.EQUAL: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length, "invalid srcA register"); Expect(srcB < frame.Registers.Length, "invalid srcB register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var a = frame.Registers[srcA]; var b = frame.Registers[srcB]; var result = a.Equals(b); frame.Registers[dst].SetValue(result); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.LT: case Opcode.GT: case Opcode.LTE: case Opcode.GTE: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length, "invalid srcA register"); Expect(srcB < frame.Registers.Length, "invalid srcB register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var a = frame.Registers[srcA].AsNumber(); var b = frame.Registers[srcB].AsNumber(); bool result; switch (opcode) { case Opcode.LT: result = (a < b); break; case Opcode.GT: result = (a > b); break; case Opcode.LTE: result = (a <= b); break; case Opcode.GTE: result = (a >= b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); break; } // args: byte reg case Opcode.INC: { var dst = Read8(); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[dst].AsNumber(); frame.Registers[dst].SetValue(val + 1); break; } // args: byte reg case Opcode.DEC: { var dst = Read8(); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[dst].AsNumber(); frame.Registers[dst].SetValue(val - 1); break; } // args: byte src_reg, byte dest_reg case Opcode.SIGN: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src].AsNumber(); if (val == 0) { frame.Registers[dst].SetValue(BigInteger.Zero); } else { frame.Registers[dst].SetValue(val < 0 ? -1 : 1); } break; } // args: byte src_reg, byte dest_reg case Opcode.NEGATE: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src].AsNumber(); frame.Registers[dst].SetValue(-val); break; } // args: byte src_reg, byte dest_reg case Opcode.ABS: { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var val = frame.Registers[src].AsNumber(); frame.Registers[dst].SetValue(val < 0 ? -val : val); break; } // args: byte src_a_reg, byte src_b_reg, byte dest_reg case Opcode.ADD: case Opcode.SUB: case Opcode.MUL: case Opcode.DIV: case Opcode.MOD: case Opcode.SHR: case Opcode.SHL: case Opcode.MIN: case Opcode.MAX: case Opcode.POW: { var srcA = Read8(); var srcB = Read8(); var dst = Read8(); Expect(srcA < frame.Registers.Length, "invalid srcA register"); Expect(srcB < frame.Registers.Length, "invalid srcB register"); Expect(dst < frame.Registers.Length, "invalid dst register"); if (opcode == Opcode.ADD && frame.Registers[srcA].Type == VMType.String) { Expect(frame.Registers[srcB].Type == VMType.String, "invalid string as right operand"); var a = frame.Registers[srcA].AsString(); var b = frame.Registers[srcB].AsString(); var result = a + b; frame.Registers[dst].SetValue(result); } else { var a = frame.Registers[srcA].AsNumber(); var b = frame.Registers[srcB].AsNumber(); BigInteger result; switch (opcode) { case Opcode.ADD: result = a + b; break; case Opcode.SUB: result = a - b; break; case Opcode.MUL: result = a * b; break; case Opcode.DIV: result = a / b; break; case Opcode.MOD: result = a % b; break; case Opcode.SHR: result = a >> (int)b; break; case Opcode.SHL: result = a << (int)b; break; case Opcode.MIN: result = a < b ? a : b; break; case Opcode.MAX: result = a > b ? a : b; break; case Opcode.POW: result = BigInteger.Pow(a, b); break; default: { SetState(ExecutionState.Fault); return; } } frame.Registers[dst].SetValue(result); } break; } // args: byte src_reg, byte dest_reg, byte key case Opcode.PUT: { var src = Read8(); var dst = Read8(); var keyReg = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); Expect(keyReg < frame.Registers.Length, "invalid key register"); var key = frame.Registers[keyReg]; Throw.If(key.Type == VMType.None, "invalid key type"); var value = frame.Registers[src]; frame.Registers[dst].SetKey(key, value); break; } // args: byte src_reg, byte dest_reg, byte key case Opcode.GET: { var src = Read8(); var dst = Read8(); var keyReg = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); Expect(keyReg < frame.Registers.Length, "invalid key register"); var key = frame.Registers[keyReg]; Throw.If(key.Type == VMType.None, "invalid key type"); var val = frame.Registers[src].GetKey(key); frame.Registers[dst] = val; break; } // args: byte dest_reg case Opcode.CLEAR: { var dst = Read8(); Expect(dst < frame.Registers.Length, "invalid dst register"); frame.Registers[dst] = new VMObject(); break; } // args: byte dest_reg, var key case Opcode.CTX: using (var m = new ProfileMarker("CTX")) { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var contextName = frame.Registers[src].AsString(); ExecutionContext context = frame.VM.FindContext(contextName); if (context == null) { throw new VMException(frame.VM, $"VM ctx instruction failed: could not find context with name '{contextName}'"); } frame.Registers[dst].SetValue(context); break; } // args: byte src_reg case Opcode.SWITCH: using (var m = new ProfileMarker("SWITCH")) { var src = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); var context = frame.Registers[src].AsInterop <ExecutionContext>(); _state = frame.VM.SwitchContext(context, InstructionPointer); if (_state == ExecutionState.Halt) { _state = ExecutionState.Running; frame.VM.PopFrame(); } else { throw new VMException(frame.VM, $"VM switch instruction failed: execution state did not halt"); } break; } // args: byte src_reg dst_reg case Opcode.UNPACK: using (var m = new ProfileMarker("SWITCH")) { var src = Read8(); var dst = Read8(); Expect(src < frame.Registers.Length, "invalid src register"); Expect(dst < frame.Registers.Length, "invalid dst register"); var bytes = frame.Registers[src].AsByteArray(); frame.Registers[dst] = VMObject.FromBytes(bytes); break; } case Opcode.DEBUG: { break; // put here a breakpoint for debugging } default: { throw new VMException(frame.VM, $"Unknown VM opcode: {(int)opcode}"); } } } catch (Exception ex) { ex = ex.ExpandInnerExceptions(); Trace.WriteLine(ex.ToString()); SetState(ExecutionState.Fault); if (!(ex is VMException)) { ex = new VMException(frame.VM, ex.Message); } throw ex; } }
public abstract ExecutionState Execute(ExecutionFrame frame, Stack <VMObject> stack);