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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/custom_elements_analysis.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of js_backend;
6
7 /**
8 * Support for Custom Elements.
9 *
10 * The support for custom elements the compiler builds a table that maps the
11 * custom element class's [Type] to the interceptor for the class and the
12 * constructor(s) for the class.
13 *
14 * We want the table to contain only the custom element classes used, and we
15 * want to avoid resolving and compiling constructors that are not used since
16 * that may bring in unused code. This class controls the resolution and code
17 * generation to restrict the impact.
18 *
19 * The following line of code requires the generation of the generative
20 * constructor factory function(s) for FancyButton, and their insertion into the
21 * table:
22 *
23 * document.register(FancyButton, 'x-fancy-button');
24 *
25 * We detect this by 'joining' the classes that are referenced as type literals
26 * with the classes that are custom elements, enabled by detecting the presence
27 * of the table access code used by document.register.
28 *
29 * We have to be more conservative when the type is unknown, e.g.
30 *
31 * document.register(classMirror.reflectedType, tagFromMetadata);
32 *
33 * and
34 *
35 * class Component<T> {
36 * final tag;
37 * Component(this.tag);
38 * void register() => document.register(T, tag);
39 * }
40 * const Component<FancyButton>('x-fancy-button').register();
41 *
42 * In these cases we conservatively generate all viable entries in the table.
43 */
44 class CustomElementsAnalysis {
45 final JavaScriptBackend backend;
46 final Compiler compiler;
47 final CustomElementsAnalysisJoin resolutionJoin;
48 final CustomElementsAnalysisJoin codegenJoin;
49 bool fetchedTableAccessorMethod = false;
50 Element tableAccessorMethod;
51
52 CustomElementsAnalysis(JavaScriptBackend backend)
53 : this.backend = backend,
54 this.compiler = backend.compiler,
55 resolutionJoin = new CustomElementsAnalysisJoin(backend),
56 codegenJoin = new CustomElementsAnalysisJoin(backend) {
57 // TODO(sra): Remove this work-around. We should mark allClassesSelected in
58 // both joins only when we see a construct generating an unknown [Type] but
59 // we can't currently recognize all cases. In particular, the work-around
60 // for the unimplemented `ClassMirror.reflectedType` is not recognizable.
61 // TODO(12607): Match on [ClassMirror.reflectedType]
62 resolutionJoin.allClassesSelected = true;
63 codegenJoin.allClassesSelected = true;
64 }
65
66 CustomElementsAnalysisJoin joinFor(Enqueuer enqueuer) =>
67 enqueuer.isResolutionQueue ? resolutionJoin : codegenJoin;
68
69 void registerInstantiatedClass(ClassElement classElement, Enqueuer enqueuer) {
70 classElement.ensureResolved(compiler);
71 if (!Elements.isNativeOrExtendsNative(classElement)) return;
72 if (classElement.isMixinApplication) return;
73 if (classElement.isAbstract) return;
74 joinFor(enqueuer).instantiatedClasses.add(classElement);
75 }
76
77 void registerTypeLiteral(DartType type, Registry registry) {
78 assert(registry.isForResolution);
79 // In codegen we see the TypeConstants instead.
80 if (!registry.isForResolution) return;
81
82 if (type.isInterfaceType) {
83 // TODO(sra): If we had a flow query from the type literal expression to
84 // the Type argument of the metadata lookup, we could tell if this type
85 // literal is really a demand for the metadata.
86 resolutionJoin.selectedClasses.add(type.element);
87 } else if (type.isTypeVariable) {
88 // This is a type parameter of a parameterized class.
89 // TODO(sra): Is there a way to determine which types are bound to the
90 // parameter?
91 resolutionJoin.allClassesSelected = true;
92 }
93 }
94
95 void registerTypeConstant(Element element, Enqueuer enqueuer) {
96 assert(element.isClass);
97 assert(!enqueuer.isResolutionQueue);
98 codegenJoin.selectedClasses.add(element);
99 }
100
101 void registerStaticUse(Element element, Enqueuer enqueuer) {
102 assert(element != null);
103 if (!fetchedTableAccessorMethod) {
104 fetchedTableAccessorMethod = true;
105 tableAccessorMethod = backend.findInterceptor(
106 'findIndexForNativeSubclassType');
107 }
108 if (element == tableAccessorMethod) {
109 joinFor(enqueuer).demanded = true;
110 }
111 }
112
113 void onQueueEmpty(Enqueuer enqueuer) {
114 joinFor(enqueuer).flush(enqueuer);
115 }
116
117 bool get needsTable => codegenJoin.demanded;
118
119 bool needsClass(ClassElement classElement) =>
120 codegenJoin.activeClasses.contains(classElement);
121
122 List<Element> constructors(ClassElement classElement) =>
123 codegenJoin.computeEscapingConstructors(classElement);
124 }
125
126
127 class CustomElementsAnalysisJoin {
128 final JavaScriptBackend backend;
129 Compiler get compiler => backend.compiler;
130
131 // Classes that are candidates for needing constructors. Classes are moved to
132 // [activeClasses] when we know they need constructors.
133 final instantiatedClasses = new Set<ClassElement>();
134
135 // Classes explicitly named.
136 final selectedClasses = new Set<ClassElement>();
137
138 // True if we must conservatively include all extension classes.
139 bool allClassesSelected = false;
140
141 // Did we see a demand for the data?
142 bool demanded = false;
143
144 // ClassesOutput: classes requiring metadata.
145 final activeClasses = new Set<ClassElement>();
146
147 CustomElementsAnalysisJoin(this.backend);
148
149 void flush(Enqueuer enqueuer) {
150 if (!demanded) return;
151 var newActiveClasses = new Set<ClassElement>();
152 for (ClassElement classElement in instantiatedClasses) {
153 bool isNative = classElement.isNative;
154 bool isExtension =
155 !isNative && Elements.isNativeOrExtendsNative(classElement);
156 // Generate table entries for native classes that are explicitly named and
157 // extensions that fix our criteria.
158 if ((isNative && selectedClasses.contains(classElement)) ||
159 (isExtension &&
160 (allClassesSelected || selectedClasses.contains(classElement)))) {
161 newActiveClasses.add(classElement);
162 Iterable<Element> escapingConstructors =
163 computeEscapingConstructors(classElement);
164 escapingConstructors.forEach(enqueuer.registerStaticUse);
165 escapingConstructors
166 .forEach(compiler.globalDependencies.registerDependency);
167 // Force the generaton of the type constant that is the key to an entry
168 // in the generated table.
169 ConstantValue constant = makeTypeConstant(classElement);
170 backend.registerCompileTimeConstant(
171 constant, compiler.globalDependencies);
172 backend.constants.addCompileTimeConstantForEmission(constant);
173 }
174 }
175 activeClasses.addAll(newActiveClasses);
176 instantiatedClasses.removeAll(newActiveClasses);
177 }
178
179 TypeConstantValue makeTypeConstant(ClassElement element) {
180 DartType elementType = element.rawType;
181 DartType constantType = backend.typeImplementation.rawType;
182 return new TypeConstantValue(elementType, constantType);
183 }
184
185 List<Element> computeEscapingConstructors(ClassElement classElement) {
186 List<Element> result = <Element>[];
187 // Only classes that extend native classes have constructors in the table.
188 // We could refine this to classes that extend Element, but that would break
189 // the tests and there is no sane reason to subclass other native classes.
190 if (classElement.isNative) return result;
191
192 selectGenerativeConstructors(ClassElement enclosing, Element member) {
193 if (member.isGenerativeConstructor) {
194 // Ignore constructors that cannot be called with zero arguments.
195 FunctionElement constructor = member;
196 FunctionSignature parameters = constructor.functionSignature;
197 if (parameters.requiredParameterCount == 0) {
198 result.add(member);
199 }
200 }
201 }
202 classElement.forEachMember(selectGenerativeConstructors,
203 includeBackendMembers: false,
204 includeSuperAndInjectedMembers: false);
205 return result;
206 }
207 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698