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