[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 <rmacnak@google.com>
Commit-Queue: Liam Appelbe <liama@google.com>
This commit is contained in:
Liam Appelbe 2020-10-16 23:16:42 +00:00 committed by commit-bot@chromium.org
parent f0052ef52e
commit 89dbc35fca
23 changed files with 407 additions and 169 deletions

2
DEPS
View file

@ -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",

View file

@ -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) {

View file

@ -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<Pointer<WasmerExtern>> _imports;
int _capacity;
int _length;
Pointer<WasmerTrap> _wasmFnImportTrampoline(Pointer<_WasmFnImport> imp,
Pointer<WasmerVal> args, Pointer<WasmerVal> 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<Pointer<WasmerExtern>>(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<WasmerTrap> Function(Pointer<_WasmFnImport>, Pointer<WasmerVal>,
Pointer<WasmerVal>)>(_wasmFnImportTrampoline);
final _wasmFnImportToFn = <int, Function>{};
final _wasmFnImportFinalizerNative =
Pointer.fromFunction<Void Function(Pointer<_WasmFnImport>)>(
_wasmFnImportFinalizer);
class _WasmFnImport extends Struct {
@Int32()
external int numArgs;
@Int32()
external int returnType;
static void _call(Pointer<_WasmFnImport> imp, Pointer<WasmerVal> rawArgs,
Pointer<WasmerVal> 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<WasmImportDescriptor> _importDescs;
Map<String, int> _importIndex;
late Pointer<Pointer<WasmerExtern>> _imports;
WasmInstanceBuilder(this._module) : _importIndex = {} {
_importDescs = WasmRuntime().importDescriptors(_module._module);
_imports = allocate<Pointer<WasmerExtern>>(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<WasmerStore> _store;
Pointer<WasmerModule> _module;
WasmModule _module;
Pointer<WasmerInstance> _instance;
Pointer<WasmerMemory>? _exportedMemory;
Map<String, WasmFunction> _functions = {};
WasmInstance(this._store, this._module, WasmImports imports)
WasmInstance(this._module, Pointer<Pointer<WasmerExtern>> 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];

View file

@ -20,6 +20,18 @@ class WasmImportDescriptor {
String name;
Pointer<WasmerFunctype> 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<WasmerFunctype> 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<NativeWasmerExterntypeKindFn,
WasmerExterntypeKindFn>('wasm_externtype_kind');
_func_as_extern =
_lib.lookupFunction<NativeWasmerFuncAsExternFn, WasmerFuncAsExternFn>(
'wasm_func_as_extern');
_func_call = _lib.lookupFunction<NativeWasmerFuncCallFn, WasmerFuncCallFn>(
'wasm_func_call');
_func_delete =
_lib.lookupFunction<NativeWasmerFuncDeleteFn, WasmerFuncDeleteFn>(
'wasm_func_delete');
_func_new_with_env = _lib.lookupFunction<NativeWasmerFuncNewWithEnvFn,
WasmerFuncNewWithEnvFn>('wasm_func_new_with_env');
_functype_delete = _lib.lookupFunction<NativeWasmerFunctypeDeleteFn,
WasmerFunctypeDeleteFn>('wasm_functype_delete');
_functype_params = _lib.lookupFunction<NativeWasmerFunctypeParamsFn,
@ -235,6 +267,8 @@ class WasmRuntime {
_instance_new =
_lib.lookupFunction<NativeWasmerInstanceNewFn, WasmerInstanceNewFn>(
'wasm_instance_new');
_memory_as_extern = _lib.lookupFunction<NativeWasmerMemoryAsExternFn,
WasmerMemoryAsExternFn>('wasm_memory_as_extern');
_memory_data =
_lib.lookupFunction<NativeWasmerMemoryDataFn, WasmerMemoryDataFn>(
'wasm_memory_data');
@ -363,20 +397,8 @@ class WasmRuntime {
return imps;
}
Pointer<WasmerInstance> instantiate(
Pointer<WasmerStore> store,
Pointer<WasmerModule> module,
Pointer<Pointer<WasmerExtern>> imports,
int numImports) {
var importsVec = allocate<WasmerImporttypeVec>();
_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<WasmerInstance> instantiate(Pointer<WasmerStore> store,
Pointer<WasmerModule> module, Pointer<Pointer<WasmerExtern>> 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<WasmerExtern> functionToExtern(Pointer<WasmerFunc> func) {
return _func_as_extern(func);
}
List<int> getArgTypes(Pointer<WasmerFunctype> funcType) {
var types = <int>[];
var args = _functype_params(funcType);
@ -427,6 +453,10 @@ class WasmRuntime {
return _extern_as_memory(extern);
}
Pointer<WasmerExtern> memoryToExtern(Pointer<WasmerMemory> memory) {
return _memory_as_extern(memory);
}
Pointer<WasmerMemory> newMemory(
Pointer<WasmerStore> store, int pages, int? maxPages) {
var limPtr = allocate<WasmerLimits>();
@ -456,4 +486,20 @@ class WasmRuntime {
Uint8List memoryView(Pointer<WasmerMemory> memory) {
return _memory_data(memory).asTypedList(_memory_data_size(memory));
}
Pointer<WasmerFunc> newFunc(
Pointer<WasmerStore> store,
Pointer<WasmerFunctype> 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<int> argTypes, int returnType) {
return "${wasmerValKindName(returnType)} $name" +
"(${argTypes.map(wasmerValKindName).join(", ")})";
}
}

View file

@ -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*);
'''

View file

@ -18,6 +18,18 @@ class WasmImportDescriptor {
String name;
Pointer<WasmerFunctype> 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<WasmerFunctype> 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<WasmerInstance> instantiate(
Pointer<WasmerStore> store,
Pointer<WasmerModule> module,
Pointer<Pointer<WasmerExtern>> imports,
int numImports) {
var importsVec = allocate<WasmerImporttypeVec>();
_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<WasmerInstance> instantiate(Pointer<WasmerStore> store,
Pointer<WasmerModule> module, Pointer<Pointer<WasmerExtern>> 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<WasmerExtern> functionToExtern(Pointer<WasmerFunc> func) {
return _func_as_extern(func);
}
List<int> getArgTypes(Pointer<WasmerFunctype> funcType) {
var types = <int>[];
var args = _functype_params(funcType);
@ -211,6 +227,10 @@ class WasmRuntime {
return _extern_as_memory(extern);
}
Pointer<WasmerExtern> memoryToExtern(Pointer<WasmerMemory> memory) {
return _memory_as_extern(memory);
}
Pointer<WasmerMemory> newMemory(
Pointer<WasmerStore> store, int pages, int? maxPages) {
var limPtr = allocate<WasmerLimits>();
@ -240,4 +260,20 @@ class WasmRuntime {
Uint8List memoryView(Pointer<WasmerMemory> memory) {
return _memory_data(memory).asTypedList(_memory_data_size(memory));
}
Pointer<WasmerFunc> newFunc(
Pointer<WasmerStore> store,
Pointer<WasmerFunctype> 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<int> argTypes, int returnType) {
return "${wasmerValKindName(returnType)} $name" +
"(${argTypes.map(wasmerValKindName).join(", ")})";
}
}

View file

@ -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

View file

@ -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<WasmerExterntype>);
typedef WasmerExterntypeKindFn = int Function(Pointer<WasmerExterntype>);
// wasm_func_as_extern
typedef NativeWasmerFuncAsExternFn = Pointer<WasmerExtern> Function(
Pointer<WasmerFunc>);
typedef WasmerFuncAsExternFn = Pointer<WasmerExtern> Function(
Pointer<WasmerFunc>);
// wasm_func_call
typedef NativeWasmerFuncCallFn = Pointer<WasmerTrap> Function(
Pointer<WasmerFunc>, Pointer<WasmerVal>, Pointer<WasmerVal>);
@ -326,6 +345,20 @@ typedef WasmerFuncCallFn = Pointer<WasmerTrap> Function(
typedef NativeWasmerFuncDeleteFn = Void Function(Pointer<WasmerFunc>);
typedef WasmerFuncDeleteFn = void Function(Pointer<WasmerFunc>);
// wasm_func_new_with_env
typedef NativeWasmerFuncNewWithEnvFn = Pointer<WasmerFunc> Function(
Pointer<WasmerStore>,
Pointer<WasmerFunctype>,
Pointer<Void>,
Pointer<Void>,
Pointer<Void>);
typedef WasmerFuncNewWithEnvFn = Pointer<WasmerFunc> Function(
Pointer<WasmerStore>,
Pointer<WasmerFunctype>,
Pointer<Void>,
Pointer<Void>,
Pointer<Void>);
// wasm_functype_delete
typedef NativeWasmerFunctypeDeleteFn = Void Function(Pointer<WasmerFunctype>);
typedef WasmerFunctypeDeleteFn = void Function(Pointer<WasmerFunctype>);
@ -406,6 +439,12 @@ typedef WasmerInstanceNewFn = Pointer<WasmerInstance> Function(
Pointer<Pointer<WasmerExtern>>,
Pointer<Pointer<WasmerTrap>>);
// wasm_memory_as_extern
typedef NativeWasmerMemoryAsExternFn = Pointer<WasmerExtern> Function(
Pointer<WasmerMemory>);
typedef WasmerMemoryAsExternFn = Pointer<WasmerExtern> Function(
Pointer<WasmerMemory>);
// wasm_memory_data
typedef NativeWasmerMemoryDataFn = Pointer<Uint8> Function(
Pointer<WasmerMemory>);

View file

@ -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);

View file

@ -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());

View file

@ -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<Int64 Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32)>("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<Double Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32, Int64, Float, Float)>(
"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<dynamic Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32, Int64, dynamic, Double)>(
"env", "someFn", (num a, num b, num c, num d) => 123));
imp = WasmImports()..addGlobal<Int64>("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"));
}

View file

@ -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<Void Function(Int64, Int64)>("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<Void Function()>("reportStuff");
fn.call([]);
}).build();
var fn = inst.lookupFunction("reportStuff");
fn();
Expect.equals(report_x, 123);
Expect.equals(report_y, 456);
}

View file

@ -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<Int32 Function(Int32, Int32, Int32, Int32)>(
"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<Void Function()>("_start");
fn.call([]);
var fn = inst.lookupFunction("_start");
fn();
Expect.equals("hello, world!\n", out);
}

View file

@ -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");

View file

@ -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));

View file

@ -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);

View file

@ -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());

View file

@ -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<Int64 Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32)>("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<Double Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32, Int64, Float, Float)>(
"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<dynamic Function(Int32, Int64, Float, Double)>(
"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<Int64 Function(Int32, Int64, dynamic, Double)>(
"env", "someFn", (num a, num b, num c, num d) => 123));
imp = WasmImports()..addGlobal<Int64>("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"));
}

View file

@ -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<Void Function(Int64, Int64)>("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<Void Function()>("reportStuff");
fn.call([]);
}).build();
var fn = inst.lookupFunction("reportStuff");
fn();
Expect.equals(report_x, 123);
Expect.equals(report_y, 456);
}

View file

@ -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<Int32 Function(Int32, Int32, Int32, Int32)>(
"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<Void Function()>("_start");
fn.call([]);
var fn = inst.lookupFunction("_start");
fn();
Expect.equals("hello, world!\n", out);
}

View file

@ -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");

View file

@ -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));

View file

@ -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"]