diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart index 68cf701ff14..418bd2d2372 100644 --- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart +++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart @@ -1287,14 +1287,28 @@ class TypeGraphInferrerEngine } void clear() { + void cleanup(TypeInformation info) => info.cleanup(); + + allocatedCalls.forEach(cleanup); allocatedCalls.clear(); + defaultTypeOfParameter.clear(); - types.typeInformations.values.forEach((info) => info.clear()); + + types.typeInformations.values.forEach(cleanup); + + types.allocatedTypes.forEach(cleanup); types.allocatedTypes.clear(); + types.concreteTypes.clear(); + + types.allocatedClosures.forEach(cleanup); types.allocatedClosures.clear(); + analyzedElements.clear(); generativeConstructorsExposingThis.clear(); + + types.allocatedMaps.values.forEach(cleanup); + types.allocatedLists.values.forEach(cleanup); } Iterable getCallersOf(Element element) { diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart index 98a9309d355..974e2d89d03 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> _callers = new Map(); + Map> _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 ??= {}; _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,20 @@ class MemberTypeInformation extends ElementTypeInformation } } - Iterable get callers => _callers.keys; + Iterable get callers { + // TODO(sra): This is called only from an unused API. If it becomes used, + // [cleanup] will need to copy `_caller.keys`. + assert(false); // Unused. + return _callers.keys; + } bool isCalledOnce() { + assert(_isCalledOnce != null); + return _isCalledOnce; + } + + bool _computeIsCalledOnce() { + if (_callers == null) return false; int count = 0; for (var set in _callers.values) { count += set.length; @@ -530,6 +556,13 @@ class MemberTypeInformation extends ElementTypeInformation return super.hasStableType(inferrer); } + + void cleanup() { + if (_isCalledOnce != null) return; + _isCalledOnce = _computeIsCalledOnce(); + _callers = null; + super.cleanup(); + } } /** @@ -1319,6 +1352,12 @@ class ListTypeInformation extends TypeInformation } TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; + + void cleanup() { + super.cleanup(); + elementType.cleanup(); + _flowsInto = null; + } } /** @@ -1482,6 +1521,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'; }