mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
dart2js: Destroy some type inference graph edges after type inference.
Removing the `_assignments` and `users` collections from TypeInformation nodes causes interior nodes (e.g. Phi, Narrow) to become unreachable and available for GC. This seems to trim 1%-5% off the final heap of an SSA compile. R=sigmund@google.com Review URL: https://codereview.chromium.org/1776533002 .
This commit is contained in:
parent
60ce67d91f
commit
e85ac19134
2 changed files with 66 additions and 3 deletions
|
@ -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<Element> getCallersOf(Element element) {
|
||||
|
|
|
@ -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,20 @@ class MemberTypeInformation extends ElementTypeInformation
|
|||
}
|
||||
}
|
||||
|
||||
Iterable<Element> get callers => _callers.keys;
|
||||
Iterable<Element> 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';
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue