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; | |
86 | 88 |
87 class KernelTarget extends TargetImplementation { | 89 class KernelTarget extends TargetImplementation { |
88 /// The [FileSystem] which should be used to access files. | 90 /// The [FileSystem] which should be used to access files. |
89 final FileSystem fileSystem; | 91 final FileSystem fileSystem; |
90 | 92 |
91 final bool strongMode; | 93 final bool strongMode; |
92 | 94 |
93 final DillTarget dillTarget; | 95 final DillTarget dillTarget; |
94 | 96 |
95 /// Shared with [CompilerContext]. | 97 /// Shared with [CompilerContext]. |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
207 cls.implementedTypes.clear(); | 209 cls.implementedTypes.clear(); |
208 cls.supertype = null; | 210 cls.supertype = null; |
209 cls.mixedInType = null; | 211 cls.mixedInType = null; |
210 builder.supertype = new KernelNamedTypeBuilder("Object", null, | 212 builder.supertype = new KernelNamedTypeBuilder("Object", null, |
211 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) | 213 builder.charOffset, builder.fileUri ?? Uri.parse(cls.fileUri)) |
212 ..builder = objectClassBuilder; | 214 ..builder = objectClassBuilder; |
213 builder.interfaces = null; | 215 builder.interfaces = null; |
214 builder.mixedInType = null; | 216 builder.mixedInType = null; |
215 } | 217 } |
216 | 218 |
217 void handleInputError(InputError error, {bool isFullProgram}) { | 219 void handleInputError(InputError error, |
220 {bool isFullProgram, bool trimDependencies: false}) { | |
218 if (error != null) { | 221 if (error != null) { |
219 String message = error.format(); | 222 String message = error.format(); |
220 print(message); | 223 print(message); |
221 errors.add(message); | 224 errors.add(message); |
222 } | 225 } |
223 _program = erroneousProgram(isFullProgram); | 226 _program = erroneousProgram(isFullProgram); |
224 } | 227 } |
225 | 228 |
226 @override | 229 @override |
227 Future<Program> buildOutlines({CanonicalName nameRoot}) async { | 230 Future<Program> buildOutlines({CanonicalName nameRoot}) async { |
(...skipping 21 matching lines...) Expand all Loading... | |
249 loader.prepareInitializerInference(); | 252 loader.prepareInitializerInference(); |
250 loader.performInitializerInference(); | 253 loader.performInitializerInference(); |
251 } on InputError catch (e) { | 254 } on InputError catch (e) { |
252 handleInputError(e, isFullProgram: false); | 255 handleInputError(e, isFullProgram: false); |
253 } catch (e, s) { | 256 } catch (e, s) { |
254 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 257 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
255 } | 258 } |
256 return _program; | 259 return _program; |
257 } | 260 } |
258 | 261 |
262 /// Build the kernel representation of the program loaded by this target. The | |
263 /// program will contain full bodies for the code loaded from sources, and | |
264 /// only references to the code loaded by the [DillTarget], which may or may | |
265 /// not include method bodies (depending on what was loaded into that target, | |
266 /// an outline or a full kernel program). | |
267 /// | |
268 /// When [trimDependencies] is true, this also runs a tree-shaker that deletes | |
ahe
2017/05/22 11:49:04
This documentation states what is currently going
Siggi Cherem (dart-lang)
2017/05/22 23:15:48
added a note about it.
| |
269 /// anything from the [DillTarget] that is not needed for the source program, | |
270 /// this includes function bodies and types that are not reachable. | |
271 /// | |
272 /// If [verify], run the default kernel verification on the resulting program. | |
259 @override | 273 @override |
260 Future<Program> buildProgram({bool verify: false}) async { | 274 Future<Program> buildProgram( |
275 {bool verify: false, bool trimDependencies: false}) async { | |
261 if (loader.first == null) return null; | 276 if (loader.first == null) return null; |
262 if (errors.isNotEmpty) { | 277 if (errors.isNotEmpty) { |
263 handleInputError(null, isFullProgram: true); | 278 handleInputError(null, |
279 isFullProgram: true, trimDependencies: trimDependencies); | |
280 if (trimDependencies) trimDependenciesInProgram(); | |
264 return _program; | 281 return _program; |
265 } | 282 } |
283 | |
266 try { | 284 try { |
267 await loader.buildBodies(); | 285 await loader.buildBodies(); |
268 loader.finishStaticInvocations(); | 286 loader.finishStaticInvocations(); |
269 finishAllConstructors(); | 287 finishAllConstructors(); |
270 loader.finishNativeMethods(); | 288 loader.finishNativeMethods(); |
271 runBuildTransformations(); | 289 runBuildTransformations(); |
272 | 290 |
273 if (verify) this.verify(); | 291 if (verify) this.verify(); |
274 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); | 292 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); |
275 if (errors.isNotEmpty) { | 293 if (errors.isNotEmpty) { |
276 handleInputError(null, isFullProgram: true); | 294 handleInputError(null, |
295 isFullProgram: true, trimDependencies: trimDependencies); | |
277 } | 296 } |
278 } on InputError catch (e) { | 297 } on InputError catch (e) { |
279 handleInputError(e, isFullProgram: true); | 298 handleInputError(e, |
299 isFullProgram: true, trimDependencies: trimDependencies); | |
280 } catch (e, s) { | 300 } catch (e, s) { |
281 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 301 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
282 } | 302 } |
303 if (trimDependencies) trimDependenciesInProgram(); | |
283 return _program; | 304 return _program; |
284 } | 305 } |
285 | 306 |
286 Future writeDepsFile(Uri output, Uri depsFile, | 307 Future writeDepsFile(Uri output, Uri depsFile, |
287 {Iterable<Uri> extraDependencies}) async { | 308 {Iterable<Uri> extraDependencies}) async { |
288 String toRelativeFilePath(Uri uri) { | 309 String toRelativeFilePath(Uri uri) { |
289 // Ninja expects to find file names relative to the current working | 310 // Ninja expects to find file names relative to the current working |
290 // directory. We've tried making them relative to the deps file, but that | 311 // directory. We've tried making them relative to the deps file, but that |
291 // doesn't work for downstream projects. Making them absolute also | 312 // doesn't work for downstream projects. Making them absolute also |
292 // doesn't work. | 313 // doesn't work. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 library.build(loader.coreLibrary); | 368 library.build(loader.coreLibrary); |
348 return link(<Library>[library.library]); | 369 return link(<Library>[library.library]); |
349 } | 370 } |
350 | 371 |
351 /// Creates a program by combining [libraries] with the libraries of | 372 /// Creates a program by combining [libraries] with the libraries of |
352 /// `dillTarget.loader.program`. | 373 /// `dillTarget.loader.program`. |
353 Program link(List<Library> libraries, {CanonicalName nameRoot}) { | 374 Program link(List<Library> libraries, {CanonicalName nameRoot}) { |
354 Map<String, Source> uriToSource = | 375 Map<String, Source> uriToSource = |
355 new Map<String, Source>.from(this.uriToSource); | 376 new Map<String, Source>.from(this.uriToSource); |
356 | 377 |
357 libraries.addAll(dillTarget.loader.libraries); | 378 List<Library> extraLibraries = dillTarget.loader.libraries; |
379 libraries.addAll(extraLibraries); | |
ahe
2017/05/22 11:49:04
Seems like an unnecessary change.
Siggi Cherem (dart-lang)
2017/05/22 23:15:48
Ouch, my apologies. I undid a bunch of other chang
| |
358 // TODO(scheglov) Should we also somehow update `uriToSource`? | 380 // TODO(scheglov) Should we also somehow update `uriToSource`? |
359 // uriToSource.addAll(binary.uriToSource); | 381 // uriToSource.addAll(binary.uriToSource); |
360 | 382 |
361 // TODO(ahe): Remove this line. Kernel seems to generate a default line map | 383 // TODO(ahe): Remove this line. Kernel seems to generate a default line map |
362 // that used when there's no fileUri on an element. Instead, ensure all | 384 // that used when there's no fileUri on an element. Instead, ensure all |
363 // elements have a fileUri. | 385 // elements have a fileUri. |
364 uriToSource[""] = new Source(<int>[0], const <int>[]); | 386 uriToSource[""] = new Source(<int>[0], const <int>[]); |
365 Program program = new Program( | 387 Program program = new Program( |
366 nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource); | 388 nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource); |
367 if (loader.first != null) { | 389 if (loader.first != null) { |
390 // TODO(sigmund): do only for full program | |
368 Builder builder = loader.first.lookup("main", -1, null); | 391 Builder builder = loader.first.lookup("main", -1, null); |
369 if (builder is KernelProcedureBuilder) { | 392 if (builder is KernelProcedureBuilder) { |
370 program.mainMethod = builder.procedure; | 393 program.mainMethod = builder.procedure; |
371 } | 394 } |
372 } | 395 } |
373 if (errors.isEmpty || dillTarget.isLoaded) { | 396 |
374 runLinkTransformations(program); | |
375 } | |
376 ticker.logMs("Linked program"); | 397 ticker.logMs("Linked program"); |
377 return program; | 398 return program; |
378 } | 399 } |
379 | 400 |
380 void installDefaultSupertypes() { | 401 void installDefaultSupertypes() { |
381 Class objectClass = this.objectClass; | 402 Class objectClass = this.objectClass; |
382 loader.builders.forEach((Uri uri, LibraryBuilder library) { | 403 loader.builders.forEach((Uri uri, LibraryBuilder library) { |
383 library.forEach((String name, Builder builder) { | 404 library.forEach((String name, Builder builder) { |
384 if (builder is SourceClassBuilder) { | 405 if (builder is SourceClassBuilder) { |
385 Class cls = builder.target; | 406 Class cls = builder.target; |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
631 }); | 652 }); |
632 } | 653 } |
633 | 654 |
634 /// Run all transformations that are needed when building a program for the | 655 /// Run all transformations that are needed when building a program for the |
635 /// first time. | 656 /// first time. |
636 void runBuildTransformations() { | 657 void runBuildTransformations() { |
637 transformMixinApplications(); | 658 transformMixinApplications(); |
638 otherTransformations(); | 659 otherTransformations(); |
639 } | 660 } |
640 | 661 |
641 /// Run all transformations that are needed when linking a program. | |
642 void runLinkTransformations(Program program) {} | |
643 | |
644 void transformMixinApplications() { | 662 void transformMixinApplications() { |
645 new MixinFullResolution().transform(_program); | 663 new MixinFullResolution().transform(_program); |
646 ticker.logMs("Transformed mixin applications"); | 664 ticker.logMs("Transformed mixin applications"); |
647 } | 665 } |
648 | 666 |
649 void otherTransformations() { | 667 void otherTransformations() { |
650 // TODO(ahe): Don't generate type variables in the first place. | 668 // TODO(ahe): Don't generate type variables in the first place. |
651 if (!strongMode) { | 669 if (!strongMode) { |
652 _program.accept(new Erasure()); | 670 _program.accept(new Erasure()); |
653 ticker.logMs("Erased type variables in generic methods"); | 671 ticker.logMs("Erased type variables in generic methods"); |
654 } | 672 } |
655 // TODO(kmillikin): Make this run on a per-method basis. | 673 // TODO(kmillikin): Make this run on a per-method basis. |
656 transformAsync.transformProgram(_program); | 674 transformAsync.transformProgram(_program); |
657 ticker.logMs("Transformed async methods"); | 675 ticker.logMs("Transformed async methods"); |
658 } | 676 } |
659 | 677 |
660 void verify() { | 678 void verify() { |
661 var verifyErrors = verifyProgram(_program); | 679 var verifyErrors = verifyProgram(_program); |
662 errors.addAll(verifyErrors.map((error) => '$error')); | 680 errors.addAll(verifyErrors.map((error) => '$error')); |
663 ticker.logMs("Verified program"); | 681 ticker.logMs("Verified program"); |
664 } | 682 } |
683 | |
684 /// Tree-shakes most code from the [dillTarget] by visiting all other | |
685 /// libraries in [_program] and marking the APIs from the [dillTarget] | |
686 /// libraries that are in use. | |
687 trimDependenciesInProgram() { | |
688 var toShake = | |
689 dillTarget.loader.libraries.map((lib) => lib.importUri).toSet(); | |
690 var isIncluded = (Uri uri) => !toShake.contains(uri); | |
691 var data = new RetainedDataBuilder(); | |
692 // TODO(sigmund): replace this step with data that is directly computed from | |
693 // the builders: we should know the tree-shaking roots without having to do | |
694 // a second visit over the tree. | |
695 new RootsMarker(data).run(_program, isIncluded); | |
696 trimProgram(_program, data, isIncluded); | |
697 } | |
665 } | 698 } |
666 | 699 |
667 /// Looks for a constructor call that matches `super()` from a constructor in | 700 /// Looks for a constructor call that matches `super()` from a constructor in |
668 /// [cls]. Such a constructor may have optional arguments, but no required | 701 /// [cls]. Such a constructor may have optional arguments, but no required |
669 /// arguments. | 702 /// arguments. |
670 Constructor defaultSuperConstructor(Class cls) { | 703 Constructor defaultSuperConstructor(Class cls) { |
671 Class superclass = cls.superclass; | 704 Class superclass = cls.superclass; |
672 while (superclass != null && superclass.isMixinApplication) { | 705 while (superclass != null && superclass.isMixinApplication) { |
673 superclass = superclass.superclass; | 706 superclass = superclass.superclass; |
674 } | 707 } |
675 for (Constructor constructor in superclass.constructors) { | 708 for (Constructor constructor in superclass.constructors) { |
676 if (constructor.name.name.isEmpty) { | 709 if (constructor.name.name.isEmpty) { |
677 return constructor.function.requiredParameterCount == 0 | 710 return constructor.function.requiredParameterCount == 0 |
678 ? constructor | 711 ? constructor |
679 : null; | 712 : null; |
680 } | 713 } |
681 } | 714 } |
682 return null; | 715 return null; |
683 } | 716 } |
OLD | NEW |