34052bf2bb
- Move expression evaluation to ddc in preparation for google3 - Added server to ddc to handle update and compileExpression requests - Added tests - Added 'experimental-output-compiled-kernel' option to ddc to generate full kernel files only for compiled libraries, and store with '.full.dill' extension - Added AssetFileSystem to communicate to the asset server in the debugger - Made expression_compiler_worker work with full kernel files, so removed invalidation of current file to improve performance - Made expression_compiler_worker reuse already loaded imports to avoid reading them from source in the incremental compiler - Updated tests to work with DDC (for simulating webdev) - Disabled tests that work with bazel kernel worker for now as it does not generate full dill files yet - Addressed code review comments from the prototype version: https://dart-review.googlesource.com/c/sdk/+/157005 Details: Currently, in flutter tools, expression evaluation is supported via expression compilation, which is done by the incremental compiler in the frontend server. The same incremental compiler is used for initial application compilation, incremental code compilation for hot reload, and any number of expression compilation requests. In google3, the apps are typically too large to be compiled as a whole in memory by the frontend server. Build in google3 is currently done by blaze, as a distributed build using a task dependency graph. Build tasks output kernel outline files as an interface between components produced by individual tasks. We are proposing an implementation of the expression compilation in google3 that is taking advantage of full kernel files produced by the build (supporting build changes to follow). This change introduces a small server based on dev_compiler, which can handle following requests: - update: load full kernel for given modules (done on app start) - compileExpression: compile expression in a given library and module (done when paused on a breakpoint) Expression compilation uses previously loaded kernel files for the application component and its dependencies to compile an expression. Change-Id: Icf73868069faf3a2eb6d43ba78e459f8457e9e35 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/160944 Reviewed-by: Nicholas Shahan <nshahan@google.com> Reviewed-by: Gary Roumanis <grouma@google.com> Reviewed-by: Jens Johansen <jensj@google.com> Reviewed-by: Jake Macdonald <jakemac@google.com> Commit-Queue: Anna Gringauze <annagrin@google.com>
121 lines
4.0 KiB
Dart
Executable File
121 lines
4.0 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.
|
|
|
|
/// 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) {
|
|
ExpressionCompilerWorker worker;
|
|
if (sendPort != null) {
|
|
var receivePort = ReceivePort();
|
|
sendPort.send(receivePort.sendPort);
|
|
worker = await ExpressionCompilerWorker.createFromArgs(parsedArgs.rest,
|
|
requestStream: receivePort.cast<Map<String, dynamic>>(),
|
|
sendResponse: sendPort.send);
|
|
} else {
|
|
worker = await ExpressionCompilerWorker.createFromArgs(parsedArgs.rest);
|
|
}
|
|
await worker.start();
|
|
} 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');
|
|
}
|