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' show Future; | 23 import 'dart:async' show Future; |
24 import 'dart:convert' show JSON; | |
24 import 'dart:io' show Platform hide FileSystemEntity; | 25 import 'dart:io' show Platform hide FileSystemEntity; |
25 import 'dart:isolate'; | 26 import 'dart:isolate'; |
26 import 'dart:typed_data' show Uint8List; | 27 import 'dart:typed_data' show Uint8List; |
27 | 28 |
28 import 'package:front_end/file_system.dart'; | 29 import 'package:front_end/file_system.dart'; |
29 import 'package:front_end/front_end.dart'; | 30 import 'package:front_end/front_end.dart'; |
31 import 'package:front_end/incremental_kernel_generator.dart'; | |
30 import 'package:front_end/memory_file_system.dart'; | 32 import 'package:front_end/memory_file_system.dart'; |
31 import 'package:front_end/physical_file_system.dart'; | 33 import 'package:front_end/physical_file_system.dart'; |
32 import 'package:front_end/src/fasta/kernel/utils.dart'; | 34 import 'package:front_end/src/fasta/kernel/utils.dart'; |
33 import 'package:front_end/src/testing/hybrid_file_system.dart'; | 35 import 'package:front_end/src/testing/hybrid_file_system.dart'; |
34 import 'package:kernel/kernel.dart' show Program; | 36 import 'package:kernel/kernel.dart' show Program; |
35 import 'package:kernel/target/targets.dart' show TargetFlags; | 37 import 'package:kernel/target/targets.dart' show TargetFlags; |
36 import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget; | 38 import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget; |
37 | 39 |
38 const bool verbose = const bool.fromEnvironment('DFE_VERBOSE'); | 40 const bool verbose = const bool.fromEnvironment('DFE_VERBOSE'); |
39 const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE'); | 41 const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE'); |
40 | 42 |
43 abstract class Compiler { | |
44 final FileSystem fileSystem; | |
45 final List<String> errors = new List<String>(); | |
46 | |
47 CompilerOptions options; | |
48 | |
49 Compiler(this.fileSystem) { | |
50 Uri packagesUri = (Platform.packageConfig != null) | |
51 ? Uri.parse(Platform.packageConfig) | |
52 : null; | |
53 | |
54 Uri sdkSummary = Uri.base | |
55 .resolveUri(new Uri.file(Platform.resolvedExecutable)) | |
56 .resolveUri(new Uri.directory("patched_sdk")) | |
57 // TODO(sigmund): use outline.dill when the mixin transformer is | |
58 // modular. | |
59 .resolve('platform.dill'); | |
60 | |
61 if (verbose) { | |
62 print("DFE: Platform.packageConfig: ${Platform.packageConfig}"); | |
63 print("DFE: packagesUri: ${packagesUri}"); | |
64 print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}"); | |
65 print("DFE: sdkSummary: ${sdkSummary}"); | |
66 } | |
67 | |
68 options = new CompilerOptions() | |
69 ..strongMode = strongMode | |
70 ..fileSystem = fileSystem | |
71 ..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode)) | |
72 ..packagesFileUri = packagesUri | |
73 ..sdkSummary = sdkSummary | |
74 ..verbose = verbose | |
75 ..throwOnErrors = false | |
76 ..reportMessages = true | |
77 ..onError = (CompilationMessage e) { | |
78 if (e.severity == Severity.error) { | |
79 // TODO(sigmund): support emitting code with errors as long as they | |
80 // are handled in the generated code (issue #30194). | |
81 errors.add(e.message); | |
82 } | |
83 }; | |
84 } | |
85 | |
86 Future<Program> compile(Uri script); | |
87 } | |
88 | |
89 class IncrementalCompiler extends Compiler { | |
90 IncrementalKernelGenerator generator; | |
91 | |
92 IncrementalCompiler(FileSystem fileSystem) : super(fileSystem); | |
93 | |
94 @override | |
95 Future<Program> compile(Uri script) async { | |
96 if (generator == null) { | |
97 generator = await IncrementalKernelGenerator.newInstance(options, script); | |
98 } | |
99 DeltaProgram deltaProgram = await generator.computeDelta(); | |
100 return deltaProgram.newProgram; | |
101 } | |
102 | |
103 void invalidate(Uri uri) { | |
104 generator.invalidate(uri); | |
105 } | |
106 } | |
107 | |
108 class SingleShotCompiler extends Compiler { | |
109 final bool requireMain; | |
110 | |
111 SingleShotCompiler(FileSystem fileSystem, this.requireMain) | |
112 : super(fileSystem); | |
113 | |
114 @override | |
115 Future<Program> compile(Uri script) async { | |
116 return requireMain | |
117 ? kernelForProgram(script, options) | |
118 : kernelForBuildUnit([script], options..chaseDependencies = true); | |
119 } | |
120 } | |
121 | |
122 final Map<int, Compiler> isolateCompilers = new Map<int, Compiler>(); | |
123 | |
124 Future<Compiler> lookupOrBuildNewIncrementalCompiler( | |
125 int isolateId, List sourceFiles) async { | |
126 IncrementalCompiler compiler; | |
127 if (isolateCompilers.containsKey(isolateId)) { | |
128 compiler = isolateCompilers[isolateId]; | |
129 final HybridFileSystem fileSystem = compiler.fileSystem; | |
130 if (sourceFiles != null) { | |
131 for (int i = 0; i < sourceFiles.length ~/ 2; i++) { | |
132 Uri uri = Uri.parse(sourceFiles[i * 2]); | |
133 fileSystem.memory | |
134 .entityForUri(uri) | |
135 .writeAsBytesSync(sourceFiles[i * 2 + 1]); | |
136 compiler.invalidate(uri); | |
137 } | |
138 } | |
139 } else { | |
140 final FileSystem fileSystem = sourceFiles == null | |
141 ? PhysicalFileSystem.instance | |
142 : _buildFileSystem(sourceFiles); | |
143 | |
144 // TODO(aam): IncrementalCompiler instance created below have to be | |
145 // destroyed when corresponding isolate is shut down. To achieve that kernel | |
146 // isolate needs to receive a message indicating that particular | |
147 // isolate was shut down. Message should be handled here in this script. | |
148 compiler = new IncrementalCompiler(fs, librariesUri, librariesJson); | |
Siggi Cherem (dart-lang)
2017/08/09 15:57:58
delete this line?
aam
2017/08/09 16:17:04
Oops, done. Thanks!
| |
149 compiler = new IncrementalCompiler(fileSystem); | |
150 isolateCompilers[isolateId] = compiler; | |
151 } | |
152 return compiler; | |
153 } | |
154 | |
41 // Process a request from the runtime. See KernelIsolate::CompileToKernel in | 155 // Process a request from the runtime. See KernelIsolate::CompileToKernel in |
42 // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc. | 156 // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc. |
43 Future _processLoadRequest(request) async { | 157 Future _processLoadRequest(request) async { |
44 if (verbose) print("DFE: request: $request"); | 158 if (verbose) print("DFE: request: $request"); |
45 | 159 |
46 int tag = request[0]; | 160 int tag = request[0]; |
47 final SendPort port = request[1]; | 161 final SendPort port = request[1]; |
48 final String inputFileUri = request[2]; | 162 final String inputFileUri = request[2]; |
49 final Uri script = Uri.base.resolve(inputFileUri); | 163 final Uri script = Uri.base.resolve(inputFileUri); |
164 final bool incremental = request[3]; | |
50 | 165 |
51 FileSystem fileSystem = PhysicalFileSystem.instance; | 166 final List sourceFiles = request.length > 5 ? request[5] : null; |
52 bool requireMain = true; | |
53 | 167 |
54 if (request.length > 3) { | 168 Compiler compiler; |
55 fileSystem = _buildFileSystem(request[3]); | 169 // TODO(aam): There should be no need to have an option to choose |
56 requireMain = false; | 170 // one compiler or another. We should always use an incremental |
171 // compiler as its functionality is a super set of the other one. We need to | |
172 // watch the performance though. | |
173 if (incremental) { | |
174 final int isolateId = request[4]; | |
175 compiler = | |
176 await lookupOrBuildNewIncrementalCompiler(isolateId, sourceFiles); | |
177 } else { | |
178 final FileSystem fileSystem = sourceFiles == null | |
179 ? PhysicalFileSystem.instance | |
180 : _buildFileSystem(sourceFiles); | |
181 compiler = new SingleShotCompiler( | |
182 fileSystem, sourceFiles == null /* requireMain */); | |
57 } | 183 } |
58 | 184 |
59 Uri packagesUri = (Platform.packageConfig != null) | |
60 ? Uri.parse(Platform.packageConfig) | |
61 : null; | |
62 | |
63 Uri sdkSummary = Uri.base | |
64 .resolveUri(new Uri.file(Platform.resolvedExecutable)) | |
65 .resolveUri(new Uri.directory("patched_sdk")) | |
66 // TODO(sigmund): use outline.dill when the mixin transformer is modular. | |
67 .resolve('platform.dill'); | |
68 | |
69 if (verbose) { | |
70 print("DFE: scriptUri: ${script}"); | |
71 print("DFE: Platform.packageConfig: ${Platform.packageConfig}"); | |
72 print("DFE: packagesUri: ${packagesUri}"); | |
73 print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}"); | |
74 print("DFE: sdkSummary: ${sdkSummary}"); | |
75 } | |
76 | |
77 var errors = <String>[]; | |
78 var options = new CompilerOptions() | |
79 ..strongMode = strongMode | |
80 ..fileSystem = fileSystem | |
81 ..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode)) | |
82 ..packagesFileUri = packagesUri | |
83 ..sdkSummary = sdkSummary | |
84 ..verbose = verbose | |
85 ..throwOnErrors = false | |
86 ..reportMessages = true | |
87 ..onError = (CompilationMessage e) { | |
88 if (e.severity == Severity.error) { | |
89 // TODO(sigmund): support emitting code with errors as long as they are | |
90 // handled in the generated code (issue #30194). | |
91 errors.add(e.message); | |
92 } | |
93 }; | |
94 | |
95 CompilationResult result; | 185 CompilationResult result; |
96 try { | 186 try { |
97 Program program = requireMain | 187 if (verbose) { |
98 ? await kernelForProgram(script, options) | 188 print("DFE: scriptUri: ${script}"); |
99 : await kernelForBuildUnit([script], options..chaseDependencies = true); | 189 } |
100 | 190 |
101 if (errors.isNotEmpty) { | 191 Program program = await compiler.compile(script); |
192 | |
193 if (compiler.errors.isNotEmpty) { | |
102 // TODO(sigmund): the compiler prints errors to the console, so we | 194 // TODO(sigmund): the compiler prints errors to the console, so we |
103 // shouldn't print those messages again here. | 195 // shouldn't print those messages again here. |
104 result = new CompilationResult.errors(errors); | 196 result = new CompilationResult.errors(compiler.errors); |
105 } else { | 197 } else { |
106 // We serialize the program excluding platform.dill because the VM has | 198 // We serialize the program excluding platform.dill because the VM has |
107 // these sources built-in. Everything loaded as a summary in | 199 // these sources built-in. Everything loaded as a summary in |
108 // [kernelForProgram] is marked `external`, so we can use that bit to | 200 // [kernelForProgram] is marked `external`, so we can use that bit to |
109 // decide what to excluce. | 201 // decide what to exclude. |
110 // TODO(sigmund): remove the following line (Issue #30111) | 202 // TODO(sigmund): remove the following line (Issue #30111) |
111 program.libraries.forEach((e) => e.isExternal = false); | 203 program.libraries.forEach((e) => e.isExternal = false); |
112 result = new CompilationResult.ok( | 204 result = new CompilationResult.ok( |
113 serializeProgram(program, filter: (lib) => !lib.isExternal)); | 205 serializeProgram(program, filter: (lib) => !lib.isExternal)); |
114 } | 206 } |
115 } catch (error, stack) { | 207 } catch (error, stack) { |
116 result = new CompilationResult.crash(error, stack); | 208 result = new CompilationResult.crash(error, stack); |
117 } | 209 } |
118 | 210 |
119 if (verbose) print("DFE:> ${result}"); | 211 if (verbose) print("DFE:> ${result}"); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 if (response[0] == tag) { | 251 if (response[0] == tag) { |
160 // Success. | 252 // Success. |
161 responsePort.close(); | 253 responsePort.close(); |
162 } else if (response[0] == -tag) { | 254 } else if (response[0] == -tag) { |
163 // Compilation error. | 255 // Compilation error. |
164 throw response[4]; | 256 throw response[4]; |
165 } else { | 257 } else { |
166 throw "Unexpected response: $response"; | 258 throw "Unexpected response: $response"; |
167 } | 259 } |
168 }; | 260 }; |
169 var request = [tag, responsePort.sendPort, scriptUri]; | 261 var request = [ |
262 tag, | |
263 responsePort.sendPort, | |
264 scriptUri, | |
265 1 /* isolateId chosen randomly */, | |
266 false /* incremental */ | |
267 ]; | |
170 _processLoadRequest(request); | 268 _processLoadRequest(request); |
171 } | 269 } |
172 | 270 |
173 main([args]) { | 271 main([args]) { |
174 if (args?.length == 2 && args[0] == '--train') { | 272 if (args?.length == 2 && args[0] == '--train') { |
175 // This entry point is used when creating an app snapshot. The argument | 273 // This entry point is used when creating an app snapshot. The argument |
176 // provides a script to compile to warm-up generated code. | 274 // provides a script to compile to warm-up generated code. |
177 train(args[1]); | 275 train(args[1]); |
178 } else { | 276 } else { |
179 // Entry point for the Kernel isolate. | 277 // Entry point for the Kernel isolate. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 _CompilationCrash(this.exception, this.stack); | 356 _CompilationCrash(this.exception, this.stack); |
259 | 357 |
260 @override | 358 @override |
261 Status get status => Status.crash; | 359 Status get status => Status.crash; |
262 | 360 |
263 @override | 361 @override |
264 String get errorString => "${exception}\n${stack}"; | 362 String get errorString => "${exception}\n${stack}"; |
265 | 363 |
266 String toString() => "_CompilationCrash(${errorString})"; | 364 String toString() => "_CompilationCrash(${errorString})"; |
267 } | 365 } |
OLD | NEW |