[wasm] Wrapper library to get import/export names

Since FFI doesn't support structs by value yet, this thin wrapper
library just provides versions of the import/export name functions that
return the name by pointer. Also, I've used these functions to allow
looking up functions by name, and added a function that prints a
module's imports and exports (which is handy for debugging).

Change-Id: Iff386e0b843bd8ab3763c99d3dc445ffedb12d6a
BUG: https://github.com/dart-lang/sdk/issues/37882
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161765
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Liam Appelbe <liama@google.com>
This commit is contained in:
Liam Appelbe 2020-09-14 22:00:07 +00:00 committed by commit-bot@chromium.org
parent cdd1260ef0
commit 0e84aceb7e
8 changed files with 313 additions and 23 deletions

View file

@ -89,7 +89,7 @@ template("rust_library") {
config("${target_name}_cargo_config") {
if (!shared) {
libs = [ invoker.lib_name ]
lib_dirs = [ out_dir ]
lib_dirs = [ target_out_dir ]
}
}
@ -97,7 +97,7 @@ template("rust_library") {
# So we need to copy it to target_out_dir to make it easier for dependees to
# locate the library.
copy(target_name) {
deps = [ ":${target_name}_cargo" ]
public_deps = [ ":${target_name}_cargo" ]
sources = [ "${cargo_out_dir}/${output_file}" ]
outputs = [ "${target_out_dir}/${output_file}" ]
}

View file

@ -22,6 +22,24 @@ class WasmModule {
WasmInstance instantiate(WasmImports imports) {
return WasmInstance(_module, imports);
}
/// Returns a description of all of the module's imports and exports, for
/// debugging.
String describe() {
var description = StringBuffer();
var runtime = WasmRuntime();
var imports = runtime.importDescriptors(_module);
for (var imp in imports) {
var kind = wasmerImpExpKindName(imp.kind);
description.write('import $kind: ${imp.moduleName}::${imp.name}\n');
}
var exports = runtime.exportDescriptors(_module);
for (var exp in exports) {
var kind = wasmerImpExpKindName(exp.kind);
description.write('export $kind: ${exp.name}\n');
}
return description.toString();
}
}
/// WasmImports holds all the imports for a WasmInstance.
@ -43,22 +61,25 @@ class WasmImports {
class WasmInstance {
Pointer<WasmerModule> _module;
Pointer<WasmerInstance> _instance;
List<WasmFunction> _functions;
Map<String, WasmFunction> _functions;
WasmInstance(this._module, WasmImports imports) {
var runtime = WasmRuntime();
_instance = runtime.instantiate(_module, imports._imports, imports.length);
_functions = [];
_functions = {};
var exps = runtime.exports(_instance);
for (var e in exps) {
var kind = runtime.exportKind(e);
String name = runtime.exportName(e);
if (kind == WasmerImpExpKindFunction) {
var f = runtime.exportToFunction(e);
_functions.add(
WasmFunction(f, runtime.getArgTypes(f), runtime.getReturnType(f)));
_functions[name] =
WasmFunction(f, runtime.getArgTypes(f), runtime.getReturnType(f));
}
}
}
List<dynamic> get functions => _functions;
dynamic lookupFunction(String name) {
return _functions[name];
}
}

View file

@ -10,6 +10,19 @@ import 'package:ffi/ffi.dart';
import 'package:path/path.dart' as path;
import 'wasmer_api.dart';
class WasmImportDescriptor {
int kind;
String moduleName;
String name;
WasmImportDescriptor(this.kind, this.moduleName, this.name);
}
class WasmExportDescriptor {
int kind;
String name;
WasmExportDescriptor(this.kind, this.name);
}
class WasmRuntime {
static WasmRuntime _inst;
@ -26,6 +39,20 @@ class WasmRuntime {
WasmerExportFuncParamsArityFn _export_func_params_arity;
WasmerExportFuncParamsFn _export_func_params;
WasmerExportFuncCallFn _export_func_call;
WasmerExportNamePtrFn _export_name_ptr;
WasmerExportDescriptorsFn _export_descriptors;
WasmerExportDescriptorsDestroyFn _export_descriptors_destroy;
WasmerExportDescriptorsLenFn _export_descriptors_len;
WasmerExportDescriptorsGetFn _export_descriptors_get;
WasmerExportDescriptorKindFn _export_descriptor_kind;
WasmerExportDescriptorNamePtrFn _export_descriptor_name_ptr;
WasmerImportDescriptorModuleNamePtrFn _import_descriptor_module_name_ptr;
WasmerImportDescriptorNamePtrFn _import_descriptor_name_ptr;
WasmerImportDescriptorsFn _import_descriptors;
WasmerImportDescriptorsDestroyFn _import_descriptors_destroy;
WasmerImportDescriptorsLenFn _import_descriptors_len;
WasmerImportDescriptorsGetFn _import_descriptors_get;
WasmerImportDescriptorKindFn _import_descriptor_kind;
factory WasmRuntime() {
if (_inst == null) {
@ -35,8 +62,8 @@ class WasmRuntime {
}
static String _getLibName() {
if (Platform.isMacOS) return "libwasmer.dylib";
if (Platform.isLinux) return "libwasmer.so";
if (Platform.isMacOS) return "libwasmer_wrapper.dylib";
if (Platform.isLinux) return "libwasmer_wrapper.so";
throw Exception("Wasm not currently supported on this platform");
}
@ -103,6 +130,47 @@ class WasmRuntime {
WasmerExportFuncParamsFn>('wasmer_export_func_params');
_export_func_call = _lib.lookupFunction<NativeWasmerExportFuncCallFn,
WasmerExportFuncCallFn>('wasmer_export_func_call');
_export_descriptors = _lib.lookupFunction<NativeWasmerExportDescriptorsFn,
WasmerExportDescriptorsFn>('wasmer_export_descriptors');
_export_descriptors_destroy = _lib.lookupFunction<
NativeWasmerExportDescriptorsDestroyFn,
WasmerExportDescriptorsDestroyFn>('wasmer_export_descriptors_destroy');
_export_descriptors_len = _lib.lookupFunction<
NativeWasmerExportDescriptorsLenFn,
WasmerExportDescriptorsLenFn>('wasmer_export_descriptors_len');
_export_descriptors_get = _lib.lookupFunction<
NativeWasmerExportDescriptorsGetFn,
WasmerExportDescriptorsGetFn>('wasmer_export_descriptors_get');
_export_descriptor_kind = _lib.lookupFunction<
NativeWasmerExportDescriptorKindFn,
WasmerExportDescriptorKindFn>('wasmer_export_descriptor_kind');
_export_name_ptr =
_lib.lookupFunction<NativeWasmerExportNamePtrFn, WasmerExportNamePtrFn>(
'wasmer_export_name_ptr');
_export_descriptor_name_ptr = _lib.lookupFunction<
NativeWasmerExportDescriptorNamePtrFn,
WasmerExportDescriptorNamePtrFn>('wasmer_export_descriptor_name_ptr');
_import_descriptors = _lib.lookupFunction<NativeWasmerImportDescriptorsFn,
WasmerImportDescriptorsFn>('wasmer_import_descriptors');
_import_descriptors_destroy = _lib.lookupFunction<
NativeWasmerImportDescriptorsDestroyFn,
WasmerImportDescriptorsDestroyFn>('wasmer_import_descriptors_destroy');
_import_descriptors_len = _lib.lookupFunction<
NativeWasmerImportDescriptorsLenFn,
WasmerImportDescriptorsLenFn>('wasmer_import_descriptors_len');
_import_descriptors_get = _lib.lookupFunction<
NativeWasmerImportDescriptorsGetFn,
WasmerImportDescriptorsGetFn>('wasmer_import_descriptors_get');
_import_descriptor_kind = _lib.lookupFunction<
NativeWasmerImportDescriptorKindFn,
WasmerImportDescriptorKindFn>('wasmer_import_descriptor_kind');
_import_descriptor_module_name_ptr = _lib.lookupFunction<
NativeWasmerImportDescriptorModuleNamePtrFn,
WasmerImportDescriptorModuleNamePtrFn>(
'wasmer_import_descriptor_module_name_ptr');
_import_descriptor_name_ptr = _lib.lookupFunction<
NativeWasmerImportDescriptorNamePtrFn,
WasmerImportDescriptorNamePtrFn>('wasmer_import_descriptor_name_ptr');
}
Pointer<WasmerModule> compile(Uint8List data) {
@ -125,6 +193,49 @@ class WasmRuntime {
return modulePtr;
}
String _callStringWrapperFunction(Function fn, dynamic arg) {
var strPtr = allocate<WasmerByteArray>();
fn(arg, strPtr);
var str = strPtr.ref.string;
free(strPtr);
return str;
}
List<WasmExportDescriptor> exportDescriptors(Pointer<WasmerModule> module) {
var exportsPtrPtr = allocate<Pointer<WasmerExportDescriptors>>();
_export_descriptors(module, exportsPtrPtr);
Pointer<WasmerExportDescriptors> exportsPtr = exportsPtrPtr.value;
free(exportsPtrPtr);
var n = _export_descriptors_len(exportsPtr);
var exps = <WasmExportDescriptor>[];
for (var i = 0; i < n; ++i) {
var exp = _export_descriptors_get(exportsPtr, i);
exps.add(WasmExportDescriptor(_export_descriptor_kind(exp),
_callStringWrapperFunction(_export_descriptor_name_ptr, exp)));
}
_export_descriptors_destroy(exportsPtr);
return exps;
}
List<WasmImportDescriptor> importDescriptors(Pointer<WasmerModule> module) {
var importsPtrPtr = allocate<Pointer<WasmerImportDescriptors>>();
_import_descriptors(module, importsPtrPtr);
Pointer<WasmerImportDescriptors> importsPtr = importsPtrPtr.value;
free(importsPtrPtr);
var n = _import_descriptors_len(importsPtr);
var imps = <WasmImportDescriptor>[];
for (var i = 0; i < n; ++i) {
var imp = _import_descriptors_get(importsPtr, i);
imps.add(WasmImportDescriptor(
_import_descriptor_kind(imp),
_callStringWrapperFunction(_import_descriptor_module_name_ptr, imp),
_callStringWrapperFunction(_import_descriptor_name_ptr, imp)));
}
_import_descriptors_destroy(importsPtr);
return imps;
}
Pointer<WasmerInstance> instantiate(Pointer<WasmerModule> module,
Pointer<WasmerImport> imports, int numImports) {
var instancePtrPtr = allocate<Pointer<WasmerInstance>>();
@ -157,6 +268,10 @@ class WasmRuntime {
return _export_kind(export);
}
String exportName(Pointer<WasmerExport> export) {
return _callStringWrapperFunction(_export_name_ptr, export);
}
Pointer<WasmerExportFunc> exportToFunction(Pointer<WasmerExport> export) {
return _export_to_func(export);
}

View file

@ -2,6 +2,7 @@
// 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:convert';
import 'dart:ffi';
import 'dart:typed_data';
@ -24,6 +25,21 @@ const int WasmerImpExpKindGlobal = 1;
const int WasmerImpExpKindMemory = 2;
const int WasmerImpExpKindTable = 3;
String wasmerImpExpKindName(int kind) {
switch (kind) {
case WasmerImpExpKindFunction:
return "function";
case WasmerImpExpKindGlobal:
return "global";
case WasmerImpExpKindMemory:
return "memory";
case WasmerImpExpKindTable:
return "table";
default:
return "unknown";
}
}
// wasmer_module_t
class WasmerModule extends Struct {}
@ -36,9 +52,21 @@ class WasmerExports extends Struct {}
// wasmer_export_t
class WasmerExport extends Struct {}
// wasmer_export_descriptors_t
class WasmerExportDescriptors extends Struct {}
// wasmer_export_descriptor_t
class WasmerExportDescriptor extends Struct {}
// wasmer_export_func_t
class WasmerExportFunc extends Struct {}
// wasmer_import_descriptors_t
class WasmerImportDescriptors extends Struct {}
// wasmer_import_descriptor_t
class WasmerImportDescriptor extends Struct {}
// wasmer_import_t
class WasmerImport extends Struct {
Pointer<Uint8> module_name;
@ -69,6 +97,7 @@ class WasmerByteArray extends Struct {
int length;
Uint8List get list => bytes.asTypedList(length);
String get string => utf8.decode(list);
}
// wasmer_value_t
@ -130,10 +159,89 @@ typedef NativeWasmerExportsGetFn = Pointer<WasmerExport> Function(
typedef WasmerExportsGetFn = Pointer<WasmerExport> Function(
Pointer<WasmerExports>, int);
// wasmer_export_name
typedef NativeWasmerExportNameFn = WasmerByteArray Function(
Pointer<WasmerExport>);
typedef WasmerExportNameFn = WasmerByteArray Function(Pointer<WasmerExport>);
// wasmer_export_descriptors
typedef NativeWasmerExportDescriptorsFn = Void Function(
Pointer<WasmerModule>, Pointer<Pointer<WasmerExportDescriptors>>);
typedef WasmerExportDescriptorsFn = void Function(
Pointer<WasmerModule>, Pointer<Pointer<WasmerExportDescriptors>>);
// wasmer_export_descriptors_destroy
typedef NativeWasmerExportDescriptorsDestroyFn = Void Function(
Pointer<WasmerExportDescriptors>);
typedef WasmerExportDescriptorsDestroyFn = void Function(
Pointer<WasmerExportDescriptors>);
// wasmer_export_descriptors_len
typedef NativeWasmerExportDescriptorsLenFn = Int32 Function(
Pointer<WasmerExportDescriptors>);
typedef WasmerExportDescriptorsLenFn = int Function(
Pointer<WasmerExportDescriptors>);
// wasmer_export_descriptors_get
typedef NativeWasmerExportDescriptorsGetFn = Pointer<WasmerExportDescriptor>
Function(Pointer<WasmerExportDescriptors>, Int32);
typedef WasmerExportDescriptorsGetFn = Pointer<WasmerExportDescriptor> Function(
Pointer<WasmerExportDescriptors>, int);
// wasmer_export_descriptor_kind
typedef NativeWasmerExportDescriptorKindFn = Uint32 Function(
Pointer<WasmerExportDescriptor>);
typedef WasmerExportDescriptorKindFn = int Function(
Pointer<WasmerExportDescriptor>);
// wasmer_export_descriptor_name_ptr
typedef NativeWasmerExportDescriptorNamePtrFn = Void Function(
Pointer<WasmerExportDescriptor>, Pointer<WasmerByteArray>);
typedef WasmerExportDescriptorNamePtrFn = void Function(
Pointer<WasmerExportDescriptor>, Pointer<WasmerByteArray>);
// wasmer_import_descriptors
typedef NativeWasmerImportDescriptorsFn = Void Function(
Pointer<WasmerModule>, Pointer<Pointer<WasmerImportDescriptors>>);
typedef WasmerImportDescriptorsFn = void Function(
Pointer<WasmerModule>, Pointer<Pointer<WasmerImportDescriptors>>);
// wasmer_import_descriptors_destroy
typedef NativeWasmerImportDescriptorsDestroyFn = Void Function(
Pointer<WasmerImportDescriptors>);
typedef WasmerImportDescriptorsDestroyFn = void Function(
Pointer<WasmerImportDescriptors>);
// wasmer_import_descriptors_len
typedef NativeWasmerImportDescriptorsLenFn = Int32 Function(
Pointer<WasmerImportDescriptors>);
typedef WasmerImportDescriptorsLenFn = int Function(
Pointer<WasmerImportDescriptors>);
// wasmer_import_descriptors_get
typedef NativeWasmerImportDescriptorsGetFn = Pointer<WasmerImportDescriptor>
Function(Pointer<WasmerImportDescriptors>, Int32);
typedef WasmerImportDescriptorsGetFn = Pointer<WasmerImportDescriptor> Function(
Pointer<WasmerImportDescriptors>, int);
// wasmer_import_descriptor_kind
typedef NativeWasmerImportDescriptorKindFn = Uint32 Function(
Pointer<WasmerImportDescriptor>);
typedef WasmerImportDescriptorKindFn = int Function(
Pointer<WasmerImportDescriptor>);
// wasmer_import_descriptor_module_name_ptr
typedef NativeWasmerImportDescriptorModuleNamePtrFn = Void Function(
Pointer<WasmerImportDescriptor>, Pointer<WasmerByteArray>);
typedef WasmerImportDescriptorModuleNamePtrFn = void Function(
Pointer<WasmerImportDescriptor>, Pointer<WasmerByteArray>);
// wasmer_import_descriptor_name_ptr
typedef NativeWasmerImportDescriptorNamePtrFn = Void Function(
Pointer<WasmerImportDescriptor>, Pointer<WasmerByteArray>);
typedef WasmerImportDescriptorNamePtrFn = void Function(
Pointer<WasmerImportDescriptor>, Pointer<WasmerByteArray>);
// wasmer_export_name_ptr
typedef NativeWasmerExportNamePtrFn = Void Function(
Pointer<WasmerExport>, Pointer<WasmerByteArray>);
typedef WasmerExportNamePtrFn = void Function(
Pointer<WasmerExport>, Pointer<WasmerByteArray>);
// wasmer_export_kind
typedef NativeWasmerExportKindFn = Uint32 Function(Pointer<WasmerExport>);

View file

@ -586,15 +586,16 @@ copy("copy_wasmer") {
visibility = [ ":create_common_sdk" ]
deps = [
":copy_libraries",
"../third_party/wasmer:wasmer_lib",
"../third_party/wasmer:wasmer_wrapper",
]
outputs = [ "$root_out_dir/dart-sdk/bin/third_party/wasmer/{{source_file_part}}" ]
outputs =
[ "$root_out_dir/dart-sdk/bin/third_party/wasmer/{{source_file_part}}" ]
if (is_win) {
sources = [ "$target_out_dir/../third_party/wasmer/wasmer.dll" ]
sources = [ "$target_out_dir/../../wasmer_wrapper.dll" ]
} else if (is_mac) {
sources = [ "$target_out_dir/../third_party/wasmer/libwasmer.dylib" ]
sources = [ "$target_out_dir/../../libwasmer_wrapper.dylib" ]
} else {
sources = [ "$target_out_dir/../third_party/wasmer/libwasmer.so" ]
sources = [ "$target_out_dir/../../libwasmer_wrapper.so" ]
}
}

View file

@ -1,11 +1,17 @@
import("../../build/rust/rust.gni")
component("wasmer") {
public = [ "wasmer.hh" ]
shared_library("wasmer_wrapper") {
sources = [
"wasmer.hh",
"wasmer_wrapper.cc",
]
deps = [ ":wasmer_lib" ]
if (is_linux) {
libs = [ "rt" ]
}
ldflags = [ "-Wl,--no-as-needed" ] # Force linking of all wasmer symbols.
}
rust_library("wasmer_lib") {
lib_name = "wasmer"
shared = true
}

View file

@ -4,7 +4,7 @@ version = "0.17.1"
[lib]
name = "wasmer"
crate-type = ["dylib"]
crate-type = ["staticlib"]
path = "wasmer.rs"
[dependencies]

39
third_party/wasmer/wasmer_wrapper.cc vendored Normal file
View file

@ -0,0 +1,39 @@
// 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.
// Wraps several functions from wasmer.hh, so that they take and return all
// structs by pointer, rather than by value. This is necessary because Dart FFI
// doesn't support passing structs by value yet (once it does, we can delete
// this wrapper).
#include "wasmer.hh"
extern "C" {
// Wraps wasmer_export_name.
void wasmer_export_name_ptr(wasmer_export_t* export_,
wasmer_byte_array* out_name) {
*out_name = wasmer_export_name(export_);
}
// Wraps wasmer_export_descriptor_name.
void wasmer_export_descriptor_name_ptr(
wasmer_export_descriptor_t* export_descriptor,
wasmer_byte_array* out_name) {
*out_name = wasmer_export_descriptor_name(export_descriptor);
}
// Wraps wasmer_import_descriptor_module_name.
void wasmer_import_descriptor_module_name_ptr(
wasmer_import_descriptor_t* import_descriptor,
wasmer_byte_array* out_name) {
*out_name = wasmer_import_descriptor_module_name(import_descriptor);
}
// Wraps wasmer_import_descriptor_name.
void wasmer_import_descriptor_name_ptr(
wasmer_import_descriptor_t* import_descriptor,
wasmer_byte_array* out_name) {
*out_name = wasmer_import_descriptor_name(import_descriptor);
}
}