Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/roll-dart-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ jobs:
env:
DART_HASH: ${{ inputs.dart_hash }}
run: |
# Check if the root DEPS file has changed
if git diff --exit-code DEPS; then
# Check if the root DEPS file or supports_dart2wasm.js has changed
if git diff --exit-code DEPS engine/src/flutter/lib/web_ui/flutter_js/src/supports_dart2wasm.js; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "## ✅ Dart version already up to date" >> "$GITHUB_STEP_SUMMARY"
echo "The DEPS file is already up to date with Dart hash \`$DART_HASH\`." >> "$GITHUB_STEP_SUMMARY"
Expand All @@ -108,7 +108,7 @@ jobs:
if: steps.git-check.outputs.changed == 'true'
run: |
gh auth setup-git
git add DEPS
git add DEPS engine/src/flutter/lib/web_ui/flutter_js/src/supports_dart2wasm.js
git commit -m "Update flutter DEPS to dart $DART_HASH"
git push origin "$BRANCH_NAME" --force

Expand Down
26 changes: 26 additions & 0 deletions engine/src/flutter/ci/test/create_updated_flutter_deps_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2013 The Flutter Authors. 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:io' as io;

import 'package:engine_repo_tools/engine_repo_tools.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

void main() {
test('create_updated_flutter_deps_tests.py passes and verifies dart2wasm support parity', () {
final io.Directory srcDir = Engine.findWithin().srcDir;
final String testScript = path.join(
srcDir.path,
'tools',
'dart',
'create_updated_flutter_deps_tests.py',
);
final python = io.Platform.isWindows ? 'python' : 'python3';
final io.ProcessResult result = io.Process.runSync(python, <String>[
testScript,
], workingDirectory: srcDir.parent.path);
expect(result.exitCode, 0, reason: 'stdout:\n${result.stdout}\nstderr:\n${result.stderr}');
});
}
1 change: 1 addition & 0 deletions engine/src/flutter/lib/web_ui/flutter_js/sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ flutter_js_source_list = [
"src/loader.js",
"src/service_worker_loader.js",
"src/skwasm_loader.js",
"src/supports_dart2wasm.js",
"src/trusted_types.js",
"src/utils.js",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import { supportsDart2Wasm as defaultSupportsDart2Wasm } from './supports_dart2wasm.js';

/** @type {import("./types").WasmAllowList} */
export const defaultWasmSupport = {
"blink": true,
Expand Down Expand Up @@ -64,16 +66,7 @@ const supportsDart2Wasm = () => {
// https://bugzilla.mozilla.org/show_bug.cgi?id=2006811
if (browserEngine === "gecko" && getFirefoxVersion() < 147) return false;

// The `<app>.support.js` expression emitted by
// ```
// % dart compile wasm \
// --extra-compiler-option=--require-js-string-builtin \
// -o hello.wasm \
// hello.dart
// % cat hello.support.js
// ```
// It checks support for Wasm GC, SIMD, `js-string` builtins, and `try_table`.
return (WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,95,1,120,0]))&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11]))&&!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,2,23,1,14,119,97,115,109,58,106,115,45,115,116,114,105,110,103,4,99,97,115,116,0,0]),{"builtins":["js-string"]})&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,13,1,11,0,2,64,31,64,1,2,0,11,11,11])));
return window._flutter?.supportsDart2Wasm ?? defaultSupportsDart2Wasm();
}

const detectWebGLVersion = () => {
Expand Down
4 changes: 2 additions & 2 deletions engine/src/flutter/lib/web_ui/flutter_js/src/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class FlutterLoader {
switch (renderer) {
case "skwasm":
if (!supportsDart2Wasm) {
return "Skwasm requires WasmGC support; this browser does not implement it yet.";
return "Skwasm requires WebAssembly features (WasmGC, SIMD, js-string builtins, try_table) that this browser does not support.";
}
if (!(browserEnvironment.webGLVersion > 0)) {
return "Skwasm requires WebGL support; this browser does not provide it.";
Expand All @@ -106,7 +106,7 @@ export class FlutterLoader {
const buildIncompatibilityReason = (build) => {
if (build.compileTarget === "dart2wasm") {
if (!supportsDart2Wasm) {
return "dart2wasm requires WasmGC support; this browser does not implement it yet.";
return "dart2wasm requires WebAssembly features (WasmGC, SIMD, js-string builtins, try_table) that this browser does not support.";
}
if (!enableWasm) {
if (config.wasmAllowList?.[browserEnvironment.browserEngine] === false) {
Expand Down
12 changes: 12 additions & 0 deletions engine/src/flutter/lib/web_ui/flutter_js/src/supports_dart2wasm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// GENERATED FILE. DO NOT EDIT.
//
// Generated by `engine/src/tools/dart/create_updated_flutter_deps.py` from
// `pkg/dart2wasm/lib/compile.dart`.

export const supportsDart2Wasm = () => {
return (WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,95,1,120,0]))&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11]))&&!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,2,23,1,14,119,97,115,109,58,106,115,45,115,116,114,105,110,103,4,99,97,115,116,0,0]),{"builtins":["js-string"]})&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,13,1,11,0,2,64,31,64,1,2,0,11,11,11])));
};
29 changes: 26 additions & 3 deletions engine/src/flutter/lib/web_ui/test/fallbacks/fallbacks_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ external JSAny? get _flutterBuildConfig;
@JS('_flutter.buildConfig')
external set _flutterBuildConfig(JSAny? value);

@JS('_flutter.supportsDart2Wasm')
external JSAny? get _flutterSupportsDart2Wasm;

@JS('_flutter.supportsDart2Wasm')
external set _flutterSupportsDart2Wasm(JSAny? value);

@JS('WebAssembly.validate')
external JSFunction get _wasmValidate;

Expand All @@ -52,6 +58,7 @@ Future<void> testMain() async {

test('loader strictly honors wasmAllowList and WasmGC capability for dart2wasm builds', () async {
final JSAny? originalBuildConfig = _flutterBuildConfig;
final JSAny? originalSupportsDart2Wasm = _flutterSupportsDart2Wasm;
final JSFunction originalValidate = _wasmValidate;
try {
_flutterBuildConfig = <String, Object?>{
Expand Down Expand Up @@ -87,9 +94,10 @@ Future<void> testMain() async {
),
);

// 2. When WasmGC capability validation fails, explicit opt-in via
// wasmAllowList must still reject the dart2wasm build.
_wasmValidate = (() => false).toJS;
// 2. When _flutter.supportsDart2Wasm is false (e.g. from main.dart.support.js),
// explicit opt-in via wasmAllowList must reject the dart2wasm build even if
// defaultSupportsDart2Wasm() would pass.
_flutterSupportsDart2Wasm = false.toJS;
final JSAny? optInOptions = <String, Object?>{
'config': <String, Object?>{
'wasmAllowList': <String, bool>{
Expand All @@ -109,7 +117,22 @@ Future<void> testMain() async {
),
),
);

// 3. When _flutter.supportsDart2Wasm is unset and WebAssembly.validate fails,
// explicit opt-in via wasmAllowList must still reject the dart2wasm build.
_flutterSupportsDart2Wasm = null;
_wasmValidate = (() => false).toJS;

await expectLater(
_flutterLoaderLoad(optInOptions).toDart,
throwsA(
predicate<Object>(
(Object e) => e.toString().contains('FlutterLoader could not find a build compatible'),
),
),
);
} finally {
_flutterSupportsDart2Wasm = originalSupportsDart2Wasm;
_wasmValidate = originalValidate;
_flutterBuildConfig = originalBuildConfig;
}
Expand Down
Loading
Loading