Add option to run wasm-opt on module output. (#124831)
This fixes https://github.com/flutter/flutter/issues/124159 Adds the command line argument `--wasm-opt` to optimize the web assembly output.
This commit is contained in:
parent
aa8cc44e03
commit
2269dc10b3
@ -43,6 +43,8 @@ enum Artifact {
|
||||
dart2jsSnapshot,
|
||||
/// The dart snapshot of the dart2wasm compiler.
|
||||
dart2wasmSnapshot,
|
||||
/// The wasm-opt binary that ships with the dart-sdk
|
||||
wasmOptBinary,
|
||||
|
||||
/// The root of the Linux desktop sources.
|
||||
linuxDesktopPath,
|
||||
@ -184,6 +186,8 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
|
||||
return 'dart2js.dart.snapshot';
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
return 'dart2wasm_product.snapshot';
|
||||
case Artifact.wasmOptBinary:
|
||||
return 'wasm-opt$exe';
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return 'frontend_server.dart.snapshot';
|
||||
case Artifact.linuxDesktopPath:
|
||||
@ -510,6 +514,7 @@ class CachedArtifacts implements Artifacts {
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.wasmOptBinary:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.constFinder:
|
||||
case Artifact.flutterFramework:
|
||||
@ -550,6 +555,7 @@ class CachedArtifacts implements Artifacts {
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.wasmOptBinary:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.constFinder:
|
||||
case Artifact.flutterMacOSFramework:
|
||||
@ -608,6 +614,7 @@ class CachedArtifacts implements Artifacts {
|
||||
case Artifact.engineDartAotRuntime:
|
||||
case Artifact.dart2jsSnapshot:
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.wasmOptBinary:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
case Artifact.icuData:
|
||||
case Artifact.isolateSnapshotData:
|
||||
@ -646,6 +653,11 @@ class CachedArtifacts implements Artifacts {
|
||||
_dartSdkPath(_cache), 'bin', 'snapshots',
|
||||
_artifactToFileName(artifact, _platform),
|
||||
);
|
||||
case Artifact.wasmOptBinary:
|
||||
return _fileSystem.path.join(
|
||||
_dartSdkPath(_cache), 'bin', 'utils',
|
||||
_artifactToFileName(artifact, _platform),
|
||||
);
|
||||
case Artifact.flutterTester:
|
||||
case Artifact.vmSnapshotData:
|
||||
case Artifact.isolateSnapshotData:
|
||||
@ -963,6 +975,8 @@ class CachedLocalEngineArtifacts implements Artifacts {
|
||||
case Artifact.dart2wasmSnapshot:
|
||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
|
||||
case Artifact.wasmOptBinary:
|
||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName);
|
||||
case Artifact.flutterToolsFileGenerators:
|
||||
return _getFileGeneratorsPath();
|
||||
}
|
||||
@ -1092,6 +1106,11 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
|
||||
_getDartSdkPath(), 'bin', 'snapshots',
|
||||
_artifactToFileName(artifact, _platform, mode),
|
||||
);
|
||||
case Artifact.wasmOptBinary:
|
||||
return _fileSystem.path.join(
|
||||
_getDartSdkPath(), 'bin', 'snapshots',
|
||||
_artifactToFileName(artifact, _platform, mode),
|
||||
);
|
||||
case Artifact.genSnapshot:
|
||||
case Artifact.flutterTester:
|
||||
case Artifact.flutterFramework:
|
||||
|
@ -242,9 +242,12 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
||||
if (buildModeEnvironment == null) {
|
||||
throw MissingDefineException(kBuildMode, name);
|
||||
}
|
||||
final WasmCompilerConfig compilerConfig = WasmCompilerConfig.fromBuildSystemEnvironment(environment.defines);
|
||||
final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
|
||||
final Artifacts artifacts = globals.artifacts!;
|
||||
final File outputWasmFile = environment.buildDir.childFile('main.dart.wasm');
|
||||
final File outputWasmFile = environment.buildDir.childFile(
|
||||
compilerConfig.runWasmOpt ? 'main.dart.unopt.wasm' : 'main.dart.wasm'
|
||||
);
|
||||
final File depFile = environment.buildDir.childFile('dart2wasm.d');
|
||||
final String dartSdkPath = artifacts.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript);
|
||||
final String dartSdkRoot = environment.fileSystem.directory(dartSdkPath).parent.path;
|
||||
@ -260,7 +263,7 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
||||
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
|
||||
for (final String dartDefine in decodeDartDefines(environment.defines, kDartDefines))
|
||||
'-D$dartDefine',
|
||||
...WasmCompilerConfig.fromBuildSystemEnvironment(environment.defines).toCommandOptions(),
|
||||
...compilerConfig.toCommandOptions(),
|
||||
'--packages=.dart_tool/package_config.json',
|
||||
'--dart-sdk=$dartSdkPath',
|
||||
'--multi-root-scheme',
|
||||
@ -286,6 +289,35 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
||||
if (compileResult.exitCode != 0) {
|
||||
throw Exception(_collectOutput(compileResult));
|
||||
}
|
||||
if (compilerConfig.runWasmOpt) {
|
||||
final String wasmOptBinary = artifacts.getArtifactPath(
|
||||
Artifact.wasmOptBinary,
|
||||
platform: TargetPlatform.web_javascript
|
||||
);
|
||||
final File optimizedOutput = environment.buildDir.childFile('main.dart.wasm');
|
||||
final List<String> optimizeArgs = <String>[
|
||||
wasmOptBinary,
|
||||
'-all',
|
||||
'--closed-world',
|
||||
'-tnh',
|
||||
'-O3',
|
||||
'--type-ssa',
|
||||
'--gufa',
|
||||
'-O3',
|
||||
'--type-merging',
|
||||
outputWasmFile.path,
|
||||
'-o',
|
||||
optimizedOutput.path,
|
||||
];
|
||||
final ProcessResult optimizeResult = await globals.processManager.run(optimizeArgs);
|
||||
if (optimizeResult.exitCode != 0) {
|
||||
throw Exception(_collectOutput(optimizeResult));
|
||||
}
|
||||
|
||||
// Rename the .mjs file not to have the `.unopt` bit
|
||||
final File jsRuntimeFile = environment.buildDir.childFile('main.dart.unopt.mjs');
|
||||
await jsRuntimeFile.rename(environment.buildDir.childFile('main.dart.mjs').path);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -101,6 +101,12 @@ class BuildWebCommand extends BuildSubCommand {
|
||||
negatable: false,
|
||||
hide: !featureFlags.isFlutterWebWasmEnabled,
|
||||
);
|
||||
argParser.addFlag(
|
||||
'wasm-opt',
|
||||
help: 'Run wasm-opt on the output wasm module.',
|
||||
negatable: false,
|
||||
hide: !featureFlags.isFlutterWebWasmEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
final FileSystem _fileSystem;
|
||||
@ -133,6 +139,7 @@ class BuildWebCommand extends BuildSubCommand {
|
||||
}
|
||||
compilerConfig = WasmCompilerConfig(
|
||||
omitTypeChecks: boolArg('omit-type-checks'),
|
||||
runWasmOpt: boolArg('wasm-opt'),
|
||||
);
|
||||
} else {
|
||||
compilerConfig = JsCompilerConfig(
|
||||
|
@ -130,6 +130,7 @@ class JsCompilerConfig extends WebCompilerConfig {
|
||||
class WasmCompilerConfig extends WebCompilerConfig {
|
||||
const WasmCompilerConfig({
|
||||
required this.omitTypeChecks,
|
||||
required this.runWasmOpt,
|
||||
});
|
||||
|
||||
/// Creates a new [WasmCompilerConfig] from build system environment values.
|
||||
@ -139,20 +140,26 @@ class WasmCompilerConfig extends WebCompilerConfig {
|
||||
Map<String, String> defines) =>
|
||||
WasmCompilerConfig(
|
||||
omitTypeChecks: defines[kOmitTypeChecks] == 'true',
|
||||
runWasmOpt: defines[kRunWasmOpt] == 'true',
|
||||
);
|
||||
|
||||
/// Build environment for [omitTypeChecks];
|
||||
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';
|
||||
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;
|
||||
|
||||
@override
|
||||
bool get isWasm => true;
|
||||
|
||||
@override
|
||||
Map<String, String> toBuildSystemEnvironment() => <String, String>{
|
||||
kOmitTypeChecks: omitTypeChecks.toString(),
|
||||
kRunWasmOpt: runWasmOpt.toString(),
|
||||
};
|
||||
|
||||
List<String> toCommandOptions() => <String>[
|
||||
|
@ -845,6 +845,62 @@ void main() {
|
||||
ProcessManager: () => processManager,
|
||||
}));
|
||||
|
||||
test('Dart2WasmTarget invokes dart2wasm and wasm-opt when RunWasmOpt is enabled', () => testbed.run(() async {
|
||||
environment.defines[kBuildMode] = 'release';
|
||||
environment.defines[WasmCompilerConfig.kRunWasmOpt] = 'true';
|
||||
|
||||
final File depFile = environment.buildDir.childFile('dart2wasm.d');
|
||||
|
||||
final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs');
|
||||
processManager.addCommand(FakeCommand(
|
||||
command: <String>[
|
||||
'bin/cache/dart-sdk/bin/dartaotruntime',
|
||||
'--disable-dart-dev',
|
||||
'bin/cache/dart-sdk/bin/snapshots/dart2wasm_product.snapshot',
|
||||
'-Ddart.vm.product=true',
|
||||
'--packages=.dart_tool/package_config.json',
|
||||
'--dart-sdk=bin/cache/dart-sdk',
|
||||
'--multi-root-scheme',
|
||||
'org-dartlang-sdk',
|
||||
'--multi-root',
|
||||
'bin/cache/flutter_web_sdk',
|
||||
'--multi-root',
|
||||
'bin/cache',
|
||||
'--libraries-spec',
|
||||
'bin/cache/flutter_web_sdk/libraries.json',
|
||||
'--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>[
|
||||
'bin/cache/dart-sdk/bin/utils/wasm-opt',
|
||||
'-all',
|
||||
'--closed-world',
|
||||
'-tnh',
|
||||
'-O3',
|
||||
'--type-ssa',
|
||||
'--gufa',
|
||||
'-O3',
|
||||
'--type-merging',
|
||||
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 with skwasm renderer adds extra flags', () => testbed.run(() async {
|
||||
environment.defines[kBuildMode] = 'release';
|
||||
final File depFile = environment.buildDir.childFile('dart2wasm.d');
|
||||
|
@ -47,6 +47,7 @@ void main() {
|
||||
'HasWebPlugins': 'false',
|
||||
'ServiceWorkerStrategy': ServiceWorkerStrategy.offlineFirst.cliName,
|
||||
'WasmOmitTypeChecks': 'false',
|
||||
'RunWasmOpt': 'false',
|
||||
'BuildMode': 'debug',
|
||||
'DartObfuscation': 'false',
|
||||
'TrackWidgetCreation': 'true',
|
||||
@ -70,7 +71,10 @@ void main() {
|
||||
'target',
|
||||
BuildInfo.debug,
|
||||
ServiceWorkerStrategy.offlineFirst,
|
||||
compilerConfig: const WasmCompilerConfig(omitTypeChecks: false),
|
||||
compilerConfig: const WasmCompilerConfig(
|
||||
omitTypeChecks: false,
|
||||
runWasmOpt: false
|
||||
),
|
||||
);
|
||||
|
||||
expect(logger.statusText, contains('Compiling target for the Web...'));
|
||||
|
Loading…
x
Reference in New Issue
Block a user