Skip to content

Commit e5180d0

Browse files
liamappelbecommit-bot@chromium.org
authored andcommitted
[vm/wasm] Wasm module instantiation and function calling
Add support for instantiating modules, getting their exported functions, and calling those functions. Function calling is tricky to implement, because we need to put the args in an array to pass to wasm, and Dart doesn't have variadic functions. So I implemented it by overriding noSuchMethod. Users can call WasmFunction like a regular function, and the args will be dynamically type checked and put in the array to pass to wasm. WasmImports is a placeholder for now. Also, it's not possible to get the function names until FFI supports passing structs by value, so for now you can only get functions by their export index. If by-value structs are delayed, I can add an intermediate C++ layer to the wasmer library work around this. Bug: #37882 Change-Id: I1214c96df324cfc9fc02a48bc09a269da1b8c6f6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/160144 Commit-Queue: Liam Appelbe <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent e6bfae0 commit e5180d0

File tree

9 files changed

+549
-120
lines changed

9 files changed

+549
-120
lines changed

.dart_tool/package_config.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"constraint, update this by running tools/generate_package_config.dart."
1212
],
1313
"configVersion": 2,
14-
"generated": "2020-08-18T11:26:08.472483",
14+
"generated": "2020-08-18T15:38:52.410101",
1515
"generator": "tools/generate_package_config.dart",
1616
"packages": [
1717
{
@@ -719,7 +719,7 @@
719719
"name": "wasm",
720720
"rootUri": "../pkg/wasm",
721721
"packageUri": "lib/",
722-
"languageVersion": "2.6"
722+
"languageVersion": "2.10"
723723
},
724724
{
725725
"name": "watcher",

pkg/wasm/lib/module.dart

-15
This file was deleted.

pkg/wasm/lib/runtime.dart

-101
This file was deleted.

pkg/wasm/lib/src/function.dart

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'runtime.dart';
6+
import 'wasmer_api.dart';
7+
import 'dart:ffi';
8+
import 'package:ffi/ffi.dart';
9+
10+
/// WasmFunction is a callable function from a WasmInstance.
11+
class WasmFunction {
12+
Pointer<WasmerExportFunc> _func;
13+
List<int> _argTypes;
14+
int _returnType;
15+
Pointer<WasmerValue> _args;
16+
Pointer<WasmerValue> _result;
17+
18+
WasmFunction(this._func, this._argTypes, this._returnType) {
19+
_args = allocate<WasmerValue>(count: _argTypes.length);
20+
_result = allocate<WasmerValue>();
21+
for (var i = 0; i < _argTypes.length; ++i) {
22+
_args[i].tag = _argTypes[i];
23+
}
24+
}
25+
26+
bool _fillArg(dynamic arg, int i) {
27+
switch (_argTypes[i]) {
28+
case WasmerValueTagI32:
29+
if (arg is! int) return false;
30+
_args[i].i32 = arg;
31+
return true;
32+
case WasmerValueTagI64:
33+
if (arg is! int) return false;
34+
_args[i].i64 = arg;
35+
return true;
36+
case WasmerValueTagF32:
37+
if (arg is! num) return false;
38+
_args[i].f32 = arg;
39+
return true;
40+
case WasmerValueTagF64:
41+
if (arg is! num) return false;
42+
_args[i].f64 = arg;
43+
return true;
44+
}
45+
}
46+
47+
dynamic apply(List<dynamic> args) {
48+
if (args.length != _argTypes.length) {
49+
throw Exception("Wrong number arguments for WASM function");
50+
}
51+
for (var i = 0; i < args.length; ++i) {
52+
if (!_fillArg(args[i], i)) {
53+
throw Exception("Bad argument type for WASM function");
54+
}
55+
}
56+
WasmRuntime().call(_func, _args, _argTypes.length, _result,
57+
_returnType == WasmerValueTagVoid ? 0 : 1);
58+
59+
if (_returnType == WasmerValueTagVoid) {
60+
return null;
61+
}
62+
assert(_returnType == _result.ref.tag);
63+
switch (_returnType) {
64+
case WasmerValueTagI32:
65+
return _result.ref.i32;
66+
case WasmerValueTagI64:
67+
return _result.ref.i64;
68+
case WasmerValueTagF32:
69+
return _result.ref.f32;
70+
case WasmerValueTagF64:
71+
return _result.ref.f64;
72+
}
73+
}
74+
75+
dynamic noSuchMethod(Invocation invocation) {
76+
if (invocation.memberName == #call) {
77+
return apply(invocation.positionalArguments);
78+
}
79+
return super.noSuchMethod(invocation);
80+
}
81+
}

pkg/wasm/lib/src/module.dart

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'runtime.dart';
6+
import 'function.dart';
7+
import 'wasmer_api.dart';
8+
import 'dart:typed_data';
9+
import 'dart:ffi';
10+
import 'package:ffi/ffi.dart';
11+
12+
/// WasmModule is a compiled module that can be instantiated.
13+
class WasmModule {
14+
Pointer<WasmerModule> _module;
15+
16+
/// Compile a module.
17+
WasmModule(Uint8List data) {
18+
_module = WasmRuntime().compile(data);
19+
}
20+
21+
/// Instantiate the module with the given imports.
22+
WasmInstance instantiate(WasmImports imports) {
23+
return WasmInstance(_module, imports);
24+
}
25+
}
26+
27+
/// WasmImports holds all the imports for a WasmInstance.
28+
class WasmImports {
29+
Pointer<WasmerImport> _imports;
30+
int _capacity;
31+
int _length;
32+
33+
/// Create an imports object.
34+
WasmImports([this._capacity = 4]) : _length = 0 {
35+
_imports = allocate<WasmerImport>(count: this._capacity);
36+
}
37+
38+
/// Returns the number of imports.
39+
int get length => _length;
40+
}
41+
42+
/// WasmInstance is an instantiated WasmModule.
43+
class WasmInstance {
44+
Pointer<WasmerModule> _module;
45+
Pointer<WasmerInstance> _instance;
46+
List<WasmFunction> _functions;
47+
48+
WasmInstance(this._module, WasmImports imports) {
49+
var runtime = WasmRuntime();
50+
_instance = runtime.instantiate(_module, imports._imports, imports.length);
51+
_functions = [];
52+
var exps = runtime.exports(_instance);
53+
for (var e in exps) {
54+
var kind = runtime.exportKind(e);
55+
if (kind == WasmerImpExpKindFunction) {
56+
var f = runtime.exportToFunction(e);
57+
_functions.add(
58+
WasmFunction(f, runtime.getArgTypes(f), runtime.getReturnType(f)));
59+
}
60+
}
61+
}
62+
63+
List<dynamic> get functions => _functions;
64+
}

0 commit comments

Comments
 (0)