xref: /aosp_15_r20/art/compiler/optimizing/escape.h (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 #ifndef ART_COMPILER_OPTIMIZING_ESCAPE_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_ESCAPE_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker class HInstruction;
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker /*
27*795d594fSAndroid Build Coastguard Worker  * Methods related to escape analysis, i.e. determining whether an object
28*795d594fSAndroid Build Coastguard Worker  * allocation is visible outside ('escapes') its immediate method context.
29*795d594fSAndroid Build Coastguard Worker  */
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker // A visitor for seeing all instructions escape analysis considers escaping.
32*795d594fSAndroid Build Coastguard Worker // Called with each user of the reference passed to 'VisitEscapes'. Return true
33*795d594fSAndroid Build Coastguard Worker // to continue iteration and false to stop.
34*795d594fSAndroid Build Coastguard Worker class EscapeVisitor {
35*795d594fSAndroid Build Coastguard Worker  public:
~EscapeVisitor()36*795d594fSAndroid Build Coastguard Worker   virtual ~EscapeVisitor() {}
37*795d594fSAndroid Build Coastguard Worker   virtual bool Visit(HInstruction* escape) = 0;
operator()38*795d594fSAndroid Build Coastguard Worker   bool operator()(HInstruction* user) {
39*795d594fSAndroid Build Coastguard Worker     return Visit(user);
40*795d594fSAndroid Build Coastguard Worker   }
41*795d594fSAndroid Build Coastguard Worker };
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker // An explicit EscapeVisitor for lambdas
44*795d594fSAndroid Build Coastguard Worker template <typename F>
45*795d594fSAndroid Build Coastguard Worker class LambdaEscapeVisitor final : public EscapeVisitor {
46*795d594fSAndroid Build Coastguard Worker  public:
LambdaEscapeVisitor(F f)47*795d594fSAndroid Build Coastguard Worker   explicit LambdaEscapeVisitor(F f) : func_(f) {}
Visit(HInstruction * escape)48*795d594fSAndroid Build Coastguard Worker   bool Visit(HInstruction* escape) override {
49*795d594fSAndroid Build Coastguard Worker     return func_(escape);
50*795d594fSAndroid Build Coastguard Worker   }
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker  private:
53*795d594fSAndroid Build Coastguard Worker   F func_;
54*795d594fSAndroid Build Coastguard Worker };
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker // This functor is used with the escape-checking functions. If the NoEscape
57*795d594fSAndroid Build Coastguard Worker // function returns true escape analysis will consider 'user' to not have
58*795d594fSAndroid Build Coastguard Worker // escaped 'reference'. This allows clients with additional information to
59*795d594fSAndroid Build Coastguard Worker // supplement the escape-analysis. If the NoEscape function returns false then
60*795d594fSAndroid Build Coastguard Worker // the normal escape-checking code will be used to determine whether or not
61*795d594fSAndroid Build Coastguard Worker // 'reference' escapes.
62*795d594fSAndroid Build Coastguard Worker class NoEscapeCheck {
63*795d594fSAndroid Build Coastguard Worker  public:
~NoEscapeCheck()64*795d594fSAndroid Build Coastguard Worker   virtual ~NoEscapeCheck() {}
65*795d594fSAndroid Build Coastguard Worker   virtual bool NoEscape(HInstruction* reference, HInstruction* user) = 0;
operator()66*795d594fSAndroid Build Coastguard Worker   bool operator()(HInstruction* ref, HInstruction* user) {
67*795d594fSAndroid Build Coastguard Worker     return NoEscape(ref, user);
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker };
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker // An explicit NoEscapeCheck for use with c++ lambdas.
72*795d594fSAndroid Build Coastguard Worker template <typename F>
73*795d594fSAndroid Build Coastguard Worker class LambdaNoEscapeCheck final : public NoEscapeCheck {
74*795d594fSAndroid Build Coastguard Worker  public:
LambdaNoEscapeCheck(F f)75*795d594fSAndroid Build Coastguard Worker   explicit LambdaNoEscapeCheck(F f) : func_(f) {}
NoEscape(HInstruction * ref,HInstruction * user)76*795d594fSAndroid Build Coastguard Worker   bool NoEscape(HInstruction* ref, HInstruction* user) override {
77*795d594fSAndroid Build Coastguard Worker     return func_(ref, user);
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker  private:
81*795d594fSAndroid Build Coastguard Worker   F func_;
82*795d594fSAndroid Build Coastguard Worker };
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker /*
85*795d594fSAndroid Build Coastguard Worker  * Performs escape analysis on the given instruction, typically a reference to an
86*795d594fSAndroid Build Coastguard Worker  * allocation. The method assigns true to parameter 'is_singleton' if the reference
87*795d594fSAndroid Build Coastguard Worker  * is the only name that can refer to its value during the lifetime of the method,
88*795d594fSAndroid Build Coastguard Worker  * meaning that the reference is not aliased with something else, is not stored to
89*795d594fSAndroid Build Coastguard Worker  * heap memory, and not passed to another method. In addition, the method assigns
90*795d594fSAndroid Build Coastguard Worker  * true to parameter 'is_singleton_and_not_returned' if the reference is a singleton
91*795d594fSAndroid Build Coastguard Worker  * and not returned to the caller and to parameter 'is_singleton_and_not_deopt_visible'
92*795d594fSAndroid Build Coastguard Worker  * if the reference is a singleton and not used as an environment local of an
93*795d594fSAndroid Build Coastguard Worker  * HDeoptimize instruction (clients of the final value must run after BCE to ensure
94*795d594fSAndroid Build Coastguard Worker  * all such instructions have been introduced already).
95*795d594fSAndroid Build Coastguard Worker  *
96*795d594fSAndroid Build Coastguard Worker  * Note that being visible to a HDeoptimize instruction does not count for ordinary
97*795d594fSAndroid Build Coastguard Worker  * escape analysis, since switching between compiled code and interpreted code keeps
98*795d594fSAndroid Build Coastguard Worker  * non escaping references restricted to the lifetime of the method and the thread
99*795d594fSAndroid Build Coastguard Worker  * executing it. This property only concerns optimizations that are interested in
100*795d594fSAndroid Build Coastguard Worker  * escape analysis with respect to the *compiled* code (such as LSE).
101*795d594fSAndroid Build Coastguard Worker  *
102*795d594fSAndroid Build Coastguard Worker  * When set, the no_escape function is applied to any use of the allocation instruction
103*795d594fSAndroid Build Coastguard Worker  * prior to any built-in escape analysis. This allows clients to define better escape
104*795d594fSAndroid Build Coastguard Worker  * analysis in certain case-specific circumstances. If 'no_escape(reference, user)'
105*795d594fSAndroid Build Coastguard Worker  * returns true, the user is assumed *not* to cause any escape right away. The return
106*795d594fSAndroid Build Coastguard Worker  * value false means the client cannot provide a definite answer and built-in escape
107*795d594fSAndroid Build Coastguard Worker  * analysis is applied to the user instead.
108*795d594fSAndroid Build Coastguard Worker  */
109*795d594fSAndroid Build Coastguard Worker void CalculateEscape(HInstruction* reference,
110*795d594fSAndroid Build Coastguard Worker                      NoEscapeCheck& no_escape,
111*795d594fSAndroid Build Coastguard Worker                      /*out*/ bool* is_singleton,
112*795d594fSAndroid Build Coastguard Worker                      /*out*/ bool* is_singleton_and_not_returned,
113*795d594fSAndroid Build Coastguard Worker                      /*out*/ bool* is_singleton_and_not_deopt_visible);
114*795d594fSAndroid Build Coastguard Worker 
CalculateEscape(HInstruction * reference,bool (* no_escape_fn)(HInstruction *,HInstruction *),bool * is_singleton,bool * is_singleton_and_not_returned,bool * is_singleton_and_not_deopt_visible)115*795d594fSAndroid Build Coastguard Worker inline void CalculateEscape(HInstruction* reference,
116*795d594fSAndroid Build Coastguard Worker                             bool (*no_escape_fn)(HInstruction*, HInstruction*),
117*795d594fSAndroid Build Coastguard Worker                             /*out*/ bool* is_singleton,
118*795d594fSAndroid Build Coastguard Worker                             /*out*/ bool* is_singleton_and_not_returned,
119*795d594fSAndroid Build Coastguard Worker                             /*out*/ bool* is_singleton_and_not_deopt_visible) {
120*795d594fSAndroid Build Coastguard Worker   LambdaNoEscapeCheck esc(no_escape_fn);
121*795d594fSAndroid Build Coastguard Worker   LambdaNoEscapeCheck noop_esc([](HInstruction*, HInstruction*) { return false; });
122*795d594fSAndroid Build Coastguard Worker   CalculateEscape(reference,
123*795d594fSAndroid Build Coastguard Worker                   no_escape_fn == nullptr ? static_cast<NoEscapeCheck&>(noop_esc) : esc,
124*795d594fSAndroid Build Coastguard Worker                   is_singleton,
125*795d594fSAndroid Build Coastguard Worker                   is_singleton_and_not_returned,
126*795d594fSAndroid Build Coastguard Worker                   is_singleton_and_not_deopt_visible);
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker /*
130*795d594fSAndroid Build Coastguard Worker  * Performs escape analysis and visits each escape of the reference. Does not try to calculate any
131*795d594fSAndroid Build Coastguard Worker  * overall information about the method. Escapes are calculated in the same way as CalculateEscape.
132*795d594fSAndroid Build Coastguard Worker  *
133*795d594fSAndroid Build Coastguard Worker  * The escape_visitor should return true to continue visiting, false otherwise.
134*795d594fSAndroid Build Coastguard Worker  */
135*795d594fSAndroid Build Coastguard Worker void VisitEscapes(HInstruction* reference, EscapeVisitor& escape_visitor);
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker /*
138*795d594fSAndroid Build Coastguard Worker  * Convenience method for testing the singleton and not returned properties at once.
139*795d594fSAndroid Build Coastguard Worker  * Callers should be aware that this method invokes the full analysis at each call.
140*795d594fSAndroid Build Coastguard Worker  */
141*795d594fSAndroid Build Coastguard Worker bool DoesNotEscape(HInstruction* reference, NoEscapeCheck& no_escape);
142*795d594fSAndroid Build Coastguard Worker 
DoesNotEscape(HInstruction * reference,bool (* no_escape_fn)(HInstruction *,HInstruction *))143*795d594fSAndroid Build Coastguard Worker inline bool DoesNotEscape(HInstruction* reference,
144*795d594fSAndroid Build Coastguard Worker                           bool (*no_escape_fn)(HInstruction*, HInstruction*)) {
145*795d594fSAndroid Build Coastguard Worker   LambdaNoEscapeCheck<typeof(no_escape_fn)> esc(no_escape_fn);
146*795d594fSAndroid Build Coastguard Worker   return DoesNotEscape(reference, esc);
147*795d594fSAndroid Build Coastguard Worker }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker }  // namespace art
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_OPTIMIZING_ESCAPE_H_
152