Chromium Code Reviews| Index: runtime/tools/kernel-service.dart |
| diff --git a/runtime/tools/kernel-service.dart b/runtime/tools/kernel-service.dart |
| index b1b441db2ed5e7d1f6efe595150f09d973bb1c93..0d123ff907b7e183d6560ddee22429a136798468 100644 |
| --- a/runtime/tools/kernel-service.dart |
| +++ b/runtime/tools/kernel-service.dart |
| @@ -8,6 +8,24 @@ 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 |
|
kustermann
2017/01/31 15:38:59
This should be:
dart runtime/tools/kernel-se
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| +// |
| +// The port for the batch mode worker is controlled by DFE_WORKER_PORT |
| +// environment variable. When not set (or set to 0) an ephemeral port returned |
|
kustermann
2017/01/31 15:38:59
"environment variable" aren't these -D... flags to
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| +// 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'; |
| @@ -21,6 +39,7 @@ import 'package:kernel/kernel.dart'; |
| import 'package:kernel/target/targets.dart'; |
| const bool verbose = 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 +74,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 +94,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 +112,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 +203,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 +251,72 @@ 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 = |
| + new ContentType("application", "json", charset: "utf-8"); |
|
kustermann
2017/01/31 15:38:59
Isn't there a constant for it in dart:io?
Content
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| + rq.write(JSON.encode({ |
| + "inputFileUrl": scriptUri.toString(), |
| + "packagesUri": packagesUri.toString(), |
| + "patchedSdk": patchedSdk.toString(), |
|
kustermann
2017/01/31 15:39:00
If these can be relative, you should Platform.curr
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
These are all absolute.
|
| + })); |
| + final rs = await rq.close(); |
| + try { |
| + if (rs.statusCode == HttpStatus.OK) { |
| + final ds = new DataSink(); |
| + await rs.forEach(ds.add); |
|
kustermann
2017/01/31 15:38:59
Either use something like (and make DataSink be ab
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| + return new CompilationOk(ds.builder.takeBytes()); |
| + } else { |
| + return CompilationFail.fromJson(JSON.decode(await UTF8.decodeStream(rs))); |
| + } |
| + } finally { |
| + client.close(); |
|
kustermann
2017/01/31 15:38:59
await client.close()
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| + } |
| +} |
| + |
| +void startBatchServer() { |
| + final loader = new DartLoaderBatch(); |
| + HttpServer.bind(InternetAddress.LOOPBACK_IP_V6, workerPort).then((server) { |
| + print('READY ${server.port}'); |
| + server.listen((HttpRequest request) async { |
|
kustermann
2017/01/31 15:38:59
For a graceful shutdown:
ProcessSignal.SIGTERM.fi
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| + 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.headers.contentType = ContentType.BINARY; |
| + request.response.add(result.binary); |
| + request.response.close(); |
| + } else { |
| + request.response.headers.contentType = ContentType.TEXT; |
| + request.response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR; |
|
kustermann
2017/01/31 15:38:59
Maybe set the statusCode to be OK in the other bra
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| + request.response.write(JSON.encode(result.toJson())); |
| + request.response.close(); |
| + } |
| + }); |
| + }); |
| +} |
| + |
| +main([args]) { |
| + if (args?.length == 1 && args[0] == '--batch') { |
| + return startBatchServer(); |
| + } |
| + |
| + return new RawReceivePort()..handler = _processLoadRequest; |
|
kustermann
2017/01/31 15:39:00
maybe use
if () {
....
return null;
} else {
Vyacheslav Egorov (Google)
2017/01/31 17:06:55
Done.
|
| +} |
| // This duplicates functionality from the Loader which we can't easily |
| // access from here. |
| @@ -216,7 +327,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; |