Use iterators "before" the use node in HUserRecord<>.
Create a new template class IntrusiveForwardList<> that
mimicks std::forward_list<> except that all allocations
are handled externally. This is essentially the same as
boost::intrusive::slist<> but since we're not using Boost
we have to reinvent the wheel.
Use the new container to replace the HUseList and use the
iterators to "before" use nodes in HUserRecord<> to avoid
the extra pointer to the previous node which was used
exclusively for removing nodes from the list. This reduces
the size of the HUseListNode by 25%, 32B to 24B in 64-bit
compiler, 16B to 12B in 32-bit compiler. This translates
directly to overall memory savings for the 64-bit compiler
but due to rounding up of the arena allocations to 8B, we
do not get any improvement in the 32-bit compiler.
Compiling the Nexus 5 boot image with the 64-bit dex2oat
on host this CL reduces the memory used for compiling the
most hungry method, BatteryStats.dumpLocked(), by ~3.3MiB:
Before:
MEM: used: 47829200, allocated: 48769120, lost: 939920
Number of arenas allocated: 345,
Number of allocations: 815492, avg size: 58
...
UseListNode 13744640
...
After:
MEM: used: 44393040, allocated: 45361248, lost: 968208
Number of arenas allocated: 319,
Number of allocations: 815492, avg size: 54
...
UseListNode 10308480
...
Note that while we do not ship the 64-bit dex2oat to the
device, the JIT compilation for 64-bit processes is using
the 64-bit libart-compiler.
Bug: 28173563
Change-Id: I985eabd4816f845372d8aaa825a1489cf9569208
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 95f10e0..cd4391d 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -187,8 +187,8 @@
if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
if (kIsDebugBuild) {
// Check that the existing HBoundType dominates all the uses.
- for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
- HInstruction* user = it.Current()->GetUser();
+ for (const HUseListNode<HInstruction*>& use : obj->GetUses()) {
+ HInstruction* user = use.GetUser();
if (dominator_instr != nullptr) {
DCHECK(!dominator_instr->StrictlyDominates(user)
|| user == existing_bound_type
@@ -242,8 +242,12 @@
? ifInstruction->IfTrueSuccessor()
: ifInstruction->IfFalseSuccessor();
- for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
- HInstruction* user = it.Current()->GetUser();
+ const HUseList<HInstruction*>& uses = obj->GetUses();
+ for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
+ HInstruction* user = it->GetUser();
+ size_t index = it->GetIndex();
+ // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
+ ++it;
if (notNullBlock->Dominates(user->GetBlock())) {
if (bound_type == nullptr) {
ScopedObjectAccess soa(Thread::Current());
@@ -264,7 +268,7 @@
break;
}
}
- user->ReplaceInput(bound_type, it.Current()->GetIndex());
+ user->ReplaceInput(bound_type, index);
}
}
}
@@ -379,8 +383,12 @@
return;
}
DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
- for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
- HInstruction* user = it.Current()->GetUser();
+ const HUseList<HInstruction*>& uses = obj->GetUses();
+ for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
+ HInstruction* user = it->GetUser();
+ size_t index = it->GetIndex();
+ // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
+ ++it;
if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
if (bound_type == nullptr) {
ScopedObjectAccess soa(Thread::Current());
@@ -396,7 +404,7 @@
break;
}
}
- user->ReplaceInput(bound_type, it.Current()->GetIndex());
+ user->ReplaceInput(bound_type, index);
}
}
}
@@ -887,8 +895,8 @@
}
void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
- for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
- HInstruction* user = it.Current()->GetUser();
+ for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
+ HInstruction* user = use.GetUser();
if ((user->IsPhi() && user->AsPhi()->IsLive())
|| user->IsBoundType()
|| user->IsNullCheck()