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