OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// This is an interface to the Dart Kernel parser and Kernel binary generator. | 5 /// This is an interface to the Dart Kernel parser and Kernel binary generator. |
6 /// | 6 /// |
7 /// It is used by the kernel-isolate to load Dart source code and generate | 7 /// It is used by the kernel-isolate to load Dart source code and generate |
8 /// Kernel binary format. | 8 /// Kernel binary format. |
9 /// | 9 /// |
10 /// This is either invoked as the root script of the Kernel isolate when used | 10 /// This is either invoked as the root script of the Kernel isolate when used |
11 /// as a part of | 11 /// as a part of |
12 /// | 12 /// |
13 /// dart --dfe=utils/kernel-service/kernel-service.dart ... | 13 /// dart --dfe=utils/kernel-service/kernel-service.dart ... |
14 /// | 14 /// |
15 /// invocation or it is invoked as a standalone script to perform training for | 15 /// invocation or it is invoked as a standalone script to perform training for |
16 /// the app-jit snapshot | 16 /// the app-jit snapshot |
17 /// | 17 /// |
18 /// dart utils/kernel-service/kernel-service.dart --train <source-file> | 18 /// dart utils/kernel-service/kernel-service.dart --train <source-file> |
19 /// | 19 /// |
20 /// | 20 /// |
21 library runtime.tools.kernel_service; | 21 library runtime.tools.kernel_service; |
22 | 22 |
23 import 'dart:async'; | 23 import 'dart:async' show Future; |
24 import 'dart:io' hide FileSystemEntity; | 24 import 'dart:io' show File, Platform hide FileSystemEntity; |
25 import 'dart:isolate'; | 25 import 'dart:isolate'; |
| 26 import 'dart:typed_data' show Uint8List; |
26 | 27 |
27 import 'package:front_end/file_system.dart'; | 28 import 'package:front_end/file_system.dart'; |
| 29 import 'package:front_end/front_end.dart'; |
28 import 'package:front_end/memory_file_system.dart'; | 30 import 'package:front_end/memory_file_system.dart'; |
29 import 'package:front_end/physical_file_system.dart'; | 31 import 'package:front_end/physical_file_system.dart'; |
30 import 'package:front_end/src/fasta/vm.dart' | 32 import 'package:front_end/src/fasta/kernel/utils.dart'; |
31 show CompilationResult, Status, parseScriptInFileSystem; | |
32 import 'package:front_end/src/testing/hybrid_file_system.dart'; | 33 import 'package:front_end/src/testing/hybrid_file_system.dart'; |
| 34 import 'package:kernel/kernel.dart' show Program; |
| 35 import 'package:kernel/target/targets.dart' show TargetFlags; |
| 36 import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget; |
33 | 37 |
34 const bool verbose = const bool.fromEnvironment('DFE_VERBOSE'); | 38 const bool verbose = const bool.fromEnvironment('DFE_VERBOSE'); |
35 | 39 |
36 const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE'); | 40 const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE'); |
37 | 41 |
| 42 Future<CompilationResult> _parseScriptInFileSystem( |
| 43 Uri script, FileSystem fileSystem, |
| 44 {bool verbose: false, bool strongMode: false}) async { |
| 45 final Uri packagesUri = (Platform.packageConfig != null) |
| 46 ? Uri.parse(Platform.packageConfig) |
| 47 : await _findPackagesFile(fileSystem, script); |
| 48 if (packagesUri == null) { |
| 49 throw "Could not find .packages"; |
| 50 } |
| 51 |
| 52 final Uri patchedSdk = Uri.base |
| 53 .resolveUri(new Uri.file(Platform.resolvedExecutable)) |
| 54 .resolveUri(new Uri.directory("patched_sdk")); |
| 55 |
| 56 if (verbose) { |
| 57 print("""DFE: Requesting compilation { |
| 58 scriptUri: ${script} |
| 59 packagesUri: ${packagesUri} |
| 60 patchedSdk: ${patchedSdk} |
| 61 }"""); |
| 62 } |
| 63 |
| 64 try { |
| 65 var errors = <String>[]; |
| 66 var options = new CompilerOptions() |
| 67 ..strongMode = strongMode |
| 68 ..fileSystem = fileSystem |
| 69 ..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode)) |
| 70 ..packagesFileUri = packagesUri |
| 71 // TODO(sigmund): use outline.dill when the mixin transformer is modular. |
| 72 ..sdkSummary = patchedSdk.resolve('platform.dill') |
| 73 ..verbose = verbose |
| 74 ..onError = (CompilationError e) => errors.add(e.message); |
| 75 |
| 76 Program program = await kernelForProgram(script, options); |
| 77 if (errors.isNotEmpty) return new CompilationResult.errors(errors); |
| 78 |
| 79 // We serialize the program excluding platform.dill because the VM has these |
| 80 // sources built-in. Everything loaded as a summary in [kernelForProgram] is |
| 81 // marked `external`, so we can use that bit to decide what to excluce. |
| 82 return new CompilationResult.ok( |
| 83 serializeProgram(program, filter: (lib) => !lib.isExternal)); |
| 84 } catch (err, stack) { |
| 85 return new CompilationResult.crash(err, stack); |
| 86 } |
| 87 } |
| 88 |
| 89 /// This duplicates functionality from the Loader which we can't easily |
| 90 /// access from here. |
| 91 // TODO(sigmund): delete, this should be supported by the default options in |
| 92 // package:front_end. |
| 93 Future<Uri> _findPackagesFile(FileSystem fileSystem, Uri base) async { |
| 94 var dir = new File.fromUri(base).parent; |
| 95 while (true) { |
| 96 final packagesFile = dir.uri.resolve(".packages"); |
| 97 if (await fileSystem.entityForUri(packagesFile).exists()) { |
| 98 return packagesFile; |
| 99 } |
| 100 if (dir.parent.path == dir.path) { |
| 101 break; |
| 102 } |
| 103 dir = dir.parent; |
| 104 } |
| 105 return null; |
| 106 } |
| 107 |
38 Future<CompilationResult> _processLoadRequestImpl( | 108 Future<CompilationResult> _processLoadRequestImpl( |
39 String inputFilePathOrUri, FileSystem fileSystem) { | 109 String inputFilePathOrUri, FileSystem fileSystem) { |
40 Uri scriptUri = Uri.parse(inputFilePathOrUri); | 110 Uri scriptUri = Uri.parse(inputFilePathOrUri); |
41 | 111 |
42 // Because we serve both Loader and bootstrapping requests we need to | 112 // Because we serve both Loader and bootstrapping requests we need to |
43 // duplicate the logic from _resolveScriptUri(...) here and attempt to | 113 // duplicate the logic from _resolveScriptUri(...) here and attempt to |
44 // resolve schemaless uris using current working directory. | 114 // resolve schemaless uris using current working directory. |
45 if (!scriptUri.hasScheme) { | 115 if (!scriptUri.hasScheme) { |
46 // Script does not have a scheme, assume that it is a path, | 116 // Script does not have a scheme, assume that it is a path, |
47 // resolve it against the working directory. | 117 // resolve it against the working directory. |
48 scriptUri = Uri.base.resolveUri(new Uri.file(inputFilePathOrUri)); | 118 scriptUri = Uri.base.resolveUri(new Uri.file(inputFilePathOrUri)); |
49 } | 119 } |
50 | 120 |
51 if (!scriptUri.isScheme('file')) { | 121 if (!scriptUri.isScheme('file')) { |
52 // TODO(vegorov): Reuse loader code to support other schemes. | 122 // TODO(vegorov): Reuse loader code to support other schemes. |
53 return new Future<CompilationResult>.value(new CompilationResult.error( | 123 return new Future<CompilationResult>.value(new CompilationResult.errors( |
54 "Expected 'file' scheme for a script uri: got ${scriptUri.scheme}")); | 124 ["Expected 'file' scheme for a script uri: got ${scriptUri.scheme}"])); |
55 } | 125 } |
56 return parseScriptInFileSystem(scriptUri, fileSystem, | 126 return _parseScriptInFileSystem(scriptUri, fileSystem, |
57 verbose: verbose, strongMode: strongMode); | 127 verbose: verbose, strongMode: strongMode); |
58 } | 128 } |
59 | 129 |
60 // Process a request from the runtime. See KernelIsolate::CompileToKernel in | 130 // Process a request from the runtime. See KernelIsolate::CompileToKernel in |
61 // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc. | 131 // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc. |
62 Future _processLoadRequest(request) async { | 132 Future _processLoadRequest(request) async { |
63 if (verbose) { | 133 if (verbose) { |
64 print("DFE: request: $request"); | 134 print("DFE: request: $request"); |
65 print("DFE: Platform.packageConfig: ${Platform.packageConfig}"); | 135 print("DFE: Platform.packageConfig: ${Platform.packageConfig}"); |
66 print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}"); | 136 print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}"); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 main([args]) { | 209 main([args]) { |
140 if (args?.length == 2 && args[0] == '--train') { | 210 if (args?.length == 2 && args[0] == '--train') { |
141 // This entry point is used when creating an app snapshot. The argument | 211 // This entry point is used when creating an app snapshot. The argument |
142 // provides a script to compile to warm-up generated code. | 212 // provides a script to compile to warm-up generated code. |
143 train(args[1]); | 213 train(args[1]); |
144 } else { | 214 } else { |
145 // Entry point for the Kernel isolate. | 215 // Entry point for the Kernel isolate. |
146 return new RawReceivePort()..handler = _processLoadRequest; | 216 return new RawReceivePort()..handler = _processLoadRequest; |
147 } | 217 } |
148 } | 218 } |
| 219 |
| 220 /// Compilation status codes. |
| 221 /// |
| 222 /// Note: The [index] property of these constants must match |
| 223 /// `Dart_KernelCompilationStatus` in |
| 224 /// [dart_api.h](../../../../runtime/include/dart_api.h). |
| 225 enum Status { |
| 226 /// Compilation was successful. |
| 227 ok, |
| 228 |
| 229 /// Compilation failed with a compile time error. |
| 230 error, |
| 231 |
| 232 /// Compiler crashed. |
| 233 crash, |
| 234 } |
| 235 |
| 236 abstract class CompilationResult { |
| 237 CompilationResult._(); |
| 238 |
| 239 factory CompilationResult.ok(Uint8List bytes) = _CompilationOk; |
| 240 |
| 241 factory CompilationResult.errors(List<String> errors) = _CompilationError; |
| 242 |
| 243 factory CompilationResult.crash(Object exception, StackTrace stack) = |
| 244 _CompilationCrash; |
| 245 |
| 246 Status get status; |
| 247 |
| 248 get payload; |
| 249 |
| 250 List toResponse() => [status.index, payload]; |
| 251 } |
| 252 |
| 253 class _CompilationOk extends CompilationResult { |
| 254 final Uint8List bytes; |
| 255 |
| 256 _CompilationOk(this.bytes) : super._(); |
| 257 |
| 258 @override |
| 259 Status get status => Status.ok; |
| 260 |
| 261 @override |
| 262 get payload => bytes; |
| 263 |
| 264 String toString() => "_CompilationOk(${bytes.length} bytes)"; |
| 265 } |
| 266 |
| 267 abstract class _CompilationFail extends CompilationResult { |
| 268 _CompilationFail() : super._(); |
| 269 |
| 270 String get errorString; |
| 271 |
| 272 @override |
| 273 get payload => errorString; |
| 274 } |
| 275 |
| 276 class _CompilationError extends _CompilationFail { |
| 277 final List<String> errors; |
| 278 |
| 279 _CompilationError(this.errors); |
| 280 |
| 281 @override |
| 282 Status get status => Status.error; |
| 283 |
| 284 @override |
| 285 String get errorString => errors.take(10).join('\n'); |
| 286 |
| 287 String toString() => "_CompilationError(${errorString})"; |
| 288 } |
| 289 |
| 290 class _CompilationCrash extends _CompilationFail { |
| 291 final Object exception; |
| 292 final StackTrace stack; |
| 293 |
| 294 _CompilationCrash(this.exception, this.stack); |
| 295 |
| 296 @override |
| 297 Status get status => Status.crash; |
| 298 |
| 299 @override |
| 300 String get errorString => "${exception}\n${stack}"; |
| 301 |
| 302 String toString() => "_CompilationCrash(${errorString})"; |
| 303 } |
OLD | NEW |