[dart2wasm] Add flag to allow experimental wasm interop.
Adds a flag users can use via
dart compile wasm \
--extra-compiler-option=--enable-experimental-wasm-interop
which allows code to import `dart:_wasm` and use import/export
pragmas.
Similar to how we have a way to import `dart:ffi`
dart compile wasm \
--extra-compiler-option=--enable-experimental-ffi
TEST=web/wasm/allow_import_export_pragmas_test (positive test)
TEST=web/wasm/reject_import_export_pragmas_test (negative test)
Change-Id: Ibdbbac6c3aa049b2759e96b7b749dd30ecc6aaed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370063
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Jackson Gardner <jacksongardner@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/compile.dart b/pkg/dart2wasm/lib/compile.dart
index 45a08ae..89ec6c0 100644
--- a/pkg/dart2wasm/lib/compile.dart
+++ b/pkg/dart2wasm/lib/compile.dart
@@ -82,6 +82,8 @@
}
final WasmTarget target = WasmTarget(
enableExperimentalFfi: options.translatorOptions.enableExperimentalFfi,
+ enableExperimentalWasmInterop:
+ options.translatorOptions.enableExperimentalWasmInterop,
removeAsserts: !options.translatorOptions.enableAsserts,
mode: mode);
CompilerOptions compilerOptions = CompilerOptions()
diff --git a/pkg/dart2wasm/lib/dart2wasm.dart b/pkg/dart2wasm/lib/dart2wasm.dart
index bda60de..d106088 100644
--- a/pkg/dart2wasm/lib/dart2wasm.dart
+++ b/pkg/dart2wasm/lib/dart2wasm.dart
@@ -55,6 +55,9 @@
Flag("verify-type-checks",
(o, value) => o.translatorOptions.verifyTypeChecks = value,
defaultsTo: _d.translatorOptions.verifyTypeChecks),
+ Flag("enable-experimental-wasm-interop",
+ (o, value) => o.translatorOptions.enableExperimentalWasmInterop = value,
+ defaultsTo: _d.translatorOptions.enableExperimentalWasmInterop),
IntOption(
"inlining-limit", (o, value) => o.translatorOptions.inliningLimit = value,
defaultsTo: "${_d.translatorOptions.inliningLimit}"),
diff --git a/pkg/dart2wasm/lib/target.dart b/pkg/dart2wasm/lib/target.dart
index 7342b26..4af0c96 100644
--- a/pkg/dart2wasm/lib/target.dart
+++ b/pkg/dart2wasm/lib/target.dart
@@ -91,12 +91,14 @@
class WasmTarget extends Target {
WasmTarget(
{this.enableExperimentalFfi = true,
+ this.enableExperimentalWasmInterop = true,
this.removeAsserts = false,
this.mode = Mode.regular});
final bool removeAsserts;
final Mode mode;
final bool enableExperimentalFfi;
+ final bool enableExperimentalWasmInterop;
Class? _growableList;
Class? _immutableList;
Class? _wasmDefaultMap;
@@ -175,13 +177,28 @@
bool mayDefineRestrictedType(Uri uri) => uri.isScheme('dart');
@override
- bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
- super.allowPlatformPrivateLibraryAccess(importer, imported) ||
- importer.path.contains('tests/web/wasm') ||
- importer.isScheme('package') &&
- (importer.path == 'js/js.dart' ||
- importer.path.startsWith('ui/') &&
- imported.toString() == 'dart:_wasm');
+ bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) {
+ if (super.allowPlatformPrivateLibraryAccess(importer, imported)) {
+ return true;
+ }
+
+ if (imported.toString() == 'dart:_wasm') {
+ return enableExperimentalWasmInterop;
+ }
+
+ final importerString = importer.toString();
+
+ // We have some tests that import dart:js*
+ if (importerString.contains('tests/web/wasm')) return true;
+
+ // Flutter's dart:ui is also package:ui (in test mode)
+ if (importerString.startsWith('package:ui/')) return true;
+
+ // package:js can import dart:js* & dart:_js_*
+ if (importerString.startsWith('package:js/')) return true;
+
+ return false;
+ }
void _patchHostEndian(CoreTypes coreTypes) {
// Fix Endian.host to be a const field equal to Endian.little instead of
@@ -247,10 +264,12 @@
ReferenceFromIndex? referenceFromIndex,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
- // Check `wasm:import` and `wasm:export` pragmas before FFI transforms as
- // FFI transforms convert JS interop annotations to these pragmas.
- _checkWasmImportExportPragmas(libraries, coreTypes,
- diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>);
+ if (!enableExperimentalWasmInterop) {
+ // Check `wasm:import` and `wasm:export` pragmas before FFI transforms as
+ // FFI transforms convert JS interop annotations to these pragmas.
+ _checkWasmImportExportPragmas(libraries, coreTypes,
+ diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>);
+ }
Set<Library> transitiveImportingJSInterop = {
...jsInteropHelper.calculateTransitiveImportsOfJsInteropIfUsed(
@@ -545,9 +564,7 @@
if (importUri.isScheme('dart') ||
(importUri.isScheme('package') &&
JsInteropChecks.allowedInteropLibrariesInDart2WasmPackages
- .any((pkg) => importUri.pathSegments.first == pkg)) ||
- (importUri.path.contains('tests/web/wasm') &&
- !importUri.path.contains('reject_import_export_pragmas'))) {
+ .any((pkg) => importUri.pathSegments.first == pkg))) {
continue;
}
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 938cca1..f103b14 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -45,6 +45,7 @@
bool verifyTypeChecks = false;
bool verbose = false;
bool enableExperimentalFfi = false;
+ bool enableExperimentalWasmInterop = false;
int inliningLimit = 0;
int? sharedMemoryMaxPages;
List<int> watchPoints = [];
diff --git a/tests/web/wasm/allow_import_export_pragmas_test.dart b/tests/web/wasm/allow_import_export_pragmas_test.dart
new file mode 100644
index 0000000..57fea40
--- /dev/null
+++ b/tests/web/wasm/allow_import_export_pragmas_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2024, 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.
+
+// dart2wasmOptions=--enable-experimental-wasm-interop
+
+// Test that importing `dart:_wasm` and using import/export pragmas works if the
+// compiler is given the `--enable-experimental-wasm-interop` flag.
+
+import 'dart:_wasm';
+
+@pragma('wasm:export', 'f')
+void f() {}
+
+@pragma('wasm:import', 'g')
+external WasmI32 g(WasmI32 x);
+
+void main() {}
diff --git a/tests/web/wasm/callback_test.dart b/tests/web/wasm/callback_test.dart
index 7d49c93..118c177 100644
--- a/tests/web/wasm/callback_test.dart
+++ b/tests/web/wasm/callback_test.dart
@@ -2,6 +2,8 @@
// 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.
+// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
+
import 'dart:_wasm';
import 'dart:js_util';
diff --git a/tests/web/wasm/js_exceptions_test.dart b/tests/web/wasm/js_exceptions_test.dart
index f31d7ff..7813de8 100644
--- a/tests/web/wasm/js_exceptions_test.dart
+++ b/tests/web/wasm/js_exceptions_test.dart
@@ -2,6 +2,8 @@
// 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.
+// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
+
import 'dart:js_interop';
import 'dart:_wasm';
diff --git a/tests/web/wasm/table_test.dart b/tests/web/wasm/table_test.dart
index 91351ee..de0ef1a 100644
--- a/tests/web/wasm/table_test.dart
+++ b/tests/web/wasm/table_test.dart
@@ -2,6 +2,8 @@
// 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.
+// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
+
import 'dart:_wasm';
import 'package:expect/expect.dart';
diff --git a/tests/web/wasm/wasm_types_test.dart b/tests/web/wasm/wasm_types_test.dart
index 44f843b..dd52244 100644
--- a/tests/web/wasm/wasm_types_test.dart
+++ b/tests/web/wasm/wasm_types_test.dart
@@ -2,6 +2,8 @@
// 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.
+// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
+
import 'dart:_wasm';
import 'package:expect/expect.dart';