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 library runtime.tools.kernel_service; | |
4 | 5 |
5 // This is an interface to the Dart Kernel parser and Kernel binary generator. | 6 // This is an interface to the Dart Kernel parser and Kernel binary generator. |
7 // | |
6 // It is used by the kernel-isolate to load Dart source code and generate | 8 // It is used by the kernel-isolate to load Dart source code and generate |
7 // Kernel binary format. | 9 // Kernel binary format. |
10 // | |
8 | 11 |
12 import 'dart:async'; | |
13 import 'dart:convert'; | |
14 import 'dart:io'; | |
9 import 'dart:isolate'; | 15 import 'dart:isolate'; |
10 import 'dart:async'; | |
11 import 'dart:io'; | |
12 import 'dart:typed_data'; | 16 import 'dart:typed_data'; |
13 | 17 |
18 import 'package:kernel/analyzer/loader.dart'; | |
14 import 'package:kernel/binary/ast_to_binary.dart'; | 19 import 'package:kernel/binary/ast_to_binary.dart'; |
15 import 'package:kernel/analyzer/loader.dart'; | |
16 import 'package:kernel/kernel.dart'; | 20 import 'package:kernel/kernel.dart'; |
17 import 'package:kernel/target/targets.dart'; | 21 import 'package:kernel/target/targets.dart'; |
18 | 22 |
19 const verbose = false; | 23 const bool verbose = const bool.fromEnvironment('DFE_VERBOSE') ?? false; |
20 | 24 |
21 class DataSink implements Sink<List<int>> { | 25 class DataSink implements Sink<List<int>> { |
22 final BytesBuilder builder = new BytesBuilder(); | 26 final BytesBuilder builder = new BytesBuilder(); |
23 | 27 |
24 void add(List<int> data) { | 28 void add(List<int> data) { |
25 builder.add(data); | 29 builder.add(data); |
26 } | 30 } |
27 | 31 |
28 void close() { | 32 void close() { |
29 // Nothing to do. | 33 // Nothing to do. |
30 } | 34 } |
31 } | 35 } |
32 | 36 |
33 Future<Uint8List> parseScript( | 37 // Note: this values must match Dart_KernelCompilationStatus in dart_api.h. |
siva
2017/01/24 02:38:02
these values
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
38 const STATUS_OK = 0; // Compilation was successful. | |
39 const STATUS_ERROR = 1; // Compilation failed with a compile time error. | |
40 const STATUS_CRASH = 2; // Compiler crashed. | |
kustermann
2017/01/30 12:14:23
more types: int?
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
41 | |
42 abstract class CompilationResult { | |
43 List toResponse(); | |
44 } | |
45 | |
46 class CompilationOk extends CompilationResult { | |
47 final Uint8List binary; | |
48 | |
49 CompilationOk(this.binary); | |
50 | |
51 List toResponse() => [STATUS_OK, binary]; | |
52 | |
53 String toString() => "CompilationOk(${binary.length} bytes)"; | |
54 } | |
55 | |
56 abstract class CompilationFail extends CompilationResult { | |
57 String get errorString; | |
58 | |
59 Map<String, dynamic> toJson(); | |
siva
2017/01/24 02:38:02
Sometimes there are blank lines between methods an
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
60 static CompilationFail fromJson(Map m) { | |
61 switch (m['status']) { | |
62 case STATUS_ERROR: | |
63 return new CompilationError(m['errors']); | |
64 case STATUS_CRASH: | |
65 return new CompilationCrash(m['exception'], m['stack']); | |
66 } | |
67 } | |
kustermann
2017/01/30 12:14:23
The fromJson/toJson doesn't seem to be used in thi
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
68 } | |
69 | |
70 class CompilationError extends CompilationFail { | |
71 final List<String> errors; | |
72 | |
73 CompilationError(this.errors); | |
74 | |
75 List toResponse() => [STATUS_ERROR, errorString]; | |
76 Map<String, dynamic> toJson() => { | |
77 "status": STATUS_ERROR, | |
78 "errors": errors, | |
79 }; | |
80 | |
81 String get errorString => errors.take(10).join('\n'); | |
82 String toString() => "CompilationError(${errorString})"; | |
83 } | |
84 | |
85 class CompilationCrash extends CompilationFail { | |
86 final String exception; | |
87 final String stack; | |
88 | |
89 CompilationCrash(this.exception, this.stack); | |
90 | |
91 List toResponse() => [STATUS_CRASH, errorString]; | |
92 Map<String, dynamic> toJson() => { | |
93 "status": STATUS_CRASH, | |
94 "exception": exception, | |
95 "stack": stack, | |
96 }; | |
97 | |
98 String get errorString => "${exception}\n${stack}"; | |
99 String toString() => "CompilationCrash(${errorString})"; | |
100 } | |
101 | |
102 Future<CompilationResult> parseScriptImpl(DartLoaderBatch batch_loader, | |
34 Uri fileName, String packageConfig, String sdkPath) async { | 103 Uri fileName, String packageConfig, String sdkPath) async { |
35 if (!FileSystemEntity.isFileSync(fileName.path)) { | 104 if (!FileSystemEntity.isFileSync(fileName.path)) { |
36 throw "Input file '${fileName.path}' does not exist."; | 105 throw "Input file '${fileName.path}' does not exist."; |
37 } | 106 } |
38 | 107 |
39 if (!FileSystemEntity.isDirectorySync(sdkPath)) { | 108 if (!FileSystemEntity.isDirectorySync(sdkPath)) { |
40 throw "Patched sdk directory not found at $sdkPath"; | 109 throw "Patched sdk directory not found at $sdkPath"; |
41 } | 110 } |
42 | 111 |
43 Target target = getTarget("vm", new TargetFlags(strongMode: false)); | 112 Target target = getTarget("vm", new TargetFlags(strongMode: false)); |
44 DartOptions dartOptions = new DartOptions( | 113 DartOptions dartOptions = new DartOptions( |
45 strongMode: false, | 114 strongMode: false, |
46 strongModeSdk: false, | 115 strongModeSdk: false, |
47 sdk: sdkPath, | 116 sdk: sdkPath, |
48 packagePath: packageConfig, | 117 packagePath: packageConfig, |
49 customUriMappings: const {}, | 118 customUriMappings: const {}, |
50 declaredVariables: const {}); | 119 declaredVariables: const {}); |
51 DartLoader loader = | 120 DartLoader loader = |
52 await new DartLoaderBatch().getLoader(new Repository(), dartOptions); | 121 await batch_loader.getLoader(new Repository(), dartOptions); |
53 var program = loader.loadProgram(fileName, target: target); | 122 var program = loader.loadProgram(fileName, target: target); |
54 | 123 |
55 var errors = loader.errors; | 124 var errors = loader.errors; |
56 if (errors.isNotEmpty) { | 125 if (errors.isNotEmpty) { |
57 throw loader.errors.first; | 126 return new CompilationError(loader.errors.toList()); |
58 } | 127 } |
59 | 128 |
60 // Link program into one file, cf. --link option in dartk. | 129 // Link program into one file, cf. --link option in dartk. |
61 target.transformProgram(program); | 130 target.transformProgram(program); |
62 | 131 |
63 // Write the program to a list of bytes and return it. | 132 // Write the program to a list of bytes and return it. |
64 var sink = new DataSink(); | 133 var sink = new DataSink(); |
65 new BinaryPrinter(sink).writeProgramFile(program); | 134 new BinaryPrinter(sink).writeProgramFile(program); |
66 return sink.builder.takeBytes(); | 135 return new CompilationOk(sink.builder.takeBytes()); |
136 } | |
137 | |
138 Future<CompilationResult> parseScript(DartLoaderBatch loader, Uri fileName, | |
139 String packageConfig, String sdkPath) async { | |
140 try { | |
141 return await parseScriptImpl(loader, fileName, packageConfig, sdkPath); | |
142 } catch (err, stack) { | |
143 return new CompilationCrash(err.toString(), stack.toString()); | |
144 } | |
145 } | |
146 | |
147 Future _processLoadRequestImpl(String inputFileUrl) async { | |
148 Uri scriptUri = Uri.parse(inputFileUrl); | |
149 | |
150 // Because we serve both Loader and bootstrapping requests we need to | |
151 // duplicate the logic from _resolveScriptUri(...) here and attempt to | |
152 // resolve schemaless uris using current working directory. | |
153 if (scriptUri.scheme == '') { | |
154 // Script does not have a scheme, assume that it is a path, | |
155 // resolve it against the working directory. | |
156 scriptUri = Directory.current.uri.resolveUri(scriptUri); | |
157 } | |
158 | |
159 if (scriptUri.scheme != 'file') { | |
160 // TODO: reuse loader code to support other schemes. | |
161 throw "Expected 'file' scheme for a script uri: got ${scriptUri.scheme}"; | |
162 } | |
163 | |
164 Uri packagesUri = (Platform.packageConfig != null) | |
165 ? Uri.parse(Platform.packageConfig) | |
166 : await _findPackagesFile(scriptUri); | |
167 if (packagesUri == null) { | |
168 throw "Could not find .packages"; | |
169 } | |
170 | |
171 Uri patchedSdk = | |
kustermann
2017/01/30 12:14:24
final :)
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
172 Uri.parse(Platform.resolvedExecutable).resolve("patched_sdk"); | |
173 | |
174 if (verbose) { | |
175 print("""DFE: Requesting compilation { | |
176 scriptUri: ${scriptUri} | |
177 packagesUri: ${packagesUri} | |
178 patchedSdk: ${patchedSdk} | |
179 }"""); | |
180 } | |
181 | |
182 CompilationResult result; | |
kustermann
2017/01/30 12:14:23
unused variable
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
183 return await parseScript( | |
184 new DartLoaderBatch(), scriptUri, packagesUri.path, patchedSdk.path); | |
67 } | 185 } |
68 | 186 |
69 Future _processLoadRequest(request) async { | 187 Future _processLoadRequest(request) async { |
kustermann
2017/01/30 12:14:23
Maybe add a comment describing where the other end
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
70 if (verbose) { | 188 if (verbose) { |
71 print("FROM DART KERNEL: load request: $request"); | 189 print("DFE: request: $request"); |
72 print("FROM DART KERNEL: package: ${Platform.packageConfig}"); | 190 print("DFE: Platform.packageConfig: ${Platform.packageConfig}"); |
73 print("FROM DART KERNEL: exec: ${Platform.resolvedExecutable}"); | 191 print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}"); |
74 } | 192 } |
75 | 193 |
76 int tag = request[0]; | 194 final int tag = request[0]; |
77 SendPort port = request[1]; | 195 final SendPort port = request[1]; |
78 String inputFileUrl = request[2]; | 196 final String inputFileUrl = request[2]; |
79 Uri scriptUri = Uri.parse(inputFileUrl); | |
80 Uri packagesUri = Uri.parse(Platform.packageConfig ?? ".packages"); | |
81 Uri patchedSdk = | |
82 Uri.parse(Platform.resolvedExecutable).resolve("patched_sdk"); | |
83 | 197 |
84 var result; | 198 var result; |
85 try { | 199 try { |
86 result = await parseScript(scriptUri, packagesUri.path, patchedSdk.path); | 200 result = await _processLoadRequestImpl(inputFileUrl); |
87 } catch (error) { | 201 } catch (error, stack) { |
88 tag = -tag; // Mark reply as an exception. | 202 result = new CompilationCrash(error.toString(), stack.toString()); |
89 result = error.toString(); | |
90 } | 203 } |
91 | 204 |
92 port.send([tag, inputFileUrl, inputFileUrl, null, result]); | 205 if (verbose) { |
206 print("DFE:> ${result}"); | |
207 } | |
208 | |
209 final isBootstrapRequest = tag == null; | |
210 if (isBootstrapRequest) { | |
211 port.send(result.toResponse()); | |
212 } else { | |
213 if (result is CompilationOk) { | |
214 port.send([tag, inputFileUrl, inputFileUrl, null, result]); | |
215 } else { | |
216 port.send([-tag, inputFileUrl, inputFileUrl, null, result.errorString]); | |
kustermann
2017/01/30 12:14:23
Also add a pointer here where in c++ this is recei
Vyacheslav Egorov (Google)
2017/01/30 19:34:13
Done.
| |
217 } | |
218 } | |
93 } | 219 } |
94 | 220 |
95 main() => new RawReceivePort()..handler = _processLoadRequest; | 221 main() => new RawReceivePort()..handler = _processLoadRequest; |
222 | |
223 // This duplicates functionality from the Loader which we can't easily | |
224 // access from here. | |
225 Uri _findPackagesFile(Uri base) async { | |
226 var dir = new File.fromUri(base).parent; | |
227 while (true) { | |
228 final packagesFile = dir.uri.resolve(".packages"); | |
229 if (await new File.fromUri(packagesFile).exists()) { | |
230 return packagesFile; | |
231 } | |
232 if (dir.parent == dir) { | |
233 break; | |
234 } | |
235 dir = dir.parent; | |
236 } | |
237 return null; | |
238 } | |
OLD | NEW |