OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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.mirrors_handler; | 5 library dart2js.mirrors_handler; |
6 | 6 |
7 import '../common/resolution.dart'; | 7 import '../common/resolution.dart'; |
8 import '../diagnostics/diagnostic_listener.dart'; | 8 import '../diagnostics/diagnostic_listener.dart'; |
9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
10 import '../enqueue.dart'; | |
11 import '../universe/selector.dart'; | 10 import '../universe/selector.dart'; |
12 import '../universe/use.dart'; | 11 import '../universe/use.dart'; |
| 12 import '../universe/world_impact.dart'; |
13 import 'backend.dart'; | 13 import 'backend.dart'; |
14 | 14 |
15 class MirrorsAnalysis { | 15 class MirrorsAnalysis { |
16 final MirrorsHandler resolutionHandler; | 16 final MirrorsHandler resolutionHandler; |
17 final MirrorsHandler codegenHandler; | 17 final MirrorsHandler codegenHandler; |
18 | 18 |
19 MirrorsAnalysis(JavaScriptBackend backend, Resolution resolution) | 19 MirrorsAnalysis(JavaScriptBackend backend, Resolution resolution) |
20 : resolutionHandler = new MirrorsHandler(backend, resolution), | 20 : resolutionHandler = new MirrorsHandler(backend, resolution), |
21 codegenHandler = new MirrorsHandler(backend, resolution); | 21 codegenHandler = new MirrorsHandler(backend, resolution); |
22 | 22 |
23 /// Enqueue all elements that are matched by the mirrors used | 23 /// Compute the impact for elements that are matched by the mirrors used |
24 /// annotation or, in lack thereof, all elements. | 24 /// annotation or, in lack thereof, all elements. |
25 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. | 25 WorldImpact computeImpactForReflectiveElements( |
26 void enqueueReflectiveElements( | |
27 Enqueuer enqueuer, | |
28 Iterable<ClassElement> recents, | 26 Iterable<ClassElement> recents, |
29 Iterable<LibraryElement> loadedLibraries) { | 27 Iterable<ClassElement> processedClasses, |
30 MirrorsHandler handler = | 28 Iterable<LibraryElement> loadedLibraries, |
31 enqueuer.isResolutionQueue ? resolutionHandler : codegenHandler; | 29 {bool forResolution}) { |
32 handler.enqueueReflectiveElements(enqueuer, recents, loadedLibraries); | 30 MirrorsHandler handler = forResolution ? resolutionHandler : codegenHandler; |
| 31 handler.enqueueReflectiveElements( |
| 32 recents, processedClasses, loadedLibraries); |
| 33 return handler.flush(); |
33 } | 34 } |
34 | 35 |
35 /// Enqueue the static fields that have been marked as used by reflective | 36 /// Compute the impact for the static fields that have been marked as used by |
36 /// usage through `MirrorsUsed`. | 37 /// reflective usage through `MirrorsUsed`. |
37 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. | 38 WorldImpact computeImpactForReflectiveStaticFields(Iterable<Element> elements, |
38 void enqueueReflectiveStaticFields( | 39 {bool forResolution}) { |
39 Enqueuer enqueuer, Iterable<Element> elements) { | 40 MirrorsHandler handler = forResolution ? resolutionHandler : codegenHandler; |
40 MirrorsHandler handler = | 41 handler.enqueueReflectiveStaticFields(elements); |
41 enqueuer.isResolutionQueue ? resolutionHandler : codegenHandler; | 42 return handler.flush(); |
42 handler.enqueueReflectiveStaticFields(enqueuer, elements); | |
43 } | 43 } |
44 } | 44 } |
45 | 45 |
46 class MirrorsHandler { | 46 class MirrorsHandler { |
47 static final TRACE_MIRROR_ENQUEUING = | 47 static final TRACE_MIRROR_ENQUEUING = |
48 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); | 48 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); |
49 | 49 |
50 final JavaScriptBackend _backend; | 50 final JavaScriptBackend _backend; |
51 final Resolution _resolution; | 51 final Resolution _resolution; |
52 | 52 |
53 bool hasEnqueuedReflectiveElements = false; | 53 bool hasEnqueuedReflectiveElements = false; |
54 bool hasEnqueuedReflectiveStaticFields = false; | 54 bool hasEnqueuedReflectiveStaticFields = false; |
55 | 55 |
| 56 StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder(); |
| 57 |
56 MirrorsHandler(this._backend, this._resolution); | 58 MirrorsHandler(this._backend, this._resolution); |
57 | 59 |
58 DiagnosticReporter get _reporter => _resolution.reporter; | 60 DiagnosticReporter get _reporter => _resolution.reporter; |
59 | 61 |
| 62 WorldImpact flush() => impactBuilder.flush(); |
| 63 |
60 void _logEnqueueReflectiveAction(action, [msg = ""]) { | 64 void _logEnqueueReflectiveAction(action, [msg = ""]) { |
61 if (TRACE_MIRROR_ENQUEUING) { | 65 if (TRACE_MIRROR_ENQUEUING) { |
62 print("MIRROR_ENQUEUE (R): $action $msg"); | 66 print("MIRROR_ENQUEUE (R): $action $msg"); |
63 } | 67 } |
64 } | 68 } |
65 | 69 |
66 /** | 70 /** |
67 * Decides whether an element should be included to satisfy requirements | 71 * Decides whether an element should be included to satisfy requirements |
68 * of the mirror system. | 72 * of the mirror system. |
69 * | 73 * |
70 * During resolution, we have to resort to matching elements against the | 74 * During resolution, we have to resort to matching elements against the |
71 * [MirrorsUsed] pattern, as we do not have a complete picture of the world, | 75 * [MirrorsUsed] pattern, as we do not have a complete picture of the world, |
72 * yet. | 76 * yet. |
73 */ | 77 */ |
74 bool _shouldIncludeElementDueToMirrors(Element element, | 78 bool _shouldIncludeElementDueToMirrors(Element element, |
75 {bool includedEnclosing}) { | 79 {bool includedEnclosing}) { |
76 return includedEnclosing || _backend.requiredByMirrorSystem(element); | 80 return includedEnclosing || _backend.requiredByMirrorSystem(element); |
77 } | 81 } |
78 | 82 |
79 /// Enqeue the constructor [ctor] if it is required for reflection. | 83 /// Enqeue the constructor [ctor] if it is required for reflection. |
80 /// | 84 /// |
81 /// [enclosingWasIncluded] provides a hint whether the enclosing element was | 85 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
82 /// needed for reflection. | 86 /// needed for reflection. |
83 void _enqueueReflectiveConstructor( | 87 void _enqueueReflectiveConstructor(ConstructorElement constructor, |
84 Enqueuer enqueuer, ConstructorElement constructor, | |
85 {bool enclosingWasIncluded}) { | 88 {bool enclosingWasIncluded}) { |
86 if (_shouldIncludeElementDueToMirrors(constructor, | 89 if (_shouldIncludeElementDueToMirrors(constructor, |
87 includedEnclosing: enclosingWasIncluded)) { | 90 includedEnclosing: enclosingWasIncluded)) { |
88 _logEnqueueReflectiveAction(constructor); | 91 _logEnqueueReflectiveAction(constructor); |
89 ClassElement cls = constructor.declaration.enclosingClass; | 92 ClassElement cls = constructor.declaration.enclosingClass; |
90 enqueuer.registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType)); | 93 impactBuilder |
91 enqueuer | 94 .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType)); |
| 95 impactBuilder |
92 .registerStaticUse(new StaticUse.foreignUse(constructor.declaration)); | 96 .registerStaticUse(new StaticUse.foreignUse(constructor.declaration)); |
93 } | 97 } |
94 } | 98 } |
95 | 99 |
96 /// Enqeue the member [element] if it is required for reflection. | 100 /// Enqeue the member [element] if it is required for reflection. |
97 /// | 101 /// |
98 /// [enclosingWasIncluded] provides a hint whether the enclosing element was | 102 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
99 /// needed for reflection. | 103 /// needed for reflection. |
100 void _enqueueReflectiveMember( | 104 void _enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { |
101 Enqueuer enqueuer, Element element, bool enclosingWasIncluded) { | |
102 if (_shouldIncludeElementDueToMirrors(element, | 105 if (_shouldIncludeElementDueToMirrors(element, |
103 includedEnclosing: enclosingWasIncluded)) { | 106 includedEnclosing: enclosingWasIncluded)) { |
104 _logEnqueueReflectiveAction(element); | 107 _logEnqueueReflectiveAction(element); |
105 if (element.isTypedef) { | 108 if (element.isTypedef) { |
106 TypedefElement typedef = element; | 109 TypedefElement typedef = element; |
107 typedef.ensureResolved(_resolution); | 110 typedef.ensureResolved(_resolution); |
108 } else if (Elements.isStaticOrTopLevel(element)) { | 111 } else if (Elements.isStaticOrTopLevel(element)) { |
109 enqueuer | 112 impactBuilder |
110 .registerStaticUse(new StaticUse.foreignUse(element.declaration)); | 113 .registerStaticUse(new StaticUse.foreignUse(element.declaration)); |
111 } else if (element.isInstanceMember) { | 114 } else if (element.isInstanceMember) { |
112 // We need to enqueue all members matching this one in subclasses, as | 115 // We need to enqueue all members matching this one in subclasses, as |
113 // well. | 116 // well. |
114 // TODO(herhut): Use TypedSelector.subtype for enqueueing | 117 // TODO(herhut): Use TypedSelector.subtype for enqueueing |
115 DynamicUse dynamicUse = | 118 DynamicUse dynamicUse = |
116 new DynamicUse(new Selector.fromElement(element), null); | 119 new DynamicUse(new Selector.fromElement(element), null); |
117 enqueuer.registerDynamicUse(dynamicUse); | 120 impactBuilder.registerDynamicUse(dynamicUse); |
118 if (element.isField) { | 121 if (element.isField) { |
119 DynamicUse dynamicUse = new DynamicUse( | 122 DynamicUse dynamicUse = new DynamicUse( |
120 new Selector.setter( | 123 new Selector.setter( |
121 new Name(element.name, element.library, isSetter: true)), | 124 new Name(element.name, element.library, isSetter: true)), |
122 null); | 125 null); |
123 enqueuer.registerDynamicUse(dynamicUse); | 126 impactBuilder.registerDynamicUse(dynamicUse); |
124 } | 127 } |
125 } | 128 } |
126 } | 129 } |
127 } | 130 } |
128 | 131 |
129 /// Enqeue the member [element] if it is required for reflection. | 132 /// Enqeue the member [element] if it is required for reflection. |
130 /// | 133 /// |
131 /// [enclosingWasIncluded] provides a hint whether the enclosing element was | 134 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
132 /// needed for reflection. | 135 /// needed for reflection. |
133 void _enqueueReflectiveElementsInClass( | 136 void _enqueueReflectiveElementsInClass( |
134 Enqueuer enqueuer, ClassElement cls, Iterable<ClassElement> recents, | 137 ClassElement cls, Iterable<ClassElement> recents, |
135 {bool enclosingWasIncluded}) { | 138 {bool enclosingWasIncluded}) { |
136 if (cls.library.isInternalLibrary || cls.isInjected) return; | 139 if (cls.library.isInternalLibrary || cls.isInjected) return; |
137 bool includeClass = _shouldIncludeElementDueToMirrors(cls, | 140 bool includeClass = _shouldIncludeElementDueToMirrors(cls, |
138 includedEnclosing: enclosingWasIncluded); | 141 includedEnclosing: enclosingWasIncluded); |
139 if (includeClass) { | 142 if (includeClass) { |
140 _logEnqueueReflectiveAction(cls, "register"); | 143 _logEnqueueReflectiveAction(cls, "register"); |
141 ClassElement declaration = cls.declaration; | 144 ClassElement declaration = cls.declaration; |
142 declaration.ensureResolved(_resolution); | 145 declaration.ensureResolved(_resolution); |
143 enqueuer.registerTypeUse( | 146 impactBuilder.registerTypeUse( |
144 new TypeUse.mirrorInstantiation(declaration.rawType)); | 147 new TypeUse.mirrorInstantiation(declaration.rawType)); |
145 } | 148 } |
146 // If the class is never instantiated, we know nothing of it can possibly | 149 // If the class is never instantiated, we know nothing of it can possibly |
147 // be reflected upon. | 150 // be reflected upon. |
148 // TODO(herhut): Add a warning if a mirrors annotation cannot hit. | 151 // TODO(herhut): Add a warning if a mirrors annotation cannot hit. |
149 if (recents.contains(cls.declaration)) { | 152 if (recents.contains(cls.declaration)) { |
150 _logEnqueueReflectiveAction(cls, "members"); | 153 _logEnqueueReflectiveAction(cls, "members"); |
151 cls.constructors.forEach((Element element) { | 154 cls.constructors.forEach((Element element) { |
152 _enqueueReflectiveConstructor(enqueuer, element, | 155 _enqueueReflectiveConstructor(element, |
153 enclosingWasIncluded: includeClass); | 156 enclosingWasIncluded: includeClass); |
154 }); | 157 }); |
155 cls.forEachClassMember((Member member) { | 158 cls.forEachClassMember((Member member) { |
156 _enqueueReflectiveMember(enqueuer, member.element, includeClass); | 159 _enqueueReflectiveMember(member.element, includeClass); |
157 }); | 160 }); |
158 } | 161 } |
159 } | 162 } |
160 | 163 |
161 /// Enqeue special classes that might not be visible by normal means or that | 164 /// Enqeue special classes that might not be visible by normal means or that |
162 /// would not normally be enqueued: | 165 /// would not normally be enqueued: |
163 /// | 166 /// |
164 /// [Closure] is treated specially as it is the superclass of all closures. | 167 /// [Closure] is treated specially as it is the superclass of all closures. |
165 /// Although it is in an internal library, we mark it as reflectable. Note | 168 /// Although it is in an internal library, we mark it as reflectable. Note |
166 /// that none of its methods are reflectable, unless reflectable by | 169 /// that none of its methods are reflectable, unless reflectable by |
167 /// inheritance. | 170 /// inheritance. |
168 void _enqueueReflectiveSpecialClasses(Enqueuer enqueuer) { | 171 void _enqueueReflectiveSpecialClasses() { |
169 Iterable<ClassElement> classes = _backend.classesRequiredForReflection; | 172 Iterable<ClassElement> classes = _backend.classesRequiredForReflection; |
170 for (ClassElement cls in classes) { | 173 for (ClassElement cls in classes) { |
171 if (_backend.referencedFromMirrorSystem(cls)) { | 174 if (_backend.referencedFromMirrorSystem(cls)) { |
172 _logEnqueueReflectiveAction(cls); | 175 _logEnqueueReflectiveAction(cls); |
173 cls.ensureResolved(_resolution); | 176 cls.ensureResolved(_resolution); |
174 enqueuer.registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType)); | 177 impactBuilder |
| 178 .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType)); |
175 } | 179 } |
176 } | 180 } |
177 } | 181 } |
178 | 182 |
179 /// Enqeue all local members of the library [lib] if they are required for | 183 /// Enqeue all local members of the library [lib] if they are required for |
180 /// reflection. | 184 /// reflection. |
181 void _enqueueReflectiveElementsInLibrary( | 185 void _enqueueReflectiveElementsInLibrary( |
182 Enqueuer enqueuer, LibraryElement lib, Iterable<ClassElement> recents) { | 186 LibraryElement lib, Iterable<ClassElement> recents) { |
183 bool includeLibrary = | 187 bool includeLibrary = |
184 _shouldIncludeElementDueToMirrors(lib, includedEnclosing: false); | 188 _shouldIncludeElementDueToMirrors(lib, includedEnclosing: false); |
185 lib.forEachLocalMember((Element member) { | 189 lib.forEachLocalMember((Element member) { |
186 if (member.isInjected) return; | 190 if (member.isInjected) return; |
187 if (member.isClass) { | 191 if (member.isClass) { |
188 _enqueueReflectiveElementsInClass(enqueuer, member, recents, | 192 _enqueueReflectiveElementsInClass(member, recents, |
189 enclosingWasIncluded: includeLibrary); | 193 enclosingWasIncluded: includeLibrary); |
190 } else { | 194 } else { |
191 _enqueueReflectiveMember(enqueuer, member, includeLibrary); | 195 _enqueueReflectiveMember(member, includeLibrary); |
192 } | 196 } |
193 }); | 197 }); |
194 } | 198 } |
195 | 199 |
196 /// Enqueue all elements that are matched by the mirrors used | 200 /// Enqueue all elements that are matched by the mirrors used |
197 /// annotation or, in lack thereof, all elements. | 201 /// annotation or, in lack thereof, all elements. |
198 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. | 202 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. |
199 void enqueueReflectiveElements( | 203 void enqueueReflectiveElements( |
200 Enqueuer enqueuer, | |
201 Iterable<ClassElement> recents, | 204 Iterable<ClassElement> recents, |
| 205 Iterable<ClassElement> processedClasses, |
202 Iterable<LibraryElement> loadedLibraries) { | 206 Iterable<LibraryElement> loadedLibraries) { |
203 if (!hasEnqueuedReflectiveElements) { | 207 if (!hasEnqueuedReflectiveElements) { |
204 _logEnqueueReflectiveAction("!START enqueueAll"); | 208 _logEnqueueReflectiveAction("!START enqueueAll"); |
205 // First round of enqueuing, visit everything that is visible to | 209 // First round of enqueuing, visit everything that is visible to |
206 // also pick up static top levels, etc. | 210 // also pick up static top levels, etc. |
207 // Also, during the first round, consider all classes that have been seen | 211 // Also, during the first round, consider all classes that have been seen |
208 // as recently seen, as we do not know how many rounds of resolution might | 212 // as recently seen, as we do not know how many rounds of resolution might |
209 // have run before tree shaking is disabled and thus everything is | 213 // have run before tree shaking is disabled and thus everything is |
210 // enqueued. | 214 // enqueued. |
211 recents = enqueuer.processedClasses.toSet(); | 215 recents = processedClasses.toSet(); |
212 _reporter.log('Enqueuing everything'); | 216 _reporter.log('Enqueuing everything'); |
213 for (LibraryElement lib in loadedLibraries) { | 217 for (LibraryElement lib in loadedLibraries) { |
214 _enqueueReflectiveElementsInLibrary(enqueuer, lib, recents); | 218 _enqueueReflectiveElementsInLibrary(lib, recents); |
215 } | 219 } |
216 _enqueueReflectiveSpecialClasses(enqueuer); | 220 _enqueueReflectiveSpecialClasses(); |
217 hasEnqueuedReflectiveElements = true; | 221 hasEnqueuedReflectiveElements = true; |
218 hasEnqueuedReflectiveStaticFields = true; | 222 hasEnqueuedReflectiveStaticFields = true; |
219 _logEnqueueReflectiveAction("!DONE enqueueAll"); | 223 _logEnqueueReflectiveAction("!DONE enqueueAll"); |
220 } else if (recents.isNotEmpty) { | 224 } else if (recents.isNotEmpty) { |
221 // Keep looking at new classes until fixpoint is reached. | 225 // Keep looking at new classes until fixpoint is reached. |
222 _logEnqueueReflectiveAction("!START enqueueRecents"); | 226 _logEnqueueReflectiveAction("!START enqueueRecents"); |
223 recents.forEach((ClassElement cls) { | 227 recents.forEach((ClassElement cls) { |
224 _enqueueReflectiveElementsInClass(enqueuer, cls, recents, | 228 _enqueueReflectiveElementsInClass(cls, recents, |
225 enclosingWasIncluded: _shouldIncludeElementDueToMirrors(cls.library, | 229 enclosingWasIncluded: _shouldIncludeElementDueToMirrors(cls.library, |
226 includedEnclosing: false)); | 230 includedEnclosing: false)); |
227 }); | 231 }); |
228 _logEnqueueReflectiveAction("!DONE enqueueRecents"); | 232 _logEnqueueReflectiveAction("!DONE enqueueRecents"); |
229 } | 233 } |
230 } | 234 } |
231 | 235 |
232 /// Enqueue the static fields that have been marked as used by reflective | 236 /// Enqueue the static fields that have been marked as used by reflective |
233 /// usage through `MirrorsUsed`. | 237 /// usage through `MirrorsUsed`. |
234 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. | 238 // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly. |
235 void enqueueReflectiveStaticFields( | 239 void enqueueReflectiveStaticFields(Iterable<Element> elements) { |
236 Enqueuer enqueuer, Iterable<Element> elements) { | |
237 if (hasEnqueuedReflectiveStaticFields) return; | 240 if (hasEnqueuedReflectiveStaticFields) return; |
238 hasEnqueuedReflectiveStaticFields = true; | 241 hasEnqueuedReflectiveStaticFields = true; |
239 for (Element element in elements) { | 242 for (Element element in elements) { |
240 _enqueueReflectiveMember(enqueuer, element, true); | 243 _enqueueReflectiveMember(element, true); |
241 } | 244 } |
242 } | 245 } |
243 } | 246 } |
OLD | NEW |