Optimizations around escape analysis. With tests.
Details:
(1) added new intrinsics
(2) implemented optimizations
more !can be null information
more null check removals
replace return-this uses with incoming parameter
remove dead StringBuffer/Builder calls (with escape analysis)
(3) Fixed exposed bug in CanBeMoved()
Performance gain:
This improves CafeineString by about 360%
(removes null check from first loop, eliminates second loop completely)
Test: test-art-host
Change-Id: Iaf16a1b9cab6a7386f43d71c6b51dd59600e81c1
diff --git a/compiler/optimizing/escape.cc b/compiler/optimizing/escape.cc
index c80e19e..9df5bf1 100644
--- a/compiler/optimizing/escape.cc
+++ b/compiler/optimizing/escape.cc
@@ -23,16 +23,19 @@
void CalculateEscape(HInstruction* reference,
bool (*no_escape)(HInstruction*, HInstruction*),
/*out*/ bool* is_singleton,
- /*out*/ bool* is_singleton_and_non_escaping) {
+ /*out*/ bool* is_singleton_and_not_returned,
+ /*out*/ bool* is_singleton_and_not_deopt_visible) {
// For references not allocated in the method, don't assume anything.
if (!reference->IsNewInstance() && !reference->IsNewArray()) {
*is_singleton = false;
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_returned = false;
+ *is_singleton_and_not_deopt_visible = false;
return;
}
// Assume the best until proven otherwise.
*is_singleton = true;
- *is_singleton_and_non_escaping = true;
+ *is_singleton_and_not_returned = true;
+ *is_singleton_and_not_deopt_visible = true;
// Visit all uses to determine if this reference can escape into the heap,
// a method call, an alias, etc.
for (const HUseListNode<HInstruction*>& use : reference->GetUses()) {
@@ -45,7 +48,8 @@
// for the uncommon cases. Similarly, null checks are eventually eliminated for explicit
// allocations, but if we see one before it is simplified, assume an alias.
*is_singleton = false;
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_returned = false;
+ *is_singleton_and_not_deopt_visible = false;
return;
} else if (user->IsPhi() || user->IsSelect() || user->IsInvoke() ||
(user->IsInstanceFieldSet() && (reference == user->InputAt(1))) ||
@@ -56,7 +60,8 @@
// The reference is merged to HPhi/HSelect, passed to a callee, or stored to heap.
// Hence, the reference is no longer the only name that can refer to its value.
*is_singleton = false;
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_returned = false;
+ *is_singleton_and_not_deopt_visible = false;
return;
} else if ((user->IsUnresolvedInstanceFieldGet() && (reference == user->InputAt(0))) ||
(user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(0)))) {
@@ -64,37 +69,35 @@
// Note that we could optimize this case and still perform some optimizations until
// we hit the unresolved access, but the conservative assumption is the simplest.
*is_singleton = false;
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_returned = false;
+ *is_singleton_and_not_deopt_visible = false;
return;
} else if (user->IsReturn()) {
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_returned = false;
}
}
- // Need for further analysis?
- if (!*is_singleton_and_non_escaping) {
- return;
- }
-
- // Look at the environment uses and if it's for HDeoptimize, it's treated the
- // same as a return which escapes at the end of executing the compiled code.
- // Other environment uses are fine, as long as all client optimizations that
- // rely on this informations are disabled for debuggable.
+ // Look at the environment uses if it's for HDeoptimize. Other environment uses are fine,
+ // as long as client optimizations that rely on this information are disabled for debuggable.
for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
HEnvironment* user = use.GetUser();
if (user->GetHolder()->IsDeoptimize()) {
- *is_singleton_and_non_escaping = false;
+ *is_singleton_and_not_deopt_visible = false;
break;
}
}
}
-bool IsNonEscapingSingleton(HInstruction* reference,
- bool (*no_escape)(HInstruction*, HInstruction*)) {
- bool is_singleton = true;
- bool is_singleton_and_non_escaping = true;
- CalculateEscape(reference, no_escape, &is_singleton, &is_singleton_and_non_escaping);
- return is_singleton_and_non_escaping;
+bool DoesNotEscape(HInstruction* reference, bool (*no_escape)(HInstruction*, HInstruction*)) {
+ bool is_singleton = false;
+ bool is_singleton_and_not_returned = false;
+ bool is_singleton_and_not_deopt_visible = false; // not relevant for escape
+ CalculateEscape(reference,
+ no_escape,
+ &is_singleton,
+ &is_singleton_and_not_returned,
+ &is_singleton_and_not_deopt_visible);
+ return is_singleton_and_not_returned;
}
} // namespace art