OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import '../closure.dart'; | 5 import '../closure.dart'; |
6 import '../common.dart'; | 6 import '../common.dart'; |
7 import '../common_elements.dart'; | 7 import '../common_elements.dart'; |
8 import '../compiler.dart'; | 8 import '../compiler.dart'; |
9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
11 import '../elements/resolution_types.dart'; | 11 import '../elements/entities.dart'; |
12 import '../elements/types.dart'; | |
12 import '../options.dart'; | 13 import '../options.dart'; |
13 import '../world.dart'; | 14 import '../world.dart'; |
14 import '../universe/world_builder.dart'; | 15 import '../universe/world_builder.dart'; |
15 import '../util/emptyset.dart'; | 16 import '../util/emptyset.dart'; |
16 import 'backend_helpers.dart'; | 17 import 'backend_helpers.dart'; |
17 import 'constant_handler_javascript.dart'; | 18 import 'constant_handler_javascript.dart'; |
18 | 19 |
19 abstract class MirrorsData { | 20 abstract class MirrorsData { |
20 /// True if a call to preserveMetadataMarker has been seen. This means that | 21 /// True if a call to preserveMetadataMarker has been seen. This means that |
21 /// metadata must be retained for dart:mirrors to work correctly. | 22 /// metadata must be retained for dart:mirrors to work correctly. |
(...skipping 18 matching lines...) Expand all Loading... | |
40 /// True if a call to disableTreeShaking has been seen. | 41 /// True if a call to disableTreeShaking has been seen. |
41 bool get isTreeShakingDisabled; | 42 bool get isTreeShakingDisabled; |
42 | 43 |
43 /// True if a call to preserveUris has been seen and the preserve-uris flag | 44 /// True if a call to preserveUris has been seen and the preserve-uris flag |
44 /// is set. | 45 /// is set. |
45 bool get mustPreserveUris; | 46 bool get mustPreserveUris; |
46 | 47 |
47 /// Set of symbols that the user has requested for reflection. | 48 /// Set of symbols that the user has requested for reflection. |
48 Iterable<String> get symbolsUsed; | 49 Iterable<String> get symbolsUsed; |
49 | 50 |
50 /// Set of elements that the user has requested for reflection. | 51 /// The members that the user has requested for reflection through the |
51 Iterable<Element> get targetsUsed; | 52 /// 'targets' property of a `MirrorsUsed` annotation. |
53 Iterable<MemberEntity> get membersInMirrorsUsedTargets; | |
52 | 54 |
53 /// Should [element] (a getter) that would normally not be generated due to | 55 /// The classes that the user has requested for reflection through the |
54 /// treeshaking be retained for reflection? | 56 /// 'targets' property of a `MirrorsUsed` annotation. |
55 bool shouldRetainGetter(Element element); | 57 Iterable<ClassEntity> get classesInMirrorsUsedTargets; |
56 | 58 |
57 /// Should [element] (a setter) hat would normally not be generated due to | 59 /// The libraries that the user has requested for reflection through the |
58 /// treeshaking be retained for reflection? | 60 /// 'targets' property of a `MirrorsUsed` annotation. |
59 bool shouldRetainSetter(Element element); | 61 Iterable<LibraryEntity> get librariesInMirrorsUsedTargets; |
62 | |
63 /// Should the getter for [element] that would normally not be generated due | |
64 /// to tree-shaking be retained for reflection? | |
65 bool shouldRetainGetter(FieldEntity element); | |
66 | |
67 /// Should the setter for [element] that would normally not be generated due | |
68 /// to tree-shaking be retained for reflection? | |
69 bool shouldRetainSetter(FieldEntity element); | |
60 | 70 |
61 /// Should [name] be retained for reflection? | 71 /// Should [name] be retained for reflection? |
62 bool shouldRetainName(String name); | 72 bool shouldRetainName(String name); |
63 | 73 |
64 /// Returns true if this element is covered by a mirrorsUsed annotation. | 74 /// Returns `true` if the class [element] is covered by a `MirrorsUsed` |
75 /// annotation. | |
65 /// | 76 /// |
66 /// Note that it might still be ok to tree shake the element away if no | 77 /// Note that it might still be ok to tree shake the element away if no |
67 /// reflection is used in the program (and thus [isTreeShakingDisabled] is | 78 /// reflection is used in the program (and thus [isTreeShakingDisabled] is |
68 /// still false). Therefore _do not_ use this predicate to decide inclusion | 79 /// still false). Therefore _do not_ use this predicate to decide inclusion |
69 /// in the tree, use [requiredByMirrorSystem] instead. | 80 /// in the tree, use [requiredByMirrorSystem] instead. |
70 bool referencedFromMirrorSystem(Element element, [recursive = true]); | 81 bool isClassReferencedFromMirrorSystem(ClassEntity element); |
71 | 82 |
72 /// Returns `true` if [element] can be accessed through reflection, that is, | 83 /// Returns `true` if the member [element] is covered by a `MirrorsUsed` |
73 /// is in the set of elements covered by a `MirrorsUsed` annotation. | 84 /// annotation. |
85 /// | |
86 /// Note that it might still be ok to tree shake the element away if no | |
87 /// reflection is used in the program (and thus [isTreeShakingDisabled] is | |
88 /// still false). Therefore _do not_ use this predicate to decide inclusion | |
89 /// in the tree, use [requiredByMirrorSystem] instead. | |
90 bool isMemberReferencedFromMirrorSystem(MemberEntity element); | |
91 | |
92 /// Returns `true` if the library [element] is covered by a `MirrorsUsed` | |
93 /// annotation. | |
94 bool isLibraryReferencedFromMirrorSystem(LibraryEntity element); | |
95 | |
96 /// Returns `true` if the typedef [element] needs reflection information at | |
97 /// runtime. | |
74 /// | 98 /// |
75 /// This property is used to tag emitted elements with a marker which is | 99 /// This property is used to tag emitted elements with a marker which is |
76 /// checked by the runtime system to throw an exception if an element is | 100 /// checked by the runtime system to throw an exception if an element is |
77 /// accessed (invoked, get, set) that is not accessible for the reflective | 101 /// accessed (invoked, get, set) that is not accessible for the reflective |
78 /// system. | 102 /// system. |
103 bool isTypedefAccessibleByReflection(TypedefElement element); | |
104 | |
105 /// Returns `true` if the class [element] needs reflection information at | |
106 /// runtime. | |
107 /// | |
108 /// This property is used to tag emitted elements with a marker which is | |
109 /// checked by the runtime system to throw an exception if an element is | |
110 /// accessed (invoked, get, set) that is not accessible for the reflective | |
111 /// system. | |
112 bool isClassAccessibleByReflection(ClassEntity element); | |
113 | |
114 /// Returns `true` if the member [element] needs reflection information at | |
115 /// runtime. | |
116 /// | |
117 /// This property is used to tag emitted elements with a marker which is | |
118 /// checked by the runtime system to throw an exception if an element is | |
119 /// accessed (invoked, get, set) that is not accessible for the reflective | |
120 /// system. | |
121 bool isMemberAccessibleByReflection(MemberEntity element); | |
122 | |
123 // TODO(johnniwinther): Remove this. | |
124 @deprecated | |
79 bool isAccessibleByReflection(Element element); | 125 bool isAccessibleByReflection(Element element); |
80 | 126 |
81 bool retainMetadataOf(Element element); | 127 bool retainMetadataOfLibrary(LibraryEntity element); |
128 bool retainMetadataOfTypedef(TypedefElement element); | |
129 bool retainMetadataOfClass(ClassEntity element); | |
130 bool retainMetadataOfMember(MemberEntity element); | |
131 bool retainMetadataOfParameter(ParameterElement element); | |
82 | 132 |
83 bool invokedReflectively(Element element); | 133 bool invokedReflectively(Element element); |
84 | 134 |
85 /// Returns `true` if this member element needs reflection information at | |
86 /// runtime. | |
87 bool isMemberAccessibleByReflection(MemberElement element); | |
88 | |
89 /// Returns true if this element has to be enqueued due to | 135 /// Returns true if this element has to be enqueued due to |
90 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if | 136 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if |
91 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). | 137 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). |
92 bool requiredByMirrorSystem(Element element); | 138 bool requiredByMirrorSystem(Element element); |
93 } | 139 } |
94 | 140 |
95 abstract class MirrorsDataBuilder { | 141 abstract class MirrorsDataBuilder { |
96 void registerUsedMember(MemberElement member); | 142 void registerUsedMember(MemberElement member); |
97 | 143 |
98 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed | 144 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 bool hasInsufficientMirrorsUsed = false; | 183 bool hasInsufficientMirrorsUsed = false; |
138 | 184 |
139 /// True if a call to preserveUris has been seen and the preserve-uris flag | 185 /// True if a call to preserveUris has been seen and the preserve-uris flag |
140 /// is set. | 186 /// is set. |
141 bool mustPreserveUris = false; | 187 bool mustPreserveUris = false; |
142 | 188 |
143 /// Set of symbols that the user has requested for reflection. | 189 /// Set of symbols that the user has requested for reflection. |
144 final Set<String> symbolsUsed = new Set<String>(); | 190 final Set<String> symbolsUsed = new Set<String>(); |
145 | 191 |
146 /// Set of elements that the user has requested for reflection. | 192 /// Set of elements that the user has requested for reflection. |
147 final Set<Element> targetsUsed = new Set<Element>(); | 193 final Set<MemberEntity> membersInMirrorsUsedTargets = new Set<MemberEntity>(); |
194 final Set<ClassEntity> classesInMirrorsUsedTargets = new Set<ClassEntity>(); | |
195 final Set<LibraryEntity> librariesInMirrorsUsedTargets = | |
196 new Set<LibraryEntity>(); | |
197 final Set<TypedefElement> _typedefsInMirrorsUsedTargets = | |
198 new Set<TypedefElement>(); | |
148 | 199 |
149 /// List of annotations provided by user that indicate that the annotated | 200 /// List of annotations provided by user that indicate that the annotated |
150 /// element must be retained. | 201 /// element must be retained. |
151 final Set<Element> metaTargetsUsed = new Set<Element>(); | 202 final Set<ClassEntity> metaTargetsUsed = new Set<ClassEntity>(); |
152 | 203 |
153 // TODO(johnniwinther): Avoid the need for this. | 204 // TODO(johnniwinther): Avoid the need for this. |
154 final Compiler _compiler; | 205 final Compiler _compiler; |
155 | 206 |
156 final CompilerOptions _options; | 207 final CompilerOptions _options; |
157 | 208 |
158 final CommonElements _commonElements; | 209 final CommonElements _commonElements; |
159 | 210 |
160 final BackendHelpers _helpers; | 211 final BackendHelpers _helpers; |
161 | 212 |
162 final JavaScriptConstantCompiler _constants; | 213 final JavaScriptConstantCompiler _constants; |
163 | 214 |
164 MirrorsDataImpl(this._compiler, this._options, this._commonElements, | 215 MirrorsDataImpl(this._compiler, this._options, this._commonElements, |
165 this._helpers, this._constants); | 216 this._helpers, this._constants); |
166 | 217 |
167 void registerUsedMember(MemberElement member) { | 218 void registerUsedMember(MemberElement member) { |
168 if (member == _helpers.disableTreeShakingMarker) { | 219 if (member == _helpers.disableTreeShakingMarker) { |
169 isTreeShakingDisabled = true; | 220 isTreeShakingDisabled = true; |
170 } else if (member == _helpers.preserveNamesMarker) { | 221 } else if (member == _helpers.preserveNamesMarker) { |
171 mustPreserveNames = true; | 222 mustPreserveNames = true; |
172 } else if (member == _helpers.preserveMetadataMarker) { | 223 } else if (member == _helpers.preserveMetadataMarker) { |
173 mustRetainMetadata = true; | 224 mustRetainMetadata = true; |
174 } else if (member == _helpers.preserveUrisMarker) { | 225 } else if (member == _helpers.preserveUrisMarker) { |
175 if (_options.preserveUris) mustPreserveUris = true; | 226 if (_options.preserveUris) mustPreserveUris = true; |
176 } else if (member == _helpers.preserveLibraryNamesMarker) { | 227 } else if (member == _helpers.preserveLibraryNamesMarker) { |
177 mustRetainLibraryNames = true; | 228 mustRetainLibraryNames = true; |
178 } | 229 } |
179 } | 230 } |
180 | 231 |
181 /// Should [element] (a getter) that would normally not be generated due to | 232 bool shouldRetainGetter(FieldElement element) { |
182 /// treeshaking be retained for reflection? | 233 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); |
183 bool shouldRetainGetter(Element element) { | |
184 return isTreeShakingDisabled && isAccessibleByReflection(element); | |
185 } | 234 } |
186 | 235 |
187 /// Should [element] (a setter) hat would normally not be generated due to | 236 bool shouldRetainSetter(FieldElement element) { |
188 /// treeshaking be retained for reflection? | 237 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); |
189 bool shouldRetainSetter(Element element) { | |
190 return isTreeShakingDisabled && isAccessibleByReflection(element); | |
191 } | 238 } |
192 | 239 |
193 /// Should [name] be retained for reflection? | 240 /// Should [name] be retained for reflection? |
194 bool shouldRetainName(String name) { | 241 bool shouldRetainName(String name) { |
195 if (hasInsufficientMirrorsUsed) return mustPreserveNames; | 242 if (hasInsufficientMirrorsUsed) return mustPreserveNames; |
196 if (name == '') return false; | 243 if (name == '') return false; |
197 return symbolsUsed.contains(name); | 244 return symbolsUsed.contains(name); |
198 } | 245 } |
199 | 246 |
200 bool retainMetadataOf(Element element) { | 247 @override |
248 bool retainMetadataOfParameter(ParameterElement element) { | |
201 if (mustRetainMetadata) hasRetainedMetadata = true; | 249 if (mustRetainMetadata) hasRetainedMetadata = true; |
202 if (mustRetainMetadata && referencedFromMirrorSystem(element)) { | 250 if (mustRetainMetadata && isParameterReferencedFromMirrorSystem(element)) { |
203 for (MetadataAnnotation metadata in element.metadata) { | 251 _retainMetadataOf(element); |
204 metadata.ensureResolved(_compiler.resolution); | |
205 ConstantValue constant = | |
206 _constants.getConstantValueForMetadata(metadata); | |
207 _constants.addCompileTimeConstantForEmission(constant); | |
208 } | |
209 return true; | 252 return true; |
210 } | 253 } |
211 return false; | 254 return false; |
212 } | 255 } |
213 | 256 |
257 @override | |
258 bool retainMetadataOfMember(MemberElement element) { | |
259 if (mustRetainMetadata) hasRetainedMetadata = true; | |
260 if (mustRetainMetadata && isMemberReferencedFromMirrorSystem(element)) { | |
Emily Fortuna
2017/04/04 18:27:13
any reason you don't write this as a nested loop l
Johnni Winther
2017/04/05 06:59:58
No _good_ reason. Changed.
| |
261 _retainMetadataOf(element); | |
262 return true; | |
263 } | |
264 return false; | |
265 } | |
266 | |
267 @override | |
268 bool retainMetadataOfClass(ClassElement element) { | |
269 if (mustRetainMetadata) hasRetainedMetadata = true; | |
270 if (mustRetainMetadata && isClassReferencedFromMirrorSystem(element)) { | |
271 _retainMetadataOf(element); | |
272 return true; | |
273 } | |
274 return false; | |
275 } | |
276 | |
277 @override | |
278 bool retainMetadataOfTypedef(TypedefElement element) { | |
279 if (mustRetainMetadata) hasRetainedMetadata = true; | |
280 if (mustRetainMetadata && isTypedefReferencedFromMirrorSystem(element)) { | |
281 _retainMetadataOf(element); | |
282 return true; | |
283 } | |
284 return false; | |
285 } | |
286 | |
287 @override | |
288 bool retainMetadataOfLibrary(LibraryElement element) { | |
289 if (mustRetainMetadata) hasRetainedMetadata = true; | |
290 if (mustRetainMetadata && isLibraryReferencedFromMirrorSystem(element)) { | |
291 _retainMetadataOf(element); | |
292 return true; | |
293 } | |
294 return false; | |
295 } | |
296 | |
297 void _retainMetadataOf(Element element) { | |
298 for (MetadataAnnotation metadata in element.metadata) { | |
299 metadata.ensureResolved(_compiler.resolution); | |
300 ConstantValue constant = _constants.getConstantValueForMetadata(metadata); | |
301 _constants.addCompileTimeConstantForEmission(constant); | |
302 } | |
303 } | |
304 | |
214 bool invokedReflectively(Element element) { | 305 bool invokedReflectively(Element element) { |
215 if (element.isParameter) { | 306 if (element.isParameter) { |
216 ParameterElement parameter = element; | 307 ParameterElement parameter = element; |
217 if (invokedReflectively(parameter.functionDeclaration)) return true; | 308 if (invokedReflectively(parameter.functionDeclaration)) return true; |
218 } | 309 } |
219 | 310 |
220 if (element.isField) { | 311 if (element.isField) { |
221 if (Elements.isStaticOrTopLevel(element) && | 312 if (Elements.isStaticOrTopLevel(element) && |
222 (element.isFinal || element.isConst)) { | 313 (element.isFinal || element.isConst)) { |
223 return false; | 314 return false; |
224 } | 315 } |
225 } | 316 } |
226 | 317 |
227 return isAccessibleByReflection(element.declaration); | 318 return isAccessibleByReflection(element.declaration); |
228 } | 319 } |
229 | 320 |
230 /// Set of methods that are needed by reflection. Computed using | 321 /// Sets of elements that are needed by reflection. Computed using |
231 /// [computeMembersNeededForReflection] on first use. | 322 /// [computeMembersNeededForReflection] on first use. |
232 Set<Element> _membersNeededForReflection = null; | 323 Set<ClassElement> _classesNeededForReflection; |
233 Iterable<Element> get membersNeededForReflection { | 324 Set<TypedefElement> _typedefsNeededForReflection; |
234 assert(_membersNeededForReflection != null); | 325 Set<MemberElement> _membersNeededForReflection; |
235 return _membersNeededForReflection; | 326 Set<LocalFunctionElement> _closuresNeededForReflection; |
236 } | |
237 | 327 |
238 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed | 328 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed |
239 /// annotations. The arguments corresponds to the unions of the corresponding | 329 /// annotations. The arguments corresponds to the unions of the corresponding |
240 /// fields of the annotations. | 330 /// fields of the annotations. |
331 // TODO(johnniwinther): Change type of [metaTargets] to `Set<ClassEntity>`. | |
241 void registerMirrorUsage( | 332 void registerMirrorUsage( |
242 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { | 333 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { |
243 if (symbols == null && targets == null && metaTargets == null) { | 334 if (symbols == null && targets == null && metaTargets == null) { |
244 // The user didn't specify anything, or there are imports of | 335 // The user didn't specify anything, or there are imports of |
245 // 'dart:mirrors' without @MirrorsUsed. | 336 // 'dart:mirrors' without @MirrorsUsed. |
246 hasInsufficientMirrorsUsed = true; | 337 hasInsufficientMirrorsUsed = true; |
247 return; | 338 return; |
248 } | 339 } |
249 if (symbols != null) symbolsUsed.addAll(symbols); | 340 if (symbols != null) symbolsUsed.addAll(symbols); |
250 if (targets != null) { | 341 if (targets != null) { |
251 for (Element target in targets) { | 342 for (Element target in targets) { |
252 if (target.isAbstractField) { | 343 if (target.isAbstractField) { |
253 AbstractFieldElement field = target; | 344 AbstractFieldElement field = target; |
254 targetsUsed.add(field.getter); | 345 if (field.getter != null) { |
255 targetsUsed.add(field.setter); | 346 membersInMirrorsUsedTargets.add(field.getter); |
256 } else { | 347 } |
257 targetsUsed.add(target); | 348 if (field.setter != null) { |
349 membersInMirrorsUsedTargets.add(field.setter); | |
350 } | |
351 } else if (target.isClass) { | |
352 classesInMirrorsUsedTargets.add(target as ClassEntity); | |
353 } else if (target.isTypedef) { | |
354 _typedefsInMirrorsUsedTargets.add(target); | |
355 } else if (target.isLibrary) { | |
356 librariesInMirrorsUsedTargets.add(target as LibraryEntity); | |
357 } else if (target != null) { | |
358 membersInMirrorsUsedTargets.add(target as MemberEntity); | |
258 } | 359 } |
259 } | 360 } |
260 } | 361 } |
261 if (metaTargets != null) metaTargetsUsed.addAll(metaTargets); | 362 if (metaTargets != null) { |
363 for (var element in metaTargets) { | |
364 if (element is ClassEntity) { | |
365 metaTargetsUsed.add(element); | |
366 } | |
367 } | |
368 } | |
262 } | 369 } |
263 | 370 |
264 /// Returns `true` if [element] can be accessed through reflection, that is, | 371 @override |
265 /// is in the set of elements covered by a `MirrorsUsed` annotation. | 372 bool isClassAccessibleByReflection(ClassElement element) { |
266 /// | 373 return _classesNeededForReflection.contains(_getDartClass(element)); |
267 /// This property is used to tag emitted elements with a marker which is | 374 } |
268 /// checked by the runtime system to throw an exception if an element is | 375 |
269 /// accessed (invoked, get, set) that is not accessible for the reflective | 376 @override |
270 /// system. | 377 bool isTypedefAccessibleByReflection(TypedefElement element) { |
378 return _typedefsNeededForReflection.contains(element); | |
379 } | |
380 | |
271 bool isAccessibleByReflection(Element element) { | 381 bool isAccessibleByReflection(Element element) { |
272 if (element.isClass) { | 382 if (element.isLibrary) { |
273 element = _getDartClass(element); | 383 return false; |
384 } else if (element.isClass) { | |
385 return isClassAccessibleByReflection(element); | |
386 } else if (element.isTypedef) { | |
387 return isTypedefAccessibleByReflection(element); | |
388 } else { | |
389 return isMemberAccessibleByReflection(element); | |
274 } | 390 } |
275 return membersNeededForReflection.contains(element); | |
276 } | 391 } |
277 | 392 |
278 ClassElement _getDartClass(ClassElement cls) { | 393 ClassElement _getDartClass(ClassElement cls) { |
279 if (cls == _helpers.jsIntClass) { | 394 if (cls == _helpers.jsIntClass) { |
280 return _commonElements.intClass; | 395 return _commonElements.intClass; |
281 } else if (cls == _helpers.jsBoolClass) { | 396 } else if (cls == _helpers.jsBoolClass) { |
282 return _commonElements.boolClass; | 397 return _commonElements.boolClass; |
283 } else if (cls == _helpers.jsNumberClass) { | 398 } else if (cls == _helpers.jsNumberClass) { |
284 return _commonElements.numClass; | 399 return _commonElements.numClass; |
285 } else if (cls == _helpers.jsDoubleClass) { | 400 } else if (cls == _helpers.jsDoubleClass) { |
286 return _commonElements.doubleClass; | 401 return _commonElements.doubleClass; |
287 } else if (cls == _helpers.jsStringClass) { | 402 } else if (cls == _helpers.jsStringClass) { |
288 return _commonElements.stringClass; | 403 return _commonElements.stringClass; |
289 } else if (cls == _helpers.jsArrayClass) { | 404 } else if (cls == _helpers.jsArrayClass) { |
290 return _commonElements.listClass; | 405 return _commonElements.listClass; |
291 } else if (cls == _helpers.jsNullClass) { | 406 } else if (cls == _helpers.jsNullClass) { |
292 return _commonElements.nullClass; | 407 return _commonElements.nullClass; |
293 } else { | 408 } else { |
294 return cls; | 409 return cls; |
295 } | 410 } |
296 } | 411 } |
297 | 412 |
298 /// Returns `true` if this member element needs reflection information at | |
299 /// runtime. | |
300 bool isMemberAccessibleByReflection(MemberElement element) { | 413 bool isMemberAccessibleByReflection(MemberElement element) { |
301 return membersNeededForReflection.contains(element); | 414 return _membersNeededForReflection.contains(element); |
302 } | 415 } |
303 | 416 |
304 /// Returns true if this element has to be enqueued due to | 417 /// Returns true if this element has to be enqueued due to |
305 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if | 418 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if |
306 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). | 419 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). |
307 bool requiredByMirrorSystem(Element element) { | 420 bool requiredByMirrorSystem(Element element) { |
308 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || | 421 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || |
309 matchesMirrorsMetaTarget(element) || | 422 matchesMirrorsMetaTarget(element) || |
310 targetsUsed.contains(element); | 423 classesInMirrorsUsedTargets.contains(element) || |
424 membersInMirrorsUsedTargets.contains(element) || | |
425 librariesInMirrorsUsedTargets.contains(element) || | |
426 _typedefsInMirrorsUsedTargets.contains(element); | |
311 } | 427 } |
312 | 428 |
313 /// Returns true if this element is covered by a mirrorsUsed annotation. | 429 @override |
314 /// | 430 bool isLibraryReferencedFromMirrorSystem(LibraryElement element) { |
315 /// Note that it might still be ok to tree shake the element away if no | 431 return _libraryReferencedFromMirrorSystem(element); |
316 /// reflection is used in the program (and thus [isTreeShakingDisabled] is | 432 } |
317 /// still false). Therefore _do not_ use this predicate to decide inclusion | |
318 /// in the tree, use [requiredByMirrorSystem] instead. | |
319 bool referencedFromMirrorSystem(Element element, [recursive = true]) { | |
320 Element enclosing = recursive ? element.enclosingElement : null; | |
321 | 433 |
434 @override | |
435 bool isMemberReferencedFromMirrorSystem(MemberElement element) { | |
436 if (_memberReferencedFromMirrorSystem(element)) return true; | |
437 if (element.enclosingClass != null) { | |
438 return isClassReferencedFromMirrorSystem(element.enclosingClass); | |
439 } else { | |
440 return isLibraryReferencedFromMirrorSystem(element.library); | |
441 } | |
442 } | |
443 | |
444 @override | |
445 bool isClassReferencedFromMirrorSystem(ClassElement element) { | |
446 return _classReferencedFromMirrorSystem(element) || | |
447 isLibraryReferencedFromMirrorSystem(element.library); | |
448 } | |
449 | |
450 bool isParameterReferencedFromMirrorSystem(ParameterElement element) { | |
451 return _parameterReferencedFromMirrorSystem(element) || | |
452 isMemberReferencedFromMirrorSystem(element.memberContext); | |
453 } | |
454 | |
455 bool isTypedefReferencedFromMirrorSystem(TypedefElement element) { | |
456 return _typedefReferencedFromMirrorSystem(element) || | |
457 isLibraryReferencedFromMirrorSystem(element.library); | |
458 } | |
459 | |
460 bool _memberReferencedFromMirrorSystem(MemberElement element) { | |
322 return hasInsufficientMirrorsUsed || | 461 return hasInsufficientMirrorsUsed || |
323 matchesMirrorsMetaTarget(element) || | 462 matchesMirrorsMetaTarget(element) || |
324 targetsUsed.contains(element) || | 463 membersInMirrorsUsedTargets.contains(element); |
325 (enclosing != null && referencedFromMirrorSystem(enclosing)); | 464 } |
465 | |
466 bool _parameterReferencedFromMirrorSystem(ParameterElement element) { | |
467 return hasInsufficientMirrorsUsed || matchesMirrorsMetaTarget(element); | |
468 } | |
469 | |
470 bool _classReferencedFromMirrorSystem(ClassElement element) { | |
471 return hasInsufficientMirrorsUsed || | |
472 matchesMirrorsMetaTarget(element) || | |
473 classesInMirrorsUsedTargets.contains(element); | |
474 } | |
475 | |
476 bool _typedefReferencedFromMirrorSystem(TypedefElement element) { | |
477 return hasInsufficientMirrorsUsed || | |
478 matchesMirrorsMetaTarget(element) || | |
479 _typedefsInMirrorsUsedTargets.contains(element); | |
480 } | |
481 | |
482 bool _libraryReferencedFromMirrorSystem(LibraryElement element) { | |
483 return hasInsufficientMirrorsUsed || | |
484 matchesMirrorsMetaTarget(element) || | |
485 librariesInMirrorsUsedTargets.contains(element); | |
326 } | 486 } |
327 | 487 |
328 /** | 488 /** |
329 * Returns `true` if the element is needed because it has an annotation | 489 * Returns `true` if the element is needed because it has an annotation |
330 * of a type that is used as a meta target for reflection. | 490 * of a type that is used as a meta target for reflection. |
331 */ | 491 */ |
332 bool matchesMirrorsMetaTarget(Element element) { | 492 bool matchesMirrorsMetaTarget(Element element) { |
333 if (metaTargetsUsed.isEmpty) return false; | 493 if (metaTargetsUsed.isEmpty) return false; |
334 for (MetadataAnnotation metadata in element.metadata) { | 494 for (MetadataAnnotation metadata in element.metadata) { |
335 // TODO(kasperl): It would be nice if we didn't have to resolve | 495 // TODO(kasperl): It would be nice if we didn't have to resolve |
336 // all metadata but only stuff that potentially would match one | 496 // all metadata but only stuff that potentially would match one |
337 // of the used meta targets. | 497 // of the used meta targets. |
338 metadata.ensureResolved(_compiler.resolution); | 498 metadata.ensureResolved(_compiler.resolution); |
339 ConstantValue value = | 499 ConstantValue value = |
340 _compiler.constants.getConstantValue(metadata.constant); | 500 _compiler.constants.getConstantValue(metadata.constant); |
341 if (value == null) continue; | 501 if (value == null) continue; |
342 ResolutionDartType type = value.getType(_commonElements); | 502 DartType type = value.getType(_commonElements); |
343 if (metaTargetsUsed.contains(type.element)) return true; | 503 if (type is InterfaceType && metaTargetsUsed.contains(type.element)) |
504 return true; | |
344 } | 505 } |
345 return false; | 506 return false; |
346 } | 507 } |
347 | 508 |
348 /** | 509 /** |
349 * Visits all classes and computes whether its members are needed for | 510 * Visits all classes and computes whether its members are needed for |
350 * reflection. | 511 * reflection. |
351 * | 512 * |
352 * We have to precompute this set as we cannot easily answer the need for | 513 * We have to precompute this set as we cannot easily answer the need for |
353 * reflection locally when looking at the member: We lack the information by | 514 * reflection locally when looking at the member: We lack the information by |
354 * which classes a member is inherited. Called after resolution is complete. | 515 * which classes a member is inherited. Called after resolution is complete. |
355 * | 516 * |
356 * We filter out private libraries here, as their elements should not | 517 * We filter out private libraries here, as their elements should not |
357 * be visible by reflection unless some other interfaces makes them | 518 * be visible by reflection unless some other interfaces makes them |
358 * accessible. | 519 * accessible. |
359 */ | 520 */ |
360 void computeMembersNeededForReflection( | 521 void computeMembersNeededForReflection( |
361 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { | 522 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { |
362 if (_membersNeededForReflection != null) return; | 523 if (_membersNeededForReflection != null) return; |
363 if (closedWorld.commonElements.mirrorsLibrary == null) { | 524 if (closedWorld.commonElements.mirrorsLibrary == null) { |
364 _membersNeededForReflection = const ImmutableEmptySet<Element>(); | 525 _classesNeededForReflection = const ImmutableEmptySet<ClassElement>(); |
526 _typedefsNeededForReflection = const ImmutableEmptySet<TypedefElement>(); | |
527 _membersNeededForReflection = const ImmutableEmptySet<MemberElement>(); | |
528 _closuresNeededForReflection = | |
529 const ImmutableEmptySet<LocalFunctionElement>(); | |
365 return; | 530 return; |
366 } | 531 } |
532 _classesNeededForReflection = new Set<ClassElement>(); | |
533 _typedefsNeededForReflection = new Set<TypedefElement>(); | |
534 _membersNeededForReflection = new Set<MemberElement>(); | |
535 _closuresNeededForReflection = new Set<LocalFunctionElement>(); | |
536 | |
367 // Compute a mapping from class to the closures it contains, so we | 537 // Compute a mapping from class to the closures it contains, so we |
368 // can include the correct ones when including the class. | 538 // can include the correct ones when including the class. |
369 Map<ClassElement, List<LocalFunctionElement>> closureMap = | 539 Map<ClassElement, List<LocalFunctionElement>> closureMap = |
370 new Map<ClassElement, List<LocalFunctionElement>>(); | 540 new Map<ClassElement, List<LocalFunctionElement>>(); |
371 for (LocalFunctionElement closure in worldBuilder.localFunctions) { | 541 for (LocalFunctionElement closure in worldBuilder.localFunctions) { |
372 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure); | 542 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure); |
373 } | 543 } |
374 bool foundClosure = false; | 544 bool foundClosure = false; |
375 Set<Element> reflectableMembers = new Set<Element>(); | |
376 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { | 545 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { |
377 // Do not process internal classes. | 546 // Do not process internal classes. |
378 if (cls.library.isInternalLibrary || cls.isInjected) continue; | 547 if (cls.library.isInternalLibrary || cls.isInjected) continue; |
379 if (referencedFromMirrorSystem(cls)) { | 548 if (isClassReferencedFromMirrorSystem(cls)) { |
380 Set<Name> memberNames = new Set<Name>(); | 549 Set<Name> memberNames = new Set<Name>(); |
381 // 1) the class (should be resolved) | 550 // 1) the class (should be resolved) |
382 assert(invariant(cls, cls.isResolved)); | 551 assert(invariant(cls, cls.isResolved)); |
383 reflectableMembers.add(cls); | 552 _classesNeededForReflection.add(cls); |
384 // 2) its constructors (if resolved) | 553 // 2) its constructors (if resolved) |
385 cls.constructors.forEach((ConstructorElement constructor) { | 554 cls.constructors.forEach((ConstructorElement constructor) { |
386 if (worldBuilder.isMemberUsed(constructor)) { | 555 if (worldBuilder.isMemberUsed(constructor)) { |
387 reflectableMembers.add(constructor); | 556 _membersNeededForReflection.add(constructor); |
388 } | 557 } |
389 }); | 558 }); |
390 // 3) all members, including fields via getter/setters (if resolved) | 559 // 3) all members, including fields via getter/setters (if resolved) |
391 cls.forEachClassMember((Member member) { | 560 cls.forEachClassMember((Member member) { |
392 MemberElement element = member.element; | 561 MemberElement element = member.element; |
393 if (worldBuilder.isMemberUsed(element)) { | 562 if (worldBuilder.isMemberUsed(element)) { |
394 memberNames.add(member.name); | 563 memberNames.add(member.name); |
395 reflectableMembers.add(element); | 564 _membersNeededForReflection.add(element); |
396 element.nestedClosures | 565 element.nestedClosures |
397 .forEach((SynthesizedCallMethodElementX callFunction) { | 566 .forEach((SynthesizedCallMethodElementX callFunction) { |
398 reflectableMembers.add(callFunction); | 567 _membersNeededForReflection.add(callFunction); |
399 reflectableMembers.add(callFunction.closureClass); | 568 _classesNeededForReflection.add(callFunction.closureClass); |
400 }); | 569 }); |
401 } | 570 } |
402 }); | 571 }); |
403 // 4) all overriding members of subclasses/subtypes (should be resolved) | 572 // 4) all overriding members of subclasses/subtypes (should be resolved) |
404 if (closedWorld.hasAnyStrictSubtype(cls)) { | 573 if (closedWorld.hasAnyStrictSubtype(cls)) { |
405 closedWorld.forEachStrictSubtypeOf(cls, (ClassElement subcls) { | 574 closedWorld.forEachStrictSubtypeOf(cls, (ClassElement subcls) { |
406 subcls.forEachClassMember((Member member) { | 575 subcls.forEachClassMember((Member member) { |
407 if (memberNames.contains(member.name)) { | 576 if (memberNames.contains(member.name)) { |
408 // TODO(20993): find out why this assertion fails. | 577 // TODO(20993): find out why this assertion fails. |
409 // assert(invariant(member.element, | 578 // assert(invariant(member.element, |
410 // worldBuilder.isMemberUsed(member.element))); | 579 // worldBuilder.isMemberUsed(member.element))); |
411 if (worldBuilder.isMemberUsed(member.element)) { | 580 if (worldBuilder.isMemberUsed(member.element)) { |
412 reflectableMembers.add(member.element); | 581 _membersNeededForReflection.add(member.element); |
413 } | 582 } |
414 } | 583 } |
415 }); | 584 }); |
416 }); | 585 }); |
417 } | 586 } |
418 // 5) all its closures | 587 // 5) all its closures |
419 List<LocalFunctionElement> closures = closureMap[cls]; | 588 List<LocalFunctionElement> closures = closureMap[cls]; |
420 if (closures != null) { | 589 if (closures != null) { |
421 reflectableMembers.addAll(closures); | 590 _closuresNeededForReflection.addAll(closures); |
422 foundClosure = true; | 591 foundClosure = true; |
423 } | 592 } |
424 } else { | 593 } else { |
425 // check members themselves | 594 // check members themselves |
426 cls.constructors.forEach((ConstructorElement element) { | 595 cls.constructors.forEach((ConstructorElement element) { |
427 if (!worldBuilder.isMemberUsed(element)) return; | 596 if (!worldBuilder.isMemberUsed(element)) return; |
428 if (referencedFromMirrorSystem(element, false)) { | 597 if (_memberReferencedFromMirrorSystem(element)) { |
429 reflectableMembers.add(element); | 598 _membersNeededForReflection.add(element); |
430 } | 599 } |
431 }); | 600 }); |
432 cls.forEachClassMember((Member member) { | 601 cls.forEachClassMember((Member member) { |
433 if (!worldBuilder.isMemberUsed(member.element)) return; | 602 if (!worldBuilder.isMemberUsed(member.element)) return; |
434 if (referencedFromMirrorSystem(member.element, false)) { | 603 if (_memberReferencedFromMirrorSystem(member.element)) { |
435 reflectableMembers.add(member.element); | 604 _membersNeededForReflection.add(member.element); |
436 } | 605 } |
437 }); | 606 }); |
438 // Also add in closures. Those might be reflectable is their enclosing | 607 // Also add in closures. Those might be reflectable is their enclosing |
439 // member is. | 608 // member is. |
440 List<LocalFunctionElement> closures = closureMap[cls]; | 609 List<LocalFunctionElement> closures = closureMap[cls]; |
441 if (closures != null) { | 610 if (closures != null) { |
442 for (LocalFunctionElement closure in closures) { | 611 for (LocalFunctionElement closure in closures) { |
443 MemberElement member = closure.memberContext; | 612 MemberElement member = closure.memberContext; |
444 if (referencedFromMirrorSystem(member, false)) { | 613 if (_memberReferencedFromMirrorSystem(member)) { |
445 reflectableMembers.add(closure); | 614 _closuresNeededForReflection.add(closure); |
446 foundClosure = true; | 615 foundClosure = true; |
447 } | 616 } |
448 } | 617 } |
449 } | 618 } |
450 } | 619 } |
451 } | 620 } |
452 // We also need top-level non-class elements like static functions and | 621 // We also need top-level non-class elements like static functions and |
453 // global fields. We use the resolution queue to decide which elements are | 622 // global fields. We use the resolution queue to decide which elements are |
454 // part of the live world. | 623 // part of the live world. |
455 for (LibraryElement lib in _compiler.libraryLoader.libraries) { | 624 for (LibraryElement lib in _compiler.libraryLoader.libraries) { |
456 if (lib.isInternalLibrary) continue; | 625 if (lib.isInternalLibrary) continue; |
457 lib.forEachLocalMember((Element element) { | 626 lib.forEachLocalMember((Element element) { |
458 if (element.isClass || element.isTypedef) return; | 627 if (element.isClass || element.isTypedef) return; |
459 MemberElement member = element; | 628 MemberElement member = element; |
460 if (worldBuilder.isMemberUsed(member) && | 629 if (worldBuilder.isMemberUsed(member) && |
461 referencedFromMirrorSystem(member)) { | 630 isMemberReferencedFromMirrorSystem(member)) { |
462 reflectableMembers.add(member); | 631 _membersNeededForReflection.add(member); |
463 } | 632 } |
464 }); | 633 }); |
465 } | 634 } |
466 // And closures inside top-level elements that do not have a surrounding | 635 // And closures inside top-level elements that do not have a surrounding |
467 // class. These will be in the [:null:] bucket of the [closureMap]. | 636 // class. These will be in the [:null:] bucket of the [closureMap]. |
468 if (closureMap.containsKey(null)) { | 637 if (closureMap.containsKey(null)) { |
469 for (Element closure in closureMap[null]) { | 638 for (LocalFunctionElement closure in closureMap[null]) { |
470 if (referencedFromMirrorSystem(closure)) { | 639 if (isMemberReferencedFromMirrorSystem(closure.memberContext)) { |
471 reflectableMembers.add(closure); | 640 _closuresNeededForReflection.add(closure); |
472 foundClosure = true; | 641 foundClosure = true; |
473 } | 642 } |
474 } | 643 } |
475 } | 644 } |
476 // As we do not think about closures as classes, yet, we have to make sure | 645 // As we do not think about closures as classes, yet, we have to make sure |
477 // their superclasses are available for reflection manually. | 646 // their superclasses are available for reflection manually. |
478 if (foundClosure) { | 647 if (foundClosure) { |
479 ClassElement cls = _helpers.closureClass; | 648 ClassElement cls = _helpers.closureClass; |
480 reflectableMembers.add(cls); | 649 _classesNeededForReflection.add(cls); |
481 } | 650 } |
482 Set<MethodElement> closurizedMembers = worldBuilder.closurizedMembers; | 651 Set<MethodElement> closurizedMembers = worldBuilder.closurizedMembers; |
483 if (closurizedMembers.any(reflectableMembers.contains)) { | 652 if (closurizedMembers.any(_membersNeededForReflection.contains)) { |
484 ClassElement cls = _helpers.boundClosureClass; | 653 ClassElement cls = _helpers.boundClosureClass; |
485 reflectableMembers.add(cls); | 654 _classesNeededForReflection.add(cls); |
486 } | 655 } |
487 // Add typedefs. | 656 // Add typedefs. |
488 reflectableMembers | 657 _typedefsNeededForReflection.addAll( |
489 .addAll(closedWorld.allTypedefs.where(referencedFromMirrorSystem)); | 658 closedWorld.allTypedefs.where(isTypedefReferencedFromMirrorSystem)); |
490 // Register all symbols of reflectable elements | 659 // Register all symbols of reflectable elements |
491 for (Element element in reflectableMembers) { | 660 for (ClassElement element in _classesNeededForReflection) { |
492 symbolsUsed.add(element.name); | 661 symbolsUsed.add(element.name); |
493 } | 662 } |
494 _membersNeededForReflection = reflectableMembers; | 663 for (TypedefElement element in _typedefsNeededForReflection) { |
664 symbolsUsed.add(element.name); | |
665 } | |
666 for (MemberElement element in _membersNeededForReflection) { | |
667 symbolsUsed.add(element.name); | |
668 } | |
669 for (LocalFunctionElement element in _closuresNeededForReflection) { | |
670 symbolsUsed.add(element.name); | |
671 } | |
495 } | 672 } |
496 | 673 |
497 // TODO(20791): compute closure classes after resolution and move this code to | 674 // TODO(20791): compute closure classes after resolution and move this code to |
498 // [computeMembersNeededForReflection]. | 675 // [computeMembersNeededForReflection]. |
499 void maybeMarkClosureAsNeededForReflection( | 676 void maybeMarkClosureAsNeededForReflection( |
500 ClosureClassElement globalizedElement, | 677 ClosureClassElement globalizedElement, |
501 FunctionElement callFunction, | 678 MethodElement callFunction, |
502 FunctionElement function) { | 679 LocalFunctionElement function) { |
503 if (!_membersNeededForReflection.contains(function)) return; | 680 if (!_closuresNeededForReflection.contains(function)) return; |
504 _membersNeededForReflection.add(callFunction); | 681 _membersNeededForReflection.add(callFunction); |
505 _membersNeededForReflection.add(globalizedElement); | 682 _classesNeededForReflection.add(globalizedElement); |
506 } | 683 } |
507 | 684 |
508 /// Called when `const Symbol(name)` is seen. | 685 /// Called when `const Symbol(name)` is seen. |
509 void registerConstSymbol(String name) { | 686 void registerConstSymbol(String name) { |
510 symbolsUsed.add(name); | 687 symbolsUsed.add(name); |
511 if (name.endsWith('=')) { | 688 if (name.endsWith('=')) { |
512 symbolsUsed.add(name.substring(0, name.length - 1)); | 689 symbolsUsed.add(name.substring(0, name.length - 1)); |
513 } | 690 } |
514 } | 691 } |
515 } | 692 } |
OLD | NEW |