| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.mirrors_handler; | 5 library dart2js.mirrors_handler; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/resolution.dart'; | 8 import '../common/resolution.dart'; |
| 9 import '../compiler.dart'; | 9 import '../compiler.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| 11 import '../diagnostics/diagnostic_listener.dart'; | 11 import '../diagnostics/diagnostic_listener.dart'; |
| 12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
| 13 import '../elements/entities.dart'; | 13 import '../elements/entities.dart'; |
| 14 import '../enqueue.dart'; | 14 import '../enqueue.dart'; |
| 15 import '../universe/selector.dart'; | 15 import '../universe/selector.dart'; |
| 16 import '../universe/use.dart'; | 16 import '../universe/use.dart'; |
| 17 import '../universe/world_impact.dart'; | 17 import '../universe/world_impact.dart'; |
| 18 import 'backend.dart'; | 18 import 'backend.dart'; |
| 19 import 'constant_handler_javascript.dart'; | 19 import 'constant_handler_javascript.dart'; |
| 20 import 'mirrors_data.dart'; | 20 import 'mirrors_data.dart'; |
| 21 | 21 |
| 22 class MirrorsAnalysis { | 22 abstract class MirrorsResolutionAnalysis { |
| 23 final JavaScriptBackend backend; | 23 void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses); |
| 24 final MirrorsHandler resolutionHandler; | |
| 25 final MirrorsHandler codegenHandler; | |
| 26 | 24 |
| 27 /// List of constants from metadata. If metadata must be preserved, | 25 void onResolutionComplete(); |
| 28 /// these constants must be registered. | 26 |
| 29 final List<Dependency> metadataConstants = <Dependency>[]; | 27 /// Close this analysis and create the [MirrorsCodegenAnalysis] for the |
| 28 /// collected data. |
| 29 MirrorsCodegenAnalysis close(); |
| 30 } |
| 31 |
| 32 abstract class MirrorsCodegenAnalysis { |
| 33 void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses); |
| 34 |
| 35 /// Number of methods compiled before considering reflection. |
| 36 int get preMirrorsMethodCount; |
| 37 } |
| 38 |
| 39 class MirrorsResolutionAnalysisImpl implements MirrorsResolutionAnalysis { |
| 40 final JavaScriptBackend _backend; |
| 41 final MirrorsHandler handler; |
| 30 | 42 |
| 31 /// Set of elements for which metadata has been registered as dependencies. | 43 /// Set of elements for which metadata has been registered as dependencies. |
| 32 final Set<Element> _registeredMetadata = new Set<Element>(); | 44 final Set<Element> _registeredMetadata = new Set<Element>(); |
| 33 | 45 |
| 34 StagedWorldImpactBuilder constantImpactsForResolution = | 46 /// List of constants from metadata. If metadata must be preserved, |
| 35 new StagedWorldImpactBuilder(); | 47 /// these constants must be registered. |
| 48 final List<Dependency> _metadataConstants = <Dependency>[]; |
| 36 | 49 |
| 37 StagedWorldImpactBuilder constantImpactsForCodegen = | 50 StagedWorldImpactBuilder _impactBuilder = new StagedWorldImpactBuilder(); |
| 38 new StagedWorldImpactBuilder(); | |
| 39 | 51 |
| 40 /// Number of methods compiled before considering reflection. | 52 MirrorsResolutionAnalysisImpl(this._backend, Resolution resolution) |
| 41 int preMirrorsMethodCount = 0; | 53 : handler = new MirrorsHandler(_backend, resolution); |
| 42 | 54 |
| 43 MirrorsAnalysis(this.backend, Resolution resolution) | 55 DiagnosticReporter get _reporter => _backend.reporter; |
| 44 : resolutionHandler = new MirrorsHandler(backend, resolution), | 56 Compiler get _compiler => _backend.compiler; |
| 45 codegenHandler = new MirrorsHandler(backend, resolution); | 57 JavaScriptConstantCompiler get _constants => _backend.constants; |
| 46 | 58 MirrorsData get _mirrorsData => _backend.mirrorsData; |
| 47 DiagnosticReporter get reporter => backend.reporter; | |
| 48 Compiler get compiler => backend.compiler; | |
| 49 JavaScriptConstantCompiler get constants => backend.constants; | |
| 50 MirrorsData get mirrorsData => backend.mirrorsData; | |
| 51 | 59 |
| 52 /// Returns all static fields that are referenced through | 60 /// Returns all static fields that are referenced through |
| 53 /// `mirrorsData.targetsUsed`. If the target is a library or class all nested | 61 /// `mirrorsData.targetsUsed`. If the target is a library or class all nested |
| 54 /// static fields are included too. | 62 /// static fields are included too. |
| 55 Iterable<Element> _findStaticFieldTargets() { | 63 Iterable<Element> _findStaticFieldTargets() { |
| 56 List staticFields = []; | 64 List staticFields = []; |
| 57 | 65 |
| 58 void addFieldsInContainer(ScopeContainerElement container) { | 66 void addFieldsInContainer(ScopeContainerElement container) { |
| 59 container.forEachLocalMember((Element member) { | 67 container.forEachLocalMember((Element member) { |
| 60 if (!member.isInstanceMember && member.isField) { | 68 if (!member.isInstanceMember && member.isField) { |
| 61 staticFields.add(member); | 69 staticFields.add(member); |
| 62 } else if (member.isClass) { | 70 } else if (member.isClass) { |
| 63 addFieldsInContainer(member); | 71 addFieldsInContainer(member); |
| 64 } | 72 } |
| 65 }); | 73 }); |
| 66 } | 74 } |
| 67 | 75 |
| 68 for (Element target in mirrorsData.targetsUsed) { | 76 for (Element target in _mirrorsData.targetsUsed) { |
| 69 if (target == null) continue; | 77 if (target == null) continue; |
| 70 if (target.isField) { | 78 if (target.isField) { |
| 71 staticFields.add(target); | 79 staticFields.add(target); |
| 72 } else if (target.isLibrary || target.isClass) { | 80 } else if (target.isLibrary || target.isClass) { |
| 73 addFieldsInContainer(target); | 81 addFieldsInContainer(target); |
| 74 } | 82 } |
| 75 } | 83 } |
| 76 return staticFields; | 84 return staticFields; |
| 77 } | 85 } |
| 78 | 86 |
| 87 /// Compute the impact for elements that are matched by the mirrors used |
| 88 /// annotation or, in lack thereof, all elements. |
| 89 WorldImpact _computeImpactForReflectiveElements( |
| 90 Iterable<ClassEntity> recents, |
| 91 Iterable<ClassEntity> processedClasses, |
| 92 Iterable<LibraryElement> loadedLibraries) { |
| 93 handler.enqueueReflectiveElements( |
| 94 recents, processedClasses, loadedLibraries); |
| 95 return handler.flush(); |
| 96 } |
| 97 |
| 98 /// Compute the impact for the static fields that have been marked as used by |
| 99 /// reflective usage through `MirrorsUsed`. |
| 100 WorldImpact _computeImpactForReflectiveStaticFields( |
| 101 Iterable<Element> elements) { |
| 102 handler.enqueueReflectiveStaticFields(elements); |
| 103 return handler.flush(); |
| 104 } |
| 105 |
| 106 void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) { |
| 107 if (_mirrorsData.isTreeShakingDisabled) { |
| 108 enqueuer.applyImpact(_computeImpactForReflectiveElements(recentClasses, |
| 109 enqueuer.processedClasses, _compiler.libraryLoader.libraries)); |
| 110 } else if (!_mirrorsData.targetsUsed.isEmpty) { |
| 111 // Add all static elements (not classes) that have been requested for |
| 112 // reflection. If there is no mirror-usage these are probably not |
| 113 // necessary, but the backend relies on them being resolved. |
| 114 enqueuer.applyImpact( |
| 115 _computeImpactForReflectiveStaticFields(_findStaticFieldTargets())); |
| 116 } |
| 117 |
| 118 if (_mirrorsData.mustPreserveNames) _reporter.log('Preserving names.'); |
| 119 |
| 120 if (_mirrorsData.mustRetainMetadata) { |
| 121 _reporter.log('Retaining metadata.'); |
| 122 |
| 123 _compiler.libraryLoader.libraries.forEach(_mirrorsData.retainMetadataOf); |
| 124 |
| 125 if (!enqueuer.queueIsClosed) { |
| 126 /// Register the constant value of [metadata] as live in resolution. |
| 127 void registerMetadataConstant(MetadataAnnotation metadata) { |
| 128 ConstantValue constant = |
| 129 _constants.getConstantValueForMetadata(metadata); |
| 130 Dependency dependency = |
| 131 new Dependency(constant, metadata.annotatedElement); |
| 132 _metadataConstants.add(dependency); |
| 133 _impactBuilder.registerConstantUse(new ConstantUse.mirrors(constant)); |
| 134 } |
| 135 |
| 136 // TODO(johnniwinther): We should have access to all recently processed |
| 137 // elements and process these instead. |
| 138 processMetadata(enqueuer.processedEntities, registerMetadataConstant); |
| 139 } else { |
| 140 for (Dependency dependency in _metadataConstants) { |
| 141 _impactBuilder.registerConstantUse( |
| 142 new ConstantUse.mirrors(dependency.constant)); |
| 143 } |
| 144 _metadataConstants.clear(); |
| 145 } |
| 146 enqueuer.applyImpact(_impactBuilder.flush()); |
| 147 } |
| 148 } |
| 149 |
| 79 /// Call [registerMetadataConstant] on all metadata from [entities]. | 150 /// Call [registerMetadataConstant] on all metadata from [entities]. |
| 80 void processMetadata( | 151 void processMetadata( |
| 81 Iterable<Entity> entities, void onMetadata(MetadataAnnotation metadata)) { | 152 Iterable<Entity> entities, void onMetadata(MetadataAnnotation metadata)) { |
| 82 void processLibraryMetadata(LibraryElement library) { | 153 void processLibraryMetadata(LibraryElement library) { |
| 83 if (_registeredMetadata.add(library)) { | 154 if (_registeredMetadata.add(library)) { |
| 84 library.metadata.forEach(onMetadata); | 155 library.metadata.forEach(onMetadata); |
| 85 library.entryCompilationUnit.metadata.forEach(onMetadata); | 156 library.entryCompilationUnit.metadata.forEach(onMetadata); |
| 86 for (ImportElement import in library.imports) { | 157 for (ImportElement import in library.imports) { |
| 87 import.metadata.forEach(onMetadata); | 158 import.metadata.forEach(onMetadata); |
| 88 } | 159 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 110 } | 181 } |
| 111 } else { | 182 } else { |
| 112 processLibraryMetadata(element.library); | 183 processLibraryMetadata(element.library); |
| 113 } | 184 } |
| 114 } | 185 } |
| 115 } | 186 } |
| 116 | 187 |
| 117 entities.forEach(processElementMetadata); | 188 entities.forEach(processElementMetadata); |
| 118 } | 189 } |
| 119 | 190 |
| 120 void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) { | |
| 121 if (!enqueuer.isResolutionQueue && preMirrorsMethodCount == 0) { | |
| 122 preMirrorsMethodCount = backend.generatedCode.length; | |
| 123 } | |
| 124 if (mirrorsData.isTreeShakingDisabled) { | |
| 125 enqueuer.applyImpact(_computeImpactForReflectiveElements(recentClasses, | |
| 126 enqueuer.processedClasses, compiler.libraryLoader.libraries, | |
| 127 forResolution: enqueuer.isResolutionQueue)); | |
| 128 } else if (!mirrorsData.targetsUsed.isEmpty && enqueuer.isResolutionQueue) { | |
| 129 // Add all static elements (not classes) that have been requested for | |
| 130 // reflection. If there is no mirror-usage these are probably not | |
| 131 // necessary, but the backend relies on them being resolved. | |
| 132 enqueuer.applyImpact( | |
| 133 _computeImpactForReflectiveStaticFields(_findStaticFieldTargets())); | |
| 134 } | |
| 135 | |
| 136 if (mirrorsData.mustPreserveNames) reporter.log('Preserving names.'); | |
| 137 | |
| 138 if (mirrorsData.mustRetainMetadata) { | |
| 139 reporter.log('Retaining metadata.'); | |
| 140 | |
| 141 compiler.libraryLoader.libraries.forEach(mirrorsData.retainMetadataOf); | |
| 142 | |
| 143 StagedWorldImpactBuilder impactBuilder = enqueuer.isResolutionQueue | |
| 144 ? constantImpactsForResolution | |
| 145 : constantImpactsForCodegen; | |
| 146 if (enqueuer.isResolutionQueue && !enqueuer.queueIsClosed) { | |
| 147 /// Register the constant value of [metadata] as live in resolution. | |
| 148 void registerMetadataConstant(MetadataAnnotation metadata) { | |
| 149 ConstantValue constant = | |
| 150 constants.getConstantValueForMetadata(metadata); | |
| 151 Dependency dependency = | |
| 152 new Dependency(constant, metadata.annotatedElement); | |
| 153 metadataConstants.add(dependency); | |
| 154 impactBuilder.registerConstantUse(new ConstantUse.mirrors(constant)); | |
| 155 } | |
| 156 | |
| 157 // TODO(johnniwinther): We should have access to all recently processed | |
| 158 // elements and process these instead. | |
| 159 processMetadata(enqueuer.processedEntities, registerMetadataConstant); | |
| 160 } else { | |
| 161 for (Dependency dependency in metadataConstants) { | |
| 162 impactBuilder.registerConstantUse( | |
| 163 new ConstantUse.mirrors(dependency.constant)); | |
| 164 } | |
| 165 metadataConstants.clear(); | |
| 166 } | |
| 167 enqueuer.applyImpact(impactBuilder.flush()); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void onResolutionComplete() { | 191 void onResolutionComplete() { |
| 172 _registeredMetadata.clear(); | 192 _registeredMetadata.clear(); |
| 173 } | 193 } |
| 174 | 194 |
| 195 MirrorsCodegenAnalysis close() => new MirrorsCodegenAnalysisImpl( |
| 196 _backend, handler._resolution, _metadataConstants); |
| 197 } |
| 198 |
| 199 class MirrorsCodegenAnalysisImpl implements MirrorsCodegenAnalysis { |
| 200 final JavaScriptBackend _backend; |
| 201 final MirrorsHandler handler; |
| 202 |
| 203 StagedWorldImpactBuilder _impactBuilder = new StagedWorldImpactBuilder(); |
| 204 |
| 205 /// List of constants from metadata. If metadata must be preserved, |
| 206 /// these constants must be registered. |
| 207 final List<Dependency> _metadataConstants; |
| 208 |
| 209 /// Number of methods compiled before considering reflection. |
| 210 int preMirrorsMethodCount = 0; |
| 211 |
| 212 MirrorsCodegenAnalysisImpl( |
| 213 this._backend, Resolution resolution, this._metadataConstants) |
| 214 : handler = new MirrorsHandler(_backend, resolution); |
| 215 |
| 216 DiagnosticReporter get _reporter => _backend.reporter; |
| 217 Compiler get _compiler => _backend.compiler; |
| 218 JavaScriptConstantCompiler get _constants => _backend.constants; |
| 219 MirrorsData get _mirrorsData => _backend.mirrorsData; |
| 220 |
| 175 /// Compute the impact for elements that are matched by the mirrors used | 221 /// Compute the impact for elements that are matched by the mirrors used |
| 176 /// annotation or, in lack thereof, all elements. | 222 /// annotation or, in lack thereof, all elements. |
| 177 WorldImpact _computeImpactForReflectiveElements( | 223 WorldImpact _computeImpactForReflectiveElements( |
| 178 Iterable<ClassEntity> recents, | 224 Iterable<ClassEntity> recents, |
| 179 Iterable<ClassEntity> processedClasses, | 225 Iterable<ClassEntity> processedClasses, |
| 180 Iterable<LibraryElement> loadedLibraries, | 226 Iterable<LibraryElement> loadedLibraries) { |
| 181 {bool forResolution}) { | |
| 182 MirrorsHandler handler = forResolution ? resolutionHandler : codegenHandler; | |
| 183 handler.enqueueReflectiveElements( | 227 handler.enqueueReflectiveElements( |
| 184 recents, processedClasses, loadedLibraries); | 228 recents, processedClasses, loadedLibraries); |
| 185 return handler.flush(); | 229 return handler.flush(); |
| 186 } | 230 } |
| 187 | 231 |
| 188 /// Compute the impact for the static fields that have been marked as used by | 232 void onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) { |
| 189 /// reflective usage through `MirrorsUsed`. | 233 if (preMirrorsMethodCount == 0) { |
| 190 WorldImpact _computeImpactForReflectiveStaticFields( | 234 preMirrorsMethodCount = _backend.generatedCode.length; |
| 191 Iterable<Element> elements) { | 235 } |
| 192 resolutionHandler.enqueueReflectiveStaticFields(elements); | 236 if (_mirrorsData.isTreeShakingDisabled) { |
| 193 return resolutionHandler.flush(); | 237 enqueuer.applyImpact(_computeImpactForReflectiveElements(recentClasses, |
| 238 enqueuer.processedClasses, _compiler.libraryLoader.libraries)); |
| 239 } |
| 240 |
| 241 if (_mirrorsData.mustPreserveNames) _reporter.log('Preserving names.'); |
| 242 |
| 243 if (_mirrorsData.mustRetainMetadata) { |
| 244 _reporter.log('Retaining metadata.'); |
| 245 |
| 246 _compiler.libraryLoader.libraries.forEach(_mirrorsData.retainMetadataOf); |
| 247 |
| 248 for (Dependency dependency in _metadataConstants) { |
| 249 _impactBuilder |
| 250 .registerConstantUse(new ConstantUse.mirrors(dependency.constant)); |
| 251 } |
| 252 _metadataConstants.clear(); |
| 253 enqueuer.applyImpact(_impactBuilder.flush()); |
| 254 } |
| 194 } | 255 } |
| 195 } | 256 } |
| 196 | 257 |
| 197 class MirrorsHandler { | 258 class MirrorsHandler { |
| 198 static final TRACE_MIRROR_ENQUEUING = | 259 static final TRACE_MIRROR_ENQUEUING = |
| 199 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); | 260 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); |
| 200 | 261 |
| 201 final JavaScriptBackend _backend; | 262 final JavaScriptBackend _backend; |
| 202 final Resolution _resolution; | 263 final Resolution _resolution; |
| 203 | 264 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 | 468 |
| 408 /// Records that [constant] is used by the element behind [registry]. | 469 /// Records that [constant] is used by the element behind [registry]. |
| 409 class Dependency { | 470 class Dependency { |
| 410 final ConstantValue constant; | 471 final ConstantValue constant; |
| 411 final Element annotatedElement; | 472 final Element annotatedElement; |
| 412 | 473 |
| 413 const Dependency(this.constant, this.annotatedElement); | 474 const Dependency(this.constant, this.annotatedElement); |
| 414 | 475 |
| 415 String toString() => '$annotatedElement:${constant.toStructuredText()}'; | 476 String toString() => '$annotatedElement:${constant.toStructuredText()}'; |
| 416 } | 477 } |
| OLD | NEW |