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,
|
dart2jsSnapshot,
|
||||||
/// The dart snapshot of the dart2wasm compiler.
|
/// The dart snapshot of the dart2wasm compiler.
|
||||||
dart2wasmSnapshot,
|
dart2wasmSnapshot,
|
||||||
|
/// The wasm-opt binary that ships with the dart-sdk
|
||||||
|
wasmOptBinary,
|
||||||
|
|
||||||
/// The root of the Linux desktop sources.
|
/// The root of the Linux desktop sources.
|
||||||
linuxDesktopPath,
|
linuxDesktopPath,
|
||||||
@ -184,6 +186,8 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
|
|||||||
return 'dart2js.dart.snapshot';
|
return 'dart2js.dart.snapshot';
|
||||||
case Artifact.dart2wasmSnapshot:
|
case Artifact.dart2wasmSnapshot:
|
||||||
return 'dart2wasm_product.snapshot';
|
return 'dart2wasm_product.snapshot';
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
|
return 'wasm-opt$exe';
|
||||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
return 'frontend_server.dart.snapshot';
|
return 'frontend_server.dart.snapshot';
|
||||||
case Artifact.linuxDesktopPath:
|
case Artifact.linuxDesktopPath:
|
||||||
@ -510,6 +514,7 @@ class CachedArtifacts implements Artifacts {
|
|||||||
case Artifact.engineDartAotRuntime:
|
case Artifact.engineDartAotRuntime:
|
||||||
case Artifact.dart2jsSnapshot:
|
case Artifact.dart2jsSnapshot:
|
||||||
case Artifact.dart2wasmSnapshot:
|
case Artifact.dart2wasmSnapshot:
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
case Artifact.constFinder:
|
case Artifact.constFinder:
|
||||||
case Artifact.flutterFramework:
|
case Artifact.flutterFramework:
|
||||||
@ -550,6 +555,7 @@ class CachedArtifacts implements Artifacts {
|
|||||||
case Artifact.engineDartAotRuntime:
|
case Artifact.engineDartAotRuntime:
|
||||||
case Artifact.dart2jsSnapshot:
|
case Artifact.dart2jsSnapshot:
|
||||||
case Artifact.dart2wasmSnapshot:
|
case Artifact.dart2wasmSnapshot:
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
case Artifact.constFinder:
|
case Artifact.constFinder:
|
||||||
case Artifact.flutterMacOSFramework:
|
case Artifact.flutterMacOSFramework:
|
||||||
@ -608,6 +614,7 @@ class CachedArtifacts implements Artifacts {
|
|||||||
case Artifact.engineDartAotRuntime:
|
case Artifact.engineDartAotRuntime:
|
||||||
case Artifact.dart2jsSnapshot:
|
case Artifact.dart2jsSnapshot:
|
||||||
case Artifact.dart2wasmSnapshot:
|
case Artifact.dart2wasmSnapshot:
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
case Artifact.icuData:
|
case Artifact.icuData:
|
||||||
case Artifact.isolateSnapshotData:
|
case Artifact.isolateSnapshotData:
|
||||||
@ -646,6 +653,11 @@ class CachedArtifacts implements Artifacts {
|
|||||||
_dartSdkPath(_cache), 'bin', 'snapshots',
|
_dartSdkPath(_cache), 'bin', 'snapshots',
|
||||||
_artifactToFileName(artifact, _platform),
|
_artifactToFileName(artifact, _platform),
|
||||||
);
|
);
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
|
return _fileSystem.path.join(
|
||||||
|
_dartSdkPath(_cache), 'bin', 'utils',
|
||||||
|
_artifactToFileName(artifact, _platform),
|
||||||
|
);
|
||||||
case Artifact.flutterTester:
|
case Artifact.flutterTester:
|
||||||
case Artifact.vmSnapshotData:
|
case Artifact.vmSnapshotData:
|
||||||
case Artifact.isolateSnapshotData:
|
case Artifact.isolateSnapshotData:
|
||||||
@ -963,6 +975,8 @@ class CachedLocalEngineArtifacts implements Artifacts {
|
|||||||
case Artifact.dart2wasmSnapshot:
|
case Artifact.dart2wasmSnapshot:
|
||||||
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
|
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
|
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName);
|
||||||
case Artifact.flutterToolsFileGenerators:
|
case Artifact.flutterToolsFileGenerators:
|
||||||
return _getFileGeneratorsPath();
|
return _getFileGeneratorsPath();
|
||||||
}
|
}
|
||||||
@ -1092,6 +1106,11 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
|
|||||||
_getDartSdkPath(), 'bin', 'snapshots',
|
_getDartSdkPath(), 'bin', 'snapshots',
|
||||||
_artifactToFileName(artifact, _platform, mode),
|
_artifactToFileName(artifact, _platform, mode),
|
||||||
);
|
);
|
||||||
|
case Artifact.wasmOptBinary:
|
||||||
|
return _fileSystem.path.join(
|
||||||
|
_getDartSdkPath(), 'bin', 'snapshots',
|
||||||
|
_artifactToFileName(artifact, _platform, mode),
|
||||||
|
);
|
||||||
case Artifact.genSnapshot:
|
case Artifact.genSnapshot:
|
||||||
case Artifact.flutterTester:
|
case Artifact.flutterTester:
|
||||||
case Artifact.flutterFramework:
|
case Artifact.flutterFramework:
|
||||||
|
@ -242,9 +242,12 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
|||||||
if (buildModeEnvironment == null) {
|
if (buildModeEnvironment == null) {
|
||||||
throw MissingDefineException(kBuildMode, name);
|
throw MissingDefineException(kBuildMode, name);
|
||||||
}
|
}
|
||||||
|
final WasmCompilerConfig compilerConfig = WasmCompilerConfig.fromBuildSystemEnvironment(environment.defines);
|
||||||
final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
|
final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
|
||||||
final Artifacts artifacts = globals.artifacts!;
|
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 File depFile = environment.buildDir.childFile('dart2wasm.d');
|
||||||
final String dartSdkPath = artifacts.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript);
|
final String dartSdkPath = artifacts.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript);
|
||||||
final String dartSdkRoot = environment.fileSystem.directory(dartSdkPath).parent.path;
|
final String dartSdkRoot = environment.fileSystem.directory(dartSdkPath).parent.path;
|
||||||
@ -260,7 +263,7 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
|||||||
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
|
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
|
||||||
for (final String dartDefine in decodeDartDefines(environment.defines, kDartDefines))
|
for (final String dartDefine in decodeDartDefines(environment.defines, kDartDefines))
|
||||||
'-D$dartDefine',
|
'-D$dartDefine',
|
||||||
...WasmCompilerConfig.fromBuildSystemEnvironment(environment.defines).toCommandOptions(),
|
...compilerConfig.toCommandOptions(),
|
||||||
'--packages=.dart_tool/package_config.json',
|
'--packages=.dart_tool/package_config.json',
|
||||||
'--dart-sdk=$dartSdkPath',
|
'--dart-sdk=$dartSdkPath',
|
||||||
'--multi-root-scheme',
|
'--multi-root-scheme',
|
||||||
@ -286,6 +289,35 @@ class Dart2WasmTarget extends Dart2WebTarget {
|
|||||||
if (compileResult.exitCode != 0) {
|
if (compileResult.exitCode != 0) {
|
||||||
throw Exception(_collectOutput(compileResult));
|
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
|
@override
|
||||||
|
@ -101,6 +101,12 @@ class BuildWebCommand extends BuildSubCommand {
|
|||||||
negatable: false,
|
negatable: false,
|
||||||
hide: !featureFlags.isFlutterWebWasmEnabled,
|
hide: !featureFlags.isFlutterWebWasmEnabled,
|
||||||
);
|
);
|
||||||
|
argParser.addFlag(
|
||||||
|
'wasm-opt',
|
||||||
|
help: 'Run wasm-opt on the output wasm module.',
|
||||||
|
negatable: false,
|
||||||
|
hide: !featureFlags.isFlutterWebWasmEnabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final FileSystem _fileSystem;
|
final FileSystem _fileSystem;
|
||||||
@ -133,6 +139,7 @@ class BuildWebCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
compilerConfig = WasmCompilerConfig(
|
compilerConfig = WasmCompilerConfig(
|
||||||
omitTypeChecks: boolArg('omit-type-checks'),
|
omitTypeChecks: boolArg('omit-type-checks'),
|
||||||
|
runWasmOpt: boolArg('wasm-opt'),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
compilerConfig = JsCompilerConfig(
|
compilerConfig = JsCompilerConfig(
|
||||||
|
@ -130,6 +130,7 @@ class JsCompilerConfig extends WebCompilerConfig {
|
|||||||
class WasmCompilerConfig extends WebCompilerConfig {
|
class WasmCompilerConfig extends WebCompilerConfig {
|
||||||
const WasmCompilerConfig({
|
const WasmCompilerConfig({
|
||||||
required this.omitTypeChecks,
|
required this.omitTypeChecks,
|
||||||
|
required this.runWasmOpt,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Creates a new [WasmCompilerConfig] from build system environment values.
|
/// Creates a new [WasmCompilerConfig] from build system environment values.
|
||||||
@ -139,20 +140,26 @@ class WasmCompilerConfig extends WebCompilerConfig {
|
|||||||
Map<String, String> defines) =>
|
Map<String, String> defines) =>
|
||||||
WasmCompilerConfig(
|
WasmCompilerConfig(
|
||||||
omitTypeChecks: defines[kOmitTypeChecks] == 'true',
|
omitTypeChecks: defines[kOmitTypeChecks] == 'true',
|
||||||
|
runWasmOpt: defines[kRunWasmOpt] == 'true',
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Build environment for [omitTypeChecks];
|
/// Build environment for [omitTypeChecks];
|
||||||
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';
|
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';
|
||||||
|
static const String kRunWasmOpt = 'RunWasmOpt';
|
||||||
|
|
||||||
/// If `omit-type-checks` should be passed to `dart2wasm`.
|
/// If `omit-type-checks` should be passed to `dart2wasm`.
|
||||||
final bool omitTypeChecks;
|
final bool omitTypeChecks;
|
||||||
|
|
||||||
|
// Run wasm-opt on the resulting module.
|
||||||
|
final bool runWasmOpt;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isWasm => true;
|
bool get isWasm => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, String> toBuildSystemEnvironment() => <String, String>{
|
Map<String, String> toBuildSystemEnvironment() => <String, String>{
|
||||||
kOmitTypeChecks: omitTypeChecks.toString(),
|
kOmitTypeChecks: omitTypeChecks.toString(),
|
||||||
|
kRunWasmOpt: runWasmOpt.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
List<String> toCommandOptions() => <String>[
|
List<String> toCommandOptions() => <String>[
|
||||||
|
@ -845,6 +845,62 @@ void main() {
|
|||||||
ProcessManager: () => processManager,
|
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 {
|
test('Dart2WasmTarget with skwasm renderer adds extra flags', () => testbed.run(() async {
|
||||||
environment.defines[kBuildMode] = 'release';
|
environment.defines[kBuildMode] = 'release';
|
||||||
final File depFile = environment.buildDir.childFile('dart2wasm.d');
|
final File depFile = environment.buildDir.childFile('dart2wasm.d');
|
||||||
|
@ -47,6 +47,7 @@ void main() {
|
|||||||
'HasWebPlugins': 'false',
|
'HasWebPlugins': 'false',
|
||||||
'ServiceWorkerStrategy': ServiceWorkerStrategy.offlineFirst.cliName,
|
'ServiceWorkerStrategy': ServiceWorkerStrategy.offlineFirst.cliName,
|
||||||
'WasmOmitTypeChecks': 'false',
|
'WasmOmitTypeChecks': 'false',
|
||||||
|
'RunWasmOpt': 'false',
|
||||||
'BuildMode': 'debug',
|
'BuildMode': 'debug',
|
||||||
'DartObfuscation': 'false',
|
'DartObfuscation': 'false',
|
||||||
'TrackWidgetCreation': 'true',
|
'TrackWidgetCreation': 'true',
|
||||||
@ -70,7 +71,10 @@ void main() {
|
|||||||
'target',
|
'target',
|
||||||
BuildInfo.debug,
|
BuildInfo.debug,
|
||||||
ServiceWorkerStrategy.offlineFirst,
|
ServiceWorkerStrategy.offlineFirst,
|
||||||
compilerConfig: const WasmCompilerConfig(omitTypeChecks: false),
|
compilerConfig: const WasmCompilerConfig(
|
||||||
|
omitTypeChecks: false,
|
||||||
|
runWasmOpt: false
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logger.statusText, contains('Compiling target for the Web...'));
|
expect(logger.statusText, contains('Compiling target for the Web...'));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user