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