| Index: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (revision 23797)
|
| +++ sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (working copy)
|
| @@ -4,607 +4,6 @@
|
|
|
| part of js_backend;
|
|
|
| -typedef void Recompile(Element element);
|
| -
|
| -class ReturnInfo {
|
| - HType returnType;
|
| - List<Element> compiledFunctions;
|
| -
|
| - ReturnInfo(HType this.returnType)
|
| - : compiledFunctions = new List<Element>();
|
| -
|
| - ReturnInfo.unknownType() : this(null);
|
| -
|
| - void update(HType type, Recompile recompile, Compiler compiler) {
|
| - HType newType =
|
| - returnType != null ? returnType.union(type, compiler) : type;
|
| - if (newType != returnType) {
|
| - if (returnType == null && identical(newType, HType.UNKNOWN)) {
|
| - // If the first actual piece of information is not providing any type
|
| - // information there is no need to recompile callers.
|
| - compiledFunctions.clear();
|
| - }
|
| - returnType = newType;
|
| - if (recompile != null) {
|
| - compiledFunctions.forEach(recompile);
|
| - }
|
| - compiledFunctions.clear();
|
| - }
|
| - }
|
| -
|
| - // Note that lazy initializers are treated like functions (but are not
|
| - // of type [FunctionElement].
|
| - addCompiledFunction(Element function) => compiledFunctions.add(function);
|
| -}
|
| -
|
| -class OptionalParameterTypes {
|
| - final List<SourceString> names;
|
| - final List<HType> types;
|
| -
|
| - OptionalParameterTypes(int optionalArgumentsCount)
|
| - : names = new List<SourceString>(optionalArgumentsCount),
|
| - types = new List<HType>(optionalArgumentsCount);
|
| -
|
| - int get length => names.length;
|
| - SourceString name(int index) => names[index];
|
| - HType type(int index) => types[index];
|
| - int indexOf(SourceString name) => names.indexOf(name);
|
| -
|
| - HType typeFor(SourceString name) {
|
| - int index = indexOf(name);
|
| - if (index == -1) return null;
|
| - return type(index);
|
| - }
|
| -
|
| - void update(int index, SourceString name, HType type) {
|
| - names[index] = name;
|
| - types[index] = type;
|
| - }
|
| -
|
| - String toString() => "OptionalParameterTypes($names, $types)";
|
| -}
|
| -
|
| -class HTypeList {
|
| - final List<HType> types;
|
| - final List<SourceString> namedArguments;
|
| -
|
| - HTypeList(int length)
|
| - : types = new List<HType>(length),
|
| - namedArguments = null;
|
| - HTypeList.withNamedArguments(int length, this.namedArguments)
|
| - : types = new List<HType>(length);
|
| - const HTypeList.withAllUnknown()
|
| - : types = null,
|
| - namedArguments = null;
|
| -
|
| - factory HTypeList.fromStaticInvocation(HInvokeStatic node) {
|
| - bool allUnknown = true;
|
| - for (int i = 0; i < node.inputs.length; i++) {
|
| - if (node.inputs[i].instructionType != HType.UNKNOWN) {
|
| - allUnknown = false;
|
| - break;
|
| - }
|
| - }
|
| - if (allUnknown) return HTypeList.ALL_UNKNOWN;
|
| -
|
| - HTypeList result = new HTypeList(node.inputs.length);
|
| - for (int i = 0; i < result.types.length; i++) {
|
| - result.types[i] = node.inputs[i].instructionType;
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - factory HTypeList.fromDynamicInvocation(HInvoke node,
|
| - Selector selector) {
|
| - HTypeList result;
|
| - int argumentsCount = node.inputs.length - 1;
|
| - int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET;
|
| -
|
| - if (node.isInterceptedCall) {
|
| - argumentsCount--;
|
| - startInvokeIndex++;
|
| - }
|
| -
|
| - if (selector.namedArgumentCount > 0) {
|
| - result =
|
| - new HTypeList.withNamedArguments(
|
| - argumentsCount, selector.namedArguments);
|
| - } else {
|
| - result = new HTypeList(argumentsCount);
|
| - }
|
| -
|
| - for (int i = 0; i < result.types.length; i++) {
|
| - result.types[i] = node.inputs[i + startInvokeIndex].instructionType;
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown();
|
| -
|
| - bool get allUnknown => types == null;
|
| - bool get hasNamedArguments => namedArguments != null;
|
| - int get length => types.length;
|
| - HType operator[](int index) => types[index];
|
| - void operator[]=(int index, HType type) { types[index] = type; }
|
| -
|
| - HTypeList union(HTypeList other, Compiler compiler) {
|
| - if (allUnknown) return this;
|
| - if (other.allUnknown) return other;
|
| - if (length != other.length) return HTypeList.ALL_UNKNOWN;
|
| - bool onlyUnknown = true;
|
| - HTypeList result = this;
|
| - for (int i = 0; i < length; i++) {
|
| - HType newType = this[i].union(other[i], compiler);
|
| - if (result == this && newType != this[i]) {
|
| - // Create a new argument types object with the matching types copied.
|
| - result = new HTypeList(length);
|
| - result.types.setRange(0, i, this.types);
|
| - }
|
| - if (result != this) {
|
| - result.types[i] = newType;
|
| - }
|
| - if (result[i] != HType.UNKNOWN) onlyUnknown = false;
|
| - }
|
| - return onlyUnknown ? HTypeList.ALL_UNKNOWN : result;
|
| - }
|
| -
|
| - HTypeList unionWithOptionalParameters(
|
| - Selector selector,
|
| - FunctionSignature signature,
|
| - OptionalParameterTypes defaultValueTypes) {
|
| - assert(allUnknown || selector.argumentCount == this.length);
|
| - // Create a new HTypeList for holding types for all parameters.
|
| - HTypeList result = new HTypeList(signature.parameterCount);
|
| -
|
| - // First fill in the type of the positional arguments.
|
| - int nextTypeIndex = -1;
|
| - if (allUnknown) {
|
| - for (int i = 0; i < selector.positionalArgumentCount; i++) {
|
| - result.types[i] = HType.UNKNOWN;
|
| - }
|
| - } else {
|
| - result.types.setRange(0, selector.positionalArgumentCount, this.types);
|
| - nextTypeIndex = selector.positionalArgumentCount;
|
| - }
|
| -
|
| - // Next fill the type of the optional arguments.
|
| - // As the selector can pass optional arguments positionally some of the
|
| - // optional arguments might already have a type set. We only need to look
|
| - // at the optional arguments not passed positionally.
|
| - // The variable 'index' is counting the signatures optional arguments, the
|
| - // variable 'next' is set to the next optional arguments to look at and
|
| - // is used to skip some optional arguments.
|
| - int next = selector.positionalArgumentCount;
|
| - int index = signature.requiredParameterCount;
|
| - signature.forEachOptionalParameter((Element element) {
|
| - // If some optional parameters were passed positionally these have
|
| - // already been filled.
|
| - if (index == next) {
|
| - assert(result.types[index] == null);
|
| - HType type = null;
|
| - if (hasNamedArguments &&
|
| - selector.namedArguments.indexOf(element.name) >= 0) {
|
| - type = types[nextTypeIndex++];
|
| - } else {
|
| - type = defaultValueTypes.typeFor(element.name);
|
| - }
|
| - result.types[index] = type;
|
| - next++;
|
| - }
|
| - index++;
|
| - });
|
| - return result;
|
| - }
|
| -
|
| - String toString() =>
|
| - allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
|
| -}
|
| -
|
| -class FieldTypesRegistry {
|
| - final JavaScriptBackend backend;
|
| -
|
| - /**
|
| - * For each class, [constructors] holds the set of constructors. If there is
|
| - * more than one constructor for a class it is currently not possible to
|
| - * infer the field types from construction, as the information collected does
|
| - * not correlate the generative constructors and generative constructor
|
| - * body/bodies.
|
| - */
|
| - final Map<ClassElement, Set<Element>> constructors;
|
| -
|
| - /**
|
| - * The collected type information is stored in three maps. One for types
|
| - * assigned in the initializer list(s) [fieldInitializerTypeMap], one for
|
| - * types assigned in the constructor(s) [fieldConstructorTypeMap], and one
|
| - * for types assigned in the rest of the code, where the field can be
|
| - * resolved [fieldTypeMap].
|
| - *
|
| - * If a field has a type both from constructors and from the initializer
|
| - * list(s), then the type from the constructor(s) will owerride the one from
|
| - * the initializer list(s).
|
| - *
|
| - * Because the order in which generative constructors, generative constructor
|
| - * bodies and normal method/function bodies are compiled is undefined, and
|
| - * because they can all be recompiled, it is not possible to combine this
|
| - * information into one map at the moment.
|
| - */
|
| - final Map<Element, HType> fieldInitializerTypeMap;
|
| - final Map<Element, HType> fieldConstructorTypeMap;
|
| - final Map<Element, HType> fieldTypeMap;
|
| -
|
| - /**
|
| - * The set of current names setter selectors used. If a named selector is
|
| - * used it is currently not possible to infer the type of the field.
|
| - */
|
| - final Set<SourceString> setterSelectorsUsed;
|
| -
|
| - final Map<Element, Set<Element>> optimizedStaticFunctions;
|
| - final Map<Element, FunctionSet> optimizedFunctions;
|
| -
|
| - FieldTypesRegistry(JavaScriptBackend backend)
|
| - : constructors = new Map<ClassElement, Set<Element>>(),
|
| - fieldInitializerTypeMap = new Map<Element, HType>(),
|
| - fieldConstructorTypeMap = new Map<Element, HType>(),
|
| - fieldTypeMap = new Map<Element, HType>(),
|
| - setterSelectorsUsed = new Set<SourceString>(),
|
| - optimizedStaticFunctions = new Map<Element, Set<Element>>(),
|
| - optimizedFunctions = new Map<Element, FunctionSet>(),
|
| - this.backend = backend;
|
| -
|
| - Compiler get compiler => backend.compiler;
|
| -
|
| - void scheduleRecompilation(Element field) {
|
| - Set optimizedStatics = optimizedStaticFunctions[field];
|
| - if (optimizedStatics != null) {
|
| - optimizedStatics.forEach(backend.scheduleForRecompilation);
|
| - optimizedStaticFunctions.remove(field);
|
| - }
|
| - FunctionSet optimized = optimizedFunctions[field];
|
| - if (optimized != null) {
|
| - optimized.forEach(backend.scheduleForRecompilation);
|
| - optimizedFunctions.remove(field);
|
| - }
|
| - }
|
| -
|
| - int constructorCount(Element element) {
|
| - assert(element.isClass());
|
| - Set<Element> ctors = constructors[element];
|
| - return ctors == null ? 0 : ctors.length;
|
| - }
|
| -
|
| - void registerFieldType(Map<Element, HType> typeMap,
|
| - Element field,
|
| - HType type) {
|
| - assert(field.isField());
|
| - HType before = optimisticFieldType(field);
|
| -
|
| - HType oldType = typeMap[field];
|
| - HType newType;
|
| -
|
| - if (oldType != null) {
|
| - newType = oldType.union(type, compiler);
|
| - } else {
|
| - newType = type;
|
| - }
|
| - typeMap[field] = newType;
|
| - if (oldType != newType) {
|
| - scheduleRecompilation(field);
|
| - }
|
| - }
|
| -
|
| - void registerConstructor(Element element) {
|
| - assert(element.isGenerativeConstructor());
|
| - Element cls = element.getEnclosingClass();
|
| - constructors.putIfAbsent(cls, () => new Set<Element>());
|
| - Set<Element> ctors = constructors[cls];
|
| - if (ctors.contains(element)) return;
|
| - ctors.add(element);
|
| - // We cannot infer field types for classes with more than one constructor.
|
| - // When the second constructor is seen, recompile all functions relying on
|
| - // optimistic field types for that class.
|
| - // TODO(sgjesse): Handle field types for classes with more than one
|
| - // constructor.
|
| - if (ctors.length == 2) {
|
| - optimizedFunctions.keys.toList().forEach((Element field) {
|
| - if (identical(field.enclosingElement, cls)) {
|
| - scheduleRecompilation(field);
|
| - }
|
| - });
|
| - }
|
| - }
|
| -
|
| - void registerFieldInitializer(Element field, HType type) {
|
| - registerFieldType(fieldInitializerTypeMap, field, type);
|
| - }
|
| -
|
| - void registerFieldConstructor(Element field, HType type) {
|
| - registerFieldType(fieldConstructorTypeMap, field, type);
|
| - }
|
| -
|
| - void registerFieldSetter(Element element, Element field, HType type) {
|
| - HType initializerType = fieldInitializerTypeMap[field];
|
| - HType constructorType = fieldConstructorTypeMap[field];
|
| - HType setterType = fieldTypeMap[field];
|
| - if (type == HType.UNKNOWN
|
| - && initializerType == null
|
| - && constructorType == null
|
| - && setterType == null) {
|
| - // Don't register UNKNOWN if there is currently no type information
|
| - // present for the field. Instead register the function holding the
|
| - // setter for recompilation if better type information for the field
|
| - // becomes available.
|
| - registerOptimizedFunction(element, field, type);
|
| - return;
|
| - }
|
| - registerFieldType(fieldTypeMap, field, type);
|
| - }
|
| -
|
| - void addedDynamicSetter(Selector setter, HType type) {
|
| - // Field type optimizations are disabled for all fields matching a
|
| - // setter selector.
|
| - assert(setter.isSetter());
|
| - // TODO(sgjesse): Take the type of the setter into account.
|
| - if (setterSelectorsUsed.contains(setter.name)) return;
|
| - setterSelectorsUsed.add(setter.name);
|
| - optimizedStaticFunctions.keys.toList().forEach((Element field) {
|
| - if (field.name == setter.name) {
|
| - scheduleRecompilation(field);
|
| - }
|
| - });
|
| - optimizedFunctions.keys.toList().forEach((Element field) {
|
| - if (field.name == setter.name) {
|
| - scheduleRecompilation(field);
|
| - }
|
| - });
|
| - }
|
| -
|
| - HType optimisticFieldType(Element field) {
|
| - assert(field.isField());
|
| - if (constructorCount(field.getEnclosingClass()) > 1) {
|
| - return HType.UNKNOWN;
|
| - }
|
| - if (setterSelectorsUsed.contains(field.name)) {
|
| - return HType.UNKNOWN;
|
| - }
|
| - HType initializerType = fieldInitializerTypeMap[field];
|
| - HType constructorType = fieldConstructorTypeMap[field];
|
| - if (initializerType == null && constructorType == null) {
|
| - // If there are no constructor type information return UNKNOWN. This
|
| - // ensures that the function will be recompiled if useful constructor
|
| - // type information becomes available.
|
| - return HType.UNKNOWN;
|
| - }
|
| - // A type set through the constructor overrides the type from the
|
| - // initializer list.
|
| - HType result = constructorType != null ? constructorType : initializerType;
|
| - HType type = fieldTypeMap[field];
|
| - if (type != null) result = result.union(type, compiler);
|
| - return result;
|
| - }
|
| -
|
| - void registerOptimizedFunction(Element element,
|
| - Element field,
|
| - HType type) {
|
| - assert(field.isField());
|
| - if (Elements.isStaticOrTopLevel(element)) {
|
| - optimizedStaticFunctions.putIfAbsent(
|
| - field, () => new Set<Element>());
|
| - optimizedStaticFunctions[field].add(element);
|
| - } else {
|
| - optimizedFunctions.putIfAbsent(
|
| - field, () => new FunctionSet(backend.compiler));
|
| - optimizedFunctions[field].add(element);
|
| - }
|
| - }
|
| -
|
| - void dump() {
|
| - Set<Element> allFields = new Set<Element>();
|
| - fieldInitializerTypeMap.keys.forEach(allFields.add);
|
| - fieldConstructorTypeMap.keys.forEach(allFields.add);
|
| - fieldTypeMap.keys.forEach(allFields.add);
|
| - allFields.forEach((Element field) {
|
| - print("Inferred $field has type ${optimisticFieldType(field)}");
|
| - });
|
| - }
|
| -}
|
| -
|
| -class ArgumentTypesRegistry {
|
| - final JavaScriptBackend backend;
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: Keys must be declaration elements.
|
| - */
|
| - final Map<Element, HTypeList> staticTypeMap;
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: Elements must be declaration elements.
|
| - */
|
| - final Set<Element> optimizedStaticFunctions;
|
| - final SelectorMap<HTypeList> selectorTypeMap;
|
| - final FunctionSet optimizedFunctions;
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: Keys must be declaration elements.
|
| - */
|
| - final Map<Element, HTypeList> optimizedTypes;
|
| - final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
|
| -
|
| - ArgumentTypesRegistry(JavaScriptBackend backend)
|
| - : staticTypeMap = new Map<Element, HTypeList>(),
|
| - optimizedStaticFunctions = new Set<Element>(),
|
| - selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler),
|
| - optimizedFunctions = new FunctionSet(backend.compiler),
|
| - optimizedTypes = new Map<Element, HTypeList>(),
|
| - optimizedDefaultValueTypes =
|
| - new Map<Element, OptionalParameterTypes>(),
|
| - this.backend = backend;
|
| -
|
| - Compiler get compiler => backend.compiler;
|
| -
|
| - bool updateTypes(HTypeList oldTypes, HTypeList newTypes, var key, var map) {
|
| - if (oldTypes.allUnknown) return false;
|
| - newTypes = oldTypes.union(newTypes, backend.compiler);
|
| - if (identical(newTypes, oldTypes)) return false;
|
| - map[key] = newTypes;
|
| - return true;
|
| - }
|
| -
|
| - void registerStaticInvocation(HInvokeStatic node) {
|
| - Element element = node.element;
|
| - assert(invariant(node, element.isDeclaration));
|
| - HTypeList oldTypes = staticTypeMap[element];
|
| - HTypeList newTypes = new HTypeList.fromStaticInvocation(node);
|
| - if (oldTypes == null) {
|
| - staticTypeMap[element] = newTypes;
|
| - } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) {
|
| - if (optimizedStaticFunctions.contains(element)) {
|
| - backend.scheduleForRecompilation(element);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void registerNonCallStaticUse(HStatic node) {
|
| - // When a static is used for anything else than a call target we cannot
|
| - // infer anything about its parameter types.
|
| - Element element = node.element;
|
| - assert(invariant(node, element.isDeclaration));
|
| - if (optimizedStaticFunctions.contains(element)) {
|
| - backend.scheduleForRecompilation(element);
|
| - }
|
| - staticTypeMap[element] = HTypeList.ALL_UNKNOWN;
|
| - }
|
| -
|
| - void registerDynamicInvocation(HTypeList providedTypes, Selector selector) {
|
| - if (selector.isClosureCall()) {
|
| - // We cannot use the current framework to do optimizations based
|
| - // on the 'call' selector because we are also generating closure
|
| - // calls during the emitter phase, which at this point, does not
|
| - // track parameter types, nor invalidates optimized methods.
|
| - return;
|
| - }
|
| - if (!selectorTypeMap.containsKey(selector)) {
|
| - selectorTypeMap[selector] = providedTypes;
|
| - } else {
|
| - HTypeList oldTypes = selectorTypeMap[selector];
|
| - updateTypes(oldTypes, providedTypes, selector, selectorTypeMap);
|
| - }
|
| -
|
| - // If we're not compiling, we don't have to do anything.
|
| - if (compiler.phase != Compiler.PHASE_COMPILING) return;
|
| -
|
| - // Run through all optimized functions and figure out if they need
|
| - // to be recompiled because of this new invocation.
|
| - for (Element element in optimizedFunctions.filter(selector)) {
|
| - // TODO(kasperl): Maybe check if the element is already marked for
|
| - // recompilation? Could be pretty cheap compared to computing
|
| - // union types.
|
| - HTypeList newTypes =
|
| - parameterTypes(element, optimizedDefaultValueTypes[element]);
|
| - bool recompile = false;
|
| - if (newTypes.allUnknown) {
|
| - recompile = true;
|
| - } else {
|
| - HTypeList oldTypes = optimizedTypes[element];
|
| - assert(newTypes.length == oldTypes.length);
|
| - for (int i = 0; i < oldTypes.length; i++) {
|
| - if (newTypes[i] != oldTypes[i]) {
|
| - recompile = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (recompile) backend.scheduleForRecompilation(element);
|
| - }
|
| - }
|
| -
|
| - HTypeList parameterTypes(FunctionElement element,
|
| - OptionalParameterTypes defaultValueTypes) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - // Handle static functions separately.
|
| - if (Elements.isStaticOrTopLevelFunction(element) ||
|
| - element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
|
| - HTypeList types = staticTypeMap[element];
|
| - if (types != null) {
|
| - if (!optimizedStaticFunctions.contains(element)) {
|
| - optimizedStaticFunctions.add(element);
|
| - }
|
| - return types;
|
| - } else {
|
| - return HTypeList.ALL_UNKNOWN;
|
| - }
|
| - }
|
| -
|
| - // Getters have no parameters.
|
| - if (element.isGetter()) return HTypeList.ALL_UNKNOWN;
|
| -
|
| - // TODO(kasperl): What kind of non-members do we get here?
|
| - if (!element.isMember()) return HTypeList.ALL_UNKNOWN;
|
| -
|
| - // If there are any getters for this method we cannot know anything about
|
| - // the types of the provided parameters. Use resolverWorld for now as that
|
| - // information does not change during compilation.
|
| - // TODO(ngeoffray): These checks should use the codegenWorld and keep track
|
| - // of changes to this information.
|
| - if (compiler.resolverWorld.hasInvokedGetter(element, compiler)) {
|
| - return HTypeList.ALL_UNKNOWN;
|
| - }
|
| -
|
| - FunctionSignature signature = element.computeSignature(compiler);
|
| - HTypeList found = null;
|
| - selectorTypeMap.visitMatching(element,
|
| - (Selector selector, HTypeList types) {
|
| - if (selector.argumentCount != signature.parameterCount ||
|
| - selector.namedArgumentCount > 0) {
|
| - types = types.unionWithOptionalParameters(selector,
|
| - signature,
|
| - defaultValueTypes);
|
| - }
|
| - assert(types.allUnknown || types.length == signature.parameterCount);
|
| - found = (found == null) ? types : found.union(types, compiler);
|
| - return !found.allUnknown;
|
| - });
|
| - return found != null ? found : HTypeList.ALL_UNKNOWN;
|
| - }
|
| -
|
| - void registerOptimizedFunction(Element element,
|
| - HTypeList parameterTypes,
|
| - OptionalParameterTypes defaultValueTypes) {
|
| - if (Elements.isStaticOrTopLevelFunction(element)) {
|
| - if (parameterTypes.allUnknown) {
|
| - optimizedStaticFunctions.remove(element);
|
| - } else {
|
| - optimizedStaticFunctions.add(element);
|
| - }
|
| - }
|
| -
|
| - // TODO(kasperl): What kind of non-members do we get here?
|
| - if (!element.isInstanceMember()) return;
|
| -
|
| - if (parameterTypes.allUnknown) {
|
| - optimizedFunctions.remove(element);
|
| - optimizedTypes.remove(element);
|
| - optimizedDefaultValueTypes.remove(element);
|
| - } else {
|
| - optimizedFunctions.add(element);
|
| - optimizedTypes[element] = parameterTypes;
|
| - optimizedDefaultValueTypes[element] = defaultValueTypes;
|
| - }
|
| - }
|
| -
|
| - void dump() {
|
| - optimizedFunctions.forEach((Element element) {
|
| - HTypeList types = optimizedTypes[element];
|
| - print("Inferred $element has argument types ${types.types}");
|
| - });
|
| - }
|
| -}
|
| -
|
| class JavaScriptItemCompilationContext extends ItemCompilationContext {
|
| final Set<HInstruction> boundsChecked;
|
|
|
| @@ -691,18 +90,7 @@
|
| */
|
| ClassElement jsIndexingBehaviorInterface;
|
|
|
| - final Map<Element, ReturnInfo> returnInfo;
|
| -
|
| /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: Elements must be declaration elements.
|
| - */
|
| - final List<Element> invalidateAfterCodegen;
|
| - ArgumentTypesRegistry argumentTypes;
|
| - FieldTypesRegistry fieldTypes;
|
| -
|
| - /**
|
| * A collection of selectors of intercepted method calls. The
|
| * emitter uses this set to generate the [:ObjectInterceptor:] class
|
| * whose members just forward the call to the intercepted receiver.
|
| @@ -762,8 +150,6 @@
|
|
|
| JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
|
| : namer = determineNamer(compiler),
|
| - returnInfo = new Map<Element, ReturnInfo>(),
|
| - invalidateAfterCodegen = new List<Element>(),
|
| usedInterceptors = new Set<Selector>(),
|
| oneShotInterceptors = new Map<String, Selector>(),
|
| interceptedElements = new Map<SourceString, Set<Element>>(),
|
| @@ -776,8 +162,6 @@
|
| builder = new SsaBuilderTask(this);
|
| optimizer = new SsaOptimizerTask(this);
|
| generator = new SsaCodeGeneratorTask(this);
|
| - argumentTypes = new ArgumentTypesRegistry(this);
|
| - fieldTypes = new FieldTypesRegistry(this);
|
| }
|
|
|
| static Namer determineNamer(Compiler compiler) {
|
| @@ -1052,23 +436,10 @@
|
| }
|
| }
|
|
|
| - void initializeNoSuchMethod() {
|
| - // In case the emitter generates noSuchMethod calls, we need to
|
| - // make sure all [noSuchMethod] methods know they might take a
|
| - // [JsInvocationMirror] as parameter.
|
| - HTypeList types = new HTypeList(1);
|
| - types[0] = new HType.nonNullExact(
|
| - compiler.jsInvocationMirrorClass.computeType(compiler),
|
| - compiler);
|
| - argumentTypes.registerDynamicInvocation(
|
| - types, compiler.noSuchMethodSelector);
|
| - }
|
| -
|
| void registerInstantiatedClass(ClassElement cls,
|
| Enqueuer enqueuer,
|
| TreeElements elements) {
|
| if (!seenAnyClass) {
|
| - initializeNoSuchMethod();
|
| seenAnyClass = true;
|
| if (enqueuer.isResolutionQueue) {
|
| // TODO(9577): Make it so that these are not needed when there are no
|
| @@ -1411,8 +782,6 @@
|
| }
|
| jsAst.Expression code = generator.generateCode(work, graph);
|
| generatedCode[element] = code;
|
| - invalidateAfterCodegen.forEach(eagerRecompile);
|
| - invalidateAfterCodegen.clear();
|
| }
|
|
|
| native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
|
| @@ -1442,153 +811,6 @@
|
| emitter.assembleProgram();
|
| }
|
|
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void scheduleForRecompilation(Element element) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - if (compiler.phase == Compiler.PHASE_COMPILING) {
|
| - invalidateAfterCodegen.add(element);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Register a dynamic invocation and collect the provided types for the
|
| - * named selector.
|
| - */
|
| - void registerDynamicInvocation(HInvoke node, Selector selector) {
|
| - HTypeList providedTypes =
|
| - new HTypeList.fromDynamicInvocation(node, selector);
|
| - argumentTypes.registerDynamicInvocation(providedTypes, selector);
|
| - }
|
| -
|
| - /**
|
| - * Register a static invocation and collect the provided types for the
|
| - * named selector.
|
| - */
|
| - void registerStaticInvocation(HInvokeStatic node) {
|
| - argumentTypes.registerStaticInvocation(node);
|
| - }
|
| -
|
| - /**
|
| - * Register that a static is used for something else than a direct call
|
| - * target.
|
| - */
|
| - void registerNonCallStaticUse(HStatic node) {
|
| - argumentTypes.registerNonCallStaticUse(node);
|
| - }
|
| -
|
| - /**
|
| - * Retrieve the types of the parameters used for calling the [element]
|
| - * function. The types are optimistic in the sense as they are based on the
|
| - * possible invocations of the function seen so far.
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - HTypeList optimisticParameterTypes(
|
| - FunctionElement element,
|
| - OptionalParameterTypes defaultValueTypes) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN;
|
| - return argumentTypes.parameterTypes(element, defaultValueTypes);
|
| - }
|
| -
|
| - /**
|
| - * Register that the function [element] has been optimized under the
|
| - * assumptions that the types [parameterType] will be used for calling it.
|
| - * The passed [defaultValueTypes] holds the types of default values for
|
| - * the optional parameters. If this assumption fail the function will be
|
| - * scheduled for recompilation.
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - registerParameterTypesOptimization(
|
| - FunctionElement element,
|
| - HTypeList parameterTypes,
|
| - OptionalParameterTypes defaultValueTypes) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - if (element.parameterCount(compiler) == 0) return;
|
| - argumentTypes.registerOptimizedFunction(
|
| - element, parameterTypes, defaultValueTypes);
|
| - }
|
| -
|
| - registerFieldTypesOptimization(Element element,
|
| - Element field,
|
| - HType type) {
|
| - fieldTypes.registerOptimizedFunction(element, field, type);
|
| - }
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void registerReturnType(FunctionElement element, HType returnType) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - ReturnInfo info = returnInfo[element];
|
| - if (info != null) {
|
| - info.update(returnType, scheduleForRecompilation, compiler);
|
| - } else {
|
| - returnInfo[element] = new ReturnInfo(returnType);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Retrieve the return type of the function [callee]. The type is optimistic
|
| - * in the sense that is is based on the compilation of [callee]. If [callee]
|
| - * is recompiled the return type might change to someting broader. For that
|
| - * reason [caller] is registered for recompilation if this happens. If the
|
| - * function [callee] has not yet been compiled the returned type is [null].
|
| - *
|
| - * Invariant: Both [caller] and [callee] must be declaration elements.
|
| - */
|
| - HType optimisticReturnTypesWithRecompilationOnTypeChange(
|
| - Element caller, FunctionElement callee) {
|
| - assert(invariant(callee, callee.isDeclaration));
|
| - returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType());
|
| - ReturnInfo info = returnInfo[callee];
|
| - HType returnType = info.returnType;
|
| - if (returnType != HType.UNKNOWN && returnType != null && caller != null) {
|
| - assert(invariant(caller, caller.isDeclaration));
|
| - info.addCompiledFunction(caller);
|
| - }
|
| - return info.returnType;
|
| - }
|
| -
|
| - void dumpReturnTypes() {
|
| - returnInfo.forEach((Element element, ReturnInfo info) {
|
| - if (info.returnType != HType.UNKNOWN) {
|
| - print("Inferred $element has return type ${info.returnType}");
|
| - }
|
| - });
|
| - }
|
| -
|
| - void registerConstructor(Element element) {
|
| - fieldTypes.registerConstructor(element);
|
| - }
|
| -
|
| - void registerFieldInitializer(Element field, HType type) {
|
| - fieldTypes.registerFieldInitializer(field, type);
|
| - }
|
| -
|
| - void registerFieldConstructor(Element field, HType type) {
|
| - fieldTypes.registerFieldConstructor(field, type);
|
| - }
|
| -
|
| - void registerFieldSetter(Element element, Element field, HType type) {
|
| - fieldTypes.registerFieldSetter(element, field, type);
|
| - }
|
| -
|
| - void addedDynamicSetter(Selector setter, HType type) {
|
| - fieldTypes.addedDynamicSetter(setter, type);
|
| - }
|
| -
|
| - HType optimisticFieldType(Element element) {
|
| - return fieldTypes.optimisticFieldType(element);
|
| - }
|
| -
|
| Element getImplementationClass(Element element) {
|
| if (element == compiler.intClass) {
|
| return jsIntClass;
|
| @@ -1740,21 +962,6 @@
|
| }
|
| }
|
|
|
| - void dumpInferredTypes() {
|
| - print("Inferred argument types:");
|
| - print("------------------------");
|
| - argumentTypes.dump();
|
| - print("");
|
| - print("Inferred return types:");
|
| - print("----------------------");
|
| - dumpReturnTypes();
|
| - print("");
|
| - print("Inferred field types:");
|
| - print("------------------------");
|
| - fieldTypes.dump();
|
| - print("");
|
| - }
|
| -
|
| Element getExceptionUnwrapper() {
|
| return compiler.findHelper(const SourceString('unwrapException'));
|
| }
|
|
|