예제 #1
0
        public void SetKey(VMObject key, VMObject obj)
        {
            Dictionary <VMObject, VMObject> children;

            // NOTE: here we need to instantiate the key as new object
            // otherwise keeping the key in a register allows modifications to it that also affect the dictionary keys
            var temp = new VMObject();

            temp.Copy(key);
            key = temp;

            if (this.Type == VMType.Struct)
            {
                children = GetChildren();
            }
            else
            if (this.Type == VMType.None)
            {
                this.Type       = VMType.Struct;
                children        = new Dictionary <VMObject, VMObject>();
                this.Data       = children;
                this._localSize = 0;
            }
            else
            {
                throw new Exception($"Invalid cast from {this.Type} to struct");
            }

            var result = new VMObject();

            children[key] = result;
            result.Copy(obj);
        }
예제 #2
0
        public static VMObject FromObject(object obj)
        {
            var type = GetVMType(obj.GetType());

            Throw.If(type == VMType.None, "not a valid object");

            var result = new VMObject();

            switch (type)
            {
            case VMType.Bool: result.SetValue((bool)obj); break;

            case VMType.Bytes: result.SetValue((byte[])obj, VMType.Bytes); break;

            case VMType.String: result.SetValue((string)obj); break;

            case VMType.Number: result.SetValue((BigInteger)obj); break;

            case VMType.Enum: result.SetValue((Enum)obj); break;

            case VMType.Object: result.SetValue(obj); break;

            default: return(null);
            }

            return(result);
        }
예제 #3
0
        internal void Copy(VMObject other)
        {
            if (other == null || other.Type == VMType.None)
            {
                this.Type = VMType.None;
                this.Data = null;
                return;
            }

            this.Type = other.Type;

            if (other.Type == VMType.Struct)
            {
                var children      = new Dictionary <VMObject, VMObject>();
                var otherChildren = other.GetChildren();
                foreach (var key in otherChildren.Keys)
                {
                    var temp = new VMObject();
                    temp.Copy(otherChildren[key]);
                    children[key] = temp;
                }

                this.Data = children;
            }
            else
            {
                this.Data = other.Data;

                /*var temp = other.Data;
                 * _data = new byte[temp.Length];
                 * Array.Copy(temp, _data, _data.Length);*/
            }
        }
예제 #4
0
        public static VMObject CastTo(VMObject srcObj, VMType type)
        {
            if (srcObj.Type == type)
            {
                var result = new VMObject();
                result.Copy(srcObj);
                return(result);
            }

            switch (type)
            {
            case VMType.None:
                return(new VMObject());

            case VMType.String:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsString());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Timestamp:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsTimestamp());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Bool:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsBool());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Bytes:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsByteArray());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Number:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsNumber());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Struct:
                switch (srcObj.Type)
                {
                case VMType.Object: return(CastViaReflection(srcObj.Data, 0));

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
            }
        }
예제 #5
0
        public static VMObject FromBytes(byte[] bytes)
        {
            var result = new VMObject();

            result.UnserializeData(bytes);
            return(result);
        }
예제 #6
0
        public void UnserializeData(BinaryReader reader)
        {
            this.Type = (VMType)reader.ReadByte();
            switch (this.Type)
            {
            case VMType.Bool:
                this.Data = Serialization.Unserialize <bool>(reader);
                break;

            case VMType.Bytes:
                this.Data = Serialization.Unserialize <byte[]>(reader);
                break;

            case VMType.Number:
                this.Data = Serialization.Unserialize <BigInteger>(reader);
                break;

            case VMType.Timestamp:
                this.Data = Serialization.Unserialize <Timestamp>(reader);
                break;

            case VMType.String:
                this.Data = Serialization.Unserialize <string>(reader);
                break;

            case VMType.Struct:
                var childCount = reader.ReadVarInt();
                var children   = new Dictionary <VMObject, VMObject>();
                while (childCount > 0)
                {
                    var key = new VMObject();
                    key.UnserializeData(reader);

                    var val = new VMObject();
                    val.UnserializeData(reader);

                    children[key] = val;
                    childCount--;
                }

                this.Data = children;
                break;

            // NOTE object type information is lost during serialization, so we reconstruct it as byte array
            case VMType.Object:
                this.Type = VMType.Bytes;
                this.Data = reader.ReadByteArray();
                break;

            case VMType.Enum:     // TODO
            default:
                throw new Exception($"invalid unserialize: type {this.Type}");
            }
        }
예제 #7
0
 public static VMObject FromBytes(byte[] bytes)
 {
     using (var stream = new MemoryStream(bytes))
     {
         using (var reader = new BinaryReader(stream))
         {
             var result = new VMObject();
             result.UnserializeData(reader);
             return(result);
         }
     }
 }
예제 #8
0
        public ExecutionFrame(VirtualMachine VM, uint offset, ExecutionContext context, int registerCount)
        {
            this.VM      = VM;
            this.Offset  = offset;
            this.Context = context;

            Registers = new VMObject[registerCount];

            for (int i = 0; i < registerCount; i++)
            {
                Registers[i] = new VMObject();
            }
        }
예제 #9
0
        public object ToStruct(Type structType)
        {
            Throw.If(Type != VMType.Struct, "not a valid source struct");

            Throw.If(!structType.IsStructOrClass(), "not a valid destination struct");

            var dict = this.GetChildren();

            var fields = structType.GetFields();
            var result = Activator.CreateInstance(structType);

            object boxed = result;

            foreach (var field in fields)
            {
                var key = VMObject.FromObject(field.Name);
                Throw.If(!dict.ContainsKey(key), "field not present in source struct: " + field.Name);
                var val = dict[key].ToObject(field.FieldType);

                // here we check if the types mismatch
                // in case of getting a byte[] instead of an object, we try unserializing the bytes in a different approach
                // NOTE this should not be necessary often, but is already getting into black magic territory...
                if (val != null && field.FieldType != typeof(byte[]) && val.GetType() == typeof(byte[]))
                {
                    if (typeof(ISerializable).IsAssignableFrom(field.FieldType))
                    {
                        var temp  = (ISerializable)Activator.CreateInstance(field.FieldType);
                        var bytes = (byte[])val;
                        using (var stream = new MemoryStream(bytes))
                        {
                            using (var reader = new BinaryReader(stream))
                            {
                                temp.UnserializeData(reader);
                            }
                        }
                        val = temp;
                    }
                }

                // HACK allows treating uints as enums, without this it is impossible to transform between C# objects and VM objects
                if (field.FieldType.IsEnum && !val.GetType().IsEnum)
                {
                    val = Enum.Parse(field.FieldType, val.ToString());
                }

                field.SetValue(boxed, val);
            }
            return(boxed);
        }
예제 #10
0
        public VMObject GetKey(VMObject key)
        {
            if (this.Type != VMType.Struct)
            {
                throw new Exception($"Invalid cast: expected struct, got {this.Type}");
            }

            var children = GetChildren();

            if (children.ContainsKey(key))
            {
                return(children[key]);
            }

            return(new VMObject());
        }
예제 #11
0
        public static VMObject FromObject(object obj)
        {
            var objType = obj.GetType();
            var type    = GetVMType(objType);

            Throw.If(type == VMType.None, "not a valid object");

            var result = new VMObject();

            switch (type)
            {
            case VMType.Bool: result.SetValue((bool)obj); break;

            case VMType.Bytes: result.SetValue((byte[])obj, VMType.Bytes); break;

            case VMType.String: result.SetValue((string)obj); break;

            case VMType.Number:
                if (obj.GetType() == typeof(int))
                {
                    obj = new BigInteger((int)obj);     // HACK
                }
                result.SetValue((BigInteger)obj);
                break;

            case VMType.Enum: result.SetValue((Enum)obj); break;

            case VMType.Object: result.SetValue(obj); break;

            case VMType.Timestamp:
                if (obj.GetType() == typeof(uint))
                {
                    obj = new Timestamp((uint)obj);     // HACK
                }
                result.SetValue((Timestamp)obj);
                break;

            default: return(null);
            }

            return(result);
        }
예제 #12
0
        public void SetKey(string key, VMObject obj)
        {
            Dictionary <string, VMObject> children;

            if (this.Type == VMType.Struct)
            {
                children = GetChildren();
            }
            else
            {
                this.Type       = VMType.Struct;
                children        = new Dictionary <string, VMObject>();
                this.Data       = children;
                this._localSize = 0;
            }

            var result = new VMObject();

            children[key] = result;
            result.Copy(obj);
        }
예제 #13
0
        public object ToStruct(Type structType)
        {
            Throw.If(Type != VMType.Struct, "not a valid source struct");

            Throw.If(!structType.IsStructOrClass(), "not a valid destination struct");

            var dict = this.GetChildren();

            var fields = structType.GetFields();
            var result = Activator.CreateInstance(structType);

            object boxed = result;

            foreach (var field in fields)
            {
                var key = VMObject.FromObject(field.Name);
                Throw.If(!dict.ContainsKey(key), "field not present in source struct: " + field.Name);
                var val = dict[key].ToObject(field.FieldType);
                field.SetValue(boxed, val);
            }
            return(boxed);
        }
예제 #14
0
        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;
                }
            }
        }
예제 #15
0
        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;
            }
        }
예제 #16
0
 public void SetKey(BigInteger key, VMObject obj)
 {
     SetKey(key.ToString(), obj);
 }
예제 #17
0
        public static VMObject CastTo(VMObject srcObj, VMType type)
        {
            if (srcObj.Type == type)
            {
                var result = new VMObject();
                result.Copy(srcObj);
                return(result);
            }

            switch (type)
            {
            case VMType.None:
                return(new VMObject());

            case VMType.String:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsString());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Timestamp:
            {
                var result = new VMObject();
                result.SetValue(srcObj.AsTimestamp());         // TODO does this work for all types?
                return(result);
            }

            case VMType.Bool:
                // TODO move this stuff to AsBool()
                switch (srcObj.Type)
                {
                case VMType.Number:
                {
                    var result = new VMObject();
                    result.SetValue(srcObj.AsNumber() != 0);
                    return(result);
                }

                case VMType.String:
                {
                    var result = new VMObject();
                    result.SetValue(!(((string)srcObj.Data).Equals("false", StringComparison.OrdinalIgnoreCase)));
                    return(result);
                }

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            case VMType.Bytes:
                switch (srcObj.Type)
                {
                case VMType.Bool:
                {
                    var result = new VMObject();
                    result.SetValue(new byte[] { (byte)(srcObj.AsBool() ? 1 : 0) }, VMType.Bytes);
                    return(result);
                }

                case VMType.String:
                {
                    var result = new VMObject();
                    result.SetValue(Encoding.UTF8.GetBytes((string)srcObj.Data), VMType.Bytes);
                    return(result);
                }

                case VMType.Number:
                {
                    var result = new VMObject();
                    result.SetValue(((BigInteger)srcObj.Data).ToSignedByteArray(), VMType.Bytes);
                    return(result);
                }

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            case VMType.Number:
                switch (srcObj.Type)
                {
                case VMType.Bool:
                {
                    var result = new VMObject();
                    result.SetValue(srcObj.AsBool() ? 1 : 0);
                    return(result);
                }

                case VMType.String:
                {
                    var result = new VMObject();
                    result.SetValue(BigInteger.Parse((string)srcObj.Data));
                    return(result);
                }

                case VMType.Bytes:
                {
                    var result = new VMObject();
                    result.SetValue(BigInteger.FromSignedArray((byte[])srcObj.Data));
                    return(result);
                }

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            case VMType.Struct:
                switch (srcObj.Type)
                {
                case VMType.Object: return(CastViaReflection(srcObj.Data, 0));

                default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
                }

            default: throw new Exception($"invalid cast: {srcObj.Type} to {type}");
            }
        }
예제 #18
0
        // this does the opposite of ToStruct(), takes a InteropObject and converts it to a VM.Struct
        private static VMObject CastViaReflection(object srcObj, int level)
        {
            var srcType = srcObj.GetType();

            if (srcType.IsArray)
            {
                var children = new Dictionary <VMObject, VMObject>();

                var array = (Array)srcObj;
                for (int i = 0; i < array.Length; i++)
                {
                    var val = array.GetValue(i);
                    var key = new VMObject();
                    key.SetValue(i);
                    var vmVal = CastViaReflection(val, level + 1);
                    children[key] = vmVal;
                }

                var result = new VMObject();
                result.SetValue(children);
                return(result);
            }
            else
            {
                var targetType = VMObject.GetVMType(srcType);

                VMObject result;

                bool isKnownType = typeof(BigInteger) == srcType || typeof(Timestamp) == srcType || typeof(ISerializable).IsAssignableFrom(srcType);

                if (srcType.IsStructOrClass() && !isKnownType)
                {
                    var children = new Dictionary <VMObject, VMObject>();

                    var fields = srcType.GetFields();

                    if (fields.Length > 0)
                    {
                        foreach (var field in fields)
                        {
                            var key = new VMObject();
                            key.SetValue(field.Name);
                            var val   = field.GetValue(srcObj);
                            var vmVal = CastViaReflection(val, level + 1);
                            children[key] = vmVal;
                        }

                        result = new VMObject();
                        result.SetValue(children);
                        return(result);
                    }
                }

                result = VMObject.FromObject(srcObj);
                if (result != null)
                {
                    return(result);
                }

                throw new Exception($"invalid cast: Interop.{srcType.Name} to vm object");
            }
        }
예제 #19
0
        // this does the opposite of ToStruct(), takes a InteropObject and converts it to a VM.Struct
        private static VMObject CastViaReflection(object srcObj, int level)
        {
            var srcType = srcObj.GetType();

            if (srcType.IsArray)
            {
                var children = new Dictionary <VMObject, VMObject>();

                var array = (Array)srcObj;
                for (int i = 0; i < array.Length; i++)
                {
                    var val = array.GetValue(i);
                    var key = new VMObject();
                    key.SetValue(i);
                    var vmVal = CastViaReflection(val, level + 1);
                    children[key] = vmVal;
                }

                var result = new VMObject();
                result.SetValue(children);
                return(result);
            }
            else
            {
                VMObject result;

                if (level == 0 && srcType.IsStructOrClass())
                {
                    var children = new Dictionary <VMObject, VMObject>();

                    var fields = srcType.GetFields();

                    if (fields.Length > 0)
                    {
                        foreach (var field in fields)
                        {
                            var key = new VMObject();
                            key.SetValue(field.Name);
                            var val   = field.GetValue(srcObj);
                            var vmVal = CastViaReflection(val, level + 1);
                            children[key] = vmVal;
                        }

                        result = new VMObject();
                        result.SetValue(children);
                        return(result);
                    }
                    else
                    {
                        throw new Exception("Invalid cast, no fields available");
                    }
                }

                result = VMObject.FromObject(srcObj);
                if (result != null)
                {
                    return(result);
                }

                throw new Exception($"invalid cast: Interop.{srcType.Name} to vm object");
            }
        }