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 |
201 if (mustRetainMetadata) hasRetainedMetadata = true; | 248 bool retainMetadataOfParameter(ParameterElement element) { |
202 if (mustRetainMetadata && referencedFromMirrorSystem(element)) { | 249 if (mustRetainMetadata) { |
203 for (MetadataAnnotation metadata in element.metadata) { | 250 hasRetainedMetadata = true; |
204 metadata.ensureResolved(_compiler.resolution); | 251 if (isParameterReferencedFromMirrorSystem(element)) { |
205 ConstantValue constant = | 252 _retainMetadataOf(element); |
206 _constants.getConstantValueForMetadata(metadata); | 253 return true; |
207 _constants.addCompileTimeConstantForEmission(constant); | |
208 } | 254 } |
209 return true; | |
210 } | 255 } |
211 return false; | 256 return false; |
212 } | 257 } |
213 | 258 |
| 259 @override |
| 260 bool retainMetadataOfMember(MemberElement element) { |
| 261 if (mustRetainMetadata) { |
| 262 hasRetainedMetadata = true; |
| 263 if (isMemberReferencedFromMirrorSystem(element)) { |
| 264 _retainMetadataOf(element); |
| 265 return true; |
| 266 } |
| 267 } |
| 268 return false; |
| 269 } |
| 270 |
| 271 @override |
| 272 bool retainMetadataOfClass(ClassElement element) { |
| 273 if (mustRetainMetadata) { |
| 274 hasRetainedMetadata = true; |
| 275 if (isClassReferencedFromMirrorSystem(element)) { |
| 276 _retainMetadataOf(element); |
| 277 return true; |
| 278 } |
| 279 } |
| 280 return false; |
| 281 } |
| 282 |
| 283 @override |
| 284 bool retainMetadataOfTypedef(TypedefElement element) { |
| 285 if (mustRetainMetadata) { |
| 286 hasRetainedMetadata = true; |
| 287 if (isTypedefReferencedFromMirrorSystem(element)) { |
| 288 _retainMetadataOf(element); |
| 289 return true; |
| 290 } |
| 291 } |
| 292 return false; |
| 293 } |
| 294 |
| 295 @override |
| 296 bool retainMetadataOfLibrary(LibraryElement element) { |
| 297 if (mustRetainMetadata) { |
| 298 hasRetainedMetadata = true; |
| 299 if (isLibraryReferencedFromMirrorSystem(element)) { |
| 300 _retainMetadataOf(element); |
| 301 return true; |
| 302 } |
| 303 } |
| 304 return false; |
| 305 } |
| 306 |
| 307 void _retainMetadataOf(Element element) { |
| 308 for (MetadataAnnotation metadata in element.metadata) { |
| 309 metadata.ensureResolved(_compiler.resolution); |
| 310 ConstantValue constant = _constants.getConstantValueForMetadata(metadata); |
| 311 _constants.addCompileTimeConstantForEmission(constant); |
| 312 } |
| 313 } |
| 314 |
214 bool invokedReflectively(Element element) { | 315 bool invokedReflectively(Element element) { |
215 if (element.isParameter) { | 316 if (element.isParameter) { |
216 ParameterElement parameter = element; | 317 ParameterElement parameter = element; |
217 if (invokedReflectively(parameter.functionDeclaration)) return true; | 318 if (invokedReflectively(parameter.functionDeclaration)) return true; |
218 } | 319 } |
219 | 320 |
220 if (element.isField) { | 321 if (element.isField) { |
221 if (Elements.isStaticOrTopLevel(element) && | 322 if (Elements.isStaticOrTopLevel(element) && |
222 (element.isFinal || element.isConst)) { | 323 (element.isFinal || element.isConst)) { |
223 return false; | 324 return false; |
224 } | 325 } |
225 } | 326 } |
226 | 327 |
227 return isAccessibleByReflection(element.declaration); | 328 return isAccessibleByReflection(element.declaration); |
228 } | 329 } |
229 | 330 |
230 /// Set of methods that are needed by reflection. Computed using | 331 /// Sets of elements that are needed by reflection. Computed using |
231 /// [computeMembersNeededForReflection] on first use. | 332 /// [computeMembersNeededForReflection] on first use. |
232 Set<Element> _membersNeededForReflection = null; | 333 Set<ClassElement> _classesNeededForReflection; |
233 Iterable<Element> get membersNeededForReflection { | 334 Set<TypedefElement> _typedefsNeededForReflection; |
234 assert(_membersNeededForReflection != null); | 335 Set<MemberElement> _membersNeededForReflection; |
235 return _membersNeededForReflection; | 336 Set<LocalFunctionElement> _closuresNeededForReflection; |
236 } | |
237 | 337 |
238 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed | 338 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed |
239 /// annotations. The arguments corresponds to the unions of the corresponding | 339 /// annotations. The arguments corresponds to the unions of the corresponding |
240 /// fields of the annotations. | 340 /// fields of the annotations. |
| 341 // TODO(johnniwinther): Change type of [metaTargets] to `Set<ClassEntity>`. |
241 void registerMirrorUsage( | 342 void registerMirrorUsage( |
242 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { | 343 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { |
243 if (symbols == null && targets == null && metaTargets == null) { | 344 if (symbols == null && targets == null && metaTargets == null) { |
244 // The user didn't specify anything, or there are imports of | 345 // The user didn't specify anything, or there are imports of |
245 // 'dart:mirrors' without @MirrorsUsed. | 346 // 'dart:mirrors' without @MirrorsUsed. |
246 hasInsufficientMirrorsUsed = true; | 347 hasInsufficientMirrorsUsed = true; |
247 return; | 348 return; |
248 } | 349 } |
249 if (symbols != null) symbolsUsed.addAll(symbols); | 350 if (symbols != null) symbolsUsed.addAll(symbols); |
250 if (targets != null) { | 351 if (targets != null) { |
251 for (Element target in targets) { | 352 for (Element target in targets) { |
252 if (target.isAbstractField) { | 353 if (target.isAbstractField) { |
253 AbstractFieldElement field = target; | 354 AbstractFieldElement field = target; |
254 targetsUsed.add(field.getter); | 355 if (field.getter != null) { |
255 targetsUsed.add(field.setter); | 356 membersInMirrorsUsedTargets.add(field.getter); |
256 } else { | 357 } |
257 targetsUsed.add(target); | 358 if (field.setter != null) { |
| 359 membersInMirrorsUsedTargets.add(field.setter); |
| 360 } |
| 361 } else if (target.isClass) { |
| 362 classesInMirrorsUsedTargets.add(target as ClassEntity); |
| 363 } else if (target.isTypedef) { |
| 364 _typedefsInMirrorsUsedTargets.add(target); |
| 365 } else if (target.isLibrary) { |
| 366 librariesInMirrorsUsedTargets.add(target as LibraryEntity); |
| 367 } else if (target != null) { |
| 368 membersInMirrorsUsedTargets.add(target as MemberEntity); |
258 } | 369 } |
259 } | 370 } |
260 } | 371 } |
261 if (metaTargets != null) metaTargetsUsed.addAll(metaTargets); | 372 if (metaTargets != null) { |
| 373 for (var element in metaTargets) { |
| 374 if (element is ClassEntity) { |
| 375 metaTargetsUsed.add(element); |
| 376 } |
| 377 } |
| 378 } |
262 } | 379 } |
263 | 380 |
264 /// Returns `true` if [element] can be accessed through reflection, that is, | 381 @override |
265 /// is in the set of elements covered by a `MirrorsUsed` annotation. | 382 bool isClassAccessibleByReflection(ClassElement element) { |
266 /// | 383 return _classesNeededForReflection.contains(_getDartClass(element)); |
267 /// This property is used to tag emitted elements with a marker which is | 384 } |
268 /// checked by the runtime system to throw an exception if an element is | 385 |
269 /// accessed (invoked, get, set) that is not accessible for the reflective | 386 @override |
270 /// system. | 387 bool isTypedefAccessibleByReflection(TypedefElement element) { |
| 388 return _typedefsNeededForReflection.contains(element); |
| 389 } |
| 390 |
271 bool isAccessibleByReflection(Element element) { | 391 bool isAccessibleByReflection(Element element) { |
272 if (element.isClass) { | 392 if (element.isLibrary) { |
273 element = _getDartClass(element); | 393 return false; |
| 394 } else if (element.isClass) { |
| 395 return isClassAccessibleByReflection(element); |
| 396 } else if (element.isTypedef) { |
| 397 return isTypedefAccessibleByReflection(element); |
| 398 } else { |
| 399 return isMemberAccessibleByReflection(element); |
274 } | 400 } |
275 return membersNeededForReflection.contains(element); | |
276 } | 401 } |
277 | 402 |
278 ClassElement _getDartClass(ClassElement cls) { | 403 ClassElement _getDartClass(ClassElement cls) { |
279 if (cls == _helpers.jsIntClass) { | 404 if (cls == _helpers.jsIntClass) { |
280 return _commonElements.intClass; | 405 return _commonElements.intClass; |
281 } else if (cls == _helpers.jsBoolClass) { | 406 } else if (cls == _helpers.jsBoolClass) { |
282 return _commonElements.boolClass; | 407 return _commonElements.boolClass; |
283 } else if (cls == _helpers.jsNumberClass) { | 408 } else if (cls == _helpers.jsNumberClass) { |
284 return _commonElements.numClass; | 409 return _commonElements.numClass; |
285 } else if (cls == _helpers.jsDoubleClass) { | 410 } else if (cls == _helpers.jsDoubleClass) { |
286 return _commonElements.doubleClass; | 411 return _commonElements.doubleClass; |
287 } else if (cls == _helpers.jsStringClass) { | 412 } else if (cls == _helpers.jsStringClass) { |
288 return _commonElements.stringClass; | 413 return _commonElements.stringClass; |
289 } else if (cls == _helpers.jsArrayClass) { | 414 } else if (cls == _helpers.jsArrayClass) { |
290 return _commonElements.listClass; | 415 return _commonElements.listClass; |
291 } else if (cls == _helpers.jsNullClass) { | 416 } else if (cls == _helpers.jsNullClass) { |
292 return _commonElements.nullClass; | 417 return _commonElements.nullClass; |
293 } else { | 418 } else { |
294 return cls; | 419 return cls; |
295 } | 420 } |
296 } | 421 } |
297 | 422 |
298 /// Returns `true` if this member element needs reflection information at | |
299 /// runtime. | |
300 bool isMemberAccessibleByReflection(MemberElement element) { | 423 bool isMemberAccessibleByReflection(MemberElement element) { |
301 return membersNeededForReflection.contains(element); | 424 return _membersNeededForReflection.contains(element); |
302 } | 425 } |
303 | 426 |
304 /// Returns true if this element has to be enqueued due to | 427 /// Returns true if this element has to be enqueued due to |
305 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if | 428 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if |
306 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). | 429 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). |
307 bool requiredByMirrorSystem(Element element) { | 430 bool requiredByMirrorSystem(Element element) { |
308 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || | 431 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || |
309 matchesMirrorsMetaTarget(element) || | 432 matchesMirrorsMetaTarget(element) || |
310 targetsUsed.contains(element); | 433 classesInMirrorsUsedTargets.contains(element) || |
| 434 membersInMirrorsUsedTargets.contains(element) || |
| 435 librariesInMirrorsUsedTargets.contains(element) || |
| 436 _typedefsInMirrorsUsedTargets.contains(element); |
311 } | 437 } |
312 | 438 |
313 /// Returns true if this element is covered by a mirrorsUsed annotation. | 439 @override |
314 /// | 440 bool isLibraryReferencedFromMirrorSystem(LibraryElement element) { |
315 /// Note that it might still be ok to tree shake the element away if no | 441 return _libraryReferencedFromMirrorSystem(element); |
316 /// reflection is used in the program (and thus [isTreeShakingDisabled] is | 442 } |
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 | 443 |
| 444 @override |
| 445 bool isMemberReferencedFromMirrorSystem(MemberElement element) { |
| 446 if (_memberReferencedFromMirrorSystem(element)) return true; |
| 447 if (element.enclosingClass != null) { |
| 448 return isClassReferencedFromMirrorSystem(element.enclosingClass); |
| 449 } else { |
| 450 return isLibraryReferencedFromMirrorSystem(element.library); |
| 451 } |
| 452 } |
| 453 |
| 454 @override |
| 455 bool isClassReferencedFromMirrorSystem(ClassElement element) { |
| 456 return _classReferencedFromMirrorSystem(element) || |
| 457 isLibraryReferencedFromMirrorSystem(element.library); |
| 458 } |
| 459 |
| 460 bool isParameterReferencedFromMirrorSystem(ParameterElement element) { |
| 461 return _parameterReferencedFromMirrorSystem(element) || |
| 462 isMemberReferencedFromMirrorSystem(element.memberContext); |
| 463 } |
| 464 |
| 465 bool isTypedefReferencedFromMirrorSystem(TypedefElement element) { |
| 466 return _typedefReferencedFromMirrorSystem(element) || |
| 467 isLibraryReferencedFromMirrorSystem(element.library); |
| 468 } |
| 469 |
| 470 bool _memberReferencedFromMirrorSystem(MemberElement element) { |
322 return hasInsufficientMirrorsUsed || | 471 return hasInsufficientMirrorsUsed || |
323 matchesMirrorsMetaTarget(element) || | 472 matchesMirrorsMetaTarget(element) || |
324 targetsUsed.contains(element) || | 473 membersInMirrorsUsedTargets.contains(element); |
325 (enclosing != null && referencedFromMirrorSystem(enclosing)); | 474 } |
| 475 |
| 476 bool _parameterReferencedFromMirrorSystem(ParameterElement element) { |
| 477 return hasInsufficientMirrorsUsed || matchesMirrorsMetaTarget(element); |
| 478 } |
| 479 |
| 480 bool _classReferencedFromMirrorSystem(ClassElement element) { |
| 481 return hasInsufficientMirrorsUsed || |
| 482 matchesMirrorsMetaTarget(element) || |
| 483 classesInMirrorsUsedTargets.contains(element); |
| 484 } |
| 485 |
| 486 bool _typedefReferencedFromMirrorSystem(TypedefElement element) { |
| 487 return hasInsufficientMirrorsUsed || |
| 488 matchesMirrorsMetaTarget(element) || |
| 489 _typedefsInMirrorsUsedTargets.contains(element); |
| 490 } |
| 491 |
| 492 bool _libraryReferencedFromMirrorSystem(LibraryElement element) { |
| 493 return hasInsufficientMirrorsUsed || |
| 494 matchesMirrorsMetaTarget(element) || |
| 495 librariesInMirrorsUsedTargets.contains(element); |
326 } | 496 } |
327 | 497 |
328 /** | 498 /** |
329 * Returns `true` if the element is needed because it has an annotation | 499 * 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. | 500 * of a type that is used as a meta target for reflection. |
331 */ | 501 */ |
332 bool matchesMirrorsMetaTarget(Element element) { | 502 bool matchesMirrorsMetaTarget(Element element) { |
333 if (metaTargetsUsed.isEmpty) return false; | 503 if (metaTargetsUsed.isEmpty) return false; |
334 for (MetadataAnnotation metadata in element.metadata) { | 504 for (MetadataAnnotation metadata in element.metadata) { |
335 // TODO(kasperl): It would be nice if we didn't have to resolve | 505 // TODO(kasperl): It would be nice if we didn't have to resolve |
336 // all metadata but only stuff that potentially would match one | 506 // all metadata but only stuff that potentially would match one |
337 // of the used meta targets. | 507 // of the used meta targets. |
338 metadata.ensureResolved(_compiler.resolution); | 508 metadata.ensureResolved(_compiler.resolution); |
339 ConstantValue value = | 509 ConstantValue value = |
340 _compiler.constants.getConstantValue(metadata.constant); | 510 _compiler.constants.getConstantValue(metadata.constant); |
341 if (value == null) continue; | 511 if (value == null) continue; |
342 ResolutionDartType type = value.getType(_commonElements); | 512 DartType type = value.getType(_commonElements); |
343 if (metaTargetsUsed.contains(type.element)) return true; | 513 if (type is InterfaceType && metaTargetsUsed.contains(type.element)) |
| 514 return true; |
344 } | 515 } |
345 return false; | 516 return false; |
346 } | 517 } |
347 | 518 |
348 /** | 519 /** |
349 * Visits all classes and computes whether its members are needed for | 520 * Visits all classes and computes whether its members are needed for |
350 * reflection. | 521 * reflection. |
351 * | 522 * |
352 * We have to precompute this set as we cannot easily answer the need for | 523 * 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 | 524 * reflection locally when looking at the member: We lack the information by |
354 * which classes a member is inherited. Called after resolution is complete. | 525 * which classes a member is inherited. Called after resolution is complete. |
355 * | 526 * |
356 * We filter out private libraries here, as their elements should not | 527 * We filter out private libraries here, as their elements should not |
357 * be visible by reflection unless some other interfaces makes them | 528 * be visible by reflection unless some other interfaces makes them |
358 * accessible. | 529 * accessible. |
359 */ | 530 */ |
360 void computeMembersNeededForReflection( | 531 void computeMembersNeededForReflection( |
361 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { | 532 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { |
362 if (_membersNeededForReflection != null) return; | 533 if (_membersNeededForReflection != null) return; |
363 if (closedWorld.commonElements.mirrorsLibrary == null) { | 534 if (closedWorld.commonElements.mirrorsLibrary == null) { |
364 _membersNeededForReflection = const ImmutableEmptySet<Element>(); | 535 _classesNeededForReflection = const ImmutableEmptySet<ClassElement>(); |
| 536 _typedefsNeededForReflection = const ImmutableEmptySet<TypedefElement>(); |
| 537 _membersNeededForReflection = const ImmutableEmptySet<MemberElement>(); |
| 538 _closuresNeededForReflection = |
| 539 const ImmutableEmptySet<LocalFunctionElement>(); |
365 return; | 540 return; |
366 } | 541 } |
| 542 _classesNeededForReflection = new Set<ClassElement>(); |
| 543 _typedefsNeededForReflection = new Set<TypedefElement>(); |
| 544 _membersNeededForReflection = new Set<MemberElement>(); |
| 545 _closuresNeededForReflection = new Set<LocalFunctionElement>(); |
| 546 |
367 // Compute a mapping from class to the closures it contains, so we | 547 // Compute a mapping from class to the closures it contains, so we |
368 // can include the correct ones when including the class. | 548 // can include the correct ones when including the class. |
369 Map<ClassElement, List<LocalFunctionElement>> closureMap = | 549 Map<ClassElement, List<LocalFunctionElement>> closureMap = |
370 new Map<ClassElement, List<LocalFunctionElement>>(); | 550 new Map<ClassElement, List<LocalFunctionElement>>(); |
371 for (LocalFunctionElement closure in worldBuilder.localFunctions) { | 551 for (LocalFunctionElement closure in worldBuilder.localFunctions) { |
372 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure); | 552 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure); |
373 } | 553 } |
374 bool foundClosure = false; | 554 bool foundClosure = false; |
375 Set<Element> reflectableMembers = new Set<Element>(); | |
376 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { | 555 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { |
377 // Do not process internal classes. | 556 // Do not process internal classes. |
378 if (cls.library.isInternalLibrary || cls.isInjected) continue; | 557 if (cls.library.isInternalLibrary || cls.isInjected) continue; |
379 if (referencedFromMirrorSystem(cls)) { | 558 if (isClassReferencedFromMirrorSystem(cls)) { |
380 Set<Name> memberNames = new Set<Name>(); | 559 Set<Name> memberNames = new Set<Name>(); |
381 // 1) the class (should be resolved) | 560 // 1) the class (should be resolved) |
382 assert(invariant(cls, cls.isResolved)); | 561 assert(invariant(cls, cls.isResolved)); |
383 reflectableMembers.add(cls); | 562 _classesNeededForReflection.add(cls); |
384 // 2) its constructors (if resolved) | 563 // 2) its constructors (if resolved) |
385 cls.constructors.forEach((ConstructorElement constructor) { | 564 cls.constructors.forEach((ConstructorElement constructor) { |
386 if (worldBuilder.isMemberUsed(constructor)) { | 565 if (worldBuilder.isMemberUsed(constructor)) { |
387 reflectableMembers.add(constructor); | 566 _membersNeededForReflection.add(constructor); |
388 } | 567 } |
389 }); | 568 }); |
390 // 3) all members, including fields via getter/setters (if resolved) | 569 // 3) all members, including fields via getter/setters (if resolved) |
391 cls.forEachClassMember((Member member) { | 570 cls.forEachClassMember((Member member) { |
392 MemberElement element = member.element; | 571 MemberElement element = member.element; |
393 if (worldBuilder.isMemberUsed(element)) { | 572 if (worldBuilder.isMemberUsed(element)) { |
394 memberNames.add(member.name); | 573 memberNames.add(member.name); |
395 reflectableMembers.add(element); | 574 _membersNeededForReflection.add(element); |
396 element.nestedClosures | 575 element.nestedClosures |
397 .forEach((SynthesizedCallMethodElementX callFunction) { | 576 .forEach((SynthesizedCallMethodElementX callFunction) { |
398 reflectableMembers.add(callFunction); | 577 _membersNeededForReflection.add(callFunction); |
399 reflectableMembers.add(callFunction.closureClass); | 578 _classesNeededForReflection.add(callFunction.closureClass); |
400 }); | 579 }); |
401 } | 580 } |
402 }); | 581 }); |
403 // 4) all overriding members of subclasses/subtypes (should be resolved) | 582 // 4) all overriding members of subclasses/subtypes (should be resolved) |
404 if (closedWorld.hasAnyStrictSubtype(cls)) { | 583 if (closedWorld.hasAnyStrictSubtype(cls)) { |
405 closedWorld.forEachStrictSubtypeOf(cls, (ClassElement subcls) { | 584 closedWorld.forEachStrictSubtypeOf(cls, (ClassElement subcls) { |
406 subcls.forEachClassMember((Member member) { | 585 subcls.forEachClassMember((Member member) { |
407 if (memberNames.contains(member.name)) { | 586 if (memberNames.contains(member.name)) { |
408 // TODO(20993): find out why this assertion fails. | 587 // TODO(20993): find out why this assertion fails. |
409 // assert(invariant(member.element, | 588 // assert(invariant(member.element, |
410 // worldBuilder.isMemberUsed(member.element))); | 589 // worldBuilder.isMemberUsed(member.element))); |
411 if (worldBuilder.isMemberUsed(member.element)) { | 590 if (worldBuilder.isMemberUsed(member.element)) { |
412 reflectableMembers.add(member.element); | 591 _membersNeededForReflection.add(member.element); |
413 } | 592 } |
414 } | 593 } |
415 }); | 594 }); |
416 }); | 595 }); |
417 } | 596 } |
418 // 5) all its closures | 597 // 5) all its closures |
419 List<LocalFunctionElement> closures = closureMap[cls]; | 598 List<LocalFunctionElement> closures = closureMap[cls]; |
420 if (closures != null) { | 599 if (closures != null) { |
421 reflectableMembers.addAll(closures); | 600 _closuresNeededForReflection.addAll(closures); |
422 foundClosure = true; | 601 foundClosure = true; |
423 } | 602 } |
424 } else { | 603 } else { |
425 // check members themselves | 604 // check members themselves |
426 cls.constructors.forEach((ConstructorElement element) { | 605 cls.constructors.forEach((ConstructorElement element) { |
427 if (!worldBuilder.isMemberUsed(element)) return; | 606 if (!worldBuilder.isMemberUsed(element)) return; |
428 if (referencedFromMirrorSystem(element, false)) { | 607 if (_memberReferencedFromMirrorSystem(element)) { |
429 reflectableMembers.add(element); | 608 _membersNeededForReflection.add(element); |
430 } | 609 } |
431 }); | 610 }); |
432 cls.forEachClassMember((Member member) { | 611 cls.forEachClassMember((Member member) { |
433 if (!worldBuilder.isMemberUsed(member.element)) return; | 612 if (!worldBuilder.isMemberUsed(member.element)) return; |
434 if (referencedFromMirrorSystem(member.element, false)) { | 613 if (_memberReferencedFromMirrorSystem(member.element)) { |
435 reflectableMembers.add(member.element); | 614 _membersNeededForReflection.add(member.element); |
436 } | 615 } |
437 }); | 616 }); |
438 // Also add in closures. Those might be reflectable is their enclosing | 617 // Also add in closures. Those might be reflectable is their enclosing |
439 // member is. | 618 // member is. |
440 List<LocalFunctionElement> closures = closureMap[cls]; | 619 List<LocalFunctionElement> closures = closureMap[cls]; |
441 if (closures != null) { | 620 if (closures != null) { |
442 for (LocalFunctionElement closure in closures) { | 621 for (LocalFunctionElement closure in closures) { |
443 MemberElement member = closure.memberContext; | 622 MemberElement member = closure.memberContext; |
444 if (referencedFromMirrorSystem(member, false)) { | 623 if (_memberReferencedFromMirrorSystem(member)) { |
445 reflectableMembers.add(closure); | 624 _closuresNeededForReflection.add(closure); |
446 foundClosure = true; | 625 foundClosure = true; |
447 } | 626 } |
448 } | 627 } |
449 } | 628 } |
450 } | 629 } |
451 } | 630 } |
452 // We also need top-level non-class elements like static functions and | 631 // 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 | 632 // global fields. We use the resolution queue to decide which elements are |
454 // part of the live world. | 633 // part of the live world. |
455 for (LibraryElement lib in _compiler.libraryLoader.libraries) { | 634 for (LibraryElement lib in _compiler.libraryLoader.libraries) { |
456 if (lib.isInternalLibrary) continue; | 635 if (lib.isInternalLibrary) continue; |
457 lib.forEachLocalMember((Element element) { | 636 lib.forEachLocalMember((Element element) { |
458 if (element.isClass || element.isTypedef) return; | 637 if (element.isClass || element.isTypedef) return; |
459 MemberElement member = element; | 638 MemberElement member = element; |
460 if (worldBuilder.isMemberUsed(member) && | 639 if (worldBuilder.isMemberUsed(member) && |
461 referencedFromMirrorSystem(member)) { | 640 isMemberReferencedFromMirrorSystem(member)) { |
462 reflectableMembers.add(member); | 641 _membersNeededForReflection.add(member); |
463 } | 642 } |
464 }); | 643 }); |
465 } | 644 } |
466 // And closures inside top-level elements that do not have a surrounding | 645 // And closures inside top-level elements that do not have a surrounding |
467 // class. These will be in the [:null:] bucket of the [closureMap]. | 646 // class. These will be in the [:null:] bucket of the [closureMap]. |
468 if (closureMap.containsKey(null)) { | 647 if (closureMap.containsKey(null)) { |
469 for (Element closure in closureMap[null]) { | 648 for (LocalFunctionElement closure in closureMap[null]) { |
470 if (referencedFromMirrorSystem(closure)) { | 649 if (isMemberReferencedFromMirrorSystem(closure.memberContext)) { |
471 reflectableMembers.add(closure); | 650 _closuresNeededForReflection.add(closure); |
472 foundClosure = true; | 651 foundClosure = true; |
473 } | 652 } |
474 } | 653 } |
475 } | 654 } |
476 // As we do not think about closures as classes, yet, we have to make sure | 655 // As we do not think about closures as classes, yet, we have to make sure |
477 // their superclasses are available for reflection manually. | 656 // their superclasses are available for reflection manually. |
478 if (foundClosure) { | 657 if (foundClosure) { |
479 ClassElement cls = _helpers.closureClass; | 658 ClassElement cls = _helpers.closureClass; |
480 reflectableMembers.add(cls); | 659 _classesNeededForReflection.add(cls); |
481 } | 660 } |
482 Set<MethodElement> closurizedMembers = worldBuilder.closurizedMembers; | 661 Set<MethodElement> closurizedMembers = worldBuilder.closurizedMembers; |
483 if (closurizedMembers.any(reflectableMembers.contains)) { | 662 if (closurizedMembers.any(_membersNeededForReflection.contains)) { |
484 ClassElement cls = _helpers.boundClosureClass; | 663 ClassElement cls = _helpers.boundClosureClass; |
485 reflectableMembers.add(cls); | 664 _classesNeededForReflection.add(cls); |
486 } | 665 } |
487 // Add typedefs. | 666 // Add typedefs. |
488 reflectableMembers | 667 _typedefsNeededForReflection.addAll( |
489 .addAll(closedWorld.allTypedefs.where(referencedFromMirrorSystem)); | 668 closedWorld.allTypedefs.where(isTypedefReferencedFromMirrorSystem)); |
490 // Register all symbols of reflectable elements | 669 // Register all symbols of reflectable elements |
491 for (Element element in reflectableMembers) { | 670 for (ClassElement element in _classesNeededForReflection) { |
492 symbolsUsed.add(element.name); | 671 symbolsUsed.add(element.name); |
493 } | 672 } |
494 _membersNeededForReflection = reflectableMembers; | 673 for (TypedefElement element in _typedefsNeededForReflection) { |
| 674 symbolsUsed.add(element.name); |
| 675 } |
| 676 for (MemberElement element in _membersNeededForReflection) { |
| 677 symbolsUsed.add(element.name); |
| 678 } |
| 679 for (LocalFunctionElement element in _closuresNeededForReflection) { |
| 680 symbolsUsed.add(element.name); |
| 681 } |
495 } | 682 } |
496 | 683 |
497 // TODO(20791): compute closure classes after resolution and move this code to | 684 // TODO(20791): compute closure classes after resolution and move this code to |
498 // [computeMembersNeededForReflection]. | 685 // [computeMembersNeededForReflection]. |
499 void maybeMarkClosureAsNeededForReflection( | 686 void maybeMarkClosureAsNeededForReflection( |
500 ClosureClassElement globalizedElement, | 687 ClosureClassElement globalizedElement, |
501 FunctionElement callFunction, | 688 MethodElement callFunction, |
502 FunctionElement function) { | 689 LocalFunctionElement function) { |
503 if (!_membersNeededForReflection.contains(function)) return; | 690 if (!_closuresNeededForReflection.contains(function)) return; |
504 _membersNeededForReflection.add(callFunction); | 691 _membersNeededForReflection.add(callFunction); |
505 _membersNeededForReflection.add(globalizedElement); | 692 _classesNeededForReflection.add(globalizedElement); |
506 } | 693 } |
507 | 694 |
508 /// Called when `const Symbol(name)` is seen. | 695 /// Called when `const Symbol(name)` is seen. |
509 void registerConstSymbol(String name) { | 696 void registerConstSymbol(String name) { |
510 symbolsUsed.add(name); | 697 symbolsUsed.add(name); |
511 if (name.endsWith('=')) { | 698 if (name.endsWith('=')) { |
512 symbolsUsed.add(name.substring(0, name.length - 1)); | 699 symbolsUsed.add(name.substring(0, name.length - 1)); |
513 } | 700 } |
514 } | 701 } |
515 } | 702 } |
OLD | NEW |