Ejemplo n.º 1
0
        internal static ValueObject GetInitExpr(InitExpr init, List <GlobalInstance> initialized_globals)
        {
            if (init.expr.Length < 3)
            {
                throw new Exception("Unexpected init expression.");
            }

            uint pc = 0;

            ValueObject ret = null;

            switch (init.expr[0])
            {
            case (byte)WebAssemblyOpcode.I32_CONST:
                ret = new ValueObject(LEB128.ReadUInt32(init.expr, ref pc));
                break;

            case (byte)WebAssemblyOpcode.I64_CONST:
                ret = new ValueObject(LEB128.ReadUInt64(init.expr, ref pc));
                break;

            case (byte)WebAssemblyOpcode.F32_CONST:
                ret = new ValueObject(BitConverter.ToSingle(init.expr, (int)pc));
                break;

            case (byte)WebAssemblyOpcode.F64_CONST:
                ret = new ValueObject(BitConverter.ToDouble(init.expr, (int)pc));
                break;

            case (byte)WebAssemblyOpcode.GLOBAL_GET:
                GlobalInstance gi = initialized_globals[LEB128.ReadInt32(init.expr, ref pc)];
                if (!gi.is_mutable)
                {
                    throw new Exception("Unexpected init expression.");
                }
                ret = gi.value;
                break;

            default:
                throw new Exception("Invalid init expression. Expected only simple constant load instruction or global get.");
            }

            pc++;

            if (init.expr[pc] != (byte)WebAssemblyOpcode.END || init.expr.Length > pc)
            {
                throw new Exception("Invalid init expression.");
            }

            return(ret);
        }
Ejemplo n.º 2
0
        private (byte[] memory, int location) LoadOrFail(byte[] code, uint size, ref uint pc)
        {
            // align is in bytes
            // it tells us how this value is aligned
            // in our implementation, we can disregard alignment
            int  align  = 1 << (int)LEB128.ReadUInt32(code, ref pc);
            uint offset = LEB128.ReadUInt32(code, ref pc);

            ValueObject i  = GetValueOfTypeOrFail(WebAssemblyType.i32);
            long        ea = i.AsI32() + offset;
            uint        N  = size / 8;

            if ((ea + N) > ctx.linear_memory[0].size)
            {
                Trap("Illegal memory access");
            }

            logger.ConditionalTrace($"Memory location calculated = {ea}.");

            return(ctx.linear_memory[0].memory, (int)ea);
        }
Ejemplo n.º 3
0
        // TODO: Can now transform Execute from a recursive function into an iterative function
        // Each time a new "frame" is added, we just update activation_object and func
        // ctx records the current pc so when we go back
        // Simply need to inline the Invoke method into Execute
        private void Execute()
        {
            try
            {
                ActivationObject activation_object = ctx.GetCurrentFunction();
                FunctionInstance func = activation_object.function;
                byte[]           code = func.code;

                logger.Info($"Entering Execute with function {func.module}.{func.name}.");
                logger.ConditionalTrace($"Function returns: {func.return_type}.");
                logger.ConditionalTrace("Function parameters: {0}.", WebAssemblyHelper.ToString(func.parameters, ", "));
                logger.ConditionalTrace("Function arguments: {0}.", WebAssemblyHelper.ToString(activation_object.parameters, ", "));
                logger.ConditionalTrace("Function locals: {0}.", WebAssemblyHelper.ToString(func.locals, ", "));

                //WebAssemblyHelper.ReinterpretHelper reinterpret_helper = new WebAssemblyHelper.ReinterpretHelper();

                bool continue_executing = true;

                // https://webassembly.github.io/spec/core/exec/instructions.html
                while (continue_executing)
                {
                    logger.ConditionalTrace($"PC = {activation_object.pc}.");
                    logger.Debug($"Executing: {(WebAssemblyOpcode)code[activation_object.pc]}.");

                    switch ((WebAssemblyOpcode)code[activation_object.pc])
                    {
                    case WebAssemblyOpcode.UNREACHABLE:
                    {
                        Trap("Unreachable reached!");

                        break;
                    }

                    case WebAssemblyOpcode.NOP:
                    {
                        break;
                    }

                    case WebAssemblyOpcode.END:
                    {
                        continue_executing = false;

                        break;
                    }

                    case WebAssemblyOpcode.LOOP:
                    {
                        // ignore result for now
                        activation_object.pc++;
                        var result = (WebAssemblyType)code[activation_object.pc];

                        Enter(new LabelObject(0, activation_object.pc - 2));

                        break;
                    }

                    case WebAssemblyOpcode.BR:
                    {
                        uint l = LEB128.ReadUInt32(code, ref activation_object.pc);

                        Exit(l);

                        break;
                    }

                    case WebAssemblyOpcode.BR_IF:
                    {
                        ValueObject c = GetValueOfTypeOrFail(WebAssemblyType.i32);
                        if (c.AsI32() != 0)
                        {
                            goto case WebAssemblyOpcode.BR;
                        }

                        break;
                    }

                    case WebAssemblyOpcode.LOCAL_GET:
                    {
                        uint local = LEB128.ReadUInt32(code, ref activation_object.pc);
                        if (local > func.locals.Length)
                        {
                            Trap("Function corrupt.");
                        }

                        ctx.Push(activation_object.locals[local]);

                        break;
                    }

                    case WebAssemblyOpcode.LOCAL_SET:
                    {
                        uint local = LEB128.ReadUInt32(code, ref activation_object.pc);
                        if (local > func.locals.Length)
                        {
                            Trap("Function corrupt.");
                        }

                        ValueObject val = GetValueOrFail();

                        activation_object.locals[local] = val;

                        break;
                    }

                    case WebAssemblyOpcode.LOCAL_TEE:
                    {
                        ValueObject val = GetValueOrFail();
                        ctx.Push(val);
                        ctx.Push(val);
                        goto case WebAssemblyOpcode.LOCAL_SET;
                    }

                    case WebAssemblyOpcode.I32_CONST:
                    {
                        ctx.Push(new ValueObject(LEB128.ReadUInt32(code, ref activation_object.pc)));
                        break;
                    }

                    case WebAssemblyOpcode.I64_CONST:
                    {
                        ctx.Push(new ValueObject(LEB128.ReadUInt64(code, ref activation_object.pc)));
                        break;
                    }

                    case WebAssemblyOpcode.F32_CONST:
                    {
                        ctx.Push(new ValueObject(BitConverter.ToSingle(code, (int)activation_object.pc + 1)));
                        activation_object.pc += 4;
                        break;
                    }

                    case WebAssemblyOpcode.F64_CONST:
                    {
                        ctx.Push(new ValueObject(BitConverter.ToDouble(code, (int)activation_object.pc + 1)));
                        activation_object.pc += 7;
                        break;
                    }

                    case WebAssemblyOpcode.I32_LOAD:
                    {
                        var(memory, location) = LoadOrFail(code, 32, ref activation_object.pc);

                        ctx.Push(new ValueObject(BitConverter.ToUInt32(memory, location)));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD:
                    {
                        var(memory, location) = LoadOrFail(code, 64, ref activation_object.pc);

                        ctx.Push(new ValueObject(BitConverter.ToUInt64(memory, location)));

                        break;
                    }

                    case WebAssemblyOpcode.F32_LOAD:
                    {
                        var(memory, location) = LoadOrFail(code, 32, ref activation_object.pc);

                        ctx.Push(new ValueObject(BitConverter.ToSingle(memory, location)));

                        break;
                    }

                    case WebAssemblyOpcode.F64_LOAD:
                    {
                        var(memory, location) = LoadOrFail(code, 64, ref activation_object.pc);

                        ctx.Push(new ValueObject(BitConverter.ToDouble(memory, location)));

                        break;
                    }

                    case WebAssemblyOpcode.I32_LOAD8_S:
                    {
                        var(memory, location) = LoadOrFail(code, 8, ref activation_object.pc);

                        ctx.Push(new ValueObject((uint)(sbyte)memory[location]));

                        break;
                    }

                    case WebAssemblyOpcode.I32_LOAD8_U:
                    {
                        var(memory, location) = LoadOrFail(code, 8, ref activation_object.pc);

                        ctx.Push(new ValueObject((uint)memory[location]));

                        break;
                    }

                    case WebAssemblyOpcode.I32_LOAD16_S:
                    {
                        var(memory, location) = LoadOrFail(code, 16, ref activation_object.pc);

                        ctx.Push(new ValueObject((uint)BitConverter.ToInt16(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I32_LOAD16_U:
                    {
                        var(memory, location) = LoadOrFail(code, 16, ref activation_object.pc);

                        ctx.Push(new ValueObject(BitConverter.ToUInt16(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD8_S:
                    {
                        var(memory, location) = LoadOrFail(code, 8, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)(sbyte)memory[location]));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD8_U:
                    {
                        var(memory, location) = LoadOrFail(code, 8, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)memory[location]));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD16_S:
                    {
                        var(memory, location) = LoadOrFail(code, 16, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)BitConverter.ToInt16(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD16_U:
                    {
                        var(memory, location) = LoadOrFail(code, 16, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)BitConverter.ToUInt16(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD32_S:
                    {
                        var(memory, location) = LoadOrFail(code, 32, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)BitConverter.ToInt32(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I64_LOAD32_U:
                    {
                        var(memory, location) = LoadOrFail(code, 32, ref activation_object.pc);

                        ctx.Push(new ValueObject((ulong)BitConverter.ToUInt32(memory, (int)activation_object.pc)));

                        break;
                    }

                    case WebAssemblyOpcode.I32_STORE:
                    {
                        var(value, memory, location) = StoreOrFail(code, 32, WebAssemblyType.i32, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes(value.AsI32()), 0, memory, location, 32 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.I64_STORE:
                    {
                        var(value, memory, location) = StoreOrFail(code, 64, WebAssemblyType.i64, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes(value.AsI64()), 0, memory, location, 64 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.F32_STORE:
                    {
                        var(value, memory, location) = StoreOrFail(code, 32, WebAssemblyType.f32, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes(value.AsF32()), 0, memory, location, 32 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.F64_STORE:
                    {
                        var(value, memory, location) = StoreOrFail(code, 64, WebAssemblyType.f64, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes(value.AsF64()), 0, memory, location, 64 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.I32_STORE8:
                    {
                        var(value, memory, location) = StoreOrFail(code, 32, WebAssemblyType.i32, ref activation_object.pc);

                        memory[location] = (byte)value.AsI32();

                        break;
                    }

                    case WebAssemblyOpcode.I32_STORE16:
                    {
                        var(value, memory, location) = StoreOrFail(code, 32, WebAssemblyType.i32, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes((ushort)value.AsI32()), 0, memory, location, 16 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.I64_STORE8:
                    {
                        var(value, memory, location) = StoreOrFail(code, 64, WebAssemblyType.i64, ref activation_object.pc);

                        memory[location] = (byte)value.AsI64();

                        break;
                    }

                    case WebAssemblyOpcode.I64_STORE16:
                    {
                        var(value, memory, location) = StoreOrFail(code, 64, WebAssemblyType.i64, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes((ushort)value.AsI64()), 0, memory, location, 16 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.I64_STORE32:
                    {
                        var(value, memory, location) = StoreOrFail(code, 64, WebAssemblyType.i64, ref activation_object.pc);

                        Array.Copy(BitConverter.GetBytes((uint)value.AsI64()), 0, memory, location, 32 / 8);

                        break;
                    }

                    case WebAssemblyOpcode.MEMORY_SIZE:
                    {
                        ctx.Push(new ValueObject((uint)ctx.linear_memory[0].pages));

                        break;
                    }

                    case WebAssemblyOpcode.MEMORY_GROW:
                    {
                        ValueObject n = GetValueOfTypeOrFail(WebAssemblyType.i32);

                        if (ctx.linear_memory[0].GrowMemory(n.AsI32()))
                        {
                            ctx.Push(n);
                        }
                        else
                        {
                            ctx.Push(new ValueObject(unchecked ((uint)-1)));
                        }

                        break;
                    }

                    case WebAssemblyOpcode.CALL:
                    {
                        uint new_func = LEB128.ReadUInt32(code, ref activation_object.pc);

                        ctx.Push(Invoke(new_func));

                        break;
                    }

                    case WebAssemblyOpcode.DROP:
                    {
                        GetValueOrFail();

                        break;
                    }

                    case WebAssemblyOpcode.SELECT:
                    {
                        ValueObject c    = GetValueOfTypeOrFail(WebAssemblyType.i32);
                        ValueObject val2 = GetValueOrFail();
                        ValueObject val1 = GetValueOrFail();

                        ctx.Push(c.AsI32() != 0 ? val1 : val2);

                        break;
                    }

                    default:
                    {
                        Trap($"Unknown Opcode {code[activation_object.pc]}.");

                        break;
                    }
                    }
                    activation_object.pc++;
                }
            }
            catch (WebAssemblyTrap)
            {
                throw;
            }
            catch (Exception ex)
            {
                logger.Debug(ex.StackTrace);

                Trap("Unexpected Error: " + ex.Message);
            }
        }