[dart2wasm] Make `dart compile wasm` use AOT-compiled dart2wasm via subprocess
This reduces time for `dart compile wasm` on a hello world in
* `--no-optimize` mode from 8.2 to 1.8 seconds (0.6 sec via [0])
* `--optimize` mode from 9.2 to 3 seconds (1.6 sec via [0])
[0] pkg/dart2wasm/tool/compile_benchmark
Issue https://github.com/dart-lang/sdk/issues/54675
Change-Id: I47093e747f343b542bc7faa34e102c62657c7b81
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347902
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/dart2wasm.dart b/pkg/dart2wasm/lib/dart2wasm.dart
index e1a2203..fd47eb9 100644
--- a/pkg/dart2wasm/lib/dart2wasm.dart
+++ b/pkg/dart2wasm/lib/dart2wasm.dart
@@ -45,6 +45,8 @@
Flag("omit-type-checks",
(o, value) => o.translatorOptions.omitTypeChecks = value,
defaultsTo: _d.translatorOptions.omitTypeChecks),
+ Flag("verbose", (o, value) => o.translatorOptions.verbose = value,
+ defaultsTo: _d.translatorOptions.verbose),
Flag("verify-type-checks",
(o, value) => o.translatorOptions.verifyTypeChecks = value,
defaultsTo: _d.translatorOptions.verifyTypeChecks),
@@ -143,5 +145,5 @@
Future<int> main(List<String> args) async {
WasmCompilerOptions options = parseArguments(args);
- return generateWasm(options);
+ return generateWasm(options, errorPrinter: stderr.writeln);
}
diff --git a/pkg/dart2wasm/lib/generate_wasm.dart b/pkg/dart2wasm/lib/generate_wasm.dart
index 234967e..01ff1d0 100644
--- a/pkg/dart2wasm/lib/generate_wasm.dart
+++ b/pkg/dart2wasm/lib/generate_wasm.dart
@@ -7,8 +7,8 @@
typedef PrintError = void Function(String error);
Future<int> generateWasm(WasmCompilerOptions options,
- {bool verbose = false, PrintError errorPrinter = print}) async {
- if (verbose) {
+ {PrintError errorPrinter = print}) async {
+ if (options.translatorOptions.verbose) {
print('Running dart compile wasm...');
print(' - input file name = ${options.mainUri}');
print(' - output file name = ${options.outputFile}');
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 2cfb43b..97a68bb 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -40,6 +40,7 @@
bool printWasm = false;
bool minify = false;
bool verifyTypeChecks = false;
+ bool verbose = false;
int inliningLimit = 0;
int? sharedMemoryMaxPages;
List<int> watchPoints = [];
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 7b915ad..e3297bc 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -7,7 +7,6 @@
import 'package:args/args.dart';
import 'package:dart2native/generate.dart';
-import 'package:dart2wasm/generate_wasm.dart';
import 'package:front_end/src/api_prototype/compiler_options.dart'
show Verbosity;
import 'package:path/path.dart' as path;
@@ -247,9 +246,7 @@
log.stdout('Compiling $sourcePath to $commandName file $outputFile.');
// TODO(bkonyi): perform compilation in same process.
- final process = await startDartProcess(sdk, buildArgs);
- routeToStdout(process);
- return process.exitCode;
+ return await runProcess([sdk.dart, ...buildArgs]);
}
}
@@ -413,9 +410,6 @@
static const String help =
'Compile Dart to a WebAssembly/WasmGC module (EXPERIMENTAL).';
- final String optimizer = path.join(
- binDir.path, 'utils', Platform.isWindows ? 'wasm-opt.exe' : 'wasm-opt');
-
CompileWasmCommand({bool verbose = false})
: super(commandName, help, verbose, hidden: !verbose) {
argParser
@@ -499,13 +493,14 @@
log.stdout(
'The support may change, or be removed, with no advance notice.\n');
- final libraries = path.absolute(sdk.sdkPath, 'lib', 'libraries.json');
- if (!Sdk.checkArtifactExists(libraries)) {
- return 255;
- }
final args = argResults!;
- bool verbose = this.verbose || args['verbose'];
- if (args['optimize'] && !Sdk.checkArtifactExists(optimizer)) {
+ final verbose = this.verbose || args['verbose'];
+ final optimize = args['optimize'];
+
+ if (!Sdk.checkArtifactExists(sdk.librariesJson) ||
+ !Sdk.checkArtifactExists(sdk.dartAotRuntime) ||
+ !Sdk.checkArtifactExists(sdk.dart2wasmSnapshot) ||
+ (optimize && !Sdk.checkArtifactExists(sdk.wasmOpt))) {
return 255;
}
@@ -536,37 +531,40 @@
final outputFileBasename =
outputFile.substring(0, outputFile.length - '.wasm'.length);
- final options = WasmCompilerOptions(
- mainUri: Uri.file(path.absolute(sourcePath)),
- outputFile: outputFile,
- );
- options.librariesSpecPath =
- Uri.file(path.absolute(sdk.sdkPath, 'lib', 'libraries.json'));
- options.sdkPath = Uri.file(path.absolute(sdk.sdkPath));
- options.packagesPath = args[packagesOption.flag];
- options.translatorOptions.enableAsserts = args['enable-asserts'];
- options.translatorOptions.printWasm = args['print-wasm'];
- options.translatorOptions.printKernel = args['print-kernel'];
- options.translatorOptions.omitTypeChecks = args['omit-type-checks'];
- options.translatorOptions.nameSection = args['name-section'];
+ final sdkPath = path.absolute(sdk.sdkPath);
+ final packages = args[packagesOption.flag];
+
+ int? maxPages;
if (args['shared-memory'] != null) {
- int? maxPages = int.tryParse(args['shared-memory']);
+ maxPages = int.tryParse(args['shared-memory']);
if (maxPages == null) {
usageException(
'Error: The --shared-memory flag must specify a number!');
}
- options.translatorOptions.importSharedMemory = true;
- options.translatorOptions.sharedMemoryMaxPages = maxPages;
}
- int result;
+ final dart2wasmCommand = [
+ sdk.dartAotRuntime,
+ sdk.dart2wasmSnapshot,
+ '--libraries-spec=${sdk.librariesJson}',
+ '--dart-sdk=$sdkPath',
+ if (verbose) '--verbose',
+ if (packages != null) '--packages=$packages',
+ if (args['enable-asserts']) '--enable-asserts',
+ if (args['print-wasm']) '--print-wasm',
+ if (args['print-kernel']) '--print-kernel',
+ if (args['omit-type-checks']) '--omit-type-checks',
+ if (args['name-section']) '--name-section',
+ if (maxPages != null) ...[
+ '--import-shared-memory',
+ '--shared-memory-max-pages=$maxPages',
+ ],
+ path.absolute(sourcePath),
+ outputFile,
+ ];
try {
- result = await generateWasm(
- options,
- verbose: verbose,
- errorPrinter: (error) => log.stderr(error),
- );
- if (result != 0) return compileErrorExitCode;
+ final exitCode = await runProcess(dart2wasmCommand);
+ if (exitCode != 0) return compileErrorExitCode;
} catch (e, st) {
log.stderr('Error: Wasm compilation failed');
log.stderr(e.toString());
@@ -586,10 +584,10 @@
];
if (verbose) {
- log.stdout('Optimizing output with: $optimizer $flags');
+ log.stdout('Optimizing output with: ${sdk.wasmOpt} $flags');
}
final processResult = Process.runSync(
- optimizer,
+ sdk.wasmOpt,
[...flags, '-o', outputFile, unoptFile],
);
if (processResult.exitCode != 0) {
@@ -602,7 +600,7 @@
final mjsFile = '$outputFileBasename.mjs';
log.stdout(
"Generated wasm module '$outputFile', and JS init file '$mjsFile'.");
- return result;
+ return 0;
}
}
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index 959c7bf..afc8f99 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -113,19 +113,15 @@
if (args['pub']) {
log.stdout('');
- var progress = log.progress('Running pub get');
- var process = await startDartProcess(
- sdk,
- ['pub', 'get'],
- cwd: dir,
- );
+ final progress = log.progress('Running pub get');
// Run 'pub get'. We display output from the pub command, but keep the
// output terse. This is to give the user a sense of the work that pub
// did without scrolling the previous stdout sections off the screen.
- var buffer = StringBuffer();
- routeToStdout(
- process,
+ final buffer = StringBuffer();
+ final exitCode = await runProcess(
+ [sdk.dart, 'pub', 'get'],
+ cwd: dir,
logToTrace: true,
listener: (str) {
// Filter lines like '+ multi_server_socket 1.0.2'.
@@ -134,8 +130,7 @@
}
},
);
- int code = await process.exitCode;
- if (code != 0) return code;
+ if (exitCode != 0) return exitCode;
progress.finish(showTiming: true);
log.stdout(buffer.toString().trimRight());
}
diff --git a/pkg/dartdev/lib/src/core.dart b/pkg/dartdev/lib/src/core.dart
index 9b880ae..6aae37a 100644
--- a/pkg/dartdev/lib/src/core.dart
+++ b/pkg/dartdev/lib/src/core.dart
@@ -101,41 +101,42 @@
return Process.start(sdk.dart, arguments, workingDirectory: cwd);
}
-void routeToStdout(
- Process process, {
+Future<int> runProcess(
+ List<String> command, {
bool logToTrace = false,
void Function(String str)? listener,
-}) {
- if (isDiagnostics) {
- _streamLineTransform(process.stdout, (String line) {
- logToTrace ? log.trace(line.trimRight()) : log.stdout(line.trimRight());
- if (listener != null) listener(line);
- });
- _streamLineTransform(process.stderr, (String line) {
- log.stderr(line.trimRight());
- if (listener != null) listener(line);
- });
- } else {
- _streamLineTransform(process.stdout, (String line) {
- logToTrace ? log.trace(line.trimRight()) : log.stdout(line.trimRight());
- if (listener != null) listener(line);
- });
-
- _streamLineTransform(process.stderr, (String line) {
- log.stderr(line.trimRight());
+ String? cwd,
+}) async {
+ Future forward(Stream<List<int>> output, bool isStderr) {
+ return _streamLineTransform(output, (line) {
+ final trimmed = line.trimRight();
+ logToTrace
+ ? log.trace(trimmed)
+ : (isStderr ? log.stderr(trimmed) : log.stdout(trimmed));
if (listener != null) listener(line);
});
}
+
+ log.trace(command.join(' '));
+ final process = await Process.start(command.first, command.skip(1).toList(),
+ workingDirectory: cwd);
+ final (_, _, exitCode) = await (
+ forward(process.stdout, false),
+ forward(process.stderr, true),
+ process.exitCode
+ ).wait;
+ return exitCode;
}
-void _streamLineTransform(
+Future _streamLineTransform(
Stream<List<int>> stream,
Function(String line) handler,
) {
- stream
+ return stream
.transform(utf8.decoder)
.transform(const LineSplitter())
- .forEach(handler);
+ .listen(handler)
+ .asFuture();
}
/// A representation of a project on disk.
diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart
index d479745..73cb607 100644
--- a/pkg/dartdev/lib/src/sdk.dart
+++ b/pkg/dartdev/lib/src/sdk.dart
@@ -49,6 +49,13 @@
'dart2js.dart.snapshot',
);
+ String get dart2wasmSnapshot => path.absolute(
+ sdkPath,
+ 'bin',
+ 'snapshots',
+ 'dart2wasm_product.snapshot',
+ );
+
String get ddsSnapshot => path.absolute(
sdkPath,
'bin',
@@ -91,6 +98,11 @@
'devtools',
);
+ String get wasmOpt => path.join(sdkPath, 'bin', 'utils',
+ Platform.isWindows ? 'wasm-opt.exe' : 'wasm-opt');
+
+ String get librariesJson => path.absolute(sdkPath, 'lib', 'libraries.json');
+
static bool checkArtifactExists(String path, {bool logError = true}) {
if (!File(path).existsSync()) {
if (logError) {
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index 1cdf135..96cc856 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -15,7 +15,6 @@
cli_util: any
collection: any
dart2native: any
- dart2wasm: any
dart_style: any
dartdoc: any
dds: any
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 8a51394..3ecb92f 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -1146,7 +1146,8 @@
@override
void _parseErrors() {
var errors = <StaticError>[];
- parseErrors(decodeUtf8(stdout), errors);
+ // We expect errors to be printed to `stderr` for dart2wasm.
+ parseErrors(decodeUtf8(stderr), errors);
errors.forEach(addError);
}
}