From 89dbc35fca4c994d5ff1c076e1c564519c687f0c Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Fri, 16 Oct 2020 23:16:42 +0000 Subject: [PATCH] [wasm] Wasm function imports. I switched from a WasmImports object to a builder pattern: module.instantiate().addMemory(...).addFunction(...).build(); Bug: https://github.com/dart-lang/sdk/issues/37882 Change-Id: I381aa0f7df1fa006ce8d051cd5b4a1bcc1835e46 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/167460 Reviewed-by: Ryan Macnak Commit-Queue: Liam Appelbe --- DEPS | 2 +- pkg/wasm/lib/src/function.dart | 3 +- pkg/wasm/lib/src/module.dart | 166 +++++++++++++++--- pkg/wasm/lib/src/runtime.dart | 74 ++++++-- .../lib/src/tools/generate_ffi_boilerplate.py | 3 + pkg/wasm/lib/src/tools/runtime_template.dart | 64 +++++-- .../lib/src/tools/wasmer_api_template.dart | 13 ++ pkg/wasm/lib/src/wasmer_api.dart | 39 ++++ tests/lib/wasm/basic_test.dart | 2 +- tests/lib/wasm/fn_call_error_test.dart | 2 +- tests/lib/wasm/fn_import_error_test.dart | 45 ++--- tests/lib/wasm/fn_import_test.dart | 12 +- tests/lib/wasm/hello_world_test.dart | 40 ++--- tests/lib/wasm/numerics_test.dart | 2 +- tests/lib/wasm/void_test.dart | 2 +- tests/lib_2/wasm/basic_test.dart | 2 +- tests/lib_2/wasm/fn_call_error_test.dart | 2 +- tests/lib_2/wasm/fn_import_error_test.dart | 45 ++--- tests/lib_2/wasm/fn_import_test.dart | 12 +- tests/lib_2/wasm/hello_world_test.dart | 38 ++-- tests/lib_2/wasm/numerics_test.dart | 2 +- tests/lib_2/wasm/void_test.dart | 2 +- third_party/wasmer/Cargo.toml | 4 +- 23 files changed, 407 insertions(+), 169 deletions(-) diff --git a/DEPS b/DEPS index dcadfea102b..122c1785045 100644 --- a/DEPS +++ b/DEPS @@ -133,7 +133,7 @@ vars = { "quiver-dart_tag": "246e754fe45cecb6aa5f3f13b4ed61037ff0d784", "resource_rev": "f8e37558a1c4f54550aa463b88a6a831e3e33cd6", "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8", - "rust_revision": "cbe7c5ce705896d4e22bf6096590bc1f17993b78", + "rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244", "shelf_static_rev": "v0.2.8", "shelf_packages_handler_tag": "2.0.0", "shelf_proxy_tag": "0.1.0+7", diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart index e9a23c5c5ef..8cc2c323d78 100644 --- a/pkg/wasm/lib/src/function.dart +++ b/pkg/wasm/lib/src/function.dart @@ -28,8 +28,7 @@ class WasmFunction { } String toString() { - return "${wasmerValKindName(_returnType)} $_name" + - "(${_argTypes.map(wasmerValKindName).join(", ")})"; + return WasmRuntime.getSignatureString(_name, _argTypes, _returnType); } bool _fillArg(dynamic arg, int i) { diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart index a2a9944d000..349757a9781 100644 --- a/pkg/wasm/lib/src/module.dart +++ b/pkg/wasm/lib/src/module.dart @@ -19,9 +19,10 @@ class WasmModule { _module = WasmRuntime().compile(_store, data); } - /// Instantiate the module with the given imports. - WasmInstance instantiate(WasmImports imports) { - return WasmInstance(_store, _module, imports); + /// Returns a WasmInstanceBuilder that is used to add all the imports that the + /// module needs, and then instantiate it. + WasmInstanceBuilder instantiate() { + return WasmInstanceBuilder(this); } /// Create a new memory with the given number of initial pages, and optional @@ -37,47 +38,166 @@ class WasmModule { var runtime = WasmRuntime(); var imports = runtime.importDescriptors(_module); for (var imp in imports) { - var kind = wasmerExternKindName(imp.kind); - description.write('import $kind: ${imp.moduleName}::${imp.name}\n'); + description.write("import $imp\n"); } var exports = runtime.exportDescriptors(_module); for (var exp in exports) { - var kind = wasmerExternKindName(exp.kind); - description.write('export $kind: ${exp.name}\n'); + description.write("export $exp\n"); } return description.toString(); } } -/// WasmImports holds all the imports for a WasmInstance. -class WasmImports { - Pointer> _imports; - int _capacity; - int _length; +Pointer _wasmFnImportTrampoline(Pointer<_WasmFnImport> imp, + Pointer args, Pointer results) { + try { + _WasmFnImport._call(imp, args, results); + } catch (e) { + // TODO: Use WasmerTrap to handle this case. For now just print the + // exception (if we ignore it, FFI will silently return a default result). + print(e); + } + return nullptr; +} - /// Create an imports object. - WasmImports([this._capacity = 4]) - : _imports = allocate>(count: _capacity), - _length = 0 {} +void _wasmFnImportFinalizer(Pointer<_WasmFnImport> imp) { + _wasmFnImportToFn.remove(imp.address); + free(imp); +} - /// Returns the number of imports. - int get length => _length; +final _wasmFnImportTrampolineNative = Pointer.fromFunction< + Pointer Function(Pointer<_WasmFnImport>, Pointer, + Pointer)>(_wasmFnImportTrampoline); +final _wasmFnImportToFn = {}; +final _wasmFnImportFinalizerNative = + Pointer.fromFunction)>( + _wasmFnImportFinalizer); + +class _WasmFnImport extends Struct { + @Int32() + external int numArgs; + + @Int32() + external int returnType; + + static void _call(Pointer<_WasmFnImport> imp, Pointer rawArgs, + Pointer rawResult) { + Function fn = _wasmFnImportToFn[imp.address] as Function; + var args = []; + for (var i = 0; i < imp.ref.numArgs; ++i) { + args.add(rawArgs[i].toDynamic); + } + var result = Function.apply(fn, args); + switch (imp.ref.returnType) { + case WasmerValKindI32: + rawResult.ref.i32 = result; + break; + case WasmerValKindI64: + rawResult.ref.i64 = result; + break; + case WasmerValKindF32: + rawResult.ref.f32 = result; + break; + case WasmerValKindF64: + rawResult.ref.f64 = result; + break; + case WasmerValKindVoid: + // Do nothing. + } + } +} + +/// WasmInstanceBuilder is used collect all the imports that a WasmModule +/// requires before it is instantiated. +class WasmInstanceBuilder { + WasmModule _module; + late List _importDescs; + Map _importIndex; + late Pointer> _imports; + + WasmInstanceBuilder(this._module) : _importIndex = {} { + _importDescs = WasmRuntime().importDescriptors(_module._module); + _imports = allocate>(count: _importDescs.length); + for (var i = 0; i < _importDescs.length; ++i) { + var imp = _importDescs[i]; + _importIndex["${imp.moduleName}::${imp.name}"] = i; + _imports[i] = nullptr; + } + } + + int _getIndex(String moduleName, String name) { + var index = _importIndex["${moduleName}::${name}"]; + if (index == null) { + throw Exception("Import not found: ${moduleName}::${name}"); + } else if (_imports[index] != nullptr) { + throw Exception("Import already filled: ${moduleName}::${name}"); + } else { + return index; + } + } + + /// Add a WasmMemory to the imports. + WasmInstanceBuilder addMemory( + String moduleName, String name, WasmMemory memory) { + var index = _getIndex(moduleName, name); + var imp = _importDescs[index]; + if (imp.kind != WasmerExternKindMemory) { + throw Exception("Import is not a memory: $imp"); + } + _imports[index] = WasmRuntime().memoryToExtern(memory._mem); + return this; + } + + /// Add a function to the imports. + WasmInstanceBuilder addFunction(String moduleName, String name, Function fn) { + var index = _getIndex(moduleName, name); + var imp = _importDescs[index]; + var runtime = WasmRuntime(); + + if (imp.kind != WasmerExternKindFunction) { + throw Exception("Import is not a function: $imp"); + } + + var argTypes = runtime.getArgTypes(imp.funcType); + var returnType = runtime.getReturnType(imp.funcType); + var wasmFnImport = allocate<_WasmFnImport>(); + wasmFnImport.ref.numArgs = argTypes.length; + wasmFnImport.ref.returnType = returnType; + _wasmFnImportToFn[wasmFnImport.address] = fn; + var fnImp = runtime.newFunc( + _module._store, + imp.funcType, + _wasmFnImportTrampolineNative, + wasmFnImport, + _wasmFnImportFinalizerNative); + _imports[index] = runtime.functionToExtern(fnImp); + return this; + } + + /// Build the module instance. + WasmInstance build() { + for (var i = 0; i < _importDescs.length; ++i) { + if (_imports[i] == nullptr) { + throw Exception("Missing import: ${_importDescs[i]}"); + } + } + return WasmInstance(_module, _imports); + } } /// WasmInstance is an instantiated WasmModule. class WasmInstance { - Pointer _store; - Pointer _module; + WasmModule _module; Pointer _instance; Pointer? _exportedMemory; Map _functions = {}; - WasmInstance(this._store, this._module, WasmImports imports) + WasmInstance(this._module, Pointer> imports) : _instance = WasmRuntime() - .instantiate(_store, _module, imports._imports, imports.length) { + .instantiate(_module._store, _module._module, imports) { var runtime = WasmRuntime(); var exports = runtime.exports(_instance); - var exportDescs = runtime.exportDescriptors(_module); + var exportDescs = runtime.exportDescriptors(_module._module); assert(exports.ref.length == exportDescs.length); for (var i = 0; i < exports.ref.length; ++i) { var e = exports.ref.data[i]; diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart index 6f092083d6c..f3908915e78 100644 --- a/pkg/wasm/lib/src/runtime.dart +++ b/pkg/wasm/lib/src/runtime.dart @@ -20,6 +20,18 @@ class WasmImportDescriptor { String name; Pointer funcType; WasmImportDescriptor(this.kind, this.moduleName, this.name, this.funcType); + + String toString() { + var kindName = wasmerExternKindName(kind); + if (kind == WasmerExternKindFunction) { + var runtime = WasmRuntime(); + var sig = WasmRuntime.getSignatureString("${moduleName}::${name}", + runtime.getArgTypes(funcType), runtime.getReturnType(funcType)); + return "$kindName: $sig"; + } else { + return "$kindName: ${moduleName}::${name}"; + } + } } class WasmExportDescriptor { @@ -27,6 +39,18 @@ class WasmExportDescriptor { String name; Pointer funcType; WasmExportDescriptor(this.kind, this.name, this.funcType); + + String toString() { + var kindName = wasmerExternKindName(kind); + if (kind == WasmerExternKindFunction) { + var runtime = WasmRuntime(); + var sig = WasmRuntime.getSignatureString( + name, runtime.getArgTypes(funcType), runtime.getReturnType(funcType)); + return "$kindName: $sig"; + } else { + return "$kindName: ${name}"; + } + } } class WasmRuntime { @@ -57,8 +81,10 @@ class WasmRuntime { late WasmerExterntypeAsFunctypeFn _externtype_as_functype; late WasmerExterntypeDeleteFn _externtype_delete; late WasmerExterntypeKindFn _externtype_kind; + late WasmerFuncAsExternFn _func_as_extern; late WasmerFuncCallFn _func_call; late WasmerFuncDeleteFn _func_delete; + late WasmerFuncNewWithEnvFn _func_new_with_env; late WasmerFunctypeDeleteFn _functype_delete; late WasmerFunctypeParamsFn _functype_params; late WasmerFunctypeResultsFn _functype_results; @@ -72,6 +98,7 @@ class WasmRuntime { late WasmerInstanceDeleteFn _instance_delete; late WasmerInstanceExportsFn _instance_exports; late WasmerInstanceNewFn _instance_new; + late WasmerMemoryAsExternFn _memory_as_extern; late WasmerMemoryDataFn _memory_data; late WasmerMemoryDataSizeFn _memory_data_size; late WasmerMemoryDeleteFn _memory_delete; @@ -199,11 +226,16 @@ class WasmRuntime { WasmerExterntypeDeleteFn>('wasm_externtype_delete'); _externtype_kind = _lib.lookupFunction('wasm_externtype_kind'); + _func_as_extern = + _lib.lookupFunction( + 'wasm_func_as_extern'); _func_call = _lib.lookupFunction( 'wasm_func_call'); _func_delete = _lib.lookupFunction( 'wasm_func_delete'); + _func_new_with_env = _lib.lookupFunction('wasm_func_new_with_env'); _functype_delete = _lib.lookupFunction('wasm_functype_delete'); _functype_params = _lib.lookupFunction( 'wasm_instance_new'); + _memory_as_extern = _lib.lookupFunction('wasm_memory_as_extern'); _memory_data = _lib.lookupFunction( 'wasm_memory_data'); @@ -363,20 +397,8 @@ class WasmRuntime { return imps; } - Pointer instantiate( - Pointer store, - Pointer module, - Pointer> imports, - int numImports) { - var importsVec = allocate(); - _module_imports(module, importsVec); - if (importsVec.ref.length != numImports) { - throw Exception( - "Wrong number of imports. Expected ${importsVec.ref.length} but " + - "found $numImports."); - } - free(importsVec); - + Pointer instantiate(Pointer store, + Pointer module, Pointer> imports) { var instancePtr = _instance_new(store, module, imports, nullptr); if (instancePtr == nullptr) { throw Exception("Wasm module instantiation failed"); @@ -399,6 +421,10 @@ class WasmRuntime { return _extern_as_func(extern); } + Pointer functionToExtern(Pointer func) { + return _func_as_extern(func); + } + List getArgTypes(Pointer funcType) { var types = []; var args = _functype_params(funcType); @@ -427,6 +453,10 @@ class WasmRuntime { return _extern_as_memory(extern); } + Pointer memoryToExtern(Pointer memory) { + return _memory_as_extern(memory); + } + Pointer newMemory( Pointer store, int pages, int? maxPages) { var limPtr = allocate(); @@ -456,4 +486,20 @@ class WasmRuntime { Uint8List memoryView(Pointer memory) { return _memory_data(memory).asTypedList(_memory_data_size(memory)); } + + Pointer newFunc( + Pointer store, + Pointer funcType, + Pointer func, + Pointer env, + Pointer finalizer) { + return _func_new_with_env( + store, funcType, func.cast(), env.cast(), finalizer.cast()); + } + + static String getSignatureString( + String name, List argTypes, int returnType) { + return "${wasmerValKindName(returnType)} $name" + + "(${argTypes.map(wasmerValKindName).join(", ")})"; + } } diff --git a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py index cf9621c4adb..94ed9652c45 100755 --- a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py +++ b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py @@ -283,9 +283,12 @@ WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*); WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*); +WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*); WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*); +WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*); WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*); WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*); +WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env( wasm_store_t*, const wasm_functype_t* type, void* fn, void* env, void *finalizer); WASM_API_EXTERN own wasm_trap_t* wasm_func_call(const wasm_func_t*, const wasm_val_t args[], wasm_val_t results[]); WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*); ''' diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart index d40388200a1..280edb5ee10 100644 --- a/pkg/wasm/lib/src/tools/runtime_template.dart +++ b/pkg/wasm/lib/src/tools/runtime_template.dart @@ -18,6 +18,18 @@ class WasmImportDescriptor { String name; Pointer funcType; WasmImportDescriptor(this.kind, this.moduleName, this.name, this.funcType); + + String toString() { + var kindName = wasmerExternKindName(kind); + if (kind == WasmerExternKindFunction) { + var runtime = WasmRuntime(); + var sig = WasmRuntime.getSignatureString("${moduleName}::${name}", + runtime.getArgTypes(funcType), runtime.getReturnType(funcType)); + return "$kindName: $sig"; + } else { + return "$kindName: ${moduleName}::${name}"; + } + } } class WasmExportDescriptor { @@ -25,6 +37,18 @@ class WasmExportDescriptor { String name; Pointer funcType; WasmExportDescriptor(this.kind, this.name, this.funcType); + + String toString() { + var kindName = wasmerExternKindName(kind); + if (kind == WasmerExternKindFunction) { + var runtime = WasmRuntime(); + var sig = WasmRuntime.getSignatureString( + name, runtime.getArgTypes(funcType), runtime.getReturnType(funcType)); + return "$kindName: $sig"; + } else { + return "$kindName: ${name}"; + } + } } class WasmRuntime { @@ -147,20 +171,8 @@ class WasmRuntime { return imps; } - Pointer instantiate( - Pointer store, - Pointer module, - Pointer> imports, - int numImports) { - var importsVec = allocate(); - _module_imports(module, importsVec); - if (importsVec.ref.length != numImports) { - throw Exception( - "Wrong number of imports. Expected ${importsVec.ref.length} but " + - "found $numImports."); - } - free(importsVec); - + Pointer instantiate(Pointer store, + Pointer module, Pointer> imports) { var instancePtr = _instance_new(store, module, imports, nullptr); if (instancePtr == nullptr) { throw Exception("Wasm module instantiation failed"); @@ -183,6 +195,10 @@ class WasmRuntime { return _extern_as_func(extern); } + Pointer functionToExtern(Pointer func) { + return _func_as_extern(func); + } + List getArgTypes(Pointer funcType) { var types = []; var args = _functype_params(funcType); @@ -211,6 +227,10 @@ class WasmRuntime { return _extern_as_memory(extern); } + Pointer memoryToExtern(Pointer memory) { + return _memory_as_extern(memory); + } + Pointer newMemory( Pointer store, int pages, int? maxPages) { var limPtr = allocate(); @@ -240,4 +260,20 @@ class WasmRuntime { Uint8List memoryView(Pointer memory) { return _memory_data(memory).asTypedList(_memory_data_size(memory)); } + + Pointer newFunc( + Pointer store, + Pointer funcType, + Pointer func, + Pointer env, + Pointer finalizer) { + return _func_new_with_env( + store, funcType, func.cast(), env.cast(), finalizer.cast()); + } + + static String getSignatureString( + String name, List argTypes, int returnType) { + return "${wasmerValKindName(returnType)} $name" + + "(${argTypes.map(wasmerValKindName).join(", ")})"; + } } diff --git a/pkg/wasm/lib/src/tools/wasmer_api_template.dart b/pkg/wasm/lib/src/tools/wasmer_api_template.dart index 6a7717151ed..62c2ac09c74 100644 --- a/pkg/wasm/lib/src/tools/wasmer_api_template.dart +++ b/pkg/wasm/lib/src/tools/wasmer_api_template.dart @@ -86,6 +86,19 @@ class WasmerVal extends Struct { bool get isI64 => kind == WasmerValKindI64; bool get isF32 => kind == WasmerValKindF32; bool get isF64 => kind == WasmerValKindF64; + + dynamic get toDynamic { + switch (kind) { + case WasmerValKindI32: + return i32; + case WasmerValKindI64: + return i64; + case WasmerValKindF32: + return f32; + case WasmerValKindF64: + return f64; + } + } } // wasmer_limits_t diff --git a/pkg/wasm/lib/src/wasmer_api.dart b/pkg/wasm/lib/src/wasmer_api.dart index ad8219dbaeb..95f244f7bcd 100644 --- a/pkg/wasm/lib/src/wasmer_api.dart +++ b/pkg/wasm/lib/src/wasmer_api.dart @@ -88,6 +88,19 @@ class WasmerVal extends Struct { bool get isI64 => kind == WasmerValKindI64; bool get isF32 => kind == WasmerValKindF32; bool get isF64 => kind == WasmerValKindF64; + + dynamic get toDynamic { + switch (kind) { + case WasmerValKindI32: + return i32; + case WasmerValKindI64: + return i64; + case WasmerValKindF32: + return f32; + case WasmerValKindF64: + return f64; + } + } } // wasmer_limits_t @@ -316,6 +329,12 @@ typedef NativeWasmerExterntypeKindFn = Uint8 Function( Pointer); typedef WasmerExterntypeKindFn = int Function(Pointer); +// wasm_func_as_extern +typedef NativeWasmerFuncAsExternFn = Pointer Function( + Pointer); +typedef WasmerFuncAsExternFn = Pointer Function( + Pointer); + // wasm_func_call typedef NativeWasmerFuncCallFn = Pointer Function( Pointer, Pointer, Pointer); @@ -326,6 +345,20 @@ typedef WasmerFuncCallFn = Pointer Function( typedef NativeWasmerFuncDeleteFn = Void Function(Pointer); typedef WasmerFuncDeleteFn = void Function(Pointer); +// wasm_func_new_with_env +typedef NativeWasmerFuncNewWithEnvFn = Pointer Function( + Pointer, + Pointer, + Pointer, + Pointer, + Pointer); +typedef WasmerFuncNewWithEnvFn = Pointer Function( + Pointer, + Pointer, + Pointer, + Pointer, + Pointer); + // wasm_functype_delete typedef NativeWasmerFunctypeDeleteFn = Void Function(Pointer); typedef WasmerFunctypeDeleteFn = void Function(Pointer); @@ -406,6 +439,12 @@ typedef WasmerInstanceNewFn = Pointer Function( Pointer>, Pointer>); +// wasm_memory_as_extern +typedef NativeWasmerMemoryAsExternFn = Pointer Function( + Pointer); +typedef WasmerMemoryAsExternFn = Pointer Function( + Pointer); + // wasm_memory_data typedef NativeWasmerMemoryDataFn = Pointer Function( Pointer); diff --git a/tests/lib/wasm/basic_test.dart b/tests/lib/wasm/basic_test.dart index da2fb9a0c2a..309f94328a3 100644 --- a/tests/lib/wasm/basic_test.dart +++ b/tests/lib/wasm/basic_test.dart @@ -20,7 +20,7 @@ void main() { 0x7e, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var fn = inst.lookupFunction("square"); int n = fn(1234); diff --git a/tests/lib/wasm/fn_call_error_test.dart b/tests/lib/wasm/fn_call_error_test.dart index 0c747686e2a..641f91597a1 100644 --- a/tests/lib/wasm/fn_call_error_test.dart +++ b/tests/lib/wasm/fn_call_error_test.dart @@ -20,7 +20,7 @@ void main() { 0x7e, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var fn = inst.lookupFunction("square"); Expect.throwsArgumentError(() => fn()); diff --git a/tests/lib/wasm/fn_import_error_test.dart b/tests/lib/wasm/fn_import_error_test.dart index 40466fb4bc3..844c9bfb9f9 100644 --- a/tests/lib/wasm/fn_import_error_test.dart +++ b/tests/lib/wasm/fn_import_error_test.dart @@ -5,7 +5,7 @@ // Test errors thrown by function imports. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -25,36 +25,27 @@ void main() { ]); var mod = WasmModule(data); - var imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - mod.instantiate(imp); - imp = WasmImports(); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Valid instantiation. + var inst = mod.instantiate() + .addFunction( + "env", "someFn", (int a, int b, num c, double d) => 123).build(); - imp = WasmImports() - ..addFunction("env", "someFn", (num a) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Missing imports. + Expect.throws(() => mod.instantiate().build(), (Exception e) => "$e".contains("Missing import")); - imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Wrong kind of import. + Expect.throws(() => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)), (Exception e) => "$e".contains("Import is not a memory")); - imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Wrong namespace. + Expect.throws(() => mod.instantiate().addFunction("foo", "someFn", (int a, int b, num c, double d) => 123).build(), (Exception e) => "$e".contains("Import not found")); - Expect.throwsArgumentError(() => WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123)); + // Wrong name. + Expect.throws(() => mod.instantiate().addFunction("env", "otherFn", (int a, int b, num c, double d) => 123).build(), (Exception e) => "$e".contains("Import not found")); - Expect.throwsArgumentError(() => WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123)); - - imp = WasmImports()..addGlobal("env", "someFn", 123, false); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Already filled. + Expect.throws(() => mod.instantiate() + .addFunction("env", "someFn", (int a, int b, num c, double d) => 123) + .addFunction("env", "someFn", (int a, int b, num c, double d) => 456) + .build(), (Exception e) => "$e".contains("Import already filled")); } diff --git a/tests/lib/wasm/fn_import_test.dart b/tests/lib/wasm/fn_import_test.dart index a9f9bdb1c23..3558c17e4aa 100644 --- a/tests/lib/wasm/fn_import_test.dart +++ b/tests/lib/wasm/fn_import_test.dart @@ -5,7 +5,7 @@ // Test that we can load a wasm module, find a function, and call it. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -25,13 +25,13 @@ void main() { int report_x = -1; int report_y = -1; - var inst = WasmModule(data).instantiate(WasmImports() - ..addFunction("env", "report", (int x, int y) { + var inst = WasmModule(data).instantiate() + .addFunction("env", "report", (int x, int y) { report_x = x; report_y = y; - })); - var fn = inst.lookupFunction("reportStuff"); - fn.call([]); + }).build(); + var fn = inst.lookupFunction("reportStuff"); + fn(); Expect.equals(report_x, 123); Expect.equals(report_y, 456); } diff --git a/tests/lib/wasm/hello_world_test.dart b/tests/lib/wasm/hello_world_test.dart index c4441e33ebd..1dc49e995ef 100644 --- a/tests/lib/wasm/hello_world_test.dart +++ b/tests/lib/wasm/hello_world_test.dart @@ -5,7 +5,7 @@ // Test for hello world built using emscripten with WASI. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -169,7 +169,7 @@ void main() { 0x0b, 0x05, 0x0a, 0xff, 0xff, 0xff, 0xff, ]); - WasmMemory mem = null; + late WasmMemory mem; String out = ""; var getI32 = (int p) { // Read a little-endian I32. @@ -180,26 +180,26 @@ void main() { } return n; }; - var inst = WasmModule(data).instantiate(WasmImports() - ..addFunction( - "wasi_unstable", "fd_write", - (int fd, int iovs, int iovs_len, int unused) { - // iovs points to an array of length iovs_len. Each element is two I32s, - // a char* and a length. - String o = ""; - for (var i = 0; i < iovs_len; ++i) { - var str = getI32(iovs + 8 * i); - var len = getI32(iovs + 4 + 8 * i); - for (var j = 0; j < len; ++j) { - o += String.fromCharCode(mem[str + j]); - } + var inst = WasmModule(data) + .instantiate() + .addFunction("wasi_unstable", "fd_write", + (int fd, int iovs, int iovs_len, int unused) { + // iovs points to an array of length iovs_len. Each element is two I32s, + // a char* and a length. + String o = ""; + for (var i = 0; i < iovs_len; ++i) { + var str = getI32(iovs + 8 * i); + var len = getI32(iovs + 4 + 8 * i); + for (var j = 0; j < len; ++j) { + o += String.fromCharCode(mem[str + j]); } - out += o; - return o.length; - })); + } + out += o; + return o.length; + }).build(); mem = inst.memory; - var fn = inst.lookupFunction("_start"); - fn.call([]); + var fn = inst.lookupFunction("_start"); + fn(); Expect.equals("hello, world!\n", out); } diff --git a/tests/lib/wasm/numerics_test.dart b/tests/lib/wasm/numerics_test.dart index 158549a73a8..eba9aaa9fa2 100644 --- a/tests/lib/wasm/numerics_test.dart +++ b/tests/lib/wasm/numerics_test.dart @@ -29,7 +29,7 @@ void main() { 0x01, 0x92, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var addI64 = inst.lookupFunction("addI64"); var addI32 = inst.lookupFunction("addI32"); var addF64 = inst.lookupFunction("addF64"); diff --git a/tests/lib/wasm/void_test.dart b/tests/lib/wasm/void_test.dart index fe946937415..aba9c655fde 100644 --- a/tests/lib/wasm/void_test.dart +++ b/tests/lib/wasm/void_test.dart @@ -25,7 +25,7 @@ void main() { 0x80, 0x08, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var setFn = inst.lookupFunction("set"); var getFn = inst.lookupFunction("get"); Expect.isNull(setFn(123, 456)); diff --git a/tests/lib_2/wasm/basic_test.dart b/tests/lib_2/wasm/basic_test.dart index da2fb9a0c2a..309f94328a3 100644 --- a/tests/lib_2/wasm/basic_test.dart +++ b/tests/lib_2/wasm/basic_test.dart @@ -20,7 +20,7 @@ void main() { 0x7e, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var fn = inst.lookupFunction("square"); int n = fn(1234); diff --git a/tests/lib_2/wasm/fn_call_error_test.dart b/tests/lib_2/wasm/fn_call_error_test.dart index 0c747686e2a..641f91597a1 100644 --- a/tests/lib_2/wasm/fn_call_error_test.dart +++ b/tests/lib_2/wasm/fn_call_error_test.dart @@ -20,7 +20,7 @@ void main() { 0x7e, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var fn = inst.lookupFunction("square"); Expect.throwsArgumentError(() => fn()); diff --git a/tests/lib_2/wasm/fn_import_error_test.dart b/tests/lib_2/wasm/fn_import_error_test.dart index 40466fb4bc3..844c9bfb9f9 100644 --- a/tests/lib_2/wasm/fn_import_error_test.dart +++ b/tests/lib_2/wasm/fn_import_error_test.dart @@ -5,7 +5,7 @@ // Test errors thrown by function imports. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -25,36 +25,27 @@ void main() { ]); var mod = WasmModule(data); - var imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - mod.instantiate(imp); - imp = WasmImports(); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Valid instantiation. + var inst = mod.instantiate() + .addFunction( + "env", "someFn", (int a, int b, num c, double d) => 123).build(); - imp = WasmImports() - ..addFunction("env", "someFn", (num a) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Missing imports. + Expect.throws(() => mod.instantiate().build(), (Exception e) => "$e".contains("Missing import")); - imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Wrong kind of import. + Expect.throws(() => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)), (Exception e) => "$e".contains("Import is not a memory")); - imp = WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Wrong namespace. + Expect.throws(() => mod.instantiate().addFunction("foo", "someFn", (int a, int b, num c, double d) => 123).build(), (Exception e) => "$e".contains("Import not found")); - Expect.throwsArgumentError(() => WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123)); + // Wrong name. + Expect.throws(() => mod.instantiate().addFunction("env", "otherFn", (int a, int b, num c, double d) => 123).build(), (Exception e) => "$e".contains("Import not found")); - Expect.throwsArgumentError(() => WasmImports() - ..addFunction( - "env", "someFn", (num a, num b, num c, num d) => 123)); - - imp = WasmImports()..addGlobal("env", "someFn", 123, false); - Expect.throwsArgumentError(() => mod.instantiate(imp)); + // Already filled. + Expect.throws(() => mod.instantiate() + .addFunction("env", "someFn", (int a, int b, num c, double d) => 123) + .addFunction("env", "someFn", (int a, int b, num c, double d) => 456) + .build(), (Exception e) => "$e".contains("Import already filled")); } diff --git a/tests/lib_2/wasm/fn_import_test.dart b/tests/lib_2/wasm/fn_import_test.dart index a9f9bdb1c23..3558c17e4aa 100644 --- a/tests/lib_2/wasm/fn_import_test.dart +++ b/tests/lib_2/wasm/fn_import_test.dart @@ -5,7 +5,7 @@ // Test that we can load a wasm module, find a function, and call it. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -25,13 +25,13 @@ void main() { int report_x = -1; int report_y = -1; - var inst = WasmModule(data).instantiate(WasmImports() - ..addFunction("env", "report", (int x, int y) { + var inst = WasmModule(data).instantiate() + .addFunction("env", "report", (int x, int y) { report_x = x; report_y = y; - })); - var fn = inst.lookupFunction("reportStuff"); - fn.call([]); + }).build(); + var fn = inst.lookupFunction("reportStuff"); + fn(); Expect.equals(report_x, 123); Expect.equals(report_y, 456); } diff --git a/tests/lib_2/wasm/hello_world_test.dart b/tests/lib_2/wasm/hello_world_test.dart index c4441e33ebd..b3ef2a599f6 100644 --- a/tests/lib_2/wasm/hello_world_test.dart +++ b/tests/lib_2/wasm/hello_world_test.dart @@ -5,7 +5,7 @@ // Test for hello world built using emscripten with WASI. import "package:expect/expect.dart"; -import "dart:wasm"; +import "package:wasm/wasm.dart"; import "dart:typed_data"; void main() { @@ -180,26 +180,26 @@ void main() { } return n; }; - var inst = WasmModule(data).instantiate(WasmImports() - ..addFunction( - "wasi_unstable", "fd_write", - (int fd, int iovs, int iovs_len, int unused) { - // iovs points to an array of length iovs_len. Each element is two I32s, - // a char* and a length. - String o = ""; - for (var i = 0; i < iovs_len; ++i) { - var str = getI32(iovs + 8 * i); - var len = getI32(iovs + 4 + 8 * i); - for (var j = 0; j < len; ++j) { - o += String.fromCharCode(mem[str + j]); - } + var inst = WasmModule(data) + .instantiate() + .addFunction("wasi_unstable", "fd_write", + (int fd, int iovs, int iovs_len, int unused) { + // iovs points to an array of length iovs_len. Each element is two I32s, + // a char* and a length. + String o = ""; + for (var i = 0; i < iovs_len; ++i) { + var str = getI32(iovs + 8 * i); + var len = getI32(iovs + 4 + 8 * i); + for (var j = 0; j < len; ++j) { + o += String.fromCharCode(mem[str + j]); } - out += o; - return o.length; - })); + } + out += o; + return o.length; + }).build(); mem = inst.memory; - var fn = inst.lookupFunction("_start"); - fn.call([]); + var fn = inst.lookupFunction("_start"); + fn(); Expect.equals("hello, world!\n", out); } diff --git a/tests/lib_2/wasm/numerics_test.dart b/tests/lib_2/wasm/numerics_test.dart index 158549a73a8..eba9aaa9fa2 100644 --- a/tests/lib_2/wasm/numerics_test.dart +++ b/tests/lib_2/wasm/numerics_test.dart @@ -29,7 +29,7 @@ void main() { 0x01, 0x92, 0x0b, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var addI64 = inst.lookupFunction("addI64"); var addI32 = inst.lookupFunction("addI32"); var addF64 = inst.lookupFunction("addF64"); diff --git a/tests/lib_2/wasm/void_test.dart b/tests/lib_2/wasm/void_test.dart index fe946937415..aba9c655fde 100644 --- a/tests/lib_2/wasm/void_test.dart +++ b/tests/lib_2/wasm/void_test.dart @@ -25,7 +25,7 @@ void main() { 0x80, 0x08, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]); - var inst = WasmModule(data).instantiate(WasmImports()); + var inst = WasmModule(data).instantiate().build(); var setFn = inst.lookupFunction("set"); var getFn = inst.lookupFunction("get"); Expect.isNull(setFn(123, 456)); diff --git a/third_party/wasmer/Cargo.toml b/third_party/wasmer/Cargo.toml index bc52adad6a4..8ec064a8fc1 100644 --- a/third_party/wasmer/Cargo.toml +++ b/third_party/wasmer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "1.0.0-alpha3" +version = "1.0.0-alpha4" [lib] name = "wasmer" @@ -8,6 +8,6 @@ crate-type = ["dylib"] path = "wasmer.rs" [dependencies.wasmer-c-api] -version = "1.0.0-alpha3" +version = "1.0.0-alpha4" default-features = false features = ["jit", "cranelift", "wasi"]