| 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..f0eceb6522d4eb92d59e80b08c7b91c9819fe252 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) {
|
| + trimDependenciesInProgram(_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) {
|
| + trimDependenciesInProgram(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,17 @@ Constructor defaultSuperConstructor(Class cls) {
|
| }
|
| return null;
|
| }
|
| +
|
| +/// Tree-shakes most code from [librariesToShake] by visiting all other
|
| +/// libraries in [program] and marking the APIs from [librariesToShake] that are
|
| +/// in use.
|
| +trimDependenciesInProgram(Program program, List<Library> librariesToShake) {
|
| + var toShake = librariesToShake.map((lib) => lib.importUri).toSet();
|
| + var isIncluded = (Uri uri) => !toShake.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);
|
| +}
|
|
|