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:
Stephen Adams 2016-03-09 12:47:10 -08:00
parent 60ce67d91f
commit e85ac19134
2 changed files with 66 additions and 3 deletions

View file

@ -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) {

View file

@ -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';
}