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

Unified Diff: pkg/compiler/lib/src/js_backend/backend.dart

Issue 693183006: Revert "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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/js/template.dart ('k') | pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/js_backend/backend.dart
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
deleted file mode 100644
index dfd5a92a974849f20cdaecc6a8e44d7428143636..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ /dev/null
@@ -1,2450 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of js_backend;
-
-const VERBOSE_OPTIMIZER_HINTS = false;
-
-class JavaScriptItemCompilationContext extends ItemCompilationContext {
- final Set<HInstruction> boundsChecked = new Set<HInstruction>();
- final Set<HInstruction> allocatedFixedLists = new Set<HInstruction>();
-}
-
-/*
- * Invariants:
- * canInline(function) implies canInline(function, insideLoop:true)
- * !canInline(function, insideLoop: true) implies !canInline(function)
- */
-class FunctionInlineCache {
- final Map<FunctionElement, bool> canBeInlined =
- new Map<FunctionElement, bool>();
-
- final Map<FunctionElement, bool> canBeInlinedInsideLoop =
- new Map<FunctionElement, bool>();
-
- // Returns [:true:]/[:false:] if we have a cached decision.
- // Returns [:null:] otherwise.
- bool canInline(FunctionElement element, {bool insideLoop}) {
- return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element];
- }
-
- void markAsInlinable(FunctionElement element, {bool insideLoop}) {
- if (insideLoop) {
- canBeInlinedInsideLoop[element] = true;
- } else {
- // If we can inline a function outside a loop then we should do it inside
- // a loop as well.
- canBeInlined[element] = true;
- canBeInlinedInsideLoop[element] = true;
- }
- }
-
- void markAsNonInlinable(FunctionElement element, {bool insideLoop}) {
- if (insideLoop == null || insideLoop) {
- // If we can't inline a function inside a loop, then we should not inline
- // it outside a loop either.
- canBeInlined[element] = false;
- canBeInlinedInsideLoop[element] = false;
- } else {
- canBeInlined[element] = false;
- }
- }
-}
-
-class JavaScriptBackend extends Backend {
- static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper');
- static final Uri DART_INTERCEPTORS =
- new Uri(scheme: 'dart', path: '_interceptors');
- static final Uri DART_INTERNAL =
- new Uri(scheme: 'dart', path: '_internal');
- static final Uri DART_FOREIGN_HELPER =
- new Uri(scheme: 'dart', path: '_foreign_helper');
- static final Uri DART_JS_MIRRORS =
- new Uri(scheme: 'dart', path: '_js_mirrors');
- static final Uri DART_JS_NAMES =
- new Uri(scheme: 'dart', path: '_js_names');
- static final Uri DART_ISOLATE_HELPER =
- new Uri(scheme: 'dart', path: '_isolate_helper');
- static final Uri DART_HTML =
- new Uri(scheme: 'dart', path: 'html');
-
- static const String INVOKE_ON = '_getCachedInvocation';
- static const String START_ROOT_ISOLATE = 'startRootIsolate';
-
-
- /// The list of functions for classes in the [internalLibrary] that we want
- /// to inline always. Any function in this list must be inlinable with
- /// respect to the conditions used in [InlineWeeder.canInline], except for
- /// size/complexity heuristics.
- static const Map<String, List<String>> ALWAYS_INLINE =
- const <String, List<String>> {
- 'IterableMixinWorkaround': const <String>['forEach'],
- };
-
- /// List of [FunctionElement]s that we want to inline always. This list is
- /// filled when resolution is complete by looking up in [internalLibrary].
- List<FunctionElement> functionsToAlwaysInline;
-
- /// Reference to the internal library to lookup functions to always inline.
- LibraryElement internalLibrary;
-
-
- /// Set of classes that need to be considered for reflection although not
- /// otherwise visible during resolution.
- Iterable<ClassElement> get classesRequiredForReflection {
- // TODO(herhut): Clean this up when classes needed for rti are tracked.
- return [closureClass, jsIndexableClass];
- }
-
- SsaBuilderTask builder;
- SsaOptimizerTask optimizer;
- SsaCodeGeneratorTask generator;
- CodeEmitterTask emitter;
-
- /**
- * The generated code as a js AST for compiled methods.
- */
- Map<Element, jsAst.Expression> get generatedCode {
- return compiler.enqueuer.codegen.generatedCode;
- }
-
- FunctionInlineCache inlineCache = new FunctionInlineCache();
-
- LibraryElement jsHelperLibrary;
- LibraryElement interceptorsLibrary;
- LibraryElement foreignLibrary;
- LibraryElement isolateHelperLibrary;
-
- ClassElement closureClass;
- ClassElement boundClosureClass;
- Element assertMethod;
- Element invokeOnMethod;
-
- ClassElement jsInterceptorClass;
- ClassElement jsStringClass;
- ClassElement jsArrayClass;
- ClassElement jsNumberClass;
- ClassElement jsIntClass;
- ClassElement jsDoubleClass;
- ClassElement jsNullClass;
- ClassElement jsBoolClass;
- ClassElement jsPlainJavaScriptObjectClass;
- ClassElement jsUnknownJavaScriptObjectClass;
-
- ClassElement jsIndexableClass;
- ClassElement jsMutableIndexableClass;
-
- ClassElement jsMutableArrayClass;
- ClassElement jsFixedArrayClass;
- ClassElement jsExtendableArrayClass;
- ClassElement jsPositiveIntClass;
- ClassElement jsUInt32Class;
- ClassElement jsUInt31Class;
-
- Element jsIndexableLength;
- Element jsArrayTypedConstructor;
- Element jsArrayRemoveLast;
- Element jsArrayAdd;
- Element jsStringSplit;
- Element jsStringToString;
- Element jsStringOperatorAdd;
- Element objectEquals;
-
- ClassElement typeLiteralClass;
- ClassElement mapLiteralClass;
- ClassElement constMapLiteralClass;
- ClassElement typeVariableClass;
- ConstructorElement mapLiteralConstructor;
- ConstructorElement mapLiteralConstructorEmpty;
-
- ClassElement noSideEffectsClass;
- ClassElement noThrowsClass;
- ClassElement noInlineClass;
- ClassElement irRepresentationClass;
-
- Element getInterceptorMethod;
- Element interceptedNames;
-
- ClassElement jsInvocationMirrorClass;
-
- /// If [true], the compiler will emit code that writes the name of the current
- /// method together with its class and library to the console the first time
- /// the method is called.
- static const bool TRACE_CALLS = false;
- Element traceHelper;
-
- /**
- * This element is a top-level variable (in generated output) that the
- * compiler initializes to a datastructure used to map from a Type to the
- * interceptor. See declaration of `mapTypeToInterceptor` in
- * `interceptors.dart`.
- */
- Element mapTypeToInterceptor;
-
- TypeMask get stringType => compiler.typesTask.stringType;
- TypeMask get doubleType => compiler.typesTask.doubleType;
- TypeMask get intType => compiler.typesTask.intType;
- TypeMask get uint32Type => compiler.typesTask.uint32Type;
- TypeMask get uint31Type => compiler.typesTask.uint31Type;
- TypeMask get positiveIntType => compiler.typesTask.positiveIntType;
- TypeMask get numType => compiler.typesTask.numType;
- TypeMask get boolType => compiler.typesTask.boolType;
- TypeMask get dynamicType => compiler.typesTask.dynamicType;
- TypeMask get nullType => compiler.typesTask.nullType;
- TypeMask get emptyType => const TypeMask.nonNullEmpty();
-
- TypeMask _indexablePrimitiveTypeCache;
- TypeMask get indexablePrimitiveType {
- if (_indexablePrimitiveTypeCache == null) {
- _indexablePrimitiveTypeCache =
- new TypeMask.nonNullSubtype(jsIndexableClass, compiler.world);
- }
- return _indexablePrimitiveTypeCache;
- }
-
- TypeMask _readableArrayTypeCache;
- TypeMask get readableArrayType {
- if (_readableArrayTypeCache == null) {
- _readableArrayTypeCache = new TypeMask.nonNullSubclass(jsArrayClass,
- compiler.world);
- }
- return _readableArrayTypeCache;
- }
-
- TypeMask _mutableArrayTypeCache;
- TypeMask get mutableArrayType {
- if (_mutableArrayTypeCache == null) {
- _mutableArrayTypeCache = new TypeMask.nonNullSubclass(jsMutableArrayClass,
- compiler.world);
- }
- return _mutableArrayTypeCache;
- }
-
- TypeMask _fixedArrayTypeCache;
- TypeMask get fixedArrayType {
- if (_fixedArrayTypeCache == null) {
- _fixedArrayTypeCache = new TypeMask.nonNullExact(jsFixedArrayClass,
- compiler.world);
- }
- return _fixedArrayTypeCache;
- }
-
- TypeMask _extendableArrayTypeCache;
- TypeMask get extendableArrayType {
- if (_extendableArrayTypeCache == null) {
- _extendableArrayTypeCache =
- new TypeMask.nonNullExact(jsExtendableArrayClass, compiler.world);
- }
- return _extendableArrayTypeCache;
- }
-
- TypeMask _nonNullTypeCache;
- TypeMask get nonNullType {
- if (_nonNullTypeCache == null) {
- _nonNullTypeCache =
- compiler.typesTask.dynamicType.nonNullable();
- }
- return _nonNullTypeCache;
- }
-
- /// Maps special classes to their implementation (JSXxx) class.
- Map<ClassElement, ClassElement> implementationClasses;
-
- Element getNativeInterceptorMethod;
- bool needToInitializeIsolateAffinityTag = false;
- bool needToInitializeDispatchProperty = false;
-
- /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been
- /// loaded.
- FunctionElement getIsolateAffinityTagMarker;
-
- final Namer namer;
-
- /**
- * Interface used to determine if an object has the JavaScript
- * indexing behavior. The interface is only visible to specific
- * libraries.
- */
- ClassElement jsIndexingBehaviorInterface;
-
- /**
- * A collection of selectors that must have a one shot interceptor
- * generated.
- */
- final Map<String, Selector> oneShotInterceptors;
-
- /**
- * The members of instantiated interceptor classes: maps a member name to the
- * list of members that have that name. This map is used by the codegen to
- * know whether a send must be intercepted or not.
- */
- final Map<String, Set<Element>> interceptedElements;
-
- /**
- * The members of mixin classes that are mixed into an instantiated
- * interceptor class. This is a cached subset of [interceptedElements].
- *
- * Mixin methods are not specialized for the class they are mixed into.
- * Methods mixed into intercepted classes thus always make use of the explicit
- * receiver argument, even when mixed into non-interceptor classes.
- *
- * These members must be invoked with a correct explicit receiver even when
- * the receiver is not an intercepted class.
- */
- final Map<String, Set<Element>> interceptedMixinElements =
- new Map<String, Set<Element>>();
-
- /**
- * A map of specialized versions of the [getInterceptorMethod].
- * Since [getInterceptorMethod] is a hot method at runtime, we're
- * always specializing it based on the incoming type. The keys in
- * the map are the names of these specialized versions. Note that
- * the generic version that contains all possible type checks is
- * also stored in this map.
- */
- final Map<String, Set<ClassElement>> specializedGetInterceptors;
-
- /**
- * Set of classes whose methods are intercepted.
- */
- final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
-
- /**
- * Set of classes used as mixins on intercepted (native and primitive)
- * classes. Methods on these classes might also be mixed in to regular Dart
- * (unintercepted) classes.
- */
- final Set<ClassElement> classesMixedIntoInterceptedClasses =
- new Set<ClassElement>();
-
- /**
- * Set of classes whose `operator ==` methods handle `null` themselves.
- */
- final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>();
-
- List<CompilerTask> get tasks {
- return <CompilerTask>[builder, optimizer, generator, emitter];
- }
-
- final RuntimeTypes rti;
-
- /// Holds the method "disableTreeShaking" in js_mirrors when
- /// dart:mirrors has been loaded.
- FunctionElement disableTreeShakingMarker;
-
- /// Holds the method "preserveNames" in js_mirrors when
- /// dart:mirrors has been loaded.
- FunctionElement preserveNamesMarker;
-
- /// Holds the method "preserveMetadata" in js_mirrors when
- /// dart:mirrors has been loaded.
- FunctionElement preserveMetadataMarker;
-
- /// Holds the method "preserveUris" in js_mirrors when
- /// dart:mirrors has been loaded.
- FunctionElement preserveUrisMarker;
-
- /// Holds the method "preserveLibraryNames" in js_mirrors when
- /// dart:mirrors has been loaded.
- FunctionElement preserveLibraryNamesMarker;
-
- /// Holds the method "requiresPreamble" in _js_helper.
- FunctionElement requiresPreambleMarker;
-
- /// True if a call to preserveMetadataMarker has been seen. This means that
- /// metadata must be retained for dart:mirrors to work correctly.
- bool mustRetainMetadata = false;
-
- /// True if any metadata has been retained. This is slightly different from
- /// [mustRetainMetadata] and tells us if any metadata was retained. For
- /// example, if [mustRetainMetadata] is true but there is no metadata in the
- /// program, this variable will stil be false.
- bool hasRetainedMetadata = false;
-
- /// True if a call to preserveUris has been seen and the preserve-uris flag
- /// is set.
- bool mustPreserveUris = false;
-
- /// True if a call to preserveLibraryNames has been seen.
- bool mustRetainLibraryNames = false;
-
- /// True if a call to preserveNames has been seen.
- bool mustPreserveNames = false;
-
- /// True if a call to disableTreeShaking has been seen.
- bool isTreeShakingDisabled = false;
-
- /// True if there isn't sufficient @MirrorsUsed data.
- bool hasInsufficientMirrorsUsed = false;
-
- /// True if a core-library function requires the preamble file to function.
- bool requiresPreamble = false;
-
- /// True if the html library has been loaded.
- bool htmlLibraryIsLoaded = false;
-
- /// List of constants from metadata. If metadata must be preserved,
- /// these constants must be registered.
- final List<Dependency> metadataConstants = <Dependency>[];
-
- /// List of elements that the user has requested for reflection.
- final Set<Element> targetsUsed = new Set<Element>();
-
- /// List of annotations provided by user that indicate that the annotated
- /// element must be retained.
- final Set<Element> metaTargetsUsed = new Set<Element>();
-
- /// Set of methods that are needed by reflection. Computed using
- /// [computeMembersNeededForReflection] on first use.
- Set<Element> _membersNeededForReflection = null;
- Iterable<Element> get membersNeededForReflection {
- assert(_membersNeededForReflection != null);
- return _membersNeededForReflection;
- }
-
- /// List of symbols that the user has requested for reflection.
- final Set<String> symbolsUsed = new Set<String>();
-
- /// List of elements that the backend may use.
- final Set<Element> helpersUsed = new Set<Element>();
-
- /// All the checked mode helpers.
- static const checkedModeHelpers = CheckedModeHelper.helpers;
-
- // Checked mode helpers indexed by name.
- Map<String, CheckedModeHelper> checkedModeHelperByName =
- new Map<String, CheckedModeHelper>.fromIterable(
- checkedModeHelpers,
- key: (helper) => helper.name);
-
- TypeVariableHandler typeVariableHandler;
-
- /// Number of methods compiled before considering reflection.
- int preMirrorsMethodCount = 0;
-
- /// Resolution and codegen support for generating table of interceptors and
- /// constructors for custom elements.
- CustomElementsAnalysis customElementsAnalysis;
-
- JavaScriptConstantTask constantCompilerTask;
-
- JavaScriptResolutionCallbacks resolutionCallbacks;
-
- JavaScriptBackend(Compiler compiler, bool generateSourceMap)
- : namer = determineNamer(compiler),
- oneShotInterceptors = new Map<String, Selector>(),
- interceptedElements = new Map<String, Set<Element>>(),
- rti = new RuntimeTypes(compiler),
- specializedGetInterceptors = new Map<String, Set<ClassElement>>(),
- super(compiler) {
- emitter = new CodeEmitterTask(compiler, namer, generateSourceMap);
- builder = new SsaBuilderTask(this);
- optimizer = new SsaOptimizerTask(this);
- generator = new SsaCodeGeneratorTask(this);
- typeVariableHandler = new TypeVariableHandler(this);
- customElementsAnalysis = new CustomElementsAnalysis(this);
- constantCompilerTask = new JavaScriptConstantTask(compiler);
- resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
- }
-
- ConstantSystem get constantSystem => constants.constantSystem;
-
- /// Returns constant environment for the JavaScript interpretation of the
- /// constants.
- JavaScriptConstantCompiler get constants {
- return constantCompilerTask.jsConstantCompiler;
- }
-
- // TODO(karlklose): Split into findHelperFunction and findHelperClass and
- // add a check that the element has the expected kind.
- Element findHelper(String name) => find(jsHelperLibrary, name);
- Element findInterceptor(String name) => find(interceptorsLibrary, name);
-
- Element find(LibraryElement library, String name) {
- Element element = library.findLocal(name);
- assert(invariant(library, element != null,
- message: "Element '$name' not found in '${library.canonicalUri}'."));
- return element;
- }
-
- bool isForeign(Element element) => element.library == foreignLibrary;
-
- bool isBackendLibrary(LibraryElement library) {
- return library == interceptorsLibrary ||
- library == jsHelperLibrary;
- }
-
- static Namer determineNamer(Compiler compiler) {
- return compiler.enableMinification ?
- new MinifyNamer(compiler) :
- new Namer(compiler);
- }
-
- bool usedByBackend(Element element) {
- if (element.isParameter
- || element.isInitializingFormal
- || element.isField) {
- if (usedByBackend(element.enclosingElement)) return true;
- }
- return helpersUsed.contains(element.declaration);
- }
-
- bool invokedReflectively(Element element) {
- if (element.isParameter || element.isInitializingFormal) {
- ParameterElement parameter = element;
- if (invokedReflectively(parameter.functionDeclaration)) return true;
- }
-
- if (element.isField) {
- if (Elements.isStaticOrTopLevel(element)
- && (element.isFinal || element.isConst)) {
- return false;
- }
- }
-
- return isAccessibleByReflection(element.declaration);
- }
-
- bool canBeUsedForGlobalOptimizations(Element element) {
- return !usedByBackend(element) && !invokedReflectively(element);
- }
-
- bool isInterceptorClass(ClassElement element) {
- if (element == null) return false;
- if (Elements.isNativeOrExtendsNative(element)) return true;
- if (interceptedClasses.contains(element)) return true;
- if (classesMixedIntoInterceptedClasses.contains(element)) return true;
- return false;
- }
-
- String registerOneShotInterceptor(Selector selector) {
- Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
- String name = namer.getOneShotInterceptorName(selector, classes);
- if (!oneShotInterceptors.containsKey(name)) {
- registerSpecializedGetInterceptor(classes);
- oneShotInterceptors[name] = selector;
- }
- return name;
- }
-
- bool isInterceptedMethod(Element element) {
- if (!element.isInstanceMember) return false;
- if (element.isGenerativeConstructorBody) {
- return Elements.isNativeOrExtendsNative(element.enclosingClass);
- }
- return interceptedElements[element.name] != null;
- }
-
- bool fieldHasInterceptedGetter(Element element) {
- assert(element.isField);
- return interceptedElements[element.name] != null;
- }
-
- bool fieldHasInterceptedSetter(Element element) {
- assert(element.isField);
- return interceptedElements[element.name] != null;
- }
-
- bool isInterceptedName(String name) {
- return interceptedElements[name] != null;
- }
-
- bool isInterceptedSelector(Selector selector) {
- return interceptedElements[selector.name] != null;
- }
-
- /**
- * Returns `true` iff [selector] matches an element defined in a class mixed
- * into an intercepted class. These selectors are not eligible for the 'dummy
- * explicit receiver' optimization.
- */
- bool isInterceptedMixinSelector(Selector selector) {
- Set<Element> elements = interceptedMixinElements.putIfAbsent(
- selector.name,
- () {
- Set<Element> elements = interceptedElements[selector.name];
- if (elements == null) return null;
- return elements
- .where((element) =>
- classesMixedIntoInterceptedClasses.contains(
- element.enclosingClass))
- .toSet();
- });
-
- if (elements == null) return false;
- if (elements.isEmpty) return false;
- return elements.any((element) => selector.applies(element, compiler.world));
- }
-
- final Map<String, Set<ClassElement>> interceptedClassesCache =
- new Map<String, Set<ClassElement>>();
-
- /**
- * Returns a set of interceptor classes that contain a member named
- * [name]. Returns [:null:] if there is no class.
- */
- Set<ClassElement> getInterceptedClassesOn(String name) {
- Set<Element> intercepted = interceptedElements[name];
- if (intercepted == null) return null;
- return interceptedClassesCache.putIfAbsent(name, () {
- // Populate the cache by running through all the elements and
- // determine if the given selector applies to them.
- Set<ClassElement> result = new Set<ClassElement>();
- for (Element element in intercepted) {
- ClassElement classElement = element.enclosingClass;
- if (Elements.isNativeOrExtendsNative(classElement)
- || interceptedClasses.contains(classElement)) {
- result.add(classElement);
- }
- if (classesMixedIntoInterceptedClasses.contains(classElement)) {
- Set<ClassElement> nativeSubclasses =
- nativeSubclassesOfMixin(classElement);
- if (nativeSubclasses != null) result.addAll(nativeSubclasses);
- }
- }
- return result;
- });
- }
-
- Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
- ClassWorld classWorld = compiler.world;
- Iterable<MixinApplicationElement> uses = classWorld.mixinUsesOf(mixin);
- Set<ClassElement> result = null;
- for (MixinApplicationElement use in uses) {
- Iterable<ClassElement> subclasses = classWorld.subclassesOf(use);
- for (ClassElement subclass in subclasses) {
- if (Elements.isNativeOrExtendsNative(subclass)) {
- if (result == null) result = new Set<ClassElement>();
- result.add(subclass);
- }
- }
- }
- return result;
- }
-
- bool operatorEqHandlesNullArgument(FunctionElement operatorEqfunction) {
- return specialOperatorEqClasses.contains(
- operatorEqfunction.enclosingClass);
- }
-
- void validateInterceptorImplementsAllObjectMethods(
- ClassElement interceptorClass) {
- if (interceptorClass == null) return;
- interceptorClass.ensureResolved(compiler);
- compiler.objectClass.forEachMember((_, Element member) {
- if (member.isGenerativeConstructor) return;
- Element interceptorMember = interceptorClass.lookupMember(member.name);
- // Interceptors must override all Object methods due to calling convention
- // differences.
- assert(interceptorMember.enclosingClass == interceptorClass);
- });
- }
-
- void addInterceptorsForNativeClassMembers(
- ClassElement cls, Enqueuer enqueuer) {
- if (enqueuer.isResolutionQueue) {
- cls.ensureResolved(compiler);
- cls.forEachMember((ClassElement classElement, Element member) {
- if (member.name == Compiler.CALL_OPERATOR_NAME) {
- compiler.reportError(
- member,
- MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS);
- return;
- }
- if (member.isSynthesized) return;
- // All methods on [Object] are shadowed by [Interceptor].
- if (classElement == compiler.objectClass) return;
- Set<Element> set = interceptedElements.putIfAbsent(
- member.name, () => new Set<Element>());
- set.add(member);
- },
- includeSuperAndInjectedMembers: true);
-
- // Walk superclass chain to find mixins.
- for (; cls != null; cls = cls.superclass) {
- if (cls.isMixinApplication) {
- MixinApplicationElement mixinApplication = cls;
- classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
- }
- }
- }
- }
-
- void addInterceptors(ClassElement cls,
- Enqueuer enqueuer,
- Registry registry) {
- if (enqueuer.isResolutionQueue) {
- _interceptedClasses.add(jsInterceptorClass);
- _interceptedClasses.add(cls);
- cls.ensureResolved(compiler);
- cls.forEachMember((ClassElement classElement, Element member) {
- // All methods on [Object] are shadowed by [Interceptor].
- if (classElement == compiler.objectClass) return;
- Set<Element> set = interceptedElements.putIfAbsent(
- member.name, () => new Set<Element>());
- set.add(member);
- },
- includeSuperAndInjectedMembers: true);
- }
- enqueueClass(enqueuer, cls, registry);
- }
-
- Set<ClassElement> get interceptedClasses {
- assert(compiler.enqueuer.resolution.queueIsClosed);
- return _interceptedClasses;
- }
-
- void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
- String name = namer.getInterceptorName(getInterceptorMethod, classes);
- if (classes.contains(jsInterceptorClass)) {
- // We can't use a specialized [getInterceptorMethod], so we make
- // sure we emit the one with all checks.
- specializedGetInterceptors[name] = interceptedClasses;
- } else {
- specializedGetInterceptors[name] = classes;
- }
- }
-
- void registerCompileTimeConstant(ConstantValue constant, Registry registry) {
- registerCompileTimeConstantInternal(constant, registry);
- for (ConstantValue dependency in constant.getDependencies()) {
- registerCompileTimeConstant(dependency, registry);
- }
- }
-
- void registerCompileTimeConstantInternal(ConstantValue constant,
- Registry registry) {
- DartType type = constant.computeType(compiler);
- registerInstantiatedConstantType(type, registry);
-
- if (constant.isFunction) {
- FunctionConstantValue function = constant;
- registry.registerGetOfStaticFunction(function.element);
- } else if (constant.isInterceptor) {
- // An interceptor constant references the class's prototype chain.
- InterceptorConstantValue interceptor = constant;
- registerInstantiatedConstantType(interceptor.dispatchedType, registry);
- } else if (constant.isType) {
- enqueueInResolution(getCreateRuntimeType(), registry);
- registry.registerInstantiation(typeImplementation.rawType);
- }
- }
-
- void registerInstantiatedConstantType(DartType type, Registry registry) {
- DartType instantiatedType =
- type.isFunctionType ? compiler.functionClass.rawType : type;
- if (type is InterfaceType) {
- registry.registerInstantiation(instantiatedType);
- if (!type.treatAsRaw && classNeedsRti(type.element)) {
- registry.registerStaticInvocation(getSetRuntimeTypeInfo());
- }
- if (type.element == typeImplementation) {
- // If we use a type literal in a constant, the compile time
- // constant emitter will generate a call to the createRuntimeType
- // helper so we register a use of that.
- registry.registerStaticInvocation(getCreateRuntimeType());
- }
- }
- }
-
- void registerMetadataConstant(MetadataAnnotation metadata,
- Element annotatedElement,
- Registry registry) {
- assert(registry.isForResolution);
- ConstantValue constant = constants.getConstantForMetadata(metadata).value;
- registerCompileTimeConstant(constant, registry);
- metadataConstants.add(new Dependency(constant, annotatedElement));
- }
-
- void registerInstantiatedClass(ClassElement cls,
- Enqueuer enqueuer,
- Registry registry) {
- if (!cls.typeVariables.isEmpty) {
- typeVariableHandler.registerClassWithTypeVariables(cls);
- }
-
- // Register any helper that will be needed by the backend.
- if (enqueuer.isResolutionQueue) {
- if (cls == compiler.intClass
- || cls == compiler.doubleClass
- || cls == compiler.numClass) {
- // The backend will try to optimize number operations and use the
- // `iae` helper directly.
- enqueue(enqueuer, findHelper('iae'), registry);
- } else if (cls == compiler.listClass
- || cls == compiler.stringClass) {
- // The backend will try to optimize array and string access and use the
- // `ioore` and `iae` helpers directly.
- enqueue(enqueuer, findHelper('ioore'), registry);
- enqueue(enqueuer, findHelper('iae'), registry);
- } else if (cls == compiler.functionClass) {
- enqueueClass(enqueuer, closureClass, registry);
- } else if (cls == compiler.mapClass) {
- // The backend will use a literal list to initialize the entries
- // of the map.
- enqueueClass(enqueuer, compiler.listClass, registry);
- enqueueClass(enqueuer, mapLiteralClass, registry);
- // For map literals, the dependency between the implementation class
- // and [Map] is not visible, so we have to add it manually.
- rti.registerRtiDependency(mapLiteralClass, cls);
- } else if (cls == boundClosureClass) {
- // TODO(johnniwinther): Is this a noop?
- enqueueClass(enqueuer, boundClosureClass, registry);
- } else if (Elements.isNativeOrExtendsNative(cls)) {
- enqueue(enqueuer, getNativeInterceptorMethod, registry);
- enqueueClass(enqueuer, jsInterceptorClass, compiler.globalDependencies);
- enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry);
- } else if (cls == mapLiteralClass) {
- // For map literals, the dependency between the implementation class
- // and [Map] is not visible, so we have to add it manually.
- Element getFactory(String name, int arity) {
- // The constructor is on the patch class, but dart2js unit tests don't
- // have a patch class.
- ClassElement implementation = cls.patch != null ? cls.patch : cls;
- return implementation.lookupConstructor(
- new Selector.callConstructor(
- name, mapLiteralClass.library, arity),
- (element) {
- compiler.internalError(mapLiteralClass,
- "Map literal class $mapLiteralClass missing "
- "'$name' constructor"
- " ${mapLiteralClass.constructors}");
- });
- }
- mapLiteralConstructor = getFactory('_literal', 1);
- mapLiteralConstructorEmpty = getFactory('_empty', 0);
- enqueueInResolution(mapLiteralConstructor, registry);
- enqueueInResolution(mapLiteralConstructorEmpty, registry);
- }
- }
- if (cls == closureClass) {
- enqueue(enqueuer, findHelper('closureFromTearOff'), registry);
- }
- ClassElement result = null;
- if (cls == compiler.stringClass || cls == jsStringClass) {
- addInterceptors(jsStringClass, enqueuer, registry);
- } else if (cls == compiler.listClass ||
- cls == jsArrayClass ||
- cls == jsFixedArrayClass ||
- cls == jsExtendableArrayClass) {
- addInterceptors(jsArrayClass, enqueuer, registry);
- addInterceptors(jsMutableArrayClass, enqueuer, registry);
- addInterceptors(jsFixedArrayClass, enqueuer, registry);
- addInterceptors(jsExtendableArrayClass, enqueuer, registry);
- } else if (cls == compiler.intClass || cls == jsIntClass) {
- addInterceptors(jsIntClass, enqueuer, registry);
- addInterceptors(jsPositiveIntClass, enqueuer, registry);
- addInterceptors(jsUInt32Class, enqueuer, registry);
- addInterceptors(jsUInt31Class, enqueuer, registry);
- addInterceptors(jsNumberClass, enqueuer, registry);
- } else if (cls == compiler.doubleClass || cls == jsDoubleClass) {
- addInterceptors(jsDoubleClass, enqueuer, registry);
- addInterceptors(jsNumberClass, enqueuer, registry);
- } else if (cls == compiler.boolClass || cls == jsBoolClass) {
- addInterceptors(jsBoolClass, enqueuer, registry);
- } else if (cls == compiler.nullClass || cls == jsNullClass) {
- addInterceptors(jsNullClass, enqueuer, registry);
- } else if (cls == compiler.numClass || cls == jsNumberClass) {
- addInterceptors(jsIntClass, enqueuer, registry);
- addInterceptors(jsPositiveIntClass, enqueuer, registry);
- addInterceptors(jsUInt32Class, enqueuer, registry);
- addInterceptors(jsUInt31Class, enqueuer, registry);
- addInterceptors(jsDoubleClass, enqueuer, registry);
- addInterceptors(jsNumberClass, enqueuer, registry);
- } else if (cls == jsPlainJavaScriptObjectClass) {
- addInterceptors(jsPlainJavaScriptObjectClass, enqueuer, registry);
- } else if (cls == jsUnknownJavaScriptObjectClass) {
- addInterceptors(jsUnknownJavaScriptObjectClass, enqueuer, registry);
- } else if (Elements.isNativeOrExtendsNative(cls)) {
- addInterceptorsForNativeClassMembers(cls, enqueuer);
- } else if (cls == jsIndexingBehaviorInterface) {
- // These two helpers are used by the emitter and the codegen.
- // Because we cannot enqueue elements at the time of emission,
- // we make sure they are always generated.
- enqueue(enqueuer, findHelper('isJsIndexable'), registry);
- }
-
- customElementsAnalysis.registerInstantiatedClass(cls, enqueuer);
- }
-
- void registerUseInterceptor(Enqueuer enqueuer) {
- assert(!enqueuer.isResolutionQueue);
- if (!enqueuer.nativeEnqueuer.hasInstantiatedNativeClasses()) return;
- Registry registry = compiler.globalDependencies;
- enqueue(enqueuer, getNativeInterceptorMethod, registry);
- enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry);
- needToInitializeIsolateAffinityTag = true;
- needToInitializeDispatchProperty = true;
- }
-
- JavaScriptItemCompilationContext createItemCompilationContext() {
- return new JavaScriptItemCompilationContext();
- }
-
- void enqueueHelpers(ResolutionEnqueuer world, Registry registry) {
- assert(interceptorsLibrary != null);
- // TODO(ngeoffray): Not enqueuing those two classes currently make
- // the compiler potentially crash. However, any reasonable program
- // will instantiate those two classes.
- addInterceptors(jsBoolClass, world, registry);
- addInterceptors(jsNullClass, world, registry);
- if (compiler.enableTypeAssertions) {
- // Unconditionally register the helper that checks if the
- // expression in an if/while/for is a boolean.
- // TODO(ngeoffray): Should we have the resolver register those instead?
- Element e = findHelper('boolConversionCheck');
- if (e != null) enqueue(world, e, registry);
- }
- if (TRACE_CALLS) {
- traceHelper = findHelper('traceHelper');
- assert(traceHelper != null);
- enqueueInResolution(traceHelper, registry);
- }
- registerCheckedModeHelpers(registry);
- }
-
- onResolutionComplete() {
- super.onResolutionComplete();
- computeMembersNeededForReflection();
- rti.computeClassesNeedingRti();
- computeFunctionsToAlwaysInline();
- }
-
- void computeFunctionsToAlwaysInline() {
- functionsToAlwaysInline = <FunctionElement>[];
- if (internalLibrary == null) return;
-
- // Try to find all functions intended to always inline. If their enclosing
- // class is not resolved we skip the methods, but it is an error to mention
- // a function or class that cannot be found.
- for (String className in ALWAYS_INLINE.keys) {
- ClassElement cls = find(internalLibrary, className);
- if (cls.resolutionState != STATE_DONE) continue;
- for (String functionName in ALWAYS_INLINE[className]) {
- Element function = cls.lookupMember(functionName);
- assert(invariant(cls, function is FunctionElement,
- message: 'unable to find function $functionName in $className'));
- functionsToAlwaysInline.add(function);
- }
- }
- }
-
- void registerGetRuntimeTypeArgument(Registry registry) {
- enqueueInResolution(getGetRuntimeTypeArgument(), registry);
- enqueueInResolution(getGetTypeArgumentByIndex(), registry);
- enqueueInResolution(getCopyTypeArguments(), registry);
- }
-
- void registerCallMethodWithFreeTypeVariables(
- Element callMethod,
- Enqueuer enqueuer,
- Registry registry) {
- if (enqueuer.isResolutionQueue || methodNeedsRti(callMethod)) {
- registerComputeSignature(enqueuer, registry);
- }
- }
-
- void registerClosureWithFreeTypeVariables(
- Element closure,
- Enqueuer enqueuer,
- Registry registry) {
- if (enqueuer.isResolutionQueue || methodNeedsRti(closure)) {
- registerComputeSignature(enqueuer, registry);
- }
- }
-
- void registerBoundClosure(Enqueuer enqueuer) {
- enqueuer.registerInstantiatedClass(
- boundClosureClass,
- // Precise dependency is not important here.
- compiler.globalDependencies);
- }
-
- void registerGetOfStaticFunction(Enqueuer enqueuer) {
- enqueuer.registerInstantiatedClass(closureClass,
- compiler.globalDependencies);
- }
-
- void registerComputeSignature(Enqueuer enqueuer, Registry registry) {
- // Calls to [:computeSignature:] are generated by the emitter and we
- // therefore need to enqueue the used elements in the codegen enqueuer as
- // well as in the resolution enqueuer.
- enqueue(enqueuer, getSetRuntimeTypeInfo(), registry);
- enqueue(enqueuer, getGetRuntimeTypeInfo(), registry);
- enqueue(enqueuer, getComputeSignature(), registry);
- enqueue(enqueuer, getGetRuntimeTypeArguments(), registry);
- enqueueClass(enqueuer, compiler.listClass, registry);
- }
-
- void registerRuntimeType(Enqueuer enqueuer, Registry registry) {
- registerComputeSignature(enqueuer, registry);
- enqueueInResolution(getSetRuntimeTypeInfo(), registry);
- enqueueInResolution(getGetRuntimeTypeInfo(), registry);
- registerGetRuntimeTypeArgument(registry);
- enqueueClass(enqueuer, compiler.listClass, registry);
- }
-
- void registerIsCheckForCodegen(DartType type,
- Enqueuer world,
- Registry registry) {
- assert(!registry.isForResolution);
- type = type.unalias(compiler);
- enqueueClass(world, compiler.boolClass, registry);
- bool inCheckedMode = compiler.enableTypeAssertions;
- // [registerIsCheck] is also called for checked mode checks, so we
- // need to register checked mode helpers.
- if (inCheckedMode) {
- // All helpers are added to resolution queue in enqueueHelpers. These
- // calls to enqueueInResolution serve as assertions that the helper was
- // in fact added.
- // TODO(13155): Find a way to enqueue helpers lazily.
- CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: false);
- if (helper != null) {
- enqueue(world, helper.getElement(compiler), registry);
- }
- // We also need the native variant of the check (for DOM types).
- helper = getNativeCheckedModeHelper(type, typeCast: false);
- if (helper != null) {
- enqueue(world, helper.getElement(compiler), registry);
- }
- }
- if (!type.treatAsRaw || type.containsTypeVariables) {
- enqueueClass(world, compiler.listClass, registry);
- }
- if (type.element != null && type.element.isNative) {
- // We will neeed to add the "$is" and "$as" properties on the
- // JavaScript object prototype, so we make sure
- // [:defineProperty:] is compiled.
- enqueue(world, findHelper('defineProperty'), registry);
- }
- }
-
- void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
- DartType bound) {
- rti.registerTypeVariableBoundsSubtypeCheck(typeArgument, bound);
- }
-
- void registerCheckDeferredIsLoaded(Registry registry) {
- enqueueInResolution(getCheckDeferredIsLoaded(), registry);
- // Also register the types of the arguments passed to this method.
- enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, registry);
- }
-
- void enableNoSuchMethod(Element context, Enqueuer world) {
- enqueue(world, getCreateInvocationMirror(), compiler.globalDependencies);
- world.registerInvocation(compiler.noSuchMethodSelector);
- // TODO(tyoverby): Send the context element to DumpInfoTask to be
- // blamed.
- }
-
- void enableIsolateSupport(Enqueuer enqueuer) {
- // TODO(floitsch): We should also ensure that the class IsolateMessage is
- // instantiated. Currently, just enabling isolate support works.
- if (compiler.mainFunction != null) {
- // The JavaScript backend implements [Isolate.spawn] by looking up
- // top-level functions by name. So all top-level function tear-off
- // closures have a private name field.
- //
- // The JavaScript backend of [Isolate.spawnUri] uses the same internal
- // implementation as [Isolate.spawn], and fails if it cannot look main up
- // by name.
- enqueuer.registerGetOfStaticFunction(compiler.mainFunction);
- }
- if (enqueuer.isResolutionQueue) {
- for (String name in const [START_ROOT_ISOLATE,
- '_currentIsolate',
- '_callInIsolate']) {
- Element element = find(isolateHelperLibrary, name);
- enqueuer.addToWorkList(element);
- compiler.globalDependencies.registerDependency(element);
- }
- } else {
- enqueuer.addToWorkList(find(isolateHelperLibrary, START_ROOT_ISOLATE));
- }
- }
-
- bool isAssertMethod(Element element) => element == assertMethod;
-
- void registerRequiredType(DartType type, Element enclosingElement) {
- // If [argument] has type variables or is a type variable, this method
- // registers a RTI dependency between the class where the type variable is
- // defined (that is the enclosing class of the current element being
- // resolved) and the class of [type]. If the class of [type] requires RTI,
- // then the class of the type variable does too.
- ClassElement contextClass = Types.getClassContext(type);
- if (contextClass != null) {
- assert(contextClass == enclosingElement.enclosingClass.declaration);
- rti.registerRtiDependency(type.element, contextClass);
- }
- }
-
- void registerClassUsingVariableExpression(ClassElement cls) {
- rti.classesUsingTypeVariableExpression.add(cls);
- }
-
- bool classNeedsRti(ClassElement cls) {
- return rti.classesNeedingRti.contains(cls.declaration) ||
- compiler.enabledRuntimeType;
- }
-
- bool isDefaultNoSuchMethodImplementation(Element element) {
- assert(element.name == Compiler.NO_SUCH_METHOD);
- ClassElement classElement = element.enclosingClass;
- return classElement == compiler.objectClass
- || classElement == jsInterceptorClass
- || classElement == jsNullClass;
- }
-
- bool isDefaultEqualityImplementation(Element element) {
- assert(element.name == '==');
- ClassElement classElement = element.enclosingClass;
- return classElement == compiler.objectClass
- || classElement == jsInterceptorClass
- || classElement == jsNullClass;
- }
-
- bool methodNeedsRti(FunctionElement function) {
- return rti.methodsNeedingRti.contains(function) ||
- compiler.enabledRuntimeType;
- }
-
- /// The backend must *always* call this method when enqueuing an
- /// element. Calls done by the backend are not seen by global
- /// optimizations, so they would make these optimizations unsound.
- /// Therefore we need to collect the list of helpers the backend may
- /// use.
- Element registerBackendUse(Element element) {
- if (element != null) {
- helpersUsed.add(element.declaration);
- if (element.isClass && element.isPatched) {
- // Both declaration and implementation may declare fields, so we
- // add both to the list of helpers.
- helpersUsed.add(element.implementation);
- }
- }
- return element;
- }
-
- /// Enqueue [e] in [enqueuer].
- ///
- /// This method calls [registerBackendUse].
- void enqueue(Enqueuer enqueuer, Element e, Registry registry) {
- if (e == null) return;
- registerBackendUse(e);
- enqueuer.addToWorkList(e);
- registry.registerDependency(e);
- }
-
- /// Enqueue [e] in the resolution enqueuer.
- ///
- /// This method calls [registerBackendUse].
- void enqueueInResolution(Element e, Registry registry) {
- if (e == null) return;
- ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
- enqueue(enqueuer, e, registry);
- }
-
- /// Register instantiation of [cls] in [enqueuer].
- ///
- /// This method calls [registerBackendUse].
- void enqueueClass(Enqueuer enqueuer, Element cls, Registry registry) {
- if (cls == null) return;
- registerBackendUse(cls);
- helpersUsed.add(cls.declaration);
- if (cls.declaration != cls.implementation) {
- helpersUsed.add(cls.implementation);
- }
- enqueuer.registerInstantiatedClass(cls, registry);
- }
-
- void codegen(CodegenWorkItem work) {
- Element element = work.element;
- var kind = element.kind;
- if (kind == ElementKind.TYPEDEF) return;
- if (element.isConstructor && element.enclosingClass == jsNullClass) {
- // Work around a problem compiling JSNull's constructor.
- return;
- }
- if (kind.category == ElementCategory.VARIABLE) {
- ConstantExpression initialValue = constants.getConstantForVariable(element);
- if (initialValue != null) {
- registerCompileTimeConstant(initialValue.value, work.registry);
- constants.addCompileTimeConstantForEmission(initialValue.value);
- // We don't need to generate code for static or top-level
- // variables. For instance variables, we may need to generate
- // the checked setter.
- if (Elements.isStaticOrTopLevel(element)) return;
- } else {
- // If the constant-handler was not able to produce a result we have to
- // go through the builder (below) to generate the lazy initializer for
- // the static variable.
- // We also need to register the use of the cyclic-error helper.
- compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper());
- }
- }
- HGraph graph = builder.build(work);
- optimizer.optimize(work, graph);
- jsAst.Expression code = generator.generateCode(work, graph);
- generatedCode[element] = code;
- }
-
- native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
- return new native.NativeResolutionEnqueuer(world, compiler);
- }
-
- native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) {
- return new native.NativeCodegenEnqueuer(world, compiler, emitter);
- }
-
- ClassElement defaultSuperclass(ClassElement element) {
- // Native classes inherit from Interceptor.
- return element.isNative ? jsInterceptorClass : compiler.objectClass;
- }
-
- /**
- * Unit test hook that returns code of an element as a String.
- *
- * Invariant: [element] must be a declaration element.
- */
- String assembleCode(Element element) {
- assert(invariant(element, element.isDeclaration));
- return jsAst.prettyPrint(generatedCode[element], compiler).getText();
- }
-
- void assembleProgram() {
- emitter.assembleProgram();
- int totalMethodCount = generatedCode.length;
- if (totalMethodCount != preMirrorsMethodCount) {
- int mirrorCount = totalMethodCount - preMirrorsMethodCount;
- double percentage = (mirrorCount / totalMethodCount) * 100;
- compiler.reportHint(
- compiler.mainApp, MessageKind.MIRROR_BLOAT,
- {'count': mirrorCount,
- 'total': totalMethodCount,
- 'percentage': percentage.round()});
- for (LibraryElement library in compiler.libraryLoader.libraries) {
- if (library.isInternalLibrary) continue;
- for (LibraryTag tag in library.tags) {
- Import importTag = tag.asImport();
- if (importTag == null) continue;
- LibraryElement importedLibrary = library.getLibraryFromTag(tag);
- if (importedLibrary != compiler.mirrorsLibrary) continue;
- MessageKind kind =
- compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
- ? MessageKind.MIRROR_IMPORT
- : MessageKind.MIRROR_IMPORT_NO_USAGE;
- compiler.withCurrentElement(library, () {
- compiler.reportInfo(importTag, kind);
- });
- }
- }
- }
- }
-
- Element getDartClass(Element element) {
- for (ClassElement dartClass in implementationClasses.keys) {
- if (element == implementationClasses[dartClass]) {
- return dartClass;
- }
- }
- return element;
- }
-
- /**
- * Returns the checked mode helper that will be needed to do a type check/type
- * cast on [type] at runtime. Note that this method is being called both by
- * the resolver with interface types (int, String, ...), and by the SSA
- * backend with implementation types (JSInt, JSString, ...).
- */
- CheckedModeHelper getCheckedModeHelper(DartType type, {bool typeCast}) {
- return getCheckedModeHelperInternal(
- type, typeCast: typeCast, nativeCheckOnly: false);
- }
-
- /**
- * Returns the native checked mode helper that will be needed to do a type
- * check/type cast on [type] at runtime. If no native helper exists for
- * [type], [:null:] is returned.
- */
- CheckedModeHelper getNativeCheckedModeHelper(DartType type, {bool typeCast}) {
- return getCheckedModeHelperInternal(
- type, typeCast: typeCast, nativeCheckOnly: true);
- }
-
- /**
- * Returns the checked mode helper for the type check/type cast for [type]. If
- * [nativeCheckOnly] is [:true:], only names for native helpers are returned.
- */
- CheckedModeHelper getCheckedModeHelperInternal(DartType type,
- {bool typeCast,
- bool nativeCheckOnly}) {
- String name = getCheckedModeHelperNameInternal(type,
- typeCast: typeCast, nativeCheckOnly: nativeCheckOnly);
- if (name == null) return null;
- CheckedModeHelper helper = checkedModeHelperByName[name];
- assert(helper != null);
- return helper;
- }
-
- String getCheckedModeHelperNameInternal(DartType type,
- {bool typeCast,
- bool nativeCheckOnly}) {
- assert(type.kind != TypeKind.TYPEDEF);
- if (type.isMalformed) {
- // The same error is thrown for type test and type cast of a malformed
- // type so we only need one check method.
- return 'checkMalformedType';
- }
- Element element = type.element;
- bool nativeCheck = nativeCheckOnly ||
- emitter.nativeEmitter.requiresNativeIsCheck(element);
-
- // TODO(13955), TODO(9731). The test for non-primitive types should use an
- // interceptor. The interceptor should be an argument to HTypeConversion so
- // that it can be optimized by standard interceptor optimizations.
- nativeCheck = true;
-
- if (type.isVoid) {
- assert(!typeCast); // Cannot cast to void.
- if (nativeCheckOnly) return null;
- return 'voidTypeCheck';
- } else if (element == jsStringClass || element == compiler.stringClass) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'stringTypeCast'
- : 'stringTypeCheck';
- } else if (element == jsDoubleClass || element == compiler.doubleClass) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'doubleTypeCast'
- : 'doubleTypeCheck';
- } else if (element == jsNumberClass || element == compiler.numClass) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'numTypeCast'
- : 'numTypeCheck';
- } else if (element == jsBoolClass || element == compiler.boolClass) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'boolTypeCast'
- : 'boolTypeCheck';
- } else if (element == jsIntClass || element == compiler.intClass
- || element == jsUInt32Class || element == jsUInt31Class
- || element == jsPositiveIntClass) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'intTypeCast'
- : 'intTypeCheck';
- } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
- if (nativeCheck) {
- return typeCast
- ? 'numberOrStringSuperNativeTypeCast'
- : 'numberOrStringSuperNativeTypeCheck';
- } else {
- return typeCast
- ? 'numberOrStringSuperTypeCast'
- : 'numberOrStringSuperTypeCheck';
- }
- } else if (Elements.isStringOnlySupertype(element, compiler)) {
- if (nativeCheck) {
- return typeCast
- ? 'stringSuperNativeTypeCast'
- : 'stringSuperNativeTypeCheck';
- } else {
- return typeCast
- ? 'stringSuperTypeCast'
- : 'stringSuperTypeCheck';
- }
- } else if ((element == compiler.listClass || element == jsArrayClass) &&
- type.treatAsRaw) {
- if (nativeCheckOnly) return null;
- return typeCast
- ? 'listTypeCast'
- : 'listTypeCheck';
- } else {
- if (Elements.isListSupertype(element, compiler)) {
- if (nativeCheck) {
- return typeCast
- ? 'listSuperNativeTypeCast'
- : 'listSuperNativeTypeCheck';
- } else {
- return typeCast
- ? 'listSuperTypeCast'
- : 'listSuperTypeCheck';
- }
- } else {
- if (type.isInterfaceType && !type.treatAsRaw) {
- return typeCast
- ? 'subtypeCast'
- : 'assertSubtype';
- } else if (type.isTypeVariable) {
- return typeCast
- ? 'subtypeOfRuntimeTypeCast'
- : 'assertSubtypeOfRuntimeType';
- } else if (type.isFunctionType) {
- return null;
- } else {
- if (nativeCheck) {
- // TODO(karlklose): can we get rid of this branch when we use
- // interceptors?
- return typeCast
- ? 'interceptedTypeCast'
- : 'interceptedTypeCheck';
- } else {
- return typeCast
- ? 'propertyTypeCast'
- : 'propertyTypeCheck';
- }
- }
- }
- }
- }
-
- void registerCheckedModeHelpers(Registry registry) {
- // We register all the helpers in the resolution queue.
- // TODO(13155): Find a way to register fewer helpers.
- for (CheckedModeHelper helper in checkedModeHelpers) {
- enqueueInResolution(helper.getElement(compiler), registry);
- }
- }
-
- /**
- * Returns [:true:] if the checking of [type] is performed directly on the
- * object and not on an interceptor.
- */
- bool hasDirectCheckFor(DartType type) {
- Element element = type.element;
- return element == compiler.stringClass ||
- element == compiler.boolClass ||
- element == compiler.numClass ||
- element == compiler.intClass ||
- element == compiler.doubleClass ||
- element == jsArrayClass ||
- element == jsMutableArrayClass ||
- element == jsExtendableArrayClass ||
- element == jsFixedArrayClass;
- }
-
- Element getExceptionUnwrapper() {
- return findHelper('unwrapException');
- }
-
- Element getThrowRuntimeError() {
- return findHelper('throwRuntimeError');
- }
-
- Element getThrowTypeError() {
- return findHelper('throwTypeError');
- }
-
- Element getThrowAbstractClassInstantiationError() {
- return findHelper('throwAbstractClassInstantiationError');
- }
-
- Element getStringInterpolationHelper() {
- return findHelper('S');
- }
-
- Element getWrapExceptionHelper() {
- return findHelper(r'wrapException');
- }
-
- Element getThrowExpressionHelper() {
- return findHelper('throwExpression');
- }
-
- Element getClosureConverter() {
- return findHelper('convertDartClosureToJS');
- }
-
- Element getTraceFromException() {
- return findHelper('getTraceFromException');
- }
-
- Element getSetRuntimeTypeInfo() {
- return findHelper('setRuntimeTypeInfo');
- }
-
- Element getGetRuntimeTypeInfo() {
- return findHelper('getRuntimeTypeInfo');
- }
-
- Element getGetTypeArgumentByIndex() {
- return findHelper('getTypeArgumentByIndex');
- }
-
- Element getCopyTypeArguments() {
- return findHelper('copyTypeArguments');
- }
-
- Element getComputeSignature() {
- return findHelper('computeSignature');
- }
-
- Element getGetRuntimeTypeArguments() {
- return findHelper('getRuntimeTypeArguments');
- }
-
- Element getGetRuntimeTypeArgument() {
- return findHelper('getRuntimeTypeArgument');
- }
-
- Element getRuntimeTypeToString() {
- return findHelper('runtimeTypeToString');
- }
-
- Element getAssertIsSubtype() {
- return findHelper('assertIsSubtype');
- }
-
- Element getCheckSubtype() {
- return findHelper('checkSubtype');
- }
-
- Element getAssertSubtype() {
- return findHelper('assertSubtype');
- }
-
- Element getCheckSubtypeOfRuntimeType() {
- return findHelper('checkSubtypeOfRuntimeType');
- }
-
- Element getCheckDeferredIsLoaded() {
- return findHelper('checkDeferredIsLoaded');
- }
-
- Element getAssertSubtypeOfRuntimeType() {
- return findHelper('assertSubtypeOfRuntimeType');
- }
-
- Element getThrowNoSuchMethod() {
- return findHelper('throwNoSuchMethod');
- }
-
- Element getCreateRuntimeType() {
- return findHelper('createRuntimeType');
- }
-
- Element getFallThroughError() {
- return findHelper("getFallThroughError");
- }
-
- Element getCreateInvocationMirror() {
- return findHelper(Compiler.CREATE_INVOCATION_MIRROR);
- }
-
- Element getCyclicThrowHelper() {
- return findHelper("throwCyclicInit");
- }
-
- bool isNullImplementation(ClassElement cls) {
- return cls == jsNullClass;
- }
-
- ClassElement get intImplementation => jsIntClass;
- ClassElement get uint32Implementation => jsUInt32Class;
- ClassElement get uint31Implementation => jsUInt31Class;
- ClassElement get positiveIntImplementation => jsPositiveIntClass;
- ClassElement get doubleImplementation => jsDoubleClass;
- ClassElement get numImplementation => jsNumberClass;
- ClassElement get stringImplementation => jsStringClass;
- ClassElement get listImplementation => jsArrayClass;
- ClassElement get constListImplementation => jsArrayClass;
- ClassElement get fixedListImplementation => jsFixedArrayClass;
- ClassElement get growableListImplementation => jsExtendableArrayClass;
- ClassElement get mapImplementation => mapLiteralClass;
- ClassElement get constMapImplementation => constMapLiteralClass;
- ClassElement get typeImplementation => typeLiteralClass;
- ClassElement get boolImplementation => jsBoolClass;
- ClassElement get nullImplementation => jsNullClass;
-
- void registerStaticUse(Element element, Enqueuer enqueuer) {
- if (element == disableTreeShakingMarker) {
- compiler.disableTypeInferenceForMirrors = true;
- isTreeShakingDisabled = true;
- typeVariableHandler.onTreeShakingDisabled(enqueuer);
- } else if (element == preserveNamesMarker) {
- mustPreserveNames = true;
- } else if (element == preserveMetadataMarker) {
- mustRetainMetadata = true;
- } else if (element == preserveUrisMarker) {
- if (compiler.preserveUris) mustPreserveUris = true;
- } else if (element == preserveLibraryNamesMarker) {
- mustRetainLibraryNames = true;
- } else if (element == getIsolateAffinityTagMarker) {
- needToInitializeIsolateAffinityTag = true;
- } else if (element.isDeferredLoaderGetter) {
- // TODO(sigurdm): Create a function registerLoadLibraryAccess.
- if (compiler.loadLibraryFunction == null) {
- compiler.loadLibraryFunction =
- findHelper("_loadLibraryWrapper");
- enqueueInResolution(compiler.loadLibraryFunction,
- compiler.globalDependencies);
- }
- } else if (element == requiresPreambleMarker) {
- requiresPreamble = true;
- }
- customElementsAnalysis.registerStaticUse(element, enqueuer);
- }
-
- /// Called when [:const Symbol(name):] is seen.
- void registerConstSymbol(String name, Registry registry) {
- symbolsUsed.add(name);
- if (name.endsWith('=')) {
- symbolsUsed.add(name.substring(0, name.length - 1));
- }
- }
-
- /// Called when [:new Symbol(...):] is seen.
- void registerNewSymbol(Registry registry) {
- }
-
- /// Should [element] (a getter) that would normally not be generated due to
- /// treeshaking be retained for reflection?
- bool shouldRetainGetter(Element element) {
- return isTreeShakingDisabled && isAccessibleByReflection(element);
- }
-
- /// Should [element] (a setter) hat would normally not be generated due to
- /// treeshaking be retained for reflection?
- bool shouldRetainSetter(Element element) {
- return isTreeShakingDisabled && isAccessibleByReflection(element);
- }
-
- /// Should [name] be retained for reflection?
- bool shouldRetainName(String name) {
- if (hasInsufficientMirrorsUsed) return mustPreserveNames;
- if (name == '') return false;
- return symbolsUsed.contains(name);
- }
-
- bool retainMetadataOf(Element element) {
- if (mustRetainMetadata) hasRetainedMetadata = true;
- if (mustRetainMetadata && referencedFromMirrorSystem(element)) {
- for (MetadataAnnotation metadata in element.metadata) {
- metadata.ensureResolved(compiler);
- ConstantValue constant =
- constants.getConstantForMetadata(metadata).value;
- constants.addCompileTimeConstantForEmission(constant);
- }
- return true;
- }
- return false;
- }
-
- void onLibraryCreated(LibraryElement library) {
- Uri uri = library.canonicalUri;
- if (uri == DART_JS_HELPER) {
- jsHelperLibrary = library;
- } else if (uri == DART_INTERNAL) {
- internalLibrary = library;
- } else if (uri == DART_INTERCEPTORS) {
- interceptorsLibrary = library;
- } else if (uri == DART_FOREIGN_HELPER) {
- foreignLibrary = library;
- } else if (uri == DART_ISOLATE_HELPER) {
- isolateHelperLibrary = library;
- }
- }
-
- void initializeHelperClasses() {
- final List missingHelperClasses = [];
- ClassElement lookupHelperClass(String name) {
- ClassElement result = findHelper(name);
- if (result == null) {
- missingHelperClasses.add(name);
- }
- return result;
- }
- jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror');
- boundClosureClass = lookupHelperClass('BoundClosure');
- closureClass = lookupHelperClass('Closure');
- if (!missingHelperClasses.isEmpty) {
- compiler.internalError(jsHelperLibrary,
- 'dart:_js_helper library does not contain required classes: '
- '$missingHelperClasses');
- }
- }
-
- Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
- return super.onLibraryScanned(library, loader).then((_) {
- Uri uri = library.canonicalUri;
-
- VariableElement findVariable(String name) {
- return find(library, name);
- }
-
- FunctionElement findMethod(String name) {
- return find(library, name);
- }
-
- ClassElement findClass(String name) {
- return find(library, name);
- }
-
- if (uri == DART_INTERCEPTORS) {
- getInterceptorMethod = findMethod('getInterceptor');
- interceptedNames = findVariable('interceptedNames');
- mapTypeToInterceptor = findVariable('mapTypeToInterceptor');
- getNativeInterceptorMethod = findMethod('getNativeInterceptor');
-
- List<ClassElement> classes = [
- jsInterceptorClass = findClass('Interceptor'),
- jsStringClass = findClass('JSString'),
- jsArrayClass = findClass('JSArray'),
- // The int class must be before the double class, because the
- // emitter relies on this list for the order of type checks.
- jsIntClass = findClass('JSInt'),
- jsPositiveIntClass = findClass('JSPositiveInt'),
- jsUInt32Class = findClass('JSUInt32'),
- jsUInt31Class = findClass('JSUInt31'),
- jsDoubleClass = findClass('JSDouble'),
- jsNumberClass = findClass('JSNumber'),
- jsNullClass = findClass('JSNull'),
- jsBoolClass = findClass('JSBool'),
- jsMutableArrayClass = findClass('JSMutableArray'),
- jsFixedArrayClass = findClass('JSFixedArray'),
- jsExtendableArrayClass = findClass('JSExtendableArray'),
- jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject'),
- jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject'),
- ];
-
- jsIndexableClass = findClass('JSIndexable');
- jsMutableIndexableClass = findClass('JSMutableIndexable');
- } else if (uri == DART_JS_HELPER) {
- initializeHelperClasses();
- assertMethod = findHelper('assertHelper');
-
- typeLiteralClass = findClass('TypeImpl');
- constMapLiteralClass = findClass('ConstantMap');
- typeVariableClass = findClass('TypeVariable');
-
- jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior');
-
- noSideEffectsClass = findClass('NoSideEffects');
- noThrowsClass = findClass('NoThrows');
- noInlineClass = findClass('NoInline');
- irRepresentationClass = findClass('IrRepresentation');
-
- getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
-
- requiresPreambleMarker = findMethod('requiresPreamble');
- } else if (uri == DART_JS_MIRRORS) {
- disableTreeShakingMarker = find(library, 'disableTreeShaking');
- preserveMetadataMarker = find(library, 'preserveMetadata');
- preserveUrisMarker = find(library, 'preserveUris');
- preserveLibraryNamesMarker = find(library, 'preserveLibraryNames');
- } else if (uri == DART_JS_NAMES) {
- preserveNamesMarker = find(library, 'preserveNames');
- } else if (uri == DART_HTML) {
- htmlLibraryIsLoaded = true;
- }
- });
- }
-
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
- if (!loadedLibraries.containsKey(Compiler.DART_CORE)) {
- return new Future.value();
- }
-
- assert(loadedLibraries.containsKey(Compiler.DART_CORE));
- assert(loadedLibraries.containsKey(DART_INTERCEPTORS));
- assert(loadedLibraries.containsKey(DART_JS_HELPER));
-
- if (jsInvocationMirrorClass != null) {
- jsInvocationMirrorClass.ensureResolved(compiler);
- invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
- }
-
- // [LinkedHashMap] is reexported from dart:collection and can therefore not
- // be loaded from dart:core in [onLibraryScanned].
- mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap');
- assert(invariant(compiler.coreLibrary, mapLiteralClass != null,
- message: "Element 'LinkedHashMap' not found in 'dart:core'."));
-
- implementationClasses = <ClassElement, ClassElement>{};
- implementationClasses[compiler.intClass] = jsIntClass;
- implementationClasses[compiler.boolClass] = jsBoolClass;
- implementationClasses[compiler.numClass] = jsNumberClass;
- implementationClasses[compiler.doubleClass] = jsDoubleClass;
- implementationClasses[compiler.stringClass] = jsStringClass;
- implementationClasses[compiler.listClass] = jsArrayClass;
- implementationClasses[compiler.nullClass] = jsNullClass;
-
- // These methods are overwritten with generated versions.
- inlineCache.markAsNonInlinable(getInterceptorMethod, insideLoop: true);
-
- // TODO(kasperl): Some tests do not define the special JSArray
- // subclasses, so we check to see if they are defined before
- // trying to resolve them.
- if (jsFixedArrayClass != null) {
- jsFixedArrayClass.ensureResolved(compiler);
- }
- if (jsExtendableArrayClass != null) {
- jsExtendableArrayClass.ensureResolved(compiler);
- }
-
- jsIndexableClass.ensureResolved(compiler);
- jsIndexableLength = compiler.lookupElementIn(
- jsIndexableClass, 'length');
- if (jsIndexableLength != null && jsIndexableLength.isAbstractField) {
- AbstractFieldElement element = jsIndexableLength;
- jsIndexableLength = element.getter;
- }
-
- jsArrayClass.ensureResolved(compiler);
- jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed');
- jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast');
- jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add');
-
- jsStringClass.ensureResolved(compiler);
- jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split');
- jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+');
- jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString');
-
- objectEquals = compiler.lookupElementIn(compiler.objectClass, '==');
-
- specialOperatorEqClasses
- ..add(compiler.objectClass)
- ..add(jsInterceptorClass)
- ..add(jsNullClass);
-
- validateInterceptorImplementsAllObjectMethods(jsInterceptorClass);
- // The null-interceptor must also implement *all* methods.
- validateInterceptorImplementsAllObjectMethods(jsNullClass);
-
- return new Future.value();
- }
-
- void registerMirrorUsage(Set<String> symbols,
- Set<Element> targets,
- Set<Element> metaTargets) {
- if (symbols == null && targets == null && metaTargets == null) {
- // The user didn't specify anything, or there are imports of
- // 'dart:mirrors' without @MirrorsUsed.
- hasInsufficientMirrorsUsed = true;
- return;
- }
- if (symbols != null) symbolsUsed.addAll(symbols);
- if (targets != null) {
- for (Element target in targets) {
- if (target.isAbstractField) {
- AbstractFieldElement field = target;
- targetsUsed.add(field.getter);
- targetsUsed.add(field.setter);
- } else {
- targetsUsed.add(target);
- }
- }
- }
- if (metaTargets != null) metaTargetsUsed.addAll(metaTargets);
- }
-
- /**
- * Returns `true` if [element] can be accessed through reflection, that is,
- * is in the set of elements covered by a `MirrorsUsed` annotation.
- *
- * This property is used to tag emitted elements with a marker which is
- * checked by the runtime system to throw an exception if an element is
- * accessed (invoked, get, set) that is not accessible for the reflective
- * system.
- */
- bool isAccessibleByReflection(Element element) {
- if (element.isClass) {
- element = getDartClass(element);
- }
- return membersNeededForReflection.contains(element);
- }
-
- /**
- * Returns true if the element has to be resolved due to a mirrorsUsed
- * annotation. If we have insufficient mirrors used annotations, we only
- * keep additonal elements if treeshaking has been disabled.
- */
- bool requiredByMirrorSystem(Element element) {
- return hasInsufficientMirrorsUsed && isTreeShakingDisabled ||
- matchesMirrorsMetaTarget(element) ||
- targetsUsed.contains(element);
- }
-
- /**
- * Returns true if the element matches a mirrorsUsed annotation. If
- * we have insufficient mirrorsUsed information, this returns true for
- * all elements, as they might all be potentially referenced.
- */
- bool referencedFromMirrorSystem(Element element, [recursive = true]) {
- Element enclosing = recursive ? element.enclosingElement : null;
-
- return hasInsufficientMirrorsUsed ||
- matchesMirrorsMetaTarget(element) ||
- targetsUsed.contains(element) ||
- (enclosing != null && referencedFromMirrorSystem(enclosing));
- }
-
- /**
- * Returns `true` if the element is needed because it has an annotation
- * of a type that is used as a meta target for reflection.
- */
- bool matchesMirrorsMetaTarget(Element element) {
- if (metaTargetsUsed.isEmpty) return false;
- for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
- MetadataAnnotation metadata = link.head;
- // TODO(kasperl): It would be nice if we didn't have to resolve
- // all metadata but only stuff that potentially would match one
- // of the used meta targets.
- metadata.ensureResolved(compiler);
- ConstantValue value = metadata.constant.value;
- if (value == null) continue;
- DartType type = value.computeType(compiler);
- if (metaTargetsUsed.contains(type.element)) return true;
- }
- return false;
- }
-
- /**
- * Visits all classes and computes whether its members are needed for
- * reflection.
- *
- * We have to precompute this set as we cannot easily answer the need for
- * reflection locally when looking at the member: We lack the information by
- * which classes a member is inherited. Called after resolution is complete.
- *
- * We filter out private libraries here, as their elements should not
- * be visible by reflection unless some other interfaces makes them
- * accessible.
- */
- computeMembersNeededForReflection() {
- if (_membersNeededForReflection != null) return;
- if (compiler.mirrorsLibrary == null) {
- _membersNeededForReflection = const ImmutableEmptySet<Element>();
- return;
- }
- // Compute a mapping from class to the closures it contains, so we
- // can include the correct ones when including the class.
- Map<ClassElement, List<LocalFunctionElement>> closureMap =
- new Map<ClassElement, List<LocalFunctionElement>>();
- for (LocalFunctionElement closure in compiler.resolverWorld.allClosures) {
- closureMap.putIfAbsent(closure.enclosingClass, () => []).add(closure);
- }
- bool foundClosure = false;
- Set<Element> reflectableMembers = new Set<Element>();
- ResolutionEnqueuer resolution = compiler.enqueuer.resolution;
- for (ClassElement cls in resolution.universe.directlyInstantiatedClasses) {
- // Do not process internal classes.
- if (cls.library.isInternalLibrary || cls.isInjected) continue;
- if (referencedFromMirrorSystem(cls)) {
- Set<Name> memberNames = new Set<Name>();
- // 1) the class (should be resolved)
- assert(invariant(cls, cls.isResolved));
- reflectableMembers.add(cls);
- // 2) its constructors (if resolved)
- cls.constructors.forEach((Element constructor) {
- if (resolution.hasBeenResolved(constructor)) {
- reflectableMembers.add(constructor);
- }
- });
- // 3) all members, including fields via getter/setters (if resolved)
- cls.forEachClassMember((Member member) {
- if (resolution.hasBeenResolved(member.element)) {
- memberNames.add(member.name);
- reflectableMembers.add(member.element);
- }
- });
- // 4) all overriding members of subclasses/subtypes (should be resolved)
- if (compiler.world.hasAnySubtype(cls)) {
- for (ClassElement subcls in compiler.world.subtypesOf(cls)) {
- subcls.forEachClassMember((Member member) {
- if (memberNames.contains(member.name)) {
- // TODO(20993): find out why this assertion fails.
- // assert(invariant(member.element,
- // resolution.hasBeenResolved(member.element)));
- if (resolution.hasBeenResolved(member.element)) {
- reflectableMembers.add(member.element);
- }
- }
- });
- }
- }
- // 5) all its closures
- List<LocalFunctionElement> closures = closureMap[cls];
- if (closures != null) {
- reflectableMembers.addAll(closures);
- foundClosure = true;
- }
- } else {
- // check members themselves
- cls.constructors.forEach((ConstructorElement element) {
- if (!resolution.hasBeenResolved(element)) return;
- if (referencedFromMirrorSystem(element, false)) {
- reflectableMembers.add(element);
- }
- });
- cls.forEachClassMember((Member member) {
- if (!resolution.hasBeenResolved(member.element)) return;
- if (referencedFromMirrorSystem(member.element, false)) {
- reflectableMembers.add(member.element);
- }
- });
- // Also add in closures. Those might be reflectable is their enclosing
- // member is.
- List<LocalFunctionElement> closures = closureMap[cls];
- if (closures != null) {
- for (LocalFunctionElement closure in closures) {
- if (referencedFromMirrorSystem(closure.memberContext, false)) {
- reflectableMembers.add(closure);
- foundClosure = true;
- }
- }
- }
- }
- }
- // We also need top-level non-class elements like static functions and
- // global fields. We use the resolution queue to decide which elements are
- // part of the live world.
- for (LibraryElement lib in compiler.libraryLoader.libraries) {
- if (lib.isInternalLibrary) continue;
- lib.forEachLocalMember((Element member) {
- if (!member.isClass &&
- resolution.hasBeenResolved(member) &&
- referencedFromMirrorSystem(member)) {
- reflectableMembers.add(member);
- }
- });
- }
- // And closures inside top-level elements that do not have a surrounding
- // class. These will be in the [:null:] bucket of the [closureMap].
- if (closureMap.containsKey(null)) {
- for (Element closure in closureMap[null]) {
- if (referencedFromMirrorSystem(closure)) {
- reflectableMembers.add(closure);
- foundClosure = true;
- }
- }
- }
- // As we do not think about closures as classes, yet, we have to make sure
- // their superclasses are available for reflection manually.
- if (foundClosure) {
- reflectableMembers.add(closureClass);
- }
- Set<Element> closurizedMembers = compiler.resolverWorld.closurizedMembers;
- if (closurizedMembers.any(reflectableMembers.contains)) {
- reflectableMembers.add(boundClosureClass);
- }
- // Add typedefs.
- reflectableMembers
- .addAll(compiler.world.allTypedefs.where(referencedFromMirrorSystem));
- // Register all symbols of reflectable elements
- for (Element element in reflectableMembers) {
- symbolsUsed.add(element.name);
- }
- _membersNeededForReflection = reflectableMembers;
- }
-
- // TODO(20791): compute closure classes after resolution and move this code to
- // [computeMembersNeededForReflection].
- void maybeMarkClosureAsNeededForReflection(
- ClosureClassElement globalizedElement,
- FunctionElement callFunction,
- FunctionElement function) {
- if (!_membersNeededForReflection.contains(function)) return;
- _membersNeededForReflection.add(callFunction);
- _membersNeededForReflection.add(globalizedElement);
- }
-
- jsAst.Call generateIsJsIndexableCall(jsAst.Expression use1,
- jsAst.Expression use2) {
- String dispatchPropertyName = embeddedNames.DISPATCH_PROPERTY_NAME;
- jsAst.Expression dispatchProperty =
- emitter.generateEmbeddedGlobalAccess(dispatchPropertyName);
-
- // We pass the dispatch property record to the isJsIndexable
- // helper rather than reading it inside the helper to increase the
- // chance of making the dispatch record access monomorphic.
- jsAst.PropertyAccess record =
- new jsAst.PropertyAccess(use2, dispatchProperty);
-
- List<jsAst.Expression> arguments = <jsAst.Expression>[use1, record];
- FunctionElement helper = findHelper('isJsIndexable');
- jsAst.Expression helperExpression = namer.elementAccess(helper);
- return new jsAst.Call(helperExpression, arguments);
- }
-
- bool isTypedArray(TypeMask mask) {
- // Just checking for [:TypedData:] is not sufficient, as it is an
- // abstract class any user-defined class can implement. So we also
- // check for the interface [JavaScriptIndexingBehavior].
- return
- compiler.typedDataClass != null &&
- compiler.world.isInstantiated(compiler.typedDataClass) &&
- mask.satisfies(compiler.typedDataClass, compiler.world) &&
- mask.satisfies(jsIndexingBehaviorInterface, compiler.world);
- }
-
- bool couldBeTypedArray(TypeMask mask) {
- bool intersects(TypeMask type1, TypeMask type2) =>
- !type1.intersection(type2, compiler.world).isEmpty;
- // TODO(herhut): Maybe cache the TypeMask for typedDataClass and
- // jsIndexingBehaviourInterface.
- return
- compiler.typedDataClass != null &&
- compiler.world.isInstantiated(compiler.typedDataClass) &&
- intersects(mask,
- new TypeMask.subtype(compiler.typedDataClass, compiler.world)) &&
- intersects(mask,
- new TypeMask.subtype(jsIndexingBehaviorInterface, compiler.world));
- }
-
- /// Returns all static fields that are referenced through [targetsUsed].
- /// If the target is a library or class all nested static fields are
- /// included too.
- Iterable<Element> _findStaticFieldTargets() {
- List staticFields = [];
-
- void addFieldsInContainer(ScopeContainerElement container) {
- container.forEachLocalMember((Element member) {
- if (!member.isInstanceMember && member.isField) {
- staticFields.add(member);
- } else if (member.isClass) {
- addFieldsInContainer(member);
- }
- });
- }
-
- for (Element target in targetsUsed) {
- if (target == null) continue;
- if (target.isField) {
- staticFields.add(target);
- } else if (target.isLibrary || target.isClass) {
- addFieldsInContainer(target);
- }
- }
- return staticFields;
- }
-
- /// Called when [enqueuer] is empty, but before it is closed.
- bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
- // Add elements referenced only via custom elements. Return early if any
- // elements are added to avoid counting the elements as due to mirrors.
- customElementsAnalysis.onQueueEmpty(enqueuer);
- if (!enqueuer.queueIsEmpty) return false;
-
- if (!enqueuer.isResolutionQueue && preMirrorsMethodCount == 0) {
- preMirrorsMethodCount = generatedCode.length;
- }
-
- if (isTreeShakingDisabled) {
- enqueuer.enqueueReflectiveElements(recentClasses);
- } else if (!targetsUsed.isEmpty && enqueuer.isResolutionQueue) {
- // Add all static elements (not classes) that have been requested for
- // reflection. If there is no mirror-usage these are probably not
- // necessary, but the backend relies on them being resolved.
- enqueuer.enqueueReflectiveStaticFields(_findStaticFieldTargets());
- }
-
- if (mustPreserveNames) compiler.log('Preserving names.');
-
- if (mustRetainMetadata) {
- compiler.log('Retaining metadata.');
-
- compiler.libraryLoader.libraries.forEach(retainMetadataOf);
- if (!enqueuer.isResolutionQueue) {
- for (Dependency dependency in metadataConstants) {
- registerCompileTimeConstant(
- dependency.constant,
- new CodegenRegistry(compiler,
- dependency.annotatedElement.analyzableElement.treeElements));
- }
- metadataConstants.clear();
- }
- }
- return true;
- }
-
- void onElementResolved(Element element, TreeElements elements) {
- LibraryElement library = element.library;
- if (!library.isPlatformLibrary && !library.canUseNative) return;
- bool hasNoInline = false;
- bool hasNoThrows = false;
- bool hasNoSideEffects = false;
- for (MetadataAnnotation metadata in element.metadata) {
- metadata.ensureResolved(compiler);
- if (!metadata.constant.value.isConstructedObject) continue;
- ObjectConstantValue value = metadata.constant.value;
- ClassElement cls = value.type.element;
- if (cls == noInlineClass) {
- hasNoInline = true;
- if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHint(element,
- MessageKind.GENERIC,
- {'text': "Cannot inline"});
- }
- inlineCache.markAsNonInlinable(element);
- } else if (cls == noThrowsClass) {
- hasNoThrows = true;
- if (!Elements.isStaticOrTopLevelFunction(element)) {
- compiler.internalError(element,
- "@NoThrows() is currently limited to top-level"
- " or static functions");
- }
- if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHint(element,
- MessageKind.GENERIC,
- {'text': "Cannot throw"});
- }
- compiler.world.registerCannotThrow(element);
- } else if (cls == noSideEffectsClass) {
- hasNoSideEffects = true;
- if (VERBOSE_OPTIMIZER_HINTS) {
- compiler.reportHint(element,
- MessageKind.GENERIC,
- {'text': "Has no side effects"});
- }
- compiler.world.registerSideEffectsFree(element);
- }
- }
- if (hasNoThrows && !hasNoInline) {
- compiler.internalError(element,
- "@NoThrows() should always be combined with @NoInline.");
- }
- if (hasNoSideEffects && !hasNoInline) {
- compiler.internalError(element,
- "@NoSideEffects() should always be combined with @NoInline.");
- }
- if (element == invokeOnMethod) {
- compiler.enabledInvokeOn = true;
- }
- }
-
- CodeBuffer codeOf(Element element) {
- return generatedCode.containsKey(element)
- ? jsAst.prettyPrint(generatedCode[element], compiler)
- : null;
- }
-
- FunctionElement helperForBadMain() => findHelper('badMain');
-
- FunctionElement helperForMissingMain() => findHelper('missingMain');
-
- FunctionElement helperForMainArity() {
- return findHelper('mainHasTooManyParameters');
- }
-
- void forgetElement(Element element) {
- constants.forgetElement(element);
- constantCompilerTask.dartConstantCompiler.forgetElement(element);
- }
-
- void registerMainHasArguments(Enqueuer enqueuer) {
- // If the main method takes arguments, this compilation could be the target
- // of Isolate.spawnUri. Strictly speaking, that can happen also if main
- // takes no arguments, but in this case the spawned isolate can't
- // communicate with the spawning isolate.
- enqueuer.enableIsolateSupport();
- }
-}
-
-class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
- final JavaScriptBackend backend;
-
- JavaScriptResolutionCallbacks(this.backend);
-
- void registerBackendStaticInvocation(Element element, Registry registry) {
- registry.registerStaticInvocation(backend.registerBackendUse(element));
- }
-
- void registerBackendInstantiation(ClassElement element, Registry registry) {
- backend.registerBackendUse(element);
- element.ensureResolved(backend.compiler);
- registry.registerInstantiation(element.rawType);
- }
-
- void onAssert(Send node, Registry registry) {
- registerBackendStaticInvocation(backend.assertMethod, registry);
- }
-
- void onStringInterpolation(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(
- backend.getStringInterpolationHelper(), registry);
- }
-
- void onCatchStatement(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getExceptionUnwrapper(), registry);
- registerBackendInstantiation(
- backend.jsPlainJavaScriptObjectClass, registry);
- registerBackendInstantiation(
- backend.jsUnknownJavaScriptObjectClass, registry);
- }
-
- void onThrowExpression(Registry registry) {
- assert(registry.isForResolution);
- // We don't know ahead of time whether we will need the throw in a
- // statement context or an expression context, so we register both
- // here, even though we may not need the throwExpression helper.
- registerBackendStaticInvocation(backend.getWrapExceptionHelper(), registry);
- registerBackendStaticInvocation(
- backend.getThrowExpressionHelper(), registry);
- }
-
- void onLazyField(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getCyclicThrowHelper(), registry);
- }
-
- void onTypeLiteral(DartType type, Registry registry) {
- assert(registry.isForResolution);
- registerBackendInstantiation(backend.typeImplementation, registry);
- registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
- // TODO(ahe): Might want to register [element] as an instantiated class
- // when reflection is used. However, as long as we disable tree-shaking
- // eagerly it doesn't matter.
- if (type.isTypedef) {
- backend.compiler.world.allTypedefs.add(type.element);
- }
- backend.customElementsAnalysis.registerTypeLiteral(type, registry);
- }
-
- void onStackTraceInCatch(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getTraceFromException(), registry);
- }
-
-
- void onTypeVariableExpression(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getSetRuntimeTypeInfo(), registry);
- registerBackendStaticInvocation(backend.getGetRuntimeTypeInfo(), registry);
- backend.registerGetRuntimeTypeArgument(registry);
- registerBackendInstantiation(backend.compiler.listClass, registry);
- registerBackendStaticInvocation(backend.getRuntimeTypeToString(), registry);
- registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
- }
-
- // TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
- void onIsCheck(DartType type, Registry registry) {
- assert(registry.isForResolution);
- type = type.unalias(backend.compiler);
- registerBackendInstantiation(backend.compiler.boolClass, registry);
- bool inCheckedMode = backend.compiler.enableTypeAssertions;
- if (inCheckedMode) {
- registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
- }
- if (type.isMalformed) {
- registerBackendStaticInvocation(backend.getThrowTypeError(), registry);
- }
- if (!type.treatAsRaw || type.containsTypeVariables) {
- // TODO(johnniwinther): Investigate why this is needed.
- registerBackendStaticInvocation(
- backend.getSetRuntimeTypeInfo(), registry);
- registerBackendStaticInvocation(
- backend.getGetRuntimeTypeInfo(), registry);
- backend.registerGetRuntimeTypeArgument(registry);
- if (inCheckedMode) {
- registerBackendStaticInvocation(backend.getAssertSubtype(), registry);
- }
- registerBackendStaticInvocation(backend.getCheckSubtype(), registry);
- if (type.isTypeVariable) {
- registerBackendStaticInvocation(
- backend.getCheckSubtypeOfRuntimeType(), registry);
- if (inCheckedMode) {
- registerBackendStaticInvocation(
- backend.getAssertSubtypeOfRuntimeType(), registry);
- }
- }
- registerBackendInstantiation(backend.compiler.listClass, registry);
- }
- if (type is FunctionType) {
- registerBackendStaticInvocation(
- backend.find(backend.jsHelperLibrary, 'functionTypeTestMetaHelper'),
- registry);
- }
- if (type.element != null && type.element.isNative) {
- // We will neeed to add the "$is" and "$as" properties on the
- // JavaScript object prototype, so we make sure
- // [:defineProperty:] is compiled.
- registerBackendStaticInvocation(
- backend.find(backend.jsHelperLibrary, 'defineProperty'), registry);
- }
- }
-
- void onTypeVariableBoundCheck(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getThrowTypeError(), registry);
- registerBackendStaticInvocation(backend.getAssertIsSubtype(), registry);
- }
-
- void onAbstractClassInstantiation(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(
- backend.getThrowAbstractClassInstantiationError(), registry);
- // Also register the types of the arguments passed to this method.
- registerBackendInstantiation(backend.compiler.stringClass, registry);
- }
-
- void onFallThroughError(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getFallThroughError(), registry);
- }
-
- void onAsCheck(DartType type, Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
- }
-
- void onThrowNoSuchMethod(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getThrowNoSuchMethod(), registry);
- // Also register the types of the arguments passed to this method.
- registerBackendInstantiation(backend.compiler.listClass, registry);
- registerBackendInstantiation(backend.compiler.stringClass, registry);
- }
-
- void onThrowRuntimeError(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(backend.getThrowRuntimeError(), registry);
- // Also register the types of the arguments passed to this method.
- registerBackendInstantiation(backend.compiler.stringClass, registry);
- }
-
- void onSuperNoSuchMethod(Registry registry) {
- assert(registry.isForResolution);
- registerBackendStaticInvocation(
- backend.getCreateInvocationMirror(), registry);
- registerBackendStaticInvocation(
- backend.compiler.objectClass.lookupLocalMember(Compiler.NO_SUCH_METHOD),
- registry);
- registerBackendInstantiation(backend.compiler.listClass, registry);
- }
-
- void onConstantMap(Registry registry) {
- assert(registry.isForResolution);
- void enqueue(String name) {
- Element e = backend.find(backend.jsHelperLibrary, name);
- registerBackendInstantiation(e, registry);
- }
-
- enqueue(JavaScriptMapConstant.DART_CLASS);
- enqueue(JavaScriptMapConstant.DART_PROTO_CLASS);
- enqueue(JavaScriptMapConstant.DART_STRING_CLASS);
- enqueue(JavaScriptMapConstant.DART_GENERAL_CLASS);
- }
-
- /// Called when resolving the `Symbol` constructor.
- void onSymbolConstructor(Registry registry) {
- assert(registry.isForResolution);
- // Make sure that _internals.Symbol.validated is registered.
- assert(backend.compiler.symbolValidatedConstructor != null);
- registerBackendStaticInvocation(
- backend.compiler.symbolValidatedConstructor, registry);
- }
-}
-
-/// Records that [constant] is used by the element behind [registry].
-class Dependency {
- final ConstantValue constant;
- final Element annotatedElement;
-
- const Dependency(this.constant, this.annotatedElement);
-}
« no previous file with comments | « pkg/compiler/lib/src/js/template.dart ('k') | pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698