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

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)) { 181 addToWorkList(member);
182 return;
183 } else if (universe.hasInvokedSetter(member, _world)) {
157 addToWorkList(member); 184 addToWorkList(member);
158 return; 185 return;
159 } 186 }
160 if (universe.hasInvokedSetter(member, compiler.world)) {
161 addToWorkList(member);
162 return;
163 }
164 // Native fields need to go into instanceMembersByName as they 187 // Native fields need to go into instanceMembersByName as they
165 // are virtual instantiation points and escape points. 188 // are virtual instantiation points and escape points.
166 } else { 189 } else {
167 // All field initializers must be resolved as they could 190 // All field initializers must be resolved as they could
168 // have an observable side-effect (and cannot be tree-shaken 191 // have an observable side-effect (and cannot be tree-shaken
169 // away). 192 // away).
170 addToWorkList(member); 193 addToWorkList(member);
171 return; 194 return;
172 } 195 }
173 } else if (member.isFunction) { 196 } else if (member.isFunction) {
174 FunctionElement function = member; 197 FunctionElement function = member;
175 function.computeType(resolution);
176 if (function.name == Identifiers.noSuchMethod_) { 198 if (function.name == Identifiers.noSuchMethod_) {
177 registerNoSuchMethod(function); 199 registerNoSuchMethod(function);
178 } 200 }
179 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { 201 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
180 registerCallMethodWithFreeTypeVariables(function); 202 registerCallMethodWithFreeTypeVariables(function);
181 } 203 }
182 // If there is a property access with the same name as a method we 204 // If there is a property access with the same name as a method we
183 // need to emit the method. 205 // need to emit the method.
184 if (universe.hasInvokedGetter(function, compiler.world)) { 206 if (universe.hasInvokedGetter(function, _world)) {
185 registerClosurizedMember(function); 207 registerClosurizedMember(function);
186 addToWorkList(function); 208 addToWorkList(function);
187 return; 209 return;
188 } 210 }
189 // Store the member in [instanceFunctionsByName] to catch 211 // Store the member in [instanceFunctionsByName] to catch
190 // getters on the function. 212 // getters on the function.
191 instanceFunctionsByName 213 instanceFunctionsByName
192 .putIfAbsent(memberName, () => new Set<Element>()) 214 .putIfAbsent(memberName, () => new Set<Element>())
193 .add(member); 215 .add(member);
194 if (universe.hasInvocation(function, compiler.world)) { 216 if (universe.hasInvocation(function, _world)) {
195 addToWorkList(function); 217 addToWorkList(function);
196 return; 218 return;
197 } 219 }
198 } else if (member.isGetter) { 220 } else if (member.isGetter) {
199 FunctionElement getter = member; 221 FunctionElement getter = member;
200 getter.computeType(resolution); 222 if (universe.hasInvokedGetter(getter, _world)) {
201 if (universe.hasInvokedGetter(getter, compiler.world)) {
202 addToWorkList(getter); 223 addToWorkList(getter);
203 return; 224 return;
204 } 225 }
205 // We don't know what selectors the returned closure accepts. If 226 // We don't know what selectors the returned closure accepts. If
206 // the set contains any selector we have to assume that it matches. 227 // the set contains any selector we have to assume that it matches.
207 if (universe.hasInvocation(getter, compiler.world)) { 228 if (universe.hasInvocation(getter, _world)) {
208 addToWorkList(getter); 229 addToWorkList(getter);
209 return; 230 return;
210 } 231 }
211 } else if (member.isSetter) { 232 } else if (member.isSetter) {
212 FunctionElement setter = member; 233 FunctionElement setter = member;
213 setter.computeType(resolution); 234 if (universe.hasInvokedSetter(setter, _world)) {
214 if (universe.hasInvokedSetter(setter, compiler.world)) {
215 addToWorkList(setter); 235 addToWorkList(setter);
216 return; 236 return;
217 } 237 }
218 } 238 }
219 239
220 // The element is not yet used. Add it to the list of instance 240 // The element is not yet used. Add it to the list of instance
221 // members to still be processed. 241 // members to still be processed.
222 instanceMembersByName 242 instanceMembersByName
223 .putIfAbsent(memberName, () => new Set<Element>()) 243 .putIfAbsent(memberName, () => new Set<Element>())
224 .add(member); 244 .add(member);
225 } 245 }
226 246
227 void enableIsolateSupport() {} 247 void enableIsolateSupport() {}
228 248
229 void processInstantiatedClass(ClassElement cls) { 249 void processInstantiatedClass(ClassElement cls) {
230 task.measure(() { 250 task.measure(() {
231 if (_processedClasses.contains(cls)) return; 251 if (_processedClasses.contains(cls)) return;
232 // The class must be resolved to compute the set of all
233 // supertypes.
234 cls.ensureResolved(resolution);
235 252
236 void processClass(ClassElement superclass) { 253 void processClass(ClassElement superclass) {
237 if (_processedClasses.contains(superclass)) return; 254 if (_processedClasses.contains(superclass)) return;
238 // TODO(johnniwinther): Re-insert this invariant when unittests don't 255 // TODO(johnniwinther): Re-insert this invariant when unittests don't
239 // fail. There is already a similar invariant on the members. 256 // fail. There is already a similar invariant on the members.
240 /*if (!isResolutionQueue) { 257 /*assert(invariant(superclass,
241 assert(invariant(superclass,
242 superclass.isClosure || 258 superclass.isClosure ||
243 compiler.enqueuer.resolution.isClassProcessed(superclass), 259 _compiler.enqueuer.resolution.isClassProcessed(superclass),
244 message: "Class $superclass has not been " 260 message: "Class $superclass has not been "
245 "processed in resolution.")); 261 "processed in resolution."));
246 }*/ 262 */
247 263
248 _processedClasses.add(superclass); 264 _processedClasses.add(superclass);
249 recentClasses.add(superclass); 265 recentClasses.add(superclass);
250 superclass.ensureResolved(resolution);
251 superclass.implementation.forEachMember(processInstantiatedClassMember); 266 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 267 // We only tell the backend once that [superclass] was instantiated, so
257 // any additional dependencies must be treated as global 268 // any additional dependencies must be treated as global
258 // dependencies. 269 // dependencies.
259 compiler.backend.registerInstantiatedClass( 270 backend.registerInstantiatedClass(superclass, this, globalDependencies);
260 superclass, this, compiler.globalDependencies);
261 } 271 }
262 272
263 ClassElement superclass = cls; 273 ClassElement superclass = cls;
264 while (superclass != null) { 274 while (superclass != null) {
265 processClass(superclass); 275 processClass(superclass);
266 superclass = superclass.superclass; 276 superclass = superclass.superclass;
267 } 277 }
268 }); 278 });
269 } 279 }
270 280
271 void registerDynamicUse(DynamicUse dynamicUse) { 281 void registerDynamicUse(DynamicUse dynamicUse) {
272 task.measure(() { 282 task.measure(() {
273 if (universe.registerDynamicUse(dynamicUse)) { 283 if (universe.registerDynamicUse(dynamicUse)) {
274 handleUnseenSelector(dynamicUse); 284 handleUnseenSelector(dynamicUse);
275 } 285 }
276 }); 286 });
277 } 287 }
278 288
279 void logEnqueueReflectiveAction(action, [msg = ""]) { 289 void logEnqueueReflectiveAction(action, [msg = ""]) {
280 if (TRACE_MIRROR_ENQUEUING) { 290 if (TRACE_MIRROR_ENQUEUING) {
281 print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg"); 291 print("MIRROR_ENQUEUE (C): $action $msg");
282 } 292 }
283 } 293 }
284 294
285 /// Enqeue the constructor [ctor] if it is required for reflection. 295 /// Enqeue the constructor [ctor] if it is required for reflection.
286 /// 296 ///
287 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 297 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
288 /// needed for reflection. 298 /// needed for reflection.
289 void enqueueReflectiveConstructor( 299 void enqueueReflectiveConstructor(
290 ConstructorElement ctor, bool enclosingWasIncluded) { 300 ConstructorElement ctor, bool enclosingWasIncluded) {
291 if (shouldIncludeElementDueToMirrors(ctor, 301 if (shouldIncludeElementDueToMirrors(ctor,
292 includedEnclosing: enclosingWasIncluded)) { 302 includedEnclosing: enclosingWasIncluded)) {
293 logEnqueueReflectiveAction(ctor); 303 logEnqueueReflectiveAction(ctor);
294 ClassElement cls = ctor.declaration.enclosingClass; 304 ClassElement cls = ctor.declaration.enclosingClass;
295 compiler.backend.registerInstantiatedType( 305 backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies,
296 cls.rawType, this, compiler.mirrorDependencies,
297 mirrorUsage: true); 306 mirrorUsage: true);
298 registerStaticUse(new StaticUse.foreignUse(ctor.declaration)); 307 registerStaticUse(new StaticUse.foreignUse(ctor.declaration));
299 } 308 }
300 } 309 }
301 310
302 /// Enqeue the member [element] if it is required for reflection. 311 /// Enqeue the member [element] if it is required for reflection.
303 /// 312 ///
304 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 313 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
305 /// needed for reflection. 314 /// needed for reflection.
306 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { 315 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) {
307 if (shouldIncludeElementDueToMirrors(element, 316 if (shouldIncludeElementDueToMirrors(element,
308 includedEnclosing: enclosingWasIncluded)) { 317 includedEnclosing: enclosingWasIncluded)) {
309 logEnqueueReflectiveAction(element); 318 logEnqueueReflectiveAction(element);
310 if (element.isTypedef) { 319 if (element.isTypedef) {
311 TypedefElement typedef = element; 320 // Do nothing.
312 typedef.ensureResolved(resolution);
313 compiler.world.allTypedefs.add(element);
314 } else if (Elements.isStaticOrTopLevel(element)) { 321 } else if (Elements.isStaticOrTopLevel(element)) {
315 registerStaticUse(new StaticUse.foreignUse(element.declaration)); 322 registerStaticUse(new StaticUse.foreignUse(element.declaration));
316 } else if (element.isInstanceMember) { 323 } else if (element.isInstanceMember) {
317 // We need to enqueue all members matching this one in subclasses, as 324 // We need to enqueue all members matching this one in subclasses, as
318 // well. 325 // well.
319 // TODO(herhut): Use TypedSelector.subtype for enqueueing 326 // TODO(herhut): Use TypedSelector.subtype for enqueueing
320 DynamicUse dynamicUse = 327 DynamicUse dynamicUse =
321 new DynamicUse(new Selector.fromElement(element), null); 328 new DynamicUse(new Selector.fromElement(element), null);
322 registerDynamicUse(dynamicUse); 329 registerDynamicUse(dynamicUse);
323 if (element.isField) { 330 if (element.isField) {
(...skipping 12 matching lines...) Expand all
336 /// [enclosingWasIncluded] provides a hint whether the enclosing element was 343 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
337 /// needed for reflection. 344 /// needed for reflection.
338 void enqueueReflectiveElementsInClass(ClassElement cls, 345 void enqueueReflectiveElementsInClass(ClassElement cls,
339 Iterable<ClassElement> recents, bool enclosingWasIncluded) { 346 Iterable<ClassElement> recents, bool enclosingWasIncluded) {
340 if (cls.library.isInternalLibrary || cls.isInjected) return; 347 if (cls.library.isInternalLibrary || cls.isInjected) return;
341 bool includeClass = shouldIncludeElementDueToMirrors(cls, 348 bool includeClass = shouldIncludeElementDueToMirrors(cls,
342 includedEnclosing: enclosingWasIncluded); 349 includedEnclosing: enclosingWasIncluded);
343 if (includeClass) { 350 if (includeClass) {
344 logEnqueueReflectiveAction(cls, "register"); 351 logEnqueueReflectiveAction(cls, "register");
345 ClassElement decl = cls.declaration; 352 ClassElement decl = cls.declaration;
346 decl.ensureResolved(resolution); 353 backend.registerInstantiatedType(decl.rawType, this, mirrorDependencies,
347 compiler.backend.registerInstantiatedType(
348 decl.rawType, this, compiler.mirrorDependencies,
349 mirrorUsage: true); 354 mirrorUsage: true);
350 } 355 }
351 // If the class is never instantiated, we know nothing of it can possibly 356 // If the class is never instantiated, we know nothing of it can possibly
352 // be reflected upon. 357 // be reflected upon.
353 // TODO(herhut): Add a warning if a mirrors annotation cannot hit. 358 // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
354 if (recents.contains(cls.declaration)) { 359 if (recents.contains(cls.declaration)) {
355 logEnqueueReflectiveAction(cls, "members"); 360 logEnqueueReflectiveAction(cls, "members");
356 cls.constructors.forEach((Element element) { 361 cls.constructors.forEach((Element element) {
357 enqueueReflectiveConstructor(element, includeClass); 362 enqueueReflectiveConstructor(element, includeClass);
358 }); 363 });
359 cls.forEachClassMember((Member member) { 364 cls.forEachClassMember((Member member) {
360 enqueueReflectiveMember(member.element, includeClass); 365 enqueueReflectiveMember(member.element, includeClass);
361 }); 366 });
362 } 367 }
363 } 368 }
364 369
365 /// Enqeue special classes that might not be visible by normal means or that 370 /// Enqeue special classes that might not be visible by normal means or that
366 /// would not normally be enqueued: 371 /// would not normally be enqueued:
367 /// 372 ///
368 /// [Closure] is treated specially as it is the superclass of all closures. 373 /// [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 374 /// Although it is in an internal library, we mark it as reflectable. Note
370 /// that none of its methods are reflectable, unless reflectable by 375 /// that none of its methods are reflectable, unless reflectable by
371 /// inheritance. 376 /// inheritance.
372 void enqueueReflectiveSpecialClasses() { 377 void enqueueReflectiveSpecialClasses() {
373 Iterable<ClassElement> classes = 378 Iterable<ClassElement> classes = backend.classesRequiredForReflection;
374 compiler.backend.classesRequiredForReflection;
375 for (ClassElement cls in classes) { 379 for (ClassElement cls in classes) {
376 if (compiler.backend.referencedFromMirrorSystem(cls)) { 380 if (backend.referencedFromMirrorSystem(cls)) {
377 logEnqueueReflectiveAction(cls); 381 logEnqueueReflectiveAction(cls);
378 cls.ensureResolved(resolution); 382 backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies,
379 compiler.backend.registerInstantiatedType(
380 cls.rawType, this, compiler.mirrorDependencies,
381 mirrorUsage: true); 383 mirrorUsage: true);
382 } 384 }
383 } 385 }
384 } 386 }
385 387
386 /// Enqeue all local members of the library [lib] if they are required for 388 /// Enqeue all local members of the library [lib] if they are required for
387 /// reflection. 389 /// reflection.
388 void enqueueReflectiveElementsInLibrary( 390 void enqueueReflectiveElementsInLibrary(
389 LibraryElement lib, Iterable<ClassElement> recents) { 391 LibraryElement lib, Iterable<ClassElement> recents) {
390 bool includeLibrary = 392 bool includeLibrary =
(...skipping 14 matching lines...) Expand all
405 if (!hasEnqueuedReflectiveElements) { 407 if (!hasEnqueuedReflectiveElements) {
406 logEnqueueReflectiveAction("!START enqueueAll"); 408 logEnqueueReflectiveAction("!START enqueueAll");
407 // First round of enqueuing, visit everything that is visible to 409 // First round of enqueuing, visit everything that is visible to
408 // also pick up static top levels, etc. 410 // also pick up static top levels, etc.
409 // Also, during the first round, consider all classes that have been seen 411 // 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 412 // 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 413 // have run before tree shaking is disabled and thus everything is
412 // enqueued. 414 // enqueued.
413 recents = _processedClasses.toSet(); 415 recents = _processedClasses.toSet();
414 reporter.log('Enqueuing everything'); 416 reporter.log('Enqueuing everything');
415 for (LibraryElement lib in compiler.libraryLoader.libraries) { 417 for (LibraryElement lib in _compiler.libraryLoader.libraries) {
416 enqueueReflectiveElementsInLibrary(lib, recents); 418 enqueueReflectiveElementsInLibrary(lib, recents);
417 } 419 }
418 enqueueReflectiveSpecialClasses(); 420 enqueueReflectiveSpecialClasses();
419 hasEnqueuedReflectiveElements = true; 421 hasEnqueuedReflectiveElements = true;
420 hasEnqueuedReflectiveStaticFields = true; 422 hasEnqueuedReflectiveStaticFields = true;
421 logEnqueueReflectiveAction("!DONE enqueueAll"); 423 logEnqueueReflectiveAction("!DONE enqueueAll");
422 } else if (recents.isNotEmpty) { 424 } else if (recents.isNotEmpty) {
423 // Keep looking at new classes until fixpoint is reached. 425 // Keep looking at new classes until fixpoint is reached.
424 logEnqueueReflectiveAction("!START enqueueRecents"); 426 logEnqueueReflectiveAction("!START enqueueRecents");
425 recents.forEach((ClassElement cls) { 427 recents.forEach((ClassElement cls) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 } 469 }
468 470
469 void _handleUnseenSelector(DynamicUse universeSelector) { 471 void _handleUnseenSelector(DynamicUse universeSelector) {
470 strategy.processDynamicUse(this, universeSelector); 472 strategy.processDynamicUse(this, universeSelector);
471 } 473 }
472 474
473 void handleUnseenSelectorInternal(DynamicUse dynamicUse) { 475 void handleUnseenSelectorInternal(DynamicUse dynamicUse) {
474 Selector selector = dynamicUse.selector; 476 Selector selector = dynamicUse.selector;
475 String methodName = selector.name; 477 String methodName = selector.name;
476 processInstanceMembers(methodName, (Element member) { 478 processInstanceMembers(methodName, (Element member) {
477 if (dynamicUse.appliesUnnamed(member, compiler.world)) { 479 if (dynamicUse.appliesUnnamed(member, _world)) {
478 if (member.isFunction && selector.isGetter) { 480 if (member.isFunction && selector.isGetter) {
479 registerClosurizedMember(member); 481 registerClosurizedMember(member);
480 } 482 }
481 addToWorkList(member); 483 addToWorkList(member);
482 return true; 484 return true;
483 } 485 }
484 return false; 486 return false;
485 }); 487 });
486 if (selector.isGetter) { 488 if (selector.isGetter) {
487 processInstanceFunctions(methodName, (Element member) { 489 processInstanceFunctions(methodName, (Element member) {
488 if (dynamicUse.appliesUnnamed(member, compiler.world)) { 490 if (dynamicUse.appliesUnnamed(member, _world)) {
489 registerClosurizedMember(member); 491 registerClosurizedMember(member);
490 return true; 492 return true;
491 } 493 }
492 return false; 494 return false;
493 }); 495 });
494 } 496 }
495 } 497 }
496 498
497 /** 499 /**
498 * Documentation wanted -- johnniwinther 500 * Documentation wanted -- johnniwinther
499 * 501 *
500 * Invariant: [element] must be a declaration element. 502 * Invariant: [element] must be a declaration element.
501 */ 503 */
502 void registerStaticUse(StaticUse staticUse) { 504 void registerStaticUse(StaticUse staticUse) {
503 strategy.processStaticUse(this, staticUse); 505 strategy.processStaticUse(this, staticUse);
504 } 506 }
505 507
506 void registerStaticUseInternal(StaticUse staticUse) { 508 void registerStaticUseInternal(StaticUse staticUse) {
507 Element element = staticUse.element; 509 Element element = staticUse.element;
508 assert(invariant(element, element.isDeclaration, 510 assert(invariant(element, element.isDeclaration,
509 message: "Element ${element} is not the declaration.")); 511 message: "Element ${element} is not the declaration."));
510 universe.registerStaticUse(staticUse); 512 universe.registerStaticUse(staticUse);
511 compiler.backend.registerStaticUse(element, this); 513 backend.registerStaticUse(element, this);
512 bool addElement = true; 514 bool addElement = true;
513 switch (staticUse.kind) { 515 switch (staticUse.kind) {
514 case StaticUseKind.STATIC_TEAR_OFF: 516 case StaticUseKind.STATIC_TEAR_OFF:
515 compiler.backend.registerGetOfStaticFunction(this); 517 backend.registerGetOfStaticFunction(this);
516 break; 518 break;
517 case StaticUseKind.FIELD_GET: 519 case StaticUseKind.FIELD_GET:
518 case StaticUseKind.FIELD_SET: 520 case StaticUseKind.FIELD_SET:
519 case StaticUseKind.CLOSURE: 521 case StaticUseKind.CLOSURE:
520 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and 522 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and
521 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. 523 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue.
522 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot 524 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot
523 // enqueue. 525 // enqueue.
524 addElement = false; 526 addElement = false;
525 break; 527 break;
(...skipping 13 matching lines...) Expand all
539 case TypeUseKind.INSTANTIATION: 541 case TypeUseKind.INSTANTIATION:
540 registerInstantiatedType(type); 542 registerInstantiatedType(type);
541 break; 543 break;
542 case TypeUseKind.INSTANTIATION: 544 case TypeUseKind.INSTANTIATION:
543 case TypeUseKind.IS_CHECK: 545 case TypeUseKind.IS_CHECK:
544 case TypeUseKind.AS_CAST: 546 case TypeUseKind.AS_CAST:
545 case TypeUseKind.CATCH_TYPE: 547 case TypeUseKind.CATCH_TYPE:
546 _registerIsCheck(type); 548 _registerIsCheck(type);
547 break; 549 break;
548 case TypeUseKind.CHECKED_MODE_CHECK: 550 case TypeUseKind.CHECKED_MODE_CHECK:
549 if (compiler.options.enableTypeAssertions) { 551 if (options.enableTypeAssertions) {
550 _registerIsCheck(type); 552 _registerIsCheck(type);
551 } 553 }
552 break; 554 break;
553 case TypeUseKind.TYPE_LITERAL: 555 case TypeUseKind.TYPE_LITERAL:
554 break; 556 break;
555 } 557 }
556 } 558 }
557 559
558 void _registerIsCheck(DartType type) { 560 void _registerIsCheck(DartType type) {
559 type = universe.registerIsCheck(type, compiler); 561 type = universe.registerIsCheck(type, _compiler);
560 // Even in checked mode, type annotations for return type and argument 562 // 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 563 // types do not imply type checks, so there should never be a check
562 // against the type variable of a typedef. 564 // against the type variable of a typedef.
563 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); 565 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
564 } 566 }
565 567
566 void registerCallMethodWithFreeTypeVariables(Element element) { 568 void registerCallMethodWithFreeTypeVariables(Element element) {
567 compiler.backend.registerCallMethodWithFreeTypeVariables( 569 backend.registerCallMethodWithFreeTypeVariables(
568 element, this, compiler.globalDependencies); 570 element, this, globalDependencies);
569 universe.callMethodsWithFreeTypeVariables.add(element); 571 universe.callMethodsWithFreeTypeVariables.add(element);
570 } 572 }
571 573
572 void registerClosurizedMember(TypedElement element) { 574 void registerClosurizedMember(TypedElement element) {
573 assert(element.isInstanceMember); 575 assert(element.isInstanceMember);
574 if (element.computeType(resolution).containsTypeVariables) { 576 if (element.type.containsTypeVariables) {
575 compiler.backend.registerClosureWithFreeTypeVariables( 577 backend.registerClosureWithFreeTypeVariables(
576 element, this, compiler.globalDependencies); 578 element, this, globalDependencies);
577 } 579 }
578 compiler.backend.registerBoundClosure(this); 580 backend.registerBoundClosure(this);
579 universe.closurizedMembers.add(element); 581 universe.closurizedMembers.add(element);
580 } 582 }
581 583
582 void forEach(void f(WorkItem work)) { 584 void forEach(void f(WorkItem work)) {
583 do { 585 do {
584 while (queue.isNotEmpty) { 586 while (queue.isNotEmpty) {
585 // TODO(johnniwinther): Find an optimal process order. 587 // TODO(johnniwinther): Find an optimal process order.
586 filter.processWorkItem(f, queue.removeLast()); 588 filter.processWorkItem(f, queue.removeLast());
587 } 589 }
588 List recents = recentClasses.toList(growable: false); 590 List recents = recentClasses.toList(growable: false);
589 recentClasses.clear(); 591 recentClasses.clear();
590 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); 592 if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
591 } while (queue.isNotEmpty || recentClasses.isNotEmpty); 593 } while (queue.isNotEmpty || recentClasses.isNotEmpty);
592 } 594 }
593 595
594 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses] 596 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
595 /// contains the set of all classes seen for the first time since 597 /// contains the set of all classes seen for the first time since
596 /// [onQueueEmpty] was called last. A return value of [true] indicates that 598 /// [onQueueEmpty] was called last. A return value of [true] indicates that
597 /// the [recentClasses] have been processed and may be cleared. If [false] is 599 /// 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 600 /// 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. 601 /// still empty) and [recentClasses] will be a superset of the current value.
600 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { 602 bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
601 return compiler.backend.onQueueEmpty(this, recentClasses); 603 return backend.onQueueEmpty(this, recentClasses);
602 } 604 }
603 605
604 void logSummary(log(message)) { 606 void logSummary(log(message)) {
605 _logSpecificSummary(log); 607 _logSpecificSummary(log);
606 nativeEnqueuer.logSummary(log); 608 nativeEnqueuer.logSummary(log);
607 } 609 }
608 610
609 String toString() => 'Enqueuer($name)'; 611 String toString() => 'Enqueuer($name)';
610 612
611 void _forgetElement(Element element) { 613 void _forgetElement(Element element) {
612 universe.forgetElement(element, compiler); 614 universe.forgetElement(element, _compiler);
613 _processedClasses.remove(element); 615 _processedClasses.remove(element);
614 instanceMembersByName[element.name]?.remove(element); 616 instanceMembersByName[element.name]?.remove(element);
615 instanceFunctionsByName[element.name]?.remove(element); 617 instanceFunctionsByName[element.name]?.remove(element);
616 } 618 }
617 619
618 final Queue<CodegenWorkItem> queue; 620 final Queue<CodegenWorkItem> queue;
619 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; 621 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{};
620 622
621 final Set<Element> newlyEnqueuedElements; 623 final Set<Element> newlyEnqueuedElements;
622 624
(...skipping 11 matching lines...) Expand all
634 636
635 /** 637 /**
636 * Decides whether an element should be included to satisfy requirements 638 * Decides whether an element should be included to satisfy requirements
637 * of the mirror system. 639 * of the mirror system.
638 * 640 *
639 * For code generation, we rely on the precomputed set of elements that takes 641 * For code generation, we rely on the precomputed set of elements that takes
640 * subtyping constraints into account. 642 * subtyping constraints into account.
641 */ 643 */
642 bool shouldIncludeElementDueToMirrors(Element element, 644 bool shouldIncludeElementDueToMirrors(Element element,
643 {bool includedEnclosing}) { 645 {bool includedEnclosing}) {
644 return compiler.backend.isAccessibleByReflection(element); 646 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 } 647 }
676 648
677 void registerNoSuchMethod(Element element) { 649 void registerNoSuchMethod(Element element) {
678 if (!enabledNoSuchMethod && compiler.backend.enabledNoSuchMethod) { 650 if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) {
679 compiler.backend.enableNoSuchMethod(this); 651 backend.enableNoSuchMethod(this);
680 enabledNoSuchMethod = true; 652 enabledNoSuchMethod = true;
681 } 653 }
682 } 654 }
683 655
684 void _logSpecificSummary(log(message)) { 656 void _logSpecificSummary(log(message)) {
685 log('Compiled ${generatedCode.length} methods.'); 657 log('Compiled ${generatedCode.length} methods.');
686 } 658 }
687 659
688 void forgetElement(Element element) { 660 void forgetElement(Element element) {
689 _forgetElement(element); 661 _forgetElement(element);
690 generatedCode.remove(element); 662 generatedCode.remove(element);
691 if (element is MemberElement) { 663 if (element is MemberElement) {
692 for (Element closure in element.nestedClosures) { 664 for (Element closure in element.nestedClosures) {
693 generatedCode.remove(closure); 665 generatedCode.remove(closure);
694 removeFromSet(instanceMembersByName, closure); 666 removeFromSet(instanceMembersByName, closure);
695 removeFromSet(instanceFunctionsByName, closure); 667 removeFromSet(instanceFunctionsByName, closure);
696 } 668 }
697 } 669 }
698 } 670 }
699 671
700 void handleUnseenSelector(DynamicUse dynamicUse) { 672 void handleUnseenSelector(DynamicUse dynamicUse) {
701 if (compiler.options.hasIncrementalSupport) { 673 if (options.hasIncrementalSupport) {
702 newlySeenSelectors.add(dynamicUse); 674 newlySeenSelectors.add(dynamicUse);
703 } 675 }
704 _handleUnseenSelector(dynamicUse); 676 _handleUnseenSelector(dynamicUse);
705 } 677 }
706 678
707 @override 679 @override
708 Iterable<Entity> get processedEntities => generatedCode.keys; 680 Iterable<Entity> get processedEntities => generatedCode.keys;
709 } 681 }
710 682
711 void removeFromSet(Map<String, Set<Element>> map, Element element) { 683 void removeFromSet(Map<String, Set<Element>> map, Element element) {
(...skipping 15 matching lines...) Expand all
727 @override 699 @override
728 void visitStaticUse(StaticUse staticUse) { 700 void visitStaticUse(StaticUse staticUse) {
729 enqueuer.registerStaticUse(staticUse); 701 enqueuer.registerStaticUse(staticUse);
730 } 702 }
731 703
732 @override 704 @override
733 void visitTypeUse(TypeUse typeUse) { 705 void visitTypeUse(TypeUse typeUse) {
734 enqueuer.registerTypeUse(typeUse); 706 enqueuer.registerTypeUse(typeUse);
735 } 707 }
736 } 708 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698