diff options
Diffstat (limited to 'compiler/optimizing/escape.cc')
| -rw-r--r-- | compiler/optimizing/escape.cc | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/compiler/optimizing/escape.cc b/compiler/optimizing/escape.cc new file mode 100644 index 0000000000..9df5bf1017 --- /dev/null +++ b/compiler/optimizing/escape.cc @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "escape.h" + +#include "nodes.h" + +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; + // 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()) { + // 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; + } else if (user->IsPhi() || user->IsSelect() || user->IsInvoke() || + (user->IsInstanceFieldSet() && (reference == user->InputAt(1))) || + (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(1))) || + (user->IsStaticFieldSet() && (reference == user->InputAt(1))) || + (user->IsUnresolvedStaticFieldSet() && (reference == user->InputAt(0))) || + (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; + } 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; + } else if (user->IsReturn()) { + *is_singleton_and_not_returned = false; + } + } + + // 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_not_deopt_visible = false; + break; + } + } +} + +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 |