Version 2.10.0-86.0.dev
Merge commit 'c9182ad3c00c802af5fba20283801a4cdaf38614' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index c3ba326..12e1c33 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2020-08-18T11:26:08.472483",
+ "generated": "2020-08-18T15:38:52.410101",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -719,7 +719,7 @@
"name": "wasm",
"rootUri": "../pkg/wasm",
"packageUri": "lib/",
- "languageVersion": "2.6"
+ "languageVersion": "2.10"
},
{
"name": "watcher",
diff --git a/DEPS b/DEPS
index f84b666..a31cd21 100644
--- a/DEPS
+++ b/DEPS
@@ -220,7 +220,7 @@
Var("dart_root") + "/third_party/d8": {
"packages": [{
"package": "dart/d8",
- "version": "version:7.8.279",
+ "version": "version:8.5.210",
}],
"dep_type": "cipd",
},
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_null_aware_test.dart
index 032264e..ed938e6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_null_aware_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_null_aware_test.dart
@@ -20,18 +20,16 @@
Future<void> test_singleFile() async {
await resolveTestUnit('''
-abstract class A {
- int m();
+class A {
+ int m(int p) => p;
}
-int f(A a) => null == a ? null : a.m();
-int g(A a) => a == null ? null : a.m();
+int f(A x, A y) => x == null ? null : x.m(y == null ? null : y.m(0));
''');
await assertHasFix('''
-abstract class A {
- int m();
+class A {
+ int m(int p) => p;
}
-int f(A a) => a?.m();
-int g(A a) => a?.m();
+int f(A x, A y) => x?.m(y?.m(0));
''');
}
}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 8f199a4..7353b55 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.40.2
+* Require `meta: ^1.2.3`.
+
## 0.40.1
* Added `LocalVariableElement.hasInitializer`,
`PropertyInducingElement.hasInitializer`, `ParameterElement.hasDefaultValue`.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 1204ae1..0cff7cf 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.40.1
+version: 0.40.2
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -15,7 +15,7 @@
convert: ^2.0.0
crypto: ^2.0.0
glob: ^1.0.3
- meta: ^1.0.2
+ meta: ^1.2.3
package_config: ^1.0.0
path: ^1.0.0
pub_semver: ^1.4.2
diff --git a/pkg/wasm/lib/module.dart b/pkg/wasm/lib/module.dart
deleted file mode 100644
index 4b9cde4..0000000
--- a/pkg/wasm/lib/module.dart
+++ /dev/null
@@ -1,15 +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 'runtime.dart';
-import 'dart:typed_data';
-import 'dart:ffi';
-
-class WasmModule {
- Pointer<WasmerModule> _module;
-
- WasmModule(Uint8List data) {
- _module = WasmRuntime().compile(data);
- }
-}
diff --git a/pkg/wasm/lib/runtime.dart b/pkg/wasm/lib/runtime.dart
deleted file mode 100644
index f26689c..0000000
--- a/pkg/wasm/lib/runtime.dart
+++ /dev/null
@@ -1,101 +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 'dart:io';
-import 'dart:typed_data';
-import 'package:ffi/ffi.dart';
-import 'package:path/path.dart' as path;
-
-const int WasmerResultOk = 1;
-const int WasmerResultError = 2;
-
-const int WasmerValueTagI32 = 0;
-const int WasmerValueTagI64 = 1;
-const int WasmerValueTagF32 = 2;
-const int WasmerValueTagF64 = 3;
-
-class WasmerModule extends Struct {}
-
-typedef NativeWasmerCompileFn = Uint32 Function(
- Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, Uint32);
-typedef WasmerCompileFn = int Function(
- Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, int);
-
-class WasmRuntime {
- static WasmRuntime _inst;
-
- DynamicLibrary _lib;
- WasmerCompileFn _compile;
-
- factory WasmRuntime() {
- if (_inst == null) {
- _inst = WasmRuntime._init();
- }
- return _inst;
- }
-
- static String _getLibName() {
- if (Platform.isMacOS) return "libwasmer.dylib";
- if (Platform.isLinux) return "libwasmer.so";
- throw Exception("Wasm not currently supported on this platform");
- }
-
- static String _getLibDir() {
- // The common case, and how cli_util.dart computes the Dart SDK directory,
- // path.dirname called twice on Platform.resolvedExecutable.
- var commonLibDir = path.join(
- path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))),
- 'bin',
- 'third_party',
- 'wasmer');
- if (Directory(commonLibDir).existsSync()) {
- return commonLibDir;
- }
-
- // This is the less common case where the user is in the checked out Dart
- // SDK, and is executing dart via:
- // ./out/ReleaseX64/dart ...
- var checkedOutLibDir = path.join(
- path.absolute(path.dirname(Platform.resolvedExecutable)),
- 'dart-sdk',
- 'bin',
- 'third_party',
- 'wasmer');
- if (Directory(checkedOutLibDir).existsSync()) {
- return checkedOutLibDir;
- }
-
- // If neither returned above, we return the common case:
- return commonLibDir;
- }
-
- WasmRuntime._init() {
- var libPath = path.join(_getLibDir(), _getLibName());
- _lib = DynamicLibrary.open(libPath);
- _compile = _lib
- .lookup<NativeFunction<NativeWasmerCompileFn>>('wasmer_compile')
- .asFunction();
- }
-
- Pointer<WasmerModule> compile(Uint8List data) {
- var dataPtr = allocate<Uint8>(count: data.length);
- for (int i = 0; i < data.length; ++i) {
- dataPtr[i] = data[i];
- }
-
- var modulePtrPtr = allocate<Pointer<WasmerModule>>();
- int result = _compile(modulePtrPtr, dataPtr, data.length);
- Pointer<WasmerModule> modulePtr = modulePtrPtr.value;
-
- free(modulePtrPtr);
- free(dataPtr);
-
- if (result != WasmerResultOk) {
- throw Exception("Wasm module compile failed");
- }
-
- return modulePtr;
- }
-}
diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart
new file mode 100644
index 0000000..c5840bf
--- /dev/null
+++ b/pkg/wasm/lib/src/function.dart
@@ -0,0 +1,81 @@
+// 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 'runtime.dart';
+import 'wasmer_api.dart';
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+/// WasmFunction is a callable function from a WasmInstance.
+class WasmFunction {
+ Pointer<WasmerExportFunc> _func;
+ List<int> _argTypes;
+ int _returnType;
+ Pointer<WasmerValue> _args;
+ Pointer<WasmerValue> _result;
+
+ WasmFunction(this._func, this._argTypes, this._returnType) {
+ _args = allocate<WasmerValue>(count: _argTypes.length);
+ _result = allocate<WasmerValue>();
+ for (var i = 0; i < _argTypes.length; ++i) {
+ _args[i].tag = _argTypes[i];
+ }
+ }
+
+ bool _fillArg(dynamic arg, int i) {
+ switch (_argTypes[i]) {
+ case WasmerValueTagI32:
+ if (arg is! int) return false;
+ _args[i].i32 = arg;
+ return true;
+ case WasmerValueTagI64:
+ if (arg is! int) return false;
+ _args[i].i64 = arg;
+ return true;
+ case WasmerValueTagF32:
+ if (arg is! num) return false;
+ _args[i].f32 = arg;
+ return true;
+ case WasmerValueTagF64:
+ if (arg is! num) return false;
+ _args[i].f64 = arg;
+ return true;
+ }
+ }
+
+ dynamic apply(List<dynamic> args) {
+ if (args.length != _argTypes.length) {
+ throw Exception("Wrong number arguments for WASM function");
+ }
+ for (var i = 0; i < args.length; ++i) {
+ if (!_fillArg(args[i], i)) {
+ throw Exception("Bad argument type for WASM function");
+ }
+ }
+ WasmRuntime().call(_func, _args, _argTypes.length, _result,
+ _returnType == WasmerValueTagVoid ? 0 : 1);
+
+ if (_returnType == WasmerValueTagVoid) {
+ return null;
+ }
+ assert(_returnType == _result.ref.tag);
+ switch (_returnType) {
+ case WasmerValueTagI32:
+ return _result.ref.i32;
+ case WasmerValueTagI64:
+ return _result.ref.i64;
+ case WasmerValueTagF32:
+ return _result.ref.f32;
+ case WasmerValueTagF64:
+ return _result.ref.f64;
+ }
+ }
+
+ dynamic noSuchMethod(Invocation invocation) {
+ if (invocation.memberName == #call) {
+ return apply(invocation.positionalArguments);
+ }
+ return super.noSuchMethod(invocation);
+ }
+}
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
new file mode 100644
index 0000000..1034a9e
--- /dev/null
+++ b/pkg/wasm/lib/src/module.dart
@@ -0,0 +1,64 @@
+// 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 'runtime.dart';
+import 'function.dart';
+import 'wasmer_api.dart';
+import 'dart:typed_data';
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+/// WasmModule is a compiled module that can be instantiated.
+class WasmModule {
+ Pointer<WasmerModule> _module;
+
+ /// Compile a module.
+ WasmModule(Uint8List data) {
+ _module = WasmRuntime().compile(data);
+ }
+
+ /// Instantiate the module with the given imports.
+ WasmInstance instantiate(WasmImports imports) {
+ return WasmInstance(_module, imports);
+ }
+}
+
+/// WasmImports holds all the imports for a WasmInstance.
+class WasmImports {
+ Pointer<WasmerImport> _imports;
+ int _capacity;
+ int _length;
+
+ /// Create an imports object.
+ WasmImports([this._capacity = 4]) : _length = 0 {
+ _imports = allocate<WasmerImport>(count: this._capacity);
+ }
+
+ /// Returns the number of imports.
+ int get length => _length;
+}
+
+/// WasmInstance is an instantiated WasmModule.
+class WasmInstance {
+ Pointer<WasmerModule> _module;
+ Pointer<WasmerInstance> _instance;
+ List<WasmFunction> _functions;
+
+ WasmInstance(this._module, WasmImports imports) {
+ var runtime = WasmRuntime();
+ _instance = runtime.instantiate(_module, imports._imports, imports.length);
+ _functions = [];
+ var exps = runtime.exports(_instance);
+ for (var e in exps) {
+ var kind = runtime.exportKind(e);
+ if (kind == WasmerImpExpKindFunction) {
+ var f = runtime.exportToFunction(e);
+ _functions.add(
+ WasmFunction(f, runtime.getArgTypes(f), runtime.getReturnType(f)));
+ }
+ }
+ }
+
+ List<dynamic> get functions => _functions;
+}
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
new file mode 100644
index 0000000..b8d3686
--- /dev/null
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -0,0 +1,219 @@
+// 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:convert';
+import 'dart:ffi';
+import 'dart:io';
+import 'dart:typed_data';
+import 'package:ffi/ffi.dart';
+import 'package:path/path.dart' as path;
+import 'wasmer_api.dart';
+
+class WasmRuntime {
+ static WasmRuntime _inst;
+
+ DynamicLibrary _lib;
+ WasmerCompileFn _compile;
+ WasmerInstantiateFn _instantiate;
+ WasmerInstanceExportsFn _instance_exports;
+ WasmerExportsLenFn _exports_len;
+ WasmerExportsGetFn _exports_get;
+ WasmerExportKindFn _export_kind;
+ WasmerExportToFuncFn _export_to_func;
+ WasmerExportFuncReturnsArityFn _export_func_returns_arity;
+ WasmerExportFuncReturnsFn _export_func_returns;
+ WasmerExportFuncParamsArityFn _export_func_params_arity;
+ WasmerExportFuncParamsFn _export_func_params;
+ WasmerExportFuncCallFn _export_func_call;
+
+ factory WasmRuntime() {
+ if (_inst == null) {
+ _inst = WasmRuntime._init();
+ }
+ return _inst;
+ }
+
+ static String _getLibName() {
+ if (Platform.isMacOS) return "libwasmer.dylib";
+ if (Platform.isLinux) return "libwasmer.so";
+ throw Exception("Wasm not currently supported on this platform");
+ }
+
+ static String _getLibDir() {
+ // The common case, and how cli_util.dart computes the Dart SDK directory,
+ // path.dirname called twice on Platform.resolvedExecutable.
+ var commonLibDir = path.join(
+ path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))),
+ 'bin',
+ 'third_party',
+ 'wasmer');
+ if (Directory(commonLibDir).existsSync()) {
+ return commonLibDir;
+ }
+
+ // This is the less common case where the user is in the checked out Dart
+ // SDK, and is executing dart via:
+ // ./out/ReleaseX64/dart ...
+ var checkedOutLibDir = path.join(
+ path.absolute(path.dirname(Platform.resolvedExecutable)),
+ 'dart-sdk',
+ 'bin',
+ 'third_party',
+ 'wasmer');
+ if (Directory(checkedOutLibDir).existsSync()) {
+ return checkedOutLibDir;
+ }
+
+ // If neither returned above, we return the common case:
+ return commonLibDir;
+ }
+
+ WasmRuntime._init() {
+ var libPath = path.join(_getLibDir(), _getLibName());
+ _lib = DynamicLibrary.open(libPath);
+ _compile = _lib.lookupFunction<NativeWasmerCompileFn, WasmerCompileFn>(
+ 'wasmer_compile');
+ _instantiate =
+ _lib.lookupFunction<NativeWasmerInstantiateFn, WasmerInstantiateFn>(
+ 'wasmer_module_instantiate');
+ _instance_exports = _lib.lookupFunction<NativeWasmerInstanceExportsFn,
+ WasmerInstanceExportsFn>('wasmer_instance_exports');
+ _exports_len =
+ _lib.lookupFunction<NativeWasmerExportsLenFn, WasmerExportsLenFn>(
+ 'wasmer_exports_len');
+ _exports_get =
+ _lib.lookupFunction<NativeWasmerExportsGetFn, WasmerExportsGetFn>(
+ 'wasmer_exports_get');
+ _export_kind =
+ _lib.lookupFunction<NativeWasmerExportKindFn, WasmerExportKindFn>(
+ 'wasmer_export_kind');
+ _export_to_func =
+ _lib.lookupFunction<NativeWasmerExportToFuncFn, WasmerExportToFuncFn>(
+ 'wasmer_export_to_func');
+ _export_func_returns_arity = _lib.lookupFunction<
+ NativeWasmerExportFuncReturnsArityFn,
+ WasmerExportFuncReturnsArityFn>('wasmer_export_func_returns_arity');
+ _export_func_returns = _lib.lookupFunction<NativeWasmerExportFuncReturnsFn,
+ WasmerExportFuncReturnsFn>('wasmer_export_func_returns');
+ _export_func_params_arity = _lib.lookupFunction<
+ NativeWasmerExportFuncParamsArityFn,
+ WasmerExportFuncParamsArityFn>('wasmer_export_func_params_arity');
+ _export_func_params = _lib.lookupFunction<NativeWasmerExportFuncParamsFn,
+ WasmerExportFuncParamsFn>('wasmer_export_func_params');
+ _export_func_call = _lib.lookupFunction<NativeWasmerExportFuncCallFn,
+ WasmerExportFuncCallFn>('wasmer_export_func_call');
+ }
+
+ Pointer<WasmerModule> compile(Uint8List data) {
+ var dataPtr = allocate<Uint8>(count: data.length);
+ for (int i = 0; i < data.length; ++i) {
+ dataPtr[i] = data[i];
+ }
+
+ var modulePtrPtr = allocate<Pointer<WasmerModule>>();
+ int result = _compile(modulePtrPtr, dataPtr, data.length);
+ Pointer<WasmerModule> modulePtr = modulePtrPtr.value;
+
+ free(modulePtrPtr);
+ free(dataPtr);
+
+ if (result != WasmerResultOk) {
+ throw Exception("Wasm module compile failed");
+ }
+
+ return modulePtr;
+ }
+
+ Pointer<WasmerInstance> instantiate(Pointer<WasmerModule> module,
+ Pointer<WasmerImport> imports, int numImports) {
+ var instancePtrPtr = allocate<Pointer<WasmerInstance>>();
+ int result = _instantiate(module, instancePtrPtr, imports, numImports);
+ Pointer<WasmerInstance> instancePtr = instancePtrPtr.value;
+ free(instancePtrPtr);
+
+ if (result != WasmerResultOk) {
+ throw Exception("Wasm module instantiation failed");
+ }
+
+ return instancePtr;
+ }
+
+ List<Pointer<WasmerExport>> exports(Pointer<WasmerInstance> instancePtr) {
+ var exportsPtrPtr = allocate<Pointer<WasmerExports>>();
+ _instance_exports(instancePtr, exportsPtrPtr);
+ Pointer<WasmerExports> exportsPtr = exportsPtrPtr.value;
+ free(exportsPtrPtr);
+
+ var n = _exports_len(exportsPtr);
+ var exps = <Pointer<WasmerExport>>[];
+ for (var i = 0; i < n; ++i) {
+ exps.add(_exports_get(exportsPtr, i));
+ }
+ return exps;
+ }
+
+ int exportKind(Pointer<WasmerExport> export) {
+ return _export_kind(export);
+ }
+
+ Pointer<WasmerExportFunc> exportToFunction(Pointer<WasmerExport> export) {
+ return _export_to_func(export);
+ }
+
+ List<int> getArgTypes(Pointer<WasmerExportFunc> func) {
+ var types = <int>[];
+ var nPtr = allocate<Uint32>();
+ var result = _export_func_params_arity(func, nPtr);
+ if (result != WasmerResultOk) {
+ free(nPtr);
+ throw Exception("Failed to get number of WASM function args");
+ }
+ var n = nPtr.value;
+ free(nPtr);
+ var argsPtr = allocate<Uint32>(count: n);
+ result = _export_func_params(func, argsPtr, n);
+ if (result != WasmerResultOk) {
+ free(argsPtr);
+ throw Exception("Failed to get WASM function args");
+ }
+ for (var i = 0; i < n; ++i) {
+ types.add(argsPtr[i]);
+ }
+ free(argsPtr);
+ return types;
+ }
+
+ int getReturnType(Pointer<WasmerExportFunc> func) {
+ var nPtr = allocate<Uint32>();
+ var result = _export_func_returns_arity(func, nPtr);
+ if (result != WasmerResultOk) {
+ free(nPtr);
+ throw Exception("Failed to get number of WASM function returns");
+ }
+ var n = nPtr.value;
+ free(nPtr);
+ if (n == 0) {
+ return WasmerValueTagVoid;
+ } else if (n > 1) {
+ throw Exception("Multiple return values are not supported");
+ }
+ var returnsPtr = allocate<Uint32>();
+ result = _export_func_params(func, returnsPtr, 1);
+ if (result != WasmerResultOk) {
+ free(returnsPtr);
+ throw Exception("Failed to get WASM function args");
+ }
+ var type = returnsPtr.value;
+ free(returnsPtr);
+ return type;
+ }
+
+ void call(Pointer<WasmerExportFunc> func, Pointer<WasmerValue> args,
+ int numArgs, Pointer<WasmerValue> results, int numResults) {
+ var result = _export_func_call(func, args, numArgs, results, numArgs);
+ if (result != WasmerResultOk) {
+ throw Exception("Failed to call WASM function");
+ }
+ }
+}
diff --git a/pkg/wasm/lib/src/wasmer_api.dart b/pkg/wasm/lib/src/wasmer_api.dart
new file mode 100644
index 0000000..dc5df74
--- /dev/null
+++ b/pkg/wasm/lib/src/wasmer_api.dart
@@ -0,0 +1,180 @@
+// 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 'dart:typed_data';
+
+// wasmer_result_t
+const int WasmerResultOk = 1;
+const int WasmerResultError = 2;
+
+// wasmer_value_tag
+const int WasmerValueTagI32 = 0;
+const int WasmerValueTagI64 = 1;
+const int WasmerValueTagF32 = 2;
+const int WasmerValueTagF64 = 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 WasmerValueTagVoid = -1;
+
+// wasmer_import_export_kind
+const int WasmerImpExpKindFunction = 0;
+const int WasmerImpExpKindGlobal = 1;
+const int WasmerImpExpKindMemory = 2;
+const int WasmerImpExpKindTable = 3;
+
+// wasmer_module_t
+class WasmerModule extends Struct {}
+
+// wasmer_instance_t
+class WasmerInstance extends Struct {}
+
+// wasmer_exports_t
+class WasmerExports extends Struct {}
+
+// wasmer_export_t
+class WasmerExport extends Struct {}
+
+// wasmer_export_func_t
+class WasmerExportFunc extends Struct {}
+
+// wasmer_import_t
+class WasmerImport extends Struct {
+ Pointer<Uint8> module_name;
+
+ @Uint32()
+ int module_name_length;
+
+ Pointer<Uint8> import_name;
+
+ @Uint32()
+ int import_name_length;
+
+ // wasmer_import_export_kind
+ @Uint32()
+ int tag;
+
+ // wasmer_import_export_value, which is a union of wasmer_import_func_t*,
+ // wasmer_table_t*, wasmer_memory_t*, and wasmer_global_t*. The tag determines
+ // which type it is.
+ Pointer<Void> value;
+}
+
+// wasmer_byte_array
+class WasmerByteArray extends Struct {
+ Pointer<Uint8> bytes;
+
+ @Uint32()
+ int length;
+
+ Uint8List get list => bytes.asTypedList(length);
+}
+
+// wasmer_value_t
+class WasmerValue extends Struct {
+ // wasmer_value_tag
+ @Uint32()
+ int tag;
+
+ // wasmer_value, which is a union of int32_t, int64_t, float, and double. The
+ // tag determines which type it is. It's declared as an int64_t because that's
+ // large enough to hold all the types. We use ByteData to get the other types.
+ @Int64()
+ int value;
+
+ int get _off32 => Endian.host == Endian.little ? 0 : 4;
+ int get i64 => value;
+ ByteData get _getterBytes => ByteData(8)..setInt64(0, value, Endian.host);
+ int get i32 => _getterBytes.getInt32(_off32, Endian.host);
+ double get f32 => _getterBytes.getFloat32(_off32, Endian.host);
+ double get f64 => _getterBytes.getFloat64(0, Endian.host);
+
+ set i64(int val) => value = val;
+ set _val(ByteData bytes) => value = bytes.getInt64(0, Endian.host);
+ set i32(int val) => _val = ByteData(8)..setInt32(_off32, val, Endian.host);
+ set f32(num val) => _val = ByteData(8)..setFloat32(_off32, val, Endian.host);
+ set f64(num val) => _val = ByteData(8)..setFloat64(0, val, Endian.host);
+
+ bool get isI32 => tag == WasmerValueTagI32;
+ bool get isI64 => tag == WasmerValueTagI64;
+ bool get isF32 => tag == WasmerValueTagF32;
+ bool get isF64 => tag == WasmerValueTagF64;
+}
+
+// wasmer_compile
+typedef NativeWasmerCompileFn = Uint32 Function(
+ Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, Uint32);
+typedef WasmerCompileFn = int Function(
+ Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, int);
+
+// wasmer_module_instantiate
+typedef NativeWasmerInstantiateFn = Uint32 Function(Pointer<WasmerModule>,
+ Pointer<Pointer<WasmerInstance>>, Pointer<WasmerImport>, Int32);
+typedef WasmerInstantiateFn = int Function(Pointer<WasmerModule>,
+ Pointer<Pointer<WasmerInstance>>, Pointer<WasmerImport>, int);
+
+// wasmer_instance_exports
+typedef NativeWasmerInstanceExportsFn = Void Function(
+ Pointer<WasmerInstance>, Pointer<Pointer<WasmerExports>>);
+typedef WasmerInstanceExportsFn = void Function(
+ Pointer<WasmerInstance>, Pointer<Pointer<WasmerExports>>);
+
+// wasmer_exports_len
+typedef NativeWasmerExportsLenFn = Int32 Function(Pointer<WasmerExports>);
+typedef WasmerExportsLenFn = int Function(Pointer<WasmerExports>);
+
+// wasmer_exports_get
+typedef NativeWasmerExportsGetFn = Pointer<WasmerExport> Function(
+ Pointer<WasmerExports>, Int32);
+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_kind
+typedef NativeWasmerExportKindFn = Uint32 Function(Pointer<WasmerExport>);
+typedef WasmerExportKindFn = int Function(Pointer<WasmerExport>);
+
+// wasmer_export_to_func
+typedef NativeWasmerExportToFuncFn = Pointer<WasmerExportFunc> Function(
+ Pointer<WasmerExport>);
+typedef WasmerExportToFuncFn = Pointer<WasmerExportFunc> Function(
+ Pointer<WasmerExport>);
+
+// wasmer_export_func_returns_arity
+typedef NativeWasmerExportFuncReturnsArityFn = Uint32 Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>);
+typedef WasmerExportFuncReturnsArityFn = int Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>);
+
+// wasmer_export_func_returns
+typedef NativeWasmerExportFuncReturnsFn = Uint32 Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>, Uint32);
+typedef WasmerExportFuncReturnsFn = int Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>, int);
+
+// wasmer_export_func_params_arity
+typedef NativeWasmerExportFuncParamsArityFn = Uint32 Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>);
+typedef WasmerExportFuncParamsArityFn = int Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>);
+
+// wasmer_export_func_params
+typedef NativeWasmerExportFuncParamsFn = Uint32 Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>, Uint32);
+typedef WasmerExportFuncParamsFn = int Function(
+ Pointer<WasmerExportFunc>, Pointer<Uint32>, int);
+
+// wasmer_export_func_call
+typedef NativeWasmerExportFuncCallFn = Uint32 Function(
+ Pointer<WasmerExportFunc>,
+ Pointer<WasmerValue>,
+ Uint32,
+ Pointer<WasmerValue>,
+ Uint32);
+typedef WasmerExportFuncCallFn = int Function(Pointer<WasmerExportFunc>,
+ Pointer<WasmerValue>, int, Pointer<WasmerValue>, int);
diff --git a/pkg/wasm/lib/wasm.dart b/pkg/wasm/lib/wasm.dart
index 56b2f4b..877ff90 100644
--- a/pkg/wasm/lib/wasm.dart
+++ b/pkg/wasm/lib/wasm.dart
@@ -2,4 +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 'module.dart';
+export 'src/function.dart';
+export 'src/module.dart';
diff --git a/pkg/wasm/pubspec.yaml b/pkg/wasm/pubspec.yaml
index 04f9586..570631c 100644
--- a/pkg/wasm/pubspec.yaml
+++ b/pkg/wasm/pubspec.yaml
@@ -6,7 +6,7 @@
# This package is not intended for consumption on pub.dev. DO NOT publish.
publish_to: none
environment:
- sdk: ">=2.6.0"
+ sdk: '>=2.10.0-0 <2.10.0'
dependencies:
ffi: ^0.1.3
path: ^1.0.0
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index a844493..6e0547b 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -15,13 +15,13 @@
namespace dart {
-static const int8_t kDataBitsPerByte = 7;
-static const int8_t kByteMask = (1 << kDataBitsPerByte) - 1;
-static const int8_t kMaxUnsignedDataPerByte = kByteMask;
-static const int8_t kMinDataPerByte = -(1 << (kDataBitsPerByte - 1));
-static const int8_t kMaxDataPerByte = (~kMinDataPerByte & kByteMask); // NOLINT
-static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte);
-static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte);
+// (S)LEB128 encodes 7 bits of data per byte (hence 128).
+static constexpr uint8_t kDataBitsPerByte = 7;
+static constexpr uint8_t kDataByteMask = (1 << kDataBitsPerByte) - 1;
+// If more data follows a given data byte, the high bit is set.
+static constexpr uint8_t kMoreDataMask = (1 << kDataBitsPerByte);
+// For SLEB128, the high bit in the data of the last byte is the sign bit.
+static constexpr uint8_t kSignMask = (1 << (kDataBitsPerByte - 1));
typedef uint8_t* (*ReAlloc)(uint8_t* ptr, intptr_t old_size, intptr_t new_size);
typedef void (*DeAlloc)(uint8_t* ptr);
@@ -50,19 +50,19 @@
template <typename T>
class Raw<2, T> {
public:
- static T Read(ReadStream* st) { return bit_cast<T>(st->Read16()); }
+ static T Read(ReadStream* st) { return bit_cast<T>(st->Read16<int16_t>()); }
};
template <typename T>
class Raw<4, T> {
public:
- static T Read(ReadStream* st) { return bit_cast<T>(st->Read32()); }
+ static T Read(ReadStream* st) { return bit_cast<T>(st->Read32<int32_t>()); }
};
template <typename T>
class Raw<8, T> {
public:
- static T Read(ReadStream* st) { return bit_cast<T>(st->Read64()); }
+ static T Read(ReadStream* st) { return bit_cast<T>(st->Read64<int64_t>()); }
};
// Reads 'len' bytes from the stream.
@@ -74,9 +74,15 @@
current_ += len;
}
+ // Reads a value of type [T] assuming an encoding of LEB128 (whether or not
+ // the type itself is unsigned).
template <typename T = intptr_t>
T ReadUnsigned() {
- return Read<T>(kEndUnsignedByteMarker);
+ if (std::is_unsigned<T>::value) {
+ return ReadInternal<T>();
+ } else {
+ return bit_cast<T>(ReadUnsigned<typename std::make_unsigned<T>::type>());
+ }
}
intptr_t Position() const { return current_ - buffer_; }
@@ -103,9 +109,15 @@
return (end_ - current_);
}
+ // Reads a value of type [T] assuming an encoding of SLEB128 (whether or not
+ // the type itself is signed).
template <typename T>
T Read() {
- return Read<T>(kEndByteMarker);
+ if (std::is_signed<T>::value) {
+ return ReadInternal<T>();
+ } else {
+ return bit_cast<T>(Read<typename std::make_signed<T>::type>());
+ }
}
uword ReadWordWith32BitReads() {
@@ -122,179 +134,112 @@
}
private:
- uint16_t Read16() { return Read16(kEndByteMarker); }
-
- uint32_t Read32() { return Read32(kEndByteMarker); }
-
- uint64_t Read64() { return Read64(kEndByteMarker); }
-
template <typename T>
- T Read(uint8_t end_byte_marker) {
+ T ReadInternal() {
using Unsigned = typename std::make_unsigned<T>::type;
const uint8_t* c = current_;
- ASSERT(c < end_);
- Unsigned b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return b - end_byte_marker;
- }
- T r = 0;
+ Unsigned r = 0;
uint8_t s = 0;
+ uint8_t b;
do {
- r |= static_cast<Unsigned>(b) << s;
- s += kDataBitsPerByte;
ASSERT(c < end_);
b = *c++;
- } while (b <= kMaxUnsignedDataPerByte);
+ r |= static_cast<Unsigned>(b & kDataByteMask) << s;
+ s += kDataBitsPerByte;
+ } while ((b & kMoreDataMask) != 0);
current_ = c;
- return r | (static_cast<Unsigned>(b - end_byte_marker) << s);
+ // At this point, [s] contains how many data bits have made it into the
+ // value. If the type is signed, the value negative, and the count of data
+ // bits is less than the size of the value, then we need to extend the sign
+ // by setting the remaining (unset) most significant bits (MSBs).
+ Unsigned sign_bits = 0;
+ const bool is_signed = std::is_signed<T>::value;
+ if (is_signed && (b & kSignMask) != 0 && s < (kBitsPerByte * sizeof(T))) {
+ // Create a bitmask for the current data bits and invert it.
+ sign_bits = ~((static_cast<Unsigned>(1) << s) - 1);
+ }
+ return static_cast<T>(r | sign_bits);
}
- uint16_t Read16(uint8_t end_byte_marker) {
- const uint8_t* c = current_;
- ASSERT(c < end_);
- uint16_t b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return b - end_byte_marker;
- }
- uint16_t r = b;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint16_t>(b - end_byte_marker) << 7);
- }
+// Setting up needed variables for the unrolled loop sections below.
+#define UNROLLED_INIT() \
+ using Unsigned = typename std::make_unsigned<T>::type; \
+ const uint8_t* c = current_; \
+ uint8_t b; \
+ Unsigned r = 0;
- r |= b << 7;
- ASSERT(c < end_);
- b = *c++;
- ASSERT(b > kMaxUnsignedDataPerByte);
- current_ = c;
- return r | (static_cast<uint16_t>(b - end_byte_marker) << 14);
+// Part of the unrolled loop where the loop may stop, having read the last part,
+// or continue reading. If stopping, extend the sign for signed values.
+#define UNROLLED_BODY(bit_start) \
+ static_assert(bit_start % kDataBitsPerByte == 0, \
+ "Bit start must be a multiple of the data bits per byte"); \
+ static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T), \
+ "Starting unrolled body at invalid bit position"); \
+ ASSERT(c < end_); \
+ b = *c++; \
+ r |= static_cast<Unsigned>(b & kDataByteMask) << bit_start; \
+ if ((b & kMoreDataMask) == 0) { \
+ current_ = c; \
+ Unsigned sign_bits = 0; \
+ if (std::is_signed<T>::value && (b & kSignMask) != 0) { \
+ sign_bits = ~((static_cast<Unsigned>(1) << (bit_start + 7)) - 1); \
+ } \
+ return static_cast<T>(r | sign_bits); \
}
- uint32_t Read32(uint8_t end_byte_marker) {
- const uint8_t* c = current_;
- ASSERT(c < end_);
- uint32_t b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return b - end_byte_marker;
- }
+// If the unrolled end is reached, the last part always includes the original
+// sign bit, so no need to sign extend.
+#define UNROLLED_END(bit_start) \
+ static_assert(bit_start % kDataBitsPerByte == 0, \
+ "Bit start must be a multiple of the data bits per byte"); \
+ static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T), \
+ "Starting unrolled end at invalid bit position"); \
+ static_assert(bit_start + kDataBitsPerByte >= kBitsPerByte * sizeof(T), \
+ "Unrolled end does not contain final bits in value"); \
+ ASSERT(c < end_); \
+ b = *c++; \
+ r |= static_cast<Unsigned>(b & kDataByteMask) << bit_start; \
+ ASSERT_EQUAL((b & kMoreDataMask), 0); \
+ current_ = c; \
+ return static_cast<T>(r);
- uint32_t r = b;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint32_t>(b - end_byte_marker) << 7);
- }
-
- r |= b << 7;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint32_t>(b - end_byte_marker) << 14);
- }
-
- r |= b << 14;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint32_t>(b - end_byte_marker) << 21);
- }
-
- r |= b << 21;
- ASSERT(c < end_);
- b = *c++;
- ASSERT(b > kMaxUnsignedDataPerByte);
- current_ = c;
- return r | (static_cast<uint32_t>(b - end_byte_marker) << 28);
+ template <typename T>
+ T Read16() {
+ UNROLLED_INIT();
+ UNROLLED_BODY(0);
+ UNROLLED_BODY(7);
+ UNROLLED_END(14);
}
- uint64_t Read64(uint8_t end_byte_marker) {
- const uint8_t* c = current_;
- ASSERT(c < end_);
- uint64_t b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return b - end_byte_marker;
- }
- uint64_t r = b;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 7);
- }
-
- r |= b << 7;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 14);
- }
-
- r |= b << 14;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 21);
- }
-
- r |= b << 21;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 28);
- }
-
- r |= b << 28;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 35);
- }
-
- r |= b << 35;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 42);
- }
-
- r |= b << 42;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 49);
- }
-
- r |= b << 49;
- ASSERT(c < end_);
- b = *c++;
- if (b > kMaxUnsignedDataPerByte) {
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 56);
- }
-
- r |= b << 56;
- ASSERT(c < end_);
- b = *c++;
- ASSERT(b > kMaxUnsignedDataPerByte);
- current_ = c;
- return r | (static_cast<uint64_t>(b - end_byte_marker) << 63);
+ template <typename T>
+ T Read32() {
+ UNROLLED_INIT();
+ UNROLLED_BODY(0);
+ UNROLLED_BODY(7);
+ UNROLLED_BODY(14);
+ UNROLLED_BODY(21);
+ UNROLLED_END(28);
}
+ template <typename T>
+ T Read64() {
+ UNROLLED_INIT();
+ UNROLLED_BODY(0);
+ UNROLLED_BODY(7);
+ UNROLLED_BODY(14);
+ UNROLLED_BODY(21);
+ UNROLLED_BODY(28);
+ UNROLLED_BODY(35);
+ UNROLLED_BODY(42);
+ UNROLLED_BODY(49);
+ UNROLLED_BODY(56);
+ UNROLLED_END(63);
+ }
+
+#undef UNROLLED_END
+#undef UNROLLED_BODY
+#undef UNROLLED_INIT
+
uint8_t ReadByte() {
ASSERT(current_ < end_);
return *current_++;
@@ -350,7 +295,7 @@
class Raw<1, T> {
public:
static void Write(WriteStream* st, T value) {
- st->WriteByte(bit_cast<int8_t>(value));
+ st->WriteByte(bit_cast<uint8_t>(value));
}
};
@@ -390,14 +335,17 @@
}
}
+ // Writes the LEB128 encoding of [value] to the stream (whether or not the
+ // type [T] is unsigned).
template <typename T>
void WriteUnsigned(T value) {
ASSERT(value >= 0);
- while (value > kMaxUnsignedDataPerByte) {
- WriteByte(static_cast<uint8_t>(value & kByteMask));
- value = value >> kDataBitsPerByte;
+ if (std::is_unsigned<T>::value) {
+ WriteInternal<T>(value);
+ } else {
+ using Unsigned = typename std::make_unsigned<T>::type;
+ WriteUnsigned<Unsigned>(bit_cast<Unsigned>(value));
}
- WriteByte(static_cast<uint8_t>(value + kEndUnsignedByteMarker));
}
void WriteBytes(const void* addr, intptr_t len) {
@@ -465,14 +413,16 @@
current_ += len; // Not len + 1 to swallow the terminating NUL.
}
+ // Writes the SLEB128 encoding of [value] to the stream (whether or not the
+ // type [T] is signed).
template <typename T>
void Write(T value) {
- T v = value;
- while (v < kMinDataPerByte || v > kMaxDataPerByte) {
- WriteByte(static_cast<uint8_t>(v & kByteMask));
- v = v >> kDataBitsPerByte;
+ if (std::is_signed<T>::value) {
+ WriteInternal<T>(value);
+ } else {
+ using Signed = typename std::make_signed<T>::type;
+ Write<Signed>(bit_cast<Signed>(value));
}
- WriteByte(static_cast<uint8_t>(v + kEndByteMarker));
}
template <typename T>
@@ -487,6 +437,33 @@
}
private:
+ template <typename T>
+ void WriteInternal(T value) {
+ T remainder = value;
+ bool is_last_part;
+ do {
+ uint8_t part = static_cast<uint8_t>(remainder & kDataByteMask);
+ remainder >>= kDataBitsPerByte;
+ // For unsigned types, we're done when the remainder has no bits set.
+ // For signed types, we're done when either:
+ // - the remainder has no bits set and the part's sign bit is unset, or
+ // - the remainder has all bits set and the part's sign bit is set.
+ // If the remainder matches but the sign bit does not, we need one more
+ // part to set the sign bit correctly.
+ is_last_part =
+ std::is_unsigned<T>::value
+ ? remainder == static_cast<T>(0)
+ : (remainder == static_cast<T>(0) && (part & kSignMask) == 0) ||
+ (remainder == ~static_cast<T>(0) &&
+ (part & kSignMask) != 0);
+ if (!is_last_part) {
+ // Mark this part as having more parts following it.
+ part |= kMoreDataMask;
+ }
+ WriteByte(part);
+ } while (!is_last_part);
+ }
+
DART_FORCE_INLINE void WriteByte(uint8_t value) {
if (current_ >= end_) {
Resize(1);
@@ -514,7 +491,6 @@
ASSERT(end_ > *buffer_);
}
- private:
uint8_t** const buffer_;
uint8_t* end_;
uint8_t* current_;
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 606ef61..cce2eac 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -962,35 +962,8 @@
stream_(ASSERT_NOTNULL(stream)),
address_map_(address_map) {}
- void sleb128(intptr_t value) {
- bool is_last_part = false;
- while (!is_last_part) {
- uint8_t part = value & 0x7F;
- value >>= 7;
- if ((value == 0 && (part & 0x40) == 0) ||
- (value == static_cast<intptr_t>(-1) && (part & 0x40) != 0)) {
- is_last_part = true;
- } else {
- part |= 0x80;
- }
- stream_->WriteFixed(part);
- }
- }
-
- void uleb128(uintptr_t value) {
- bool is_last_part = false;
- while (!is_last_part) {
- uint8_t part = value & 0x7F;
- value >>= 7;
- if (value == 0) {
- is_last_part = true;
- } else {
- part |= 0x80;
- }
- stream_->WriteFixed(part);
- }
- }
-
+ void sleb128(intptr_t value) { stream_->Write(value); }
+ void uleb128(uintptr_t value) { stream_->WriteUnsigned(value); }
void u1(uint8_t value) { stream_->WriteFixed(value); }
// Can't use WriteFixed for these, as we may not be at aligned positions.
void u2(uint16_t value) { stream_->WriteBytes(&value, sizeof(value)); }
diff --git a/tools/VERSION b/tools/VERSION
index 295e955..db91a19 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 85
+PRERELEASE 86
PRERELEASE_PATCH 0
\ No newline at end of file