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 library fasta.kernel_target; | 5 library fasta.kernel_target; |
6 | 6 |
7 import 'dart:async' show Future; | 7 import 'dart:async' show Future; |
8 | 8 |
9 import 'dart:io' show File; | 9 import 'dart:io' show File; |
10 | 10 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 KernelNamedTypeBuilder, | 76 KernelNamedTypeBuilder, |
77 KernelProcedureBuilder, | 77 KernelProcedureBuilder, |
78 LibraryBuilder, | 78 LibraryBuilder, |
79 MemberBuilder, | 79 MemberBuilder, |
80 NamedTypeBuilder, | 80 NamedTypeBuilder, |
81 TypeBuilder, | 81 TypeBuilder, |
82 TypeDeclarationBuilder, | 82 TypeDeclarationBuilder, |
83 TypeVariableBuilder; | 83 TypeVariableBuilder; |
84 | 84 |
85 import 'verifier.dart' show verifyProgram; | 85 import 'verifier.dart' show verifyProgram; |
86 import 'kernel_outline_shaker.dart' | |
87 show trimProgram, RetainedDataBuilder, RootsMarker; | |
88 | 86 |
89 class KernelTarget extends TargetImplementation { | 87 class KernelTarget extends TargetImplementation { |
90 /// The [FileSystem] which should be used to access files. | 88 /// The [FileSystem] which should be used to access files. |
91 final FileSystem fileSystem; | 89 final FileSystem fileSystem; |
92 | 90 |
93 final bool strongMode; | 91 final bool strongMode; |
94 | 92 |
95 final DillTarget dillTarget; | 93 final DillTarget dillTarget; |
96 | 94 |
97 /// Shared with [CompilerContext]. | 95 /// Shared with [CompilerContext]. |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 cls.implementedTypes.clear(); | 207 cls.implementedTypes.clear(); |
210 cls.supertype = null; | 208 cls.supertype = null; |
211 cls.mixedInType = null; | 209 cls.mixedInType = null; |
212 builder.supertype = new KernelNamedTypeBuilder("Object", null, | 210 builder.supertype = new KernelNamedTypeBuilder("Object", null, |
213 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) | 211 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) |
214 ..builder = objectClassBuilder; | 212 ..builder = objectClassBuilder; |
215 builder.interfaces = null; | 213 builder.interfaces = null; |
216 builder.mixedInType = null; | 214 builder.mixedInType = null; |
217 } | 215 } |
218 | 216 |
219 void handleInputError(InputError error, | 217 void handleInputError(InputError error, {bool isFullProgram}) { |
220 {bool isFullProgram, bool trimDependencies: false}) { | |
221 if (error != null) { | 218 if (error != null) { |
222 String message = error.format(); | 219 String message = error.format(); |
223 print(message); | 220 print(message); |
224 errors.add(message); | 221 errors.add(message); |
225 } | 222 } |
226 _program = erroneousProgram(isFullProgram); | 223 _program = erroneousProgram(isFullProgram); |
227 if (trimDependencies) { | |
228 trimDependenciesInProgram(_program, dillTarget.loader.libraries); | |
229 } | |
230 } | 224 } |
231 | 225 |
232 @override | 226 @override |
233 Future<Program> buildOutlines({CanonicalName nameRoot}) async { | 227 Future<Program> buildOutlines({CanonicalName nameRoot}) async { |
234 if (loader.first == null) return null; | 228 if (loader.first == null) return null; |
235 try { | 229 try { |
236 loader.createTypeInferenceEngine(); | 230 loader.createTypeInferenceEngine(); |
237 await loader.buildOutlines(); | 231 await loader.buildOutlines(); |
238 loader.coreLibrary | 232 loader.coreLibrary |
239 .becomeCoreLibrary(const DynamicType(), const VoidType()); | 233 .becomeCoreLibrary(const DynamicType(), const VoidType()); |
(...skipping 15 matching lines...) Expand all Loading... |
255 loader.prepareInitializerInference(); | 249 loader.prepareInitializerInference(); |
256 loader.performInitializerInference(); | 250 loader.performInitializerInference(); |
257 } on InputError catch (e) { | 251 } on InputError catch (e) { |
258 handleInputError(e, isFullProgram: false); | 252 handleInputError(e, isFullProgram: false); |
259 } catch (e, s) { | 253 } catch (e, s) { |
260 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 254 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
261 } | 255 } |
262 return _program; | 256 return _program; |
263 } | 257 } |
264 | 258 |
265 /// Build the kernel representation of the program loaded by this target. The | |
266 /// program will contain full bodies for the code loaded from sources, and | |
267 /// only references to the code loaded by the [DillTarget], which may or may | |
268 /// not include method bodies (depending on what was loaded into that target, | |
269 /// an outline or a full kernel program). | |
270 /// | |
271 /// When [trimDependencies] is true, this also runs a tree-shaker that deletes | |
272 /// anything from the [DillTarget] that is not needed for the source program, | |
273 /// this includes function bodies and types that are not reachable. | |
274 /// | |
275 /// If [verify], run the default kernel verification on the resulting program. | |
276 @override | 259 @override |
277 Future<Program> buildProgram( | 260 Future<Program> buildProgram({bool verify: false}) async { |
278 {bool verify: false, bool trimDependencies: false}) async { | |
279 if (loader.first == null) return null; | 261 if (loader.first == null) return null; |
280 if (errors.isNotEmpty) { | 262 if (errors.isNotEmpty) { |
281 handleInputError(null, | 263 handleInputError(null, isFullProgram: true); |
282 isFullProgram: true, trimDependencies: trimDependencies); | |
283 return _program; | 264 return _program; |
284 } | 265 } |
285 try { | 266 try { |
286 await loader.buildBodies(); | 267 await loader.buildBodies(); |
287 _program = link(new List<Library>.from(loader.libraries), | |
288 trimDependencies: trimDependencies); | |
289 loader.finishStaticInvocations(); | 268 loader.finishStaticInvocations(); |
290 finishAllConstructors(); | 269 finishAllConstructors(); |
291 loader.finishNativeMethods(); | 270 loader.finishNativeMethods(); |
292 runBuildTransformations(); | 271 runBuildTransformations(); |
293 | 272 |
294 if (verify) this.verify(); | 273 if (verify) this.verify(); |
295 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); | 274 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); |
296 if (errors.isNotEmpty) { | 275 if (errors.isNotEmpty) { |
297 handleInputError(null, | 276 handleInputError(null, isFullProgram: true); |
298 isFullProgram: true, trimDependencies: trimDependencies); | |
299 } | 277 } |
300 } on InputError catch (e) { | 278 } on InputError catch (e) { |
301 handleInputError(e, | 279 handleInputError(e, isFullProgram: true); |
302 isFullProgram: true, trimDependencies: trimDependencies); | |
303 } catch (e, s) { | 280 } catch (e, s) { |
304 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 281 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
305 } | 282 } |
306 return _program; | 283 return _program; |
307 } | 284 } |
308 | 285 |
309 Future writeDepsFile(Uri output, Uri depsFile, | 286 Future writeDepsFile(Uri output, Uri depsFile, |
310 {Iterable<Uri> extraDependencies}) async { | 287 {Iterable<Uri> extraDependencies}) async { |
311 String toRelativeFilePath(Uri uri) { | 288 String toRelativeFilePath(Uri uri) { |
312 // Ninja expects to find file names relative to the current working | 289 // Ninja expects to find file names relative to the current working |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 library.addBuilder(mainBuilder.name, mainBuilder, -1); | 343 library.addBuilder(mainBuilder.name, mainBuilder, -1); |
367 mainBuilder.body = new ExpressionStatement( | 344 mainBuilder.body = new ExpressionStatement( |
368 new Throw(new StringLiteral("${errors.join('\n')}"))); | 345 new Throw(new StringLiteral("${errors.join('\n')}"))); |
369 } | 346 } |
370 library.build(loader.coreLibrary); | 347 library.build(loader.coreLibrary); |
371 return link(<Library>[library.library]); | 348 return link(<Library>[library.library]); |
372 } | 349 } |
373 | 350 |
374 /// Creates a program by combining [libraries] with the libraries of | 351 /// Creates a program by combining [libraries] with the libraries of |
375 /// `dillTarget.loader.program`. | 352 /// `dillTarget.loader.program`. |
376 Program link(List<Library> libraries, | 353 Program link(List<Library> libraries, {CanonicalName nameRoot}) { |
377 {CanonicalName nameRoot, bool trimDependencies: false}) { | |
378 Map<String, Source> uriToSource = | 354 Map<String, Source> uriToSource = |
379 new Map<String, Source>.from(this.uriToSource); | 355 new Map<String, Source>.from(this.uriToSource); |
380 | 356 |
381 List<Library> extraLibraries = dillTarget.loader.libraries; | 357 libraries.addAll(dillTarget.loader.libraries); |
382 libraries.addAll(extraLibraries); | |
383 // TODO(scheglov) Should we also somehow update `uriToSource`? | 358 // TODO(scheglov) Should we also somehow update `uriToSource`? |
384 // uriToSource.addAll(binary.uriToSource); | 359 // uriToSource.addAll(binary.uriToSource); |
385 | 360 |
386 // TODO(ahe): Remove this line. Kernel seems to generate a default line map | 361 // TODO(ahe): Remove this line. Kernel seems to generate a default line map |
387 // that used when there's no fileUri on an element. Instead, ensure all | 362 // that used when there's no fileUri on an element. Instead, ensure all |
388 // elements have a fileUri. | 363 // elements have a fileUri. |
389 uriToSource[""] = new Source(<int>[0], const <int>[]); | 364 uriToSource[""] = new Source(<int>[0], const <int>[]); |
390 Program program = new Program( | 365 Program program = new Program( |
391 nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource); | 366 nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource); |
392 if (loader.first != null) { | 367 if (loader.first != null) { |
393 // TODO(sigmund): do only for full program | |
394 Builder builder = loader.first.lookup("main", -1, null); | 368 Builder builder = loader.first.lookup("main", -1, null); |
395 if (builder is KernelProcedureBuilder) { | 369 if (builder is KernelProcedureBuilder) { |
396 program.mainMethod = builder.procedure; | 370 program.mainMethod = builder.procedure; |
397 } | 371 } |
398 } | 372 } |
399 if (trimDependencies) { | 373 if (errors.isEmpty || dillTarget.isLoaded) { |
400 trimDependenciesInProgram(program, extraLibraries); | 374 runLinkTransformations(program); |
401 } | 375 } |
402 | |
403 ticker.logMs("Linked program"); | 376 ticker.logMs("Linked program"); |
404 return program; | 377 return program; |
405 } | 378 } |
406 | 379 |
407 void installDefaultSupertypes() { | 380 void installDefaultSupertypes() { |
408 Class objectClass = this.objectClass; | 381 Class objectClass = this.objectClass; |
409 loader.builders.forEach((Uri uri, LibraryBuilder library) { | 382 loader.builders.forEach((Uri uri, LibraryBuilder library) { |
410 library.forEach((String name, Builder builder) { | 383 library.forEach((String name, Builder builder) { |
411 if (builder is SourceClassBuilder) { | 384 if (builder is SourceClassBuilder) { |
412 Class cls = builder.target; | 385 Class cls = builder.target; |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 }); | 631 }); |
659 } | 632 } |
660 | 633 |
661 /// Run all transformations that are needed when building a program for the | 634 /// Run all transformations that are needed when building a program for the |
662 /// first time. | 635 /// first time. |
663 void runBuildTransformations() { | 636 void runBuildTransformations() { |
664 transformMixinApplications(); | 637 transformMixinApplications(); |
665 otherTransformations(); | 638 otherTransformations(); |
666 } | 639 } |
667 | 640 |
| 641 /// Run all transformations that are needed when linking a program. |
| 642 void runLinkTransformations(Program program) {} |
| 643 |
668 void transformMixinApplications() { | 644 void transformMixinApplications() { |
669 new MixinFullResolution().transform(_program); | 645 new MixinFullResolution().transform(_program); |
670 ticker.logMs("Transformed mixin applications"); | 646 ticker.logMs("Transformed mixin applications"); |
671 } | 647 } |
672 | 648 |
673 void otherTransformations() { | 649 void otherTransformations() { |
674 // TODO(ahe): Don't generate type variables in the first place. | 650 // TODO(ahe): Don't generate type variables in the first place. |
675 if (!strongMode) { | 651 if (!strongMode) { |
676 _program.accept(new Erasure()); | 652 _program.accept(new Erasure()); |
677 ticker.logMs("Erased type variables in generic methods"); | 653 ticker.logMs("Erased type variables in generic methods"); |
(...skipping 20 matching lines...) Expand all Loading... |
698 } | 674 } |
699 for (Constructor constructor in superclass.constructors) { | 675 for (Constructor constructor in superclass.constructors) { |
700 if (constructor.name.name.isEmpty) { | 676 if (constructor.name.name.isEmpty) { |
701 return constructor.function.requiredParameterCount == 0 | 677 return constructor.function.requiredParameterCount == 0 |
702 ? constructor | 678 ? constructor |
703 : null; | 679 : null; |
704 } | 680 } |
705 } | 681 } |
706 return null; | 682 return null; |
707 } | 683 } |
708 | |
709 /// Tree-shakes most code from [librariesToShake] by visiting all other | |
710 /// libraries in [program] and marking the APIs from [librariesToShake] that are | |
711 /// in use. | |
712 trimDependenciesInProgram(Program program, List<Library> librariesToShake) { | |
713 var toShake = librariesToShake.map((lib) => lib.importUri).toSet(); | |
714 var isIncluded = (Uri uri) => !toShake.contains(uri); | |
715 var data = new RetainedDataBuilder(); | |
716 // TODO(sigmund): replace this step with data that is directly computed from | |
717 // the builders: we should know the tree-shaking roots without having to do a | |
718 // second visit over the tree. | |
719 new RootsMarker(data).run(program, isIncluded); | |
720 trimProgram(program, data, isIncluded); | |
721 } | |
OLD | NEW |