| 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/entities.dart'; | 11 import '../elements/entities.dart'; |
| 12 import '../elements/names.dart'; | 12 import '../elements/names.dart'; |
| 13 import '../elements/types.dart'; | 13 import '../elements/types.dart'; |
| 14 import '../options.dart'; | 14 import '../options.dart'; |
| 15 import '../world.dart'; | 15 import '../world.dart'; |
| 16 import '../universe/world_builder.dart'; | 16 import '../universe/world_builder.dart'; |
| 17 import '../util/emptyset.dart'; | 17 import '../util/emptyset.dart'; |
| 18 import 'constant_handler_javascript.dart'; | |
| 19 | 18 |
| 20 abstract class MirrorsData { | 19 abstract class MirrorsData { |
| 21 /// True if a call to preserveMetadataMarker has been seen. This means that | 20 /// True if a call to preserveMetadataMarker has been seen. This means that |
| 22 /// metadata must be retained for dart:mirrors to work correctly. | 21 /// metadata must be retained for dart:mirrors to work correctly. |
| 23 // resolution-empty-queue | 22 // resolution-empty-queue |
| 24 bool get mustRetainMetadata; | 23 bool get mustRetainMetadata; |
| 25 | 24 |
| 26 /// True if any metadata has been retained. This is slightly different from | 25 /// True if any metadata has been retained. This is slightly different from |
| 27 /// [mustRetainMetadata] and tells us if any metadata was retained. For | 26 /// [mustRetainMetadata] and tells us if any metadata was retained. For |
| 28 /// example, if [mustRetainMetadata] is true but there is no metadata in the | 27 /// example, if [mustRetainMetadata] is true but there is no metadata in the |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 /// Should [name] be retained for reflection? | 70 /// Should [name] be retained for reflection? |
| 72 bool shouldRetainName(String name); | 71 bool shouldRetainName(String name); |
| 73 | 72 |
| 74 /// Returns `true` if the class [element] is covered by a `MirrorsUsed` | 73 /// Returns `true` if the class [element] is covered by a `MirrorsUsed` |
| 75 /// annotation. | 74 /// annotation. |
| 76 /// | 75 /// |
| 77 /// Note that it might still be ok to tree shake the element away if no | 76 /// Note that it might still be ok to tree shake the element away if no |
| 78 /// reflection is used in the program (and thus [isTreeShakingDisabled] is | 77 /// reflection is used in the program (and thus [isTreeShakingDisabled] is |
| 79 /// still false). Therefore _do not_ use this predicate to decide inclusion | 78 /// still false). Therefore _do not_ use this predicate to decide inclusion |
| 80 /// in the tree, use [requiredByMirrorSystem] instead. | 79 /// in the tree, use [requiredByMirrorSystem] instead. |
| 81 bool isClassReferencedFromMirrorSystem(covariant ClassEntity element); | 80 bool isClassReferencedFromMirrorSystem(ClassEntity element); |
| 82 | 81 |
| 83 /// Returns `true` if the member [element] is covered by a `MirrorsUsed` | 82 /// Returns `true` if the member [element] is covered by a `MirrorsUsed` |
| 84 /// annotation. | 83 /// annotation. |
| 85 /// | 84 /// |
| 86 /// Note that it might still be ok to tree shake the element away if no | 85 /// 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 | 86 /// reflection is used in the program (and thus [isTreeShakingDisabled] is |
| 88 /// still false). Therefore _do not_ use this predicate to decide inclusion | 87 /// still false). Therefore _do not_ use this predicate to decide inclusion |
| 89 /// in the tree, use [requiredByMirrorSystem] instead. | 88 /// in the tree, use [requiredByMirrorSystem] instead. |
| 90 bool isMemberReferencedFromMirrorSystem(covariant MemberEntity element); | 89 bool isMemberReferencedFromMirrorSystem(MemberEntity element); |
| 91 | 90 |
| 92 /// Returns `true` if the library [element] is covered by a `MirrorsUsed` | 91 /// Returns `true` if the library [element] is covered by a `MirrorsUsed` |
| 93 /// annotation. | 92 /// annotation. |
| 94 bool isLibraryReferencedFromMirrorSystem(covariant LibraryEntity element); | 93 bool isLibraryReferencedFromMirrorSystem(LibraryEntity element); |
| 95 | 94 |
| 96 /// Returns `true` if the typedef [element] needs reflection information at | 95 /// Returns `true` if the typedef [element] needs reflection information at |
| 97 /// runtime. | 96 /// runtime. |
| 98 /// | 97 /// |
| 99 /// This property is used to tag emitted elements with a marker which is | 98 /// This property is used to tag emitted elements with a marker which is |
| 100 /// checked by the runtime system to throw an exception if an element is | 99 /// checked by the runtime system to throw an exception if an element is |
| 101 /// accessed (invoked, get, set) that is not accessible for the reflective | 100 /// accessed (invoked, get, set) that is not accessible for the reflective |
| 102 /// system. | 101 /// system. |
| 103 bool isTypedefAccessibleByReflection(covariant TypedefEntity element); | 102 bool isTypedefAccessibleByReflection(TypedefEntity element); |
| 104 | 103 |
| 105 /// Returns `true` if the class [element] needs reflection information at | 104 /// Returns `true` if the class [element] needs reflection information at |
| 106 /// runtime. | 105 /// runtime. |
| 107 /// | 106 /// |
| 108 /// This property is used to tag emitted elements with a marker which is | 107 /// 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 | 108 /// 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 | 109 /// accessed (invoked, get, set) that is not accessible for the reflective |
| 111 /// system. | 110 /// system. |
| 112 bool isClassAccessibleByReflection(ClassEntity element); | 111 bool isClassAccessibleByReflection(ClassEntity element); |
| 113 | 112 |
| 114 /// Returns `true` if the member [element] needs reflection information at | 113 /// Returns `true` if the member [element] needs reflection information at |
| 115 /// runtime. | 114 /// runtime. |
| 116 /// | 115 /// |
| 117 /// This property is used to tag emitted elements with a marker which is | 116 /// 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 | 117 /// 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 | 118 /// accessed (invoked, get, set) that is not accessible for the reflective |
| 120 /// system. | 119 /// system. |
| 121 bool isMemberAccessibleByReflection(MemberEntity element); | 120 bool isMemberAccessibleByReflection(MemberEntity element); |
| 122 | 121 |
| 123 // TODO(johnniwinther): Remove this. | 122 bool retainMetadataOfLibrary(LibraryEntity element, |
| 124 @deprecated | |
| 125 bool isAccessibleByReflection(Element element); | |
| 126 | |
| 127 bool retainMetadataOfLibrary(covariant LibraryEntity element, | |
| 128 {bool addForEmission: true}); | 123 {bool addForEmission: true}); |
| 129 bool retainMetadataOfTypedef(covariant TypedefEntity element); | 124 bool retainMetadataOfTypedef(TypedefEntity element); |
| 130 bool retainMetadataOfClass(covariant ClassEntity element); | 125 bool retainMetadataOfClass(ClassEntity element); |
| 131 bool retainMetadataOfMember(covariant MemberEntity element); | 126 bool retainMetadataOfMember(MemberEntity element); |
| 132 bool retainMetadataOfParameter(ParameterElement element); | |
| 133 | 127 |
| 134 /// Returns true if this element has to be enqueued due to | 128 /// Returns true if this element has to be enqueued due to |
| 135 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if | 129 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if |
| 136 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). | 130 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). |
| 137 bool requiredByMirrorSystem(Element element); | 131 bool isLibraryRequiredByMirrorSystem(LibraryEntity element); |
| 132 bool isClassRequiredByMirrorSystem(ClassEntity element); |
| 133 bool isMemberRequiredByMirrorSystem(MemberEntity element); |
| 138 } | 134 } |
| 139 | 135 |
| 140 abstract class MirrorsDataBuilder { | 136 abstract class MirrorsDataBuilder { |
| 141 void registerUsedMember(MemberElement member); | 137 void registerUsedMember(MemberEntity member); |
| 142 | 138 |
| 143 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed | 139 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed |
| 144 /// annotations. The arguments corresponds to the unions of the corresponding | 140 /// annotations. The arguments corresponds to the unions of the corresponding |
| 145 /// fields of the annotations. | 141 /// fields of the annotations. |
| 146 void registerMirrorUsage( | 142 void registerMirrorUsage( |
| 147 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets); | 143 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets); |
| 148 | 144 |
| 149 /// Called when `const Symbol(name)` is seen. | 145 /// Called when `const Symbol(name)` is seen. |
| 150 void registerConstSymbol(String name); | 146 void registerConstSymbol(String name); |
| 151 | 147 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 | 194 |
| 199 /// List of annotations provided by user that indicate that the annotated | 195 /// List of annotations provided by user that indicate that the annotated |
| 200 /// element must be retained. | 196 /// element must be retained. |
| 201 final Set<ClassEntity> metaTargetsUsed = new Set<ClassEntity>(); | 197 final Set<ClassEntity> metaTargetsUsed = new Set<ClassEntity>(); |
| 202 | 198 |
| 203 // TODO(johnniwinther): Avoid the need for this. | 199 // TODO(johnniwinther): Avoid the need for this. |
| 204 final Compiler _compiler; | 200 final Compiler _compiler; |
| 205 | 201 |
| 206 final CompilerOptions _options; | 202 final CompilerOptions _options; |
| 207 | 203 |
| 204 final ElementEnvironment _elementEnvironment; |
| 208 final CommonElements _commonElements; | 205 final CommonElements _commonElements; |
| 209 | 206 |
| 210 MirrorsDataImpl(this._compiler, this._options, this._commonElements); | 207 MirrorsDataImpl(this._compiler, this._options, this._elementEnvironment, |
| 208 this._commonElements); |
| 211 | 209 |
| 212 JavaScriptConstantCompiler get _constants => _compiler.backend.constants; | 210 void registerUsedMember(MemberEntity member) { |
| 213 | |
| 214 void registerUsedMember(MemberElement member) { | |
| 215 if (member == _commonElements.disableTreeShakingMarker) { | 211 if (member == _commonElements.disableTreeShakingMarker) { |
| 216 isTreeShakingDisabled = true; | 212 isTreeShakingDisabled = true; |
| 217 } else if (member == _commonElements.preserveNamesMarker) { | 213 } else if (member == _commonElements.preserveNamesMarker) { |
| 218 mustPreserveNames = true; | 214 mustPreserveNames = true; |
| 219 } else if (member == _commonElements.preserveMetadataMarker) { | 215 } else if (member == _commonElements.preserveMetadataMarker) { |
| 220 mustRetainMetadata = true; | 216 mustRetainMetadata = true; |
| 221 } else if (member == _commonElements.preserveUrisMarker) { | 217 } else if (member == _commonElements.preserveUrisMarker) { |
| 222 if (_options.preserveUris) mustPreserveUris = true; | 218 if (_options.preserveUris) mustPreserveUris = true; |
| 223 } else if (member == _commonElements.preserveLibraryNamesMarker) { | 219 } else if (member == _commonElements.preserveLibraryNamesMarker) { |
| 224 mustRetainLibraryNames = true; | 220 mustRetainLibraryNames = true; |
| 225 } | 221 } |
| 226 } | 222 } |
| 227 | 223 |
| 228 bool shouldRetainGetter(FieldEntity element) { | 224 bool shouldRetainGetter(FieldEntity element) { |
| 229 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); | 225 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); |
| 230 } | 226 } |
| 231 | 227 |
| 232 bool shouldRetainSetter(FieldEntity element) { | 228 bool shouldRetainSetter(FieldEntity element) { |
| 233 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); | 229 return isTreeShakingDisabled && isMemberAccessibleByReflection(element); |
| 234 } | 230 } |
| 235 | 231 |
| 236 /// Should [name] be retained for reflection? | 232 /// Should [name] be retained for reflection? |
| 237 bool shouldRetainName(String name) { | 233 bool shouldRetainName(String name) { |
| 238 if (hasInsufficientMirrorsUsed) return mustPreserveNames; | 234 if (hasInsufficientMirrorsUsed) return mustPreserveNames; |
| 239 if (name == '') return false; | 235 if (name == '') return false; |
| 240 return symbolsUsed.contains(name); | 236 return symbolsUsed.contains(name); |
| 241 } | 237 } |
| 242 | 238 |
| 243 @override | 239 @override |
| 244 bool retainMetadataOfParameter(ParameterElement element) { | 240 bool retainMetadataOfMember(covariant MemberElement element) { |
| 245 if (mustRetainMetadata) { | 241 if (mustRetainMetadata) { |
| 246 hasRetainedMetadata = true; | 242 hasRetainedMetadata = true; |
| 247 if (isParameterReferencedFromMirrorSystem(element)) { | 243 if (isMemberReferencedFromMirrorSystem(element)) { |
| 248 _retainMetadataOf(element); | 244 _addConstantsForEmission( |
| 245 getMemberMetadata(element, includeParameterMetadata: true)); |
| 249 return true; | 246 return true; |
| 250 } | 247 } |
| 251 } | 248 } |
| 252 return false; | |
| 253 } | |
| 254 | |
| 255 @override | |
| 256 bool retainMetadataOfMember(MemberElement element) { | |
| 257 if (mustRetainMetadata) { | |
| 258 hasRetainedMetadata = true; | |
| 259 if (isMemberReferencedFromMirrorSystem(element)) { | |
| 260 _retainMetadataOf(element); | |
| 261 return true; | |
| 262 } | |
| 263 } | |
| 264 return false; | 249 return false; |
| 265 } | 250 } |
| 266 | 251 |
| 267 @override | 252 @override |
| 268 bool retainMetadataOfClass(ClassElement element) { | 253 bool retainMetadataOfClass(ClassEntity element) { |
| 269 if (mustRetainMetadata) { | 254 if (mustRetainMetadata) { |
| 270 hasRetainedMetadata = true; | 255 hasRetainedMetadata = true; |
| 271 if (isClassReferencedFromMirrorSystem(element)) { | 256 if (isClassReferencedFromMirrorSystem(element)) { |
| 272 _retainMetadataOf(element); | 257 _addConstantsForEmission(getClassMetadata(element)); |
| 273 return true; | 258 return true; |
| 274 } | 259 } |
| 275 } | 260 } |
| 276 return false; | 261 return false; |
| 277 } | 262 } |
| 278 | 263 |
| 279 @override | 264 @override |
| 280 bool retainMetadataOfTypedef(TypedefElement element) { | 265 bool retainMetadataOfTypedef(TypedefEntity element) { |
| 281 if (mustRetainMetadata) { | 266 if (mustRetainMetadata) { |
| 282 hasRetainedMetadata = true; | 267 hasRetainedMetadata = true; |
| 283 if (isTypedefReferencedFromMirrorSystem(element)) { | 268 if (_isTypedefReferencedFromMirrorSystem(element)) { |
| 284 _retainMetadataOf(element); | 269 _addConstantsForEmission(getTypedefMetadata(element)); |
| 285 return true; | 270 return true; |
| 286 } | 271 } |
| 287 } | 272 } |
| 288 return false; | 273 return false; |
| 289 } | 274 } |
| 290 | 275 |
| 291 @override | 276 @override |
| 292 bool retainMetadataOfLibrary(LibraryElement element, | 277 bool retainMetadataOfLibrary(LibraryEntity element, |
| 293 {bool addForEmission: true}) { | 278 {bool addForEmission: true}) { |
| 294 if (mustRetainMetadata) { | 279 if (mustRetainMetadata) { |
| 295 hasRetainedMetadata = true; | 280 hasRetainedMetadata = true; |
| 296 if (isLibraryReferencedFromMirrorSystem(element)) { | 281 if (isLibraryReferencedFromMirrorSystem(element)) { |
| 297 _retainMetadataOf(element, addForEmission: addForEmission); | 282 Iterable<ConstantValue> constants = getLibraryMetadata(element); |
| 283 if (addForEmission) { |
| 284 _addConstantsForEmission(constants); |
| 285 } |
| 298 return true; | 286 return true; |
| 299 } | 287 } |
| 300 } | 288 } |
| 301 return false; | 289 return false; |
| 302 } | 290 } |
| 303 | 291 |
| 304 void _retainMetadataOf(Element element, {bool addForEmission: true}) { | 292 Iterable<ConstantValue> getLibraryMetadata(LibraryElement element) { |
| 305 for (MetadataAnnotation metadata in element.metadata) { | 293 return _elementEnvironment.getLibraryMetadata(element); |
| 306 metadata.ensureResolved(_compiler.resolution); | 294 } |
| 307 ConstantValue constant = _constants.getConstantValueForMetadata(metadata); | 295 |
| 308 if (addForEmission) { | 296 Iterable<ConstantValue> getClassMetadata(ClassElement element) { |
| 309 CodegenWorldBuilder worldBuilder = _compiler.codegenWorldBuilder; | 297 return _elementEnvironment.getClassMetadata(element); |
| 310 worldBuilder.addCompileTimeConstantForEmission(constant); | 298 } |
| 311 } | 299 |
| 300 Iterable<ConstantValue> getMemberMetadata(MemberEntity element, |
| 301 {bool includeParameterMetadata}) { |
| 302 return _elementEnvironment.getMemberMetadata(element, |
| 303 includeParameterMetadata: includeParameterMetadata); |
| 304 } |
| 305 |
| 306 Iterable<ConstantValue> getTypedefMetadata(TypedefElement element) { |
| 307 return _elementEnvironment.getTypedefMetadata(element); |
| 308 } |
| 309 |
| 310 void _addConstantsForEmission(Iterable<ConstantValue> constants) { |
| 311 for (ConstantValue constant in constants) { |
| 312 CodegenWorldBuilder worldBuilder = _compiler.codegenWorldBuilder; |
| 313 worldBuilder.addCompileTimeConstantForEmission(constant); |
| 312 } | 314 } |
| 313 } | 315 } |
| 314 | 316 |
| 315 /// Sets of elements that are needed by reflection. Computed using | 317 /// Sets of elements that are needed by reflection. Computed using |
| 316 /// [computeMembersNeededForReflection] on first use. | 318 /// [computeMembersNeededForReflection] on first use. |
| 317 Set<ClassElement> _classesNeededForReflection; | 319 Set<ClassEntity> _classesNeededForReflection; |
| 318 Set<TypedefElement> _typedefsNeededForReflection; | 320 Set<TypedefEntity> _typedefsNeededForReflection; |
| 319 Set<MemberElement> _membersNeededForReflection; | 321 Set<MemberEntity> _membersNeededForReflection; |
| 320 Set<LocalFunctionElement> _closuresNeededForReflection; | 322 Set<Local> _closuresNeededForReflection; |
| 321 | 323 |
| 322 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed | 324 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed |
| 323 /// annotations. The arguments corresponds to the unions of the corresponding | 325 /// annotations. The arguments corresponds to the unions of the corresponding |
| 324 /// fields of the annotations. | 326 /// fields of the annotations. |
| 325 // TODO(redemption): Change type of [metaTargets] to `Set<ClassEntity>`. | 327 // TODO(redemption): Change type of [metaTargets] to `Set<ClassEntity>`. |
| 326 void registerMirrorUsage( | 328 void registerMirrorUsage( |
| 327 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { | 329 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) { |
| 328 if (symbols == null && targets == null && metaTargets == null) { | 330 if (symbols == null && targets == null && metaTargets == null) { |
| 329 // The user didn't specify anything, or there are imports of | 331 // The user didn't specify anything, or there are imports of |
| 330 // 'dart:mirrors' without @MirrorsUsed. | 332 // 'dart:mirrors' without @MirrorsUsed. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 361 } | 363 } |
| 362 } | 364 } |
| 363 } | 365 } |
| 364 | 366 |
| 365 @override | 367 @override |
| 366 bool isClassAccessibleByReflection(ClassEntity element) { | 368 bool isClassAccessibleByReflection(ClassEntity element) { |
| 367 return _classesNeededForReflection.contains(_getDartClass(element)); | 369 return _classesNeededForReflection.contains(_getDartClass(element)); |
| 368 } | 370 } |
| 369 | 371 |
| 370 @override | 372 @override |
| 371 bool isTypedefAccessibleByReflection(TypedefElement element) { | 373 bool isTypedefAccessibleByReflection(TypedefEntity element) { |
| 372 return _typedefsNeededForReflection.contains(element); | 374 return _typedefsNeededForReflection.contains(element); |
| 373 } | 375 } |
| 374 | 376 |
| 375 bool isAccessibleByReflection(Element element) { | |
| 376 if (element.isLibrary) { | |
| 377 return false; | |
| 378 } else if (element.isClass) { | |
| 379 ClassElement cls = element; | |
| 380 return isClassAccessibleByReflection(cls); | |
| 381 } else if (element.isTypedef) { | |
| 382 return isTypedefAccessibleByReflection(element); | |
| 383 } else { | |
| 384 MemberElement member = element; | |
| 385 return isMemberAccessibleByReflection(member); | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 ClassEntity _getDartClass(ClassEntity cls) { | 377 ClassEntity _getDartClass(ClassEntity cls) { |
| 390 if (cls == _commonElements.jsIntClass) { | 378 if (cls == _commonElements.jsIntClass) { |
| 391 return _commonElements.intClass; | 379 return _commonElements.intClass; |
| 392 } else if (cls == _commonElements.jsBoolClass) { | 380 } else if (cls == _commonElements.jsBoolClass) { |
| 393 return _commonElements.boolClass; | 381 return _commonElements.boolClass; |
| 394 } else if (cls == _commonElements.jsNumberClass) { | 382 } else if (cls == _commonElements.jsNumberClass) { |
| 395 return _commonElements.numClass; | 383 return _commonElements.numClass; |
| 396 } else if (cls == _commonElements.jsDoubleClass) { | 384 } else if (cls == _commonElements.jsDoubleClass) { |
| 397 return _commonElements.doubleClass; | 385 return _commonElements.doubleClass; |
| 398 } else if (cls == _commonElements.jsStringClass) { | 386 } else if (cls == _commonElements.jsStringClass) { |
| 399 return _commonElements.stringClass; | 387 return _commonElements.stringClass; |
| 400 } else if (cls == _commonElements.jsArrayClass) { | 388 } else if (cls == _commonElements.jsArrayClass) { |
| 401 return _commonElements.listClass; | 389 return _commonElements.listClass; |
| 402 } else if (cls == _commonElements.jsNullClass) { | 390 } else if (cls == _commonElements.jsNullClass) { |
| 403 return _commonElements.nullClass; | 391 return _commonElements.nullClass; |
| 404 } else { | 392 } else { |
| 405 return cls; | 393 return cls; |
| 406 } | 394 } |
| 407 } | 395 } |
| 408 | 396 |
| 409 bool isMemberAccessibleByReflection(MemberEntity element) { | 397 bool isMemberAccessibleByReflection(MemberEntity element) { |
| 410 return _membersNeededForReflection.contains(element); | 398 return _membersNeededForReflection.contains(element); |
| 411 } | 399 } |
| 412 | 400 |
| 413 /// Returns true if this element has to be enqueued due to | 401 /// Returns true if this element has to be enqueued due to |
| 414 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if | 402 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if |
| 415 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). | 403 /// normal tree shaking is still active ([isTreeShakingDisabled] is false). |
| 416 bool requiredByMirrorSystem(Element element) { | 404 bool isLibraryRequiredByMirrorSystem(LibraryEntity element) { |
| 417 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || | 405 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || |
| 418 matchesMirrorsMetaTarget(element) || | 406 _libraryMatchesMirrorsMetaTarget(element) || |
| 419 classesInMirrorsUsedTargets.contains(element) || | 407 librariesInMirrorsUsedTargets.contains(element); |
| 420 membersInMirrorsUsedTargets.contains(element) || | 408 } |
| 421 librariesInMirrorsUsedTargets.contains(element) || | 409 |
| 422 _typedefsInMirrorsUsedTargets.contains(element); | 410 bool isClassRequiredByMirrorSystem(ClassEntity element) { |
| 411 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || |
| 412 _classMatchesMirrorsMetaTarget(element) || |
| 413 classesInMirrorsUsedTargets.contains(element); |
| 414 } |
| 415 |
| 416 bool isMemberRequiredByMirrorSystem(MemberEntity element) { |
| 417 return hasInsufficientMirrorsUsed && isTreeShakingDisabled || |
| 418 _memberMatchesMirrorsMetaTarget(element) || |
| 419 membersInMirrorsUsedTargets.contains(element); |
| 423 } | 420 } |
| 424 | 421 |
| 425 @override | 422 @override |
| 426 bool isLibraryReferencedFromMirrorSystem(LibraryElement element) { | 423 bool isLibraryReferencedFromMirrorSystem(LibraryEntity element) { |
| 427 return _libraryReferencedFromMirrorSystem(element); | 424 return _libraryReferencedFromMirrorSystem(element); |
| 428 } | 425 } |
| 429 | 426 |
| 430 @override | 427 @override |
| 431 bool isMemberReferencedFromMirrorSystem(MemberElement element) { | 428 bool isMemberReferencedFromMirrorSystem(MemberEntity element) { |
| 432 if (_memberReferencedFromMirrorSystem(element)) return true; | 429 if (_memberReferencedFromMirrorSystem(element)) return true; |
| 433 if (element.enclosingClass != null) { | 430 if (element.enclosingClass != null) { |
| 434 return isClassReferencedFromMirrorSystem(element.enclosingClass); | 431 return isClassReferencedFromMirrorSystem(element.enclosingClass); |
| 435 } else { | 432 } else { |
| 436 return isLibraryReferencedFromMirrorSystem(element.library); | 433 return isLibraryReferencedFromMirrorSystem(element.library); |
| 437 } | 434 } |
| 438 } | 435 } |
| 439 | 436 |
| 440 @override | 437 @override |
| 441 bool isClassReferencedFromMirrorSystem(ClassElement element) { | 438 bool isClassReferencedFromMirrorSystem(ClassEntity element) { |
| 442 return _classReferencedFromMirrorSystem(element) || | 439 return _classReferencedFromMirrorSystem(element) || |
| 443 isLibraryReferencedFromMirrorSystem(element.library); | 440 isLibraryReferencedFromMirrorSystem(element.library); |
| 444 } | 441 } |
| 445 | 442 |
| 446 bool isParameterReferencedFromMirrorSystem(ParameterElement element) { | 443 bool _isTypedefReferencedFromMirrorSystem(TypedefEntity element) { |
| 447 return _parameterReferencedFromMirrorSystem(element) || | |
| 448 isMemberReferencedFromMirrorSystem(element.memberContext); | |
| 449 } | |
| 450 | |
| 451 bool isTypedefReferencedFromMirrorSystem(TypedefElement element) { | |
| 452 return _typedefReferencedFromMirrorSystem(element) || | 444 return _typedefReferencedFromMirrorSystem(element) || |
| 453 isLibraryReferencedFromMirrorSystem(element.library); | 445 isLibraryReferencedFromMirrorSystem(element.library); |
| 454 } | 446 } |
| 455 | 447 |
| 456 bool _memberReferencedFromMirrorSystem(MemberElement element) { | 448 bool _memberReferencedFromMirrorSystem(MemberEntity element) { |
| 457 return hasInsufficientMirrorsUsed || | 449 return hasInsufficientMirrorsUsed || |
| 458 matchesMirrorsMetaTarget(element) || | 450 _memberMatchesMirrorsMetaTarget(element) || |
| 459 membersInMirrorsUsedTargets.contains(element); | 451 membersInMirrorsUsedTargets.contains(element); |
| 460 } | 452 } |
| 461 | 453 |
| 462 bool _parameterReferencedFromMirrorSystem(ParameterElement element) { | 454 bool _classReferencedFromMirrorSystem(ClassEntity element) { |
| 463 return hasInsufficientMirrorsUsed || matchesMirrorsMetaTarget(element); | |
| 464 } | |
| 465 | |
| 466 bool _classReferencedFromMirrorSystem(ClassElement element) { | |
| 467 return hasInsufficientMirrorsUsed || | 455 return hasInsufficientMirrorsUsed || |
| 468 matchesMirrorsMetaTarget(element) || | 456 _classMatchesMirrorsMetaTarget(element) || |
| 469 classesInMirrorsUsedTargets.contains(element); | 457 classesInMirrorsUsedTargets.contains(element); |
| 470 } | 458 } |
| 471 | 459 |
| 472 bool _typedefReferencedFromMirrorSystem(TypedefElement element) { | 460 bool _typedefReferencedFromMirrorSystem(TypedefEntity element) { |
| 473 return hasInsufficientMirrorsUsed || | 461 return hasInsufficientMirrorsUsed || |
| 474 matchesMirrorsMetaTarget(element) || | 462 _typedefMatchesMirrorsMetaTarget(element) || |
| 475 _typedefsInMirrorsUsedTargets.contains(element); | 463 _typedefsInMirrorsUsedTargets.contains(element); |
| 476 } | 464 } |
| 477 | 465 |
| 478 bool _libraryReferencedFromMirrorSystem(LibraryElement element) { | 466 bool _libraryReferencedFromMirrorSystem(LibraryEntity element) { |
| 479 return hasInsufficientMirrorsUsed || | 467 return hasInsufficientMirrorsUsed || |
| 480 matchesMirrorsMetaTarget(element) || | 468 _libraryMatchesMirrorsMetaTarget(element) || |
| 481 librariesInMirrorsUsedTargets.contains(element); | 469 librariesInMirrorsUsedTargets.contains(element); |
| 482 } | 470 } |
| 483 | 471 |
| 472 bool _libraryMatchesMirrorsMetaTarget(LibraryElement element) { |
| 473 if (metaTargetsUsed.isEmpty) return false; |
| 474 return _matchesMirrorsMetaTarget(getLibraryMetadata(element)); |
| 475 } |
| 476 |
| 477 bool _classMatchesMirrorsMetaTarget(ClassEntity element) { |
| 478 if (metaTargetsUsed.isEmpty) return false; |
| 479 return _matchesMirrorsMetaTarget(getClassMetadata(element)); |
| 480 } |
| 481 |
| 482 bool _memberMatchesMirrorsMetaTarget(MemberElement element) { |
| 483 if (metaTargetsUsed.isEmpty) return false; |
| 484 return _matchesMirrorsMetaTarget( |
| 485 getMemberMetadata(element, includeParameterMetadata: false)); |
| 486 } |
| 487 |
| 488 bool _typedefMatchesMirrorsMetaTarget(TypedefElement element) { |
| 489 if (metaTargetsUsed.isEmpty) return false; |
| 490 return _matchesMirrorsMetaTarget(getTypedefMetadata(element)); |
| 491 } |
| 492 |
| 484 /** | 493 /** |
| 485 * Returns `true` if the element is needed because it has an annotation | 494 * Returns `true` if the element is needed because it has an annotation |
| 486 * of a type that is used as a meta target for reflection. | 495 * of a type that is used as a meta target for reflection. |
| 487 */ | 496 */ |
| 488 bool matchesMirrorsMetaTarget(Element element) { | 497 bool _matchesMirrorsMetaTarget(Iterable<ConstantValue> constants) { |
| 489 if (metaTargetsUsed.isEmpty) return false; | 498 if (metaTargetsUsed.isEmpty) return false; |
| 490 for (MetadataAnnotation metadata in element.metadata) { | 499 for (ConstantValue constant in constants) { |
| 491 // TODO(kasperl): It would be nice if we didn't have to resolve | 500 DartType type = constant.getType(_commonElements); |
| 492 // all metadata but only stuff that potentially would match one | |
| 493 // of the used meta targets. | |
| 494 metadata.ensureResolved(_compiler.resolution); | |
| 495 ConstantValue value = | |
| 496 _compiler.constants.getConstantValue(metadata.constant); | |
| 497 if (value == null) continue; | |
| 498 DartType type = value.getType(_commonElements); | |
| 499 if (type is InterfaceType && metaTargetsUsed.contains(type.element)) | 501 if (type is InterfaceType && metaTargetsUsed.contains(type.element)) |
| 500 return true; | 502 return true; |
| 501 } | 503 } |
| 502 return false; | 504 return false; |
| 503 } | 505 } |
| 504 | 506 |
| 505 void createImmutableSets() { | 507 void createImmutableSets() { |
| 506 _classesNeededForReflection = const ImmutableEmptySet<ClassElement>(); | 508 _classesNeededForReflection = const ImmutableEmptySet<ClassElement>(); |
| 507 _typedefsNeededForReflection = const ImmutableEmptySet<TypedefElement>(); | 509 _typedefsNeededForReflection = const ImmutableEmptySet<TypedefElement>(); |
| 508 _membersNeededForReflection = const ImmutableEmptySet<MemberElement>(); | 510 _membersNeededForReflection = const ImmutableEmptySet<MemberElement>(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 522 * be visible by reflection unless some other interfaces makes them | 524 * be visible by reflection unless some other interfaces makes them |
| 523 * accessible. | 525 * accessible. |
| 524 */ | 526 */ |
| 525 void computeMembersNeededForReflection( | 527 void computeMembersNeededForReflection( |
| 526 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { | 528 ResolutionWorldBuilder worldBuilder, ClosedWorld closedWorld) { |
| 527 if (_membersNeededForReflection != null) return; | 529 if (_membersNeededForReflection != null) return; |
| 528 if (!closedWorld.backendUsage.isMirrorsUsed) { | 530 if (!closedWorld.backendUsage.isMirrorsUsed) { |
| 529 createImmutableSets(); | 531 createImmutableSets(); |
| 530 return; | 532 return; |
| 531 } | 533 } |
| 532 _classesNeededForReflection = new Set<ClassElement>(); | 534 _classesNeededForReflection = new Set<ClassEntity>(); |
| 533 _typedefsNeededForReflection = new Set<TypedefElement>(); | 535 _typedefsNeededForReflection = new Set<TypedefEntity>(); |
| 534 _membersNeededForReflection = new Set<MemberElement>(); | 536 _membersNeededForReflection = new Set<MemberEntity>(); |
| 535 _closuresNeededForReflection = new Set<LocalFunctionElement>(); | 537 _closuresNeededForReflection = new Set<Local>(); |
| 536 | 538 |
| 537 // Compute a mapping from class to the closures it contains, so we | 539 // Compute a mapping from class to the closures it contains, so we |
| 538 // can include the correct ones when including the class. | 540 // can include the correct ones when including the class. |
| 539 Map<ClassElement, List<LocalFunctionElement>> closureMap = | 541 Map<ClassEntity, List<Local>> closureMap = |
| 540 new Map<ClassElement, List<LocalFunctionElement>>(); | 542 new Map<ClassEntity, List<Local>>(); |
| 541 for (LocalFunctionElement closure in worldBuilder.localFunctions) { | 543 for (Local closure in worldBuilder.localFunctions) { |
| 542 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure); | 544 closureMap |
| 545 .putIfAbsent(closure.memberContext.enclosingClass, () => []) |
| 546 .add(closure); |
| 543 } | 547 } |
| 544 bool foundClosure = false; | 548 bool foundClosure = false; |
| 545 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { | 549 for (ClassElement cls in worldBuilder.directlyInstantiatedClasses) { |
| 546 // Do not process internal classes. | 550 // Do not process internal classes. |
| 547 if (cls.library.isInternalLibrary || cls.isInjected) continue; | 551 if (cls.library.isInternalLibrary || cls.isInjected) continue; |
| 548 if (isClassReferencedFromMirrorSystem(cls)) { | 552 if (isClassReferencedFromMirrorSystem(cls)) { |
| 549 Set<Name> memberNames = new Set<Name>(); | 553 Set<Name> memberNames = new Set<Name>(); |
| 550 // 1) the class (should be resolved) | 554 // 1) the class (should be resolved) |
| 551 assert(cls.isResolved, failedAt(cls)); | 555 assert(cls.isResolved, failedAt(cls)); |
| 552 _classesNeededForReflection.add(cls); | 556 _classesNeededForReflection.add(cls); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 580 // assert(worldBuilder.isMemberUsed(member.element), | 584 // assert(worldBuilder.isMemberUsed(member.element), |
| 581 // failedAt(member.element)); | 585 // failedAt(member.element)); |
| 582 if (worldBuilder.isMemberUsed(member.element)) { | 586 if (worldBuilder.isMemberUsed(member.element)) { |
| 583 _membersNeededForReflection.add(member.element); | 587 _membersNeededForReflection.add(member.element); |
| 584 } | 588 } |
| 585 } | 589 } |
| 586 }); | 590 }); |
| 587 }); | 591 }); |
| 588 } | 592 } |
| 589 // 5) all its closures | 593 // 5) all its closures |
| 590 List<LocalFunctionElement> closures = closureMap[cls]; | 594 List<Local> closures = closureMap[cls]; |
| 591 if (closures != null) { | 595 if (closures != null) { |
| 592 _closuresNeededForReflection.addAll(closures); | 596 _closuresNeededForReflection.addAll(closures); |
| 593 foundClosure = true; | 597 foundClosure = true; |
| 594 } | 598 } |
| 595 } else { | 599 } else { |
| 596 // check members themselves | 600 // check members themselves |
| 597 cls.constructors.forEach((Element _element) { | 601 cls.constructors.forEach((Element _element) { |
| 598 ConstructorElement element = _element; | 602 ConstructorElement element = _element; |
| 599 if (!worldBuilder.isMemberUsed(element)) return; | 603 if (!worldBuilder.isMemberUsed(element)) return; |
| 600 if (_memberReferencedFromMirrorSystem(element)) { | 604 if (_memberReferencedFromMirrorSystem(element)) { |
| 601 _membersNeededForReflection.add(element); | 605 _membersNeededForReflection.add(element); |
| 602 } | 606 } |
| 603 }); | 607 }); |
| 604 cls.forEachClassMember((Member member) { | 608 cls.forEachClassMember((Member member) { |
| 605 if (!worldBuilder.isMemberUsed(member.element)) return; | 609 if (!worldBuilder.isMemberUsed(member.element)) return; |
| 606 if (_memberReferencedFromMirrorSystem(member.element)) { | 610 if (_memberReferencedFromMirrorSystem(member.element)) { |
| 607 _membersNeededForReflection.add(member.element); | 611 _membersNeededForReflection.add(member.element); |
| 608 } | 612 } |
| 609 }); | 613 }); |
| 610 // Also add in closures. Those might be reflectable is their enclosing | 614 // Also add in closures. Those might be reflectable is their enclosing |
| 611 // member is. | 615 // member is. |
| 612 List<LocalFunctionElement> closures = closureMap[cls]; | 616 List<Local> closures = closureMap[cls]; |
| 613 if (closures != null) { | 617 if (closures != null) { |
| 614 for (LocalFunctionElement closure in closures) { | 618 for (Local closure in closures) { |
| 615 MemberElement member = closure.memberContext; | 619 MemberEntity member = closure.memberContext; |
| 616 if (_memberReferencedFromMirrorSystem(member)) { | 620 if (_memberReferencedFromMirrorSystem(member)) { |
| 617 _closuresNeededForReflection.add(closure); | 621 _closuresNeededForReflection.add(closure); |
| 618 foundClosure = true; | 622 foundClosure = true; |
| 619 } | 623 } |
| 620 } | 624 } |
| 621 } | 625 } |
| 622 } | 626 } |
| 623 } | 627 } |
| 624 // We also need top-level non-class elements like static functions and | 628 // We also need top-level non-class elements like static functions and |
| 625 // global fields. We use the resolution queue to decide which elements are | 629 // global fields. We use the resolution queue to decide which elements are |
| 626 // part of the live world. | 630 // part of the live world. |
| 627 for (LibraryElement lib in _compiler.libraryLoader.libraries) { | 631 for (LibraryElement lib in _compiler.libraryLoader.libraries) { |
| 628 if (lib.isInternalLibrary) continue; | 632 if (lib.isInternalLibrary) continue; |
| 629 lib.forEachLocalMember((Element element) { | 633 lib.forEachLocalMember((Element element) { |
| 630 if (element.isClass || element.isTypedef) return; | 634 if (element.isClass || element.isTypedef) return; |
| 631 MemberElement member = element; | 635 MemberElement member = element; |
| 632 if (worldBuilder.isMemberUsed(member) && | 636 if (worldBuilder.isMemberUsed(member) && |
| 633 isMemberReferencedFromMirrorSystem(member)) { | 637 isMemberReferencedFromMirrorSystem(member)) { |
| 634 _membersNeededForReflection.add(member); | 638 _membersNeededForReflection.add(member); |
| 635 } | 639 } |
| 636 }); | 640 }); |
| 637 } | 641 } |
| 638 // And closures inside top-level elements that do not have a surrounding | 642 // And closures inside top-level elements that do not have a surrounding |
| 639 // class. These will be in the [:null:] bucket of the [closureMap]. | 643 // class. These will be in the [:null:] bucket of the [closureMap]. |
| 640 if (closureMap.containsKey(null)) { | 644 if (closureMap.containsKey(null)) { |
| 641 for (LocalFunctionElement closure in closureMap[null]) { | 645 for (Local closure in closureMap[null]) { |
| 642 if (isMemberReferencedFromMirrorSystem(closure.memberContext)) { | 646 if (isMemberReferencedFromMirrorSystem(closure.memberContext)) { |
| 643 _closuresNeededForReflection.add(closure); | 647 _closuresNeededForReflection.add(closure); |
| 644 foundClosure = true; | 648 foundClosure = true; |
| 645 } | 649 } |
| 646 } | 650 } |
| 647 } | 651 } |
| 648 // As we do not think about closures as classes, yet, we have to make sure | 652 // As we do not think about closures as classes, yet, we have to make sure |
| 649 // their superclasses are available for reflection manually. | 653 // their superclasses are available for reflection manually. |
| 650 if (foundClosure) { | 654 if (foundClosure) { |
| 651 ClassElement cls = _commonElements.closureClass; | 655 ClassEntity cls = _commonElements.closureClass; |
| 652 _classesNeededForReflection.add(cls); | 656 _classesNeededForReflection.add(cls); |
| 653 } | 657 } |
| 654 Set<FunctionEntity> closurizedMembers = worldBuilder.closurizedMembers; | 658 Set<FunctionEntity> closurizedMembers = worldBuilder.closurizedMembers; |
| 655 if (closurizedMembers.any(_membersNeededForReflection.contains)) { | 659 if (closurizedMembers.any(_membersNeededForReflection.contains)) { |
| 656 ClassElement cls = _commonElements.boundClosureClass; | 660 ClassEntity cls = _commonElements.boundClosureClass; |
| 657 _classesNeededForReflection.add(cls); | 661 _classesNeededForReflection.add(cls); |
| 658 } | 662 } |
| 659 // Add typedefs. | 663 // Add typedefs. |
| 660 for (TypedefElement element in closedWorld.allTypedefs) { | 664 for (TypedefEntity element in closedWorld.allTypedefs) { |
| 661 if (isTypedefReferencedFromMirrorSystem(element)) { | 665 if (_isTypedefReferencedFromMirrorSystem(element)) { |
| 662 _typedefsNeededForReflection.add(element); | 666 _typedefsNeededForReflection.add(element); |
| 663 } | 667 } |
| 664 } | 668 } |
| 665 // Register all symbols of reflectable elements | 669 // Register all symbols of reflectable elements |
| 666 for (ClassElement element in _classesNeededForReflection) { | 670 for (ClassEntity element in _classesNeededForReflection) { |
| 667 symbolsUsed.add(element.name); | 671 symbolsUsed.add(element.name); |
| 668 } | 672 } |
| 669 for (TypedefElement element in _typedefsNeededForReflection) { | 673 for (TypedefEntity element in _typedefsNeededForReflection) { |
| 670 symbolsUsed.add(element.name); | 674 symbolsUsed.add(element.name); |
| 671 } | 675 } |
| 672 for (MemberElement element in _membersNeededForReflection) { | 676 for (MemberEntity element in _membersNeededForReflection) { |
| 673 symbolsUsed.add(element.name); | 677 symbolsUsed.add(element.name); |
| 674 } | 678 } |
| 675 for (LocalFunctionElement element in _closuresNeededForReflection) { | 679 for (Local element in _closuresNeededForReflection) { |
| 676 symbolsUsed.add(element.name); | 680 symbolsUsed.add(element.name); |
| 677 } | 681 } |
| 678 } | 682 } |
| 679 | 683 |
| 680 // 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 |
| 681 // [computeMembersNeededForReflection]. | 685 // [computeMembersNeededForReflection]. |
| 682 void maybeMarkClosureAsNeededForReflection( | 686 void maybeMarkClosureAsNeededForReflection( |
| 683 ClosureClassElement globalizedElement, | 687 ClosureClassElement globalizedElement, |
| 684 MethodElement callFunction, | 688 MethodElement callFunction, |
| 685 LocalFunctionElement function) { | 689 LocalFunctionElement function) { |
| 686 if (!_closuresNeededForReflection.contains(function)) return; | 690 if (!_closuresNeededForReflection.contains(function)) return; |
| 687 _membersNeededForReflection.add(callFunction); | 691 _membersNeededForReflection.add(callFunction); |
| 688 _classesNeededForReflection.add(globalizedElement); | 692 _classesNeededForReflection.add(globalizedElement); |
| 689 } | 693 } |
| 690 | 694 |
| 691 /// Called when `const Symbol(name)` is seen. | 695 /// Called when `const Symbol(name)` is seen. |
| 692 void registerConstSymbol(String name) { | 696 void registerConstSymbol(String name) { |
| 693 symbolsUsed.add(name); | 697 symbolsUsed.add(name); |
| 694 if (name.endsWith('=')) { | 698 if (name.endsWith('=')) { |
| 695 symbolsUsed.add(name.substring(0, name.length - 1)); | 699 symbolsUsed.add(name.substring(0, name.length - 1)); |
| 696 } | 700 } |
| 697 } | 701 } |
| 698 } | 702 } |
| OLD | NEW |