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

Unified Diff: pkg/compiler/lib/src/inferrer/inferrer_engine.dart

Issue 2616103002: Flatten inferrer implementation (Closed)
Patch Set: Updated cf. comment. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/inferrer/inferrer_engine.dart
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
similarity index 56%
copy from pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
copy to pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 7cf3baa2797181932272c09b23eed26fa468028b..049a86a798ea10a815a36fea9f6dc6b306301c2b 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -1,587 +1,218 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2017, 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.
-library type_graph_inferrer;
-
-import 'dart:collection' show Queue;
-
import '../common.dart';
-import '../common/names.dart' show Identifiers;
-import '../compiler.dart' show Compiler;
-import '../constants/expressions.dart' show ConstantExpression;
+import '../common/names.dart';
+import '../compiler.dart';
+import '../constants/expressions.dart';
import '../constants/values.dart';
-import '../elements/resolution_types.dart' show ResolutionDartType;
+import '../core_types.dart';
import '../elements/elements.dart';
-import '../js_backend/js_backend.dart' show Annotations, JavaScriptBackend;
-import '../resolution/tree_elements.dart' show TreeElementMapping;
-import '../tree/dartstring.dart' show DartString;
-import '../tree/tree.dart' as ast show Node, LiteralBool, TryStatement;
-import '../types/constants.dart' show computeTypeMask;
-import '../types/masks.dart'
- show CommonMasks, ContainerTypeMask, MapTypeMask, TypeMask;
-import '../types/types.dart' show TypesInferrer;
-import '../universe/call_structure.dart' show CallStructure;
-import '../universe/selector.dart' show Selector;
-import '../universe/side_effects.dart' show SideEffects;
-import '../util/util.dart' show Setlet;
-import '../world.dart' show ClosedWorld, ClosedWorldRefiner;
+import '../js_backend/js_backend.dart';
+import '../native/behavior.dart' as native;
+import '../resolution/tree_elements.dart';
+import '../tree/nodes.dart' as ast;
+import '../types/constants.dart';
+import '../types/types.dart';
+import '../universe/call_structure.dart';
+import '../universe/selector.dart';
+import '../universe/side_effects.dart';
+import '../util/util.dart';
+import '../world.dart';
import 'closure_tracer.dart';
import 'debug.dart' as debug;
-import 'inferrer_visitor.dart' show ArgumentsTypes, TypeSystem;
+import 'inferrer_visitor.dart';
import 'list_tracer.dart';
import 'map_tracer.dart';
import 'simple_types_inferrer.dart';
import 'type_graph_dump.dart';
+import 'type_graph_inferrer.dart';
import 'type_graph_nodes.dart';
+import 'type_system.dart';
-class TypeInformationSystem extends TypeSystem<TypeInformation> {
- final ClosedWorld closedWorld;
-
- /// [ElementTypeInformation]s for elements.
- final Map<Element, TypeInformation> typeInformations =
+/**
+ * An inferencing engine that computes a call graph of
+ * [TypeInformation] nodes by visiting the AST of the application, and
+ * then does the inferencing on the graph.
+ */
+class InferrerEngine {
+ final Map<Element, TypeInformation> defaultTypeOfParameter =
new Map<Element, TypeInformation>();
+ final List<CallSiteTypeInformation> allocatedCalls =
+ <CallSiteTypeInformation>[];
+ final WorkQueue workQueue = new WorkQueue();
+ final Element mainElement;
+ final Set<Element> analyzedElements = new Set<Element>();
- /// [ListTypeInformation] for allocated lists.
- final Map<ast.Node, TypeInformation> allocatedLists =
- new Map<ast.Node, TypeInformation>();
-
- /// [MapTypeInformation] for allocated Maps.
- final Map<ast.Node, TypeInformation> allocatedMaps =
- new Map<ast.Node, TypeInformation>();
-
- /// Closures found during the analysis.
- final Set<TypeInformation> allocatedClosures = new Set<TypeInformation>();
-
- /// Cache of [ConcreteTypeInformation].
- final Map<TypeMask, TypeInformation> concreteTypes =
- new Map<TypeMask, TypeInformation>();
-
- /// List of [TypeInformation]s allocated inside method bodies (calls,
- /// narrowing, phis, and containers).
- final List<TypeInformation> allocatedTypes = <TypeInformation>[];
-
- Iterable<TypeInformation> get allTypes => [
- typeInformations.values,
- allocatedLists.values,
- allocatedMaps.values,
- allocatedClosures,
- concreteTypes.values,
- allocatedTypes
- ].expand((x) => x);
-
- TypeInformationSystem(this.closedWorld) {
- nonNullEmptyType = getConcreteTypeFor(commonMasks.emptyType);
- }
-
- CommonMasks get commonMasks => closedWorld.commonMasks;
-
- /// Used to group [TypeInformation] nodes by the element that triggered their
- /// creation.
- MemberTypeInformation _currentMember = null;
- MemberTypeInformation get currentMember => _currentMember;
-
- void withMember(MemberElement element, action) {
- assert(invariant(element, _currentMember == null,
- message: "Already constructing graph for $_currentMember."));
- _currentMember = getInferredTypeOf(element);
- action();
- _currentMember = null;
- }
-
- TypeInformation nullTypeCache;
- TypeInformation get nullType {
- if (nullTypeCache != null) return nullTypeCache;
- return nullTypeCache = getConcreteTypeFor(commonMasks.nullType);
- }
-
- TypeInformation intTypeCache;
- TypeInformation get intType {
- if (intTypeCache != null) return intTypeCache;
- return intTypeCache = getConcreteTypeFor(commonMasks.intType);
- }
-
- TypeInformation uint32TypeCache;
- TypeInformation get uint32Type {
- if (uint32TypeCache != null) return uint32TypeCache;
- return uint32TypeCache = getConcreteTypeFor(commonMasks.uint32Type);
- }
-
- TypeInformation uint31TypeCache;
- TypeInformation get uint31Type {
- if (uint31TypeCache != null) return uint31TypeCache;
- return uint31TypeCache = getConcreteTypeFor(commonMasks.uint31Type);
- }
-
- TypeInformation positiveIntTypeCache;
- TypeInformation get positiveIntType {
- if (positiveIntTypeCache != null) return positiveIntTypeCache;
- return positiveIntTypeCache =
- getConcreteTypeFor(commonMasks.positiveIntType);
- }
-
- TypeInformation doubleTypeCache;
- TypeInformation get doubleType {
- if (doubleTypeCache != null) return doubleTypeCache;
- return doubleTypeCache = getConcreteTypeFor(commonMasks.doubleType);
- }
-
- TypeInformation numTypeCache;
- TypeInformation get numType {
- if (numTypeCache != null) return numTypeCache;
- return numTypeCache = getConcreteTypeFor(commonMasks.numType);
- }
-
- TypeInformation boolTypeCache;
- TypeInformation get boolType {
- if (boolTypeCache != null) return boolTypeCache;
- return boolTypeCache = getConcreteTypeFor(commonMasks.boolType);
- }
-
- TypeInformation functionTypeCache;
- TypeInformation get functionType {
- if (functionTypeCache != null) return functionTypeCache;
- return functionTypeCache = getConcreteTypeFor(commonMasks.functionType);
- }
-
- TypeInformation listTypeCache;
- TypeInformation get listType {
- if (listTypeCache != null) return listTypeCache;
- return listTypeCache = getConcreteTypeFor(commonMasks.listType);
- }
-
- TypeInformation constListTypeCache;
- TypeInformation get constListType {
- if (constListTypeCache != null) return constListTypeCache;
- return constListTypeCache = getConcreteTypeFor(commonMasks.constListType);
- }
-
- TypeInformation fixedListTypeCache;
- TypeInformation get fixedListType {
- if (fixedListTypeCache != null) return fixedListTypeCache;
- return fixedListTypeCache = getConcreteTypeFor(commonMasks.fixedListType);
- }
-
- TypeInformation growableListTypeCache;
- TypeInformation get growableListType {
- if (growableListTypeCache != null) return growableListTypeCache;
- return growableListTypeCache =
- getConcreteTypeFor(commonMasks.growableListType);
- }
-
- TypeInformation mapTypeCache;
- TypeInformation get mapType {
- if (mapTypeCache != null) return mapTypeCache;
- return mapTypeCache = getConcreteTypeFor(commonMasks.mapType);
- }
-
- TypeInformation constMapTypeCache;
- TypeInformation get constMapType {
- if (constMapTypeCache != null) return constMapTypeCache;
- return constMapTypeCache = getConcreteTypeFor(commonMasks.constMapType);
- }
-
- TypeInformation stringTypeCache;
- TypeInformation get stringType {
- if (stringTypeCache != null) return stringTypeCache;
- return stringTypeCache = getConcreteTypeFor(commonMasks.stringType);
- }
-
- TypeInformation typeTypeCache;
- TypeInformation get typeType {
- if (typeTypeCache != null) return typeTypeCache;
- return typeTypeCache = getConcreteTypeFor(commonMasks.typeType);
- }
+ /// The maximum number of times we allow a node in the graph to
+ /// change types. If a node reaches that limit, we give up
+ /// inferencing on it and give it the dynamic type.
+ final int MAX_CHANGE_COUNT = 6;
- TypeInformation dynamicTypeCache;
- TypeInformation get dynamicType {
- if (dynamicTypeCache != null) return dynamicTypeCache;
- return dynamicTypeCache = getConcreteTypeFor(commonMasks.dynamicType);
- }
+ int overallRefineCount = 0;
+ int addedInGraph = 0;
- TypeInformation asyncFutureTypeCache;
- TypeInformation get asyncFutureType {
- if (asyncFutureTypeCache != null) return asyncFutureTypeCache;
- return asyncFutureTypeCache =
- getConcreteTypeFor(commonMasks.asyncFutureType);
- }
+ final Compiler compiler;
- TypeInformation syncStarIterableTypeCache;
- TypeInformation get syncStarIterableType {
- if (syncStarIterableTypeCache != null) return syncStarIterableTypeCache;
- return syncStarIterableTypeCache =
- getConcreteTypeFor(commonMasks.syncStarIterableType);
- }
+ /// The [ClosedWorld] on which inference reasoning is based.
+ final ClosedWorld closedWorld;
- TypeInformation asyncStarStreamTypeCache;
- TypeInformation get asyncStarStreamType {
- if (asyncStarStreamTypeCache != null) return asyncStarStreamTypeCache;
- return asyncStarStreamTypeCache =
- getConcreteTypeFor(commonMasks.asyncStarStreamType);
- }
+ final ClosedWorldRefiner closedWorldRefiner;
+ final TypeSystem types;
+ final Map<ast.Node, TypeInformation> concreteTypes =
+ new Map<ast.Node, TypeInformation>();
+ final Set<Element> generativeConstructorsExposingThis = new Set<Element>();
- TypeInformation nonNullEmptyType;
+ /// Data computed internally within elements, like the type-mask of a send a
+ /// list allocation, or a for-in loop.
+ final Map<Element, GlobalTypeInferenceElementData> inTreeData =
+ new Map<Element, GlobalTypeInferenceElementData>();
- TypeInformation stringLiteralType(DartString value) {
- return new StringLiteralTypeInformation(value, commonMasks.stringType);
- }
+ InferrerEngine(this.compiler, ClosedWorld closedWorld,
+ this.closedWorldRefiner, this.mainElement)
+ : this.types = new TypeSystem(closedWorld),
+ this.closedWorld = closedWorld;
- TypeInformation boolLiteralType(ast.LiteralBool value) {
- return new BoolLiteralTypeInformation(value, commonMasks.boolType);
- }
+ CommonElements get commonElements => closedWorld.commonElements;
- TypeInformation computeLUB(
- TypeInformation firstType, TypeInformation secondType) {
- if (firstType == null) return secondType;
- if (firstType == secondType) return firstType;
- if (firstType == nonNullEmptyType) return secondType;
- if (secondType == nonNullEmptyType) return firstType;
- if (firstType == dynamicType || secondType == dynamicType) {
- return dynamicType;
+ /**
+ * Applies [f] to all elements in the universe that match
+ * [selector] and [mask]. If [f] returns false, aborts the iteration.
+ */
+ void forEachElementMatching(
+ Selector selector, TypeMask mask, bool f(Element element)) {
+ Iterable<Element> elements =
+ closedWorld.allFunctions.filter(selector, mask);
+ for (Element e in elements) {
+ if (!f(e.implementation)) return;
}
- return getConcreteTypeFor(
- firstType.type.union(secondType.type, closedWorld));
- }
-
- bool selectorNeedsUpdate(TypeInformation info, TypeMask mask) {
- return info.type != mask;
}
- TypeInformation refineReceiver(Selector selector, TypeMask mask,
- TypeInformation receiver, bool isConditional) {
- if (receiver.type.isExact) return receiver;
- TypeMask otherType = closedWorld.allFunctions.receiverType(selector, mask);
- // Conditional sends (a?.b) can still narrow the possible types of `a`,
- // however, we still need to consider that `a` may be null.
- if (isConditional) {
- // Note: we don't check that receiver.type.isNullable here because this is
- // called during the graph construction.
- otherType = otherType.nullable();
- }
- // If this is refining to nullable subtype of `Object` just return
- // the receiver. We know the narrowing is useless.
- if (otherType.isNullable && otherType.containsAll(closedWorld)) {
- return receiver;
- }
- assert(TypeMask.assertIsNormalized(otherType, closedWorld));
- TypeInformation newType = new NarrowTypeInformation(receiver, otherType);
- allocatedTypes.add(newType);
- return newType;
- }
+ // TODO(johnniwinther): Make this private again.
+ GlobalTypeInferenceElementData dataOf(AstElement element) => inTreeData
+ .putIfAbsent(element, () => new GlobalTypeInferenceElementData());
- TypeInformation narrowType(
- TypeInformation type, ResolutionDartType annotation,
- {bool isNullable: true}) {
- if (annotation.treatAsDynamic) return type;
- if (annotation.isVoid) return nullType;
- if (annotation.element == closedWorld.commonElements.objectClass &&
- isNullable) {
- return type;
- }
- TypeMask otherType;
- if (annotation.isTypedef || annotation.isFunctionType) {
- otherType = functionType.type;
- } else if (annotation.isTypeVariable) {
- // TODO(ngeoffray): Narrow to bound.
- return type;
- } else {
- assert(annotation.isInterfaceType);
- otherType = annotation.element == closedWorld.commonElements.objectClass
- ? dynamicType.type.nonNullable()
- : new TypeMask.nonNullSubtype(annotation.element, closedWorld);
- }
- if (isNullable) otherType = otherType.nullable();
- if (type.type.isExact) {
- return type;
+ /**
+ * Update [sideEffects] with the side effects of [callee] being
+ * called with [selector].
+ */
+ void updateSideEffects(
+ SideEffects sideEffects, Selector selector, Element callee) {
+ if (callee.isField) {
+ if (callee.isInstanceMember) {
+ if (selector.isSetter) {
+ sideEffects.setChangesInstanceProperty();
+ } else if (selector.isGetter) {
+ sideEffects.setDependsOnInstancePropertyStore();
+ } else {
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
+ }
+ } else {
+ if (selector.isSetter) {
+ sideEffects.setChangesStaticProperty();
+ } else if (selector.isGetter) {
+ sideEffects.setDependsOnStaticPropertyStore();
+ } else {
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
+ }
+ }
+ } else if (callee.isGetter && !selector.isGetter) {
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
} else {
- assert(TypeMask.assertIsNormalized(otherType, closedWorld));
- TypeInformation newType = new NarrowTypeInformation(type, otherType);
- allocatedTypes.add(newType);
- return newType;
+ sideEffects.add(closedWorldRefiner.getCurrentlyKnownSideEffects(callee));
}
}
- TypeInformation narrowNotNull(TypeInformation type) {
- if (type.type.isExact && !type.type.isNullable) {
- return type;
+ /**
+ * Returns the type for [nativeBehavior]. See documentation on
+ * [native.NativeBehavior].
+ */
+ TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior) {
+ if (nativeBehavior == null) return types.dynamicType;
+ List typesReturned = nativeBehavior.typesReturned;
+ if (typesReturned.isEmpty) return types.dynamicType;
+ TypeInformation returnType;
+ for (var type in typesReturned) {
+ TypeInformation mappedType;
+ if (type == native.SpecialType.JsObject) {
+ mappedType = types.nonNullExact(commonElements.objectClass);
+ } else if (type == commonElements.stringType) {
+ mappedType = types.stringType;
+ } else if (type == commonElements.intType) {
+ mappedType = types.intType;
+ } else if (type == commonElements.numType ||
+ type == commonElements.doubleType) {
+ // Note: the backend double class is specifically for non-integer
+ // doubles, and a native behavior returning 'double' does not guarantee
+ // a non-integer return type, so we return the number type for those.
+ mappedType = types.numType;
+ } else if (type == commonElements.boolType) {
+ mappedType = types.boolType;
+ } else if (type == commonElements.nullType) {
+ mappedType = types.nullType;
+ } else if (type.isVoid) {
+ mappedType = types.nullType;
+ } else if (type.isDynamic) {
+ return types.dynamicType;
+ } else {
+ mappedType = types.nonNullSubtype(type.element);
+ }
+ returnType = types.computeLUB(returnType, mappedType);
+ if (returnType == types.dynamicType) {
+ break;
+ }
}
- TypeInformation newType =
- new NarrowTypeInformation(type, dynamicType.type.nonNullable());
- allocatedTypes.add(newType);
- return newType;
- }
-
- ElementTypeInformation getInferredTypeOf(Element element) {
- element = element.implementation;
- return typeInformations.putIfAbsent(element, () {
- return new ElementTypeInformation(element, this);
- });
- }
-
- ConcreteTypeInformation getConcreteTypeFor(TypeMask mask) {
- assert(mask != null);
- return concreteTypes.putIfAbsent(mask, () {
- return new ConcreteTypeInformation(mask);
- });
- }
-
- String getInferredSignatureOf(FunctionElement function) {
- ElementTypeInformation info = getInferredTypeOf(function);
- FunctionElement impl = function.implementation;
- FunctionSignature signature = impl.functionSignature;
- var res = "";
- signature.forEachParameter((Element parameter) {
- TypeInformation type = getInferredTypeOf(parameter);
- res += "${res.isEmpty ? '(' : ', '}${type.type} ${parameter.name}";
- });
- res += ") -> ${info.type}";
- return res;
- }
-
- TypeInformation nonNullSubtype(ClassElement type) {
- return getConcreteTypeFor(
- new TypeMask.nonNullSubtype(type.declaration, closedWorld));
- }
-
- TypeInformation nonNullSubclass(ClassElement type) {
- return getConcreteTypeFor(
- new TypeMask.nonNullSubclass(type.declaration, closedWorld));
- }
-
- TypeInformation nonNullExact(ClassElement type) {
- return getConcreteTypeFor(
- new TypeMask.nonNullExact(type.declaration, closedWorld));
- }
-
- TypeInformation nonNullEmpty() {
- return nonNullEmptyType;
- }
-
- bool isNull(TypeInformation type) {
- return type == nullType;
- }
-
- TypeInformation allocateList(
- TypeInformation type, ast.Node node, Element enclosing,
- [TypeInformation elementType, int length]) {
- ClassElement typedDataClass = closedWorld.commonElements.typedDataClass;
- bool isTypedArray = typedDataClass != null &&
- closedWorld.isInstantiated(typedDataClass) &&
- type.type.satisfies(typedDataClass, closedWorld);
- bool isConst = (type.type == commonMasks.constListType);
- bool isFixed =
- (type.type == commonMasks.fixedListType) || isConst || isTypedArray;
- bool isElementInferred = isConst || isTypedArray;
-
- int inferredLength = isFixed ? length : null;
- TypeMask elementTypeMask =
- isElementInferred ? elementType.type : dynamicType.type;
- ContainerTypeMask mask = new ContainerTypeMask(
- type.type, node, enclosing, elementTypeMask, inferredLength);
- ElementInContainerTypeInformation element =
- new ElementInContainerTypeInformation(currentMember, elementType);
- element.inferred = isElementInferred;
-
- allocatedTypes.add(element);
- return allocatedLists[node] =
- new ListTypeInformation(currentMember, mask, element, length);
- }
-
- TypeInformation allocateClosure(ast.Node node, Element element) {
- TypeInformation result =
- new ClosureTypeInformation(currentMember, node, element);
- allocatedClosures.add(result);
- return result;
- }
-
- TypeInformation allocateMap(
- ConcreteTypeInformation type, ast.Node node, Element element,
- [List<TypeInformation> keyTypes, List<TypeInformation> valueTypes]) {
- assert(keyTypes.length == valueTypes.length);
- bool isFixed = (type.type == commonMasks.constMapType);
-
- TypeMask keyType, valueType;
- if (isFixed) {
- keyType = keyTypes.fold(nonNullEmptyType.type,
- (type, info) => type.union(info.type, closedWorld));
- valueType = valueTypes.fold(nonNullEmptyType.type,
- (type, info) => type.union(info.type, closedWorld));
+ return returnType;
+ }
+
+ // TODO(johnniwinther): Pass the [ResolvedAst] instead of [owner].
+ void updateSelectorInTree(
+ AstElement owner, Spannable node, Selector selector, TypeMask mask) {
+ ast.Node astNode = node;
+ GlobalTypeInferenceElementData data = dataOf(owner);
+ if (astNode.asSendSet() != null) {
+ if (selector.isSetter || selector.isIndexSet) {
+ data.setTypeMask(node, mask);
+ } else if (selector.isGetter || selector.isIndex) {
+ data.setGetterTypeMaskInComplexSendSet(node, mask);
+ } else {
+ assert(selector.isOperator);
+ data.setOperatorTypeMaskInComplexSendSet(node, mask);
+ }
+ } else if (astNode.asSend() != null) {
+ data.setTypeMask(node, mask);
} else {
- keyType = valueType = dynamicType.type;
- }
- MapTypeMask mask =
- new MapTypeMask(type.type, node, element, keyType, valueType);
-
- TypeInformation keyTypeInfo =
- new KeyInMapTypeInformation(currentMember, null);
- TypeInformation valueTypeInfo =
- new ValueInMapTypeInformation(currentMember, null);
- allocatedTypes.add(keyTypeInfo);
- allocatedTypes.add(valueTypeInfo);
-
- MapTypeInformation map =
- new MapTypeInformation(currentMember, mask, keyTypeInfo, valueTypeInfo);
-
- for (int i = 0; i < keyTypes.length; ++i) {
- TypeInformation newType =
- map.addEntryAssignment(keyTypes[i], valueTypes[i], true);
- if (newType != null) allocatedTypes.add(newType);
- }
-
- // Shortcut: If we already have a first approximation of the key/value type,
- // start propagating it early.
- if (isFixed) map.markAsInferred();
-
- allocatedMaps[node] = map;
- return map;
- }
-
- TypeMask newTypedSelector(TypeInformation info, TypeMask mask) {
- // Only type the selector if [info] is concrete, because the other
- // kinds of [TypeInformation] have the empty type at this point of
- // analysis.
- return info.isConcrete ? info.type : mask;
- }
-
- TypeInformation allocateDiamondPhi(
- TypeInformation firstInput, TypeInformation secondInput) {
- PhiElementTypeInformation result =
- new PhiElementTypeInformation(currentMember, null, false, null);
- result.addAssignment(firstInput);
- result.addAssignment(secondInput);
- allocatedTypes.add(result);
- return result;
- }
-
- PhiElementTypeInformation _addPhi(
- ast.Node node, Local variable, inputType, bool isLoop) {
- PhiElementTypeInformation result =
- new PhiElementTypeInformation(currentMember, node, isLoop, variable);
- allocatedTypes.add(result);
- result.addAssignment(inputType);
- return result;
- }
-
- PhiElementTypeInformation allocatePhi(
- ast.Node node, Local variable, inputType) {
- // Check if [inputType] is a phi for a local updated in
- // the try/catch block [node]. If it is, no need to allocate a new
- // phi.
- if (inputType is PhiElementTypeInformation &&
- inputType.branchNode == node &&
- inputType.branchNode is ast.TryStatement) {
- return inputType;
+ assert(astNode.asForIn() != null);
+ if (selector == Selectors.iterator) {
+ data.setIteratorTypeMask(node, mask);
+ } else if (selector == Selectors.current) {
+ data.setCurrentTypeMask(node, mask);
+ } else {
+ assert(selector == Selectors.moveNext);
+ data.setMoveNextTypeMask(node, mask);
+ }
}
- return _addPhi(node, variable, inputType, false);
- }
-
- PhiElementTypeInformation allocateLoopPhi(
- ast.Node node, Local variable, inputType) {
- return _addPhi(node, variable, inputType, true);
}
- TypeInformation simplifyPhi(
- ast.Node node, Local variable, PhiElementTypeInformation phiType) {
- assert(phiType.branchNode == node);
- if (phiType.assignments.length == 1) return phiType.assignments.first;
- return phiType;
+ bool isNativeElement(Element element) {
+ return compiler.backend.isNative(element);
}
- PhiElementTypeInformation addPhiInput(Local variable,
- PhiElementTypeInformation phiType, TypeInformation newType) {
- phiType.addAssignment(newType);
- return phiType;
- }
-
- TypeMask computeTypeMask(Iterable<TypeInformation> assignments) {
- return joinTypeMasks(assignments.map((e) => e.type));
+ bool checkIfExposesThis(Element element) {
+ element = element.implementation;
+ return generativeConstructorsExposingThis.contains(element);
}
- TypeMask joinTypeMasks(Iterable<TypeMask> masks) {
- var dynamicType = commonMasks.dynamicType;
- // Optimization: we are iterating over masks twice, but because `masks` is a
- // mapped iterable, we save the intermediate results to avoid computing them
- // again.
- var list = [];
- for (TypeMask mask in masks) {
- // Don't do any work on computing unions if we know that after all that
- // work the result will be `dynamic`.
- // TODO(sigmund): change to `mask == dynamicType` so we can continue to
- // track the non-nullable bit.
- if (mask.containsAll(closedWorld)) return dynamicType;
- list.add(mask);
- }
-
- TypeMask newType = null;
- for (TypeMask mask in list) {
- newType = newType == null ? mask : newType.union(mask, closedWorld);
- // Likewise - stop early if we already reach dynamic.
- if (newType.containsAll(closedWorld)) return dynamicType;
+ void recordExposesThis(Element element, bool exposesThis) {
+ element = element.implementation;
+ if (exposesThis) {
+ generativeConstructorsExposingThis.add(element);
}
-
- return newType ?? const TypeMask.nonNullEmpty();
}
-}
-
-/**
- * A work queue for the inferrer. It filters out nodes that are tagged as
- * [TypeInformation.doNotEnqueue], as well as ensures through
- * [TypeInformation.inQueue] that a node is in the queue only once at
- * a time.
- */
-class WorkQueue {
- final Queue<TypeInformation> queue = new Queue<TypeInformation>();
-
- void add(TypeInformation element) {
- if (element.doNotEnqueue) return;
- if (element.inQueue) return;
- queue.addLast(element);
- element.inQueue = true;
- }
-
- void addAll(Iterable<TypeInformation> all) {
- all.forEach(add);
- }
-
- TypeInformation remove() {
- TypeInformation element = queue.removeFirst();
- element.inQueue = false;
- return element;
- }
-
- bool get isEmpty => queue.isEmpty;
-
- int get length => queue.length;
-}
-
-/**
- * An inferencing engine that computes a call graph of
- * [TypeInformation] nodes by visiting the AST of the application, and
- * then does the inferencing on the graph.
- *
- */
-class TypeGraphInferrerEngine
- extends InferrerEngine<TypeInformation, TypeInformationSystem> {
- final Map<Element, TypeInformation> defaultTypeOfParameter =
- new Map<Element, TypeInformation>();
- final List<CallSiteTypeInformation> allocatedCalls =
- <CallSiteTypeInformation>[];
- final WorkQueue workQueue = new WorkQueue();
- final Element mainElement;
- final Set<Element> analyzedElements = new Set<Element>();
-
- /// The maximum number of times we allow a node in the graph to
- /// change types. If a node reaches that limit, we give up
- /// inferencing on it and give it the dynamic type.
- final int MAX_CHANGE_COUNT = 6;
-
- int overallRefineCount = 0;
- int addedInGraph = 0;
-
- TypeGraphInferrerEngine(Compiler compiler, ClosedWorld closedWorld,
- ClosedWorldRefiner closedWorldRefiner, this.mainElement)
- : super(compiler, closedWorld, closedWorldRefiner,
- new TypeInformationSystem(closedWorld));
JavaScriptBackend get backend => compiler.backend;
Annotations get annotations => backend.annotations;
@@ -727,7 +358,7 @@ class TypeGraphInferrerEngine
if (debug.VERBOSE) {
print("traced closure $e as "
"${closedWorldRefiner
- .getCurrentlyKnownMightBePassedToApply(e)}");
+ .getCurrentlyKnownMightBePassedToApply(e)}");
}
});
}
@@ -1086,39 +717,63 @@ class TypeGraphInferrerEngine
}
/**
- * Helper to inspect the [TypeGraphInferrer]'s state. To be removed by
- * TODO(johnniwinther) once synthetic parameters get their own default
- * values.
+ * This helper breaks abstractions but is currently required to work around
+ * the wrong modeling of default values of optional parameters of
+ * synthetic constructors.
+ *
+ * TODO(johnniwinther): Remove once default values of synthetic parameters
+ * are fixed.
*/
bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) {
TypeInformation seen = defaultTypeOfParameter[parameter];
return (seen != null && seen is! PlaceholderTypeInformation);
}
+ /**
+ * Returns the type of [element].
+ */
TypeInformation typeOfElement(Element element) {
if (element is FunctionElement) return types.functionType;
return types.getInferredTypeOf(element);
}
+ /**
+ * Returns the return type of [element].
+ */
TypeInformation returnTypeOfElement(Element element) {
if (element is! FunctionElement) return types.dynamicType;
return types.getInferredTypeOf(element);
}
+ /**
+ * Records that [node] sets final field [element] to be of type [type].
+ *
+ * [nodeHolder] is the element holder of [node].
+ */
void recordTypeOfFinalField(
Spannable node, Element analyzed, Element element, TypeInformation type) {
types.getInferredTypeOf(element).addAssignment(type);
}
+ /**
+ * Records that [node] sets non-final field [element] to be of type
+ * [type].
+ */
void recordTypeOfNonFinalField(
Spannable node, Element element, TypeInformation type) {
types.getInferredTypeOf(element).addAssignment(type);
}
+ /**
+ * Records that [element] is of type [type].
+ */
void recordType(Element element, TypeInformation type) {
types.getInferredTypeOf(element).addAssignment(type);
}
+ /**
+ * Records that the return type [element] is of type [type].
+ */
void recordReturnType(Element element, TypeInformation type) {
TypeInformation info = types.getInferredTypeOf(element);
if (element.name == '==') {
@@ -1131,6 +786,13 @@ class TypeGraphInferrerEngine
if (info.assignments.isEmpty) info.addAssignment(type);
}
+ /**
+ * Notifies to the inferrer that [analyzedElement] can have return
+ * type [newType]. [currentType] is the type the [InferrerVisitor]
+ * currently found.
+ *
+ * Returns the new type for [analyzedElement].
+ */
TypeInformation addReturnTypeFor(
Element element, TypeInformation unused, TypeInformation newType) {
TypeInformation type = types.getInferredTypeOf(element);
@@ -1141,6 +803,16 @@ class TypeGraphInferrerEngine
return type;
}
+ /**
+ * Registers that [caller] calls [callee] at location [node], with
+ * [selector], and [arguments]. Note that [selector] is null for
+ * forwarding constructors.
+ *
+ * [sideEffects] will be updated to incorporate [callee]'s side
+ * effects.
+ *
+ * [inLoop] tells whether the call happens in a loop.
+ */
TypeInformation registerCalledElement(
Spannable node,
Selector selector,
@@ -1173,6 +845,15 @@ class TypeGraphInferrerEngine
return info;
}
+ /**
+ * Registers that [caller] calls [selector] with [receiverType] as
+ * receiver, and [arguments].
+ *
+ * [sideEffects] will be updated to incorporate the potential
+ * callees' side effects.
+ *
+ * [inLoop] tells whether the call happens in a loop.
+ */
TypeInformation registerCalledSelector(
ast.Node node,
Selector selector,
@@ -1206,6 +887,10 @@ class TypeGraphInferrerEngine
return info;
}
+ /**
+ * Registers a call to await with an expression of type [argumentType] as
+ * argument.
+ */
TypeInformation registerAwait(ast.Node node, TypeInformation argument) {
AwaitTypeInformation info =
new AwaitTypeInformation(types.currentMember, node);
@@ -1214,6 +899,14 @@ class TypeGraphInferrerEngine
return info;
}
+ /**
+ * Registers that [caller] calls [closure] with [arguments].
+ *
+ * [sideEffects] will be updated to incorporate the potential
+ * callees' side effects.
+ *
+ * [inLoop] tells whether the call happens in a loop.
+ */
TypeInformation registerCalledClosure(
ast.Node node,
Selector selector,
@@ -1346,102 +1039,13 @@ class TypeGraphInferrerEngine
}
}
+ /**
+ * Records that the captured variable [local] is read.
+ */
void recordCapturedLocalRead(Local local) {}
+ /**
+ * Records that the variable [local] is being updated.
+ */
void recordLocalUpdate(Local local, TypeInformation type) {}
}
-
-class TypeGraphInferrer implements TypesInferrer {
- TypeGraphInferrerEngine inferrer;
- final Compiler compiler;
- final ClosedWorld closedWorld;
- final ClosedWorldRefiner closedWorldRefiner;
-
- TypeGraphInferrer(this.compiler, this.closedWorld, this.closedWorldRefiner);
-
- String get name => 'Graph inferrer';
-
- CommonMasks get commonMasks => closedWorld.commonMasks;
-
- TypeMask get _dynamicType => commonMasks.dynamicType;
-
- void analyzeMain(Element main) {
- inferrer = new TypeGraphInferrerEngine(
- compiler, closedWorld, closedWorldRefiner, main);
- inferrer.runOverAllElements();
- }
-
- TypeMask getReturnTypeOfElement(Element element) {
- if (compiler.disableTypeInference) return _dynamicType;
- // Currently, closure calls return dynamic.
- if (element is! FunctionElement) return _dynamicType;
- return inferrer.types.getInferredTypeOf(element).type;
- }
-
- TypeMask getTypeOfElement(Element element) {
- if (compiler.disableTypeInference) return _dynamicType;
- // The inferrer stores the return type for a function, so we have to
- // be careful to not return it here.
- if (element is FunctionElement) return commonMasks.functionType;
- return inferrer.types.getInferredTypeOf(element).type;
- }
-
- TypeMask getTypeForNewList(Element owner, ast.Node node) {
- if (compiler.disableTypeInference) return _dynamicType;
- return inferrer.types.allocatedLists[node].type;
- }
-
- bool isFixedArrayCheckedForGrowable(ast.Node node) {
- if (compiler.disableTypeInference) return true;
- ListTypeInformation info = inferrer.types.allocatedLists[node];
- return info.checksGrowable;
- }
-
- TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
- if (compiler.disableTypeInference) return _dynamicType;
- // Bailout for closure calls. We're not tracking types of
- // closures.
- if (selector.isClosureCall) return _dynamicType;
- if (selector.isSetter || selector.isIndexSet) {
- return _dynamicType;
- }
- if (inferrer.returnsListElementType(selector, mask)) {
- ContainerTypeMask containerTypeMask = mask;
- TypeMask elementType = containerTypeMask.elementType;
- return elementType == null ? _dynamicType : elementType;
- }
- if (inferrer.returnsMapValueType(selector, mask)) {
- MapTypeMask mapTypeMask = mask;
- TypeMask valueType = mapTypeMask.valueType;
- return valueType == null ? _dynamicType : valueType;
- }
-
- TypeMask result = const TypeMask.nonNullEmpty();
- Iterable<Element> elements =
- inferrer.closedWorld.allFunctions.filter(selector, mask);
- for (Element element in elements) {
- TypeMask type =
- inferrer.typeOfElementWithSelector(element, selector).type;
- result = result.union(type, inferrer.closedWorld);
- }
- return result;
- }
-
- Iterable<Element> getCallersOf(Element element) {
- if (compiler.disableTypeInference) {
- throw new UnsupportedError(
- "Cannot query the type inferrer when type inference is disabled.");
- }
- return inferrer.getCallersOf(element);
- }
-
- bool isCalledOnce(Element element) {
- if (compiler.disableTypeInference) return false;
- MemberTypeInformation info = inferrer.types.getInferredTypeOf(element);
- return info.isCalledOnce();
- }
-
- void clear() {
- inferrer.clear();
- }
-}
« no previous file with comments | « pkg/compiler/lib/src/inferrer/closure_tracer.dart ('k') | pkg/compiler/lib/src/inferrer/inferrer_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698