| 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);
|
| -}
|
|
|