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

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

Issue 2762493002: Type tracing bug fix for issue 28919. (Closed)
Patch Set: add type Created 3 years, 9 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/node_tracer.dart
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index 7f6ad9974a5440758c830241f82708669524a7a3..f4546032b2fcbed7c8aff65deb401753440aef67 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -244,77 +244,138 @@ abstract class TracerVisitor implements TypeInformationVisitor {
}
/**
- * Checks whether this is a call to a list adding method. The definition
- * of what list adding means has to stay in sync with
+ * Checks whether this is a call to a list adding method. The definition of
+ * what list adding means has to stay in sync with
* [isParameterOfListAddingMethod].
*/
- bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
+ bool mightAddToContainer(DynamicCallSiteTypeInformation info) {
if (info.arguments == null) return false;
- var receiverType = info.receiver.type;
- if (!receiverType.isContainer) return false;
+ if (info.arguments.named.isNotEmpty) return false;
String selectorName = info.selector.name;
List<TypeInformation> arguments = info.arguments.positional;
- return (selectorName == '[]=' && currentUser == arguments[1]) ||
- (selectorName == 'insert' && currentUser == arguments[1]) ||
- (selectorName == 'add' && currentUser == arguments[0]);
+ if (arguments.length == 1) {
+ return (selectorName == 'add' && currentUser == arguments[0]);
+ } else if (arguments.length == 2) {
+ return (selectorName == 'insert' && currentUser == arguments[1]);
+ }
+ return false;
}
- bool isIndexSetOnMap(DynamicCallSiteTypeInformation info) {
- if (info.arguments == null) return false;
- var receiverType = info.receiver.type;
- if (!receiverType.isMap) return false;
- return info.selector.name == '[]=';
+ bool isIndexSetArgument(DynamicCallSiteTypeInformation info, int index) {
+ String selectorName = info.selector.name;
+ if (selectorName != '[]=') return false;
+ assert(info.arguments.length == 2);
+ List<TypeInformation> arguments = info.arguments.positional;
+ return currentUser == arguments[index];
}
/**
- * Checks whether this is a call to a map adding method for values. The
- * definition of map adding method has to stay in sync with
+ * Checks whether the call site flows the currentUser to the key argument of
+ * an indexing setter. This must be kept in sync with
* [isParameterOfMapAddingMethod].
*/
- bool isValueAddedToMap(DynamicCallSiteTypeInformation info) {
- return isIndexSetOnMap(info) && currentUser == info.arguments.positional[1];
+ bool isIndexSetKey(DynamicCallSiteTypeInformation info) {
+ return isIndexSetArgument(info, 0);
}
/**
- * Checks whether this is a call to a map adding method for keys. The
- * definition of map adding method has to stay in sync with
- * [isParameterOfMapAddingMethod].
+ * Checks whether the call site flows the currentUser to the value argument of
+ * an indexing setter. This must be kept in sync with
+ * [isParameterOfListAddingMethod] and [isParameterOfMapAddingMethod].
*/
- bool isKeyAddedToMap(DynamicCallSiteTypeInformation info) {
- return isIndexSetOnMap(info) && currentUser == info.arguments.positional[0];
+ bool isIndexSetValue(DynamicCallSiteTypeInformation info) {
+ return isIndexSetArgument(info, 1);
+ }
+
+ void bailoutIfReaches(bool predicate(Element e)) {
+ for (var user in currentUser.users) {
+ if (user is ParameterTypeInformation) {
+ if (predicate(user.element)) {
+ bailout('Reached suppressed parameter without precise receiver');
+ break;
+ }
+ }
+ }
}
void visitDynamicCallSiteTypeInformation(
DynamicCallSiteTypeInformation info) {
- if (isAddedToContainer(info)) {
- ContainerTypeMask mask = info.receiver.type;
+ void addsToContainer(ContainerTypeMask mask) {
if (mask.allocationNode != null) {
ListTypeInformation list =
inferrer.types.allocatedLists[mask.allocationNode];
listsToAnalyze.add(list);
} else {
- // The [ContainerTypeMask] is a union of two containers, and
- // we lose track of where these containers have been allocated
- // at this point.
+ // The [ContainerTypeMask] is a union of two containers, and we lose
+ // track of where these containers have been allocated at this point.
bailout('Stored in too many containers');
}
- } else if (isValueAddedToMap(info)) {
- MapTypeMask mask = info.receiver.type;
+ }
+
+ void addsToMapValue(MapTypeMask mask) {
if (mask.allocationNode != null) {
MapTypeInformation map =
inferrer.types.allocatedMaps[mask.allocationNode];
mapsToAnalyze.add(map);
} else {
- // The [MapTypeMask] is a union. See comment for
- // [ContainerTypeMask] above.
+ // The [MapTypeMask] is a union. See comment for [ContainerTypeMask]
+ // above.
bailout('Stored in too many maps');
}
- } else if (isKeyAddedToMap(info)) {
+ }
+
+ void addsToMapKey(MapTypeMask mask) {
// We do not track the use of keys from a map, so we have to bail.
bailout('Used as key in Map');
}
+ // "a[...] = x" could be a list (container) or map assignemnt.
+ if (isIndexSetValue(info)) {
+ var receiverType = info.receiver.type;
+ if (receiverType is ContainerTypeMask) {
+ addsToContainer(receiverType);
+ } else if (receiverType is MapTypeMask) {
+ addsToMapValue(receiverType);
+ } else {
+ // Not a container or mask, so the targets could be any methods. There
Siggi Cherem (dart-lang) 2017/03/21 17:05:01 or mask => or map
sra1 2017/03/21 18:17:22 Done.
+ // are edges from the [currentUser] to the parameters of the targets, so
+ // tracing will continue into the targets. Tracing stops at parameters
+ // that match the targets corresponding to the receiverTypes above (to
+ // prevent imprecise results from tracing the implementation), so we
+ // need compensate if one of the targets is in the target set. If there
+ // is an edge to a parameter matching [isParameterOfListAddingMethod] or
+ // [isParameterOfMapAddingMethod] then the traced value is being stored
+ // into an untraced list or map.
+
+ // TODO(sra): It would be more precise to specifically match the `value'
+ // parameters of "operator []=".
+ bailoutIfReaches(isParameterOfListAddingMethod);
+ bailoutIfReaches(isParameterOfMapAddingMethod);
+ }
+ }
+
+ // Could be: m[x] = ...;
+ if (isIndexSetKey(info)) {
+ var receiverType = info.receiver.type;
+ if (receiverType is MapTypeMask) {
+ addsToMapKey(receiverType);
+ } else {
+ bailoutIfReaches(isParameterOfListAddingMethod);
Siggi Cherem (dart-lang) 2017/03/21 17:05:01 would this case ever occur? (since the key is like
sra1 2017/03/21 18:17:22 It could happen in code that would throw an except
+ bailoutIfReaches(isParameterOfMapAddingMethod);
+ }
+ }
+
+ if (mightAddToContainer(info)) {
+ var receiverType = info.receiver.type;
+ if (receiverType is ContainerTypeMask) {
+ addsToContainer(receiverType);
+ } else {
+ // Not a container, see note above.
+ bailoutIfReaches(isParameterOfListAddingMethod);
+ }
+ }
+
if (info.targetsIncludeComplexNoSuchMethod(inferrer) &&
info.arguments != null &&
info.arguments.contains(currentUser)) {
@@ -332,31 +393,29 @@ abstract class TracerVisitor implements TypeInformationVisitor {
/**
* Check whether element is the parameter of a list adding method.
* The definition of what a list adding method is has to stay in sync with
- * [isAddedToContainer].
+ * [mightAddToContainer].
*/
bool isParameterOfListAddingMethod(Element element) {
if (!element.isRegularParameter) return false;
if (element.enclosingClass != compiler.backend.backendClasses.listClass) {
return false;
}
- Element method = element.enclosingElement;
- return (method.name == '[]=') ||
- (method.name == 'add') ||
- (method.name == 'insert');
+ String name = element.enclosingElement.name;
+ return (name == '[]=') || (name == 'add') || (name == 'insert');
}
/**
* Check whether element is the parameter of a list adding method.
* The definition of what a list adding method is has to stay in sync with
- * [isValueAddedToMap] and [isKeyAddedToMap].
+ * [isIndexSetKey] and [isIndexSetValue].
*/
bool isParameterOfMapAddingMethod(Element element) {
if (!element.isRegularParameter) return false;
if (element.enclosingClass != compiler.backend.backendClasses.mapClass) {
return false;
}
- Element method = element.enclosingElement;
- return (method.name == '[]=');
+ String name = element.enclosingElement.name;
+ return (name == '[]=');
}
bool isClosure(Element element) {
@@ -399,8 +458,8 @@ abstract class TracerVisitor implements TypeInformationVisitor {
element.functionDeclaration)) {
bailout('Escape to code that has special backend treatment');
}
- if (isParameterOfListAddingMethod(info.element) ||
- isParameterOfMapAddingMethod(info.element)) {
+ if (isParameterOfListAddingMethod(element) ||
+ isParameterOfMapAddingMethod(element)) {
// These elements are being handled in
// [visitDynamicCallSiteTypeInformation].
return;
« no previous file with comments | « pkg/compiler/lib/src/inferrer/inferrer_engine.dart ('k') | pkg/compiler/lib/src/inferrer/type_graph_dump.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698