Skip to content

Commit

Permalink
[dart2wasm] Make dart compile wasm compiled apps disable `dart.libr…
Browse files Browse the repository at this point in the history
…ary.ffi`

This is a follow-up to [0]. That CL changed dart2wasm's modular
transformer to issue an error if `dart:ffi` is imported.

Users of packages that have specialized code for the VM (which supports
FFI) use conditional imports based on `dart.library.ffi`. We don't want
the VM-specific code to be used for web in dart2wasm (as dart2wasm
doesn't support the entirety of `dart:ffi`).

As a result we're going to make `dart.library.ffi` be false in
coditional imports (as well as in
`const bool.fromEnvironment('dart.library.ffi')`).

[0] https://dart-review.googlesource.com/c/sdk/+/368568

Issue #55948
Issue flutter/flutter#149984

Change-Id: I70a775278ab701d1fd2596521e378cb6364edac2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370580
Commit-Queue: Martin Kustermann <[email protected]>
Reviewed-by: Srujan Gaddam <[email protected]>
  • Loading branch information
mkustermann authored and Commit Queue committed Jun 11, 2024
1 parent 324ba0c commit 847c356
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 11 deletions.
14 changes: 10 additions & 4 deletions pkg/_js_interop_checks/lib/js_interop_checks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class JsInteropChecks extends RecursiveVisitor {
final ExportChecker exportChecker;
final bool isDart2Wasm;

final List<String> _disallowedInteropLibrariesInDart2Wasm;

/// Native tests to exclude from checks on external.
// TODO(rileyporter): Use ExternalName from CFE to exclude native tests.
static final List<Pattern> _allowedNativeTestPatterns = [
Expand All @@ -107,7 +109,7 @@ class JsInteropChecks extends RecursiveVisitor {
// Negative lookahead to test the violation.
RegExp(
r'(?<!generated_)tests/lib/js/static_interop_test(?!/disallowed_interop_libraries_test.dart)'),
RegExp(r'(?<!generated_)tests/web/wasm'),
RegExp(r'(?<!generated_)tests/web/wasm/(?!ffi/).*'),
// Flutter tests.
RegExp(r'flutter/lib/web_ui/test'),
];
Expand All @@ -131,7 +133,7 @@ class JsInteropChecks extends RecursiveVisitor {
];

/// Interop libraries that cannot be used in dart2wasm.
static const _disallowedInteropLibrariesInDart2Wasm = [
static const _disallowedInteropLibrariesInDart2WasmByDefault = [
'package:js/js.dart',
'package:js/js_util.dart',
'dart:js_util',
Expand Down Expand Up @@ -163,12 +165,16 @@ class JsInteropChecks extends RecursiveVisitor {

JsInteropChecks(this._coreTypes, ClassHierarchy hierarchy, this._reporter,
this._nativeClasses,
{this.isDart2Wasm = false})
{this.isDart2Wasm = false, bool enableExperimentalFfi = false})
: exportChecker = ExportChecker(_reporter, _coreTypes.objectClass),
_functionToJSTarget = _coreTypes.index.getTopLevelProcedure(
'dart:js_interop', 'FunctionToJSExportedDartFunction|get#toJS'),
_staticTypeContext = StatefulStaticTypeContext.stacked(
TypeEnvironment(_coreTypes, hierarchy)) {
TypeEnvironment(_coreTypes, hierarchy)),
_disallowedInteropLibrariesInDart2Wasm = [
for (final entry in _disallowedInteropLibrariesInDart2WasmByDefault)
if (!(entry == 'dart:ffi' && enableExperimentalFfi)) entry
] {
extensionIndex =
ExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/dart2wasm/lib/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ Future<CompilerOutput?> compileToModule(compiler.WasmCompilerOptions options,
mode = wasm.Mode.regular;
}
final WasmTarget target = WasmTarget(
removeAsserts: !options.translatorOptions.enableAsserts, mode: mode);
enableExperimentalFfi: options.translatorOptions.enableExperimentalFfi,
removeAsserts: !options.translatorOptions.enableAsserts,
mode: mode);
CompilerOptions compilerOptions = CompilerOptions()
..target = target
// This is a dummy directory that always exists. This option should be
Expand Down
3 changes: 3 additions & 0 deletions pkg/dart2wasm/lib/dart2wasm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ final List<Option> options = [
StringOption(
"dump-kernel-after-tfa", (o, value) => o.dumpKernelAfterTfa = value,
hide: true),
Flag("enable-experimental-ffi",
(o, value) => o.translatorOptions.enableExperimentalFfi = value,
defaultsTo: _d.translatorOptions.enableExperimentalFfi),
];

Map<fe.ExperimentalFlag, bool> processFeExperimentalFlags(
Expand Down
18 changes: 13 additions & 5 deletions pkg/dart2wasm/lib/target.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,14 @@ class ConstantResolver extends Transformer {
}

class WasmTarget extends Target {
WasmTarget({this.removeAsserts = false, this.mode = Mode.regular});

bool removeAsserts;
Mode mode;
WasmTarget(
{this.enableExperimentalFfi = true,
this.removeAsserts = false,
this.mode = Mode.regular});

final bool removeAsserts;
final Mode mode;
final bool enableExperimentalFfi;
Class? _growableList;
Class? _immutableList;
Class? _wasmDefaultMap;
Expand Down Expand Up @@ -206,7 +210,7 @@ class WasmTarget extends Target {
diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>);
final jsInteropChecks = JsInteropChecks(
coreTypes, hierarchy, jsInteropReporter, _nativeClasses!,
isDart2Wasm: true);
isDart2Wasm: true, enableExperimentalFfi: enableExperimentalFfi);
// Process and validate first before doing anything with exports.
for (Library library in interopDependentLibraries) {
jsInteropChecks.visitLibrary(library);
Expand Down Expand Up @@ -497,6 +501,10 @@ class WasmTarget extends Target {
@override
Class concreteDoubleLiteralClass(CoreTypes coreTypes, double value) =>
_boxedDouble ??= coreTypes.index.getClass("dart:core", "_BoxedDouble");

@override
DartLibrarySupport get dartLibrarySupport => CustomizedDartLibrarySupport(
unsupported: {if (!enableExperimentalFfi) 'ffi'});
}

class WasmVerification extends Verification {
Expand Down
1 change: 1 addition & 0 deletions pkg/dart2wasm/lib/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class TranslatorOptions {
bool minify = false;
bool verifyTypeChecks = false;
bool verbose = false;
bool enableExperimentalFfi = false;
int inliningLimit = 0;
int? sharedMemoryMaxPages;
List<int> watchPoints = [];
Expand Down
5 changes: 5 additions & 0 deletions tests/web/wasm/ffi/disabled_helper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// 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.

String tryAccessFfi() => 'Have no dart:ffi support';
12 changes: 12 additions & 0 deletions tests/web/wasm/ffi/disabled_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.

import 'package:expect/expect.dart';

import 'disabled_helper.dart' if (dart.library.ffi) 'enabled_helper.dart';

void main() {
Expect.isFalse(const bool.fromEnvironment('dart.library.ffi'));
Expect.equals('Have no dart:ffi support', tryAccessFfi());
}
8 changes: 8 additions & 0 deletions tests/web/wasm/ffi/enabled_helper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// 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.

import 'dart:ffi';

String tryAccessFfi() =>
'Have dart:ffi support (${Pointer<Int8>.fromAddress(int.parse('10')).address})';
14 changes: 14 additions & 0 deletions tests/web/wasm/ffi/enabled_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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=--extra-compiler-option=--enable-experimental-ffi

import 'package:expect/expect.dart';

import 'disabled_helper.dart' if (dart.library.ffi) 'enabled_helper.dart';

void main() {
Expect.isTrue(const bool.fromEnvironment('dart.library.ffi'));
Expect.equals('Have dart:ffi support (10)', tryAccessFfi());
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.

// dart2wasmOptions=--extra-compiler-option=--enable-experimental-ffi
// SharedObjects=ffi_native_test_module

import 'dart:ffi';
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion utils/dart2wasm/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ template("wasm_module") {
"compiled_action",
rebase_path("//third_party/emsdk/upstream/emscripten/emcc"),
"--no-entry",
rebase_path("//tests/web/wasm/${invoker.module_name}.c"),
rebase_path("//tests/web/wasm/ffi/${invoker.module_name}.c"),
"-o",
rebase_path("$root_out_dir/wasm/${invoker.module_name}.wasm"),
"-O",
Expand Down

0 comments on commit 847c356

Please sign in to comment.