Index: pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
index 98a9309d35567c9fd3ce8f42a27751f82b804289..4e0dd845b91a1c0e02820e32b1dbdf10828a61c0 100644 |
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
@@ -237,6 +237,12 @@ abstract class TypeInformation { |
abandonInferencing = false; |
doNotEnqueue = false; |
} |
+ |
+ /// Destroys information not needed after type inference. |
+ void cleanup() { |
+ users = null; |
+ _assignments = null; |
+ } |
} |
abstract class ApplyableTypeInformation implements TypeInformation { |
@@ -385,6 +391,10 @@ class MemberTypeInformation extends ElementTypeInformation |
*/ |
int closurizedCount = 0; |
+ // Strict `bool` value is computed in cleanup(). Also used as a flag to see if |
+ // cleanup has been called. |
+ bool _isCalledOnce = null; |
+ |
/** |
* This map contains the callers of [element]. It stores all unique call sites |
* to enable counting the global number of call sites of [element]. |
@@ -392,18 +402,23 @@ class MemberTypeInformation extends ElementTypeInformation |
* A call site is either an AST [ast.Node], a [cps_ir.Node] or in the case of |
* synthesized calls, an [Element] (see uses of [synthesizeForwardingCall] |
* in [SimpleTypeInferrerVisitor]). |
+ * |
+ * The global information is summarized in [cleanup], after which [_callers] |
+ * is set to `null`. |
*/ |
- final Map<Element, Setlet<Spannable>> _callers = new Map<Element, Setlet>(); |
+ Map<Element, Setlet<Spannable>> _callers; |
MemberTypeInformation._internal(Element element) |
: super._internal(null, element); |
void addCall(Element caller, Spannable node) { |
assert(node is ast.Node || node is cps_ir.Node || node is Element); |
+ _callers ??= <Element, Setlet>{}; |
_callers.putIfAbsent(caller, () => new Setlet()).add(node); |
} |
void removeCall(Element caller, node) { |
+ if (_callers == null) return; |
Setlet calls = _callers[caller]; |
if (calls == null) return; |
calls.remove(node); |
@@ -412,9 +427,27 @@ class MemberTypeInformation extends ElementTypeInformation |
} |
} |
- Iterable<Element> get callers => _callers.keys; |
+ Iterable<Element> get callers { |
+ // TODO(sra): This is called only from an unused API and a test. If it |
+ // becomes used, [cleanup] will need to copy `_caller.keys`. |
+ |
+ // `simple_inferrer_callers_test.dart` ensures that cleanup has not |
+ // happened. |
+ return _callers.keys; |
+ } |
bool isCalledOnce() { |
+ // If this assert fires it means that this MemberTypeInformation for the |
+ // element was not part of type inference. This happens for |
+ // ConstructorBodyElements, so guard the call with a test for |
+ // ConstructorBodyElement. For other elements, investigate why the element |
+ // was not present for type inference. |
+ assert(_isCalledOnce != null); |
+ return _isCalledOnce ?? false; |
+ } |
+ |
+ bool _computeIsCalledOnce() { |
+ if (_callers == null) return false; |
int count = 0; |
for (var set in _callers.values) { |
count += set.length; |
@@ -530,6 +563,14 @@ class MemberTypeInformation extends ElementTypeInformation |
return super.hasStableType(inferrer); |
} |
+ |
+ void cleanup() { |
+ // This node is on multiple lists so cleanup() can be called twice. |
+ if (_isCalledOnce != null) return; |
+ _isCalledOnce = _computeIsCalledOnce(); |
+ _callers = null; |
+ super.cleanup(); |
+ } |
} |
/** |
@@ -1319,6 +1360,12 @@ class ListTypeInformation extends TypeInformation |
} |
TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; |
+ |
+ void cleanup() { |
+ super.cleanup(); |
+ elementType.cleanup(); |
+ _flowsInto = null; |
+ } |
} |
/** |
@@ -1482,6 +1529,16 @@ class MapTypeInformation extends TypeInformation |
super.hasStableType(inferrer); |
} |
+ void cleanup() { |
+ super.cleanup(); |
+ keyType.cleanup(); |
+ valueType.cleanup(); |
+ for (TypeInformation info in typeInfoMap.values) { |
+ info.cleanup(); |
+ } |
+ _flowsInto = null; |
+ } |
+ |
String toString() { |
return 'Map $type (K:$keyType, V:$valueType) contents $typeInfoMap'; |
} |