blob: 18723691a4f5e82b8762eafb10b8078dfe6421ff [file] [log] [blame] [edit]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert';
import 'dart:io';
import 'package:compiler/src/commandline_options.dart';
Future<void> main(List<String> args) async {
Stopwatch stopwatch = Stopwatch();
String? input;
String? serializedInput;
String output = 'out.js';
List<String> arguments = [];
int start = 0;
int stop = 3;
int? shards;
bool enableAssertions = false;
for (String arg in args) {
if (arg.startsWith('-')) {
if (arg.startsWith('--start=')) {
start = int.parse(arg.substring('--start='.length));
} else if (arg.startsWith('--stop=')) {
stop = int.parse(arg.substring('--stop='.length));
} else if (arg.startsWith('--shards=')) {
shards = int.parse(arg.substring('--shards='.length));
} else if (arg == '-ea' || arg == '--enable_asserts') {
enableAssertions = true;
} else if (arg.startsWith('--in=')) {
serializedInput = arg.substring('--in='.length);
} else if (arg.startsWith('-o')) {
output = arg.substring('-o'.length);
} else if (arg.startsWith('--out=')) {
output = arg.substring('--out='.length);
} else {
arguments.add(arg);
}
} else {
if (input != null) {
print("Multiple entrypoints provided: '$input' and '$arg'.");
exit(-1);
}
input = arg;
}
}
if (input == null) {
print("No entrypoint provided.");
exit(-1);
}
serializedInput ??= output;
String inputPrefix = serializedInput;
if (serializedInput.endsWith('.js')) {
inputPrefix = output.substring(0, output.length - '.js'.length);
}
String outputPrefix = output;
if (output.endsWith('.js')) {
outputPrefix = output.substring(0, output.length - '.js'.length);
}
List<String> baseOptions = ['--packages=${Platform.packageConfig}'];
if (enableAssertions) {
baseOptions.add('--enable_asserts');
}
baseOptions.add('package:compiler/src/dart2js.dart');
baseOptions.addAll(arguments);
String cfeOutput = '${inputPrefix}0.dill';
String dillOutput = '$inputPrefix.dill';
String dataOutput = '$inputPrefix.dill.data';
String codeOutput = '$outputPrefix.code';
shards ??= 2;
stopwatch.start();
if (start <= 0 && stop >= 0) {
await subProcess(baseOptions, [
input,
'${Flags.stage}=cfe',
'--out=$cfeOutput',
], '0:\t');
}
if (start <= 1 && stop >= 1) {
await subProcess(baseOptions, [
cfeOutput,
'--out=$dillOutput',
'${Flags.closedWorldUri}=$dataOutput',
'${Flags.stage}=closed-world',
], '1:\t');
}
if (shards <= 1) {
await subProcess(baseOptions, [
dillOutput,
'${Flags.globalInferenceUri}=$dataOutput',
'${Flags.stage}=codegen-emit-js',
'--out=$output',
], '3:\t');
} else {
if (start <= 2 && stop >= 2) {
List<List<String>> additionalArguments = [];
List<String> outputPrefixes = [];
for (int shard = 0; shard < shards; shard++) {
additionalArguments.add([
dillOutput,
'${Flags.globalInferenceUri}=$dataOutput',
'${Flags.codegenShard}=$shard',
'${Flags.codegenShards}=$shards',
'${Flags.codegenUri}=$codeOutput',
'${Flags.stage}=codegen',
]);
outputPrefixes.add('2:${shard + 1}/$shards\t');
}
Stopwatch subwatch = Stopwatch();
subwatch.start();
await Future.wait(
List<Future<void>>.generate(shards, (int shard) {
return subProcess(
baseOptions,
additionalArguments[shard],
outputPrefixes[shard],
);
}),
);
subwatch.stop();
print('2:\tTotal time: ${_formatMs(subwatch.elapsedMilliseconds)}');
}
if (start <= 3 && stop >= 3) {
await subProcess(baseOptions, [
dillOutput,
'${Flags.globalInferenceUri}=$dataOutput',
'${Flags.codegenUri}=$codeOutput',
'${Flags.codegenShards}=$shards',
'${Flags.stage}=emit-js',
'--out=$output',
], '3:\t');
}
}
stopwatch.stop();
print('Total time: ${_formatMs(stopwatch.elapsedMilliseconds)}');
}
Future<void> subProcess(
List<String> baseOptions,
List<String> additionalOptions,
String outputPrefix,
) async {
List<String> options = [...baseOptions, ...additionalOptions];
print(
'${outputPrefix}Command: ${Platform.resolvedExecutable} ${options.join(' ')}',
);
Process process = await Process.start(
Platform.resolvedExecutable,
options,
runInShell: true,
);
_Prefixer stdoutPrefixer = _Prefixer(outputPrefix, stdout);
_Prefixer stderrOutputter = _Prefixer(outputPrefix, stderr);
process.stdout.transform(utf8.decoder).listen(stdoutPrefixer.call);
process.stderr.transform(utf8.decoder).listen(stderrOutputter.call);
int exitCode = await process.exitCode;
if (exitCode != 0) {
exit(exitCode);
}
}
class _Prefixer {
final String _prefix;
final Stdout _stdout;
bool _atNewLine = true;
_Prefixer(this._prefix, this._stdout);
void call(String text) {
int index = 0;
while (index < text.length) {
if (_atNewLine) {
_stdout.write(_prefix);
_atNewLine = false;
}
int pos = text.indexOf('\n', index);
if (pos != -1) {
_stdout.write(text.substring(index, pos + 1));
_atNewLine = true;
index = pos + 1;
} else {
_stdout.write(text.substring(index));
index = text.length;
}
}
}
}
String _formatMs(int ms) {
return '${(ms / 1000).toStringAsFixed(3)}s';
}