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