Example #1
0
 public override string ToString()
 {
     return($"({GetType().Name} (pc {pc}) {function} (parameters {WebAssemblyHelper.ToString(parameters)}) (locals {WebAssemblyHelper.ToString(locals)}))");
 }
Example #2
0
 public override string ToString()
 {
     return($"({GetType().Name} (is_in_module {is_in_module}) (is_export {is_export}) (module {module}) (name {name}) (return {return_type?.ToString() ?? "void"}) (parameters {WebAssemblyHelper.ToString(parameters)}) (locals {WebAssemblyHelper.ToString(locals)}))");
 }
Example #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);
            }
        }