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; |