Files
sdk/pkg/dev_compiler/bin/dartdevc.dart
T
Anna Gringauze 9b901bc21f Communicate start failures from ExpressionCompilerWorker to the consumer
In some cases, such as file system exceptions,  ExpressionCompilerWorker
fails to start but does not close its receiver port, which causes the
consumer to wait indefinitely for responses.

Make ExpressionCompilerWorker communicate the failure to the consumer,
close the receiver port, and exit.

Added tests to verify graceful exit.

Issue that uncovered the bug: https://b.corp.google.com/issues/183218372

Change-Id: I54a9c3620cfc5f77c101b26b4e98b6eeb03ad7e1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192260
Commit-Queue: Anna Gringauze <annagrin@google.com>
Reviewed-by: Gary Roumanis <grouma@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
2021-03-23 02:27:55 +00:00

114 lines
3.7 KiB
Dart
Executable File

#!/usr/bin/env dart
// Copyright (c) 2016, 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.
// @dart = 2.9
/// Command line entry point for Dart Development Compiler (dartdevc), used to
/// compile a collection of dart libraries into a single JS module
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'package:bazel_worker/bazel_worker.dart';
import 'package:dev_compiler/src/compiler/shared_command.dart';
import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
/// The entry point for the Dart Dev Compiler.
///
/// [sendPort] may be passed in when started in an isolate. If provided, it is
/// used for bazel worker communication instead of stdin/stdout.
Future main(List<String> args, [SendPort sendPort]) async {
// Always returns a new modifiable list.
var parsedArgs = ParsedArguments.from(args);
if (parsedArgs.isWorker) {
var workerConnection = sendPort == null
? StdAsyncWorkerConnection()
: SendPortAsyncWorkerConnection(sendPort);
await _CompilerWorker(parsedArgs, workerConnection).run();
} else if (parsedArgs.isBatch) {
await runBatch(parsedArgs);
} else if (parsedArgs.isExpressionCompiler) {
await ExpressionCompilerWorker.createAndStart(parsedArgs.rest,
sendPort: sendPort);
} else {
var result = await compile(parsedArgs);
exitCode = result.exitCode;
}
}
/// Runs the compiler worker loop.
class _CompilerWorker extends AsyncWorkerLoop {
/// The original args supplied to the executable.
final ParsedArguments _startupArgs;
_CompilerWorker(this._startupArgs, AsyncWorkerConnection workerConnection)
: super(connection: workerConnection);
/// Keeps track of our last compilation result so it can potentially be
/// re-used in a worker.
CompilerResult lastResult;
/// Performs each individual work request.
@override
Future<WorkResponse> performRequest(WorkRequest request) async {
var args = _startupArgs.merge(request.arguments);
var output = StringBuffer();
var context = args.reuseResult ? lastResult : null;
/// Build a map of uris to digests.
final inputDigests = <Uri, List<int>>{};
for (var input in request.inputs) {
inputDigests[sourcePathToUri(input.path)] = input.digest;
}
lastResult = await runZoned(
() =>
compile(args, previousResult: context, inputDigests: inputDigests),
zoneSpecification:
ZoneSpecification(print: (self, parent, zone, message) {
output.writeln(message.toString());
}));
return WorkResponse()
..exitCode = lastResult.success ? 0 : 1
..output = output.toString();
}
}
/// Runs DDC in Kernel batch mode for test.dart.
Future runBatch(ParsedArguments batchArgs) async {
var totalTests = 0;
var failedTests = 0;
var watch = Stopwatch()..start();
print('>>> BATCH START');
String line;
CompilerResult result;
while ((line = stdin.readLineSync(encoding: utf8))?.isNotEmpty == true) {
totalTests++;
var args = batchArgs.merge(line.split(RegExp(r'\s+')));
String outcome;
try {
result = await compile(args, previousResult: result);
outcome = result.success ? 'PASS' : (result.crashed ? 'CRASH' : 'FAIL');
} catch (e, s) {
outcome = 'CRASH';
print('Unhandled exception:');
print(e);
print(s);
}
stderr.writeln('>>> EOF STDERR');
print('>>> TEST $outcome ${watch.elapsedMilliseconds}ms');
}
var time = watch.elapsedMilliseconds;
print('>>> BATCH END (${totalTests - failedTests})/$totalTests ${time}ms');
}