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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 final FileSystem fileSystem; | 90 final FileSystem fileSystem; |
91 | 91 |
92 final bool strongMode; | 92 final bool strongMode; |
93 | 93 |
94 final DillTarget dillTarget; | 94 final DillTarget dillTarget; |
95 | 95 |
96 /// Shared with [CompilerContext]. | 96 /// Shared with [CompilerContext]. |
97 final Map<String, Source> uriToSource; | 97 final Map<String, Source> uriToSource; |
98 | 98 |
99 SourceLoader<Library> loader; | 99 SourceLoader<Library> loader; |
100 Program _program; | 100 |
| 101 Program program; |
101 | 102 |
102 final List<String> errors = <String>[]; | 103 final List<String> errors = <String>[]; |
103 | 104 |
104 final TypeBuilder dynamicType = | 105 final TypeBuilder dynamicType = |
105 new KernelNamedTypeBuilder("dynamic", null, -1, null); | 106 new KernelNamedTypeBuilder("dynamic", null, -1, null); |
106 | 107 |
107 KernelTarget(this.fileSystem, DillTarget dillTarget, | 108 KernelTarget(this.fileSystem, DillTarget dillTarget, |
108 TranslateUri uriTranslator, this.strongMode, | 109 TranslateUri uriTranslator, this.strongMode, |
109 [Map<String, Source> uriToSource]) | 110 [Map<String, Source> uriToSource]) |
110 : dillTarget = dillTarget, | 111 : dillTarget = dillTarget, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 builder.mixedInType = null; | 216 builder.mixedInType = null; |
216 } | 217 } |
217 | 218 |
218 void handleInputError(InputError error, | 219 void handleInputError(InputError error, |
219 {bool isFullProgram, bool trimDependencies: false}) { | 220 {bool isFullProgram, bool trimDependencies: false}) { |
220 if (error != null) { | 221 if (error != null) { |
221 String message = error.format(); | 222 String message = error.format(); |
222 print(message); | 223 print(message); |
223 errors.add(message); | 224 errors.add(message); |
224 } | 225 } |
225 _program = erroneousProgram(isFullProgram); | 226 program = erroneousProgram(isFullProgram); |
226 } | 227 } |
227 | 228 |
228 @override | 229 @override |
229 Future<Program> buildOutlines({CanonicalName nameRoot}) async { | 230 Future<Program> buildOutlines({CanonicalName nameRoot}) async { |
230 if (loader.first == null) return null; | 231 if (loader.first == null) return null; |
231 try { | 232 try { |
232 loader.createTypeInferenceEngine(); | 233 loader.createTypeInferenceEngine(); |
233 await loader.buildOutlines(); | 234 await loader.buildOutlines(); |
234 loader.coreLibrary | 235 loader.coreLibrary |
235 .becomeCoreLibrary(const DynamicType(), const VoidType()); | 236 .becomeCoreLibrary(const DynamicType(), const VoidType()); |
236 dynamicType.bind(loader.coreLibrary["dynamic"]); | 237 dynamicType.bind(loader.coreLibrary["dynamic"]); |
237 loader.resolveParts(); | 238 loader.resolveParts(); |
238 loader.computeLibraryScopes(); | 239 loader.computeLibraryScopes(); |
239 loader.resolveTypes(); | 240 loader.resolveTypes(); |
240 loader.checkSemantics(); | 241 loader.checkSemantics(); |
241 loader.buildProgram(); | 242 loader.buildProgram(); |
242 List<SourceClassBuilder> sourceClasses = collectAllSourceClasses(); | 243 List<SourceClassBuilder> sourceClasses = collectAllSourceClasses(); |
243 installDefaultSupertypes(); | 244 installDefaultSupertypes(); |
244 installDefaultConstructors(sourceClasses); | 245 installDefaultConstructors(sourceClasses); |
245 loader.resolveConstructors(); | 246 loader.resolveConstructors(); |
246 loader.finishTypeVariables(objectClassBuilder); | 247 loader.finishTypeVariables(objectClassBuilder); |
247 _program = | 248 program = |
248 link(new List<Library>.from(loader.libraries), nameRoot: nameRoot); | 249 link(new List<Library>.from(loader.libraries), nameRoot: nameRoot); |
249 loader.computeHierarchy(_program); | 250 loader.computeHierarchy(program); |
250 loader.checkOverrides(sourceClasses); | 251 loader.checkOverrides(sourceClasses); |
251 loader.prepareInitializerInference(); | 252 loader.prepareInitializerInference(); |
252 loader.performInitializerInference(); | 253 loader.performInitializerInference(); |
253 } on InputError catch (e) { | 254 } on InputError catch (e) { |
254 handleInputError(e, isFullProgram: false); | 255 handleInputError(e, isFullProgram: false); |
255 } catch (e, s) { | 256 } catch (e, s) { |
256 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 257 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
257 } | 258 } |
258 return _program; | 259 return program; |
259 } | 260 } |
260 | 261 |
261 /// Build the kernel representation of the program loaded by this target. The | 262 /// Build the kernel representation of the program loaded by this target. The |
262 /// program will contain full bodies for the code loaded from sources, and | 263 /// program will contain full bodies for the code loaded from sources, and |
263 /// only references to the code loaded by the [DillTarget], which may or may | 264 /// only references to the code loaded by the [DillTarget], which may or may |
264 /// not include method bodies (depending on what was loaded into that target, | 265 /// not include method bodies (depending on what was loaded into that target, |
265 /// an outline or a full kernel program). | 266 /// an outline or a full kernel program). |
266 /// | 267 /// |
267 /// When [trimDependencies] is true, this also runs a tree-shaker that deletes | 268 /// When [trimDependencies] is true, this also runs a tree-shaker that deletes |
268 /// anything from the [DillTarget] that is not needed for the source program, | 269 /// anything from the [DillTarget] that is not needed for the source program, |
269 /// this includes function bodies and types that are not reachable. This | 270 /// this includes function bodies and types that are not reachable. This |
270 /// option is currently in flux and the internal implementation might change. | 271 /// option is currently in flux and the internal implementation might change. |
271 /// See [trimDependenciesInProgram] for more details. | 272 /// See [trimDependenciesInProgram] for more details. |
272 /// | 273 /// |
273 /// If [verify], run the default kernel verification on the resulting program. | 274 /// If [verify], run the default kernel verification on the resulting program. |
274 @override | 275 @override |
275 Future<Program> buildProgram( | 276 Future<Program> buildProgram( |
276 {bool verify: false, bool trimDependencies: false}) async { | 277 {bool verify: false, bool trimDependencies: false}) async { |
277 if (loader.first == null) return null; | 278 if (loader.first == null) return null; |
278 if (errors.isNotEmpty) { | 279 if (errors.isNotEmpty) { |
279 handleInputError(null, | 280 handleInputError(null, |
280 isFullProgram: true, trimDependencies: trimDependencies); | 281 isFullProgram: true, trimDependencies: trimDependencies); |
281 return _program; | 282 return program; |
282 } | 283 } |
283 | 284 |
284 try { | 285 try { |
285 await loader.buildBodies(); | 286 await loader.buildBodies(); |
286 loader.finishStaticInvocations(); | 287 loader.finishStaticInvocations(); |
287 finishAllConstructors(); | 288 finishAllConstructors(); |
288 loader.finishNativeMethods(); | 289 loader.finishNativeMethods(); |
289 runBuildTransformations(); | 290 runBuildTransformations(); |
290 | 291 |
291 if (verify) this.verify(); | 292 if (verify) this.verify(); |
292 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); | 293 errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); |
293 if (errors.isNotEmpty) { | 294 if (errors.isNotEmpty) { |
294 handleInputError(null, | 295 handleInputError(null, |
295 isFullProgram: true, trimDependencies: trimDependencies); | 296 isFullProgram: true, trimDependencies: trimDependencies); |
296 } | 297 } |
297 } on InputError catch (e) { | 298 } on InputError catch (e) { |
298 handleInputError(e, | 299 handleInputError(e, |
299 isFullProgram: true, trimDependencies: trimDependencies); | 300 isFullProgram: true, trimDependencies: trimDependencies); |
300 } catch (e, s) { | 301 } catch (e, s) { |
301 return reportCrash(e, s, loader?.currentUriForCrashReporting); | 302 return reportCrash(e, s, loader?.currentUriForCrashReporting); |
302 } | 303 } |
303 if (trimDependencies) trimDependenciesInProgram(); | 304 if (trimDependencies) trimDependenciesInProgram(); |
304 return _program; | 305 return program; |
305 } | 306 } |
306 | 307 |
307 Future writeDepsFile(Uri output, Uri depsFile, | 308 Future writeDepsFile(Uri output, Uri depsFile, |
308 {Iterable<Uri> extraDependencies}) async { | 309 {Iterable<Uri> extraDependencies}) async { |
309 String toRelativeFilePath(Uri uri) { | 310 String toRelativeFilePath(Uri uri) { |
310 // Ninja expects to find file names relative to the current working | 311 // Ninja expects to find file names relative to the current working |
311 // directory. We've tried making them relative to the deps file, but that | 312 // directory. We've tried making them relative to the deps file, but that |
312 // doesn't work for downstream projects. Making them absolute also | 313 // doesn't work for downstream projects. Making them absolute also |
313 // doesn't work. | 314 // doesn't work. |
314 // | 315 // |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 transformMixinApplications(); | 658 transformMixinApplications(); |
658 otherTransformations(); | 659 otherTransformations(); |
659 } | 660 } |
660 | 661 |
661 void transformMixinApplications() { | 662 void transformMixinApplications() { |
662 mix.transformLibraries(backendTarget, loader.coreTypes, loader.libraries); | 663 mix.transformLibraries(backendTarget, loader.coreTypes, loader.libraries); |
663 ticker.logMs("Transformed mixin applications"); | 664 ticker.logMs("Transformed mixin applications"); |
664 } | 665 } |
665 | 666 |
666 void otherTransformations() { | 667 void otherTransformations() { |
667 // TODO(ahe): Don't generate type variables in the first place. | |
668 if (!strongMode) { | 668 if (!strongMode) { |
669 _program.accept(new Erasure()); | 669 // TODO(ahe): Don't generate type variables in the first place. |
| 670 program.accept(new Erasure()); |
670 ticker.logMs("Erased type variables in generic methods"); | 671 ticker.logMs("Erased type variables in generic methods"); |
671 } | 672 } |
672 // TODO(kmillikin): Make this run on a per-method basis. | 673 if (errors.isEmpty && loader.collectCompileTimeErrors().isEmpty) { |
673 transformAsync.transformLibraries(loader.coreTypes, loader.libraries); | 674 // TODO(kmillikin): Make this run on a per-method basis. |
| 675 transformAsync.transformLibraries(loader.coreTypes, loader.libraries); |
| 676 } |
674 ticker.logMs("Transformed async methods"); | 677 ticker.logMs("Transformed async methods"); |
675 } | 678 } |
676 | 679 |
677 void verify() { | 680 void verify() { |
678 var verifyErrors = verifyProgram(_program); | 681 var verifyErrors = verifyProgram(program); |
679 errors.addAll(verifyErrors.map((error) => '$error')); | 682 errors.addAll(verifyErrors.map((error) => '$error')); |
680 ticker.logMs("Verified program"); | 683 ticker.logMs("Verified program"); |
681 } | 684 } |
682 | 685 |
683 /// Tree-shakes most code from the [dillTarget] by visiting all other | 686 /// Tree-shakes most code from the [dillTarget] by visiting all other |
684 /// libraries in [_program] and marking the APIs from the [dillTarget] | 687 /// libraries in [program] and marking the APIs from the [dillTarget] |
685 /// libraries that are in use. | 688 /// libraries that are in use. |
686 /// | 689 /// |
687 /// Note: while it's likely we'll do some trimming of programs for modular | 690 /// Note: while it's likely we'll do some trimming of programs for modular |
688 /// compilation, it is unclear at this time when and how that trimming should | 691 /// compilation, it is unclear at this time when and how that trimming should |
689 /// happen. We are likely going to remove the extra visitor my either marking | 692 /// happen. We are likely going to remove the extra visitor my either marking |
690 /// things while code is built, or by handling tree-shaking after the fact | 693 /// things while code is built, or by handling tree-shaking after the fact |
691 /// (e.g. during serialization). | 694 /// (e.g. during serialization). |
692 trimDependenciesInProgram() { | 695 trimDependenciesInProgram() { |
693 var toShake = | 696 var toShake = |
694 dillTarget.loader.libraries.map((lib) => lib.importUri).toSet(); | 697 dillTarget.loader.libraries.map((lib) => lib.importUri).toSet(); |
695 var isIncluded = (Uri uri) => !toShake.contains(uri); | 698 var isIncluded = (Uri uri) => !toShake.contains(uri); |
696 var data = new RetainedDataBuilder(); | 699 var data = new RetainedDataBuilder(); |
697 // TODO(sigmund): replace this step with data that is directly computed from | 700 // TODO(sigmund): replace this step with data that is directly computed from |
698 // the builders: we should know the tree-shaking roots without having to do | 701 // the builders: we should know the tree-shaking roots without having to do |
699 // a second visit over the tree. | 702 // a second visit over the tree. |
700 new RootsMarker(loader.coreTypes, data).run(_program, isIncluded); | 703 new RootsMarker(loader.coreTypes, data).run(program, isIncluded); |
701 trimProgram(_program, data, isIncluded); | 704 trimProgram(program, data, isIncluded); |
702 } | 705 } |
703 | 706 |
704 /// Return `true` if the given [library] was built by this [KernelTarget] | 707 /// Return `true` if the given [library] was built by this [KernelTarget] |
705 /// from sources, and not loaded from a [DillTarget]. | 708 /// from sources, and not loaded from a [DillTarget]. |
706 bool isSourceLibrary(Library library) { | 709 bool isSourceLibrary(Library library) { |
707 return loader.libraries.contains(library); | 710 return loader.libraries.contains(library); |
708 } | 711 } |
709 } | 712 } |
710 | 713 |
711 /// Looks for a constructor call that matches `super()` from a constructor in | 714 /// Looks for a constructor call that matches `super()` from a constructor in |
712 /// [cls]. Such a constructor may have optional arguments, but no required | 715 /// [cls]. Such a constructor may have optional arguments, but no required |
713 /// arguments. | 716 /// arguments. |
714 Constructor defaultSuperConstructor(Class cls) { | 717 Constructor defaultSuperConstructor(Class cls) { |
715 Class superclass = cls.superclass; | 718 Class superclass = cls.superclass; |
716 while (superclass != null && superclass.isMixinApplication) { | 719 while (superclass != null && superclass.isMixinApplication) { |
717 superclass = superclass.superclass; | 720 superclass = superclass.superclass; |
718 } | 721 } |
719 for (Constructor constructor in superclass.constructors) { | 722 for (Constructor constructor in superclass.constructors) { |
720 if (constructor.name.name.isEmpty) { | 723 if (constructor.name.name.isEmpty) { |
721 return constructor.function.requiredParameterCount == 0 | 724 return constructor.function.requiredParameterCount == 0 |
722 ? constructor | 725 ? constructor |
723 : null; | 726 : null; |
724 } | 727 } |
725 } | 728 } |
726 return null; | 729 return null; |
727 } | 730 } |
OLD | NEW |