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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 part of js_backend;
6
7 const VERBOSE_OPTIMIZER_HINTS = false;
8
9 class JavaScriptItemCompilationContext extends ItemCompilationContext {
10 final Set<HInstruction> boundsChecked = new Set<HInstruction>();
11 final Set<HInstruction> allocatedFixedLists = new Set<HInstruction>();
12 }
13
14 /*
15 * Invariants:
16 * canInline(function) implies canInline(function, insideLoop:true)
17 * !canInline(function, insideLoop: true) implies !canInline(function)
18 */
19 class FunctionInlineCache {
20 final Map<FunctionElement, bool> canBeInlined =
21 new Map<FunctionElement, bool>();
22
23 final Map<FunctionElement, bool> canBeInlinedInsideLoop =
24 new Map<FunctionElement, bool>();
25
26 // Returns [:true:]/[:false:] if we have a cached decision.
27 // Returns [:null:] otherwise.
28 bool canInline(FunctionElement element, {bool insideLoop}) {
29 return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element];
30 }
31
32 void markAsInlinable(FunctionElement element, {bool insideLoop}) {
33 if (insideLoop) {
34 canBeInlinedInsideLoop[element] = true;
35 } else {
36 // If we can inline a function outside a loop then we should do it inside
37 // a loop as well.
38 canBeInlined[element] = true;
39 canBeInlinedInsideLoop[element] = true;
40 }
41 }
42
43 void markAsNonInlinable(FunctionElement element, {bool insideLoop}) {
44 if (insideLoop == null || insideLoop) {
45 // If we can't inline a function inside a loop, then we should not inline
46 // it outside a loop either.
47 canBeInlined[element] = false;
48 canBeInlinedInsideLoop[element] = false;
49 } else {
50 canBeInlined[element] = false;
51 }
52 }
53 }
54
55 class JavaScriptBackend extends Backend {
56 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper');
57 static final Uri DART_INTERCEPTORS =
58 new Uri(scheme: 'dart', path: '_interceptors');
59 static final Uri DART_INTERNAL =
60 new Uri(scheme: 'dart', path: '_internal');
61 static final Uri DART_FOREIGN_HELPER =
62 new Uri(scheme: 'dart', path: '_foreign_helper');
63 static final Uri DART_JS_MIRRORS =
64 new Uri(scheme: 'dart', path: '_js_mirrors');
65 static final Uri DART_JS_NAMES =
66 new Uri(scheme: 'dart', path: '_js_names');
67 static final Uri DART_ISOLATE_HELPER =
68 new Uri(scheme: 'dart', path: '_isolate_helper');
69 static final Uri DART_HTML =
70 new Uri(scheme: 'dart', path: 'html');
71
72 static const String INVOKE_ON = '_getCachedInvocation';
73 static const String START_ROOT_ISOLATE = 'startRootIsolate';
74
75
76 /// The list of functions for classes in the [internalLibrary] that we want
77 /// to inline always. Any function in this list must be inlinable with
78 /// respect to the conditions used in [InlineWeeder.canInline], except for
79 /// size/complexity heuristics.
80 static const Map<String, List<String>> ALWAYS_INLINE =
81 const <String, List<String>> {
82 'IterableMixinWorkaround': const <String>['forEach'],
83 };
84
85 /// List of [FunctionElement]s that we want to inline always. This list is
86 /// filled when resolution is complete by looking up in [internalLibrary].
87 List<FunctionElement> functionsToAlwaysInline;
88
89 /// Reference to the internal library to lookup functions to always inline.
90 LibraryElement internalLibrary;
91
92
93 /// Set of classes that need to be considered for reflection although not
94 /// otherwise visible during resolution.
95 Iterable<ClassElement> get classesRequiredForReflection {
96 // TODO(herhut): Clean this up when classes needed for rti are tracked.
97 return [closureClass, jsIndexableClass];
98 }
99
100 SsaBuilderTask builder;
101 SsaOptimizerTask optimizer;
102 SsaCodeGeneratorTask generator;
103 CodeEmitterTask emitter;
104
105 /**
106 * The generated code as a js AST for compiled methods.
107 */
108 Map<Element, jsAst.Expression> get generatedCode {
109 return compiler.enqueuer.codegen.generatedCode;
110 }
111
112 FunctionInlineCache inlineCache = new FunctionInlineCache();
113
114 LibraryElement jsHelperLibrary;
115 LibraryElement interceptorsLibrary;
116 LibraryElement foreignLibrary;
117 LibraryElement isolateHelperLibrary;
118
119 ClassElement closureClass;
120 ClassElement boundClosureClass;
121 Element assertMethod;
122 Element invokeOnMethod;
123
124 ClassElement jsInterceptorClass;
125 ClassElement jsStringClass;
126 ClassElement jsArrayClass;
127 ClassElement jsNumberClass;
128 ClassElement jsIntClass;
129 ClassElement jsDoubleClass;
130 ClassElement jsNullClass;
131 ClassElement jsBoolClass;
132 ClassElement jsPlainJavaScriptObjectClass;
133 ClassElement jsUnknownJavaScriptObjectClass;
134
135 ClassElement jsIndexableClass;
136 ClassElement jsMutableIndexableClass;
137
138 ClassElement jsMutableArrayClass;
139 ClassElement jsFixedArrayClass;
140 ClassElement jsExtendableArrayClass;
141 ClassElement jsPositiveIntClass;
142 ClassElement jsUInt32Class;
143 ClassElement jsUInt31Class;
144
145 Element jsIndexableLength;
146 Element jsArrayTypedConstructor;
147 Element jsArrayRemoveLast;
148 Element jsArrayAdd;
149 Element jsStringSplit;
150 Element jsStringToString;
151 Element jsStringOperatorAdd;
152 Element objectEquals;
153
154 ClassElement typeLiteralClass;
155 ClassElement mapLiteralClass;
156 ClassElement constMapLiteralClass;
157 ClassElement typeVariableClass;
158 ConstructorElement mapLiteralConstructor;
159 ConstructorElement mapLiteralConstructorEmpty;
160
161 ClassElement noSideEffectsClass;
162 ClassElement noThrowsClass;
163 ClassElement noInlineClass;
164 ClassElement irRepresentationClass;
165
166 Element getInterceptorMethod;
167 Element interceptedNames;
168
169 ClassElement jsInvocationMirrorClass;
170
171 /// If [true], the compiler will emit code that writes the name of the current
172 /// method together with its class and library to the console the first time
173 /// the method is called.
174 static const bool TRACE_CALLS = false;
175 Element traceHelper;
176
177 /**
178 * This element is a top-level variable (in generated output) that the
179 * compiler initializes to a datastructure used to map from a Type to the
180 * interceptor. See declaration of `mapTypeToInterceptor` in
181 * `interceptors.dart`.
182 */
183 Element mapTypeToInterceptor;
184
185 TypeMask get stringType => compiler.typesTask.stringType;
186 TypeMask get doubleType => compiler.typesTask.doubleType;
187 TypeMask get intType => compiler.typesTask.intType;
188 TypeMask get uint32Type => compiler.typesTask.uint32Type;
189 TypeMask get uint31Type => compiler.typesTask.uint31Type;
190 TypeMask get positiveIntType => compiler.typesTask.positiveIntType;
191 TypeMask get numType => compiler.typesTask.numType;
192 TypeMask get boolType => compiler.typesTask.boolType;
193 TypeMask get dynamicType => compiler.typesTask.dynamicType;
194 TypeMask get nullType => compiler.typesTask.nullType;
195 TypeMask get emptyType => const TypeMask.nonNullEmpty();
196
197 TypeMask _indexablePrimitiveTypeCache;
198 TypeMask get indexablePrimitiveType {
199 if (_indexablePrimitiveTypeCache == null) {
200 _indexablePrimitiveTypeCache =
201 new TypeMask.nonNullSubtype(jsIndexableClass, compiler.world);
202 }
203 return _indexablePrimitiveTypeCache;
204 }
205
206 TypeMask _readableArrayTypeCache;
207 TypeMask get readableArrayType {
208 if (_readableArrayTypeCache == null) {
209 _readableArrayTypeCache = new TypeMask.nonNullSubclass(jsArrayClass,
210 compiler.world);
211 }
212 return _readableArrayTypeCache;
213 }
214
215 TypeMask _mutableArrayTypeCache;
216 TypeMask get mutableArrayType {
217 if (_mutableArrayTypeCache == null) {
218 _mutableArrayTypeCache = new TypeMask.nonNullSubclass(jsMutableArrayClass,
219 compiler.world);
220 }
221 return _mutableArrayTypeCache;
222 }
223
224 TypeMask _fixedArrayTypeCache;
225 TypeMask get fixedArrayType {
226 if (_fixedArrayTypeCache == null) {
227 _fixedArrayTypeCache = new TypeMask.nonNullExact(jsFixedArrayClass,
228 compiler.world);
229 }
230 return _fixedArrayTypeCache;
231 }
232
233 TypeMask _extendableArrayTypeCache;
234 TypeMask get extendableArrayType {
235 if (_extendableArrayTypeCache == null) {
236 _extendableArrayTypeCache =
237 new TypeMask.nonNullExact(jsExtendableArrayClass, compiler.world);
238 }
239 return _extendableArrayTypeCache;
240 }
241
242 TypeMask _nonNullTypeCache;
243 TypeMask get nonNullType {
244 if (_nonNullTypeCache == null) {
245 _nonNullTypeCache =
246 compiler.typesTask.dynamicType.nonNullable();
247 }
248 return _nonNullTypeCache;
249 }
250
251 /// Maps special classes to their implementation (JSXxx) class.
252 Map<ClassElement, ClassElement> implementationClasses;
253
254 Element getNativeInterceptorMethod;
255 bool needToInitializeIsolateAffinityTag = false;
256 bool needToInitializeDispatchProperty = false;
257
258 /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been
259 /// loaded.
260 FunctionElement getIsolateAffinityTagMarker;
261
262 final Namer namer;
263
264 /**
265 * Interface used to determine if an object has the JavaScript
266 * indexing behavior. The interface is only visible to specific
267 * libraries.
268 */
269 ClassElement jsIndexingBehaviorInterface;
270
271 /**
272 * A collection of selectors that must have a one shot interceptor
273 * generated.
274 */
275 final Map<String, Selector> oneShotInterceptors;
276
277 /**
278 * The members of instantiated interceptor classes: maps a member name to the
279 * list of members that have that name. This map is used by the codegen to
280 * know whether a send must be intercepted or not.
281 */
282 final Map<String, Set<Element>> interceptedElements;
283
284 /**
285 * The members of mixin classes that are mixed into an instantiated
286 * interceptor class. This is a cached subset of [interceptedElements].
287 *
288 * Mixin methods are not specialized for the class they are mixed into.
289 * Methods mixed into intercepted classes thus always make use of the explicit
290 * receiver argument, even when mixed into non-interceptor classes.
291 *
292 * These members must be invoked with a correct explicit receiver even when
293 * the receiver is not an intercepted class.
294 */
295 final Map<String, Set<Element>> interceptedMixinElements =
296 new Map<String, Set<Element>>();
297
298 /**
299 * A map of specialized versions of the [getInterceptorMethod].
300 * Since [getInterceptorMethod] is a hot method at runtime, we're
301 * always specializing it based on the incoming type. The keys in
302 * the map are the names of these specialized versions. Note that
303 * the generic version that contains all possible type checks is
304 * also stored in this map.
305 */
306 final Map<String, Set<ClassElement>> specializedGetInterceptors;
307
308 /**
309 * Set of classes whose methods are intercepted.
310 */
311 final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
312
313 /**
314 * Set of classes used as mixins on intercepted (native and primitive)
315 * classes. Methods on these classes might also be mixed in to regular Dart
316 * (unintercepted) classes.
317 */
318 final Set<ClassElement> classesMixedIntoInterceptedClasses =
319 new Set<ClassElement>();
320
321 /**
322 * Set of classes whose `operator ==` methods handle `null` themselves.
323 */
324 final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>();
325
326 List<CompilerTask> get tasks {
327 return <CompilerTask>[builder, optimizer, generator, emitter];
328 }
329
330 final RuntimeTypes rti;
331
332 /// Holds the method "disableTreeShaking" in js_mirrors when
333 /// dart:mirrors has been loaded.
334 FunctionElement disableTreeShakingMarker;
335
336 /// Holds the method "preserveNames" in js_mirrors when
337 /// dart:mirrors has been loaded.
338 FunctionElement preserveNamesMarker;
339
340 /// Holds the method "preserveMetadata" in js_mirrors when
341 /// dart:mirrors has been loaded.
342 FunctionElement preserveMetadataMarker;
343
344 /// Holds the method "preserveUris" in js_mirrors when
345 /// dart:mirrors has been loaded.
346 FunctionElement preserveUrisMarker;
347
348 /// Holds the method "preserveLibraryNames" in js_mirrors when
349 /// dart:mirrors has been loaded.
350 FunctionElement preserveLibraryNamesMarker;
351
352 /// Holds the method "requiresPreamble" in _js_helper.
353 FunctionElement requiresPreambleMarker;
354
355 /// True if a call to preserveMetadataMarker has been seen. This means that
356 /// metadata must be retained for dart:mirrors to work correctly.
357 bool mustRetainMetadata = false;
358
359 /// True if any metadata has been retained. This is slightly different from
360 /// [mustRetainMetadata] and tells us if any metadata was retained. For
361 /// example, if [mustRetainMetadata] is true but there is no metadata in the
362 /// program, this variable will stil be false.
363 bool hasRetainedMetadata = false;
364
365 /// True if a call to preserveUris has been seen and the preserve-uris flag
366 /// is set.
367 bool mustPreserveUris = false;
368
369 /// True if a call to preserveLibraryNames has been seen.
370 bool mustRetainLibraryNames = false;
371
372 /// True if a call to preserveNames has been seen.
373 bool mustPreserveNames = false;
374
375 /// True if a call to disableTreeShaking has been seen.
376 bool isTreeShakingDisabled = false;
377
378 /// True if there isn't sufficient @MirrorsUsed data.
379 bool hasInsufficientMirrorsUsed = false;
380
381 /// True if a core-library function requires the preamble file to function.
382 bool requiresPreamble = false;
383
384 /// True if the html library has been loaded.
385 bool htmlLibraryIsLoaded = false;
386
387 /// List of constants from metadata. If metadata must be preserved,
388 /// these constants must be registered.
389 final List<Dependency> metadataConstants = <Dependency>[];
390
391 /// List of elements that the user has requested for reflection.
392 final Set<Element> targetsUsed = new Set<Element>();
393
394 /// List of annotations provided by user that indicate that the annotated
395 /// element must be retained.
396 final Set<Element> metaTargetsUsed = new Set<Element>();
397
398 /// Set of methods that are needed by reflection. Computed using
399 /// [computeMembersNeededForReflection] on first use.
400 Set<Element> _membersNeededForReflection = null;
401 Iterable<Element> get membersNeededForReflection {
402 assert(_membersNeededForReflection != null);
403 return _membersNeededForReflection;
404 }
405
406 /// List of symbols that the user has requested for reflection.
407 final Set<String> symbolsUsed = new Set<String>();
408
409 /// List of elements that the backend may use.
410 final Set<Element> helpersUsed = new Set<Element>();
411
412 /// All the checked mode helpers.
413 static const checkedModeHelpers = CheckedModeHelper.helpers;
414
415 // Checked mode helpers indexed by name.
416 Map<String, CheckedModeHelper> checkedModeHelperByName =
417 new Map<String, CheckedModeHelper>.fromIterable(
418 checkedModeHelpers,
419 key: (helper) => helper.name);
420
421 TypeVariableHandler typeVariableHandler;
422
423 /// Number of methods compiled before considering reflection.
424 int preMirrorsMethodCount = 0;
425
426 /// Resolution and codegen support for generating table of interceptors and
427 /// constructors for custom elements.
428 CustomElementsAnalysis customElementsAnalysis;
429
430 JavaScriptConstantTask constantCompilerTask;
431
432 JavaScriptResolutionCallbacks resolutionCallbacks;
433
434 JavaScriptBackend(Compiler compiler, bool generateSourceMap)
435 : namer = determineNamer(compiler),
436 oneShotInterceptors = new Map<String, Selector>(),
437 interceptedElements = new Map<String, Set<Element>>(),
438 rti = new RuntimeTypes(compiler),
439 specializedGetInterceptors = new Map<String, Set<ClassElement>>(),
440 super(compiler) {
441 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap);
442 builder = new SsaBuilderTask(this);
443 optimizer = new SsaOptimizerTask(this);
444 generator = new SsaCodeGeneratorTask(this);
445 typeVariableHandler = new TypeVariableHandler(this);
446 customElementsAnalysis = new CustomElementsAnalysis(this);
447 constantCompilerTask = new JavaScriptConstantTask(compiler);
448 resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
449 }
450
451 ConstantSystem get constantSystem => constants.constantSystem;
452
453 /// Returns constant environment for the JavaScript interpretation of the
454 /// constants.
455 JavaScriptConstantCompiler get constants {
456 return constantCompilerTask.jsConstantCompiler;
457 }
458
459 // TODO(karlklose): Split into findHelperFunction and findHelperClass and
460 // add a check that the element has the expected kind.
461 Element findHelper(String name) => find(jsHelperLibrary, name);
462 Element findInterceptor(String name) => find(interceptorsLibrary, name);
463
464 Element find(LibraryElement library, String name) {
465 Element element = library.findLocal(name);
466 assert(invariant(library, element != null,
467 message: "Element '$name' not found in '${library.canonicalUri}'."));
468 return element;
469 }
470
471 bool isForeign(Element element) => element.library == foreignLibrary;
472
473 bool isBackendLibrary(LibraryElement library) {
474 return library == interceptorsLibrary ||
475 library == jsHelperLibrary;
476 }
477
478 static Namer determineNamer(Compiler compiler) {
479 return compiler.enableMinification ?
480 new MinifyNamer(compiler) :
481 new Namer(compiler);
482 }
483
484 bool usedByBackend(Element element) {
485 if (element.isParameter
486 || element.isInitializingFormal
487 || element.isField) {
488 if (usedByBackend(element.enclosingElement)) return true;
489 }
490 return helpersUsed.contains(element.declaration);
491 }
492
493 bool invokedReflectively(Element element) {
494 if (element.isParameter || element.isInitializingFormal) {
495 ParameterElement parameter = element;
496 if (invokedReflectively(parameter.functionDeclaration)) return true;
497 }
498
499 if (element.isField) {
500 if (Elements.isStaticOrTopLevel(element)
501 && (element.isFinal || element.isConst)) {
502 return false;
503 }
504 }
505
506 return isAccessibleByReflection(element.declaration);
507 }
508
509 bool canBeUsedForGlobalOptimizations(Element element) {
510 return !usedByBackend(element) && !invokedReflectively(element);
511 }
512
513 bool isInterceptorClass(ClassElement element) {
514 if (element == null) return false;
515 if (Elements.isNativeOrExtendsNative(element)) return true;
516 if (interceptedClasses.contains(element)) return true;
517 if (classesMixedIntoInterceptedClasses.contains(element)) return true;
518 return false;
519 }
520
521 String registerOneShotInterceptor(Selector selector) {
522 Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
523 String name = namer.getOneShotInterceptorName(selector, classes);
524 if (!oneShotInterceptors.containsKey(name)) {
525 registerSpecializedGetInterceptor(classes);
526 oneShotInterceptors[name] = selector;
527 }
528 return name;
529 }
530
531 bool isInterceptedMethod(Element element) {
532 if (!element.isInstanceMember) return false;
533 if (element.isGenerativeConstructorBody) {
534 return Elements.isNativeOrExtendsNative(element.enclosingClass);
535 }
536 return interceptedElements[element.name] != null;
537 }
538
539 bool fieldHasInterceptedGetter(Element element) {
540 assert(element.isField);
541 return interceptedElements[element.name] != null;
542 }
543
544 bool fieldHasInterceptedSetter(Element element) {
545 assert(element.isField);
546 return interceptedElements[element.name] != null;
547 }
548
549 bool isInterceptedName(String name) {
550 return interceptedElements[name] != null;
551 }
552
553 bool isInterceptedSelector(Selector selector) {
554 return interceptedElements[selector.name] != null;
555 }
556
557 /**
558 * Returns `true` iff [selector] matches an element defined in a class mixed
559 * into an intercepted class. These selectors are not eligible for the 'dummy
560 * explicit receiver' optimization.
561 */
562 bool isInterceptedMixinSelector(Selector selector) {
563 Set<Element> elements = interceptedMixinElements.putIfAbsent(
564 selector.name,
565 () {
566 Set<Element> elements = interceptedElements[selector.name];
567 if (elements == null) return null;
568 return elements
569 .where((element) =>
570 classesMixedIntoInterceptedClasses.contains(
571 element.enclosingClass))
572 .toSet();
573 });
574
575 if (elements == null) return false;
576 if (elements.isEmpty) return false;
577 return elements.any((element) => selector.applies(element, compiler.world));
578 }
579
580 final Map<String, Set<ClassElement>> interceptedClassesCache =
581 new Map<String, Set<ClassElement>>();
582
583 /**
584 * Returns a set of interceptor classes that contain a member named
585 * [name]. Returns [:null:] if there is no class.
586 */
587 Set<ClassElement> getInterceptedClassesOn(String name) {
588 Set<Element> intercepted = interceptedElements[name];
589 if (intercepted == null) return null;
590 return interceptedClassesCache.putIfAbsent(name, () {
591 // Populate the cache by running through all the elements and
592 // determine if the given selector applies to them.
593 Set<ClassElement> result = new Set<ClassElement>();
594 for (Element element in intercepted) {
595 ClassElement classElement = element.enclosingClass;
596 if (Elements.isNativeOrExtendsNative(classElement)
597 || interceptedClasses.contains(classElement)) {
598 result.add(classElement);
599 }
600 if (classesMixedIntoInterceptedClasses.contains(classElement)) {
601 Set<ClassElement> nativeSubclasses =
602 nativeSubclassesOfMixin(classElement);
603 if (nativeSubclasses != null) result.addAll(nativeSubclasses);
604 }
605 }
606 return result;
607 });
608 }
609
610 Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
611 ClassWorld classWorld = compiler.world;
612 Iterable<MixinApplicationElement> uses = classWorld.mixinUsesOf(mixin);
613 Set<ClassElement> result = null;
614 for (MixinApplicationElement use in uses) {
615 Iterable<ClassElement> subclasses = classWorld.subclassesOf(use);
616 for (ClassElement subclass in subclasses) {
617 if (Elements.isNativeOrExtendsNative(subclass)) {
618 if (result == null) result = new Set<ClassElement>();
619 result.add(subclass);
620 }
621 }
622 }
623 return result;
624 }
625
626 bool operatorEqHandlesNullArgument(FunctionElement operatorEqfunction) {
627 return specialOperatorEqClasses.contains(
628 operatorEqfunction.enclosingClass);
629 }
630
631 void validateInterceptorImplementsAllObjectMethods(
632 ClassElement interceptorClass) {
633 if (interceptorClass == null) return;
634 interceptorClass.ensureResolved(compiler);
635 compiler.objectClass.forEachMember((_, Element member) {
636 if (member.isGenerativeConstructor) return;
637 Element interceptorMember = interceptorClass.lookupMember(member.name);
638 // Interceptors must override all Object methods due to calling convention
639 // differences.
640 assert(interceptorMember.enclosingClass == interceptorClass);
641 });
642 }
643
644 void addInterceptorsForNativeClassMembers(
645 ClassElement cls, Enqueuer enqueuer) {
646 if (enqueuer.isResolutionQueue) {
647 cls.ensureResolved(compiler);
648 cls.forEachMember((ClassElement classElement, Element member) {
649 if (member.name == Compiler.CALL_OPERATOR_NAME) {
650 compiler.reportError(
651 member,
652 MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS);
653 return;
654 }
655 if (member.isSynthesized) return;
656 // All methods on [Object] are shadowed by [Interceptor].
657 if (classElement == compiler.objectClass) return;
658 Set<Element> set = interceptedElements.putIfAbsent(
659 member.name, () => new Set<Element>());
660 set.add(member);
661 },
662 includeSuperAndInjectedMembers: true);
663
664 // Walk superclass chain to find mixins.
665 for (; cls != null; cls = cls.superclass) {
666 if (cls.isMixinApplication) {
667 MixinApplicationElement mixinApplication = cls;
668 classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
669 }
670 }
671 }
672 }
673
674 void addInterceptors(ClassElement cls,
675 Enqueuer enqueuer,
676 Registry registry) {
677 if (enqueuer.isResolutionQueue) {
678 _interceptedClasses.add(jsInterceptorClass);
679 _interceptedClasses.add(cls);
680 cls.ensureResolved(compiler);
681 cls.forEachMember((ClassElement classElement, Element member) {
682 // All methods on [Object] are shadowed by [Interceptor].
683 if (classElement == compiler.objectClass) return;
684 Set<Element> set = interceptedElements.putIfAbsent(
685 member.name, () => new Set<Element>());
686 set.add(member);
687 },
688 includeSuperAndInjectedMembers: true);
689 }
690 enqueueClass(enqueuer, cls, registry);
691 }
692
693 Set<ClassElement> get interceptedClasses {
694 assert(compiler.enqueuer.resolution.queueIsClosed);
695 return _interceptedClasses;
696 }
697
698 void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
699 String name = namer.getInterceptorName(getInterceptorMethod, classes);
700 if (classes.contains(jsInterceptorClass)) {
701 // We can't use a specialized [getInterceptorMethod], so we make
702 // sure we emit the one with all checks.
703 specializedGetInterceptors[name] = interceptedClasses;
704 } else {
705 specializedGetInterceptors[name] = classes;
706 }
707 }
708
709 void registerCompileTimeConstant(ConstantValue constant, Registry registry) {
710 registerCompileTimeConstantInternal(constant, registry);
711 for (ConstantValue dependency in constant.getDependencies()) {
712 registerCompileTimeConstant(dependency, registry);
713 }
714 }
715
716 void registerCompileTimeConstantInternal(ConstantValue constant,
717 Registry registry) {
718 DartType type = constant.computeType(compiler);
719 registerInstantiatedConstantType(type, registry);
720
721 if (constant.isFunction) {
722 FunctionConstantValue function = constant;
723 registry.registerGetOfStaticFunction(function.element);
724 } else if (constant.isInterceptor) {
725 // An interceptor constant references the class's prototype chain.
726 InterceptorConstantValue interceptor = constant;
727 registerInstantiatedConstantType(interceptor.dispatchedType, registry);
728 } else if (constant.isType) {
729 enqueueInResolution(getCreateRuntimeType(), registry);
730 registry.registerInstantiation(typeImplementation.rawType);
731 }
732 }
733
734 void registerInstantiatedConstantType(DartType type, Registry registry) {
735 DartType instantiatedType =
736 type.isFunctionType ? compiler.functionClass.rawType : type;
737 if (type is InterfaceType) {
738 registry.registerInstantiation(instantiatedType);
739 if (!type.treatAsRaw && classNeedsRti(type.element)) {
740 registry.registerStaticInvocation(getSetRuntimeTypeInfo());
741 }
742 if (type.element == typeImplementation) {
743 // If we use a type literal in a constant, the compile time
744 // constant emitter will generate a call to the createRuntimeType
745 // helper so we register a use of that.
746 registry.registerStaticInvocation(getCreateRuntimeType());
747 }
748 }
749 }
750
751 void registerMetadataConstant(MetadataAnnotation metadata,
752 Element annotatedElement,
753 Registry registry) {
754 assert(registry.isForResolution);
755 ConstantValue constant = constants.getConstantForMetadata(metadata).value;
756 registerCompileTimeConstant(constant, registry);
757 metadataConstants.add(new Dependency(constant, annotatedElement));
758 }
759
760 void registerInstantiatedClass(ClassElement cls,
761 Enqueuer enqueuer,
762 Registry registry) {
763 if (!cls.typeVariables.isEmpty) {
764 typeVariableHandler.registerClassWithTypeVariables(cls);
765 }
766
767 // Register any helper that will be needed by the backend.
768 if (enqueuer.isResolutionQueue) {
769 if (cls == compiler.intClass
770 || cls == compiler.doubleClass
771 || cls == compiler.numClass) {
772 // The backend will try to optimize number operations and use the
773 // `iae` helper directly.
774 enqueue(enqueuer, findHelper('iae'), registry);
775 } else if (cls == compiler.listClass
776 || cls == compiler.stringClass) {
777 // The backend will try to optimize array and string access and use the
778 // `ioore` and `iae` helpers directly.
779 enqueue(enqueuer, findHelper('ioore'), registry);
780 enqueue(enqueuer, findHelper('iae'), registry);
781 } else if (cls == compiler.functionClass) {
782 enqueueClass(enqueuer, closureClass, registry);
783 } else if (cls == compiler.mapClass) {
784 // The backend will use a literal list to initialize the entries
785 // of the map.
786 enqueueClass(enqueuer, compiler.listClass, registry);
787 enqueueClass(enqueuer, mapLiteralClass, registry);
788 // For map literals, the dependency between the implementation class
789 // and [Map] is not visible, so we have to add it manually.
790 rti.registerRtiDependency(mapLiteralClass, cls);
791 } else if (cls == boundClosureClass) {
792 // TODO(johnniwinther): Is this a noop?
793 enqueueClass(enqueuer, boundClosureClass, registry);
794 } else if (Elements.isNativeOrExtendsNative(cls)) {
795 enqueue(enqueuer, getNativeInterceptorMethod, registry);
796 enqueueClass(enqueuer, jsInterceptorClass, compiler.globalDependencies);
797 enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry);
798 } else if (cls == mapLiteralClass) {
799 // For map literals, the dependency between the implementation class
800 // and [Map] is not visible, so we have to add it manually.
801 Element getFactory(String name, int arity) {
802 // The constructor is on the patch class, but dart2js unit tests don't
803 // have a patch class.
804 ClassElement implementation = cls.patch != null ? cls.patch : cls;
805 return implementation.lookupConstructor(
806 new Selector.callConstructor(
807 name, mapLiteralClass.library, arity),
808 (element) {
809 compiler.internalError(mapLiteralClass,
810 "Map literal class $mapLiteralClass missing "
811 "'$name' constructor"
812 " ${mapLiteralClass.constructors}");
813 });
814 }
815 mapLiteralConstructor = getFactory('_literal', 1);
816 mapLiteralConstructorEmpty = getFactory('_empty', 0);
817 enqueueInResolution(mapLiteralConstructor, registry);
818 enqueueInResolution(mapLiteralConstructorEmpty, registry);
819 }
820 }
821 if (cls == closureClass) {
822 enqueue(enqueuer, findHelper('closureFromTearOff'), registry);
823 }
824 ClassElement result = null;
825 if (cls == compiler.stringClass || cls == jsStringClass) {
826 addInterceptors(jsStringClass, enqueuer, registry);
827 } else if (cls == compiler.listClass ||
828 cls == jsArrayClass ||
829 cls == jsFixedArrayClass ||
830 cls == jsExtendableArrayClass) {
831 addInterceptors(jsArrayClass, enqueuer, registry);
832 addInterceptors(jsMutableArrayClass, enqueuer, registry);
833 addInterceptors(jsFixedArrayClass, enqueuer, registry);
834 addInterceptors(jsExtendableArrayClass, enqueuer, registry);
835 } else if (cls == compiler.intClass || cls == jsIntClass) {
836 addInterceptors(jsIntClass, enqueuer, registry);
837 addInterceptors(jsPositiveIntClass, enqueuer, registry);
838 addInterceptors(jsUInt32Class, enqueuer, registry);
839 addInterceptors(jsUInt31Class, enqueuer, registry);
840 addInterceptors(jsNumberClass, enqueuer, registry);
841 } else if (cls == compiler.doubleClass || cls == jsDoubleClass) {
842 addInterceptors(jsDoubleClass, enqueuer, registry);
843 addInterceptors(jsNumberClass, enqueuer, registry);
844 } else if (cls == compiler.boolClass || cls == jsBoolClass) {
845 addInterceptors(jsBoolClass, enqueuer, registry);
846 } else if (cls == compiler.nullClass || cls == jsNullClass) {
847 addInterceptors(jsNullClass, enqueuer, registry);
848 } else if (cls == compiler.numClass || cls == jsNumberClass) {
849 addInterceptors(jsIntClass, enqueuer, registry);
850 addInterceptors(jsPositiveIntClass, enqueuer, registry);
851 addInterceptors(jsUInt32Class, enqueuer, registry);
852 addInterceptors(jsUInt31Class, enqueuer, registry);
853 addInterceptors(jsDoubleClass, enqueuer, registry);
854 addInterceptors(jsNumberClass, enqueuer, registry);
855 } else if (cls == jsPlainJavaScriptObjectClass) {
856 addInterceptors(jsPlainJavaScriptObjectClass, enqueuer, registry);
857 } else if (cls == jsUnknownJavaScriptObjectClass) {
858 addInterceptors(jsUnknownJavaScriptObjectClass, enqueuer, registry);
859 } else if (Elements.isNativeOrExtendsNative(cls)) {
860 addInterceptorsForNativeClassMembers(cls, enqueuer);
861 } else if (cls == jsIndexingBehaviorInterface) {
862 // These two helpers are used by the emitter and the codegen.
863 // Because we cannot enqueue elements at the time of emission,
864 // we make sure they are always generated.
865 enqueue(enqueuer, findHelper('isJsIndexable'), registry);
866 }
867
868 customElementsAnalysis.registerInstantiatedClass(cls, enqueuer);
869 }
870
871 void registerUseInterceptor(Enqueuer enqueuer) {
872 assert(!enqueuer.isResolutionQueue);
873 if (!enqueuer.nativeEnqueuer.hasInstantiatedNativeClasses()) return;
874 Registry registry = compiler.globalDependencies;
875 enqueue(enqueuer, getNativeInterceptorMethod, registry);
876 enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry);
877 needToInitializeIsolateAffinityTag = true;
878 needToInitializeDispatchProperty = true;
879 }
880
881 JavaScriptItemCompilationContext createItemCompilationContext() {
882 return new JavaScriptItemCompilationContext();
883 }
884
885 void enqueueHelpers(ResolutionEnqueuer world, Registry registry) {
886 assert(interceptorsLibrary != null);
887 // TODO(ngeoffray): Not enqueuing those two classes currently make
888 // the compiler potentially crash. However, any reasonable program
889 // will instantiate those two classes.
890 addInterceptors(jsBoolClass, world, registry);
891 addInterceptors(jsNullClass, world, registry);
892 if (compiler.enableTypeAssertions) {
893 // Unconditionally register the helper that checks if the
894 // expression in an if/while/for is a boolean.
895 // TODO(ngeoffray): Should we have the resolver register those instead?
896 Element e = findHelper('boolConversionCheck');
897 if (e != null) enqueue(world, e, registry);
898 }
899 if (TRACE_CALLS) {
900 traceHelper = findHelper('traceHelper');
901 assert(traceHelper != null);
902 enqueueInResolution(traceHelper, registry);
903 }
904 registerCheckedModeHelpers(registry);
905 }
906
907 onResolutionComplete() {
908 super.onResolutionComplete();
909 computeMembersNeededForReflection();
910 rti.computeClassesNeedingRti();
911 computeFunctionsToAlwaysInline();
912 }
913
914 void computeFunctionsToAlwaysInline() {
915 functionsToAlwaysInline = <FunctionElement>[];
916 if (internalLibrary == null) return;
917
918 // Try to find all functions intended to always inline. If their enclosing
919 // class is not resolved we skip the methods, but it is an error to mention
920 // a function or class that cannot be found.
921 for (String className in ALWAYS_INLINE.keys) {
922 ClassElement cls = find(internalLibrary, className);
923 if (cls.resolutionState != STATE_DONE) continue;
924 for (String functionName in ALWAYS_INLINE[className]) {
925 Element function = cls.lookupMember(functionName);
926 assert(invariant(cls, function is FunctionElement,
927 message: 'unable to find function $functionName in $className'));
928 functionsToAlwaysInline.add(function);
929 }
930 }
931 }
932
933 void registerGetRuntimeTypeArgument(Registry registry) {
934 enqueueInResolution(getGetRuntimeTypeArgument(), registry);
935 enqueueInResolution(getGetTypeArgumentByIndex(), registry);
936 enqueueInResolution(getCopyTypeArguments(), registry);
937 }
938
939 void registerCallMethodWithFreeTypeVariables(
940 Element callMethod,
941 Enqueuer enqueuer,
942 Registry registry) {
943 if (enqueuer.isResolutionQueue || methodNeedsRti(callMethod)) {
944 registerComputeSignature(enqueuer, registry);
945 }
946 }
947
948 void registerClosureWithFreeTypeVariables(
949 Element closure,
950 Enqueuer enqueuer,
951 Registry registry) {
952 if (enqueuer.isResolutionQueue || methodNeedsRti(closure)) {
953 registerComputeSignature(enqueuer, registry);
954 }
955 }
956
957 void registerBoundClosure(Enqueuer enqueuer) {
958 enqueuer.registerInstantiatedClass(
959 boundClosureClass,
960 // Precise dependency is not important here.
961 compiler.globalDependencies);
962 }
963
964 void registerGetOfStaticFunction(Enqueuer enqueuer) {
965 enqueuer.registerInstantiatedClass(closureClass,
966 compiler.globalDependencies);
967 }
968
969 void registerComputeSignature(Enqueuer enqueuer, Registry registry) {
970 // Calls to [:computeSignature:] are generated by the emitter and we
971 // therefore need to enqueue the used elements in the codegen enqueuer as
972 // well as in the resolution enqueuer.
973 enqueue(enqueuer, getSetRuntimeTypeInfo(), registry);
974 enqueue(enqueuer, getGetRuntimeTypeInfo(), registry);
975 enqueue(enqueuer, getComputeSignature(), registry);
976 enqueue(enqueuer, getGetRuntimeTypeArguments(), registry);
977 enqueueClass(enqueuer, compiler.listClass, registry);
978 }
979
980 void registerRuntimeType(Enqueuer enqueuer, Registry registry) {
981 registerComputeSignature(enqueuer, registry);
982 enqueueInResolution(getSetRuntimeTypeInfo(), registry);
983 enqueueInResolution(getGetRuntimeTypeInfo(), registry);
984 registerGetRuntimeTypeArgument(registry);
985 enqueueClass(enqueuer, compiler.listClass, registry);
986 }
987
988 void registerIsCheckForCodegen(DartType type,
989 Enqueuer world,
990 Registry registry) {
991 assert(!registry.isForResolution);
992 type = type.unalias(compiler);
993 enqueueClass(world, compiler.boolClass, registry);
994 bool inCheckedMode = compiler.enableTypeAssertions;
995 // [registerIsCheck] is also called for checked mode checks, so we
996 // need to register checked mode helpers.
997 if (inCheckedMode) {
998 // All helpers are added to resolution queue in enqueueHelpers. These
999 // calls to enqueueInResolution serve as assertions that the helper was
1000 // in fact added.
1001 // TODO(13155): Find a way to enqueue helpers lazily.
1002 CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: false);
1003 if (helper != null) {
1004 enqueue(world, helper.getElement(compiler), registry);
1005 }
1006 // We also need the native variant of the check (for DOM types).
1007 helper = getNativeCheckedModeHelper(type, typeCast: false);
1008 if (helper != null) {
1009 enqueue(world, helper.getElement(compiler), registry);
1010 }
1011 }
1012 if (!type.treatAsRaw || type.containsTypeVariables) {
1013 enqueueClass(world, compiler.listClass, registry);
1014 }
1015 if (type.element != null && type.element.isNative) {
1016 // We will neeed to add the "$is" and "$as" properties on the
1017 // JavaScript object prototype, so we make sure
1018 // [:defineProperty:] is compiled.
1019 enqueue(world, findHelper('defineProperty'), registry);
1020 }
1021 }
1022
1023 void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
1024 DartType bound) {
1025 rti.registerTypeVariableBoundsSubtypeCheck(typeArgument, bound);
1026 }
1027
1028 void registerCheckDeferredIsLoaded(Registry registry) {
1029 enqueueInResolution(getCheckDeferredIsLoaded(), registry);
1030 // Also register the types of the arguments passed to this method.
1031 enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, registry);
1032 }
1033
1034 void enableNoSuchMethod(Element context, Enqueuer world) {
1035 enqueue(world, getCreateInvocationMirror(), compiler.globalDependencies);
1036 world.registerInvocation(compiler.noSuchMethodSelector);
1037 // TODO(tyoverby): Send the context element to DumpInfoTask to be
1038 // blamed.
1039 }
1040
1041 void enableIsolateSupport(Enqueuer enqueuer) {
1042 // TODO(floitsch): We should also ensure that the class IsolateMessage is
1043 // instantiated. Currently, just enabling isolate support works.
1044 if (compiler.mainFunction != null) {
1045 // The JavaScript backend implements [Isolate.spawn] by looking up
1046 // top-level functions by name. So all top-level function tear-off
1047 // closures have a private name field.
1048 //
1049 // The JavaScript backend of [Isolate.spawnUri] uses the same internal
1050 // implementation as [Isolate.spawn], and fails if it cannot look main up
1051 // by name.
1052 enqueuer.registerGetOfStaticFunction(compiler.mainFunction);
1053 }
1054 if (enqueuer.isResolutionQueue) {
1055 for (String name in const [START_ROOT_ISOLATE,
1056 '_currentIsolate',
1057 '_callInIsolate']) {
1058 Element element = find(isolateHelperLibrary, name);
1059 enqueuer.addToWorkList(element);
1060 compiler.globalDependencies.registerDependency(element);
1061 }
1062 } else {
1063 enqueuer.addToWorkList(find(isolateHelperLibrary, START_ROOT_ISOLATE));
1064 }
1065 }
1066
1067 bool isAssertMethod(Element element) => element == assertMethod;
1068
1069 void registerRequiredType(DartType type, Element enclosingElement) {
1070 // If [argument] has type variables or is a type variable, this method
1071 // registers a RTI dependency between the class where the type variable is
1072 // defined (that is the enclosing class of the current element being
1073 // resolved) and the class of [type]. If the class of [type] requires RTI,
1074 // then the class of the type variable does too.
1075 ClassElement contextClass = Types.getClassContext(type);
1076 if (contextClass != null) {
1077 assert(contextClass == enclosingElement.enclosingClass.declaration);
1078 rti.registerRtiDependency(type.element, contextClass);
1079 }
1080 }
1081
1082 void registerClassUsingVariableExpression(ClassElement cls) {
1083 rti.classesUsingTypeVariableExpression.add(cls);
1084 }
1085
1086 bool classNeedsRti(ClassElement cls) {
1087 return rti.classesNeedingRti.contains(cls.declaration) ||
1088 compiler.enabledRuntimeType;
1089 }
1090
1091 bool isDefaultNoSuchMethodImplementation(Element element) {
1092 assert(element.name == Compiler.NO_SUCH_METHOD);
1093 ClassElement classElement = element.enclosingClass;
1094 return classElement == compiler.objectClass
1095 || classElement == jsInterceptorClass
1096 || classElement == jsNullClass;
1097 }
1098
1099 bool isDefaultEqualityImplementation(Element element) {
1100 assert(element.name == '==');
1101 ClassElement classElement = element.enclosingClass;
1102 return classElement == compiler.objectClass
1103 || classElement == jsInterceptorClass
1104 || classElement == jsNullClass;
1105 }
1106
1107 bool methodNeedsRti(FunctionElement function) {
1108 return rti.methodsNeedingRti.contains(function) ||
1109 compiler.enabledRuntimeType;
1110 }
1111
1112 /// The backend must *always* call this method when enqueuing an
1113 /// element. Calls done by the backend are not seen by global
1114 /// optimizations, so they would make these optimizations unsound.
1115 /// Therefore we need to collect the list of helpers the backend may
1116 /// use.
1117 Element registerBackendUse(Element element) {
1118 if (element != null) {
1119 helpersUsed.add(element.declaration);
1120 if (element.isClass && element.isPatched) {
1121 // Both declaration and implementation may declare fields, so we
1122 // add both to the list of helpers.
1123 helpersUsed.add(element.implementation);
1124 }
1125 }
1126 return element;
1127 }
1128
1129 /// Enqueue [e] in [enqueuer].
1130 ///
1131 /// This method calls [registerBackendUse].
1132 void enqueue(Enqueuer enqueuer, Element e, Registry registry) {
1133 if (e == null) return;
1134 registerBackendUse(e);
1135 enqueuer.addToWorkList(e);
1136 registry.registerDependency(e);
1137 }
1138
1139 /// Enqueue [e] in the resolution enqueuer.
1140 ///
1141 /// This method calls [registerBackendUse].
1142 void enqueueInResolution(Element e, Registry registry) {
1143 if (e == null) return;
1144 ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
1145 enqueue(enqueuer, e, registry);
1146 }
1147
1148 /// Register instantiation of [cls] in [enqueuer].
1149 ///
1150 /// This method calls [registerBackendUse].
1151 void enqueueClass(Enqueuer enqueuer, Element cls, Registry registry) {
1152 if (cls == null) return;
1153 registerBackendUse(cls);
1154 helpersUsed.add(cls.declaration);
1155 if (cls.declaration != cls.implementation) {
1156 helpersUsed.add(cls.implementation);
1157 }
1158 enqueuer.registerInstantiatedClass(cls, registry);
1159 }
1160
1161 void codegen(CodegenWorkItem work) {
1162 Element element = work.element;
1163 var kind = element.kind;
1164 if (kind == ElementKind.TYPEDEF) return;
1165 if (element.isConstructor && element.enclosingClass == jsNullClass) {
1166 // Work around a problem compiling JSNull's constructor.
1167 return;
1168 }
1169 if (kind.category == ElementCategory.VARIABLE) {
1170 ConstantExpression initialValue = constants.getConstantForVariable(element );
1171 if (initialValue != null) {
1172 registerCompileTimeConstant(initialValue.value, work.registry);
1173 constants.addCompileTimeConstantForEmission(initialValue.value);
1174 // We don't need to generate code for static or top-level
1175 // variables. For instance variables, we may need to generate
1176 // the checked setter.
1177 if (Elements.isStaticOrTopLevel(element)) return;
1178 } else {
1179 // If the constant-handler was not able to produce a result we have to
1180 // go through the builder (below) to generate the lazy initializer for
1181 // the static variable.
1182 // We also need to register the use of the cyclic-error helper.
1183 compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper());
1184 }
1185 }
1186 HGraph graph = builder.build(work);
1187 optimizer.optimize(work, graph);
1188 jsAst.Expression code = generator.generateCode(work, graph);
1189 generatedCode[element] = code;
1190 }
1191
1192 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
1193 return new native.NativeResolutionEnqueuer(world, compiler);
1194 }
1195
1196 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) {
1197 return new native.NativeCodegenEnqueuer(world, compiler, emitter);
1198 }
1199
1200 ClassElement defaultSuperclass(ClassElement element) {
1201 // Native classes inherit from Interceptor.
1202 return element.isNative ? jsInterceptorClass : compiler.objectClass;
1203 }
1204
1205 /**
1206 * Unit test hook that returns code of an element as a String.
1207 *
1208 * Invariant: [element] must be a declaration element.
1209 */
1210 String assembleCode(Element element) {
1211 assert(invariant(element, element.isDeclaration));
1212 return jsAst.prettyPrint(generatedCode[element], compiler).getText();
1213 }
1214
1215 void assembleProgram() {
1216 emitter.assembleProgram();
1217 int totalMethodCount = generatedCode.length;
1218 if (totalMethodCount != preMirrorsMethodCount) {
1219 int mirrorCount = totalMethodCount - preMirrorsMethodCount;
1220 double percentage = (mirrorCount / totalMethodCount) * 100;
1221 compiler.reportHint(
1222 compiler.mainApp, MessageKind.MIRROR_BLOAT,
1223 {'count': mirrorCount,
1224 'total': totalMethodCount,
1225 'percentage': percentage.round()});
1226 for (LibraryElement library in compiler.libraryLoader.libraries) {
1227 if (library.isInternalLibrary) continue;
1228 for (LibraryTag tag in library.tags) {
1229 Import importTag = tag.asImport();
1230 if (importTag == null) continue;
1231 LibraryElement importedLibrary = library.getLibraryFromTag(tag);
1232 if (importedLibrary != compiler.mirrorsLibrary) continue;
1233 MessageKind kind =
1234 compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
1235 ? MessageKind.MIRROR_IMPORT
1236 : MessageKind.MIRROR_IMPORT_NO_USAGE;
1237 compiler.withCurrentElement(library, () {
1238 compiler.reportInfo(importTag, kind);
1239 });
1240 }
1241 }
1242 }
1243 }
1244
1245 Element getDartClass(Element element) {
1246 for (ClassElement dartClass in implementationClasses.keys) {
1247 if (element == implementationClasses[dartClass]) {
1248 return dartClass;
1249 }
1250 }
1251 return element;
1252 }
1253
1254 /**
1255 * Returns the checked mode helper that will be needed to do a type check/type
1256 * cast on [type] at runtime. Note that this method is being called both by
1257 * the resolver with interface types (int, String, ...), and by the SSA
1258 * backend with implementation types (JSInt, JSString, ...).
1259 */
1260 CheckedModeHelper getCheckedModeHelper(DartType type, {bool typeCast}) {
1261 return getCheckedModeHelperInternal(
1262 type, typeCast: typeCast, nativeCheckOnly: false);
1263 }
1264
1265 /**
1266 * Returns the native checked mode helper that will be needed to do a type
1267 * check/type cast on [type] at runtime. If no native helper exists for
1268 * [type], [:null:] is returned.
1269 */
1270 CheckedModeHelper getNativeCheckedModeHelper(DartType type, {bool typeCast}) {
1271 return getCheckedModeHelperInternal(
1272 type, typeCast: typeCast, nativeCheckOnly: true);
1273 }
1274
1275 /**
1276 * Returns the checked mode helper for the type check/type cast for [type]. If
1277 * [nativeCheckOnly] is [:true:], only names for native helpers are returned.
1278 */
1279 CheckedModeHelper getCheckedModeHelperInternal(DartType type,
1280 {bool typeCast,
1281 bool nativeCheckOnly}) {
1282 String name = getCheckedModeHelperNameInternal(type,
1283 typeCast: typeCast, nativeCheckOnly: nativeCheckOnly);
1284 if (name == null) return null;
1285 CheckedModeHelper helper = checkedModeHelperByName[name];
1286 assert(helper != null);
1287 return helper;
1288 }
1289
1290 String getCheckedModeHelperNameInternal(DartType type,
1291 {bool typeCast,
1292 bool nativeCheckOnly}) {
1293 assert(type.kind != TypeKind.TYPEDEF);
1294 if (type.isMalformed) {
1295 // The same error is thrown for type test and type cast of a malformed
1296 // type so we only need one check method.
1297 return 'checkMalformedType';
1298 }
1299 Element element = type.element;
1300 bool nativeCheck = nativeCheckOnly ||
1301 emitter.nativeEmitter.requiresNativeIsCheck(element);
1302
1303 // TODO(13955), TODO(9731). The test for non-primitive types should use an
1304 // interceptor. The interceptor should be an argument to HTypeConversion so
1305 // that it can be optimized by standard interceptor optimizations.
1306 nativeCheck = true;
1307
1308 if (type.isVoid) {
1309 assert(!typeCast); // Cannot cast to void.
1310 if (nativeCheckOnly) return null;
1311 return 'voidTypeCheck';
1312 } else if (element == jsStringClass || element == compiler.stringClass) {
1313 if (nativeCheckOnly) return null;
1314 return typeCast
1315 ? 'stringTypeCast'
1316 : 'stringTypeCheck';
1317 } else if (element == jsDoubleClass || element == compiler.doubleClass) {
1318 if (nativeCheckOnly) return null;
1319 return typeCast
1320 ? 'doubleTypeCast'
1321 : 'doubleTypeCheck';
1322 } else if (element == jsNumberClass || element == compiler.numClass) {
1323 if (nativeCheckOnly) return null;
1324 return typeCast
1325 ? 'numTypeCast'
1326 : 'numTypeCheck';
1327 } else if (element == jsBoolClass || element == compiler.boolClass) {
1328 if (nativeCheckOnly) return null;
1329 return typeCast
1330 ? 'boolTypeCast'
1331 : 'boolTypeCheck';
1332 } else if (element == jsIntClass || element == compiler.intClass
1333 || element == jsUInt32Class || element == jsUInt31Class
1334 || element == jsPositiveIntClass) {
1335 if (nativeCheckOnly) return null;
1336 return typeCast
1337 ? 'intTypeCast'
1338 : 'intTypeCheck';
1339 } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
1340 if (nativeCheck) {
1341 return typeCast
1342 ? 'numberOrStringSuperNativeTypeCast'
1343 : 'numberOrStringSuperNativeTypeCheck';
1344 } else {
1345 return typeCast
1346 ? 'numberOrStringSuperTypeCast'
1347 : 'numberOrStringSuperTypeCheck';
1348 }
1349 } else if (Elements.isStringOnlySupertype(element, compiler)) {
1350 if (nativeCheck) {
1351 return typeCast
1352 ? 'stringSuperNativeTypeCast'
1353 : 'stringSuperNativeTypeCheck';
1354 } else {
1355 return typeCast
1356 ? 'stringSuperTypeCast'
1357 : 'stringSuperTypeCheck';
1358 }
1359 } else if ((element == compiler.listClass || element == jsArrayClass) &&
1360 type.treatAsRaw) {
1361 if (nativeCheckOnly) return null;
1362 return typeCast
1363 ? 'listTypeCast'
1364 : 'listTypeCheck';
1365 } else {
1366 if (Elements.isListSupertype(element, compiler)) {
1367 if (nativeCheck) {
1368 return typeCast
1369 ? 'listSuperNativeTypeCast'
1370 : 'listSuperNativeTypeCheck';
1371 } else {
1372 return typeCast
1373 ? 'listSuperTypeCast'
1374 : 'listSuperTypeCheck';
1375 }
1376 } else {
1377 if (type.isInterfaceType && !type.treatAsRaw) {
1378 return typeCast
1379 ? 'subtypeCast'
1380 : 'assertSubtype';
1381 } else if (type.isTypeVariable) {
1382 return typeCast
1383 ? 'subtypeOfRuntimeTypeCast'
1384 : 'assertSubtypeOfRuntimeType';
1385 } else if (type.isFunctionType) {
1386 return null;
1387 } else {
1388 if (nativeCheck) {
1389 // TODO(karlklose): can we get rid of this branch when we use
1390 // interceptors?
1391 return typeCast
1392 ? 'interceptedTypeCast'
1393 : 'interceptedTypeCheck';
1394 } else {
1395 return typeCast
1396 ? 'propertyTypeCast'
1397 : 'propertyTypeCheck';
1398 }
1399 }
1400 }
1401 }
1402 }
1403
1404 void registerCheckedModeHelpers(Registry registry) {
1405 // We register all the helpers in the resolution queue.
1406 // TODO(13155): Find a way to register fewer helpers.
1407 for (CheckedModeHelper helper in checkedModeHelpers) {
1408 enqueueInResolution(helper.getElement(compiler), registry);
1409 }
1410 }
1411
1412 /**
1413 * Returns [:true:] if the checking of [type] is performed directly on the
1414 * object and not on an interceptor.
1415 */
1416 bool hasDirectCheckFor(DartType type) {
1417 Element element = type.element;
1418 return element == compiler.stringClass ||
1419 element == compiler.boolClass ||
1420 element == compiler.numClass ||
1421 element == compiler.intClass ||
1422 element == compiler.doubleClass ||
1423 element == jsArrayClass ||
1424 element == jsMutableArrayClass ||
1425 element == jsExtendableArrayClass ||
1426 element == jsFixedArrayClass;
1427 }
1428
1429 Element getExceptionUnwrapper() {
1430 return findHelper('unwrapException');
1431 }
1432
1433 Element getThrowRuntimeError() {
1434 return findHelper('throwRuntimeError');
1435 }
1436
1437 Element getThrowTypeError() {
1438 return findHelper('throwTypeError');
1439 }
1440
1441 Element getThrowAbstractClassInstantiationError() {
1442 return findHelper('throwAbstractClassInstantiationError');
1443 }
1444
1445 Element getStringInterpolationHelper() {
1446 return findHelper('S');
1447 }
1448
1449 Element getWrapExceptionHelper() {
1450 return findHelper(r'wrapException');
1451 }
1452
1453 Element getThrowExpressionHelper() {
1454 return findHelper('throwExpression');
1455 }
1456
1457 Element getClosureConverter() {
1458 return findHelper('convertDartClosureToJS');
1459 }
1460
1461 Element getTraceFromException() {
1462 return findHelper('getTraceFromException');
1463 }
1464
1465 Element getSetRuntimeTypeInfo() {
1466 return findHelper('setRuntimeTypeInfo');
1467 }
1468
1469 Element getGetRuntimeTypeInfo() {
1470 return findHelper('getRuntimeTypeInfo');
1471 }
1472
1473 Element getGetTypeArgumentByIndex() {
1474 return findHelper('getTypeArgumentByIndex');
1475 }
1476
1477 Element getCopyTypeArguments() {
1478 return findHelper('copyTypeArguments');
1479 }
1480
1481 Element getComputeSignature() {
1482 return findHelper('computeSignature');
1483 }
1484
1485 Element getGetRuntimeTypeArguments() {
1486 return findHelper('getRuntimeTypeArguments');
1487 }
1488
1489 Element getGetRuntimeTypeArgument() {
1490 return findHelper('getRuntimeTypeArgument');
1491 }
1492
1493 Element getRuntimeTypeToString() {
1494 return findHelper('runtimeTypeToString');
1495 }
1496
1497 Element getAssertIsSubtype() {
1498 return findHelper('assertIsSubtype');
1499 }
1500
1501 Element getCheckSubtype() {
1502 return findHelper('checkSubtype');
1503 }
1504
1505 Element getAssertSubtype() {
1506 return findHelper('assertSubtype');
1507 }
1508
1509 Element getCheckSubtypeOfRuntimeType() {
1510 return findHelper('checkSubtypeOfRuntimeType');
1511 }
1512
1513 Element getCheckDeferredIsLoaded() {
1514 return findHelper('checkDeferredIsLoaded');
1515 }
1516
1517 Element getAssertSubtypeOfRuntimeType() {
1518 return findHelper('assertSubtypeOfRuntimeType');
1519 }
1520
1521 Element getThrowNoSuchMethod() {
1522 return findHelper('throwNoSuchMethod');
1523 }
1524
1525 Element getCreateRuntimeType() {
1526 return findHelper('createRuntimeType');
1527 }
1528
1529 Element getFallThroughError() {
1530 return findHelper("getFallThroughError");
1531 }
1532
1533 Element getCreateInvocationMirror() {
1534 return findHelper(Compiler.CREATE_INVOCATION_MIRROR);
1535 }
1536
1537 Element getCyclicThrowHelper() {
1538 return findHelper("throwCyclicInit");
1539 }
1540
1541 bool isNullImplementation(ClassElement cls) {
1542 return cls == jsNullClass;
1543 }
1544
1545 ClassElement get intImplementation => jsIntClass;
1546 ClassElement get uint32Implementation => jsUInt32Class;
1547 ClassElement get uint31Implementation => jsUInt31Class;
1548 ClassElement get positiveIntImplementation => jsPositiveIntClass;
1549 ClassElement get doubleImplementation => jsDoubleClass;
1550 ClassElement get numImplementation => jsNumberClass;
1551 ClassElement get stringImplementation => jsStringClass;
1552 ClassElement get listImplementation => jsArrayClass;
1553 ClassElement get constListImplementation => jsArrayClass;
1554 ClassElement get fixedListImplementation => jsFixedArrayClass;
1555 ClassElement get growableListImplementation => jsExtendableArrayClass;
1556 ClassElement get mapImplementation => mapLiteralClass;
1557 ClassElement get constMapImplementation => constMapLiteralClass;
1558 ClassElement get typeImplementation => typeLiteralClass;
1559 ClassElement get boolImplementation => jsBoolClass;
1560 ClassElement get nullImplementation => jsNullClass;
1561
1562 void registerStaticUse(Element element, Enqueuer enqueuer) {
1563 if (element == disableTreeShakingMarker) {
1564 compiler.disableTypeInferenceForMirrors = true;
1565 isTreeShakingDisabled = true;
1566 typeVariableHandler.onTreeShakingDisabled(enqueuer);
1567 } else if (element == preserveNamesMarker) {
1568 mustPreserveNames = true;
1569 } else if (element == preserveMetadataMarker) {
1570 mustRetainMetadata = true;
1571 } else if (element == preserveUrisMarker) {
1572 if (compiler.preserveUris) mustPreserveUris = true;
1573 } else if (element == preserveLibraryNamesMarker) {
1574 mustRetainLibraryNames = true;
1575 } else if (element == getIsolateAffinityTagMarker) {
1576 needToInitializeIsolateAffinityTag = true;
1577 } else if (element.isDeferredLoaderGetter) {
1578 // TODO(sigurdm): Create a function registerLoadLibraryAccess.
1579 if (compiler.loadLibraryFunction == null) {
1580 compiler.loadLibraryFunction =
1581 findHelper("_loadLibraryWrapper");
1582 enqueueInResolution(compiler.loadLibraryFunction,
1583 compiler.globalDependencies);
1584 }
1585 } else if (element == requiresPreambleMarker) {
1586 requiresPreamble = true;
1587 }
1588 customElementsAnalysis.registerStaticUse(element, enqueuer);
1589 }
1590
1591 /// Called when [:const Symbol(name):] is seen.
1592 void registerConstSymbol(String name, Registry registry) {
1593 symbolsUsed.add(name);
1594 if (name.endsWith('=')) {
1595 symbolsUsed.add(name.substring(0, name.length - 1));
1596 }
1597 }
1598
1599 /// Called when [:new Symbol(...):] is seen.
1600 void registerNewSymbol(Registry registry) {
1601 }
1602
1603 /// Should [element] (a getter) that would normally not be generated due to
1604 /// treeshaking be retained for reflection?
1605 bool shouldRetainGetter(Element element) {
1606 return isTreeShakingDisabled && isAccessibleByReflection(element);
1607 }
1608
1609 /// Should [element] (a setter) hat would normally not be generated due to
1610 /// treeshaking be retained for reflection?
1611 bool shouldRetainSetter(Element element) {
1612 return isTreeShakingDisabled && isAccessibleByReflection(element);
1613 }
1614
1615 /// Should [name] be retained for reflection?
1616 bool shouldRetainName(String name) {
1617 if (hasInsufficientMirrorsUsed) return mustPreserveNames;
1618 if (name == '') return false;
1619 return symbolsUsed.contains(name);
1620 }
1621
1622 bool retainMetadataOf(Element element) {
1623 if (mustRetainMetadata) hasRetainedMetadata = true;
1624 if (mustRetainMetadata && referencedFromMirrorSystem(element)) {
1625 for (MetadataAnnotation metadata in element.metadata) {
1626 metadata.ensureResolved(compiler);
1627 ConstantValue constant =
1628 constants.getConstantForMetadata(metadata).value;
1629 constants.addCompileTimeConstantForEmission(constant);
1630 }
1631 return true;
1632 }
1633 return false;
1634 }
1635
1636 void onLibraryCreated(LibraryElement library) {
1637 Uri uri = library.canonicalUri;
1638 if (uri == DART_JS_HELPER) {
1639 jsHelperLibrary = library;
1640 } else if (uri == DART_INTERNAL) {
1641 internalLibrary = library;
1642 } else if (uri == DART_INTERCEPTORS) {
1643 interceptorsLibrary = library;
1644 } else if (uri == DART_FOREIGN_HELPER) {
1645 foreignLibrary = library;
1646 } else if (uri == DART_ISOLATE_HELPER) {
1647 isolateHelperLibrary = library;
1648 }
1649 }
1650
1651 void initializeHelperClasses() {
1652 final List missingHelperClasses = [];
1653 ClassElement lookupHelperClass(String name) {
1654 ClassElement result = findHelper(name);
1655 if (result == null) {
1656 missingHelperClasses.add(name);
1657 }
1658 return result;
1659 }
1660 jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror');
1661 boundClosureClass = lookupHelperClass('BoundClosure');
1662 closureClass = lookupHelperClass('Closure');
1663 if (!missingHelperClasses.isEmpty) {
1664 compiler.internalError(jsHelperLibrary,
1665 'dart:_js_helper library does not contain required classes: '
1666 '$missingHelperClasses');
1667 }
1668 }
1669
1670 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
1671 return super.onLibraryScanned(library, loader).then((_) {
1672 Uri uri = library.canonicalUri;
1673
1674 VariableElement findVariable(String name) {
1675 return find(library, name);
1676 }
1677
1678 FunctionElement findMethod(String name) {
1679 return find(library, name);
1680 }
1681
1682 ClassElement findClass(String name) {
1683 return find(library, name);
1684 }
1685
1686 if (uri == DART_INTERCEPTORS) {
1687 getInterceptorMethod = findMethod('getInterceptor');
1688 interceptedNames = findVariable('interceptedNames');
1689 mapTypeToInterceptor = findVariable('mapTypeToInterceptor');
1690 getNativeInterceptorMethod = findMethod('getNativeInterceptor');
1691
1692 List<ClassElement> classes = [
1693 jsInterceptorClass = findClass('Interceptor'),
1694 jsStringClass = findClass('JSString'),
1695 jsArrayClass = findClass('JSArray'),
1696 // The int class must be before the double class, because the
1697 // emitter relies on this list for the order of type checks.
1698 jsIntClass = findClass('JSInt'),
1699 jsPositiveIntClass = findClass('JSPositiveInt'),
1700 jsUInt32Class = findClass('JSUInt32'),
1701 jsUInt31Class = findClass('JSUInt31'),
1702 jsDoubleClass = findClass('JSDouble'),
1703 jsNumberClass = findClass('JSNumber'),
1704 jsNullClass = findClass('JSNull'),
1705 jsBoolClass = findClass('JSBool'),
1706 jsMutableArrayClass = findClass('JSMutableArray'),
1707 jsFixedArrayClass = findClass('JSFixedArray'),
1708 jsExtendableArrayClass = findClass('JSExtendableArray'),
1709 jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject'),
1710 jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject'),
1711 ];
1712
1713 jsIndexableClass = findClass('JSIndexable');
1714 jsMutableIndexableClass = findClass('JSMutableIndexable');
1715 } else if (uri == DART_JS_HELPER) {
1716 initializeHelperClasses();
1717 assertMethod = findHelper('assertHelper');
1718
1719 typeLiteralClass = findClass('TypeImpl');
1720 constMapLiteralClass = findClass('ConstantMap');
1721 typeVariableClass = findClass('TypeVariable');
1722
1723 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior');
1724
1725 noSideEffectsClass = findClass('NoSideEffects');
1726 noThrowsClass = findClass('NoThrows');
1727 noInlineClass = findClass('NoInline');
1728 irRepresentationClass = findClass('IrRepresentation');
1729
1730 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
1731
1732 requiresPreambleMarker = findMethod('requiresPreamble');
1733 } else if (uri == DART_JS_MIRRORS) {
1734 disableTreeShakingMarker = find(library, 'disableTreeShaking');
1735 preserveMetadataMarker = find(library, 'preserveMetadata');
1736 preserveUrisMarker = find(library, 'preserveUris');
1737 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames');
1738 } else if (uri == DART_JS_NAMES) {
1739 preserveNamesMarker = find(library, 'preserveNames');
1740 } else if (uri == DART_HTML) {
1741 htmlLibraryIsLoaded = true;
1742 }
1743 });
1744 }
1745
1746 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
1747 if (!loadedLibraries.containsKey(Compiler.DART_CORE)) {
1748 return new Future.value();
1749 }
1750
1751 assert(loadedLibraries.containsKey(Compiler.DART_CORE));
1752 assert(loadedLibraries.containsKey(DART_INTERCEPTORS));
1753 assert(loadedLibraries.containsKey(DART_JS_HELPER));
1754
1755 if (jsInvocationMirrorClass != null) {
1756 jsInvocationMirrorClass.ensureResolved(compiler);
1757 invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
1758 }
1759
1760 // [LinkedHashMap] is reexported from dart:collection and can therefore not
1761 // be loaded from dart:core in [onLibraryScanned].
1762 mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap');
1763 assert(invariant(compiler.coreLibrary, mapLiteralClass != null,
1764 message: "Element 'LinkedHashMap' not found in 'dart:core'."));
1765
1766 implementationClasses = <ClassElement, ClassElement>{};
1767 implementationClasses[compiler.intClass] = jsIntClass;
1768 implementationClasses[compiler.boolClass] = jsBoolClass;
1769 implementationClasses[compiler.numClass] = jsNumberClass;
1770 implementationClasses[compiler.doubleClass] = jsDoubleClass;
1771 implementationClasses[compiler.stringClass] = jsStringClass;
1772 implementationClasses[compiler.listClass] = jsArrayClass;
1773 implementationClasses[compiler.nullClass] = jsNullClass;
1774
1775 // These methods are overwritten with generated versions.
1776 inlineCache.markAsNonInlinable(getInterceptorMethod, insideLoop: true);
1777
1778 // TODO(kasperl): Some tests do not define the special JSArray
1779 // subclasses, so we check to see if they are defined before
1780 // trying to resolve them.
1781 if (jsFixedArrayClass != null) {
1782 jsFixedArrayClass.ensureResolved(compiler);
1783 }
1784 if (jsExtendableArrayClass != null) {
1785 jsExtendableArrayClass.ensureResolved(compiler);
1786 }
1787
1788 jsIndexableClass.ensureResolved(compiler);
1789 jsIndexableLength = compiler.lookupElementIn(
1790 jsIndexableClass, 'length');
1791 if (jsIndexableLength != null && jsIndexableLength.isAbstractField) {
1792 AbstractFieldElement element = jsIndexableLength;
1793 jsIndexableLength = element.getter;
1794 }
1795
1796 jsArrayClass.ensureResolved(compiler);
1797 jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed');
1798 jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast');
1799 jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add');
1800
1801 jsStringClass.ensureResolved(compiler);
1802 jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split');
1803 jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+');
1804 jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString');
1805
1806 objectEquals = compiler.lookupElementIn(compiler.objectClass, '==');
1807
1808 specialOperatorEqClasses
1809 ..add(compiler.objectClass)
1810 ..add(jsInterceptorClass)
1811 ..add(jsNullClass);
1812
1813 validateInterceptorImplementsAllObjectMethods(jsInterceptorClass);
1814 // The null-interceptor must also implement *all* methods.
1815 validateInterceptorImplementsAllObjectMethods(jsNullClass);
1816
1817 return new Future.value();
1818 }
1819
1820 void registerMirrorUsage(Set<String> symbols,
1821 Set<Element> targets,
1822 Set<Element> metaTargets) {
1823 if (symbols == null && targets == null && metaTargets == null) {
1824 // The user didn't specify anything, or there are imports of
1825 // 'dart:mirrors' without @MirrorsUsed.
1826 hasInsufficientMirrorsUsed = true;
1827 return;
1828 }
1829 if (symbols != null) symbolsUsed.addAll(symbols);
1830 if (targets != null) {
1831 for (Element target in targets) {
1832 if (target.isAbstractField) {
1833 AbstractFieldElement field = target;
1834 targetsUsed.add(field.getter);
1835 targetsUsed.add(field.setter);
1836 } else {
1837 targetsUsed.add(target);
1838 }
1839 }
1840 }
1841 if (metaTargets != null) metaTargetsUsed.addAll(metaTargets);
1842 }
1843
1844 /**
1845 * Returns `true` if [element] can be accessed through reflection, that is,
1846 * is in the set of elements covered by a `MirrorsUsed` annotation.
1847 *
1848 * This property is used to tag emitted elements with a marker which is
1849 * checked by the runtime system to throw an exception if an element is
1850 * accessed (invoked, get, set) that is not accessible for the reflective
1851 * system.
1852 */
1853 bool isAccessibleByReflection(Element element) {
1854 if (element.isClass) {
1855 element = getDartClass(element);
1856 }
1857 return membersNeededForReflection.contains(element);
1858 }
1859
1860 /**
1861 * Returns true if the element has to be resolved due to a mirrorsUsed
1862 * annotation. If we have insufficient mirrors used annotations, we only
1863 * keep additonal elements if treeshaking has been disabled.
1864 */
1865 bool requiredByMirrorSystem(Element element) {
1866 return hasInsufficientMirrorsUsed && isTreeShakingDisabled ||
1867 matchesMirrorsMetaTarget(element) ||
1868 targetsUsed.contains(element);
1869 }
1870
1871 /**
1872 * Returns true if the element matches a mirrorsUsed annotation. If
1873 * we have insufficient mirrorsUsed information, this returns true for
1874 * all elements, as they might all be potentially referenced.
1875 */
1876 bool referencedFromMirrorSystem(Element element, [recursive = true]) {
1877 Element enclosing = recursive ? element.enclosingElement : null;
1878
1879 return hasInsufficientMirrorsUsed ||
1880 matchesMirrorsMetaTarget(element) ||
1881 targetsUsed.contains(element) ||
1882 (enclosing != null && referencedFromMirrorSystem(enclosing));
1883 }
1884
1885 /**
1886 * Returns `true` if the element is needed because it has an annotation
1887 * of a type that is used as a meta target for reflection.
1888 */
1889 bool matchesMirrorsMetaTarget(Element element) {
1890 if (metaTargetsUsed.isEmpty) return false;
1891 for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
1892 MetadataAnnotation metadata = link.head;
1893 // TODO(kasperl): It would be nice if we didn't have to resolve
1894 // all metadata but only stuff that potentially would match one
1895 // of the used meta targets.
1896 metadata.ensureResolved(compiler);
1897 ConstantValue value = metadata.constant.value;
1898 if (value == null) continue;
1899 DartType type = value.computeType(compiler);
1900 if (metaTargetsUsed.contains(type.element)) return true;
1901 }
1902 return false;
1903 }
1904
1905 /**
1906 * Visits all classes and computes whether its members are needed for
1907 * reflection.
1908 *
1909 * We have to precompute this set as we cannot easily answer the need for
1910 * reflection locally when looking at the member: We lack the information by
1911 * which classes a member is inherited. Called after resolution is complete.
1912 *
1913 * We filter out private libraries here, as their elements should not
1914 * be visible by reflection unless some other interfaces makes them
1915 * accessible.
1916 */
1917 computeMembersNeededForReflection() {
1918 if (_membersNeededForReflection != null) return;
1919 if (compiler.mirrorsLibrary == null) {
1920 _membersNeededForReflection = const ImmutableEmptySet<Element>();
1921 return;
1922 }
1923 // Compute a mapping from class to the closures it contains, so we
1924 // can include the correct ones when including the class.
1925 Map<ClassElement, List<LocalFunctionElement>> closureMap =
1926 new Map<ClassElement, List<LocalFunctionElement>>();
1927 for (LocalFunctionElement closure in compiler.resolverWorld.allClosures) {
1928 closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure);
1929 }
1930 bool foundClosure = false;
1931 Set<Element> reflectableMembers = new Set<Element>();
1932 ResolutionEnqueuer resolution = compiler.enqueuer.resolution;
1933 for (ClassElement cls in resolution.universe.directlyInstantiatedClasses) {
1934 // Do not process internal classes.
1935 if (cls.library.isInternalLibrary || cls.isInjected) continue;
1936 if (referencedFromMirrorSystem(cls)) {
1937 Set<Name> memberNames = new Set<Name>();
1938 // 1) the class (should be resolved)
1939 assert(invariant(cls, cls.isResolved));
1940 reflectableMembers.add(cls);
1941 // 2) its constructors (if resolved)
1942 cls.constructors.forEach((Element constructor) {
1943 if (resolution.hasBeenResolved(constructor)) {
1944 reflectableMembers.add(constructor);
1945 }
1946 });
1947 // 3) all members, including fields via getter/setters (if resolved)
1948 cls.forEachClassMember((Member member) {
1949 if (resolution.hasBeenResolved(member.element)) {
1950 memberNames.add(member.name);
1951 reflectableMembers.add(member.element);
1952 }
1953 });
1954 // 4) all overriding members of subclasses/subtypes (should be resolved)
1955 if (compiler.world.hasAnySubtype(cls)) {
1956 for (ClassElement subcls in compiler.world.subtypesOf(cls)) {
1957 subcls.forEachClassMember((Member member) {
1958 if (memberNames.contains(member.name)) {
1959 // TODO(20993): find out why this assertion fails.
1960 // assert(invariant(member.element,
1961 // resolution.hasBeenResolved(member.element)));
1962 if (resolution.hasBeenResolved(member.element)) {
1963 reflectableMembers.add(member.element);
1964 }
1965 }
1966 });
1967 }
1968 }
1969 // 5) all its closures
1970 List<LocalFunctionElement> closures = closureMap[cls];
1971 if (closures != null) {
1972 reflectableMembers.addAll(closures);
1973 foundClosure = true;
1974 }
1975 } else {
1976 // check members themselves
1977 cls.constructors.forEach((ConstructorElement element) {
1978 if (!resolution.hasBeenResolved(element)) return;
1979 if (referencedFromMirrorSystem(element, false)) {
1980 reflectableMembers.add(element);
1981 }
1982 });
1983 cls.forEachClassMember((Member member) {
1984 if (!resolution.hasBeenResolved(member.element)) return;
1985 if (referencedFromMirrorSystem(member.element, false)) {
1986 reflectableMembers.add(member.element);
1987 }
1988 });
1989 // Also add in closures. Those might be reflectable is their enclosing
1990 // member is.
1991 List<LocalFunctionElement> closures = closureMap[cls];
1992 if (closures != null) {
1993 for (LocalFunctionElement closure in closures) {
1994 if (referencedFromMirrorSystem(closure.memberContext, false)) {
1995 reflectableMembers.add(closure);
1996 foundClosure = true;
1997 }
1998 }
1999 }
2000 }
2001 }
2002 // We also need top-level non-class elements like static functions and
2003 // global fields. We use the resolution queue to decide which elements are
2004 // part of the live world.
2005 for (LibraryElement lib in compiler.libraryLoader.libraries) {
2006 if (lib.isInternalLibrary) continue;
2007 lib.forEachLocalMember((Element member) {
2008 if (!member.isClass &&
2009 resolution.hasBeenResolved(member) &&
2010 referencedFromMirrorSystem(member)) {
2011 reflectableMembers.add(member);
2012 }
2013 });
2014 }
2015 // And closures inside top-level elements that do not have a surrounding
2016 // class. These will be in the [:null:] bucket of the [closureMap].
2017 if (closureMap.containsKey(null)) {
2018 for (Element closure in closureMap[null]) {
2019 if (referencedFromMirrorSystem(closure)) {
2020 reflectableMembers.add(closure);
2021 foundClosure = true;
2022 }
2023 }
2024 }
2025 // As we do not think about closures as classes, yet, we have to make sure
2026 // their superclasses are available for reflection manually.
2027 if (foundClosure) {
2028 reflectableMembers.add(closureClass);
2029 }
2030 Set<Element> closurizedMembers = compiler.resolverWorld.closurizedMembers;
2031 if (closurizedMembers.any(reflectableMembers.contains)) {
2032 reflectableMembers.add(boundClosureClass);
2033 }
2034 // Add typedefs.
2035 reflectableMembers
2036 .addAll(compiler.world.allTypedefs.where(referencedFromMirrorSystem));
2037 // Register all symbols of reflectable elements
2038 for (Element element in reflectableMembers) {
2039 symbolsUsed.add(element.name);
2040 }
2041 _membersNeededForReflection = reflectableMembers;
2042 }
2043
2044 // TODO(20791): compute closure classes after resolution and move this code to
2045 // [computeMembersNeededForReflection].
2046 void maybeMarkClosureAsNeededForReflection(
2047 ClosureClassElement globalizedElement,
2048 FunctionElement callFunction,
2049 FunctionElement function) {
2050 if (!_membersNeededForReflection.contains(function)) return;
2051 _membersNeededForReflection.add(callFunction);
2052 _membersNeededForReflection.add(globalizedElement);
2053 }
2054
2055 jsAst.Call generateIsJsIndexableCall(jsAst.Expression use1,
2056 jsAst.Expression use2) {
2057 String dispatchPropertyName = embeddedNames.DISPATCH_PROPERTY_NAME;
2058 jsAst.Expression dispatchProperty =
2059 emitter.generateEmbeddedGlobalAccess(dispatchPropertyName);
2060
2061 // We pass the dispatch property record to the isJsIndexable
2062 // helper rather than reading it inside the helper to increase the
2063 // chance of making the dispatch record access monomorphic.
2064 jsAst.PropertyAccess record =
2065 new jsAst.PropertyAccess(use2, dispatchProperty);
2066
2067 List<jsAst.Expression> arguments = <jsAst.Expression>[use1, record];
2068 FunctionElement helper = findHelper('isJsIndexable');
2069 jsAst.Expression helperExpression = namer.elementAccess(helper);
2070 return new jsAst.Call(helperExpression, arguments);
2071 }
2072
2073 bool isTypedArray(TypeMask mask) {
2074 // Just checking for [:TypedData:] is not sufficient, as it is an
2075 // abstract class any user-defined class can implement. So we also
2076 // check for the interface [JavaScriptIndexingBehavior].
2077 return
2078 compiler.typedDataClass != null &&
2079 compiler.world.isInstantiated(compiler.typedDataClass) &&
2080 mask.satisfies(compiler.typedDataClass, compiler.world) &&
2081 mask.satisfies(jsIndexingBehaviorInterface, compiler.world);
2082 }
2083
2084 bool couldBeTypedArray(TypeMask mask) {
2085 bool intersects(TypeMask type1, TypeMask type2) =>
2086 !type1.intersection(type2, compiler.world).isEmpty;
2087 // TODO(herhut): Maybe cache the TypeMask for typedDataClass and
2088 // jsIndexingBehaviourInterface.
2089 return
2090 compiler.typedDataClass != null &&
2091 compiler.world.isInstantiated(compiler.typedDataClass) &&
2092 intersects(mask,
2093 new TypeMask.subtype(compiler.typedDataClass, compiler.world)) &&
2094 intersects(mask,
2095 new TypeMask.subtype(jsIndexingBehaviorInterface, compiler.world));
2096 }
2097
2098 /// Returns all static fields that are referenced through [targetsUsed].
2099 /// If the target is a library or class all nested static fields are
2100 /// included too.
2101 Iterable<Element> _findStaticFieldTargets() {
2102 List staticFields = [];
2103
2104 void addFieldsInContainer(ScopeContainerElement container) {
2105 container.forEachLocalMember((Element member) {
2106 if (!member.isInstanceMember && member.isField) {
2107 staticFields.add(member);
2108 } else if (member.isClass) {
2109 addFieldsInContainer(member);
2110 }
2111 });
2112 }
2113
2114 for (Element target in targetsUsed) {
2115 if (target == null) continue;
2116 if (target.isField) {
2117 staticFields.add(target);
2118 } else if (target.isLibrary || target.isClass) {
2119 addFieldsInContainer(target);
2120 }
2121 }
2122 return staticFields;
2123 }
2124
2125 /// Called when [enqueuer] is empty, but before it is closed.
2126 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
2127 // Add elements referenced only via custom elements. Return early if any
2128 // elements are added to avoid counting the elements as due to mirrors.
2129 customElementsAnalysis.onQueueEmpty(enqueuer);
2130 if (!enqueuer.queueIsEmpty) return false;
2131
2132 if (!enqueuer.isResolutionQueue && preMirrorsMethodCount == 0) {
2133 preMirrorsMethodCount = generatedCode.length;
2134 }
2135
2136 if (isTreeShakingDisabled) {
2137 enqueuer.enqueueReflectiveElements(recentClasses);
2138 } else if (!targetsUsed.isEmpty && enqueuer.isResolutionQueue) {
2139 // Add all static elements (not classes) that have been requested for
2140 // reflection. If there is no mirror-usage these are probably not
2141 // necessary, but the backend relies on them being resolved.
2142 enqueuer.enqueueReflectiveStaticFields(_findStaticFieldTargets());
2143 }
2144
2145 if (mustPreserveNames) compiler.log('Preserving names.');
2146
2147 if (mustRetainMetadata) {
2148 compiler.log('Retaining metadata.');
2149
2150 compiler.libraryLoader.libraries.forEach(retainMetadataOf);
2151 if (!enqueuer.isResolutionQueue) {
2152 for (Dependency dependency in metadataConstants) {
2153 registerCompileTimeConstant(
2154 dependency.constant,
2155 new CodegenRegistry(compiler,
2156 dependency.annotatedElement.analyzableElement.treeElements));
2157 }
2158 metadataConstants.clear();
2159 }
2160 }
2161 return true;
2162 }
2163
2164 void onElementResolved(Element element, TreeElements elements) {
2165 LibraryElement library = element.library;
2166 if (!library.isPlatformLibrary && !library.canUseNative) return;
2167 bool hasNoInline = false;
2168 bool hasNoThrows = false;
2169 bool hasNoSideEffects = false;
2170 for (MetadataAnnotation metadata in element.metadata) {
2171 metadata.ensureResolved(compiler);
2172 if (!metadata.constant.value.isConstructedObject) continue;
2173 ObjectConstantValue value = metadata.constant.value;
2174 ClassElement cls = value.type.element;
2175 if (cls == noInlineClass) {
2176 hasNoInline = true;
2177 if (VERBOSE_OPTIMIZER_HINTS) {
2178 compiler.reportHint(element,
2179 MessageKind.GENERIC,
2180 {'text': "Cannot inline"});
2181 }
2182 inlineCache.markAsNonInlinable(element);
2183 } else if (cls == noThrowsClass) {
2184 hasNoThrows = true;
2185 if (!Elements.isStaticOrTopLevelFunction(element)) {
2186 compiler.internalError(element,
2187 "@NoThrows() is currently limited to top-level"
2188 " or static functions");
2189 }
2190 if (VERBOSE_OPTIMIZER_HINTS) {
2191 compiler.reportHint(element,
2192 MessageKind.GENERIC,
2193 {'text': "Cannot throw"});
2194 }
2195 compiler.world.registerCannotThrow(element);
2196 } else if (cls == noSideEffectsClass) {
2197 hasNoSideEffects = true;
2198 if (VERBOSE_OPTIMIZER_HINTS) {
2199 compiler.reportHint(element,
2200 MessageKind.GENERIC,
2201 {'text': "Has no side effects"});
2202 }
2203 compiler.world.registerSideEffectsFree(element);
2204 }
2205 }
2206 if (hasNoThrows && !hasNoInline) {
2207 compiler.internalError(element,
2208 "@NoThrows() should always be combined with @NoInline.");
2209 }
2210 if (hasNoSideEffects && !hasNoInline) {
2211 compiler.internalError(element,
2212 "@NoSideEffects() should always be combined with @NoInline.");
2213 }
2214 if (element == invokeOnMethod) {
2215 compiler.enabledInvokeOn = true;
2216 }
2217 }
2218
2219 CodeBuffer codeOf(Element element) {
2220 return generatedCode.containsKey(element)
2221 ? jsAst.prettyPrint(generatedCode[element], compiler)
2222 : null;
2223 }
2224
2225 FunctionElement helperForBadMain() => findHelper('badMain');
2226
2227 FunctionElement helperForMissingMain() => findHelper('missingMain');
2228
2229 FunctionElement helperForMainArity() {
2230 return findHelper('mainHasTooManyParameters');
2231 }
2232
2233 void forgetElement(Element element) {
2234 constants.forgetElement(element);
2235 constantCompilerTask.dartConstantCompiler.forgetElement(element);
2236 }
2237
2238 void registerMainHasArguments(Enqueuer enqueuer) {
2239 // If the main method takes arguments, this compilation could be the target
2240 // of Isolate.spawnUri. Strictly speaking, that can happen also if main
2241 // takes no arguments, but in this case the spawned isolate can't
2242 // communicate with the spawning isolate.
2243 enqueuer.enableIsolateSupport();
2244 }
2245 }
2246
2247 class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
2248 final JavaScriptBackend backend;
2249
2250 JavaScriptResolutionCallbacks(this.backend);
2251
2252 void registerBackendStaticInvocation(Element element, Registry registry) {
2253 registry.registerStaticInvocation(backend.registerBackendUse(element));
2254 }
2255
2256 void registerBackendInstantiation(ClassElement element, Registry registry) {
2257 backend.registerBackendUse(element);
2258 element.ensureResolved(backend.compiler);
2259 registry.registerInstantiation(element.rawType);
2260 }
2261
2262 void onAssert(Send node, Registry registry) {
2263 registerBackendStaticInvocation(backend.assertMethod, registry);
2264 }
2265
2266 void onStringInterpolation(Registry registry) {
2267 assert(registry.isForResolution);
2268 registerBackendStaticInvocation(
2269 backend.getStringInterpolationHelper(), registry);
2270 }
2271
2272 void onCatchStatement(Registry registry) {
2273 assert(registry.isForResolution);
2274 registerBackendStaticInvocation(backend.getExceptionUnwrapper(), registry);
2275 registerBackendInstantiation(
2276 backend.jsPlainJavaScriptObjectClass, registry);
2277 registerBackendInstantiation(
2278 backend.jsUnknownJavaScriptObjectClass, registry);
2279 }
2280
2281 void onThrowExpression(Registry registry) {
2282 assert(registry.isForResolution);
2283 // We don't know ahead of time whether we will need the throw in a
2284 // statement context or an expression context, so we register both
2285 // here, even though we may not need the throwExpression helper.
2286 registerBackendStaticInvocation(backend.getWrapExceptionHelper(), registry);
2287 registerBackendStaticInvocation(
2288 backend.getThrowExpressionHelper(), registry);
2289 }
2290
2291 void onLazyField(Registry registry) {
2292 assert(registry.isForResolution);
2293 registerBackendStaticInvocation(backend.getCyclicThrowHelper(), registry);
2294 }
2295
2296 void onTypeLiteral(DartType type, Registry registry) {
2297 assert(registry.isForResolution);
2298 registerBackendInstantiation(backend.typeImplementation, registry);
2299 registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
2300 // TODO(ahe): Might want to register [element] as an instantiated class
2301 // when reflection is used. However, as long as we disable tree-shaking
2302 // eagerly it doesn't matter.
2303 if (type.isTypedef) {
2304 backend.compiler.world.allTypedefs.add(type.element);
2305 }
2306 backend.customElementsAnalysis.registerTypeLiteral(type, registry);
2307 }
2308
2309 void onStackTraceInCatch(Registry registry) {
2310 assert(registry.isForResolution);
2311 registerBackendStaticInvocation(backend.getTraceFromException(), registry);
2312 }
2313
2314
2315 void onTypeVariableExpression(Registry registry) {
2316 assert(registry.isForResolution);
2317 registerBackendStaticInvocation(backend.getSetRuntimeTypeInfo(), registry);
2318 registerBackendStaticInvocation(backend.getGetRuntimeTypeInfo(), registry);
2319 backend.registerGetRuntimeTypeArgument(registry);
2320 registerBackendInstantiation(backend.compiler.listClass, registry);
2321 registerBackendStaticInvocation(backend.getRuntimeTypeToString(), registry);
2322 registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
2323 }
2324
2325 // TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
2326 void onIsCheck(DartType type, Registry registry) {
2327 assert(registry.isForResolution);
2328 type = type.unalias(backend.compiler);
2329 registerBackendInstantiation(backend.compiler.boolClass, registry);
2330 bool inCheckedMode = backend.compiler.enableTypeAssertions;
2331 if (inCheckedMode) {
2332 registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
2333 }
2334 if (type.isMalformed) {
2335 registerBackendStaticInvocation(backend.getThrowTypeError(), registry);
2336 }
2337 if (!type.treatAsRaw || type.containsTypeVariables) {
2338 // TODO(johnniwinther): Investigate why this is needed.
2339 registerBackendStaticInvocation(
2340 backend.getSetRuntimeTypeInfo(), registry);
2341 registerBackendStaticInvocation(
2342 backend.getGetRuntimeTypeInfo(), registry);
2343 backend.registerGetRuntimeTypeArgument(registry);
2344 if (inCheckedMode) {
2345 registerBackendStaticInvocation(backend.getAssertSubtype(), registry);
2346 }
2347 registerBackendStaticInvocation(backend.getCheckSubtype(), registry);
2348 if (type.isTypeVariable) {
2349 registerBackendStaticInvocation(
2350 backend.getCheckSubtypeOfRuntimeType(), registry);
2351 if (inCheckedMode) {
2352 registerBackendStaticInvocation(
2353 backend.getAssertSubtypeOfRuntimeType(), registry);
2354 }
2355 }
2356 registerBackendInstantiation(backend.compiler.listClass, registry);
2357 }
2358 if (type is FunctionType) {
2359 registerBackendStaticInvocation(
2360 backend.find(backend.jsHelperLibrary, 'functionTypeTestMetaHelper'),
2361 registry);
2362 }
2363 if (type.element != null && type.element.isNative) {
2364 // We will neeed to add the "$is" and "$as" properties on the
2365 // JavaScript object prototype, so we make sure
2366 // [:defineProperty:] is compiled.
2367 registerBackendStaticInvocation(
2368 backend.find(backend.jsHelperLibrary, 'defineProperty'), registry);
2369 }
2370 }
2371
2372 void onTypeVariableBoundCheck(Registry registry) {
2373 assert(registry.isForResolution);
2374 registerBackendStaticInvocation(backend.getThrowTypeError(), registry);
2375 registerBackendStaticInvocation(backend.getAssertIsSubtype(), registry);
2376 }
2377
2378 void onAbstractClassInstantiation(Registry registry) {
2379 assert(registry.isForResolution);
2380 registerBackendStaticInvocation(
2381 backend.getThrowAbstractClassInstantiationError(), registry);
2382 // Also register the types of the arguments passed to this method.
2383 registerBackendInstantiation(backend.compiler.stringClass, registry);
2384 }
2385
2386 void onFallThroughError(Registry registry) {
2387 assert(registry.isForResolution);
2388 registerBackendStaticInvocation(backend.getFallThroughError(), registry);
2389 }
2390
2391 void onAsCheck(DartType type, Registry registry) {
2392 assert(registry.isForResolution);
2393 registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
2394 }
2395
2396 void onThrowNoSuchMethod(Registry registry) {
2397 assert(registry.isForResolution);
2398 registerBackendStaticInvocation(backend.getThrowNoSuchMethod(), registry);
2399 // Also register the types of the arguments passed to this method.
2400 registerBackendInstantiation(backend.compiler.listClass, registry);
2401 registerBackendInstantiation(backend.compiler.stringClass, registry);
2402 }
2403
2404 void onThrowRuntimeError(Registry registry) {
2405 assert(registry.isForResolution);
2406 registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
2407 // Also register the types of the arguments passed to this method.
2408 registerBackendInstantiation(backend.compiler.stringClass, registry);
2409 }
2410
2411 void onSuperNoSuchMethod(Registry registry) {
2412 assert(registry.isForResolution);
2413 registerBackendStaticInvocation(
2414 backend.getCreateInvocationMirror(), registry);
2415 registerBackendStaticInvocation(
2416 backend.compiler.objectClass.lookupLocalMember(Compiler.NO_SUCH_METHOD),
2417 registry);
2418 registerBackendInstantiation(backend.compiler.listClass, registry);
2419 }
2420
2421 void onConstantMap(Registry registry) {
2422 assert(registry.isForResolution);
2423 void enqueue(String name) {
2424 Element e = backend.find(backend.jsHelperLibrary, name);
2425 registerBackendInstantiation(e, registry);
2426 }
2427
2428 enqueue(JavaScriptMapConstant.DART_CLASS);
2429 enqueue(JavaScriptMapConstant.DART_PROTO_CLASS);
2430 enqueue(JavaScriptMapConstant.DART_STRING_CLASS);
2431 enqueue(JavaScriptMapConstant.DART_GENERAL_CLASS);
2432 }
2433
2434 /// Called when resolving the `Symbol` constructor.
2435 void onSymbolConstructor(Registry registry) {
2436 assert(registry.isForResolution);
2437 // Make sure that _internals.Symbol.validated is registered.
2438 assert(backend.compiler.symbolValidatedConstructor != null);
2439 registerBackendStaticInvocation(
2440 backend.compiler.symbolValidatedConstructor, registry);
2441 }
2442 }
2443
2444 /// Records that [constant] is used by the element behind [registry].
2445 class Dependency {
2446 final ConstantValue constant;
2447 final Element annotatedElement;
2448
2449 const Dependency(this.constant, this.annotatedElement);
2450 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698