• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "escape.h"
18 
19 #include "nodes.h"
20 
21 namespace art {
22 
VisitEscapes(HInstruction * reference,EscapeVisitor & escape_visitor)23 void VisitEscapes(HInstruction* reference, EscapeVisitor& escape_visitor) {
24   // References not allocated in the method are intrinsically escaped.
25   // Finalizable references are always escaping since they end up in FinalizerQueues.
26   if ((!reference->IsNewInstance() && !reference->IsNewArray()) ||
27       (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable())) {
28     if (!escape_visitor(reference)) {
29       return;
30     }
31   }
32 
33   // Visit all uses to determine if this reference can escape into the heap,
34   // a method call, an alias, etc.
35   for (const HUseListNode<HInstruction*>& use : reference->GetUses()) {
36     HInstruction* user = use.GetUser();
37     if (user->IsBoundType() || user->IsNullCheck()) {
38       // BoundType shouldn't normally be necessary for an allocation. Just be conservative
39       // for the uncommon cases. Similarly, null checks are eventually eliminated for explicit
40       // allocations, but if we see one before it is simplified, assume an alias.
41       if (!escape_visitor(user)) {
42         return;
43       }
44     } else if (user->IsCheckCast() || user->IsInstanceOf()) {
45       // TODO Currently we'll just be conservative for Partial LSE and avoid
46       // optimizing check-cast things since we'd need to add blocks otherwise.
47       // Normally the simplifier should be able to just get rid of them
48       if (!escape_visitor(user)) {
49         return;
50       }
51     } else if (user->IsPhi() ||
52                user->IsSelect() ||
53                (user->IsInvoke() && user->GetSideEffects().DoesAnyWrite()) ||
54                (user->IsInstanceFieldSet() && (reference == user->InputAt(1))) ||
55                (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(1))) ||
56                (user->IsStaticFieldSet() && (reference == user->InputAt(1))) ||
57                (user->IsUnresolvedStaticFieldSet() && (reference == user->InputAt(0))) ||
58                (user->IsArraySet() && (reference == user->InputAt(2)))) {
59       // The reference is merged to HPhi/HSelect, passed to a callee, or stored to heap.
60       // Hence, the reference is no longer the only name that can refer to its value.
61       if (!escape_visitor(user)) {
62         return;
63       }
64     } else if ((user->IsUnresolvedInstanceFieldGet() && (reference == user->InputAt(0))) ||
65                (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(0)))) {
66       // The field is accessed in an unresolved way. We mark the object as a non-singleton.
67       // Note that we could optimize this case and still perform some optimizations until
68       // we hit the unresolved access, but the conservative assumption is the simplest.
69       if (!escape_visitor(user)) {
70         return;
71       }
72     } else if (user->IsReturn()) {
73       if (!escape_visitor(user)) {
74         return;
75       }
76     }
77   }
78 
79   // Look at the environment uses if it's for HDeoptimize. Other environment uses are fine,
80   // as long as client optimizations that rely on this information are disabled for debuggable.
81   for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
82     HEnvironment* user = use.GetUser();
83     if (user->GetHolder()->IsDeoptimize()) {
84       if (!escape_visitor(user->GetHolder())) {
85         return;
86       }
87     }
88   }
89 }
90 
CalculateEscape(HInstruction * reference,NoEscapeCheck & no_escape,bool * is_singleton,bool * is_singleton_and_not_returned,bool * is_singleton_and_not_deopt_visible)91 void CalculateEscape(HInstruction* reference,
92                      NoEscapeCheck& no_escape,
93                      /*out*/ bool* is_singleton,
94                      /*out*/ bool* is_singleton_and_not_returned,
95                      /*out*/ bool* is_singleton_and_not_deopt_visible) {
96   // For references not allocated in the method, don't assume anything.
97   if (!reference->IsNewInstance() && !reference->IsNewArray()) {
98     *is_singleton = false;
99     *is_singleton_and_not_returned = false;
100     *is_singleton_and_not_deopt_visible = false;
101     return;
102   }
103   // Assume the best until proven otherwise.
104   *is_singleton = true;
105   *is_singleton_and_not_returned = true;
106   *is_singleton_and_not_deopt_visible = true;
107 
108   if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) {
109     // Finalizable reference is treated as being returned in the end.
110     *is_singleton_and_not_returned = false;
111   }
112 
113   LambdaEscapeVisitor visitor([&](HInstruction* escape) -> bool {
114     if (escape == reference || no_escape(reference, escape)) {
115       // Ignore already known inherent escapes and escapes client supplied
116       // analysis knows is safe. Continue on.
117       return true;
118     } else if (escape->IsInstanceOf() || escape->IsCheckCast()) {
119       // Ignore since these are not relevant for regular LSE.
120       return true;
121     } else if (escape->IsReturn()) {
122       // value is returned but might still be singleton. Continue on.
123       *is_singleton_and_not_returned = false;
124       return true;
125     } else if (escape->IsDeoptimize()) {
126       // value escapes through deopt but might still be singleton. Continue on.
127       *is_singleton_and_not_deopt_visible = false;
128       return true;
129     } else {
130       // Real escape. All knowledge about what happens to the value lost. We can
131       // stop here.
132       *is_singleton = false;
133       *is_singleton_and_not_returned = false;
134       *is_singleton_and_not_deopt_visible = false;
135       return false;
136     }
137   });
138   VisitEscapes(reference, visitor);
139 }
140 
DoesNotEscape(HInstruction * reference,NoEscapeCheck & no_escape)141 bool DoesNotEscape(HInstruction* reference, NoEscapeCheck& no_escape) {
142   bool is_singleton = false;
143   bool is_singleton_and_not_returned = false;
144   bool is_singleton_and_not_deopt_visible = false;  // not relevant for escape
145   CalculateEscape(reference,
146                   no_escape,
147                   &is_singleton,
148                   &is_singleton_and_not_returned,
149                   &is_singleton_and_not_deopt_visible);
150   return is_singleton_and_not_returned;
151 }
152 
153 }  // namespace art
154