Unverified Commit abadf9ff authored by Martin Kustermann's avatar Martin Kustermann Committed by GitHub

Use `dart compile wasm` for wasm compilations (#143298)

* Flags to `dart compile wasm`

Some options are not relevant to a standalone user of `dart compile
wasm` (e.g. specyfing dart-sdk, platform file etc). => Those aren't
offered by the `dart compile wasm` tool directly. => We use the
`--extra-compiler-option=` instead which passes through arbitrary
options to the dart2wasm compiler. => We don't maintain compatibility of
those options, if we update them we'll ensure to also update flutter
tools

* Binaryen optimization passes

This change will mean we use the binaryen flags from Dart SDK which are
slightly different from the ones in flutter.

* Optimization configuration

This change will also start using the more standardized `-O` flag for
determining optimization levels. The meaning of those flags have been
mostly aligned with dart2js (with some differences remaining).

* Minimization

Using the new optimization flags, namely `-O4` for `--wasm-opt=full`,
will automatically enable the new `--minify` support. Minification is
Dart semantics preserving but changes the `<obj>.runtimeType.toString()`
to use minified names (just as in dart2js).

* Code size changes

  Overall this change will reduce wonderous code size by around 10%.

Issue https://github.com/dart-lang/sdk/issues/54675
parent 295eeaf1
...@@ -249,9 +249,8 @@ class Dart2WasmTarget extends Dart2WebTarget { ...@@ -249,9 +249,8 @@ class Dart2WasmTarget extends Dart2WebTarget {
} }
final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Artifacts artifacts = environment.artifacts; final Artifacts artifacts = environment.artifacts;
final File outputWasmFile = environment.buildDir.childFile( final File outputWasmFile =
compilerConfig.runWasmOpt ? 'main.dart.unopt.wasm' : 'main.dart.wasm' environment.buildDir.childFile('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 platformBinariesPath = artifacts.getHostArtifact(HostArtifact.webPlatformKernelFolder).path; final String platformBinariesPath = artifacts.getHostArtifact(HostArtifact.webPlatformKernelFolder).path;
...@@ -261,12 +260,16 @@ class Dart2WasmTarget extends Dart2WebTarget { ...@@ -261,12 +260,16 @@ class Dart2WasmTarget extends Dart2WebTarget {
); );
final List<String> compilationArgs = <String>[ final List<String> compilationArgs = <String>[
artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: TargetPlatform.web_javascript), artifacts.getArtifactPath(Artifact.engineDartBinary, platform: TargetPlatform.web_javascript),
'--disable-dart-dev', 'compile',
artifacts.getArtifactPath(Artifact.dart2wasmSnapshot, platform: TargetPlatform.web_javascript), 'wasm',
'--packages=.dart_tool/package_config.json', '--packages=.dart_tool/package_config.json',
'--dart-sdk=$dartSdkPath', '--extra-compiler-option=--dart-sdk=$dartSdkPath',
'--platform=$platformFilePath', '--extra-compiler-option=--platform=$platformFilePath',
if (compilerConfig.renderer == WebRendererMode.skwasm) ...<String>[
'--extra-compiler-option=--import-shared-memory',
'--extra-compiler-option=--shared-memory-max-pages=32768',
],
if (buildMode == BuildMode.profile) if (buildMode == BuildMode.profile)
'-Ddart.vm.profile=true' '-Ddart.vm.profile=true'
else else
...@@ -274,16 +277,12 @@ class Dart2WasmTarget extends Dart2WebTarget { ...@@ -274,16 +277,12 @@ class Dart2WasmTarget extends Dart2WebTarget {
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions), ...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
for (final String dartDefine in dartDefines) for (final String dartDefine in dartDefines)
'-D$dartDefine', '-D$dartDefine',
...compilerConfig.toCommandOptions(), '--extra-compiler-option=--depfile=${depFile.path}',
if (compilerConfig.renderer == WebRendererMode.skwasm)
...<String>[
'--import-shared-memory',
'--shared-memory-max-pages=32768',
],
'--depfile=${depFile.path}',
environment.buildDir.childFile('main.dart').path, // dartfile ...compilerConfig.toCommandOptions(),
'-o',
outputWasmFile.path, outputWasmFile.path,
environment.buildDir.childFile('main.dart').path, // dartfile
]; ];
final ProcessUtils processUtils = ProcessUtils( final ProcessUtils processUtils = ProcessUtils(
...@@ -295,37 +294,6 @@ class Dart2WasmTarget extends Dart2WebTarget { ...@@ -295,37 +294,6 @@ class Dart2WasmTarget extends Dart2WebTarget {
throwOnError: true, throwOnError: true,
compilationArgs, compilationArgs,
); );
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-features',
'--closed-world',
'--traps-never-happen',
'-O3',
'--type-ssa',
'--gufa',
'-O3',
'--type-merging',
if (compilerConfig.wasmOpt == WasmOptLevel.debug)
'--debuginfo',
outputWasmFile.path,
'-o',
optimizedOutput.path,
];
await processUtils.run(
throwOnError: true,
optimizeArgs,
);
// 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
......
...@@ -148,12 +148,23 @@ class WasmCompilerConfig extends WebCompilerConfig { ...@@ -148,12 +148,23 @@ class WasmCompilerConfig extends WebCompilerConfig {
@override @override
CompileTarget get compileTarget => CompileTarget.wasm; CompileTarget get compileTarget => CompileTarget.wasm;
bool get runWasmOpt => List<String> toCommandOptions() {
wasmOpt == WasmOptLevel.full || wasmOpt == WasmOptLevel.debug; // -O1: Optimizes
// -O2: Same as -O1 but also minifies (still semantics preserving)
List<String> toCommandOptions() => <String>[ // -O3: Same as -O2 but also omits implicit type checks.
if (omitTypeChecks) '--omit-type-checks', // -O4: Same as -O3 but also omits explicit type checks.
]; // (NOTE: This differs from dart2js -O4 semantics atm.)
// Ortogonal: The name section is always kept by default and we emit it only
// in [WasmOptLevel.full] mode (similar to `--strip` of static symbols in
// AOT mode).
final String level = !omitTypeChecks ? '-O2' : '-O4';
return switch (wasmOpt) {
WasmOptLevel.none => <String>['-O0'],
WasmOptLevel.debug => <String>[level, '--no-minify'],
WasmOptLevel.full => <String>[level, '--no-name-section'],
};
}
@override @override
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{ Map<String, Object> get buildEventAnalyticsValues => <String, Object>{
......
...@@ -30,24 +30,12 @@ const List<String> _kDart2jsLinuxArgs = <String>[ ...@@ -30,24 +30,12 @@ const List<String> _kDart2jsLinuxArgs = <String>[
]; ];
const List<String> _kDart2WasmLinuxArgs = <String> [ const List<String> _kDart2WasmLinuxArgs = <String> [
'Artifact.engineDartAotRuntime.TargetPlatform.web_javascript', 'Artifact.engineDartBinary.TargetPlatform.web_javascript',
'--disable-dart-dev', 'compile',
'Artifact.dart2wasmSnapshot.TargetPlatform.web_javascript', 'wasm',
'--packages=.dart_tool/package_config.json', '--packages=.dart_tool/package_config.json',
'--dart-sdk=Artifact.engineDartSdkPath.TargetPlatform.web_javascript', '--extra-compiler-option=--dart-sdk=Artifact.engineDartSdkPath.TargetPlatform.web_javascript',
'--platform=HostArtifact.webPlatformKernelFolder/dart2wasm_platform.dill', '--extra-compiler-option=--platform=HostArtifact.webPlatformKernelFolder/dart2wasm_platform.dill',
];
const List<String> _kWasmOptLinuxArgrs = <String> [
'Artifact.wasmOptBinary.TargetPlatform.web_javascript',
'--all-features',
'--closed-world',
'--traps-never-happen',
'-O3',
'--type-ssa',
'--gufa',
'-O3',
'--type-merging',
]; ];
void main() { void main() {
...@@ -920,7 +908,7 @@ void main() { ...@@ -920,7 +908,7 @@ void main() {
final File depFile = environment.buildDir.childFile('dart2wasm.d'); final File depFile = environment.buildDir.childFile('dart2wasm.d');
final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs'); final File outputJsFile = environment.buildDir.childFile('main.dart.mjs');
processManager.addCommand(FakeCommand( processManager.addCommand(FakeCommand(
command: <String>[ command: <String>[
..._kDart2WasmLinuxArgs, ..._kDart2WasmLinuxArgs,
...@@ -929,32 +917,23 @@ void main() { ...@@ -929,32 +917,23 @@ void main() {
'-DBAZ=qux', '-DBAZ=qux',
'-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKIA=true',
'--depfile=${depFile.absolute.path}', '--extra-compiler-option=--depfile=${depFile.absolute.path}',
'-O2',
'--no-name-section',
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
environment.buildDir.childFile('main.dart').absolute.path, environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
], ],
onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo')) 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( await Dart2WasmTarget(
const WasmCompilerConfig( const WasmCompilerConfig(
renderer: WebRendererMode.canvaskit renderer: WebRendererMode.canvaskit
) )
).build(environment); ).build(environment);
expect(outputJsFile.existsSync(), isFalse); expect(outputJsFile.existsSync(), isTrue);
final File movedJsFile = environment.buildDir.childFile('main.dart.mjs');
expect(movedJsFile.existsSync(), isTrue);
expect(movedJsFile.readAsStringSync(), 'foo');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => processManager, ProcessManager: () => processManager,
})); }));
...@@ -966,30 +945,23 @@ void main() { ...@@ -966,30 +945,23 @@ void main() {
final File depFile = environment.buildDir.childFile('dart2wasm.d'); final File depFile = environment.buildDir.childFile('dart2wasm.d');
final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs'); final File outputJsFile = environment.buildDir.childFile('main.dart.mjs');
processManager.addCommand(FakeCommand( processManager.addCommand(FakeCommand(
command: <String>[ command: <String>[
..._kDart2WasmLinuxArgs, ..._kDart2WasmLinuxArgs,
'-Ddart.vm.product=true', '-Ddart.vm.product=true',
'-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKIA=true',
'--omit-type-checks', '--extra-compiler-option=--depfile=${depFile.absolute.path}',
'--depfile=${depFile.absolute.path}', '-O4',
'--no-name-section',
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
environment.buildDir.childFile('main.dart').absolute.path, environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
], ],
onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo')) 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( await Dart2WasmTarget(
const WasmCompilerConfig( const WasmCompilerConfig(
omitTypeChecks: true, omitTypeChecks: true,
...@@ -997,10 +969,7 @@ void main() { ...@@ -997,10 +969,7 @@ void main() {
) )
).build(environment); ).build(environment);
expect(outputJsFile.existsSync(), isFalse); expect(outputJsFile.existsSync(), isTrue);
final File movedJsFile = environment.buildDir.childFile('main.dart.mjs');
expect(movedJsFile.existsSync(), isTrue);
expect(movedJsFile.readAsStringSync(), 'foo');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => processManager, ProcessManager: () => processManager,
})); }));
...@@ -1011,27 +980,21 @@ void main() { ...@@ -1011,27 +980,21 @@ void main() {
final File depFile = environment.buildDir.childFile('dart2wasm.d'); final File depFile = environment.buildDir.childFile('dart2wasm.d');
final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs'); final File outputJsFile = environment.buildDir.childFile('main.dart.mjs');
processManager.addCommand(FakeCommand( processManager.addCommand(FakeCommand(
command: <String>[ command: <String>[
..._kDart2WasmLinuxArgs, ..._kDart2WasmLinuxArgs,
'-Ddart.vm.product=true', '-Ddart.vm.product=true',
'-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKIA=true',
'--depfile=${depFile.absolute.path}', '--extra-compiler-option=--depfile=${depFile.absolute.path}',
'-O2',
'--no-minify',
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
environment.buildDir.childFile('main.dart').absolute.path, environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
], onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo'))); ], onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo')));
processManager.addCommand(FakeCommand(
command: <String>[
..._kWasmOptLinuxArgrs,
'--debuginfo',
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
]));
await Dart2WasmTarget( await Dart2WasmTarget(
const WasmCompilerConfig( const WasmCompilerConfig(
wasmOpt: WasmOptLevel.debug, wasmOpt: WasmOptLevel.debug,
...@@ -1039,10 +1002,7 @@ void main() { ...@@ -1039,10 +1002,7 @@ void main() {
) )
).build(environment); ).build(environment);
expect(outputJsFile.existsSync(), isFalse); expect(outputJsFile.existsSync(), isTrue);
final File movedJsFile = environment.buildDir.childFile('main.dart.mjs');
expect(movedJsFile.existsSync(), isTrue);
expect(movedJsFile.readAsStringSync(), 'foo');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => processManager, ProcessManager: () => processManager,
})); }));
...@@ -1060,9 +1020,11 @@ void main() { ...@@ -1060,9 +1020,11 @@ void main() {
'-Ddart.vm.product=true', '-Ddart.vm.product=true',
'-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKIA=true',
'--depfile=${depFile.absolute.path}', '--extra-compiler-option=--depfile=${depFile.absolute.path}',
environment.buildDir.childFile('main.dart').absolute.path, '-O0',
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path, environment.buildDir.childFile('main.dart.wasm').absolute.path,
environment.buildDir.childFile('main.dart').absolute.path,
], onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo'))); ], onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo')));
await Dart2WasmTarget( await Dart2WasmTarget(
...@@ -1080,31 +1042,26 @@ void main() { ...@@ -1080,31 +1042,26 @@ void main() {
environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.defaultValue.name; environment.defines[WasmCompilerConfig.kRunWasmOpt] = WasmOptLevel.defaultValue.name;
final File depFile = environment.buildDir.childFile('dart2wasm.d'); final File depFile = environment.buildDir.childFile('dart2wasm.d');
final File outputJsFile = environment.buildDir.childFile('main.dart.unopt.mjs'); final File outputJsFile = environment.buildDir.childFile('main.dart.mjs');
processManager.addCommand(FakeCommand( processManager.addCommand(FakeCommand(
command: <String>[ command: <String>[
..._kDart2WasmLinuxArgs, ..._kDart2WasmLinuxArgs,
'--extra-compiler-option=--import-shared-memory',
'--extra-compiler-option=--shared-memory-max-pages=32768',
'-Ddart.vm.product=true', '-Ddart.vm.product=true',
'-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_AUTO_DETECT=false',
'-DFLUTTER_WEB_USE_SKIA=false', '-DFLUTTER_WEB_USE_SKIA=false',
'-DFLUTTER_WEB_USE_SKWASM=true', '-DFLUTTER_WEB_USE_SKWASM=true',
'--import-shared-memory', '--extra-compiler-option=--depfile=${depFile.absolute.path}',
'--shared-memory-max-pages=32768', '-O2',
'--depfile=${depFile.absolute.path}', '--no-name-section',
'-o',
environment.buildDir.childFile('main.dart.wasm').absolute.path,
environment.buildDir.childFile('main.dart').absolute.path, environment.buildDir.childFile('main.dart').absolute.path,
environment.buildDir.childFile('main.dart.unopt.wasm').absolute.path,
], ],
onRun: (_) => outputJsFile..createSync()..writeAsStringSync('foo')) 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( await Dart2WasmTarget(
const WasmCompilerConfig( const WasmCompilerConfig(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment