mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:29:47 +00:00
pkg:wasm - more cleanup
- Added documentation to many members. Cleaned up existing documentation to follow standards. - Made many more fields final. - Hide (made private) constructors that a user cannot reasonably invoke. - WasmFunction, WasmInstance, WasmExportDescriptor, WasmImportDescriptor - Added, exported, and use new WasmError class. - Remove the fluent API in builder See https://dart.dev/guides/language/effective-dart/design#avoid-returning-this-from-methods-just-to-enable-a-fluent-interface Change-Id: I4222f7a95a9b20e89728d71de56b02ec91601e25 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202360 Reviewed-by: Liam Appelbe <liama@google.com> Commit-Queue: Liam Appelbe <liama@google.com> Auto-Submit: Kevin Moore <kevmoo@google.com>
This commit is contained in:
parent
9b56b4b858
commit
666f1ab898
|
@ -13,6 +13,7 @@ linter:
|
|||
- avoid_redundant_argument_values
|
||||
- avoid_renaming_method_parameters
|
||||
- avoid_returning_null_for_void
|
||||
- avoid_returning_this
|
||||
- avoid_unused_constructor_parameters
|
||||
- await_only_futures
|
||||
- cancel_subscriptions
|
||||
|
@ -25,6 +26,7 @@ linter:
|
|||
- implementation_imports
|
||||
- iterable_contains_unrelated_type
|
||||
- join_return_with_assignment
|
||||
- library_private_types_in_public_api
|
||||
- lines_longer_than_80_chars
|
||||
- list_remove_unrelated_type
|
||||
- missing_whitespace_between_adjacent_strings
|
||||
|
|
|
@ -61,7 +61,7 @@ Uri _getSdkDir() {
|
|||
Uri _getOutDir(Uri root) {
|
||||
final pkgRoot = packageRootUri(root);
|
||||
if (pkgRoot == null) {
|
||||
throw Exception('$pkgConfigFile not found');
|
||||
throw ArgumentError('Could not find "$pkgConfigFile" within "$root".');
|
||||
}
|
||||
return pkgRoot.resolve(wasmToolDir);
|
||||
}
|
||||
|
|
|
@ -12,25 +12,42 @@ import 'dart:typed_data';
|
|||
import 'package:wasm/wasm.dart';
|
||||
|
||||
// Brotli compression parameters.
|
||||
const int kDefaultQuality = 11;
|
||||
const int kDefaultWindow = 22;
|
||||
const int kDefaultMode = 0;
|
||||
const _kDefaultQuality = 11;
|
||||
const _kDefaultWindow = 22;
|
||||
const _kDefaultMode = 0;
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.length != 1) {
|
||||
print('Requires one argument: a path to the input file.');
|
||||
exitCode = 64; // bad usage
|
||||
return;
|
||||
}
|
||||
|
||||
final inputFilePath = args.single;
|
||||
|
||||
print('Loading "$inputFilePath"...');
|
||||
var inputDataFile = File(inputFilePath);
|
||||
if (!inputDataFile.existsSync()) {
|
||||
print('Input file "$inputFilePath" does not exist.');
|
||||
exitCode = 66; // no input file
|
||||
return;
|
||||
}
|
||||
|
||||
var inputData = inputDataFile.readAsBytesSync();
|
||||
print('Input size: ${inputData.length} bytes');
|
||||
|
||||
print('\nLoading wasm module');
|
||||
var brotliPath = Platform.script.resolve('libbrotli.wasm');
|
||||
var moduleData = File(brotliPath.path).readAsBytesSync();
|
||||
var module = WasmModule(moduleData);
|
||||
print(module.describe());
|
||||
|
||||
var instance = module.instantiate().enableWasi().build();
|
||||
var builder = module.builder()..enableWasi();
|
||||
var instance = builder.build();
|
||||
var memory = instance.memory;
|
||||
var compress = instance.lookupFunction('BrotliEncoderCompress');
|
||||
var decompress = instance.lookupFunction('BrotliDecoderDecompress');
|
||||
|
||||
print('Loading ${args[0]}');
|
||||
var inputData = File(args[0]).readAsBytesSync();
|
||||
print('Input size: ${inputData.length} bytes');
|
||||
|
||||
// Grow the module's memory to get unused space to put our data.
|
||||
// [initial memory][input data][output data][size][decoded data][size]
|
||||
var inputPtr = memory.lengthInBytes;
|
||||
|
@ -52,9 +69,9 @@ void main(List<String> args) {
|
|||
|
||||
print('\nCompressing...');
|
||||
var status = compress(
|
||||
kDefaultQuality,
|
||||
kDefaultWindow,
|
||||
kDefaultMode,
|
||||
_kDefaultQuality,
|
||||
_kDefaultWindow,
|
||||
_kDefaultMode,
|
||||
inputData.length,
|
||||
inputPtr,
|
||||
outSizePtr,
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import 'runtime.dart';
|
||||
import 'wasmer_api.dart';
|
||||
|
||||
/// WasmFunction is a callable function from a WasmInstance.
|
||||
class WasmFunction {
|
||||
final String _name;
|
||||
final Pointer<WasmerFunc> _func;
|
||||
final List<int> _argTypes;
|
||||
final int _returnType;
|
||||
final Pointer<WasmerValVec> _args = calloc<WasmerValVec>();
|
||||
final Pointer<WasmerValVec> _results = calloc<WasmerValVec>();
|
||||
|
||||
WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
|
||||
_args.ref.length = _argTypes.length;
|
||||
_args.ref.data =
|
||||
_argTypes.isEmpty ? nullptr : calloc<WasmerVal>(_argTypes.length);
|
||||
_results.ref.length = _returnType == WasmerValKindVoid ? 0 : 1;
|
||||
_results.ref.data =
|
||||
_returnType == WasmerValKindVoid ? nullptr : calloc<WasmerVal>();
|
||||
for (var i = 0; i < _argTypes.length; ++i) {
|
||||
_args.ref.data[i].kind = _argTypes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
WasmRuntime.getSignatureString(_name, _argTypes, _returnType);
|
||||
|
||||
bool _fillArg(dynamic arg, int i) {
|
||||
switch (_argTypes[i]) {
|
||||
case WasmerValKindI32:
|
||||
if (arg is! int) return false;
|
||||
_args.ref.data[i].i32 = arg;
|
||||
return true;
|
||||
case WasmerValKindI64:
|
||||
if (arg is! int) return false;
|
||||
_args.ref.data[i].i64 = arg;
|
||||
return true;
|
||||
case WasmerValKindF32:
|
||||
if (arg is! num) return false;
|
||||
_args.ref.data[i].f32 = arg;
|
||||
return true;
|
||||
case WasmerValKindF64:
|
||||
if (arg is! num) return false;
|
||||
_args.ref.data[i].f64 = arg;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dynamic apply(List<dynamic> args) {
|
||||
if (args.length != _argTypes.length) {
|
||||
throw ArgumentError('Wrong number arguments for WASM function: $this');
|
||||
}
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
if (!_fillArg(args[i], i)) {
|
||||
throw ArgumentError('Bad argument type for WASM function: $this');
|
||||
}
|
||||
}
|
||||
WasmRuntime().call(_func, _args, _results, toString());
|
||||
|
||||
if (_returnType == WasmerValKindVoid) {
|
||||
return null;
|
||||
}
|
||||
var result = _results.ref.data[0];
|
||||
assert(_returnType == result.kind);
|
||||
switch (_returnType) {
|
||||
case WasmerValKindI32:
|
||||
return result.i32;
|
||||
case WasmerValKindI64:
|
||||
return result.i64;
|
||||
case WasmerValKindF32:
|
||||
return result.f32;
|
||||
case WasmerValKindF64:
|
||||
return result.f64;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
if (invocation.memberName == #call) {
|
||||
return apply(invocation.positionalArguments);
|
||||
}
|
||||
return super.noSuchMethod(invocation);
|
||||
}
|
||||
}
|
|
@ -7,14 +7,14 @@ import 'dart:typed_data';
|
|||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import 'function.dart';
|
||||
import 'runtime.dart';
|
||||
import 'wasm_error.dart';
|
||||
import 'wasmer_api.dart';
|
||||
|
||||
/// WasmModule is a compiled module that can be instantiated.
|
||||
/// A compiled module that can be instantiated.
|
||||
class WasmModule {
|
||||
late Pointer<WasmerStore> _store;
|
||||
late Pointer<WasmerModule> _module;
|
||||
late final Pointer<WasmerStore> _store;
|
||||
late final Pointer<WasmerModule> _module;
|
||||
|
||||
/// Compile a module.
|
||||
WasmModule(Uint8List data) {
|
||||
|
@ -23,9 +23,9 @@ class WasmModule {
|
|||
_module = runtime.compile(this, _store, data);
|
||||
}
|
||||
|
||||
/// Returns a WasmInstanceBuilder that is used to add all the imports that the
|
||||
/// module needs, and then instantiate it.
|
||||
WasmInstanceBuilder instantiate() => WasmInstanceBuilder(this);
|
||||
/// Returns a [WasmInstanceBuilder] that is used to add all the imports that
|
||||
/// the module needs before instantiating it.
|
||||
WasmInstanceBuilder builder() => WasmInstanceBuilder._(this);
|
||||
|
||||
/// Create a new memory with the given number of initial pages, and optional
|
||||
/// maximum number of pages.
|
||||
|
@ -96,22 +96,22 @@ class _WasmFnImport extends Struct {
|
|||
args.add(rawArgs.ref.data[i].toDynamic);
|
||||
}
|
||||
assert(
|
||||
rawResult.ref.length == 1 || imp.ref.returnType == WasmerValKindVoid,
|
||||
rawResult.ref.length == 1 || imp.ref.returnType == wasmerValKindVoid,
|
||||
);
|
||||
var result = Function.apply(fn, args);
|
||||
if (imp.ref.returnType != WasmerValKindVoid) {
|
||||
if (imp.ref.returnType != wasmerValKindVoid) {
|
||||
rawResult.ref.data[0].kind = imp.ref.returnType;
|
||||
switch (imp.ref.returnType) {
|
||||
case WasmerValKindI32:
|
||||
case wasmerValKindI32:
|
||||
rawResult.ref.data[0].i32 = result as int;
|
||||
break;
|
||||
case WasmerValKindI64:
|
||||
case wasmerValKindI64:
|
||||
rawResult.ref.data[0].i64 = result as int;
|
||||
break;
|
||||
case WasmerValKindF32:
|
||||
case wasmerValKindF32:
|
||||
rawResult.ref.data[0].f32 = result as int;
|
||||
break;
|
||||
case WasmerValKindF64:
|
||||
case wasmerValKindF64:
|
||||
rawResult.ref.data[0].f64 = result as int;
|
||||
break;
|
||||
}
|
||||
|
@ -119,20 +119,18 @@ class _WasmFnImport extends Struct {
|
|||
}
|
||||
}
|
||||
|
||||
class _WasmImportOwner {}
|
||||
|
||||
/// WasmInstanceBuilder is used collect all the imports that a WasmModule
|
||||
/// requires before it is instantiated.
|
||||
/// Used to collect all of the imports that a [WasmModule] requires before it is
|
||||
/// built.
|
||||
class WasmInstanceBuilder {
|
||||
final _importOwner = _WasmImportOwner();
|
||||
final _importIndex = <String, int>{};
|
||||
final _imports = calloc<WasmerExternVec>();
|
||||
final WasmModule _module;
|
||||
late List<WasmImportDescriptor> _importDescs;
|
||||
final Map<String, int> _importIndex;
|
||||
final Pointer<WasmerExternVec> _imports = calloc<WasmerExternVec>();
|
||||
late final List<WasmImportDescriptor> _importDescs;
|
||||
Pointer<WasmerWasiEnv> _wasiEnv = nullptr;
|
||||
final _WasmImportOwner _importOwner = _WasmImportOwner();
|
||||
|
||||
WasmInstanceBuilder(this._module) : _importIndex = {} {
|
||||
_importDescs = WasmRuntime().importDescriptors(_module._module);
|
||||
WasmInstanceBuilder._(this._module)
|
||||
: _importDescs = WasmRuntime().importDescriptors(_module._module) {
|
||||
_imports.ref.length = _importDescs.length;
|
||||
_imports.ref.data = calloc<Pointer<WasmerExtern>>(_importDescs.length);
|
||||
for (var i = 0; i < _importDescs.length; ++i) {
|
||||
|
@ -145,39 +143,38 @@ class WasmInstanceBuilder {
|
|||
int _getIndex(String moduleName, String name) {
|
||||
var index = _importIndex['$moduleName::$name'];
|
||||
if (index == null) {
|
||||
throw Exception('Import not found: $moduleName::$name');
|
||||
throw WasmError('Import not found: $moduleName::$name');
|
||||
} else if (_imports.ref.data[index] != nullptr) {
|
||||
throw Exception('Import already filled: $moduleName::$name');
|
||||
throw WasmError('Import already filled: $moduleName::$name');
|
||||
} else {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a WasmMemory to the imports.
|
||||
WasmInstanceBuilder addMemory(
|
||||
void 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');
|
||||
if (imp.kind != wasmerExternKindMemory) {
|
||||
throw WasmError('Import is not a memory: $imp');
|
||||
}
|
||||
_imports.ref.data[index] = WasmRuntime().memoryToExtern(memory._mem);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Add a function to the imports.
|
||||
WasmInstanceBuilder addFunction(String moduleName, String name, Function fn) {
|
||||
void 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');
|
||||
if (imp.kind != wasmerExternKindFunction) {
|
||||
throw WasmError('Import is not a function: $imp');
|
||||
}
|
||||
|
||||
var runtime = WasmRuntime();
|
||||
var returnType = runtime.getReturnType(imp.funcType);
|
||||
var wasmFnImport = calloc<_WasmFnImport>();
|
||||
wasmFnImport.ref.returnType = returnType;
|
||||
|
@ -192,16 +189,15 @@ class WasmInstanceBuilder {
|
|||
_wasmFnImportFinalizerNative,
|
||||
);
|
||||
_imports.ref.data[index] = runtime.functionToExtern(fnImp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Enable WASI and add the default WASI imports.
|
||||
WasmInstanceBuilder enableWasi({
|
||||
void enableWasi({
|
||||
bool captureStdout = false,
|
||||
bool captureStderr = false,
|
||||
}) {
|
||||
if (_wasiEnv != nullptr) {
|
||||
throw Exception('WASI is already enabled.');
|
||||
throw WasmError('WASI is already enabled.');
|
||||
}
|
||||
var runtime = WasmRuntime();
|
||||
var config = runtime.newWasiConfig();
|
||||
|
@ -209,38 +205,51 @@ class WasmInstanceBuilder {
|
|||
if (captureStderr) runtime.captureWasiStderr(config);
|
||||
_wasiEnv = runtime.newWasiEnv(config);
|
||||
runtime.getWasiImports(_module._store, _module._module, _wasiEnv, _imports);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Build the module instance.
|
||||
WasmInstance build() {
|
||||
for (var i = 0; i < _importDescs.length; ++i) {
|
||||
if (_imports.ref.data[i] == nullptr) {
|
||||
throw Exception('Missing import: ${_importDescs[i]}');
|
||||
throw WasmError('Missing import: ${_importDescs[i]}');
|
||||
}
|
||||
}
|
||||
return WasmInstance(_module, _imports, _wasiEnv);
|
||||
return WasmInstance._(_module, _importOwner, _imports, _wasiEnv);
|
||||
}
|
||||
}
|
||||
|
||||
/// WasmInstance is an instantiated WasmModule.
|
||||
// TODO: should not be required once the min supported Dart SDK includes
|
||||
// github.com/dart-lang/sdk/commit/8fd81f72281d9d3aa5ef3890c947cc7305c56a50
|
||||
class _WasmImportOwner {}
|
||||
|
||||
/// An instantiated [WasmModule].
|
||||
///
|
||||
/// Created by calling [WasmInstanceBuilder.build].
|
||||
class WasmInstance {
|
||||
final _WasmImportOwner _importOwner;
|
||||
final _functions = <String, WasmFunction>{};
|
||||
final WasmModule _module;
|
||||
late Pointer<WasmerInstance> _instance;
|
||||
Pointer<WasmerMemory>? _exportedMemory;
|
||||
final Pointer<WasmerWasiEnv> _wasiEnv;
|
||||
|
||||
late final Pointer<WasmerInstance> _instance;
|
||||
|
||||
Pointer<WasmerMemory>? _exportedMemory;
|
||||
Stream<List<int>>? _stdout;
|
||||
Stream<List<int>>? _stderr;
|
||||
final Map<String, WasmFunction> _functions = {};
|
||||
|
||||
WasmInstance(
|
||||
WasmInstance._(
|
||||
this._module,
|
||||
this._importOwner,
|
||||
Pointer<WasmerExternVec> imports,
|
||||
this._wasiEnv,
|
||||
) {
|
||||
var runtime = WasmRuntime();
|
||||
_instance =
|
||||
runtime.instantiate(this, _module._store, _module._module, imports);
|
||||
_instance = runtime.instantiate(
|
||||
_importOwner,
|
||||
_module._store,
|
||||
_module._module,
|
||||
imports,
|
||||
);
|
||||
var exports = runtime.exports(_instance);
|
||||
var exportDescs = runtime.exportDescriptors(_module._module);
|
||||
assert(exports.ref.length == exportDescs.length);
|
||||
|
@ -248,16 +257,16 @@ class WasmInstance {
|
|||
var e = exports.ref.data[i];
|
||||
var kind = runtime.externKind(exports.ref.data[i]);
|
||||
var name = exportDescs[i].name;
|
||||
if (kind == WasmerExternKindFunction) {
|
||||
if (kind == wasmerExternKindFunction) {
|
||||
var f = runtime.externToFunction(e);
|
||||
var ft = exportDescs[i].funcType;
|
||||
_functions[name] = WasmFunction(
|
||||
_functions[name] = WasmFunction._(
|
||||
name,
|
||||
f,
|
||||
runtime.getArgTypes(ft),
|
||||
runtime.getReturnType(ft),
|
||||
);
|
||||
} else if (kind == WasmerExternKindMemory) {
|
||||
} else if (kind == wasmerExternKindMemory) {
|
||||
// WASM currently allows only one memory per module.
|
||||
var mem = runtime.externToMemory(e);
|
||||
_exportedMemory = mem;
|
||||
|
@ -268,40 +277,50 @@ class WasmInstance {
|
|||
}
|
||||
}
|
||||
|
||||
/// Searches the instantiated module for the given function. Returns null if
|
||||
/// it is not found.
|
||||
/// Searches the instantiated module for the given function.
|
||||
///
|
||||
/// Returns a [WasmFunction], but the return type is [dynamic] to allow
|
||||
/// easy invocation as a [Function].
|
||||
///
|
||||
/// Returns `null` if no function exists with name [name].
|
||||
dynamic lookupFunction(String name) => _functions[name];
|
||||
|
||||
/// Returns the memory exported from this instance.
|
||||
WasmMemory get memory {
|
||||
if (_exportedMemory == null) {
|
||||
throw Exception('Wasm module did not export its memory.');
|
||||
throw WasmError('Wasm module did not export its memory.');
|
||||
}
|
||||
return WasmMemory._fromExport(_exportedMemory as Pointer<WasmerMemory>);
|
||||
}
|
||||
|
||||
/// Returns a stream that reads from stdout. To use this, you must enable WASI
|
||||
/// when instantiating the module, and set captureStdout to true.
|
||||
/// Returns a stream that reads from `stdout`.
|
||||
///
|
||||
/// To use this, you must enable WASI when instantiating the module, and set
|
||||
/// `captureStdout` to `true`.
|
||||
Stream<List<int>> get stdout {
|
||||
if (_wasiEnv == nullptr) {
|
||||
throw Exception("Can't capture stdout without WASI enabled.");
|
||||
throw WasmError("Can't capture stdout without WASI enabled.");
|
||||
}
|
||||
return _stdout ??= WasmRuntime().getWasiStdoutStream(_wasiEnv);
|
||||
}
|
||||
|
||||
/// Returns a stream that reads from stderr. To use this, you must enable WASI
|
||||
/// when instantiating the module, and set captureStderr to true.
|
||||
/// Returns a stream that reads from `stderr`.
|
||||
///
|
||||
/// To use this, you must enable WASI when instantiating the module, and set
|
||||
/// `captureStderr` to `true`.
|
||||
Stream<List<int>> get stderr {
|
||||
if (_wasiEnv == nullptr) {
|
||||
throw Exception("Can't capture stderr without WASI enabled.");
|
||||
throw WasmError("Can't capture stderr without WASI enabled.");
|
||||
}
|
||||
return _stderr ??= WasmRuntime().getWasiStderrStream(_wasiEnv);
|
||||
}
|
||||
}
|
||||
|
||||
/// WasmMemory contains the memory of a WasmInstance.
|
||||
/// Memory of a [WasmInstance].
|
||||
///
|
||||
/// Access via [WasmInstance.memory] or create via [WasmModule.createMemory].
|
||||
class WasmMemory {
|
||||
late Pointer<WasmerMemory> _mem;
|
||||
late final Pointer<WasmerMemory> _mem;
|
||||
late Uint8List _view;
|
||||
|
||||
WasmMemory._fromExport(this._mem) {
|
||||
|
@ -318,13 +337,13 @@ class WasmMemory {
|
|||
/// The WASM spec defines the page size as 64KiB.
|
||||
static const int kPageSizeInBytes = 64 * 1024;
|
||||
|
||||
/// Returns the length of the memory in pages.
|
||||
/// The length of the memory in pages.
|
||||
int get lengthInPages => WasmRuntime().memoryLength(_mem);
|
||||
|
||||
/// Returns the length of the memory in bytes.
|
||||
/// The length of the memory in bytes.
|
||||
int get lengthInBytes => _view.lengthInBytes;
|
||||
|
||||
/// Returns the byte at the given index.
|
||||
/// The byte at the given [index].
|
||||
int operator [](int index) => _view[index];
|
||||
|
||||
/// Sets the byte at the given index to value.
|
||||
|
@ -332,12 +351,99 @@ class WasmMemory {
|
|||
_view[index] = value;
|
||||
}
|
||||
|
||||
/// Returns a Uint8List view into the memory.
|
||||
/// A view into the memory.
|
||||
Uint8List get view => _view;
|
||||
|
||||
/// Grow the memory by deltaPages.
|
||||
/// Grow the memory by [deltaPages] and invalidates any existing views into
|
||||
/// the memory.
|
||||
void grow(int deltaPages) {
|
||||
var runtime = WasmRuntime()..growMemory(_mem, deltaPages);
|
||||
_view = runtime.memoryView(_mem);
|
||||
}
|
||||
}
|
||||
|
||||
/// A callable function from a [WasmInstance].
|
||||
///
|
||||
/// Access by calling [WasmInstance.lookupFunction].
|
||||
class WasmFunction {
|
||||
final String _name;
|
||||
final Pointer<WasmerFunc> _func;
|
||||
final List<int> _argTypes;
|
||||
final int _returnType;
|
||||
final Pointer<WasmerValVec> _args = calloc<WasmerValVec>();
|
||||
final Pointer<WasmerValVec> _results = calloc<WasmerValVec>();
|
||||
|
||||
WasmFunction._(this._name, this._func, this._argTypes, this._returnType) {
|
||||
_args.ref.length = _argTypes.length;
|
||||
_args.ref.data =
|
||||
_argTypes.isEmpty ? nullptr : calloc<WasmerVal>(_argTypes.length);
|
||||
_results.ref.length = _returnType == wasmerValKindVoid ? 0 : 1;
|
||||
_results.ref.data =
|
||||
_returnType == wasmerValKindVoid ? nullptr : calloc<WasmerVal>();
|
||||
for (var i = 0; i < _argTypes.length; ++i) {
|
||||
_args.ref.data[i].kind = _argTypes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
WasmRuntime.getSignatureString(_name, _argTypes, _returnType);
|
||||
|
||||
bool _fillArg(dynamic arg, int i) {
|
||||
switch (_argTypes[i]) {
|
||||
case wasmerValKindI32:
|
||||
if (arg is! int) return false;
|
||||
_args.ref.data[i].i32 = arg;
|
||||
return true;
|
||||
case wasmerValKindI64:
|
||||
if (arg is! int) return false;
|
||||
_args.ref.data[i].i64 = arg;
|
||||
return true;
|
||||
case wasmerValKindF32:
|
||||
if (arg is! num) return false;
|
||||
_args.ref.data[i].f32 = arg;
|
||||
return true;
|
||||
case wasmerValKindF64:
|
||||
if (arg is! num) return false;
|
||||
_args.ref.data[i].f64 = arg;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dynamic apply(List<dynamic> args) {
|
||||
if (args.length != _argTypes.length) {
|
||||
throw ArgumentError('Wrong number arguments for WASM function: $this');
|
||||
}
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
if (!_fillArg(args[i], i)) {
|
||||
throw ArgumentError('Bad argument type for WASM function: $this');
|
||||
}
|
||||
}
|
||||
WasmRuntime().call(_func, _args, _results, toString());
|
||||
|
||||
if (_returnType == wasmerValKindVoid) {
|
||||
return null;
|
||||
}
|
||||
var result = _results.ref.data[0];
|
||||
assert(_returnType == result.kind);
|
||||
switch (_returnType) {
|
||||
case wasmerValKindI32:
|
||||
return result.i32;
|
||||
case wasmerValKindI64:
|
||||
return result.i64;
|
||||
case wasmerValKindF32:
|
||||
return result.f32;
|
||||
case wasmerValKindF64:
|
||||
return result.f64;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
if (invocation.memberName == #call) {
|
||||
return apply(invocation.positionalArguments);
|
||||
}
|
||||
return super.noSuchMethod(invocation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,22 +11,23 @@ import 'dart:typed_data';
|
|||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import 'shared.dart';
|
||||
import 'wasm_error.dart';
|
||||
import 'wasmer_api.dart';
|
||||
|
||||
part 'runtime.g.dart';
|
||||
|
||||
class WasmImportDescriptor {
|
||||
int kind;
|
||||
String moduleName;
|
||||
String name;
|
||||
Pointer<WasmerFunctype> funcType;
|
||||
final int kind;
|
||||
final String moduleName;
|
||||
final String name;
|
||||
final Pointer<WasmerFunctype> funcType;
|
||||
|
||||
WasmImportDescriptor(this.kind, this.moduleName, this.name, this.funcType);
|
||||
WasmImportDescriptor._(this.kind, this.moduleName, this.name, this.funcType);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var kindName = wasmerExternKindName(kind);
|
||||
if (kind == WasmerExternKindFunction) {
|
||||
if (kind == wasmerExternKindFunction) {
|
||||
var runtime = WasmRuntime();
|
||||
var sig = WasmRuntime.getSignatureString(
|
||||
'$moduleName::$name',
|
||||
|
@ -41,16 +42,16 @@ class WasmImportDescriptor {
|
|||
}
|
||||
|
||||
class WasmExportDescriptor {
|
||||
int kind;
|
||||
String name;
|
||||
Pointer<WasmerFunctype> funcType;
|
||||
final int kind;
|
||||
final String name;
|
||||
final Pointer<WasmerFunctype> funcType;
|
||||
|
||||
WasmExportDescriptor(this.kind, this.name, this.funcType);
|
||||
WasmExportDescriptor._(this.kind, this.name, this.funcType);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var kindName = wasmerExternKindName(kind);
|
||||
if (kind == WasmerExternKindFunction) {
|
||||
if (kind == wasmerExternKindFunction) {
|
||||
var runtime = WasmRuntime();
|
||||
var sig = WasmRuntime.getSignatureString(
|
||||
name,
|
||||
|
@ -65,16 +66,16 @@ class WasmExportDescriptor {
|
|||
}
|
||||
|
||||
class _WasmTrapsEntry {
|
||||
Object exception;
|
||||
final Object exception;
|
||||
|
||||
_WasmTrapsEntry(this.exception);
|
||||
}
|
||||
|
||||
class _WasiStreamIterator implements Iterator<List<int>> {
|
||||
static const int _bufferLength = 1024;
|
||||
final Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
|
||||
final Pointer<WasmerWasiEnv> _env;
|
||||
final Function _reader;
|
||||
final Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
|
||||
int _length = 0;
|
||||
|
||||
_WasiStreamIterator(this._env, this._reader);
|
||||
|
@ -103,7 +104,7 @@ String _getLibName() {
|
|||
if (Platform.isMacOS) return appleLib;
|
||||
if (Platform.isLinux) return linuxLib;
|
||||
// TODO(dartbug.com/37882): Support more platforms.
|
||||
throw Exception('Wasm not currently supported on this platform');
|
||||
throw WasmError('Wasm not currently supported on this platform');
|
||||
}
|
||||
|
||||
String? _getLibPathFrom(Uri root) {
|
||||
|
@ -117,5 +118,5 @@ String _getLibPath() {
|
|||
if (path != null) return path;
|
||||
path = _getLibPathFrom(Directory.current.uri);
|
||||
if (path != null) return path;
|
||||
throw Exception('Wasm library not found. Did you `$invocationString`?');
|
||||
throw WasmError('Wasm library not found. Did you `$invocationString`?');
|
||||
}
|
||||
|
|
|
@ -13,98 +13,99 @@
|
|||
part of 'runtime.dart';
|
||||
|
||||
class WasmRuntime {
|
||||
static WasmRuntime? _inst;
|
||||
static final WasmRuntime _inst = WasmRuntime._init();
|
||||
final DynamicLibrary _lib;
|
||||
final _traps = <int, _WasmTrapsEntry>{};
|
||||
late final Pointer<WasmerEngine> _engine;
|
||||
|
||||
DynamicLibrary _lib;
|
||||
late Pointer<WasmerEngine> _engine;
|
||||
Map<int, _WasmTrapsEntry> traps = {};
|
||||
late final WasmerDartInitializeApiDLFn _Dart_InitializeApiDL;
|
||||
late final WasmerSetFinalizerForEngineFn _set_finalizer_for_engine;
|
||||
late final WasmerSetFinalizerForFuncFn _set_finalizer_for_func;
|
||||
late final WasmerSetFinalizerForInstanceFn _set_finalizer_for_instance;
|
||||
late final WasmerSetFinalizerForMemoryFn _set_finalizer_for_memory;
|
||||
late final WasmerSetFinalizerForMemorytypeFn _set_finalizer_for_memorytype;
|
||||
late final WasmerSetFinalizerForModuleFn _set_finalizer_for_module;
|
||||
late final WasmerSetFinalizerForStoreFn _set_finalizer_for_store;
|
||||
late final WasmerSetFinalizerForTrapFn _set_finalizer_for_trap;
|
||||
late final WasmerWasiConfigInheritStderrFn _wasi_config_inherit_stderr;
|
||||
late final WasmerWasiConfigInheritStdoutFn _wasi_config_inherit_stdout;
|
||||
late final WasmerWasiConfigNewFn _wasi_config_new;
|
||||
late final WasmerWasiEnvDeleteFn _wasi_env_delete;
|
||||
late final WasmerWasiEnvNewFn _wasi_env_new;
|
||||
late final WasmerWasiEnvReadStderrFn _wasi_env_read_stderr;
|
||||
late final WasmerWasiEnvReadStdoutFn _wasi_env_read_stdout;
|
||||
late final WasmerWasiEnvSetMemoryFn _wasi_env_set_memory;
|
||||
late final WasmerWasiGetImportsFn _wasi_get_imports;
|
||||
late final WasmerByteVecDeleteFn _byte_vec_delete;
|
||||
late final WasmerByteVecNewFn _byte_vec_new;
|
||||
late final WasmerByteVecNewEmptyFn _byte_vec_new_empty;
|
||||
late final WasmerByteVecNewUninitializedFn _byte_vec_new_uninitialized;
|
||||
late final WasmerEngineDeleteFn _engine_delete;
|
||||
late final WasmerEngineNewFn _engine_new;
|
||||
late final WasmerExporttypeNameFn _exporttype_name;
|
||||
late final WasmerExporttypeTypeFn _exporttype_type;
|
||||
late final WasmerExporttypeVecDeleteFn _exporttype_vec_delete;
|
||||
late final WasmerExporttypeVecNewFn _exporttype_vec_new;
|
||||
late final WasmerExporttypeVecNewEmptyFn _exporttype_vec_new_empty;
|
||||
late final WasmerExporttypeVecNewUninitializedFn
|
||||
_exporttype_vec_new_uninitialized;
|
||||
late final WasmerExternAsFuncFn _extern_as_func;
|
||||
late final WasmerExternAsMemoryFn _extern_as_memory;
|
||||
late final WasmerExternDeleteFn _extern_delete;
|
||||
late final WasmerExternKindFn _extern_kind;
|
||||
late final WasmerExternVecDeleteFn _extern_vec_delete;
|
||||
late final WasmerExternVecNewFn _extern_vec_new;
|
||||
late final WasmerExternVecNewEmptyFn _extern_vec_new_empty;
|
||||
late final WasmerExternVecNewUninitializedFn _extern_vec_new_uninitialized;
|
||||
late final WasmerExterntypeAsFunctypeFn _externtype_as_functype;
|
||||
late final WasmerExterntypeDeleteFn _externtype_delete;
|
||||
late final WasmerExterntypeKindFn _externtype_kind;
|
||||
late final WasmerFuncAsExternFn _func_as_extern;
|
||||
late final WasmerFuncCallFn _func_call;
|
||||
late final WasmerFuncDeleteFn _func_delete;
|
||||
late final WasmerFuncNewWithEnvFn _func_new_with_env;
|
||||
late final WasmerFunctypeDeleteFn _functype_delete;
|
||||
late final WasmerFunctypeParamsFn _functype_params;
|
||||
late final WasmerFunctypeResultsFn _functype_results;
|
||||
late final WasmerImporttypeModuleFn _importtype_module;
|
||||
late final WasmerImporttypeNameFn _importtype_name;
|
||||
late final WasmerImporttypeTypeFn _importtype_type;
|
||||
late final WasmerImporttypeVecDeleteFn _importtype_vec_delete;
|
||||
late final WasmerImporttypeVecNewFn _importtype_vec_new;
|
||||
late final WasmerImporttypeVecNewEmptyFn _importtype_vec_new_empty;
|
||||
late final WasmerImporttypeVecNewUninitializedFn
|
||||
_importtype_vec_new_uninitialized;
|
||||
late final WasmerInstanceDeleteFn _instance_delete;
|
||||
late final WasmerInstanceExportsFn _instance_exports;
|
||||
late final WasmerInstanceNewFn _instance_new;
|
||||
late final WasmerMemoryAsExternFn _memory_as_extern;
|
||||
late final WasmerMemoryDataFn _memory_data;
|
||||
late final WasmerMemoryDataSizeFn _memory_data_size;
|
||||
late final WasmerMemoryDeleteFn _memory_delete;
|
||||
late final WasmerMemoryGrowFn _memory_grow;
|
||||
late final WasmerMemoryNewFn _memory_new;
|
||||
late final WasmerMemorySizeFn _memory_size;
|
||||
late final WasmerMemorytypeDeleteFn _memorytype_delete;
|
||||
late final WasmerMemorytypeNewFn _memorytype_new;
|
||||
late final WasmerModuleDeleteFn _module_delete;
|
||||
late final WasmerModuleExportsFn _module_exports;
|
||||
late final WasmerModuleImportsFn _module_imports;
|
||||
late final WasmerModuleNewFn _module_new;
|
||||
late final WasmerStoreDeleteFn _store_delete;
|
||||
late final WasmerStoreNewFn _store_new;
|
||||
late final WasmerTrapDeleteFn _trap_delete;
|
||||
late final WasmerTrapMessageFn _trap_message;
|
||||
late final WasmerTrapNewFn _trap_new;
|
||||
late final WasmerValtypeDeleteFn _valtype_delete;
|
||||
late final WasmerValtypeKindFn _valtype_kind;
|
||||
late final WasmerValtypeVecDeleteFn _valtype_vec_delete;
|
||||
late final WasmerValtypeVecNewFn _valtype_vec_new;
|
||||
late final WasmerValtypeVecNewEmptyFn _valtype_vec_new_empty;
|
||||
late final WasmerValtypeVecNewUninitializedFn _valtype_vec_new_uninitialized;
|
||||
late final WasmerWasmerLastErrorLengthFn _wasmer_last_error_length;
|
||||
late final WasmerWasmerLastErrorMessageFn _wasmer_last_error_message;
|
||||
|
||||
late WasmerDartInitializeApiDLFn _Dart_InitializeApiDL;
|
||||
late WasmerSetFinalizerForEngineFn _set_finalizer_for_engine;
|
||||
late WasmerSetFinalizerForFuncFn _set_finalizer_for_func;
|
||||
late WasmerSetFinalizerForInstanceFn _set_finalizer_for_instance;
|
||||
late WasmerSetFinalizerForMemoryFn _set_finalizer_for_memory;
|
||||
late WasmerSetFinalizerForMemorytypeFn _set_finalizer_for_memorytype;
|
||||
late WasmerSetFinalizerForModuleFn _set_finalizer_for_module;
|
||||
late WasmerSetFinalizerForStoreFn _set_finalizer_for_store;
|
||||
late WasmerSetFinalizerForTrapFn _set_finalizer_for_trap;
|
||||
late WasmerWasiConfigInheritStderrFn _wasi_config_inherit_stderr;
|
||||
late WasmerWasiConfigInheritStdoutFn _wasi_config_inherit_stdout;
|
||||
late WasmerWasiConfigNewFn _wasi_config_new;
|
||||
late WasmerWasiEnvDeleteFn _wasi_env_delete;
|
||||
late WasmerWasiEnvNewFn _wasi_env_new;
|
||||
late WasmerWasiEnvReadStderrFn _wasi_env_read_stderr;
|
||||
late WasmerWasiEnvReadStdoutFn _wasi_env_read_stdout;
|
||||
late WasmerWasiEnvSetMemoryFn _wasi_env_set_memory;
|
||||
late WasmerWasiGetImportsFn _wasi_get_imports;
|
||||
late WasmerByteVecDeleteFn _byte_vec_delete;
|
||||
late WasmerByteVecNewFn _byte_vec_new;
|
||||
late WasmerByteVecNewEmptyFn _byte_vec_new_empty;
|
||||
late WasmerByteVecNewUninitializedFn _byte_vec_new_uninitialized;
|
||||
late WasmerEngineDeleteFn _engine_delete;
|
||||
late WasmerEngineNewFn _engine_new;
|
||||
late WasmerExporttypeNameFn _exporttype_name;
|
||||
late WasmerExporttypeTypeFn _exporttype_type;
|
||||
late WasmerExporttypeVecDeleteFn _exporttype_vec_delete;
|
||||
late WasmerExporttypeVecNewFn _exporttype_vec_new;
|
||||
late WasmerExporttypeVecNewEmptyFn _exporttype_vec_new_empty;
|
||||
late WasmerExporttypeVecNewUninitializedFn _exporttype_vec_new_uninitialized;
|
||||
late WasmerExternAsFuncFn _extern_as_func;
|
||||
late WasmerExternAsMemoryFn _extern_as_memory;
|
||||
late WasmerExternDeleteFn _extern_delete;
|
||||
late WasmerExternKindFn _extern_kind;
|
||||
late WasmerExternVecDeleteFn _extern_vec_delete;
|
||||
late WasmerExternVecNewFn _extern_vec_new;
|
||||
late WasmerExternVecNewEmptyFn _extern_vec_new_empty;
|
||||
late WasmerExternVecNewUninitializedFn _extern_vec_new_uninitialized;
|
||||
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;
|
||||
late WasmerImporttypeModuleFn _importtype_module;
|
||||
late WasmerImporttypeNameFn _importtype_name;
|
||||
late WasmerImporttypeTypeFn _importtype_type;
|
||||
late WasmerImporttypeVecDeleteFn _importtype_vec_delete;
|
||||
late WasmerImporttypeVecNewFn _importtype_vec_new;
|
||||
late WasmerImporttypeVecNewEmptyFn _importtype_vec_new_empty;
|
||||
late WasmerImporttypeVecNewUninitializedFn _importtype_vec_new_uninitialized;
|
||||
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;
|
||||
late WasmerMemoryGrowFn _memory_grow;
|
||||
late WasmerMemoryNewFn _memory_new;
|
||||
late WasmerMemorySizeFn _memory_size;
|
||||
late WasmerMemorytypeDeleteFn _memorytype_delete;
|
||||
late WasmerMemorytypeNewFn _memorytype_new;
|
||||
late WasmerModuleDeleteFn _module_delete;
|
||||
late WasmerModuleExportsFn _module_exports;
|
||||
late WasmerModuleImportsFn _module_imports;
|
||||
late WasmerModuleNewFn _module_new;
|
||||
late WasmerStoreDeleteFn _store_delete;
|
||||
late WasmerStoreNewFn _store_new;
|
||||
late WasmerTrapDeleteFn _trap_delete;
|
||||
late WasmerTrapMessageFn _trap_message;
|
||||
late WasmerTrapNewFn _trap_new;
|
||||
late WasmerValtypeDeleteFn _valtype_delete;
|
||||
late WasmerValtypeKindFn _valtype_kind;
|
||||
late WasmerValtypeVecDeleteFn _valtype_vec_delete;
|
||||
late WasmerValtypeVecNewFn _valtype_vec_new;
|
||||
late WasmerValtypeVecNewEmptyFn _valtype_vec_new_empty;
|
||||
late WasmerValtypeVecNewUninitializedFn _valtype_vec_new_uninitialized;
|
||||
late WasmerWasmerLastErrorLengthFn _wasmer_last_error_length;
|
||||
late WasmerWasmerLastErrorMessageFn _wasmer_last_error_message;
|
||||
|
||||
factory WasmRuntime() => _inst ??= WasmRuntime._init();
|
||||
factory WasmRuntime() => _inst;
|
||||
|
||||
WasmRuntime._init() : _lib = DynamicLibrary.open(_getLibPath()) {
|
||||
_Dart_InitializeApiDL = _lib.lookupFunction<
|
||||
|
@ -447,7 +448,7 @@ class WasmRuntime {
|
|||
);
|
||||
|
||||
if (_Dart_InitializeApiDL(NativeApi.initializeApiDLData) != 0) {
|
||||
throw Exception('Failed to initialize Dart API');
|
||||
throw WasmError('Failed to initialize Dart API');
|
||||
}
|
||||
_engine = _engine_new();
|
||||
_checkNotEqual(_engine, nullptr, 'Failed to initialize Wasm engine.');
|
||||
|
@ -495,11 +496,11 @@ class WasmRuntime {
|
|||
var exp = exportsVec.ref.data[i];
|
||||
var extern = _exporttype_type(exp);
|
||||
var kind = _externtype_kind(extern);
|
||||
var fnType = kind == WasmerExternKindFunction
|
||||
var fnType = kind == wasmerExternKindFunction
|
||||
? _externtype_as_functype(extern)
|
||||
: nullptr;
|
||||
exps.add(
|
||||
WasmExportDescriptor(
|
||||
WasmExportDescriptor._(
|
||||
kind,
|
||||
_exporttype_name(exp).ref.toString(),
|
||||
fnType,
|
||||
|
@ -518,11 +519,11 @@ class WasmRuntime {
|
|||
var imp = importsVec.ref.data[i];
|
||||
var extern = _importtype_type(imp);
|
||||
var kind = _externtype_kind(extern);
|
||||
var fnType = kind == WasmerExternKindFunction
|
||||
var fnType = kind == wasmerExternKindFunction
|
||||
? _externtype_as_functype(extern)
|
||||
: nullptr;
|
||||
imps.add(
|
||||
WasmImportDescriptor(
|
||||
WasmImportDescriptor._(
|
||||
kind,
|
||||
_importtype_module(imp).ref.toString(),
|
||||
_importtype_name(imp).ref.toString(),
|
||||
|
@ -541,20 +542,14 @@ class WasmRuntime {
|
|||
// with a corresponding exception, and their memory is managed using a
|
||||
// finalizer on the _WasmTrapsEntry. Traps can also be created by WASM
|
||||
// code, and in that case we delete them in this function.
|
||||
var entry = traps[trap.address];
|
||||
if (entry != null) {
|
||||
traps.remove(entry);
|
||||
// ignore: only_throw_errors
|
||||
throw entry.exception;
|
||||
} else {
|
||||
var trapMessage = calloc<WasmerByteVec>();
|
||||
_trap_message(trap, trapMessage);
|
||||
var message = 'Wasm trap when calling $source: ${trapMessage.ref}';
|
||||
_byte_vec_delete(trapMessage);
|
||||
calloc.free(trapMessage);
|
||||
_trap_delete(trap);
|
||||
throw Exception(message);
|
||||
var entry = _traps.remove(trap.address);
|
||||
if (entry == null) {
|
||||
throw WasmError(
|
||||
'This case is not (yet) supported. Please file an issue on pkg:wasm.',
|
||||
);
|
||||
}
|
||||
// ignore: only_throw_errors
|
||||
throw entry.exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -606,9 +601,9 @@ class WasmRuntime {
|
|||
int getReturnType(Pointer<WasmerFunctype> funcType) {
|
||||
var rets = _functype_results(funcType);
|
||||
if (rets.ref.length == 0) {
|
||||
return WasmerValKindVoid;
|
||||
return wasmerValKindVoid;
|
||||
} else if (rets.ref.length > 1) {
|
||||
throw Exception('Multiple return values are not supported');
|
||||
throw WasmError('Multiple return values are not supported');
|
||||
}
|
||||
return _valtype_kind(rets.ref.data[0]);
|
||||
}
|
||||
|
@ -636,7 +631,7 @@ class WasmRuntime {
|
|||
) {
|
||||
var limPtr = calloc<WasmerLimits>();
|
||||
limPtr.ref.min = pages;
|
||||
limPtr.ref.max = maxPages ?? wasm_limits_max_default;
|
||||
limPtr.ref.max = maxPages ?? wasmLimitsMaxDefault;
|
||||
var memType = _memorytype_new(limPtr);
|
||||
calloc.free(limPtr);
|
||||
_checkNotEqual(memType, nullptr, 'Failed to create memory type.');
|
||||
|
@ -694,7 +689,7 @@ class WasmRuntime {
|
|||
_checkNotEqual(trap, nullptr, 'Failed to create trap.');
|
||||
var entry = _WasmTrapsEntry(exception);
|
||||
_set_finalizer_for_trap(entry, trap);
|
||||
traps[trap.address] = entry;
|
||||
_traps[trap.address] = entry;
|
||||
return trap;
|
||||
}
|
||||
|
||||
|
@ -758,7 +753,7 @@ class WasmRuntime {
|
|||
|
||||
T _checkNotEqual<T>(T x, T y, String errorMessage) {
|
||||
if (x == y) {
|
||||
throw Exception('$errorMessage\n${_getLastError()}');
|
||||
throw WasmError('$errorMessage\n${_getLastError()}'.trim());
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
|
14
pkg/wasm/lib/src/wasm_error.dart
Normal file
14
pkg/wasm/lib/src/wasm_error.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// Error specific to unexpected behavior or incorrect usage of this package.
|
||||
class WasmError extends Error {
|
||||
/// Describes the nature of the error.
|
||||
final String message;
|
||||
|
||||
WasmError(this.message) : assert(message.trim() == message);
|
||||
|
||||
@override
|
||||
String toString() => 'WasmError:$message';
|
||||
}
|
|
@ -6,8 +6,6 @@
|
|||
// To regenerate the file, use the following command
|
||||
// "generate_ffi_boilerplate.py".
|
||||
|
||||
// ignore_for_file: constant_identifier_names
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
@ -15,29 +13,29 @@ import 'dart:typed_data';
|
|||
part 'wasmer_api.g.dart';
|
||||
|
||||
// wasm_valkind_enum
|
||||
const int WasmerValKindI32 = 0;
|
||||
const int WasmerValKindI64 = 1;
|
||||
const int WasmerValKindF32 = 2;
|
||||
const int WasmerValKindF64 = 3;
|
||||
const int wasmerValKindI32 = 0;
|
||||
const int wasmerValKindI64 = 1;
|
||||
const int wasmerValKindF32 = 2;
|
||||
const int wasmerValKindF64 = 3;
|
||||
// The void tag is not part of the C API. It's used to represent the return type
|
||||
// of a void function.
|
||||
const int WasmerValKindVoid = -1;
|
||||
const int wasmerValKindVoid = -1;
|
||||
|
||||
// wasm_externkind_enum
|
||||
const int WasmerExternKindFunction = 0;
|
||||
const int WasmerExternKindGlobal = 1;
|
||||
const int WasmerExternKindTable = 2;
|
||||
const int WasmerExternKindMemory = 3;
|
||||
const int wasmerExternKindFunction = 0;
|
||||
const int wasmerExternKindGlobal = 1;
|
||||
const int wasmerExternKindTable = 2;
|
||||
const int wasmerExternKindMemory = 3;
|
||||
|
||||
String wasmerExternKindName(int kind) {
|
||||
switch (kind) {
|
||||
case WasmerExternKindFunction:
|
||||
case wasmerExternKindFunction:
|
||||
return 'function';
|
||||
case WasmerExternKindGlobal:
|
||||
case wasmerExternKindGlobal:
|
||||
return 'global';
|
||||
case WasmerExternKindTable:
|
||||
case wasmerExternKindTable:
|
||||
return 'table';
|
||||
case WasmerExternKindMemory:
|
||||
case wasmerExternKindMemory:
|
||||
return 'memory';
|
||||
default:
|
||||
return 'unknown';
|
||||
|
@ -46,15 +44,15 @@ String wasmerExternKindName(int kind) {
|
|||
|
||||
String wasmerValKindName(int kind) {
|
||||
switch (kind) {
|
||||
case WasmerValKindI32:
|
||||
case wasmerValKindI32:
|
||||
return 'int32';
|
||||
case WasmerValKindI64:
|
||||
case wasmerValKindI64:
|
||||
return 'int64';
|
||||
case WasmerValKindF32:
|
||||
case wasmerValKindF32:
|
||||
return 'float32';
|
||||
case WasmerValKindF64:
|
||||
case wasmerValKindF64:
|
||||
return 'float64';
|
||||
case WasmerValKindVoid:
|
||||
case wasmerValKindVoid:
|
||||
return 'void';
|
||||
default:
|
||||
return 'unknown';
|
||||
|
@ -97,23 +95,23 @@ class WasmerVal extends Struct {
|
|||
set f64(num val) =>
|
||||
_val = ByteData(8)..setFloat64(0, val as double, Endian.host);
|
||||
|
||||
bool get isI32 => kind == WasmerValKindI32;
|
||||
bool get isI32 => kind == wasmerValKindI32;
|
||||
|
||||
bool get isI64 => kind == WasmerValKindI64;
|
||||
bool get isI64 => kind == wasmerValKindI64;
|
||||
|
||||
bool get isF32 => kind == WasmerValKindF32;
|
||||
bool get isF32 => kind == wasmerValKindF32;
|
||||
|
||||
bool get isF64 => kind == WasmerValKindF64;
|
||||
bool get isF64 => kind == wasmerValKindF64;
|
||||
|
||||
dynamic get toDynamic {
|
||||
switch (kind) {
|
||||
case WasmerValKindI32:
|
||||
case wasmerValKindI32:
|
||||
return i32;
|
||||
case WasmerValKindI64:
|
||||
case wasmerValKindI64:
|
||||
return i64;
|
||||
case WasmerValKindF32:
|
||||
case wasmerValKindF32:
|
||||
return f32;
|
||||
case WasmerValKindF64:
|
||||
case wasmerValKindF64:
|
||||
return f64;
|
||||
}
|
||||
}
|
||||
|
@ -129,4 +127,4 @@ class WasmerLimits extends Struct {
|
|||
}
|
||||
|
||||
// Default maximum, which indicates no upper limit.
|
||||
const int wasm_limits_max_default = 0xffffffff;
|
||||
const int wasmLimitsMaxDefault = 0xffffffff;
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
export 'src/function.dart';
|
||||
export 'src/module.dart';
|
||||
export 'src/wasm_error.dart';
|
||||
|
|
|
@ -21,7 +21,7 @@ void main() {
|
|||
0x7e, 0x0b,
|
||||
]);
|
||||
|
||||
var inst = WasmModule(data).instantiate().build();
|
||||
var inst = WasmModule(data).builder().build();
|
||||
var fn = inst.lookupFunction('square');
|
||||
var n = fn(1234) as int;
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import 'dart:typed_data';
|
|||
import 'package:test/test.dart';
|
||||
import 'package:wasm/wasm.dart';
|
||||
|
||||
import 'test_shared.dart';
|
||||
|
||||
void main() {
|
||||
test('corrupted module', () {
|
||||
var data = Uint8List.fromList([
|
||||
|
@ -17,6 +19,14 @@ void main() {
|
|||
0x7e, 0x0b,
|
||||
]);
|
||||
|
||||
expect(() => WasmModule(data), throwsA(isException));
|
||||
expect(
|
||||
() => WasmModule(data),
|
||||
throwsWasmError(
|
||||
allOf(
|
||||
contains('Wasm module compile failed.'),
|
||||
contains('Validation error: Bad magic number (at offset 0)'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ void main() {
|
|||
0x7e, 0x0b,
|
||||
]);
|
||||
|
||||
var inst = WasmModule(data).instantiate().build();
|
||||
var inst = WasmModule(data).builder().build();
|
||||
var fn = inst.lookupFunction('square');
|
||||
|
||||
expect(() => fn(), throwsA(isArgumentError));
|
||||
|
|
|
@ -31,67 +31,65 @@ void main() {
|
|||
var mod = WasmModule(data);
|
||||
|
||||
// Valid instantiation.
|
||||
mod
|
||||
.instantiate()
|
||||
.addFunction('env', 'someFn', (int a, int b, num c, double d) => 123)
|
||||
(mod.builder()
|
||||
..addFunction(
|
||||
'env',
|
||||
'someFn',
|
||||
(int a, int b, num c, double d) => 123,
|
||||
))
|
||||
.build();
|
||||
|
||||
// Missing imports.
|
||||
expect(
|
||||
() => mod.instantiate().build(),
|
||||
throwsExceptionWithToString(contains('Missing import')),
|
||||
() => mod.builder().build(),
|
||||
throwsWasmError(startsWith('Missing import')),
|
||||
);
|
||||
|
||||
// Wrong kind of import.
|
||||
expect(
|
||||
() => mod.instantiate().addMemory('env', 'someFn', mod.createMemory(10)),
|
||||
throwsExceptionWithToString(
|
||||
contains('Import is not a memory'),
|
||||
),
|
||||
() => mod.builder().addMemory('env', 'someFn', mod.createMemory(10)),
|
||||
throwsWasmError(startsWith('Import is not a memory:')),
|
||||
);
|
||||
|
||||
// Wrong namespace.
|
||||
expect(
|
||||
() => mod
|
||||
.instantiate()
|
||||
.addFunction(
|
||||
'foo',
|
||||
'someFn',
|
||||
(int a, int b, num c, double d) => 123,
|
||||
)
|
||||
() => (mod.builder()
|
||||
..addFunction(
|
||||
'foo',
|
||||
'someFn',
|
||||
(int a, int b, num c, double d) => 123,
|
||||
))
|
||||
.build(),
|
||||
throwsExceptionWithToString(contains('Import not found')),
|
||||
throwsWasmError(startsWith('Import not found:')),
|
||||
);
|
||||
|
||||
// Wrong name.
|
||||
expect(
|
||||
() => mod
|
||||
.instantiate()
|
||||
.addFunction(
|
||||
'env',
|
||||
'otherFn',
|
||||
(int a, int b, num c, double d) => 123,
|
||||
)
|
||||
() => (mod.builder()
|
||||
..addFunction(
|
||||
'env',
|
||||
'otherFn',
|
||||
(int a, int b, num c, double d) => 123,
|
||||
))
|
||||
.build(),
|
||||
throwsExceptionWithToString(contains('Import not found')),
|
||||
throwsWasmError(startsWith('Import not found:')),
|
||||
);
|
||||
|
||||
// Already filled.
|
||||
expect(
|
||||
() => 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,
|
||||
)
|
||||
() => (mod.builder()
|
||||
..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(),
|
||||
throwsExceptionWithToString(contains('Import already filled')),
|
||||
throwsWasmError(startsWith('Import already filled: env::someFn')),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,26 +25,24 @@ void main() {
|
|||
0x80, 0x80, 0x00, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x0b,
|
||||
]);
|
||||
|
||||
var calledB = false;
|
||||
var thrownException = Exception('Hello exception!');
|
||||
var inst = WasmModule(data).instantiate().addFunction('env', 'a', () {
|
||||
throw thrownException;
|
||||
}).addFunction('env', 'b', () {
|
||||
calledB = true;
|
||||
}).build();
|
||||
var inst = (WasmModule(data).builder()
|
||||
..addFunction('env', 'a', () {
|
||||
throw thrownException;
|
||||
})
|
||||
..addFunction('env', 'b', () {
|
||||
fail('should not get here!');
|
||||
}))
|
||||
.build();
|
||||
|
||||
var fn = inst.lookupFunction('fn');
|
||||
expect(() => fn(), throwsA(thrownException));
|
||||
expect(calledB, isFalse);
|
||||
|
||||
var calledA = false;
|
||||
inst = WasmModule(data).instantiate().addFunction('env', 'a', () {
|
||||
calledA = true;
|
||||
}).addFunction('env', 'b', () {
|
||||
calledB = true;
|
||||
}).build();
|
||||
inst = (WasmModule(data).builder()
|
||||
..addFunction('env', 'a', expectAsync0(() => null))
|
||||
..addFunction('env', 'b', expectAsync0(() => null)))
|
||||
.build();
|
||||
fn = inst.lookupFunction('fn');
|
||||
fn();
|
||||
expect(calledA, isTrue);
|
||||
expect(calledB, isTrue);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,11 +26,12 @@ void main() {
|
|||
var reportX = -1;
|
||||
var reportY = -1;
|
||||
|
||||
var inst = WasmModule(data).instantiate().addFunction('env', 'report',
|
||||
(int x, int y) {
|
||||
reportX = x;
|
||||
reportY = y;
|
||||
}).build();
|
||||
var inst = (WasmModule(data).builder()
|
||||
..addFunction('env', 'report', (int x, int y) {
|
||||
reportX = x;
|
||||
reportY = y;
|
||||
}))
|
||||
.build();
|
||||
var fn = inst.lookupFunction('reportStuff');
|
||||
fn();
|
||||
expect(123, reportX);
|
||||
|
|
|
@ -172,7 +172,7 @@ void main() {
|
|||
]);
|
||||
|
||||
var inst =
|
||||
WasmModule(data).instantiate().enableWasi(captureStdout: true).build();
|
||||
(WasmModule(data).builder()..enableWasi(captureStdout: true)).build();
|
||||
|
||||
var fn = inst.lookupFunction('_start');
|
||||
fn();
|
||||
|
|
|
@ -184,23 +184,24 @@ void main() {
|
|||
return n;
|
||||
}
|
||||
|
||||
var inst = WasmModule(data)
|
||||
.instantiate()
|
||||
.addFunction('wasi_unstable', 'fd_write',
|
||||
(int fd, int iovs, int iovsLen, int unused) {
|
||||
// iovs points to an array of length iovs_len. Each element is two I32s,
|
||||
// a char* and a length.
|
||||
var o = StringBuffer();
|
||||
for (var i = 0; i < iovsLen; ++i) {
|
||||
var str = getI32(iovs + 8 * i);
|
||||
var len = getI32(iovs + 4 + 8 * i);
|
||||
for (var j = 0; j < len; ++j) {
|
||||
o.write(String.fromCharCode(mem[str + j]));
|
||||
var builder = WasmModule(data).builder()
|
||||
..addFunction('wasi_unstable', 'fd_write',
|
||||
(int fd, int iovs, int iovsLen, int unused) {
|
||||
// iovs points to an array of length iovs_len. Each element is two I32s,
|
||||
// a char* and a length.
|
||||
var o = StringBuffer();
|
||||
for (var i = 0; i < iovsLen; ++i) {
|
||||
var str = getI32(iovs + 8 * i);
|
||||
var len = getI32(iovs + 4 + 8 * i);
|
||||
for (var j = 0; j < len; ++j) {
|
||||
o.write(String.fromCharCode(mem[str + j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write(o.toString());
|
||||
return o.length;
|
||||
}).build();
|
||||
out.write(o.toString());
|
||||
return o.length;
|
||||
});
|
||||
|
||||
var inst = builder.build();
|
||||
mem = inst.memory;
|
||||
|
||||
var fn = inst.lookupFunction('_start');
|
||||
|
|
|
@ -8,6 +8,8 @@ import 'dart:typed_data';
|
|||
import 'package:test/test.dart';
|
||||
import 'package:wasm/wasm.dart';
|
||||
|
||||
import 'test_shared.dart';
|
||||
|
||||
void main() {
|
||||
test('memory errors', () {
|
||||
// Empty wasm module.
|
||||
|
@ -16,10 +18,19 @@ void main() {
|
|||
]);
|
||||
var module = WasmModule(data);
|
||||
|
||||
expect(() => module.createMemory(1000000000), throwsA(isException));
|
||||
expect(
|
||||
() => module.createMemory(1000000000),
|
||||
throwsWasmError(startsWith('Failed to create memory.')),
|
||||
);
|
||||
var mem = module.createMemory(100);
|
||||
expect(() => mem.grow(1000000000), throwsA(isException));
|
||||
expect(
|
||||
() => mem.grow(1000000000),
|
||||
throwsWasmError('Failed to grow memory.'),
|
||||
);
|
||||
mem = module.createMemory(100, 200);
|
||||
expect(() => mem.grow(300), throwsA(isException));
|
||||
expect(
|
||||
() => mem.grow(300),
|
||||
throwsWasmError('Failed to grow memory.'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ void main() {
|
|||
0x01, 0x92, 0x0b,
|
||||
]);
|
||||
|
||||
var inst = WasmModule(data).instantiate().build();
|
||||
var inst = WasmModule(data).builder().build();
|
||||
var addI64 = inst.lookupFunction('addI64');
|
||||
var addI32 = inst.lookupFunction('addI32');
|
||||
var addF64 = inst.lookupFunction('addF64');
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:wasm/src/wasm_error.dart';
|
||||
|
||||
Matcher throwsExceptionWithToString(Object matcher) => throwsA(
|
||||
isA<Exception>().having((p0) => p0.toString(), 'toString', matcher),
|
||||
Matcher throwsWasmError(Object messageMatcher) => throwsA(
|
||||
isA<WasmError>().having((p0) => p0.message, 'message', messageMatcher),
|
||||
);
|
||||
|
|
|
@ -26,7 +26,7 @@ void main() {
|
|||
0x80, 0x08, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
]);
|
||||
|
||||
var inst = WasmModule(data).instantiate().build();
|
||||
var inst = WasmModule(data).builder().build();
|
||||
var setFn = inst.lookupFunction('set');
|
||||
var getFn = inst.lookupFunction('get');
|
||||
expect(setFn(123, 456), isNull);
|
||||
|
|
|
@ -19,10 +19,8 @@ void main() {
|
|||
|
||||
// Failed to fill WASI imports (the empty module was not built with WASI).
|
||||
expect(
|
||||
() => WasmModule(emptyModuleData).instantiate().enableWasi(),
|
||||
throwsExceptionWithToString(
|
||||
contains('Failed to fill WASI imports'),
|
||||
),
|
||||
() => WasmModule(emptyModuleData).builder().enableWasi(),
|
||||
throwsWasmError(startsWith('Failed to fill WASI imports.')),
|
||||
);
|
||||
|
||||
// Hello world module generated by emscripten+WASI. Exports a function like
|
||||
|
@ -187,37 +185,32 @@ void main() {
|
|||
|
||||
// Trying to import WASI twice.
|
||||
expect(
|
||||
() => WasmModule(helloWorldData).instantiate().enableWasi().enableWasi(),
|
||||
throwsExceptionWithToString(contains('WASI is already enabled')),
|
||||
() => WasmModule(helloWorldData).builder()..enableWasi()..enableWasi(),
|
||||
throwsWasmError(startsWith('WASI is already enabled')),
|
||||
);
|
||||
|
||||
// Missing imports due to not enabling WASI.
|
||||
expect(
|
||||
() => WasmModule(helloWorldData).instantiate().build(),
|
||||
throwsExceptionWithToString(contains('Missing import')),
|
||||
() => WasmModule(helloWorldData).builder().build(),
|
||||
throwsWasmError(startsWith('Missing import: ')),
|
||||
);
|
||||
|
||||
// Trying to get stdout/stderr without WASI enabled (WASI function import has
|
||||
// been manually filled).
|
||||
var inst = WasmModule(helloWorldData)
|
||||
.instantiate()
|
||||
.addFunction(
|
||||
'wasi_unstable',
|
||||
'fd_write',
|
||||
(int fd, int iovs, int iovsLen, int unused) => 0,
|
||||
)
|
||||
var inst = (WasmModule(helloWorldData).builder()
|
||||
..addFunction(
|
||||
'wasi_unstable',
|
||||
'fd_write',
|
||||
(int fd, int iovs, int iovsLen, int unused) => 0,
|
||||
))
|
||||
.build();
|
||||
expect(
|
||||
() => inst.stdout,
|
||||
throwsExceptionWithToString(
|
||||
contains("Can't capture stdout without WASI enabled"),
|
||||
),
|
||||
throwsWasmError("Can't capture stdout without WASI enabled."),
|
||||
);
|
||||
expect(
|
||||
() => inst.stderr,
|
||||
throwsExceptionWithToString(
|
||||
contains("Can't capture stderr without WASI enabled"),
|
||||
),
|
||||
throwsWasmError("Can't capture stderr without WASI enabled."),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -132,8 +132,8 @@ def getWasmerApi():
|
|||
|
||||
def getRuntimeMemb():
|
||||
return '\n'.join([
|
||||
" late Wasmer%sFn %s;" % (dartFnTypeName(name), dartFnMembName(name))
|
||||
for name, _, _ in getFns()
|
||||
" late final Wasmer%sFn %s;" %
|
||||
(dartFnTypeName(name), dartFnMembName(name)) for name, _, _ in getFns()
|
||||
])
|
||||
|
||||
|
||||
|
|
|
@ -11,21 +11,20 @@
|
|||
part of 'runtime.dart';
|
||||
|
||||
class WasmRuntime {
|
||||
static WasmRuntime? _inst;
|
||||
|
||||
DynamicLibrary _lib;
|
||||
late Pointer<WasmerEngine> _engine;
|
||||
Map<int, _WasmTrapsEntry> traps = {};
|
||||
static final WasmRuntime _inst = WasmRuntime._init();
|
||||
final DynamicLibrary _lib;
|
||||
final _traps = <int, _WasmTrapsEntry>{};
|
||||
late final Pointer<WasmerEngine> _engine;
|
||||
|
||||
/* <RUNTIME_MEMB> */
|
||||
|
||||
factory WasmRuntime() => _inst ??= WasmRuntime._init();
|
||||
factory WasmRuntime() => _inst;
|
||||
|
||||
WasmRuntime._init() : _lib = DynamicLibrary.open(_getLibPath()) {
|
||||
/* <RUNTIME_LOAD> */
|
||||
|
||||
if (_Dart_InitializeApiDL(NativeApi.initializeApiDLData) != 0) {
|
||||
throw Exception('Failed to initialize Dart API');
|
||||
throw WasmError('Failed to initialize Dart API');
|
||||
}
|
||||
_engine = _engine_new();
|
||||
_checkNotEqual(_engine, nullptr, 'Failed to initialize Wasm engine.');
|
||||
|
@ -73,11 +72,11 @@ class WasmRuntime {
|
|||
var exp = exportsVec.ref.data[i];
|
||||
var extern = _exporttype_type(exp);
|
||||
var kind = _externtype_kind(extern);
|
||||
var fnType = kind == WasmerExternKindFunction
|
||||
var fnType = kind == wasmerExternKindFunction
|
||||
? _externtype_as_functype(extern)
|
||||
: nullptr;
|
||||
exps.add(
|
||||
WasmExportDescriptor(
|
||||
WasmExportDescriptor._(
|
||||
kind,
|
||||
_exporttype_name(exp).ref.toString(),
|
||||
fnType,
|
||||
|
@ -96,11 +95,11 @@ class WasmRuntime {
|
|||
var imp = importsVec.ref.data[i];
|
||||
var extern = _importtype_type(imp);
|
||||
var kind = _externtype_kind(extern);
|
||||
var fnType = kind == WasmerExternKindFunction
|
||||
var fnType = kind == wasmerExternKindFunction
|
||||
? _externtype_as_functype(extern)
|
||||
: nullptr;
|
||||
imps.add(
|
||||
WasmImportDescriptor(
|
||||
WasmImportDescriptor._(
|
||||
kind,
|
||||
_importtype_module(imp).ref.toString(),
|
||||
_importtype_name(imp).ref.toString(),
|
||||
|
@ -119,19 +118,19 @@ class WasmRuntime {
|
|||
// with a corresponding exception, and their memory is managed using a
|
||||
// finalizer on the _WasmTrapsEntry. Traps can also be created by WASM
|
||||
// code, and in that case we delete them in this function.
|
||||
var entry = traps[trap.address];
|
||||
var entry = _traps.remove(trap.address);
|
||||
if (entry != null) {
|
||||
traps.remove(entry);
|
||||
// ignore: only_throw_errors
|
||||
throw entry.exception;
|
||||
} else {
|
||||
// TODO: code path not hit in tests!
|
||||
var trapMessage = calloc<WasmerByteVec>();
|
||||
_trap_message(trap, trapMessage);
|
||||
var message = 'Wasm trap when calling $source: ${trapMessage.ref}';
|
||||
_byte_vec_delete(trapMessage);
|
||||
calloc.free(trapMessage);
|
||||
_trap_delete(trap);
|
||||
throw Exception(message);
|
||||
throw WasmError(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,9 +183,9 @@ class WasmRuntime {
|
|||
int getReturnType(Pointer<WasmerFunctype> funcType) {
|
||||
var rets = _functype_results(funcType);
|
||||
if (rets.ref.length == 0) {
|
||||
return WasmerValKindVoid;
|
||||
return wasmerValKindVoid;
|
||||
} else if (rets.ref.length > 1) {
|
||||
throw Exception('Multiple return values are not supported');
|
||||
throw WasmError('Multiple return values are not supported');
|
||||
}
|
||||
return _valtype_kind(rets.ref.data[0]);
|
||||
}
|
||||
|
@ -214,7 +213,7 @@ class WasmRuntime {
|
|||
) {
|
||||
var limPtr = calloc<WasmerLimits>();
|
||||
limPtr.ref.min = pages;
|
||||
limPtr.ref.max = maxPages ?? wasm_limits_max_default;
|
||||
limPtr.ref.max = maxPages ?? wasmLimitsMaxDefault;
|
||||
var memType = _memorytype_new(limPtr);
|
||||
calloc.free(limPtr);
|
||||
_checkNotEqual(memType, nullptr, 'Failed to create memory type.');
|
||||
|
@ -272,7 +271,7 @@ class WasmRuntime {
|
|||
_checkNotEqual(trap, nullptr, 'Failed to create trap.');
|
||||
var entry = _WasmTrapsEntry(exception);
|
||||
_set_finalizer_for_trap(entry, trap);
|
||||
traps[trap.address] = entry;
|
||||
_traps[trap.address] = entry;
|
||||
return trap;
|
||||
}
|
||||
|
||||
|
@ -336,7 +335,7 @@ class WasmRuntime {
|
|||
|
||||
T _checkNotEqual<T>(T x, T y, String errorMessage) {
|
||||
if (x == y) {
|
||||
throw Exception('$errorMessage\n${_getLastError()}');
|
||||
throw WasmError('$errorMessage\n${_getLastError()}'.trim());
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue