static void Main(string[] args)
        {
            var module = WebAssembly.Module.ReadFromBinary(@"C:\Code\superstring-net-standard\superstring.wasm");

            foreach (var e in module.Exports)
            {
                Console.WriteLine(e.ToString());
            }

            //module.Memories.Add(new WebAssembly.Memory(2, null));

            var importDictionary = new ImportDictionary();
            //Action<int> t0d = p1 => { };
            //importDictionary.Add("env", "_ZN5PointC1Ev", new FunctionImport(t0d));
            //var memory = new UnmanagedMemory(2, null);
            //importDictionary.Add("env", "memory", new MemoryImport(() => memory));


            var _instanceCreator = module.Compile <SuperstringWasmExports>();

            using (var instance = _instanceCreator(importDictionary))
            {
                IntPtr rNum = instance.Exports._ZN12PointWrapper15construct_pointEv(new IntPtr());
            }
        }
    public void Execute_Sample_MDN_Table2()
    {
        var tbl = new FunctionTable(2);

        Assert.AreEqual(2u, tbl.Length);
        Assert.IsNull(tbl[0]);
        Assert.IsNull(tbl[1]);

        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WebAssembly.Samples.table2.wasm"))
        {
            var imports = new ImportDictionary
            {
                { "js", "tbl", tbl },
            };
            Assert.IsNotNull(stream);
            Compile.FromBinary <dynamic>(stream !)(imports);
        }

        Assert.AreEqual(2u, tbl.Length);

        var f1 = tbl[0];

        Assert.IsNotNull(f1);
        Assert.IsInstanceOfType(f1, typeof(Func <int>));
        Assert.AreEqual(42, ((Func <int>)f1 !).Invoke());

        var f2 = tbl[1];

        Assert.IsNotNull(f2);
        Assert.IsInstanceOfType(f1, typeof(Func <int>));
        Assert.AreEqual(83, ((Func <int>)f2 !).Invoke());
    }
Beispiel #3
0
    static void Main()
    {
        var imports = new ImportDictionary
        {
            { "env", "greet", new FunctionImport(new Action(greet)) },
            { "env", "printf", new FunctionImport(new Func <int, int, int>(printf)) },
        };
        var compiled = Compile.FromBinary <dynamic>(new FileStream("test.wasm", FileMode.Open, FileAccess.Read))(imports);

        memory = compiled.Exports.memory;
        compiled.Exports._start();
    }
Beispiel #4
0
        public void Execute_Sample_Issue7()
        {
            Assert.AreEqual(0, issue7Received.Length);

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WebAssembly.Samples.Issue7.wasm"))
            {
                var imports = new ImportDictionary
                {
                    { "env", "sayc", new FunctionImport(new Action <int>(Issue7Receive)) },
                };
                var compiled = Compile.FromBinary <dynamic>(stream)(imports);
                Assert.AreEqual <int>(0, compiled.Exports.main());
            }

            Assert.AreEqual("Hello World (from WASM)\n", issue7Received.ToString());
        }
Beispiel #5
0
        internal static Instance <JitEntryPoint> CompileWasm(UInt160 contract, byte[] buffer, ImportDictionary imports, bool ignoreEndingCode)
        {
            if (ByteCodeCache.TryGetValue(contract, out var instance))
            {
                return(instance());
            }
            var config = new CompilerConfiguration()
            {
                IgnoreEndingCode = ignoreEndingCode
            };

            using var stream = new MemoryStream(buffer, 0, buffer.Length, false);
            return(Compile.FromBinary <JitEntryPoint>(stream, config)(imports));
        }
Beispiel #6
0
    public static void Run <TExports>(string pathBase, string json, Func <uint, bool>?skip)
        where TExports : class
    {
        TestInfo testInfo;

        using (var reader = new StreamReader(Path.Combine(pathBase, json)))
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(JsonSubtypesConverterBuilder
                                    .Of(typeof(Command), "type")
                                    .RegisterSubtype(typeof(ModuleCommand), CommandType.module)
                                    .RegisterSubtype(typeof(AssertReturn), CommandType.assert_return)
                                    .RegisterSubtype(typeof(AssertReturnCanonicalNan), CommandType.assert_return_canonical_nan)
                                    .RegisterSubtype(typeof(AssertReturnArithmeticNan), CommandType.assert_return_arithmetic_nan)
                                    .RegisterSubtype(typeof(AssertInvalid), CommandType.assert_invalid)
                                    .RegisterSubtype(typeof(AssertTrap), CommandType.assert_trap)
                                    .RegisterSubtype(typeof(AssertMalformed), CommandType.assert_malformed)
                                    .RegisterSubtype(typeof(AssertExhaustion), CommandType.assert_exhaustion)
                                    .RegisterSubtype(typeof(AssertUnlinkable), CommandType.assert_unlinkable)
                                    .RegisterSubtype(typeof(Register), CommandType.register)
                                    .RegisterSubtype(typeof(AssertReturn), CommandType.action)
                                    .RegisterSubtype(typeof(AssertUninstantiable), CommandType.assert_uninstantiable)
                                    .Build());
            settings.Converters.Add(JsonSubtypesConverterBuilder
                                    .Of(typeof(TestAction), "type")
                                    .RegisterSubtype(typeof(Invoke), TestActionType.invoke)
                                    .RegisterSubtype(typeof(Get), TestActionType.get)
                                    .Build());
            settings.Converters.Add(JsonSubtypesConverterBuilder
                                    .Of(typeof(TypedValue), "type")
                                    .RegisterSubtype(typeof(Int32Value), RawValueType.i32)
                                    .RegisterSubtype(typeof(Int64Value), RawValueType.i64)
                                    .RegisterSubtype(typeof(Float32Value), RawValueType.f32)
                                    .RegisterSubtype(typeof(Float64Value), RawValueType.f64)
                                    .Build());
            testInfo = (TestInfo)JsonSerializer.Create(settings).Deserialize(reader, typeof(TestInfo)) !;
        }

        ObjectMethods?methodsByName       = null;
        var           moduleMethodsByName = new Dictionary <string, ObjectMethods>();

        // From https://github.com/WebAssembly/spec/blob/master/interpreter/host/spectest.ml
        var imports = new ImportDictionary
        {
            { "spectest", "print_i32", new FunctionImport((Action <int>)(i => { })) },
            { "spectest", "print_i32_f32", new FunctionImport((Action <int, float>)((i, f) => { })) },
            { "spectest", "print_f64_f64", new FunctionImport((Action <double, double>)((d1, d2) => { })) },
            { "spectest", "print_f32", new FunctionImport((Action <float>)(i => { })) },
            { "spectest", "print_f64", new FunctionImport((Action <double>)(i => { })) },
            { "spectest", "global_i32", new GlobalImport(() => 666) },
            { "spectest", "global_i64", new GlobalImport(() => 666L) },
            { "spectest", "global_f32", new GlobalImport(() => 666.0F) },
            { "spectest", "global_f64", new GlobalImport(() => 666.0) },
            { "spectest", "table", new FunctionTable(10, 20) },                          // Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType))
            { "spectest", "memory", new MemoryImport(() => new UnmanagedMemory(1, 2)) }, // Memory.alloc (MemoryType {min = 1l; max = Some 2l})
        };

        var registrationCandidates = new ImportDictionary();

        Action     trapExpected;
        object?    result;
        object     obj;
        MethodInfo methodInfo;
        TExports?  exports = null;

        foreach (var command in testInfo.commands)
        {
            if (skip != null && skip(command.line))
            {
                continue;
            }

            void GetMethod(TestAction action, out MethodInfo info, out object host)
            {
                var methodSource = action.module == null ? methodsByName : moduleMethodsByName[action.module];

                Assert.IsNotNull(methodSource, $"{command.line} has no method source.");
                Assert.IsTrue(methodSource !.TryGetValue(NameCleaner.CleanName(action.field), out info !), $"{command.line} failed to look up method {action.field}");
                host = methodSource.Host;
            }

            try
            {
                switch (command)
                {
                case ModuleCommand module:
                    var path   = Path.Combine(pathBase, module.filename);
                    var parsed = Module.ReadFromBinary(path);     // Ensure the module parser can read it.
                    Assert.IsNotNull(parsed);
                    methodsByName = new ObjectMethods(exports = Compile.FromBinary <TExports>(path)(imports).Exports);
                    if (module.name != null)
                    {
                        moduleMethodsByName[module.name] = methodsByName;
                    }
                    continue;

                case AssertReturn assert:
                    GetMethod(assert.action, out methodInfo, out obj);
                    try
                    {
                        result = assert.action.Call(methodInfo, obj);
                    }
                    catch (TargetInvocationException x) when(x.InnerException != null)
                    {
                        throw new AssertFailedException($"{command.line}: {x.InnerException.Message}", x.InnerException);
                    }
                    catch (Exception x)
                    {
                        throw new AssertFailedException($"{command.line}: {x.Message}", x);
                    }
                    if (assert.expected?.Length > 0)
                    {
                        if (assert.expected[0].BoxedValue.Equals(result))
                        {
                            continue;
                        }

                        switch (assert.expected[0].type)
                        {
                        case RawValueType.f32:
                        {
                            var expected = ((Float32Value)assert.expected[0]).ActualValue;
                            Assert.AreEqual(expected, (float)result !, Math.Abs(expected * 0.000001f), $"{command.line}: f32 compare");
                        }
                            continue;

                        case RawValueType.f64:
                        {
                            var expected = ((Float64Value)assert.expected[0]).ActualValue;
                            Assert.AreEqual(expected, (double)result !, Math.Abs(expected * 0.000001), $"{command.line}: f64 compare");
                        }
                            continue;
                        }

                        throw new AssertFailedException($"{command.line}: Not equal: {assert.expected[0].BoxedValue} and {result}");
                    }
                    continue;

                case AssertReturnCanonicalNan assert:
                    GetMethod(assert.action, out methodInfo, out obj);
                    result = assert.action.Call(methodInfo, obj);
                    switch (assert.expected[0].type)
                    {
                    case RawValueType.f32:
                        Assert.IsTrue(float.IsNaN((float)result !), $"{command.line}: Expected NaN, got {result}");
                        continue;

                    case RawValueType.f64:
                        Assert.IsTrue(double.IsNaN((double)result !), $"{command.line}: Expected NaN, got {result}");
                        continue;

                    default:
                        throw new AssertFailedException($"{assert.expected[0].type} doesn't support NaN checks.");
                    }

                case AssertReturnArithmeticNan assert:
                    GetMethod(assert.action, out methodInfo, out obj);
                    result = assert.action.Call(methodInfo, obj);
                    switch (assert.expected[0].type)
                    {
                    case RawValueType.f32:
                        Assert.IsTrue(float.IsNaN((float)result !), $"{command.line}: Expected NaN, got {result}");
                        continue;

                    case RawValueType.f64:
                        Assert.IsTrue(double.IsNaN((double)result !), $"{command.line}: Expected NaN, got {result}");
                        continue;

                    default:
                        throw new AssertFailedException($"{assert.expected[0].type} doesn't support NaN checks.");
                    }

                case AssertInvalid assert:
                    trapExpected = () =>
                    {
                        try
                        {
                            Compile.FromBinary <TExports>(Path.Combine(pathBase, assert.filename));
                        }
                        catch (TargetInvocationException x) when(x.InnerException != null)
                        {
                            ExceptionDispatchInfo.Capture(x.InnerException).Throw();
                        }
                    };
                    switch (assert.text)
                    {
                    case "type mismatch":
                        try
                        {
                            trapExpected();
                        }
                        catch (StackTypeInvalidException)
                        {
                            continue;
                        }
                        catch (StackTooSmallException)
                        {
                            continue;
                        }
                        catch (ModuleLoadException)
                        {
                            continue;
                        }
                        catch (StackSizeIncorrectException)
                        {
                            continue;
                        }
                        catch (LabelTypeMismatchException)
                        {
                            continue;
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line} threw an unexpected exception of type {x.GetType().Name}.");
                        }
                        throw new AssertFailedException($"{command.line} should have thrown an exception but did not.");

                    case "alignment must not be larger than natural":
                    case "global is immutable":
                        Assert.ThrowsException <CompilerException>(trapExpected, $"{command.line}");
                        continue;

                    case "unknown memory 0":
                    case "constant expression required":
                    case "duplicate export name":
                    case "unknown table":
                    case "unknown local":
                    case "multiple memories":
                    case "size minimum must not be greater than maximum":
                    case "memory size must be at most 65536 pages (4GiB)":
                    case "unknown label":
                    case "invalid result arity":
                    case "unknown type":
                        Assert.ThrowsException <ModuleLoadException>(trapExpected, $"{command.line}");
                        continue;

                    case "unknown global":
                    case "unknown memory":
                    case "unknown function":
                    case "unknown table 0":
                        try
                        {
                            trapExpected();
                        }
                        catch (CompilerException)
                        {
                            continue;
                        }
                        catch (ModuleLoadException)
                        {
                            continue;
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line} threw an unexpected exception of type {x.GetType().Name}.");
                        }
                        throw new AssertFailedException($"{command.line} should have thrown an exception but did not.");

                    case "multiple tables":
                        Assert.ThrowsException <ModuleLoadException>(trapExpected, $"{command.line}");
                        continue;

                    default:
                        throw new AssertFailedException($"{command.line}: {assert.text} doesn't have a test procedure set up.");
                    }

                case AssertTrap assert:
                    trapExpected = () =>
                    {
                        GetMethod(assert.action, out methodInfo, out obj);
                        try
                        {
                            assert.action.Call(methodInfo, obj);
                        }
                        catch (TargetInvocationException x) when(x.InnerException != null)
                        {
                            ExceptionDispatchInfo.Capture(x.InnerException).Throw();
                        }
                    };

                    switch (assert.text)
                    {
                    case "integer divide by zero":
                        Assert.ThrowsException <DivideByZeroException>(trapExpected, $"{command.line}");
                        continue;

                    case "integer overflow":
                        Assert.ThrowsException <OverflowException>(trapExpected, $"{command.line}");
                        continue;

                    case "out of bounds memory access":
                        try
                        {
                            trapExpected();
                        }
                        catch (MemoryAccessOutOfRangeException)
                        {
                            continue;
                        }
                        catch (OverflowException)
                        {
                            continue;
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line} threw an unexpected exception of type {x.GetType().Name}.");
                        }
                        throw new AssertFailedException($"{command.line} should have thrown an exception but did not.");

                    case "invalid conversion to integer":
                        Assert.ThrowsException <OverflowException>(trapExpected, $"{command.line}");
                        continue;

                    case "undefined element":
                    case "uninitialized element 7":
                        try
                        {
                            trapExpected();
                            throw new AssertFailedException($"{command.line}: Expected ModuleLoadException or IndexOutOfRangeException, but no exception was thrown.");
                        }
                        catch (ModuleLoadException)
                        {
                        }
                        catch (IndexOutOfRangeException)
                        {
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line}: Expected ModuleLoadException or IndexOutOfRangeException, but received {x.GetType().Name}.");
                        }
                        continue;

                    case "indirect call type mismatch":
                        Assert.ThrowsException <InvalidCastException>(trapExpected, $"{command.line}");
                        continue;

                    case "unreachable":
                        Assert.ThrowsException <UnreachableException>(trapExpected, $"{command.line}");
                        continue;

                    case "uninitialized element":
                    case "uninitialized":
                        try
                        {
                            trapExpected();
                            throw new AssertFailedException($"{command.line}: Expected KeyNotFoundException or NullReferenceException, but no exception was thrown.");
                        }
                        catch (KeyNotFoundException)
                        {
                        }
                        catch (NullReferenceException)
                        {
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line}: Expected KeyNotFoundException or NullReferenceException, but received {x.GetType().Name}.");
                        }
                        continue;

                    case "undefined":
                        try
                        {
                            trapExpected();
                            throw new AssertFailedException($"{command.line}: Expected KeyNotFoundException or IndexOutOfRangeException, but no exception was thrown.");
                        }
                        catch (KeyNotFoundException)
                        {
                        }
                        catch (IndexOutOfRangeException)
                        {
                        }
                        catch (Exception x)
                        {
                            throw new AssertFailedException($"{command.line}: Expected KeyNotFoundException or IndexOutOfRangeException, but received {x.GetType().Name}.");
                        }
                        continue;

                    case "indirect call":
                        Assert.ThrowsException <InvalidCastException>(trapExpected, $"{command.line}");
                        continue;

                    default:
                        throw new AssertFailedException($"{command.line}: {assert.text} doesn't have a test procedure set up.");
                    }

                case AssertMalformed assert:
                    continue;     // Not writing a WAT parser.

                case AssertExhaustion assert:
                    trapExpected = () =>
                    {
                        GetMethod(assert.action, out methodInfo, out obj);
                        try
                        {
                            assert.action.Call(methodInfo, obj);
                        }
                        catch (TargetInvocationException x) when(x.InnerException != null)
                        {
                            ExceptionDispatchInfo.Capture(x.InnerException).Throw();
                        }
                    };

                    switch (assert.text)
                    {
                    case "call stack exhausted":
                        Assert.ThrowsException <StackOverflowException>(trapExpected, $"{command.line}");
                        continue;

                    default:
                        throw new AssertFailedException($"{command.line}: {assert.text} doesn't have a test procedure set up.");
                    }

                case AssertUnlinkable assert:
                    trapExpected = () =>
                    {
                        try
                        {
                            Compile.FromBinary <TExports>(Path.Combine(pathBase, assert.filename))(imports);
                        }
                        catch (TargetInvocationException x) when(x.InnerException != null
#if DEBUG
                                                                 && !System.Diagnostics.Debugger.IsAttached
#endif
                                                                 )
                        {
                            ExceptionDispatchInfo.Capture(x.InnerException).Throw();
                        }
                    };
                    switch (assert.text)
                    {
                    case "data segment does not fit":
                    case "elements segment does not fit":
                        try
                        {
                            trapExpected();
                            throw new AssertFailedException($"{command.line}: Expected ModuleLoadException, MemoryAccessOutOfRangeException or OverflowException, but no exception was thrown.");
                        }
                        catch (Exception x) when(x is ModuleLoadException || x is MemoryAccessOutOfRangeException || x is OverflowException)
                        {
                        }
                        continue;

                    case "unknown import":
                    case "incompatible import type":
                        Assert.ThrowsException <ImportException>(trapExpected, $"{command.line}");
                        continue;

                    default:
                        throw new AssertFailedException($"{command.line}: {assert.text} doesn't have a test procedure set up.");
                    }

                case Register register:
                    Assert.IsNotNull(
                        moduleMethodsByName[register.@as] = register.name != null ? moduleMethodsByName[register.name] : methodsByName !,
                        $"{command.line} tried to register null as a module method source.");
                    Assert.IsNotNull(exports);
                    imports.AddFromExports(register.@as, exports !);
                    continue;

                case AssertUninstantiable assert:
                    trapExpected = () =>
                    {
                        try
                        {
                            Compile.FromBinary <TExports>(Path.Combine(pathBase, assert.filename));
                        }
                        catch (TargetInvocationException x) when(x.InnerException != null)
                        {
                            ExceptionDispatchInfo.Capture(x.InnerException).Throw();
                        }
                    };
                    switch (assert.text)
                    {
                    case "unreachable":
                        Assert.ThrowsException <ModuleLoadException>(trapExpected, $"{command.line}");
                        continue;

                    default:
                        throw new AssertFailedException($"{command.line}: {assert.text} doesn't have a test procedure set up.");
                    }

                default:
                    throw new AssertFailedException($"{command.line}: {command} doesn't have a test procedure set up.");
                }
            }
            catch (Exception x) when(!System.Diagnostics.Debugger.IsAttached && !(x is AssertFailedException))
            {
                throw new AssertFailedException($"{command.line}: {x}", x);
            }
        }

        if (skip != null)
        {
            Assert.Inconclusive("Some scenarios were skipped.");
        }
    }