Chromium Code Reviews| Index: pkg/front_end/lib/src/fasta/kernel/kernel_target.dart |
| diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart |
| index eb5eda79811f23c446c213e572802c438b138cff..ee5f8addcc5a91509ce805f3817512d3c1366a7d 100644 |
| --- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart |
| +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart |
| @@ -83,6 +83,8 @@ import 'kernel_builder.dart' |
| TypeVariableBuilder; |
| import 'verifier.dart' show verifyProgram; |
| +import 'kernel_outline_shaker.dart' |
| + show trimProgram, RetainedDataBuilder, RootsMarker; |
| class KernelTarget extends TargetImplementation { |
| /// The [FileSystem] which should be used to access files. |
| @@ -214,13 +216,17 @@ class KernelTarget extends TargetImplementation { |
| builder.mixedInType = null; |
| } |
| - void handleInputError(InputError error, {bool isFullProgram}) { |
| + void handleInputError(InputError error, |
| + {bool isFullProgram, bool trimDependencies: false}) { |
| if (error != null) { |
| String message = error.format(); |
| print(message); |
| errors.add(message); |
| } |
| _program = erroneousProgram(isFullProgram); |
| + if (trimDependencies) { |
| + trimDependenciesHelper(_program, dillTarget.loader.libraries); |
| + } |
| } |
| @override |
| @@ -256,15 +262,30 @@ class KernelTarget extends TargetImplementation { |
| return _program; |
| } |
| + /// Build the kernel representation of the program loaded by this target. The |
| + /// program will contain full bodies for the code loaded from sources, and |
| + /// only references to the code loaded by the [DillTarget], which may or may |
| + /// not include method bodies (depending on what was loaded into that target, |
| + /// an outline or a full kernel program). |
| + /// |
| + /// When [trimDependencies] is true, this also runs a tree-shaker that deletes |
| + /// anything from the [DillTarget] that is not needed for the source program, |
| + /// this includes function bodies and types that are not reachable. |
| + /// |
| + /// If [verify], run the default kernel verification on the resulting program. |
| @override |
| - Future<Program> buildProgram({bool verify: false}) async { |
| + Future<Program> buildProgram( |
| + {bool verify: false, bool trimDependencies: false}) async { |
| if (loader.first == null) return null; |
| if (errors.isNotEmpty) { |
| - handleInputError(null, isFullProgram: true); |
| + handleInputError(null, |
| + isFullProgram: true, trimDependencies: trimDependencies); |
| return _program; |
| } |
| try { |
| await loader.buildBodies(); |
| + _program = link(new List<Library>.from(loader.libraries), |
| + trimDependencies: trimDependencies); |
| loader.finishStaticInvocations(); |
| finishAllConstructors(); |
| loader.finishNativeMethods(); |
| @@ -273,10 +294,12 @@ class KernelTarget extends TargetImplementation { |
| if (verify) this.verify(); |
| errors.addAll(loader.collectCompileTimeErrors().map((e) => e.format())); |
| if (errors.isNotEmpty) { |
| - handleInputError(null, isFullProgram: true); |
| + handleInputError(null, |
| + isFullProgram: true, trimDependencies: trimDependencies); |
| } |
| } on InputError catch (e) { |
| - handleInputError(e, isFullProgram: true); |
| + handleInputError(e, |
| + isFullProgram: true, trimDependencies: trimDependencies); |
| } catch (e, s) { |
| return reportCrash(e, s, loader?.currentUriForCrashReporting); |
| } |
| @@ -350,11 +373,13 @@ class KernelTarget extends TargetImplementation { |
| /// Creates a program by combining [libraries] with the libraries of |
| /// `dillTarget.loader.program`. |
| - Program link(List<Library> libraries, {CanonicalName nameRoot}) { |
| + Program link(List<Library> libraries, |
| + {CanonicalName nameRoot, bool trimDependencies: false}) { |
| Map<String, Source> uriToSource = |
| new Map<String, Source>.from(this.uriToSource); |
| - libraries.addAll(dillTarget.loader.libraries); |
| + List<Library> extraLibraries = dillTarget.loader.libraries; |
| + libraries.addAll(extraLibraries); |
| // TODO(scheglov) Should we also somehow update `uriToSource`? |
| // uriToSource.addAll(binary.uriToSource); |
| @@ -365,14 +390,16 @@ class KernelTarget extends TargetImplementation { |
| Program program = new Program( |
| nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource); |
| if (loader.first != null) { |
| + // TODO(sigmund): do only for full program |
| Builder builder = loader.first.lookup("main", -1, null); |
| if (builder is KernelProcedureBuilder) { |
| program.mainMethod = builder.procedure; |
| } |
| } |
| - if (errors.isEmpty || dillTarget.isLoaded) { |
| - runLinkTransformations(program); |
| + if (trimDependencies) { |
| + trimDependenciesHelper(program, extraLibraries); |
| } |
| + |
| ticker.logMs("Linked program"); |
| return program; |
| } |
| @@ -638,9 +665,6 @@ class KernelTarget extends TargetImplementation { |
| otherTransformations(); |
| } |
| - /// Run all transformations that are needed when linking a program. |
| - void runLinkTransformations(Program program) {} |
| - |
| void transformMixinApplications() { |
| new MixinFullResolution().transform(_program); |
| ticker.logMs("Transformed mixin applications"); |
| @@ -681,3 +705,14 @@ Constructor defaultSuperConstructor(Class cls) { |
| } |
| return null; |
| } |
| + |
| +trimDependenciesHelper(Program program, List<Library> extraLibraries) { |
|
scheglov
2017/05/19 17:19:05
1. Helper is usually an object, YMMV though.
2. Co
Siggi Cherem (dart-lang)
2017/05/19 19:43:30
indeed - I very commonly use "helper" for helper f
|
| + var excluded = extraLibraries.map((lib) => lib.importUri).toSet(); |
| + var isIncluded = (Uri uri) => !excluded.contains(uri); |
| + var data = new RetainedDataBuilder(); |
| + // TODO(sigmund): replace this step with data that is directly computed from |
| + // the builders: we should know the tree-shaking roots without having to do a |
| + // second visit over the tree. |
| + new RootsMarker(data).run(program, isIncluded); |
| + trimProgram(program, data, isIncluded); |
| +} |