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

Side by Side Diff: pkg/compiler/lib/src/js_backend/enqueuer.dart

Issue 2314703002: Split World usage into open, inference, and closed world. (Closed)
Patch Set: Updated cf. comments. Created 4 years, 3 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 dart2js.js.enqueue; 5 library dart2js.js.enqueue;
6 6
7 import 'dart:collection' show Queue; 7 import 'dart:collection' show Queue;
8 8
9 import '../common/backend_api.dart' show Backend;
9 import '../common/codegen.dart' show CodegenWorkItem; 10 import '../common/codegen.dart' show CodegenWorkItem;
11 import '../common/registry.dart' show Registry;
10 import '../common/names.dart' show Identifiers; 12 import '../common/names.dart' show Identifiers;
11 import '../common/resolution.dart' show Resolution;
12 import '../common/work.dart' show WorkItem; 13 import '../common/work.dart' show WorkItem;
13 import '../common.dart'; 14 import '../common.dart';
14 import '../compiler.dart' show Compiler; 15 import '../compiler.dart' show Compiler;
15 import '../dart_types.dart' show DartType, InterfaceType; 16 import '../dart_types.dart' show DartType, InterfaceType;
16 import '../elements/elements.dart' 17 import '../elements/elements.dart'
17 show 18 show
18 ClassElement, 19 ClassElement,
19 ConstructorElement, 20 ConstructorElement,
20 Element, 21 Element,
21 Elements, 22 Elements,
22 Entity, 23 Entity,
23 FunctionElement, 24 FunctionElement,
24 LibraryElement, 25 LibraryElement,
25 Member, 26 Member,
26 MemberElement, 27 MemberElement,
27 Name, 28 Name,
28 TypedElement, 29 TypedElement,
29 TypedefElement; 30 TypedefElement;
30 import '../enqueue.dart'; 31 import '../enqueue.dart';
31 import '../js/js.dart' as js; 32 import '../js/js.dart' as js;
32 import '../native/native.dart' as native; 33 import '../native/native.dart' as native;
34 import '../options.dart';
33 import '../types/types.dart' show TypeMaskStrategy; 35 import '../types/types.dart' show TypeMaskStrategy;
34 import '../universe/selector.dart' show Selector; 36 import '../universe/selector.dart' show Selector;
35 import '../universe/universe.dart'; 37 import '../universe/universe.dart';
36 import '../universe/use.dart' 38 import '../universe/use.dart'
37 show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind; 39 show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind;
38 import '../universe/world_impact.dart' 40 import '../universe/world_impact.dart'
39 show ImpactUseCase, WorldImpact, WorldImpactVisitor; 41 show ImpactUseCase, WorldImpact, WorldImpactVisitor;
40 import '../util/util.dart' show Setlet; 42 import '../util/util.dart' show Setlet;
43 import '../world.dart';
41 44
42 /// [Enqueuer] which is specific to code generation. 45 /// [Enqueuer] which is specific to code generation.
43 class CodegenEnqueuer implements Enqueuer { 46 class CodegenEnqueuer implements Enqueuer {
44 final String name; 47 final String name;
45 final Compiler compiler; // TODO(ahe): Remove this dependency. 48 @deprecated
49 final Compiler _compiler; // TODO(ahe): Remove this dependency.
46 final EnqueuerStrategy strategy; 50 final EnqueuerStrategy strategy;
47 final Map<String, Set<Element>> instanceMembersByName = 51 final Map<String, Set<Element>> instanceMembersByName =
48 new Map<String, Set<Element>>(); 52 new Map<String, Set<Element>>();
49 final Map<String, Set<Element>> instanceFunctionsByName = 53 final Map<String, Set<Element>> instanceFunctionsByName =
50 new Map<String, Set<Element>>(); 54 new Map<String, Set<Element>>();
51 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); 55 final Set<ClassElement> _processedClasses = new Set<ClassElement>();
52 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); 56 Set<ClassElement> recentClasses = new Setlet<ClassElement>();
53 final Universe universe = new Universe(const TypeMaskStrategy()); 57 final Universe universe = new Universe(const TypeMaskStrategy());
54 58
55 static final TRACE_MIRROR_ENQUEUING = 59 static final TRACE_MIRROR_ENQUEUING =
56 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); 60 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING");
57 61
58 bool queueIsClosed = false; 62 bool queueIsClosed = false;
59 EnqueueTask task; 63 EnqueueTask task;
60 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask 64 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask
61 65
62 bool hasEnqueuedReflectiveElements = false; 66 bool hasEnqueuedReflectiveElements = false;
63 bool hasEnqueuedReflectiveStaticFields = false; 67 bool hasEnqueuedReflectiveStaticFields = false;
64 68
65 WorldImpactVisitor impactVisitor; 69 WorldImpactVisitor impactVisitor;
66 70
67 CodegenEnqueuer(Compiler compiler, this.strategy) 71 CodegenEnqueuer(Compiler compiler, this.strategy)
68 : queue = new Queue<CodegenWorkItem>(), 72 : queue = new Queue<CodegenWorkItem>(),
69 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), 73 newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
70 newlySeenSelectors = compiler.cacheStrategy.newSet(), 74 newlySeenSelectors = compiler.cacheStrategy.newSet(),
71 this.name = 'codegen enqueuer', 75 this.name = 'codegen enqueuer',
72 this.compiler = compiler { 76 this._compiler = compiler {
73 impactVisitor = new _EnqueuerImpactVisitor(this); 77 impactVisitor = new _EnqueuerImpactVisitor(this);
74 } 78 }
75 79
76 // TODO(johnniwinther): Move this to [ResolutionEnqueuer]. 80 Backend get backend => _compiler.backend;
77 Resolution get resolution => compiler.resolution; 81
82 CompilerOptions get options => _compiler.options;
83
84 Registry get globalDependencies => _compiler.globalDependencies;
85
86 Registry get mirrorDependencies => _compiler.mirrorDependencies;
87
88 ClassWorld get _world => _compiler.closedWorld;
78 89
79 bool get queueIsEmpty => queue.isEmpty; 90 bool get queueIsEmpty => queue.isEmpty;
80 91
81 /// Returns [:true:] if this enqueuer is the resolution enqueuer. 92 /// Returns [:true:] if this enqueuer is the resolution enqueuer.
82 bool get isResolutionQueue => false; 93 bool get isResolutionQueue => false;
83 94
84 QueueFilter get filter => compiler.enqueuerFilter; 95 QueueFilter get filter => _compiler.enqueuerFilter;
85 96
86 DiagnosticReporter get reporter => compiler.reporter; 97 DiagnosticReporter get reporter => _compiler.reporter;
87
88 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
89
90 Iterable<ClassElement> get processedClasses => _processedClasses;
91 98
92 /** 99 /**
93 * Documentation wanted -- johnniwinther 100 * Documentation wanted -- johnniwinther
94 * 101 *
95 * Invariant: [element] must be a declaration element. 102 * Invariant: [element] must be a declaration element.
96 */ 103 */
97 void addToWorkList(Element element) { 104 void addToWorkList(Element element) {
98 assert(invariant(element, element.isDeclaration)); 105 assert(invariant(element, element.isDeclaration));
99 if (internalAddToWorkList(element) && compiler.options.dumpInfo) { 106 // Don't generate code for foreign elements.
107 if (backend.isForeign(element)) return;
108
109 // Codegen inlines field initializers. It only needs to generate
110 // code for checked setters.
111 if (element.isField && element.isInstanceMember) {
112 if (!options.enableTypeAssertions || element.enclosingElement.isClosure) {
113 return;
114 }
115 }
116
117 if (options.hasIncrementalSupport && !isProcessed(element)) {
118 newlyEnqueuedElements.add(element);
119 }
120
121 if (queueIsClosed) {
122 throw new SpannableAssertionFailure(
123 element, "Codegen work list is closed. Trying to add $element");
124 }
125 queue.add(new CodegenWorkItem(_compiler, element));
126 if (options.dumpInfo) {
100 // TODO(sigmund): add other missing dependencies (internals, selectors 127 // TODO(sigmund): add other missing dependencies (internals, selectors
101 // enqueued after allocations), also enable only for the codegen enqueuer. 128 // enqueued after allocations), also enable only for the codegen enqueuer.
102 compiler.dumpInfoTask 129 _compiler.dumpInfoTask
103 .registerDependency(compiler.currentElement, element); 130 .registerDependency(_compiler.currentElement, element);
104 } 131 }
105 } 132 }
106 133
107 /// Apply the [worldImpact] of processing [element] to this enqueuer. 134 /// Apply the [worldImpact] of processing [element] to this enqueuer.
108 void applyImpact(Element element, WorldImpact worldImpact) { 135 void applyImpact(Element element, WorldImpact worldImpact) {
109 compiler.impactStrategy 136 _compiler.impactStrategy
110 .visitImpact(element, worldImpact, impactVisitor, impactUse); 137 .visitImpact(element, worldImpact, impactVisitor, impactUse);
111 } 138 }
112 139
113 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { 140 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) {
114 task.measure(() { 141 task.measure(() {
115 ClassElement cls = type.element; 142 ClassElement cls = type.element;
116 cls.ensureResolved(resolution); 143 bool isNative = backend.isNative(cls);
117 bool isNative = compiler.backend.isNative(cls);
118 universe.registerTypeInstantiation(type, 144 universe.registerTypeInstantiation(type,
119 isNative: isNative, 145 isNative: isNative,
120 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { 146 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) {
121 compiler.backend 147 backend.registerImplementedClass(cls, this, globalDependencies);
122 .registerImplementedClass(cls, this, compiler.globalDependencies);
123 }); 148 });
124 // TODO(johnniwinther): Share this reasoning with [Universe]. 149 // TODO(johnniwinther): Share this reasoning with [Universe].
125 if (!cls.isAbstract || isNative || mirrorUsage) { 150 if (!cls.isAbstract || isNative || mirrorUsage) {
126 processInstantiatedClass(cls); 151 processInstantiatedClass(cls);
127 } 152 }
128 }); 153 });
129 } 154 }
130 155
131 bool checkNoEnqueuedInvokedInstanceMethods() { 156 bool checkNoEnqueuedInvokedInstanceMethods() {
132 return filter.checkNoEnqueuedInvokedInstanceMethods(this); 157 return filter.checkNoEnqueuedInvokedInstanceMethods(this);
(...skipping 10 matching lines...) Expand all
143 String memberName = member.name; 168 String memberName = member.name;
144 169
145 if (member.isField) { 170 if (member.isField) {
146 // The obvious thing to test here would be "member.isNative", 171 // The obvious thing to test here would be "member.isNative",
147 // however, that only works after metadata has been parsed/analyzed, 172 // however, that only works after metadata has been parsed/analyzed,
148 // and that may not have happened yet. 173 // and that may not have happened yet.
149 // So instead we use the enclosing class, which we know have had 174 // So instead we use the enclosing class, which we know have had
150 // its metadata parsed and analyzed. 175 // its metadata parsed and analyzed.
151 // Note: this assumes that there are no non-native fields on native 176 // Note: this assumes that there are no non-native fields on native
152 // classes, which may not be the case when a native class is subclassed. 177 // classes, which may not be the case when a native class is subclassed.
153 if (compiler.backend.isNative(cls)) { 178 if (backend.isNative(cls)) {
154 compiler.world.registerUsedElement(member); 179 if (universe.hasInvokedGetter(member, _world) ||
155 if (universe.hasInvokedGetter(member, compiler.world) || 180 universe.hasInvocation(member, _world)) {
156 universe.hasInvocation(member, compiler.world)) {
157 addToWorkList(member); 181 addToWorkList(member);
158 return; 182 return;
159 } 183 }
160 if (universe.hasInvokedSetter(member, compiler.world)) { 184 if (universe.hasInvokedSetter(member, _world)) {
Harry Terkelsen 2016/09/19 17:18:26 nit: maybe this if-statement can be merged with th
Johnni Winther 2016/09/20 08:29:58 Done.
161 addToWorkList(member); 185 addToWorkList(member);
162 return; 186 return;
163 } 187 }
164 // Native fields need to go into instanceMembersByName as they 188 // Native fields need to go into instanceMembersByName as they
165 // are virtual instantiation points and escape points. 189 // are virtual instantiation points and escape points.
166 } else { 190 } else {
167 // All field initializers must be resolved as they could 191 // All field initializers must be resolved as they could
168 // have an observable side-effect (and cannot be tree-shaken 192 // have an observable side-effect (and cannot be tree-shaken
169 // away). 193 // away).
170 addToWorkList(member); 194 addToWorkList(member);
171 return; 195 return;
172 } 196 }
173 } else if (member.isFunction) { 197 } else if (member.isFunction) {
174 FunctionElement function = member; 198 FunctionElement function = member;
175 function.computeType(resolution);
176 if (function.name == Identifiers.noSuchMethod_) { 199 if (function.name == Identifiers.noSuchMethod_) {
177 registerNoSuchMethod(function); 200 registerNoSuchMethod(function);
178 } 201 }
179 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { 202 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
180 registerCallMethodWithFreeTypeVariables(function); 203 registerCallMethodWithFreeTypeVariables(function);
181 } 204 }
182 // If there is a property access with the same name as a method we 205 // If there is a property access with the same name as a method we
183 // need to emit the method. 206 // need to emit the method.
184 if (universe.hasInvokedGetter(function, compiler.world)) { 207 if (universe.hasInvokedGetter(function, _world)) {
185 registerClosurizedMember(function); 208 registerClosurizedMember(function);
186 addToWorkList(function); 209 addToWorkList(function);
187 return; 210 return;
188 } 211 }
189 // Store the member in [instanceFunctionsByName] to catch 212 // Store the member in [instanceFunctionsByName] to catch
190 // getters on the function. 213 // getters on the function.
191 instanceFunctionsByName 214 instanceFunctionsByName
192 .putIfAbsent(memberName, () => new Set<Element>()) 215 .putIfAbsent(memberName, () => new Set<Element>())
193 .add(member); 216 .add(member);
194 if (universe.hasInvocation(function, compiler.world)) { 217 if (universe.hasInvocation(function, _world)) {
195 addToWorkList(function); 218 addToWorkList(function);
196 return; 219 return;
197 } 220 }
198 } else if (member.isGetter) { 221 } else if (member.isGetter) {
199 FunctionElement getter = member; 222 FunctionElement getter = member;
200 getter.computeType(resolution); 223 if (universe.hasInvokedGetter(getter, _world)) {
201 if (universe.hasInvokedGetter(getter, compiler.world)) {
202 addToWorkList(getter); 224 addToWorkList(getter);
203 return; 225 return;
204 } 226 }
205 // We don't know what selectors the returned closure accepts. If 227 // We don't know what selectors the returned closure accepts. If
206 // the set contains any selector we have to assume that it matches. 228 // the set contains any selector we have to assume that it matches.
207 if (universe.hasInvocation(getter, compiler.world)) { 229 if (universe.hasInvocation(getter, _world)) {
208 addToWorkList(getter); 230 addToWorkList(getter);
209 return; 231 return;
210 } 232 }
211 } else if (member.isSetter) { 233 } else if (member.isSetter) {
212 FunctionElement setter = member; 234 FunctionElement setter = member;
213 setter.computeType(resolution); 235 if (universe.hasInvokedSetter(setter, _world)) {
214 if (universe.hasInvokedSetter(setter, compiler.world)) {
215 addToWorkList(setter); 236 addToWorkList(setter);
216 return; 237 return;
217 } 238 }
218 } 239 }
219 240
220 // The element is not yet used. Add it to the list of instance 241 // The element is not yet used. Add it to the list of instance
221 // members to still be processed. 242 // members to still be processed.
222 instanceMembersByName 243 instanceMembersByName
223 .putIfAbsent(memberName, () => new Set<Element>()) 244 .putIfAbsent(memberName, () => new Set<Element>())
224 .add(member); 245 .add(member);
225 } 246 }
226 247
227 void enableIsolateSupport() {} 248 void enableIsolateSupport() {}
228 249
229 void processInstantiatedClass(ClassElement cls) { 250 void processInstantiatedClass(ClassElement cls) {
230 task.measure(() { 251 task.measure(() {
231 if (_processedClasses.contains(cls)) return; 252 if (_processedClasses.contains(cls)) return;
232 // The class must be resolved to compute the set of all
233 // supertypes.
234 cls.ensureResolved(resolution);
235 253
236 void processClass(ClassElement superclass) { 254 void processClass(ClassElement superclass) {
237 if (_processedClasses.contains(superclass)) return; 255 if (_processedClasses.contains(superclass)) return;
238 // TODO(johnniwinther): Re-insert this invariant when unittests don't 256 // TODO(johnniwinther): Re-insert this invariant when unittests don't
239 // fail. There is already a similar invariant on the members. 257 // fail. There is already a similar invariant on the members.
240 /*if (!isResolutionQueue) { 258 /*assert(invariant(superclass,
241 assert(invariant(superclass,
242 superclass.isClosure || 259 superclass.isClosure ||
243 compiler.enqueuer.resolution.isClassProcessed(superclass), 260 _compiler.enqueuer.resolution.isClassProcessed(superclass),
244 message: "Class $superclass has not been " 261 message: "Class $superclass has not been "
245 "processed in resolution.")); 262 "processed in resolution."));
246 }*/ 263 */
247 264
248 _processedClasses.add(superclass); 265 _processedClasses.add(superclass);
249 recentClasses.add(superclass); 266 recentClasses.add(superclass);
250 superclass.ensureResolved(resolution);
251 superclass.implementation.forEachMember(processInstantiatedClassMember); 267 superclass.implementation.forEachMember(processInstantiatedClassMember);
252 if (isResolutionQueue &&
253 !compiler.serialization.isDeserialized(superclass)) {
254 compiler.resolver.checkClass(superclass);
255 }
256 // We only tell the backend once that [superclass] was instantiated, so 268 // We only tell the backend once that [superclass] was instantiated, so
257 // any additional dependencies must be treated as global 269 // any additional dependencies must be treated as global
258 // dependencies. 270 // dependencies.
259 compiler.backend.registerInstantiatedClass( 271 backend.registerInstantiatedClass(superclass, this, globalDependencies);
260 superclass, this, compiler.globalDependencies);
261 } 272 }
262 273
263 ClassElement superclass = cls; 274 ClassElement superclass = cls;
264 while (superclass != null) { 275 while (superclass != null) {
265 processClass(superclass); 276 processClass(superclass);
266 superclass = superclass.superclass; 277 superclass = superclass.superclass;
267 } 278 }
268 }); 279 });
269 } 280 }
270 281
271 void registerDynamicUse(DynamicUse dynamicUse) { 282 void registerDynamicUse(DynamicUse dynamicUse) {
272 task.measure(() { 283 task.measure(() {
273 if (universe.registerDynamicUse(dynamicUse)) { 284 if (universe.registerDynamicUse(dynamicUse)) {
274 handleUnseenSelector(dynamicUse); 285 handleUnseenSelector(dynamicUse);
275 } 286 }
276 }); 287 });
277 } 288 }
278 289
279 void logEnqueueReflectiveAction(action, [msg = ""]) { 290 void logEnqueueReflectiveAction(action, [msg = ""]) {
280 if (TRACE_MIRROR_ENQUEUING) { 291 if (TRACE_MIRROR_ENQUEUING) {
281 print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg"); 292 print("MIRROR_ENQUEUE (C): $action $msg");
282 } 293 }
283 } 294 }
284 295
285 /// Enqeue the constructor [ctor] if it is required for reflection. 296 /// Enqeue the constructor [ctor] if it is required for reflection.
286 /// 297 ///
287 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 298 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
288 /// needed for reflection. 299 /// needed for reflection.
289 void enqueueReflectiveConstructor( 300 void enqueueReflectiveConstructor(
290 ConstructorElement ctor, bool enclosingWasIncluded) { 301 ConstructorElement ctor, bool enclosingWasIncluded) {
291 if (shouldIncludeElementDueToMirrors(ctor, 302 if (shouldIncludeElementDueToMirrors(ctor,
292 includedEnclosing: enclosingWasIncluded)) { 303 includedEnclosing: enclosingWasIncluded)) {
293 logEnqueueReflectiveAction(ctor); 304 logEnqueueReflectiveAction(ctor);
294 ClassElement cls = ctor.declaration.enclosingClass; 305 ClassElement cls = ctor.declaration.enclosingClass;
295 compiler.backend.registerInstantiatedType( 306 backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies,
296 cls.rawType, this, compiler.mirrorDependencies,
297 mirrorUsage: true); 307 mirrorUsage: true);
298 registerStaticUse(new StaticUse.foreignUse(ctor.declaration)); 308 registerStaticUse(new StaticUse.foreignUse(ctor.declaration));
299 } 309 }
300 } 310 }
301 311
302 /// Enqeue the member [element] if it is required for reflection. 312 /// Enqeue the member [element] if it is required for reflection.
303 /// 313 ///
304 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 314 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
305 /// needed for reflection. 315 /// needed for reflection.
306 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { 316 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) {
307 if (shouldIncludeElementDueToMirrors(element, 317 if (shouldIncludeElementDueToMirrors(element,
308 includedEnclosing: enclosingWasIncluded)) { 318 includedEnclosing: enclosingWasIncluded)) {
309 logEnqueueReflectiveAction(element); 319 logEnqueueReflectiveAction(element);
310 if (element.isTypedef) { 320 if (element.isTypedef) {
311 TypedefElement typedef = element; 321 // Do nothing.
312 typedef.ensureResolved(resolution);
313 compiler.world.allTypedefs.add(element);
314 } else if (Elements.isStaticOrTopLevel(element)) { 322 } else if (Elements.isStaticOrTopLevel(element)) {
315 registerStaticUse(new StaticUse.foreignUse(element.declaration)); 323 registerStaticUse(new StaticUse.foreignUse(element.declaration));
316 } else if (element.isInstanceMember) { 324 } else if (element.isInstanceMember) {
317 // We need to enqueue all members matching this one in subclasses, as 325 // We need to enqueue all members matching this one in subclasses, as
318 // well. 326 // well.
319 // TODO(herhut): Use TypedSelector.subtype for enqueueing 327 // TODO(herhut): Use TypedSelector.subtype for enqueueing
320 DynamicUse dynamicUse = 328 DynamicUse dynamicUse =
321 new DynamicUse(new Selector.fromElement(element), null); 329 new DynamicUse(new Selector.fromElement(element), null);
322 registerDynamicUse(dynamicUse); 330 registerDynamicUse(dynamicUse);
323 if (element.isField) { 331 if (element.isField) {
(...skipping 12 matching lines...) Expand all
336 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 344 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
337 /// needed for reflection. 345 /// needed for reflection.
338 void enqueueReflectiveElementsInClass(ClassElement cls, 346 void enqueueReflectiveElementsInClass(ClassElement cls,
339 Iterable<ClassElement> recents, bool enclosingWasIncluded) { 347 Iterable<ClassElement> recents, bool enclosingWasIncluded) {
340 if (cls.library.isInternalLibrary || cls.isInjected) return; 348 if (cls.library.isInternalLibrary || cls.isInjected) return;
341 bool includeClass = shouldIncludeElementDueToMirrors(cls, 349 bool includeClass = shouldIncludeElementDueToMirrors(cls,
342 includedEnclosing: enclosingWasIncluded); 350 includedEnclosing: enclosingWasIncluded);
343 if (includeClass) { 351 if (includeClass) {
344 logEnqueueReflectiveAction(cls, "register"); 352 logEnqueueReflectiveAction(cls, "register");
345 ClassElement decl = cls.declaration; 353 ClassElement decl = cls.declaration;
346 decl.ensureResolved(resolution); 354 backend.registerInstantiatedType(decl.rawType, this, mirrorDependencies,
347 compiler.backend.registerInstantiatedType(
348 decl.rawType, this, compiler.mirrorDependencies,
349 mirrorUsage: true); 355 mirrorUsage: true);
350 } 356 }
351 // If the class is never instantiated, we know nothing of it can possibly 357 // If the class is never instantiated, we know nothing of it can possibly
352 // be reflected upon. 358 // be reflected upon.
353 // TODO(herhut): Add a warning if a mirrors annotation cannot hit. 359 // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
354 if (recents.contains(cls.declaration)) { 360 if (recents.contains(cls.declaration)) {
355 logEnqueueReflectiveAction(cls, "members"); 361 logEnqueueReflectiveAction(cls, "members");
356 cls.constructors.forEach((Element element) { 362 cls.constructors.forEach((Element element) {
357 enqueueReflectiveConstructor(element, includeClass); 363 enqueueReflectiveConstructor(element, includeClass);
358 }); 364 });
359 cls.forEachClassMember((Member member) { 365 cls.forEachClassMember((Member member) {
360 enqueueReflectiveMember(member.element, includeClass); 366 enqueueReflectiveMember(member.element, includeClass);
361 }); 367 });
362 } 368 }
363 } 369 }
364 370
365 /// Enqeue special classes that might not be visible by normal means or that 371 /// Enqeue special classes that might not be visible by normal means or that
366 /// would not normally be enqueued: 372 /// would not normally be enqueued:
367 /// 373 ///
368 /// [Closure] is treated specially as it is the superclass of all closures. 374 /// [Closure] is treated specially as it is the superclass of all closures.
369 /// Although it is in an internal library, we mark it as reflectable. Note 375 /// Although it is in an internal library, we mark it as reflectable. Note
370 /// that none of its methods are reflectable, unless reflectable by 376 /// that none of its methods are reflectable, unless reflectable by
371 /// inheritance. 377 /// inheritance.
372 void enqueueReflectiveSpecialClasses() { 378 void enqueueReflectiveSpecialClasses() {
373 Iterable<ClassElement> classes = 379 Iterable<ClassElement> classes = backend.classesRequiredForReflection;
374 compiler.backend.classesRequiredForReflection;
375 for (ClassElement cls in classes) { 380 for (ClassElement cls in classes) {
376 if (compiler.backend.referencedFromMirrorSystem(cls)) { 381 if (backend.referencedFromMirrorSystem(cls)) {
377 logEnqueueReflectiveAction(cls); 382 logEnqueueReflectiveAction(cls);
378 cls.ensureResolved(resolution); 383 backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies,
379 compiler.backend.registerInstantiatedType(
380 cls.rawType, this, compiler.mirrorDependencies,
381 mirrorUsage: true); 384 mirrorUsage: true);
382 } 385 }
383 } 386 }
384 } 387 }
385 388
386 /// Enqeue all local members of the library [lib] if they are required for 389 /// Enqeue all local members of the library [lib] if they are required for
387 /// reflection. 390 /// reflection.
388 void enqueueReflectiveElementsInLibrary( 391 void enqueueReflectiveElementsInLibrary(
389 LibraryElement lib, Iterable<ClassElement> recents) { 392 LibraryElement lib, Iterable<ClassElement> recents) {
390 bool includeLibrary = 393 bool includeLibrary =
(...skipping 14 matching lines...) Expand all
405 if (!hasEnqueuedReflectiveElements) { 408 if (!hasEnqueuedReflectiveElements) {
406 logEnqueueReflectiveAction("!START enqueueAll"); 409 logEnqueueReflectiveAction("!START enqueueAll");
407 // First round of enqueuing, visit everything that is visible to 410 // First round of enqueuing, visit everything that is visible to
408 // also pick up static top levels, etc. 411 // also pick up static top levels, etc.
409 // Also, during the first round, consider all classes that have been seen 412 // Also, during the first round, consider all classes that have been seen
410 // as recently seen, as we do not know how many rounds of resolution might 413 // as recently seen, as we do not know how many rounds of resolution might
411 // have run before tree shaking is disabled and thus everything is 414 // have run before tree shaking is disabled and thus everything is
412 // enqueued. 415 // enqueued.
413 recents = _processedClasses.toSet(); 416 recents = _processedClasses.toSet();
414 reporter.log('Enqueuing everything'); 417 reporter.log('Enqueuing everything');
415 for (LibraryElement lib in compiler.libraryLoader.libraries) { 418 for (LibraryElement lib in _compiler.libraryLoader.libraries) {
416 enqueueReflectiveElementsInLibrary(lib, recents); 419 enqueueReflectiveElementsInLibrary(lib, recents);
417 } 420 }
418 enqueueReflectiveSpecialClasses(); 421 enqueueReflectiveSpecialClasses();
419 hasEnqueuedReflectiveElements = true; 422 hasEnqueuedReflectiveElements = true;
420 hasEnqueuedReflectiveStaticFields = true; 423 hasEnqueuedReflectiveStaticFields = true;
421 logEnqueueReflectiveAction("!DONE enqueueAll"); 424 logEnqueueReflectiveAction("!DONE enqueueAll");
422 } else if (recents.isNotEmpty) { 425 } else if (recents.isNotEmpty) {
423 // Keep looking at new classes until fixpoint is reached. 426 // Keep looking at new classes until fixpoint is reached.
424 logEnqueueReflectiveAction("!START enqueueRecents"); 427 logEnqueueReflectiveAction("!START enqueueRecents");
425 recents.forEach((ClassElement cls) { 428 recents.forEach((ClassElement cls) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 } 470 }
468 471
469 void _handleUnseenSelector(DynamicUse universeSelector) { 472 void _handleUnseenSelector(DynamicUse universeSelector) {
470 strategy.processDynamicUse(this, universeSelector); 473 strategy.processDynamicUse(this, universeSelector);
471 } 474 }
472 475
473 void handleUnseenSelectorInternal(DynamicUse dynamicUse) { 476 void handleUnseenSelectorInternal(DynamicUse dynamicUse) {
474 Selector selector = dynamicUse.selector; 477 Selector selector = dynamicUse.selector;
475 String methodName = selector.name; 478 String methodName = selector.name;
476 processInstanceMembers(methodName, (Element member) { 479 processInstanceMembers(methodName, (Element member) {
477 if (dynamicUse.appliesUnnamed(member, compiler.world)) { 480 if (dynamicUse.appliesUnnamed(member, _world)) {
478 if (member.isFunction && selector.isGetter) { 481 if (member.isFunction && selector.isGetter) {
479 registerClosurizedMember(member); 482 registerClosurizedMember(member);
480 } 483 }
481 addToWorkList(member); 484 addToWorkList(member);
482 return true; 485 return true;
483 } 486 }
484 return false; 487 return false;
485 }); 488 });
486 if (selector.isGetter) { 489 if (selector.isGetter) {
487 processInstanceFunctions(methodName, (Element member) { 490 processInstanceFunctions(methodName, (Element member) {
488 if (dynamicUse.appliesUnnamed(member, compiler.world)) { 491 if (dynamicUse.appliesUnnamed(member, _world)) {
489 registerClosurizedMember(member); 492 registerClosurizedMember(member);
490 return true; 493 return true;
491 } 494 }
492 return false; 495 return false;
493 }); 496 });
494 } 497 }
495 } 498 }
496 499
497 /** 500 /**
498 * Documentation wanted -- johnniwinther 501 * Documentation wanted -- johnniwinther
499 * 502 *
500 * Invariant: [element] must be a declaration element. 503 * Invariant: [element] must be a declaration element.
501 */ 504 */
502 void registerStaticUse(StaticUse staticUse) { 505 void registerStaticUse(StaticUse staticUse) {
503 strategy.processStaticUse(this, staticUse); 506 strategy.processStaticUse(this, staticUse);
504 } 507 }
505 508
506 void registerStaticUseInternal(StaticUse staticUse) { 509 void registerStaticUseInternal(StaticUse staticUse) {
507 Element element = staticUse.element; 510 Element element = staticUse.element;
508 assert(invariant(element, element.isDeclaration, 511 assert(invariant(element, element.isDeclaration,
509 message: "Element ${element} is not the declaration.")); 512 message: "Element ${element} is not the declaration."));
510 universe.registerStaticUse(staticUse); 513 universe.registerStaticUse(staticUse);
511 compiler.backend.registerStaticUse(element, this); 514 backend.registerStaticUse(element, this);
512 bool addElement = true; 515 bool addElement = true;
513 switch (staticUse.kind) { 516 switch (staticUse.kind) {
514 case StaticUseKind.STATIC_TEAR_OFF: 517 case StaticUseKind.STATIC_TEAR_OFF:
515 compiler.backend.registerGetOfStaticFunction(this); 518 backend.registerGetOfStaticFunction(this);
516 break; 519 break;
517 case StaticUseKind.FIELD_GET: 520 case StaticUseKind.FIELD_GET:
518 case StaticUseKind.FIELD_SET: 521 case StaticUseKind.FIELD_SET:
519 case StaticUseKind.CLOSURE: 522 case StaticUseKind.CLOSURE:
520 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and 523 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and
521 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. 524 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue.
522 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot 525 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot
523 // enqueue. 526 // enqueue.
524 addElement = false; 527 addElement = false;
525 break; 528 break;
(...skipping 13 matching lines...) Expand all
539 case TypeUseKind.INSTANTIATION: 542 case TypeUseKind.INSTANTIATION:
540 registerInstantiatedType(type); 543 registerInstantiatedType(type);
541 break; 544 break;
542 case TypeUseKind.INSTANTIATION: 545 case TypeUseKind.INSTANTIATION:
543 case TypeUseKind.IS_CHECK: 546 case TypeUseKind.IS_CHECK:
544 case TypeUseKind.AS_CAST: 547 case TypeUseKind.AS_CAST:
545 case TypeUseKind.CATCH_TYPE: 548 case TypeUseKind.CATCH_TYPE:
546 _registerIsCheck(type); 549 _registerIsCheck(type);
547 break; 550 break;
548 case TypeUseKind.CHECKED_MODE_CHECK: 551 case TypeUseKind.CHECKED_MODE_CHECK:
549 if (compiler.options.enableTypeAssertions) { 552 if (options.enableTypeAssertions) {
550 _registerIsCheck(type); 553 _registerIsCheck(type);
551 } 554 }
552 break; 555 break;
553 case TypeUseKind.TYPE_LITERAL: 556 case TypeUseKind.TYPE_LITERAL:
554 break; 557 break;
555 } 558 }
556 } 559 }
557 560
558 void _registerIsCheck(DartType type) { 561 void _registerIsCheck(DartType type) {
559 type = universe.registerIsCheck(type, compiler); 562 type = universe.registerIsCheck(type, _compiler);
560 // Even in checked mode, type annotations for return type and argument 563 // Even in checked mode, type annotations for return type and argument
561 // types do not imply type checks, so there should never be a check 564 // types do not imply type checks, so there should never be a check
562 // against the type variable of a typedef. 565 // against the type variable of a typedef.
563 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); 566 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
564 } 567 }
565 568
566 void registerCallMethodWithFreeTypeVariables(Element element) { 569 void registerCallMethodWithFreeTypeVariables(Element element) {
567 compiler.backend.registerCallMethodWithFreeTypeVariables( 570 backend.registerCallMethodWithFreeTypeVariables(
568 element, this, compiler.globalDependencies); 571 element, this, globalDependencies);
569 universe.callMethodsWithFreeTypeVariables.add(element); 572 universe.callMethodsWithFreeTypeVariables.add(element);
570 } 573 }
571 574
572 void registerClosurizedMember(TypedElement element) { 575 void registerClosurizedMember(TypedElement element) {
573 assert(element.isInstanceMember); 576 assert(element.isInstanceMember);
574 if (element.computeType(resolution).containsTypeVariables) { 577 if (element.type.containsTypeVariables) {
575 compiler.backend.registerClosureWithFreeTypeVariables( 578 backend.registerClosureWithFreeTypeVariables(
576 element, this, compiler.globalDependencies); 579 element, this, globalDependencies);
577 } 580 }
578 compiler.backend.registerBoundClosure(this); 581 backend.registerBoundClosure(this);
579 universe.closurizedMembers.add(element); 582 universe.closurizedMembers.add(element);
580 } 583 }
581 584
582 void forEach(void f(WorkItem work)) { 585 void forEach(void f(WorkItem work)) {
583 do { 586 do {
584 while (queue.isNotEmpty) { 587 while (queue.isNotEmpty) {
585 // TODO(johnniwinther): Find an optimal process order. 588 // TODO(johnniwinther): Find an optimal process order.
586 filter.processWorkItem(f, queue.removeLast()); 589 filter.processWorkItem(f, queue.removeLast());
587 } 590 }
588 List recents = recentClasses.toList(growable: false); 591 List recents = recentClasses.toList(growable: false);
589 recentClasses.clear(); 592 recentClasses.clear();
590 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); 593 if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
591 } while (queue.isNotEmpty || recentClasses.isNotEmpty); 594 } while (queue.isNotEmpty || recentClasses.isNotEmpty);
592 } 595 }
593 596
594 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses] 597 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
595 /// contains the set of all classes seen for the first time since 598 /// contains the set of all classes seen for the first time since
596 /// [onQueueEmpty] was called last. A return value of [true] indicates that 599 /// [onQueueEmpty] was called last. A return value of [true] indicates that
597 /// the [recentClasses] have been processed and may be cleared. If [false] is 600 /// the [recentClasses] have been processed and may be cleared. If [false] is
598 /// returned, [onQueueEmpty] will be called once the queue is empty again (or 601 /// returned, [onQueueEmpty] will be called once the queue is empty again (or
599 /// still empty) and [recentClasses] will be a superset of the current value. 602 /// still empty) and [recentClasses] will be a superset of the current value.
600 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { 603 bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
601 return compiler.backend.onQueueEmpty(this, recentClasses); 604 return backend.onQueueEmpty(this, recentClasses);
602 } 605 }
603 606
604 void logSummary(log(message)) { 607 void logSummary(log(message)) {
605 _logSpecificSummary(log); 608 _logSpecificSummary(log);
606 nativeEnqueuer.logSummary(log); 609 nativeEnqueuer.logSummary(log);
607 } 610 }
608 611
609 String toString() => 'Enqueuer($name)'; 612 String toString() => 'Enqueuer($name)';
610 613
611 void _forgetElement(Element element) { 614 void _forgetElement(Element element) {
612 universe.forgetElement(element, compiler); 615 universe.forgetElement(element, _compiler);
613 _processedClasses.remove(element); 616 _processedClasses.remove(element);
614 instanceMembersByName[element.name]?.remove(element); 617 instanceMembersByName[element.name]?.remove(element);
615 instanceFunctionsByName[element.name]?.remove(element); 618 instanceFunctionsByName[element.name]?.remove(element);
616 } 619 }
617 620
618 final Queue<CodegenWorkItem> queue; 621 final Queue<CodegenWorkItem> queue;
619 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; 622 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{};
620 623
621 final Set<Element> newlyEnqueuedElements; 624 final Set<Element> newlyEnqueuedElements;
622 625
(...skipping 11 matching lines...) Expand all
634 637
635 /** 638 /**
636 * Decides whether an element should be included to satisfy requirements 639 * Decides whether an element should be included to satisfy requirements
637 * of the mirror system. 640 * of the mirror system.
638 * 641 *
639 * For code generation, we rely on the precomputed set of elements that takes 642 * For code generation, we rely on the precomputed set of elements that takes
640 * subtyping constraints into account. 643 * subtyping constraints into account.
641 */ 644 */
642 bool shouldIncludeElementDueToMirrors(Element element, 645 bool shouldIncludeElementDueToMirrors(Element element,
643 {bool includedEnclosing}) { 646 {bool includedEnclosing}) {
644 return compiler.backend.isAccessibleByReflection(element); 647 return backend.isAccessibleByReflection(element);
645 }
646
647 /**
648 * Adds [element] to the work list if it has not already been processed.
649 *
650 * Returns [true] if the element was actually added to the queue.
651 */
652 bool internalAddToWorkList(Element element) {
653 // Don't generate code for foreign elements.
654 if (compiler.backend.isForeign(element)) return false;
655
656 // Codegen inlines field initializers. It only needs to generate
657 // code for checked setters.
658 if (element.isField && element.isInstanceMember) {
659 if (!compiler.options.enableTypeAssertions ||
660 element.enclosingElement.isClosure) {
661 return false;
662 }
663 }
664
665 if (compiler.options.hasIncrementalSupport && !isProcessed(element)) {
666 newlyEnqueuedElements.add(element);
667 }
668
669 if (queueIsClosed) {
670 throw new SpannableAssertionFailure(
671 element, "Codegen work list is closed. Trying to add $element");
672 }
673 queue.add(new CodegenWorkItem(compiler, element));
674 return true;
675 } 648 }
676 649
677 void registerNoSuchMethod(Element element) { 650 void registerNoSuchMethod(Element element) {
678 if (!enabledNoSuchMethod && compiler.backend.enabledNoSuchMethod) { 651 if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) {
679 compiler.backend.enableNoSuchMethod(this); 652 backend.enableNoSuchMethod(this);
680 enabledNoSuchMethod = true; 653 enabledNoSuchMethod = true;
681 } 654 }
682 } 655 }
683 656
684 void _logSpecificSummary(log(message)) { 657 void _logSpecificSummary(log(message)) {
685 log('Compiled ${generatedCode.length} methods.'); 658 log('Compiled ${generatedCode.length} methods.');
686 } 659 }
687 660
688 void forgetElement(Element element) { 661 void forgetElement(Element element) {
689 _forgetElement(element); 662 _forgetElement(element);
690 generatedCode.remove(element); 663 generatedCode.remove(element);
691 if (element is MemberElement) { 664 if (element is MemberElement) {
692 for (Element closure in element.nestedClosures) { 665 for (Element closure in element.nestedClosures) {
693 generatedCode.remove(closure); 666 generatedCode.remove(closure);
694 removeFromSet(instanceMembersByName, closure); 667 removeFromSet(instanceMembersByName, closure);
695 removeFromSet(instanceFunctionsByName, closure); 668 removeFromSet(instanceFunctionsByName, closure);
696 } 669 }
697 } 670 }
698 } 671 }
699 672
700 void handleUnseenSelector(DynamicUse dynamicUse) { 673 void handleUnseenSelector(DynamicUse dynamicUse) {
701 if (compiler.options.hasIncrementalSupport) { 674 if (options.hasIncrementalSupport) {
702 newlySeenSelectors.add(dynamicUse); 675 newlySeenSelectors.add(dynamicUse);
703 } 676 }
704 _handleUnseenSelector(dynamicUse); 677 _handleUnseenSelector(dynamicUse);
705 } 678 }
706 679
707 @override 680 @override
708 Iterable<Entity> get processedEntities => generatedCode.keys; 681 Iterable<Entity> get processedEntities => generatedCode.keys;
709 } 682 }
710 683
711 void removeFromSet(Map<String, Set<Element>> map, Element element) { 684 void removeFromSet(Map<String, Set<Element>> map, Element element) {
(...skipping 15 matching lines...) Expand all
727 @override 700 @override
728 void visitStaticUse(StaticUse staticUse) { 701 void visitStaticUse(StaticUse staticUse) {
729 enqueuer.registerStaticUse(staticUse); 702 enqueuer.registerStaticUse(staticUse);
730 } 703 }
731 704
732 @override 705 @override
733 void visitTypeUse(TypeUse typeUse) { 706 void visitTypeUse(TypeUse typeUse) {
734 enqueuer.registerTypeUse(typeUse); 707 enqueuer.registerTypeUse(typeUse);
735 } 708 }
736 } 709 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698