| Index: runtime/tools/kernel-service.dart
|
| diff --git a/runtime/tools/kernel-service.dart b/runtime/tools/kernel-service.dart
|
| index b1b441db2ed5e7d1f6efe595150f09d973bb1c93..ee32138cbeeaf7fee6477399f676fc63c3cdd175 100644
|
| --- a/runtime/tools/kernel-service.dart
|
| +++ b/runtime/tools/kernel-service.dart
|
| @@ -8,6 +8,25 @@ library runtime.tools.kernel_service;
|
| // It is used by the kernel-isolate to load Dart source code and generate
|
| // Kernel binary format.
|
| //
|
| +// This is either invoked as the root script of the Kernel isolate when used
|
| +// as a part of
|
| +//
|
| +// dart --dfe=runtime/tools/kernel-service.dart ...
|
| +//
|
| +// invocation or it is invoked as a standalone script to perform batch mode
|
| +// compilation requested via an HTTP interface
|
| +//
|
| +// dart runtime/tools/kernel-service.dart --batch
|
| +//
|
| +// The port for the batch mode worker is controlled by DFE_WORKER_PORT
|
| +// environment declarations (set by -DDFE_WORKER_PORT=... command line flag).
|
| +// When not set (or set to 0) an ephemeral port returned by the OS is used
|
| +// instead.
|
| +//
|
| +// When this script is used as a Kernel isolate root script and DFE_WORKER_PORT
|
| +// is set to non-zero value then Kernel isolate will forward all compilation
|
| +// requests it receives to the batch worker on the given port.
|
| +//
|
|
|
| import 'dart:async';
|
| import 'dart:convert';
|
| @@ -20,7 +39,8 @@ import 'package:kernel/binary/ast_to_binary.dart';
|
| import 'package:kernel/kernel.dart';
|
| import 'package:kernel/target/targets.dart';
|
|
|
| -const bool verbose = const bool.fromEnvironment('DFE_VERBOSE') ?? false;
|
| +const bool verbose = true || (const bool.fromEnvironment('DFE_VERBOSE') ?? false);
|
| +const int workerPort = const int.fromEnvironment('DFE_WORKER_PORT') ?? 0;
|
|
|
| class DataSink implements Sink<List<int>> {
|
| final BytesBuilder builder = new BytesBuilder();
|
| @@ -55,6 +75,17 @@ class CompilationOk extends CompilationResult {
|
|
|
| abstract class CompilationFail extends CompilationResult {
|
| String get errorString;
|
| +
|
| + Map<String, dynamic> toJson();
|
| +
|
| + static CompilationFail fromJson(Map m) {
|
| + switch (m['status']) {
|
| + case STATUS_ERROR:
|
| + return new CompilationError(m['errors']);
|
| + case STATUS_CRASH:
|
| + return new CompilationCrash(m['exception'], m['stack']);
|
| + }
|
| + }
|
| }
|
|
|
| class CompilationError extends CompilationFail {
|
| @@ -64,6 +95,11 @@ class CompilationError extends CompilationFail {
|
|
|
| List toResponse() => [STATUS_ERROR, errorString];
|
|
|
| + Map<String, dynamic> toJson() => {
|
| + "status": STATUS_ERROR,
|
| + "errors": errors,
|
| + };
|
| +
|
| String get errorString => errors.take(10).join('\n');
|
|
|
| String toString() => "CompilationError(${errorString})";
|
| @@ -77,6 +113,12 @@ class CompilationCrash extends CompilationFail {
|
|
|
| List toResponse() => [STATUS_CRASH, errorString];
|
|
|
| + Map<String, dynamic> toJson() => {
|
| + "status": STATUS_CRASH,
|
| + "exception": exception,
|
| + "stack": stack,
|
| + };
|
| +
|
| String get errorString => "${exception}\n${stack}";
|
|
|
| String toString() => "CompilationCrash(${errorString})";
|
| @@ -162,10 +204,15 @@ Future _processLoadRequestImpl(String inputFileUrl) async {
|
| }""");
|
| }
|
|
|
| - return await parseScript(
|
| - new DartLoaderBatch(), scriptUri, packagesUri.path, patchedSdk.path);
|
| + if (workerPort != 0) {
|
| + return await requestParse(scriptUri, packagesUri, patchedSdk);
|
| + } else {
|
| + return await parseScript(
|
| + new DartLoaderBatch(), scriptUri, packagesUri.path, patchedSdk.path);
|
| + }
|
| }
|
|
|
| +
|
| // Process a request from the runtime. See KernelIsolate::CompileToKernel in
|
| // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc.
|
| Future _processLoadRequest(request) async {
|
| @@ -205,7 +252,74 @@ Future _processLoadRequest(request) async {
|
| }
|
| }
|
|
|
| -main() => new RawReceivePort()..handler = _processLoadRequest;
|
| +Future<CompilationResult> requestParse(
|
| + Uri scriptUri, Uri packagesUri, Uri patchedSdk) async {
|
| + if (verbose) {
|
| + print(
|
| + "DFE: forwarding request to worker at http://localhost:${workerPort}/");
|
| + }
|
| +
|
| + HttpClient client = new HttpClient();
|
| + final rq = await client
|
| + .postUrl(new Uri(host: 'localhost', port: workerPort, scheme: 'http'));
|
| + rq.headers.contentType = ContentType.JSON;
|
| + rq.write(JSON.encode({
|
| + "inputFileUrl": scriptUri.toString(),
|
| + "packagesUri": packagesUri.toString(),
|
| + "patchedSdk": patchedSdk.toString(),
|
| + }));
|
| + final rs = await rq.close();
|
| + try {
|
| + if (rs.statusCode == HttpStatus.OK) {
|
| + final BytesBuilder bb = new BytesBuilder();
|
| + await rs.forEach(bb.add);
|
| + return new CompilationOk(bb.takeBytes());
|
| + } else {
|
| + return CompilationFail.fromJson(JSON.decode(await UTF8.decodeStream(rs)));
|
| + }
|
| + } finally {
|
| + await client.close();
|
| + }
|
| +}
|
| +
|
| +void startBatchServer() {
|
| + final loader = new DartLoaderBatch();
|
| + HttpServer.bind(InternetAddress.LOOPBACK_IP_V6, workerPort).then((server) {
|
| + print('READY ${server.port}');
|
| + server.listen((HttpRequest request) async {
|
| + final rq = JSON.decode(await UTF8.decodeStream(request));
|
| +
|
| + final Uri scriptUri = Uri.parse(rq['inputFileUrl']);
|
| + final Uri packagesUri = Uri.parse(rq['packagesUri']);
|
| + final Uri patchedSdk = Uri.parse(rq['patchedSdk']);
|
| +
|
| + final CompilationResult result = await parseScript(
|
| + loader, scriptUri, packagesUri.path, patchedSdk.path);
|
| +
|
| + if (result is CompilationOk) {
|
| + request.response.statusCode = HttpStatus.OK;
|
| + request.response.headers.contentType = ContentType.BINARY;
|
| + request.response.add(result.binary);
|
| + request.response.close();
|
| + } else {
|
| + request.response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
|
| + request.response.headers.contentType = ContentType.TEXT;
|
| + request.response.write(JSON.encode(result.toJson()));
|
| + request.response.close();
|
| + }
|
| + });
|
| + ProcessSignal.SIGTERM.watch().first.then((_) => server.close());
|
| + });
|
| +}
|
| +
|
| +main([args]) {
|
| + if (args?.length == 1 && args[0] == '--batch') {
|
| + startBatchServer();
|
| + } else {
|
| + // Entry point for the Kernel isolate.
|
| + return new RawReceivePort()..handler = _processLoadRequest;
|
| + }
|
| +}
|
|
|
| // This duplicates functionality from the Loader which we can't easily
|
| // access from here.
|
| @@ -216,7 +330,7 @@ Uri _findPackagesFile(Uri base) async {
|
| if (await new File.fromUri(packagesFile).exists()) {
|
| return packagesFile;
|
| }
|
| - if (dir.parent == dir) {
|
| + if (dir.parent.path == dir.path) {
|
| break;
|
| }
|
| dir = dir.parent;
|
|
|