Skip to content

Commit

Permalink
tool-web-wasm: make wasm-opt an "option" instead of a "flag" (#126035)
Browse files Browse the repository at this point in the history
Allows controlling a broader set of variables than just on/off.

Also make wasm-opt "full" the default
  • Loading branch information
kevmoo committed May 4, 2023
1 parent 5a80f8d commit 529b919
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 26 deletions.
6 changes: 4 additions & 2 deletions packages/flutter_tools/lib/src/build_system/targets/web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,16 @@ class Dart2WasmTarget extends Dart2WebTarget {
final File optimizedOutput = environment.buildDir.childFile('main.dart.wasm');
final List<String> optimizeArgs = <String>[
wasmOptBinary,
'-all',
'--all-features',
'--closed-world',
'-tnh',
'--traps-never-happen',
'-O3',
'--type-ssa',
'--gufa',
'-O3',
'--type-merging',
if (compilerConfig.wasmOpt == WasmOptLevel.debug)
'--debuginfo',
outputWasmFile.path,
'-o',
optimizedOutput.path,
Expand Down
11 changes: 6 additions & 5 deletions packages/flutter_tools/lib/src/commands/build_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ class BuildWebCommand extends BuildSubCommand {
negatable: false,
hide: !featureFlags.isFlutterWebWasmEnabled,
);
argParser.addFlag(
argParser.addOption(
'wasm-opt',
help:
'Optimize output wasm using the Binaryen (https://github.com/WebAssembly/binaryen) tool.\n'
'Increases the build time, but will yield a smaller, faster output.',
negatable: false,
'Optimize output wasm using the Binaryen (https://github.com/WebAssembly/binaryen) tool.',
defaultsTo: WasmOptLevel.defaultValue.cliName,
allowed: WasmOptLevel.values.map<String>((WasmOptLevel e) => e.cliName),
allowedHelp: CliEnum.allowedHelp(WasmOptLevel.values),
hide: !featureFlags.isFlutterWebWasmEnabled,
);
}
Expand Down Expand Up @@ -143,7 +144,7 @@ class BuildWebCommand extends BuildSubCommand {
}
compilerConfig = WasmCompilerConfig(
omitTypeChecks: boolArg('omit-type-checks'),
runWasmOpt: boolArg('wasm-opt'),
wasmOpt: WasmOptLevel.values.byName(stringArg('wasm-opt')!),
);
} else {
compilerConfig = JsCompilerConfig(
Expand Down
32 changes: 27 additions & 5 deletions packages/flutter_tools/lib/src/web/compiler_config.dart
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 '../base/utils.dart';

abstract class WebCompilerConfig {
const WebCompilerConfig();

Expand Down Expand Up @@ -134,7 +136,7 @@ class JsCompilerConfig extends WebCompilerConfig {
class WasmCompilerConfig extends WebCompilerConfig {
const WasmCompilerConfig({
required this.omitTypeChecks,
required this.runWasmOpt,
required this.wasmOpt,
});

/// Creates a new [WasmCompilerConfig] from build system environment values.
Expand All @@ -144,28 +146,30 @@ class WasmCompilerConfig extends WebCompilerConfig {
Map<String, String> defines) =>
WasmCompilerConfig(
omitTypeChecks: defines[kOmitTypeChecks] == 'true',
runWasmOpt: defines[kRunWasmOpt] == 'true',
wasmOpt: WasmOptLevel.values.byName(defines[kRunWasmOpt]!),
);

/// Build environment for [omitTypeChecks].
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';

/// Build environment for [runWasmOpt].
/// Build environment for [wasmOpt].
static const String kRunWasmOpt = 'RunWasmOpt';

/// If `omit-type-checks` should be passed to `dart2wasm`.
final bool omitTypeChecks;

/// Run wasm-opt on the resulting module.
final bool runWasmOpt;
final WasmOptLevel wasmOpt;

@override
bool get isWasm => true;

bool get runWasmOpt => wasmOpt == WasmOptLevel.full || wasmOpt == WasmOptLevel.debug;

@override
Map<String, String> toBuildSystemEnvironment() => <String, String>{
kOmitTypeChecks: omitTypeChecks.toString(),
kRunWasmOpt: runWasmOpt.toString(),
kRunWasmOpt: wasmOpt.name,
};

List<String> toCommandOptions() => <String>[
Expand All @@ -182,3 +186,21 @@ class WasmCompilerConfig extends WebCompilerConfig {
entry.key: entry.value,
};
}

enum WasmOptLevel implements CliEnum {
full,
debug,
none;

static const WasmOptLevel defaultValue = WasmOptLevel.full;

@override
String get cliName => name;

@override
String get helpText => switch(this) {
WasmOptLevel.none => 'wasm-opt is not run. Fastest build; bigger, slower output.',
WasmOptLevel.debug => 'Similar to `${WasmOptLevel.full.name}, but member names are preserved. Debugging is easier, but size is a bit bigger.',
WasmOptLevel.full => 'wasm-opt is run. Build time is slower, but output is smaller and faster.',
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import '../../../src/testbed.dart';

const List<String> _kDart2jsLinuxArgs = <String>[
'Artifact.engineDartBinary.TargetPlatform.web_javascript',
'--disable-dart-dev',
'--disable-dart-dev',
'Artifact.dart2jsSnapshot.TargetPlatform.web_javascript',
'--platform-binaries=HostArtifact.webPlatformKernelFolder',
'--invoker=flutter_tool',
Expand All @@ -46,6 +46,18 @@ const List<String> _kDart2WasmLinuxArgs = <String> [
'HostArtifact.flutterWebLibrariesJson',
];

const List<String> _kWasmOptLinuxArgrs = <String> [
'Artifact.wasmOptBinary.TargetPlatform.web_javascript',
'--all-features',
'--closed-world',
'--traps-never-happen',
'-O3',
'--type-ssa',
'--gufa',
'-O3',
'--type-merging',
];

/// The result of calling `.parent` on a Memory directory pointing to
/// `'Artifact.engineDartSdkPath.TargetPlatform.web_javascript'`.
const String _kDartSdkRoot = '.';
Expand Down Expand Up @@ -759,10 +771,12 @@ void main() {

test('Dart2WasmTarget invokes dart2wasm with dart defines', () => testbed.run(() async {
environment.defines[kBuildMode] = 'profile';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.defaultValue.name;
environment.defines[kDartDefines] = encodeDartDefines(<String>['FOO=bar', 'BAZ=qux']);

final File depFile = environment.buildDir.childFile('dart2wasm.d');

final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs');
processManager.addCommand(FakeCommand(
command: <String>[
..._kDart2WasmLinuxArgs,
Expand All @@ -771,40 +785,72 @@ void main() {
'-DBAZ=qux',
'--depfile=${depFile.absolute.path}',
environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
],
onRun: () => outputJsFile..createSync()..writeAsStringSync('foo'))
);

processManager.addCommand(FakeCommand(
command: <String>[
..._kWasmOptLinuxArgrs,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
])
);

await Dart2WasmTarget(WebRendererMode.canvaskit).build(environment);

expect(outputJsFile.existsSync(), isFalse);
final File movedJsFile = environment.buildDir.childFile('main.dart.mjs');
expect(movedJsFile.existsSync(), isTrue);
expect(movedJsFile.readAsStringSync(), 'foo');
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
}));

test('Dart2WasmTarget invokes dart2wasm with omit checks', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.defaultValue.name;
environment.defines[WasmCompilerConfig.kOmitTypeChecks] = 'true';

final File depFile = environment.buildDir.childFile('dart2wasm.d');

final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs');
processManager.addCommand(FakeCommand(
command: <String>[
..._kDart2WasmLinuxArgs,
'-Ddart.vm.product=true',
'--omit-type-checks',
'--depfile=${depFile.absolute.path}',
environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
],
onRun: () => outputJsFile..createSync()..writeAsStringSync('foo'))
);

processManager.addCommand(FakeCommand(
command: <String>[
..._kWasmOptLinuxArgrs,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
])
);

await Dart2WasmTarget(WebRendererMode.canvaskit).build(environment);

expect(outputJsFile.existsSync(), isFalse);
final File movedJsFile = environment.buildDir.childFile('main.dart.mjs');
expect(movedJsFile.existsSync(), isTrue);
expect(movedJsFile.readAsStringSync(), 'foo');
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
}));

test('Dart2WasmTarget invokes dart2wasm and wasm-opt when RunWasmOpt is enabled', () => testbed.run(() async {
test('Dart2WasmTarget invokes dart2wasm and wasm-opt with debug info in wasmopt debug mode', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = 'true';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.debug.name;

final File depFile = environment.buildDir.childFile('dart2wasm.d');

Expand All @@ -820,15 +866,8 @@ void main() {

processManager.addCommand(FakeCommand(
command: <String>[
'Artifact.wasmOptBinary.TargetPlatform.web_javascript',
'-all',
'--closed-world',
'-tnh',
'-O3',
'--type-ssa',
'--gufa',
'-O3',
'--type-merging',
..._kWasmOptLinuxArgrs,
'--debuginfo',
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
Expand All @@ -844,11 +883,33 @@ void main() {
ProcessManager: () => processManager,
}));

test('Dart2WasmTarget invokes dart2wasm (but not wasm-opt) with wasm-opt none option', () => testbed.run(() async {
environment.defines[kBuildMode] = 'debug';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.none.name;

final File depFile = environment.buildDir.childFile('dart2wasm.d');

final File outputJsFile = environment.buildDir.childFile('main.dart.mjs');
processManager.addCommand(FakeCommand(
command: <String>[
..._kDart2WasmLinuxArgs,
'-Ddart.vm.product=true',
'--depfile=${depFile.absolute.path}',
environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.wasm').absolute.path,
], onRun: () => outputJsFile..createSync()..writeAsStringSync('foo')));

await Dart2WasmTarget(WebRendererMode.canvaskit).build(environment);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
}));

test('Dart2WasmTarget with skwasm renderer adds extra flags', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.defaultValue.name;
final File depFile = environment.buildDir.childFile('dart2wasm.d');

final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs');
processManager.addCommand(FakeCommand(
command: <String>[
..._kDart2WasmLinuxArgs,
Expand All @@ -857,6 +918,16 @@ void main() {
'--shared-memory-max-pages=32768',
'--depfile=${depFile.absolute.path}',
environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
],
onRun: () => outputJsFile..createSync()..writeAsStringSync('foo'))
);

processManager.addCommand(FakeCommand(
command: <String>[
..._kWasmOptLinuxArgrs,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
])
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void main() {
'HasWebPlugins': 'false',
'ServiceWorkerStrategy': ServiceWorkerStrategy.offlineFirst.cliName,
'WasmOmitTypeChecks': 'false',
'RunWasmOpt': 'false',
'RunWasmOpt': 'none',
'BuildMode': 'debug',
'DartObfuscation': 'false',
'TrackWidgetCreation': 'true',
Expand All @@ -73,7 +73,7 @@ void main() {
ServiceWorkerStrategy.offlineFirst,
compilerConfig: const WasmCompilerConfig(
omitTypeChecks: false,
runWasmOpt: false
wasmOpt: WasmOptLevel.none,
),
);

Expand Down

0 comments on commit 529b919

Please sign in to comment.