Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2050)

Unified Diff: pkg/kernel/lib/transformations/treeshaker.dart

Issue 2668893004: VM: [Kernel] Add --embedder-entry-points-manifest to dartk/transform and pass it to the treeshaker (Closed)
Patch Set: Add missing bin/util.dart Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/kernel/lib/target/vm.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/kernel/lib/transformations/treeshaker.dart
diff --git a/pkg/kernel/lib/transformations/treeshaker.dart b/pkg/kernel/lib/transformations/treeshaker.dart
index 90540a0283633ab252284d88eaef1ed179a4837c..27ef8fb61699d24a03c528567a191cb3f0c15184 100644
--- a/pkg/kernel/lib/transformations/treeshaker.dart
+++ b/pkg/kernel/lib/transformations/treeshaker.dart
@@ -9,11 +9,48 @@ import '../class_hierarchy.dart';
import '../core_types.dart';
import '../type_environment.dart';
-Program transformProgram(Program program) {
- new TreeShaker(program).transform(program);
+Program transformProgram(Program program, {List<ProgramRoot> programRoots}) {
+ new TreeShaker(program, programRoots: programRoots).transform(program);
return program;
}
+enum ProgramRootKind {
+ /// The root is a class which will be instantiated by
+ /// external / non-Dart code.
+ ExternallyInstantiatedClass,
+
+ /// The root is a setter function or a field.
+ Setter,
+
+ /// The root is a getter function or a field.
+ Getter,
+
+ /// The root is some kind of constructor.
+ Constructor,
+
+ /// The root is a field, normal procedure or constructor.
+ Other,
+}
+
+/// A program root which the vm or embedder uses and needs to be retained.
+class ProgramRoot {
+ /// The library the root is contained in.
+ final String library;
+
+ /// The name of the class inside the library (optional).
+ final String klass;
+
+ /// The name of the member inside the library (or class, optional).
+ final String member;
+
+ /// The kind of this program root.
+ final ProgramRootKind kind;
+
+ ProgramRoot(this.library, this.klass, this.member, this.kind);
+
+ String toString() => "ProgramRoot($library, $klass, $member, $kind)";
+}
+
/// Tree shaking based on class hierarchy analysis.
///
/// Any dynamic dispatch not on `this` is conservatively assumed to target
@@ -30,13 +67,13 @@ Program transformProgram(Program program) {
///
/// If the `dart:mirrors` library is used then nothing will be tree-shaken.
//
-// TODO(asgerf): Shake off parts of the core libraries based on the Target.
// TODO(asgerf): Tree shake unused instance fields.
class TreeShaker {
final Program program;
final ClassHierarchy hierarchy;
final CoreTypes coreTypes;
final bool strongMode;
+ final List<ProgramRoot> programRoots;
/// Map from classes to set of names that have been dispatched with that class
/// as the static receiver type (meaning any subtype of that class can be
@@ -107,10 +144,17 @@ class TreeShaker {
/// Set to true if any use of the `dart:mirrors` API is found.
bool isUsingMirrors = false;
+ /// If we have roots, we will shake, even if we encounter some elements from
+ /// the mirrors library.
+ bool get forceShaking => programRoots != null && programRoots.isNotEmpty;
+
TreeShaker(Program program,
- {ClassHierarchy hierarchy, CoreTypes coreTypes, bool strongMode: false})
+ {ClassHierarchy hierarchy,
+ CoreTypes coreTypes,
+ bool strongMode: false,
+ List<ProgramRoot> programRoots})
: this._internal(program, hierarchy ?? new ClassHierarchy(program),
- coreTypes ?? new CoreTypes(program), strongMode);
+ coreTypes ?? new CoreTypes(program), strongMode, programRoots);
bool isMemberBodyUsed(Member member) {
return _usedMembers.containsKey(member);
@@ -145,8 +189,8 @@ class TreeShaker {
new _TreeShakingTransformer(this).transform(program);
}
- TreeShaker._internal(
- this.program, ClassHierarchy hierarchy, this.coreTypes, this.strongMode)
+ TreeShaker._internal(this.program, ClassHierarchy hierarchy, this.coreTypes,
+ this.strongMode, this.programRoots)
: this.hierarchy = hierarchy,
this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length),
this._usedMembersWithHost =
@@ -179,6 +223,8 @@ class TreeShaker {
_addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod'));
_addPervasiveUses();
_addUsedMember(null, program.mainMethod);
+ programRoots?.forEach(_addUsedRoot);
+
_iterateWorklist();
// Mark overridden members in order to preserve abstract members as
@@ -370,6 +416,49 @@ class TreeShaker {
visitList(classNode.annotations, _visitor);
}
+ /// Registers the given root as being used.
+ void _addUsedRoot(ProgramRoot root) {
+ Library rootLibrary = _findLibraryRoot(root, program);
+
+ if (root.kind == ProgramRootKind.ExternallyInstantiatedClass) {
+ Class rootClass = _findClassRoot(root, rootLibrary);
+
+ // This is a class which will be instantiated by non-Dart code (whether it
+ // has a valid generative construtor or not).
+ _addInstantiatedClass(rootClass);
+
+ // We keep all the constructors of externally instantiated classes.
+ // Sometimes the runtime might do a constructor call and sometimes it
+ // might just allocate the class without invoking the constructor.
+ // So we try to be on the safe side here!
+ for (var constructor in rootClass.constructors) {
+ _addUsedMember(rootClass, constructor);
+ }
+
+ // We keep all factory constructors as well for the same reason.
+ for (var member in rootClass.procedures) {
+ if (member.isStatic && member.kind == ProcedureKind.Factory) {
+ _addUsedMember(rootClass, member);
+ }
+ }
+ } else {
+ if (root.klass != null) {
+ // For class members we mark the Field/Procedure/Constructor as used.
+ // We also mark it as instantiated if it's a constructor.
+ Class rootClass = _findClassRoot(root, rootLibrary);
+ Member rootMember = _findMemberRoot(root, rootClass.members);
+ _addUsedMember(rootClass, rootMember);
+ if (rootMember is Constructor) {
+ _addInstantiatedClass(rootClass);
+ }
+ } else {
+ // For library members we mark the Field/Procedure as used.
+ Member rootMember = _findMemberRoot(root, rootLibrary.members);
+ _addUsedMember(null, rootMember);
+ }
+ }
+ }
+
/// Registers the given class as being used in a type annotation.
void _addClassUsedInType(Class classNode) {
int index = hierarchy.getClassIndex(classNode);
@@ -400,7 +489,7 @@ class TreeShaker {
/// the initializer list of another constructor.
/// - Procedures are used if they can be invoked or torn off.
void _addUsedMember(Class host, Member member) {
- if (member.enclosingLibrary == _mirrorsLibrary) {
+ if (!forceShaking && member.enclosingLibrary == _mirrorsLibrary) {
throw new _UsingMirrorsException();
}
if (host != null) {
@@ -808,7 +897,7 @@ class _TreeShakingTransformer extends Transformer {
void transform(Program program) {
for (var library in program.libraries) {
- if (library.importUri.scheme == 'dart') {
+ if (!shaker.forceShaking && library.importUri.scheme == 'dart') {
// The backend expects certain things to be present in the core
// libraries, so we currently don't shake off anything there.
continue;
@@ -979,3 +1068,53 @@ class _ExternalTypeVisitor extends DartTypeVisitor {
/// Exception that is thrown to stop the tree shaking analysis when a use
/// of `dart:mirrors` is found.
class _UsingMirrorsException {}
+
+Library _findLibraryRoot(ProgramRoot root, Program program) {
+ for (var library in program.libraries) {
+ if (library.importUri.toString() == root.library) {
+ return library;
+ }
+ }
+
+ throw "$root not found!";
+}
+
+Class _findClassRoot(ProgramRoot root, Library rootLibrary) {
+ for (var klass in rootLibrary.classes) {
+ if (klass.name == root.klass) {
+ return klass;
+ }
+ }
+ throw "$root not found!";
+}
+
+Member _findMemberRoot(ProgramRoot root, Iterable<Member> membersToSearch) {
+ for (var member in membersToSearch) {
+ if (member.name.name == root.member) {
+ switch (root.kind) {
+ case ProgramRootKind.Constructor:
+ if (member is Procedure && member.kind == ProcedureKind.Factory ||
+ member is Constructor) {
+ return member;
+ }
+ break;
+ case ProgramRootKind.Setter:
+ if (member is Procedure && member.kind == ProcedureKind.Setter ||
+ member is Field) {
+ return member;
+ }
+ break;
+ case ProgramRootKind.Getter:
+ if (member is Procedure && member.kind == ProcedureKind.Getter ||
+ member is Field) {
+ return member;
+ }
+ break;
+ case ProgramRootKind.Other:
+ return member;
+ default:
+ }
+ }
+ }
+ throw "$root not found!";
+}
« no previous file with comments | « pkg/kernel/lib/target/vm.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698