diff options
Diffstat (limited to 'compiler/optimizing/escape.cc')
-rw-r--r-- | compiler/optimizing/escape.cc | 112 |
1 files changed, 72 insertions, 40 deletions
diff --git a/compiler/optimizing/escape.cc b/compiler/optimizing/escape.cc index 2b578c1cc8..f3f5b15d99 100644 --- a/compiler/optimizing/escape.cc +++ b/compiler/optimizing/escape.cc @@ -20,43 +20,27 @@ namespace art { -void CalculateEscape(HInstruction* reference, - bool (*no_escape)(HInstruction*, HInstruction*), - /*out*/ bool* is_singleton, - /*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_not_returned = false; - *is_singleton_and_not_deopt_visible = false; - return; - } - // Assume the best until proven otherwise. - *is_singleton = true; - *is_singleton_and_not_returned = true; - *is_singleton_and_not_deopt_visible = true; - - if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) { - // Finalizable reference is treated as being returned in the end. - *is_singleton_and_not_returned = false; +void VisitEscapes(HInstruction* reference, EscapeVisitor& escape_visitor) { + // References not allocated in the method are intrinsically escaped. + // Finalizable references are always escaping since they end up in FinalizerQueues. + if ((!reference->IsNewInstance() && !reference->IsNewArray()) || + (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable())) { + if (!escape_visitor(reference)) { + return; + } } // 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()) { HInstruction* user = use.GetUser(); - if (no_escape != nullptr && (*no_escape)(reference, user)) { - // Client supplied analysis says there is no escape. - continue; - } else if (user->IsBoundType() || user->IsNullCheck()) { + if (user->IsBoundType() || user->IsNullCheck()) { // BoundType shouldn't normally be necessary for an allocation. Just be conservative // 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_not_returned = false; - *is_singleton_and_not_deopt_visible = false; - return; + if (!escape_visitor(user)) { + return; + } } else if (user->IsPhi() || user->IsSelect() || (user->IsInvoke() && user->GetSideEffects().DoesAnyWrite()) || @@ -67,21 +51,21 @@ void CalculateEscape(HInstruction* reference, (user->IsArraySet() && (reference == user->InputAt(2)))) { // 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_not_returned = false; - *is_singleton_and_not_deopt_visible = false; - return; + if (!escape_visitor(user)) { + return; + } } else if ((user->IsUnresolvedInstanceFieldGet() && (reference == user->InputAt(0))) || (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(0)))) { // The field is accessed in an unresolved way. We mark the object as a non-singleton. // 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_not_returned = false; - *is_singleton_and_not_deopt_visible = false; - return; + if (!escape_visitor(user)) { + return; + } } else if (user->IsReturn()) { - *is_singleton_and_not_returned = false; + if (!escape_visitor(user)) { + return; + } } } @@ -90,13 +74,61 @@ void CalculateEscape(HInstruction* reference, for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) { HEnvironment* user = use.GetUser(); if (user->GetHolder()->IsDeoptimize()) { - *is_singleton_and_not_deopt_visible = false; - break; + if (!escape_visitor(user->GetHolder())) { + return; + } } } } -bool DoesNotEscape(HInstruction* reference, bool (*no_escape)(HInstruction*, HInstruction*)) { +void CalculateEscape(HInstruction* reference, + NoEscapeCheck& no_escape, + /*out*/ bool* is_singleton, + /*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_not_returned = false; + *is_singleton_and_not_deopt_visible = false; + return; + } + // Assume the best until proven otherwise. + *is_singleton = true; + *is_singleton_and_not_returned = true; + *is_singleton_and_not_deopt_visible = true; + + if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) { + // Finalizable reference is treated as being returned in the end. + *is_singleton_and_not_returned = false; + } + + LambdaEscapeVisitor visitor([&](HInstruction* escape) -> bool { + if (escape == reference || no_escape(reference, escape)) { + // Ignore already known inherent escapes and escapes client supplied + // analysis knows is safe. Continue on. + return true; + } else if (escape->IsReturn()) { + // value is returned but might still be singleton. Continue on. + *is_singleton_and_not_returned = false; + return true; + } else if (escape->IsDeoptimize()) { + // value escapes through deopt but might still be singleton. Continue on. + *is_singleton_and_not_deopt_visible = false; + return true; + } else { + // Real escape. All knowledge about what happens to the value lost. We can + // stop here. + *is_singleton = false; + *is_singleton_and_not_returned = false; + *is_singleton_and_not_deopt_visible = false; + return false; + } + }); + VisitEscapes(reference, visitor); +} + +bool DoesNotEscape(HInstruction* reference, NoEscapeCheck& no_escape) { bool is_singleton = false; bool is_singleton_and_not_returned = false; bool is_singleton_and_not_deopt_visible = false; // not relevant for escape |