Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(754)

Side by Side Diff: pkg/compiler/lib/src/js_backend/mirrors_data.dart

Issue 2688413003: Extract BackendUsage, MirrorsData, and CheckedModeHelpers from Backend. (Closed)
Patch Set: Cleanup Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import '../closure.dart';
6 import '../common.dart';
7 import '../compiler.dart';
8 import '../constants/values.dart';
9 import '../elements/elements.dart';
10 import '../elements/resolution_types.dart';
11 import '../enqueue.dart';
12 import '../world.dart';
13 import '../util/emptyset.dart';
14
15 class MirrorsData {
16 /// True if a call to preserveMetadataMarker has been seen. This means that
17 /// metadata must be retained for dart:mirrors to work correctly.
18 bool mustRetainMetadata = false;
19
20 /// True if any metadata has been retained. This is slightly different from
21 /// [mustRetainMetadata] and tells us if any metadata was retained. For
22 /// example, if [mustRetainMetadata] is true but there is no metadata in the
23 /// program, this variable will stil be false.
24 bool hasRetainedMetadata = false;
25
26 /// True if a call to preserveLibraryNames has been seen.
27 bool mustRetainLibraryNames = false;
28
29 /// True if a call to preserveNames has been seen.
30 bool mustPreserveNames = false;
31
32 /// True if a call to disableTreeShaking has been seen.
33 bool isTreeShakingDisabled = false;
34
35 /// True if there isn't sufficient @MirrorsUsed data.
36 bool hasInsufficientMirrorsUsed = false;
37
38 /// List of symbols that the user has requested for reflection.
39 final Set<String> symbolsUsed = new Set<String>();
40
41 /// List of elements that the user has requested for reflection.
42 final Set<Element> targetsUsed = new Set<Element>();
43
44 /// List of annotations provided by user that indicate that the annotated
45 /// element must be retained.
46 final Set<Element> metaTargetsUsed = new Set<Element>();
47
48 final Compiler compiler;
49
50 MirrorsData(this.compiler);
51
52 /// Should [element] (a getter) that would normally not be generated due to
53 /// treeshaking be retained for reflection?
54 bool shouldRetainGetter(Element element) {
55 return isTreeShakingDisabled && isAccessibleByReflection(element);
56 }
57
58 /// Should [element] (a setter) hat would normally not be generated due to
59 /// treeshaking be retained for reflection?
60 bool shouldRetainSetter(Element element) {
61 return isTreeShakingDisabled && isAccessibleByReflection(element);
62 }
63
64 /// Should [name] be retained for reflection?
65 bool shouldRetainName(String name) {
66 if (hasInsufficientMirrorsUsed) return mustPreserveNames;
67 if (name == '') return false;
68 return symbolsUsed.contains(name);
69 }
70
71 bool retainMetadataOf(Element element) {
72 if (mustRetainMetadata) hasRetainedMetadata = true;
73 if (mustRetainMetadata && referencedFromMirrorSystem(element)) {
74 for (MetadataAnnotation metadata in element.metadata) {
75 metadata.ensureResolved(compiler.resolution);
76 ConstantValue constant =
77 compiler.backend.constants.getConstantValueForMetadata(metadata);
78 compiler.backend.constants.addCompileTimeConstantForEmission(constant);
79 }
80 return true;
81 }
82 return false;
83 }
84
85 bool invokedReflectively(Element element) {
86 if (element.isRegularParameter || element.isInitializingFormal) {
87 ParameterElement parameter = element;
88 if (invokedReflectively(parameter.functionDeclaration)) return true;
89 }
90
91 if (element.isField) {
92 if (Elements.isStaticOrTopLevel(element) &&
93 (element.isFinal || element.isConst)) {
94 return false;
95 }
96 }
97
98 return isAccessibleByReflection(element.declaration);
99 }
100
101 /// Set of methods that are needed by reflection. Computed using
102 /// [computeMembersNeededForReflection] on first use.
103 Set<Element> _membersNeededForReflection = null;
104 Iterable<Element> get membersNeededForReflection {
105 assert(_membersNeededForReflection != null);
106 return _membersNeededForReflection;
107 }
108
109 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
110 /// annotations. The arguments corresponds to the unions of the corresponding
111 /// fields of the annotations.
112 void registerMirrorUsage(
113 Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) {
114 if (symbols == null && targets == null && metaTargets == null) {
115 // The user didn't specify anything, or there are imports of
116 // 'dart:mirrors' without @MirrorsUsed.
117 hasInsufficientMirrorsUsed = true;
118 return;
119 }
120 if (symbols != null) symbolsUsed.addAll(symbols);
121 if (targets != null) {
122 for (Element target in targets) {
123 if (target.isAbstractField) {
124 AbstractFieldElement field = target;
125 targetsUsed.add(field.getter);
126 targetsUsed.add(field.setter);
127 } else {
128 targetsUsed.add(target);
129 }
130 }
131 }
132 if (metaTargets != null) metaTargetsUsed.addAll(metaTargets);
133 }
134
135 /**
136 * Returns `true` if [element] can be accessed through reflection, that is,
137 * is in the set of elements covered by a `MirrorsUsed` annotation.
138 *
139 * This property is used to tag emitted elements with a marker which is
140 * checked by the runtime system to throw an exception if an element is
141 * accessed (invoked, get, set) that is not accessible for the reflective
142 * system.
143 */
144 bool isAccessibleByReflection(Element element) {
145 if (element.isClass) {
146 element = compiler.backend.getDartClass(element);
147 }
148 return membersNeededForReflection.contains(element);
149 }
150
151 /// Returns `true` if this member element needs reflection information at
152 /// runtime.
153 bool isMemberAccessibleByReflection(MemberElement element) {
154 return membersNeededForReflection.contains(element);
155 }
156
157 /// Returns true if this element has to be enqueued due to
158 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
159 /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
160 bool requiredByMirrorSystem(Element element) {
161 return hasInsufficientMirrorsUsed && isTreeShakingDisabled ||
162 matchesMirrorsMetaTarget(element) ||
163 targetsUsed.contains(element);
164 }
165
166 /// Returns true if this element is covered by a mirrorsUsed annotation.
167 ///
168 /// Note that it might still be ok to tree shake the element away if no
169 /// reflection is used in the program (and thus [isTreeShakingDisabled] is
170 /// still false). Therefore _do not_ use this predicate to decide inclusion
171 /// in the tree, use [requiredByMirrorSystem] instead.
172 bool referencedFromMirrorSystem(Element element, [recursive = true]) {
173 Element enclosing = recursive ? element.enclosingElement : null;
174
175 return hasInsufficientMirrorsUsed ||
176 matchesMirrorsMetaTarget(element) ||
177 targetsUsed.contains(element) ||
178 (enclosing != null && referencedFromMirrorSystem(enclosing));
179 }
180
181 /**
182 * Returns `true` if the element is needed because it has an annotation
183 * of a type that is used as a meta target for reflection.
184 */
185 bool matchesMirrorsMetaTarget(Element element) {
186 if (metaTargetsUsed.isEmpty) return false;
187 for (MetadataAnnotation metadata in element.metadata) {
188 // TODO(kasperl): It would be nice if we didn't have to resolve
189 // all metadata but only stuff that potentially would match one
190 // of the used meta targets.
191 metadata.ensureResolved(compiler.resolution);
192 ConstantValue value =
193 compiler.constants.getConstantValue(metadata.constant);
194 if (value == null) continue;
195 ResolutionDartType type = value.getType(compiler.commonElements);
196 if (metaTargetsUsed.contains(type.element)) return true;
197 }
198 return false;
199 }
200
201 /**
202 * Visits all classes and computes whether its members are needed for
203 * reflection.
204 *
205 * We have to precompute this set as we cannot easily answer the need for
206 * reflection locally when looking at the member: We lack the information by
207 * which classes a member is inherited. Called after resolution is complete.
208 *
209 * We filter out private libraries here, as their elements should not
210 * be visible by reflection unless some other interfaces makes them
211 * accessible.
212 */
213 void computeMembersNeededForReflection(ClosedWorld closedWorld) {
214 if (_membersNeededForReflection != null) return;
215 if (closedWorld.commonElements.mirrorsLibrary == null) {
216 _membersNeededForReflection = const ImmutableEmptySet<Element>();
217 return;
218 }
219 // Compute a mapping from class to the closures it contains, so we
220 // can include the correct ones when including the class.
221 Map<ClassElement, List<LocalFunctionElement>> closureMap =
222 new Map<ClassElement, List<LocalFunctionElement>>();
223 for (LocalFunctionElement closure
224 in compiler.resolutionWorldBuilder.allClosures) {
225 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure);
226 }
227 bool foundClosure = false;
228 Set<Element> reflectableMembers = new Set<Element>();
229 ResolutionEnqueuer resolution = compiler.enqueuer.resolution;
230 for (ClassElement cls
231 in resolution.worldBuilder.directlyInstantiatedClasses) {
232 // Do not process internal classes.
233 if (cls.library.isInternalLibrary || cls.isInjected) continue;
234 if (referencedFromMirrorSystem(cls)) {
235 Set<Name> memberNames = new Set<Name>();
236 // 1) the class (should be resolved)
237 assert(invariant(cls, cls.isResolved));
238 reflectableMembers.add(cls);
239 // 2) its constructors (if resolved)
240 cls.constructors.forEach((Element constructor) {
241 if (resolution.hasBeenProcessed(constructor)) {
242 reflectableMembers.add(constructor);
243 }
244 });
245 // 3) all members, including fields via getter/setters (if resolved)
246 cls.forEachClassMember((Member member) {
247 MemberElement element = member.element;
248 if (resolution.hasBeenProcessed(element)) {
249 memberNames.add(member.name);
250 reflectableMembers.add(element);
251 element.nestedClosures
252 .forEach((SynthesizedCallMethodElementX callFunction) {
253 reflectableMembers.add(callFunction);
254 reflectableMembers.add(callFunction.closureClass);
255 });
256 }
257 });
258 // 4) all overriding members of subclasses/subtypes (should be resolved)
259 if (closedWorld.hasAnyStrictSubtype(cls)) {
260 closedWorld.forEachStrictSubtypeOf(cls, (ClassElement subcls) {
261 subcls.forEachClassMember((Member member) {
262 if (memberNames.contains(member.name)) {
263 // TODO(20993): find out why this assertion fails.
264 // assert(invariant(member.element,
265 // resolution.hasBeenProcessed(member.element)));
266 if (resolution.hasBeenProcessed(member.element)) {
267 reflectableMembers.add(member.element);
268 }
269 }
270 });
271 });
272 }
273 // 5) all its closures
274 List<LocalFunctionElement> closures = closureMap[cls];
275 if (closures != null) {
276 reflectableMembers.addAll(closures);
277 foundClosure = true;
278 }
279 } else {
280 // check members themselves
281 cls.constructors.forEach((ConstructorElement element) {
282 if (!resolution.hasBeenProcessed(element)) return;
283 if (referencedFromMirrorSystem(element, false)) {
284 reflectableMembers.add(element);
285 }
286 });
287 cls.forEachClassMember((Member member) {
288 if (!resolution.hasBeenProcessed(member.element)) return;
289 if (referencedFromMirrorSystem(member.element, false)) {
290 reflectableMembers.add(member.element);
291 }
292 });
293 // Also add in closures. Those might be reflectable is their enclosing
294 // member is.
295 List<LocalFunctionElement> closures = closureMap[cls];
296 if (closures != null) {
297 for (LocalFunctionElement closure in closures) {
298 MemberElement member = closure.memberContext;
299 if (referencedFromMirrorSystem(member, false)) {
300 reflectableMembers.add(closure);
301 foundClosure = true;
302 }
303 }
304 }
305 }
306 }
307 // We also need top-level non-class elements like static functions and
308 // global fields. We use the resolution queue to decide which elements are
309 // part of the live world.
310 for (LibraryElement lib in compiler.libraryLoader.libraries) {
311 if (lib.isInternalLibrary) continue;
312 lib.forEachLocalMember((Element member) {
313 if (!(member.isClass || member.isTypedef) &&
314 resolution.hasBeenProcessed(member) &&
315 referencedFromMirrorSystem(member)) {
316 reflectableMembers.add(member);
317 }
318 });
319 }
320 // And closures inside top-level elements that do not have a surrounding
321 // class. These will be in the [:null:] bucket of the [closureMap].
322 if (closureMap.containsKey(null)) {
323 for (Element closure in closureMap[null]) {
324 if (referencedFromMirrorSystem(closure)) {
325 reflectableMembers.add(closure);
326 foundClosure = true;
327 }
328 }
329 }
330 // As we do not think about closures as classes, yet, we have to make sure
331 // their superclasses are available for reflection manually.
332 if (foundClosure) {
333 ClassElement cls = compiler.backend.helpers.closureClass;
334 reflectableMembers.add(cls);
335 }
336 Set<Element> closurizedMembers =
337 compiler.resolutionWorldBuilder.closurizedMembers;
338 if (closurizedMembers.any(reflectableMembers.contains)) {
339 ClassElement cls = compiler.backend.helpers.boundClosureClass;
340 reflectableMembers.add(cls);
341 }
342 // Add typedefs.
343 reflectableMembers
344 .addAll(closedWorld.allTypedefs.where(referencedFromMirrorSystem));
345 // Register all symbols of reflectable elements
346 for (Element element in reflectableMembers) {
347 symbolsUsed.add(element.name);
348 }
349 _membersNeededForReflection = reflectableMembers;
350 }
351
352 // TODO(20791): compute closure classes after resolution and move this code to
353 // [computeMembersNeededForReflection].
354 void maybeMarkClosureAsNeededForReflection(
355 ClosureClassElement globalizedElement,
356 FunctionElement callFunction,
357 FunctionElement function) {
358 if (!_membersNeededForReflection.contains(function)) return;
359 _membersNeededForReflection.add(callFunction);
360 _membersNeededForReflection.add(globalizedElement);
361 }
362
363 /// Called when [:const Symbol(name):] is seen.
364 void registerConstSymbol(String name) {
365 symbolsUsed.add(name);
366 if (name.endsWith('=')) {
367 symbolsUsed.add(name.substring(0, name.length - 1));
368 }
369 }
370 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/mirrors_analysis.dart ('k') | pkg/compiler/lib/src/js_backend/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698