xref: /aosp_15_r20/art/compiler/dex/inline_method_analyser.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 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 "inline_method_analyser.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "art_field-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
22*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction_utils.h"
28*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "mirror/dex_cache-inl.h"
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker /*
32*795d594fSAndroid Build Coastguard Worker  * NOTE: This code is part of the quick compiler. It lives in the runtime
33*795d594fSAndroid Build Coastguard Worker  * only to allow the debugger to check whether a method has been inlined.
34*795d594fSAndroid Build Coastguard Worker  */
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker namespace {  // anonymous namespace
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker // Helper class for matching a pattern.
41*795d594fSAndroid Build Coastguard Worker class Matcher {
42*795d594fSAndroid Build Coastguard Worker  public:
43*795d594fSAndroid Build Coastguard Worker   // Match function type.
44*795d594fSAndroid Build Coastguard Worker   using MatchFn = bool(Matcher*);
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   template <size_t size>
47*795d594fSAndroid Build Coastguard Worker   static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]);
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker   // Match and advance.
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker   static bool Mark(Matcher* matcher);
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker   template <bool (Matcher::*Fn)()>
54*795d594fSAndroid Build Coastguard Worker   static bool Required(Matcher* matcher);
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker   template <bool (Matcher::*Fn)()>
57*795d594fSAndroid Build Coastguard Worker   static bool Repeated(Matcher* matcher);  // On match, returns to the mark.
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   // Match an individual instruction.
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker   template <Instruction::Code opcode> bool Opcode();
62*795d594fSAndroid Build Coastguard Worker   bool Const0();
63*795d594fSAndroid Build Coastguard Worker   bool IPutOnThis();
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker   // Match Fn1 or Fn2. This should be used in combination of e.g. Required.
66*795d594fSAndroid Build Coastguard Worker   template <bool (Matcher::*Fn1)(), bool (Matcher::*Fn2)()>
67*795d594fSAndroid Build Coastguard Worker   bool Or();
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker  private:
Matcher(const CodeItemDataAccessor * code_item)70*795d594fSAndroid Build Coastguard Worker   explicit Matcher(const CodeItemDataAccessor* code_item)
71*795d594fSAndroid Build Coastguard Worker       : code_item_(code_item),
72*795d594fSAndroid Build Coastguard Worker         instruction_(code_item->begin()) {}
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker   static bool DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size);
75*795d594fSAndroid Build Coastguard Worker 
76*795d594fSAndroid Build Coastguard Worker   const CodeItemDataAccessor* const code_item_;
77*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator instruction_;
78*795d594fSAndroid Build Coastguard Worker   size_t pos_ = 0u;
79*795d594fSAndroid Build Coastguard Worker   size_t mark_ = 0u;
80*795d594fSAndroid Build Coastguard Worker };
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker template <size_t size>
Match(const CodeItemDataAccessor * code_item,MatchFn * const (& pattern)[size])83*795d594fSAndroid Build Coastguard Worker bool Matcher::Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]) {
84*795d594fSAndroid Build Coastguard Worker   return DoMatch(code_item, pattern, size);
85*795d594fSAndroid Build Coastguard Worker }
86*795d594fSAndroid Build Coastguard Worker 
Mark(Matcher * matcher)87*795d594fSAndroid Build Coastguard Worker bool Matcher::Mark(Matcher* matcher) {
88*795d594fSAndroid Build Coastguard Worker   matcher->pos_ += 1u;  // Advance to the next match function before marking.
89*795d594fSAndroid Build Coastguard Worker   matcher->mark_ = matcher->pos_;
90*795d594fSAndroid Build Coastguard Worker   return true;
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker template <bool (Matcher::*Fn)()>
Required(Matcher * matcher)94*795d594fSAndroid Build Coastguard Worker bool Matcher::Required(Matcher* matcher) {
95*795d594fSAndroid Build Coastguard Worker   if (!(matcher->*Fn)()) {
96*795d594fSAndroid Build Coastguard Worker     return false;
97*795d594fSAndroid Build Coastguard Worker   }
98*795d594fSAndroid Build Coastguard Worker   matcher->pos_ += 1u;
99*795d594fSAndroid Build Coastguard Worker   ++matcher->instruction_;
100*795d594fSAndroid Build Coastguard Worker   return true;
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker template <bool (Matcher::*Fn)()>
Repeated(Matcher * matcher)104*795d594fSAndroid Build Coastguard Worker bool Matcher::Repeated(Matcher* matcher) {
105*795d594fSAndroid Build Coastguard Worker   if (!(matcher->*Fn)()) {
106*795d594fSAndroid Build Coastguard Worker     // Didn't match optional instruction, try the next match function.
107*795d594fSAndroid Build Coastguard Worker     matcher->pos_ += 1u;
108*795d594fSAndroid Build Coastguard Worker     return true;
109*795d594fSAndroid Build Coastguard Worker   }
110*795d594fSAndroid Build Coastguard Worker   matcher->pos_ = matcher->mark_;
111*795d594fSAndroid Build Coastguard Worker   ++matcher->instruction_;
112*795d594fSAndroid Build Coastguard Worker   return true;
113*795d594fSAndroid Build Coastguard Worker }
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker template <Instruction::Code opcode>
Opcode()116*795d594fSAndroid Build Coastguard Worker bool Matcher::Opcode() {
117*795d594fSAndroid Build Coastguard Worker   return instruction_->Opcode() == opcode;
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker // Match const 0.
Const0()121*795d594fSAndroid Build Coastguard Worker bool Matcher::Const0() {
122*795d594fSAndroid Build Coastguard Worker   return IsInstructionDirectConst(instruction_->Opcode()) &&
123*795d594fSAndroid Build Coastguard Worker       (instruction_->Opcode() == Instruction::CONST_WIDE ? instruction_->VRegB_51l() == 0
124*795d594fSAndroid Build Coastguard Worker                                                          : instruction_->VRegB() == 0);
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker 
IPutOnThis()127*795d594fSAndroid Build Coastguard Worker bool Matcher::IPutOnThis() {
128*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(code_item_->InsSize(), 0u);
129*795d594fSAndroid Build Coastguard Worker   return IsInstructionIPut(instruction_->Opcode()) &&
130*795d594fSAndroid Build Coastguard Worker       instruction_->VRegB_22c() == code_item_->RegistersSize() - code_item_->InsSize();
131*795d594fSAndroid Build Coastguard Worker }
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker template <bool (Matcher::*Fn1)(), bool (Matcher::*Fn2)()>
Or()134*795d594fSAndroid Build Coastguard Worker bool Matcher::Or() {
135*795d594fSAndroid Build Coastguard Worker   return (this->*Fn1)() || (this->*Fn2)();
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker 
DoMatch(const CodeItemDataAccessor * code_item,MatchFn * const * pattern,size_t size)138*795d594fSAndroid Build Coastguard Worker bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size) {
139*795d594fSAndroid Build Coastguard Worker   Matcher matcher(code_item);
140*795d594fSAndroid Build Coastguard Worker   while (matcher.pos_ != size) {
141*795d594fSAndroid Build Coastguard Worker     if (!pattern[matcher.pos_](&matcher)) {
142*795d594fSAndroid Build Coastguard Worker       return false;
143*795d594fSAndroid Build Coastguard Worker     }
144*795d594fSAndroid Build Coastguard Worker   }
145*795d594fSAndroid Build Coastguard Worker   return true;
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker // Used for a single invoke in a constructor. In that situation, the method verifier makes
149*795d594fSAndroid Build Coastguard Worker // sure we invoke a constructor either in the same class or superclass with at least "this".
GetTargetConstructor(ArtMethod * method,const Instruction * invoke_direct)150*795d594fSAndroid Build Coastguard Worker ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
151*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
152*795d594fSAndroid Build Coastguard Worker   DCHECK(invoke_direct->Opcode() == Instruction::INVOKE_DIRECT ||
153*795d594fSAndroid Build Coastguard Worker          invoke_direct->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
154*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
155*795d594fSAndroid Build Coastguard Worker     uint16_t vregc = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
156*795d594fSAndroid Build Coastguard Worker                          ? invoke_direct->VRegC_35c()
157*795d594fSAndroid Build Coastguard Worker                          : invoke_direct->VRegC_3rc();
158*795d594fSAndroid Build Coastguard Worker     CodeItemDataAccessor accessor(method->DexInstructionData());
159*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(vregc, accessor.RegistersSize() - accessor.InsSize());
160*795d594fSAndroid Build Coastguard Worker   }
161*795d594fSAndroid Build Coastguard Worker   uint32_t method_index = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
162*795d594fSAndroid Build Coastguard Worker                               ? invoke_direct->VRegB_35c()
163*795d594fSAndroid Build Coastguard Worker                               : invoke_direct->VRegB_3rc();
164*795d594fSAndroid Build Coastguard Worker   ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod(
165*795d594fSAndroid Build Coastguard Worker       method_index, method->GetDexCache(), method->GetClassLoader());
166*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild && target_method != nullptr) {
167*795d594fSAndroid Build Coastguard Worker     CHECK(!target_method->IsStatic());
168*795d594fSAndroid Build Coastguard Worker     CHECK(target_method->IsConstructor());
169*795d594fSAndroid Build Coastguard Worker     CHECK(method->GetDeclaringClass()->IsSubClass(target_method->GetDeclaringClass()));
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker   return target_method;
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
174*795d594fSAndroid Build Coastguard Worker // Return the forwarded arguments and check that all remaining arguments are zero.
175*795d594fSAndroid Build Coastguard Worker // If the check fails, return static_cast<size_t>(-1).
CountForwardedConstructorArguments(const CodeItemDataAccessor * code_item,const Instruction * invoke_direct,uint16_t zero_vreg_mask)176*795d594fSAndroid Build Coastguard Worker size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item,
177*795d594fSAndroid Build Coastguard Worker                                           const Instruction* invoke_direct,
178*795d594fSAndroid Build Coastguard Worker                                           uint16_t zero_vreg_mask) {
179*795d594fSAndroid Build Coastguard Worker   DCHECK(invoke_direct->Opcode() == Instruction::INVOKE_DIRECT ||
180*795d594fSAndroid Build Coastguard Worker          invoke_direct->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
181*795d594fSAndroid Build Coastguard Worker   size_t number_of_args = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
182*795d594fSAndroid Build Coastguard Worker                               ? invoke_direct->VRegA_35c()
183*795d594fSAndroid Build Coastguard Worker                               : invoke_direct->VRegA_3rc();
184*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(number_of_args, 0u);
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   if (invoke_direct->Opcode() == Instruction::INVOKE_DIRECT) {
187*795d594fSAndroid Build Coastguard Worker     uint32_t args[Instruction::kMaxVarArgRegs];
188*795d594fSAndroid Build Coastguard Worker     invoke_direct->GetVarArgs(args);
189*795d594fSAndroid Build Coastguard Worker     uint16_t this_vreg = args[0];
190*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(this_vreg,
191*795d594fSAndroid Build Coastguard Worker               code_item->RegistersSize() - code_item->InsSize());  // Checked by verifier.
192*795d594fSAndroid Build Coastguard Worker     size_t forwarded = 1u;
193*795d594fSAndroid Build Coastguard Worker     while (forwarded < number_of_args &&
194*795d594fSAndroid Build Coastguard Worker         args[forwarded] == this_vreg + forwarded &&
195*795d594fSAndroid Build Coastguard Worker         (zero_vreg_mask & (1u << args[forwarded])) == 0) {
196*795d594fSAndroid Build Coastguard Worker       ++forwarded;
197*795d594fSAndroid Build Coastguard Worker     }
198*795d594fSAndroid Build Coastguard Worker     for (size_t i = forwarded; i != number_of_args; ++i) {
199*795d594fSAndroid Build Coastguard Worker       if ((zero_vreg_mask & (1u << args[i])) == 0) {
200*795d594fSAndroid Build Coastguard Worker         return static_cast<size_t>(-1);
201*795d594fSAndroid Build Coastguard Worker       }
202*795d594fSAndroid Build Coastguard Worker     }
203*795d594fSAndroid Build Coastguard Worker     return forwarded;
204*795d594fSAndroid Build Coastguard Worker   } else {
205*795d594fSAndroid Build Coastguard Worker     uint16_t this_vreg = invoke_direct->VRegC_3rc();
206*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(this_vreg,
207*795d594fSAndroid Build Coastguard Worker               code_item->RegistersSize() - code_item->InsSize());  // Checked by verifier.
208*795d594fSAndroid Build Coastguard Worker     size_t forwarded = 1u;
209*795d594fSAndroid Build Coastguard Worker     while (forwarded < number_of_args &&
210*795d594fSAndroid Build Coastguard Worker            (zero_vreg_mask & (1u << (this_vreg + forwarded))) == 0) {
211*795d594fSAndroid Build Coastguard Worker       ++forwarded;
212*795d594fSAndroid Build Coastguard Worker     }
213*795d594fSAndroid Build Coastguard Worker     for (size_t i = forwarded; i != number_of_args; ++i) {
214*795d594fSAndroid Build Coastguard Worker       if ((zero_vreg_mask & (1u << (this_vreg + i))) == 0) {
215*795d594fSAndroid Build Coastguard Worker         return static_cast<size_t>(-1);
216*795d594fSAndroid Build Coastguard Worker       }
217*795d594fSAndroid Build Coastguard Worker     }
218*795d594fSAndroid Build Coastguard Worker     return forwarded;
219*795d594fSAndroid Build Coastguard Worker   }
220*795d594fSAndroid Build Coastguard Worker }
221*795d594fSAndroid Build Coastguard Worker 
GetZeroVRegMask(const Instruction * const0)222*795d594fSAndroid Build Coastguard Worker uint16_t GetZeroVRegMask(const Instruction* const0) {
223*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInstructionDirectConst(const0->Opcode()));
224*795d594fSAndroid Build Coastguard Worker   DCHECK((const0->Opcode() == Instruction::CONST_WIDE) ? const0->VRegB_51l() == 0u
225*795d594fSAndroid Build Coastguard Worker                                                        : const0->VRegB() == 0);
226*795d594fSAndroid Build Coastguard Worker   uint16_t base_mask = IsInstructionConstWide(const0->Opcode()) ? 3u : 1u;
227*795d594fSAndroid Build Coastguard Worker   return base_mask << const0->VRegA();
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker 
230*795d594fSAndroid Build Coastguard Worker // We limit the number of IPUTs storing parameters. There can be any number
231*795d594fSAndroid Build Coastguard Worker // of IPUTs that store the value 0 as they are useless in a constructor as
232*795d594fSAndroid Build Coastguard Worker // the object always starts zero-initialized. We also eliminate all but the
233*795d594fSAndroid Build Coastguard Worker // last store to any field as they are not observable; not even if the field
234*795d594fSAndroid Build Coastguard Worker // is volatile as no reference to the object can escape from a constructor
235*795d594fSAndroid Build Coastguard Worker // with this pattern.
236*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxConstructorIPuts = 3u;
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker struct ConstructorIPutData {
ConstructorIPutDataart::__anon3e471f560111::ConstructorIPutData239*795d594fSAndroid Build Coastguard Worker   ConstructorIPutData() : field_index(DexFile::kDexNoIndex16), arg(0u) { }
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker   uint16_t field_index;
242*795d594fSAndroid Build Coastguard Worker   uint16_t arg;
243*795d594fSAndroid Build Coastguard Worker };
244*795d594fSAndroid Build Coastguard Worker 
RecordConstructorIPut(ArtMethod * method,const Instruction * new_iput,uint16_t this_vreg,uint16_t zero_vreg_mask,ConstructorIPutData (& iputs)[kMaxConstructorIPuts],size_t & iput_count)245*795d594fSAndroid Build Coastguard Worker bool RecordConstructorIPut(ArtMethod* method,
246*795d594fSAndroid Build Coastguard Worker                            const Instruction* new_iput,
247*795d594fSAndroid Build Coastguard Worker                            uint16_t this_vreg,
248*795d594fSAndroid Build Coastguard Worker                            uint16_t zero_vreg_mask,
249*795d594fSAndroid Build Coastguard Worker                            /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts],
250*795d594fSAndroid Build Coastguard Worker                            /*inout*/ size_t& iput_count)
251*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
252*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInstructionIPut(new_iput->Opcode()));
253*795d594fSAndroid Build Coastguard Worker   uint32_t field_index = new_iput->VRegC_22c();
254*795d594fSAndroid Build Coastguard Worker   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
255*795d594fSAndroid Build Coastguard Worker   ArtField* field = class_linker->LookupResolvedField(field_index, method, /* is_static= */ false);
256*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(field == nullptr)) {
257*795d594fSAndroid Build Coastguard Worker     return false;
258*795d594fSAndroid Build Coastguard Worker   }
259*795d594fSAndroid Build Coastguard Worker   // Remove previous IPUT to the same field, if any. Different field indexes may refer
260*795d594fSAndroid Build Coastguard Worker   // to the same field, so we need to compare resolved fields from the dex cache.
261*795d594fSAndroid Build Coastguard Worker   for (size_t old_pos = 0, end = iput_count; old_pos < end; ++old_pos) {
262*795d594fSAndroid Build Coastguard Worker     ArtField* f = class_linker->LookupResolvedField(iputs[old_pos].field_index,
263*795d594fSAndroid Build Coastguard Worker                                                     method,
264*795d594fSAndroid Build Coastguard Worker                                                     /* is_static= */ false);
265*795d594fSAndroid Build Coastguard Worker     DCHECK(f != nullptr);
266*795d594fSAndroid Build Coastguard Worker     if (f == field) {
267*795d594fSAndroid Build Coastguard Worker       auto back_it = std::copy(iputs + old_pos + 1, iputs + iput_count, iputs + old_pos);
268*795d594fSAndroid Build Coastguard Worker       *back_it = ConstructorIPutData();
269*795d594fSAndroid Build Coastguard Worker       --iput_count;
270*795d594fSAndroid Build Coastguard Worker       break;
271*795d594fSAndroid Build Coastguard Worker     }
272*795d594fSAndroid Build Coastguard Worker   }
273*795d594fSAndroid Build Coastguard Worker   // If the stored value isn't zero, record the IPUT.
274*795d594fSAndroid Build Coastguard Worker   if ((zero_vreg_mask & (1u << new_iput->VRegA_22c())) == 0u) {
275*795d594fSAndroid Build Coastguard Worker     size_t new_pos = iput_count;
276*795d594fSAndroid Build Coastguard Worker     if (new_pos == arraysize(iputs)) {
277*795d594fSAndroid Build Coastguard Worker       return false;  // Exceeded capacity of the output array.
278*795d594fSAndroid Build Coastguard Worker     }
279*795d594fSAndroid Build Coastguard Worker     iputs[new_pos].field_index = field_index;
280*795d594fSAndroid Build Coastguard Worker     iputs[new_pos].arg = new_iput->VRegA_22c() - this_vreg;
281*795d594fSAndroid Build Coastguard Worker     ++iput_count;
282*795d594fSAndroid Build Coastguard Worker   }
283*795d594fSAndroid Build Coastguard Worker   return true;
284*795d594fSAndroid Build Coastguard Worker }
285*795d594fSAndroid Build Coastguard Worker 
DoAnalyseConstructor(const CodeItemDataAccessor * code_item,ArtMethod * method,ConstructorIPutData (& iputs)[kMaxConstructorIPuts],size_t & iput_count)286*795d594fSAndroid Build Coastguard Worker bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
287*795d594fSAndroid Build Coastguard Worker                           ArtMethod* method,
288*795d594fSAndroid Build Coastguard Worker                           /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts],
289*795d594fSAndroid Build Coastguard Worker                           /*inout*/ size_t &iput_count)
290*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
291*795d594fSAndroid Build Coastguard Worker   // On entry we should not have any IPUTs yet.
292*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(iput_count, 0u);
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker   // Limit the maximum number of code units we're willing to match.
295*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxCodeUnits = 16u;
296*795d594fSAndroid Build Coastguard Worker 
297*795d594fSAndroid Build Coastguard Worker   // Limit the number of registers that the constructor may use to 16.
298*795d594fSAndroid Build Coastguard Worker   // Given that IPUTs must use low 16 registers and we do not match MOVEs,
299*795d594fSAndroid Build Coastguard Worker   // this is a reasonable limitation.
300*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMaxVRegs = 16u;
301*795d594fSAndroid Build Coastguard Worker 
302*795d594fSAndroid Build Coastguard Worker   // We try to match a constructor that calls another constructor (either in
303*795d594fSAndroid Build Coastguard Worker   // superclass or in the same class) with the same parameters, or with some
304*795d594fSAndroid Build Coastguard Worker   // parameters truncated (allowed only for calls to superclass constructor)
305*795d594fSAndroid Build Coastguard Worker   // or with extra parameters with value 0 (with any type, including null).
306*795d594fSAndroid Build Coastguard Worker   // This call can be followed by optional IPUTs on "this" storing either one
307*795d594fSAndroid Build Coastguard Worker   // of the parameters or 0 and the code must then finish with RETURN_VOID.
308*795d594fSAndroid Build Coastguard Worker   // The called constructor must be either java.lang.Object.<init>() or it
309*795d594fSAndroid Build Coastguard Worker   // must also match the same pattern.
310*795d594fSAndroid Build Coastguard Worker   static constexpr Matcher::MatchFn* const kConstructorPattern[] = {
311*795d594fSAndroid Build Coastguard Worker       &Matcher::Mark,
312*795d594fSAndroid Build Coastguard Worker       &Matcher::Repeated<&Matcher::Const0>,
313*795d594fSAndroid Build Coastguard Worker       // Either invoke-direct or invoke-direct/range works
314*795d594fSAndroid Build Coastguard Worker       &Matcher::Required<&Matcher::Or<&Matcher::Opcode<Instruction::INVOKE_DIRECT>,
315*795d594fSAndroid Build Coastguard Worker                                       &Matcher::Opcode<Instruction::INVOKE_DIRECT_RANGE>>>,
316*795d594fSAndroid Build Coastguard Worker       &Matcher::Mark,
317*795d594fSAndroid Build Coastguard Worker       &Matcher::Repeated<&Matcher::Const0>,
318*795d594fSAndroid Build Coastguard Worker       &Matcher::Repeated<&Matcher::IPutOnThis>,
319*795d594fSAndroid Build Coastguard Worker       &Matcher::Required<&Matcher::Opcode<Instruction::RETURN_VOID>>,
320*795d594fSAndroid Build Coastguard Worker   };
321*795d594fSAndroid Build Coastguard Worker 
322*795d594fSAndroid Build Coastguard Worker   DCHECK(method != nullptr);
323*795d594fSAndroid Build Coastguard Worker   DCHECK(!method->IsStatic());
324*795d594fSAndroid Build Coastguard Worker   DCHECK(method->IsConstructor());
325*795d594fSAndroid Build Coastguard Worker   DCHECK(code_item != nullptr);
326*795d594fSAndroid Build Coastguard Worker   if (!method->GetDeclaringClass()->IsVerified() ||
327*795d594fSAndroid Build Coastguard Worker       code_item->InsnsSizeInCodeUnits() > kMaxCodeUnits ||
328*795d594fSAndroid Build Coastguard Worker       code_item->RegistersSize() > kMaxVRegs ||
329*795d594fSAndroid Build Coastguard Worker       !Matcher::Match(code_item, kConstructorPattern)) {
330*795d594fSAndroid Build Coastguard Worker     return false;
331*795d594fSAndroid Build Coastguard Worker   }
332*795d594fSAndroid Build Coastguard Worker 
333*795d594fSAndroid Build Coastguard Worker   // Verify the invoke, prevent a few odd cases and collect IPUTs.
334*795d594fSAndroid Build Coastguard Worker   uint16_t this_vreg = code_item->RegistersSize() - code_item->InsSize();
335*795d594fSAndroid Build Coastguard Worker   uint16_t zero_vreg_mask = 0u;
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker   for (const DexInstructionPcPair& pair : *code_item) {
338*795d594fSAndroid Build Coastguard Worker     const Instruction& instruction = pair.Inst();
339*795d594fSAndroid Build Coastguard Worker     if (instruction.Opcode() == Instruction::RETURN_VOID) {
340*795d594fSAndroid Build Coastguard Worker       break;
341*795d594fSAndroid Build Coastguard Worker     } else if (instruction.Opcode() == Instruction::INVOKE_DIRECT ||
342*795d594fSAndroid Build Coastguard Worker                instruction.Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
343*795d594fSAndroid Build Coastguard Worker       ArtMethod* target_method = GetTargetConstructor(method, &instruction);
344*795d594fSAndroid Build Coastguard Worker       if (target_method == nullptr) {
345*795d594fSAndroid Build Coastguard Worker         return false;
346*795d594fSAndroid Build Coastguard Worker       }
347*795d594fSAndroid Build Coastguard Worker       // We allow forwarding constructors only if they pass more arguments
348*795d594fSAndroid Build Coastguard Worker       // to prevent infinite recursion.
349*795d594fSAndroid Build Coastguard Worker       size_t number_of_args = instruction.Opcode() == Instruction::INVOKE_DIRECT
350*795d594fSAndroid Build Coastguard Worker                                   ? instruction.VRegA_35c()
351*795d594fSAndroid Build Coastguard Worker                                   : instruction.VRegA_3rc();
352*795d594fSAndroid Build Coastguard Worker       if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
353*795d594fSAndroid Build Coastguard Worker           number_of_args <= code_item->InsSize()) {
354*795d594fSAndroid Build Coastguard Worker         return false;
355*795d594fSAndroid Build Coastguard Worker       }
356*795d594fSAndroid Build Coastguard Worker       size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
357*795d594fSAndroid Build Coastguard Worker       if (forwarded == static_cast<size_t>(-1)) {
358*795d594fSAndroid Build Coastguard Worker         return false;
359*795d594fSAndroid Build Coastguard Worker       }
360*795d594fSAndroid Build Coastguard Worker       if (target_method->GetDeclaringClass()->IsObjectClass()) {
361*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(target_method->DexInstructionData().begin()->Opcode(), Instruction::RETURN_VOID);
362*795d594fSAndroid Build Coastguard Worker       } else {
363*795d594fSAndroid Build Coastguard Worker         CodeItemDataAccessor target_code_item(target_method->DexInstructionData());
364*795d594fSAndroid Build Coastguard Worker         if (!target_code_item.HasCodeItem()) {
365*795d594fSAndroid Build Coastguard Worker           return false;  // Native constructor?
366*795d594fSAndroid Build Coastguard Worker         }
367*795d594fSAndroid Build Coastguard Worker         if (!DoAnalyseConstructor(&target_code_item, target_method, iputs, iput_count)) {
368*795d594fSAndroid Build Coastguard Worker           return false;
369*795d594fSAndroid Build Coastguard Worker         }
370*795d594fSAndroid Build Coastguard Worker         // Prune IPUTs with zero input.
371*795d594fSAndroid Build Coastguard Worker         auto kept_end = std::remove_if(
372*795d594fSAndroid Build Coastguard Worker             iputs,
373*795d594fSAndroid Build Coastguard Worker             iputs + iput_count,
374*795d594fSAndroid Build Coastguard Worker             [forwarded](const ConstructorIPutData& iput_data) {
375*795d594fSAndroid Build Coastguard Worker               return iput_data.arg >= forwarded;
376*795d594fSAndroid Build Coastguard Worker             });
377*795d594fSAndroid Build Coastguard Worker         iput_count = std::distance(iputs, kept_end);
378*795d594fSAndroid Build Coastguard Worker         std::fill(kept_end, iputs + arraysize(iputs), ConstructorIPutData());
379*795d594fSAndroid Build Coastguard Worker         // If we have any IPUTs from the call, check that the target method is in the same
380*795d594fSAndroid Build Coastguard Worker         // dex file (compare DexCache references), otherwise field_indexes would be bogus.
381*795d594fSAndroid Build Coastguard Worker         if (iput_count > 0u && target_method->GetDexCache() != method->GetDexCache()) {
382*795d594fSAndroid Build Coastguard Worker           return false;
383*795d594fSAndroid Build Coastguard Worker         }
384*795d594fSAndroid Build Coastguard Worker       }
385*795d594fSAndroid Build Coastguard Worker     } else if (IsInstructionDirectConst(instruction.Opcode())) {
386*795d594fSAndroid Build Coastguard Worker       zero_vreg_mask |= GetZeroVRegMask(&instruction);
387*795d594fSAndroid Build Coastguard Worker       if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
388*795d594fSAndroid Build Coastguard Worker         return false;  // Overwriting `this` is unsupported.
389*795d594fSAndroid Build Coastguard Worker       }
390*795d594fSAndroid Build Coastguard Worker     } else {
391*795d594fSAndroid Build Coastguard Worker       DCHECK(IsInstructionIPut(instruction.Opcode()));
392*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(instruction.VRegB_22c(), this_vreg);
393*795d594fSAndroid Build Coastguard Worker       if (!RecordConstructorIPut(method,
394*795d594fSAndroid Build Coastguard Worker                                  &instruction,
395*795d594fSAndroid Build Coastguard Worker                                  this_vreg,
396*795d594fSAndroid Build Coastguard Worker                                  zero_vreg_mask,
397*795d594fSAndroid Build Coastguard Worker                                  iputs,
398*795d594fSAndroid Build Coastguard Worker                                  iput_count)) {
399*795d594fSAndroid Build Coastguard Worker         return false;
400*795d594fSAndroid Build Coastguard Worker       }
401*795d594fSAndroid Build Coastguard Worker     }
402*795d594fSAndroid Build Coastguard Worker   }
403*795d594fSAndroid Build Coastguard Worker   return true;
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker 
406*795d594fSAndroid Build Coastguard Worker }  // anonymous namespace
407*795d594fSAndroid Build Coastguard Worker 
AnalyseConstructor(const CodeItemDataAccessor * code_item,ArtMethod * method,InlineMethod * result)408*795d594fSAndroid Build Coastguard Worker bool AnalyseConstructor(const CodeItemDataAccessor* code_item,
409*795d594fSAndroid Build Coastguard Worker                         ArtMethod* method,
410*795d594fSAndroid Build Coastguard Worker                         InlineMethod* result)
411*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
412*795d594fSAndroid Build Coastguard Worker   size_t iput_count(0u);
413*795d594fSAndroid Build Coastguard Worker   ConstructorIPutData iputs[kMaxConstructorIPuts];
414*795d594fSAndroid Build Coastguard Worker   if (!DoAnalyseConstructor(code_item, method, iputs, iput_count)) {
415*795d594fSAndroid Build Coastguard Worker     return false;
416*795d594fSAndroid Build Coastguard Worker   }
417*795d594fSAndroid Build Coastguard Worker   static_assert(kMaxConstructorIPuts == 3, "Unexpected limit");  // Code below depends on this.
418*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(iput_count, kMaxConstructorIPuts);
419*795d594fSAndroid Build Coastguard Worker 
420*795d594fSAndroid Build Coastguard Worker #define STORE_IPUT(n)                                                         \
421*795d594fSAndroid Build Coastguard Worker   do {                                                                        \
422*795d594fSAndroid Build Coastguard Worker     result->d.constructor_data.iput##n##_field_index = iputs[n].field_index;  \
423*795d594fSAndroid Build Coastguard Worker     result->d.constructor_data.iput##n##_arg = iputs[n].arg;                  \
424*795d594fSAndroid Build Coastguard Worker   } while (false)
425*795d594fSAndroid Build Coastguard Worker 
426*795d594fSAndroid Build Coastguard Worker   STORE_IPUT(0);
427*795d594fSAndroid Build Coastguard Worker   STORE_IPUT(1);
428*795d594fSAndroid Build Coastguard Worker   STORE_IPUT(2);
429*795d594fSAndroid Build Coastguard Worker #undef STORE_IPUT
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker   result->opcode = kInlineOpConstructor;
432*795d594fSAndroid Build Coastguard Worker   result->d.constructor_data.iput_count = static_cast<uint16_t>(iput_count);
433*795d594fSAndroid Build Coastguard Worker   return true;
434*795d594fSAndroid Build Coastguard Worker }
435*795d594fSAndroid Build Coastguard Worker 
436*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET));
437*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_WIDE));
438*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_OBJECT));
439*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_BOOLEAN));
440*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_BYTE));
441*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_CHAR));
442*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIGet(Instruction::IGET_SHORT));
443*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT));
444*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_WIDE));
445*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_OBJECT));
446*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_BOOLEAN));
447*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_BYTE));
448*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_CHAR));
449*795d594fSAndroid Build Coastguard Worker static_assert(IsInstructionIPut(Instruction::IPUT_SHORT));
450*795d594fSAndroid Build Coastguard Worker static_assert(IGetMemAccessType(Instruction::IGET) == IPutMemAccessType(Instruction::IPUT));
451*795d594fSAndroid Build Coastguard Worker static_assert(
452*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_WIDE) == IPutMemAccessType(Instruction::IPUT_WIDE));
453*795d594fSAndroid Build Coastguard Worker static_assert(
454*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_OBJECT) == IPutMemAccessType(Instruction::IPUT_OBJECT));
455*795d594fSAndroid Build Coastguard Worker static_assert(
456*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_BOOLEAN) == IPutMemAccessType(Instruction::IPUT_BOOLEAN));
457*795d594fSAndroid Build Coastguard Worker static_assert(
458*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_BYTE) == IPutMemAccessType(Instruction::IPUT_BYTE));
459*795d594fSAndroid Build Coastguard Worker static_assert(
460*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_CHAR) == IPutMemAccessType(Instruction::IPUT_CHAR));
461*795d594fSAndroid Build Coastguard Worker static_assert(
462*795d594fSAndroid Build Coastguard Worker     IGetMemAccessType(Instruction::IGET_SHORT) == IPutMemAccessType(Instruction::IPUT_SHORT));
463*795d594fSAndroid Build Coastguard Worker 
AnalyseMethodCode(ArtMethod * method,const CodeItemDataAccessor * code_item,InlineMethod * result)464*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method,
465*795d594fSAndroid Build Coastguard Worker                                              const CodeItemDataAccessor* code_item,
466*795d594fSAndroid Build Coastguard Worker                                              InlineMethod* result) {
467*795d594fSAndroid Build Coastguard Worker   // We currently support only plain return or 2-instruction methods.
468*795d594fSAndroid Build Coastguard Worker 
469*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(code_item->InsnsSizeInCodeUnits(), 0u);
470*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = code_item->begin()->Opcode();
471*795d594fSAndroid Build Coastguard Worker 
472*795d594fSAndroid Build Coastguard Worker   switch (opcode) {
473*795d594fSAndroid Build Coastguard Worker     case Instruction::RETURN_VOID:
474*795d594fSAndroid Build Coastguard Worker       if (result != nullptr) {
475*795d594fSAndroid Build Coastguard Worker         result->opcode = kInlineOpNop;
476*795d594fSAndroid Build Coastguard Worker         result->d.data = 0u;
477*795d594fSAndroid Build Coastguard Worker       }
478*795d594fSAndroid Build Coastguard Worker       return true;
479*795d594fSAndroid Build Coastguard Worker     case Instruction::RETURN:
480*795d594fSAndroid Build Coastguard Worker     case Instruction::RETURN_OBJECT:
481*795d594fSAndroid Build Coastguard Worker     case Instruction::RETURN_WIDE:
482*795d594fSAndroid Build Coastguard Worker       return AnalyseReturnMethod(code_item, result);
483*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST:
484*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_4:
485*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_16:
486*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_HIGH16:
487*795d594fSAndroid Build Coastguard Worker       // TODO: Support wide constants (RETURN_WIDE).
488*795d594fSAndroid Build Coastguard Worker       if (AnalyseConstMethod(code_item, result)) {
489*795d594fSAndroid Build Coastguard Worker         return true;
490*795d594fSAndroid Build Coastguard Worker       }
491*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
492*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_WIDE:
493*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_WIDE_16:
494*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_WIDE_32:
495*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_WIDE_HIGH16:
496*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_DIRECT:
497*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_DIRECT_RANGE:
498*795d594fSAndroid Build Coastguard Worker       if (method != nullptr && !method->IsStatic() && method->IsConstructor()) {
499*795d594fSAndroid Build Coastguard Worker         return AnalyseConstructor(code_item, method, result);
500*795d594fSAndroid Build Coastguard Worker       }
501*795d594fSAndroid Build Coastguard Worker       return false;
502*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET:
503*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_OBJECT:
504*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_BOOLEAN:
505*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_BYTE:
506*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_CHAR:
507*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_SHORT:
508*795d594fSAndroid Build Coastguard Worker     case Instruction::IGET_WIDE:
509*795d594fSAndroid Build Coastguard Worker       return AnalyseIGetMethod(method, code_item, result);
510*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT:
511*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_OBJECT:
512*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_BOOLEAN:
513*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_BYTE:
514*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_CHAR:
515*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_SHORT:
516*795d594fSAndroid Build Coastguard Worker     case Instruction::IPUT_WIDE:
517*795d594fSAndroid Build Coastguard Worker       return AnalyseIPutMethod(method, code_item, result);
518*795d594fSAndroid Build Coastguard Worker     default:
519*795d594fSAndroid Build Coastguard Worker       return false;
520*795d594fSAndroid Build Coastguard Worker   }
521*795d594fSAndroid Build Coastguard Worker }
522*795d594fSAndroid Build Coastguard Worker 
IsSyntheticAccessor(ArtMethod * method)523*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::IsSyntheticAccessor(ArtMethod* method) {
524*795d594fSAndroid Build Coastguard Worker   const DexFile* dex_file = method->GetDexFile();
525*795d594fSAndroid Build Coastguard Worker   const dex::MethodId& method_id = dex_file->GetMethodId(method->GetDexMethodIndex());
526*795d594fSAndroid Build Coastguard Worker   const char* method_name = dex_file->GetMethodName(method_id);
527*795d594fSAndroid Build Coastguard Worker   // javac names synthetic accessors "access$nnn",
528*795d594fSAndroid Build Coastguard Worker   // jack names them "-getN", "-putN", "-wrapN".
529*795d594fSAndroid Build Coastguard Worker   return strncmp(method_name, "access$", strlen("access$")) == 0 ||
530*795d594fSAndroid Build Coastguard Worker       strncmp(method_name, "-", strlen("-")) == 0;
531*795d594fSAndroid Build Coastguard Worker }
532*795d594fSAndroid Build Coastguard Worker 
AnalyseReturnMethod(const CodeItemDataAccessor * code_item,InlineMethod * result)533*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::AnalyseReturnMethod(const CodeItemDataAccessor* code_item,
534*795d594fSAndroid Build Coastguard Worker                                                InlineMethod* result) {
535*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator return_instruction = code_item->begin();
536*795d594fSAndroid Build Coastguard Worker   Instruction::Code return_opcode = return_instruction->Opcode();
537*795d594fSAndroid Build Coastguard Worker   uint32_t reg = return_instruction->VRegA_11x();
538*795d594fSAndroid Build Coastguard Worker   uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
539*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(reg, arg_start);
540*795d594fSAndroid Build Coastguard Worker   DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
541*795d594fSAndroid Build Coastguard Worker       code_item->RegistersSize());
542*795d594fSAndroid Build Coastguard Worker 
543*795d594fSAndroid Build Coastguard Worker   if (result != nullptr) {
544*795d594fSAndroid Build Coastguard Worker     result->opcode = kInlineOpReturnArg;
545*795d594fSAndroid Build Coastguard Worker     InlineReturnArgData* data = &result->d.return_data;
546*795d594fSAndroid Build Coastguard Worker     data->arg = reg - arg_start;
547*795d594fSAndroid Build Coastguard Worker     data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u;
548*795d594fSAndroid Build Coastguard Worker     data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
549*795d594fSAndroid Build Coastguard Worker     data->reserved = 0u;
550*795d594fSAndroid Build Coastguard Worker     data->reserved2 = 0u;
551*795d594fSAndroid Build Coastguard Worker   }
552*795d594fSAndroid Build Coastguard Worker   return true;
553*795d594fSAndroid Build Coastguard Worker }
554*795d594fSAndroid Build Coastguard Worker 
AnalyseConstMethod(const CodeItemDataAccessor * code_item,InlineMethod * result)555*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::AnalyseConstMethod(const CodeItemDataAccessor* code_item,
556*795d594fSAndroid Build Coastguard Worker                                               InlineMethod* result) {
557*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator instruction = code_item->begin();
558*795d594fSAndroid Build Coastguard Worker   const Instruction* return_instruction = instruction->Next();
559*795d594fSAndroid Build Coastguard Worker   Instruction::Code return_opcode = return_instruction->Opcode();
560*795d594fSAndroid Build Coastguard Worker   if (return_opcode != Instruction::RETURN &&
561*795d594fSAndroid Build Coastguard Worker       return_opcode != Instruction::RETURN_OBJECT) {
562*795d594fSAndroid Build Coastguard Worker     return false;
563*795d594fSAndroid Build Coastguard Worker   }
564*795d594fSAndroid Build Coastguard Worker 
565*795d594fSAndroid Build Coastguard Worker   int32_t return_reg = return_instruction->VRegA_11x();
566*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(return_reg, code_item->RegistersSize());
567*795d594fSAndroid Build Coastguard Worker 
568*795d594fSAndroid Build Coastguard Worker   int32_t const_value = instruction->VRegB();
569*795d594fSAndroid Build Coastguard Worker   if (instruction->Opcode() == Instruction::CONST_HIGH16) {
570*795d594fSAndroid Build Coastguard Worker     const_value <<= 16;
571*795d594fSAndroid Build Coastguard Worker   }
572*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(instruction->VRegA(), code_item->RegistersSize());
573*795d594fSAndroid Build Coastguard Worker   if (instruction->VRegA() != return_reg) {
574*795d594fSAndroid Build Coastguard Worker     return false;  // Not returning the value set by const?
575*795d594fSAndroid Build Coastguard Worker   }
576*795d594fSAndroid Build Coastguard Worker   if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) {
577*795d594fSAndroid Build Coastguard Worker     return false;  // Returning non-null reference constant?
578*795d594fSAndroid Build Coastguard Worker   }
579*795d594fSAndroid Build Coastguard Worker   if (result != nullptr) {
580*795d594fSAndroid Build Coastguard Worker     result->opcode = kInlineOpNonWideConst;
581*795d594fSAndroid Build Coastguard Worker     result->d.data = static_cast<uint64_t>(const_value);
582*795d594fSAndroid Build Coastguard Worker   }
583*795d594fSAndroid Build Coastguard Worker   return true;
584*795d594fSAndroid Build Coastguard Worker }
585*795d594fSAndroid Build Coastguard Worker 
AnalyseIGetMethod(ArtMethod * method,const CodeItemDataAccessor * code_item,InlineMethod * result)586*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::AnalyseIGetMethod(ArtMethod* method,
587*795d594fSAndroid Build Coastguard Worker                                              const CodeItemDataAccessor* code_item,
588*795d594fSAndroid Build Coastguard Worker                                              InlineMethod* result) {
589*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator instruction = code_item->begin();
590*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = instruction->Opcode();
591*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInstructionIGet(opcode));
592*795d594fSAndroid Build Coastguard Worker 
593*795d594fSAndroid Build Coastguard Worker   const Instruction* return_instruction = instruction->Next();
594*795d594fSAndroid Build Coastguard Worker   Instruction::Code return_opcode = return_instruction->Opcode();
595*795d594fSAndroid Build Coastguard Worker   if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) &&
596*795d594fSAndroid Build Coastguard Worker       !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) &&
597*795d594fSAndroid Build Coastguard Worker       !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE &&
598*795d594fSAndroid Build Coastguard Worker           opcode != Instruction::IGET_OBJECT)) {
599*795d594fSAndroid Build Coastguard Worker     return false;
600*795d594fSAndroid Build Coastguard Worker   }
601*795d594fSAndroid Build Coastguard Worker 
602*795d594fSAndroid Build Coastguard Worker   uint32_t return_reg = return_instruction->VRegA_11x();
603*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
604*795d594fSAndroid Build Coastguard Worker             code_item->RegistersSize());
605*795d594fSAndroid Build Coastguard Worker 
606*795d594fSAndroid Build Coastguard Worker   uint32_t dst_reg = instruction->VRegA_22c();
607*795d594fSAndroid Build Coastguard Worker   uint32_t object_reg = instruction->VRegB_22c();
608*795d594fSAndroid Build Coastguard Worker   uint32_t field_idx = instruction->VRegC_22c();
609*795d594fSAndroid Build Coastguard Worker   uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
610*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(object_reg, arg_start);
611*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(object_reg, code_item->RegistersSize());
612*795d594fSAndroid Build Coastguard Worker   uint32_t object_arg = object_reg - arg_start;
613*795d594fSAndroid Build Coastguard Worker 
614*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize());
615*795d594fSAndroid Build Coastguard Worker   if (dst_reg != return_reg) {
616*795d594fSAndroid Build Coastguard Worker     return false;  // Not returning the value retrieved by IGET?
617*795d594fSAndroid Build Coastguard Worker   }
618*795d594fSAndroid Build Coastguard Worker 
619*795d594fSAndroid Build Coastguard Worker   // InlineIGetIPutData::object_arg is only 4 bits wide.
620*795d594fSAndroid Build Coastguard Worker   static constexpr uint16_t kMaxObjectArg = 15u;
621*795d594fSAndroid Build Coastguard Worker   if (object_arg > kMaxObjectArg) {
622*795d594fSAndroid Build Coastguard Worker     return false;
623*795d594fSAndroid Build Coastguard Worker   }
624*795d594fSAndroid Build Coastguard Worker 
625*795d594fSAndroid Build Coastguard Worker   bool is_static = method->IsStatic();
626*795d594fSAndroid Build Coastguard Worker   if (is_static || object_arg != 0u) {
627*795d594fSAndroid Build Coastguard Worker     // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE).
628*795d594fSAndroid Build Coastguard Worker     // Allow synthetic accessors. We don't care about losing their stack frame in NPE.
629*795d594fSAndroid Build Coastguard Worker     if (!IsSyntheticAccessor(method)) {
630*795d594fSAndroid Build Coastguard Worker       return false;
631*795d594fSAndroid Build Coastguard Worker     }
632*795d594fSAndroid Build Coastguard Worker   }
633*795d594fSAndroid Build Coastguard Worker 
634*795d594fSAndroid Build Coastguard Worker   DCHECK(result != nullptr);
635*795d594fSAndroid Build Coastguard Worker   InlineIGetIPutData* data = &result->d.ifield_data;
636*795d594fSAndroid Build Coastguard Worker   if (!ComputeSpecialAccessorInfo(method, field_idx, false, data)) {
637*795d594fSAndroid Build Coastguard Worker     return false;
638*795d594fSAndroid Build Coastguard Worker   }
639*795d594fSAndroid Build Coastguard Worker   result->opcode = kInlineOpIGet;
640*795d594fSAndroid Build Coastguard Worker   data->op_variant = enum_cast<uint16_t>(IGetMemAccessType(opcode));
641*795d594fSAndroid Build Coastguard Worker   data->method_is_static = is_static ? 1u : 0u;
642*795d594fSAndroid Build Coastguard Worker   data->object_arg = object_arg;  // Allow IGET on any register, not just "this".
643*795d594fSAndroid Build Coastguard Worker   data->src_arg = 0u;
644*795d594fSAndroid Build Coastguard Worker   data->return_arg_plus1 = 0u;
645*795d594fSAndroid Build Coastguard Worker   return true;
646*795d594fSAndroid Build Coastguard Worker }
647*795d594fSAndroid Build Coastguard Worker 
AnalyseIPutMethod(ArtMethod * method,const CodeItemDataAccessor * code_item,InlineMethod * result)648*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::AnalyseIPutMethod(ArtMethod* method,
649*795d594fSAndroid Build Coastguard Worker                                              const CodeItemDataAccessor* code_item,
650*795d594fSAndroid Build Coastguard Worker                                              InlineMethod* result) {
651*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator instruction = code_item->begin();
652*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = instruction->Opcode();
653*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInstructionIPut(opcode));
654*795d594fSAndroid Build Coastguard Worker 
655*795d594fSAndroid Build Coastguard Worker   const Instruction* return_instruction = instruction->Next();
656*795d594fSAndroid Build Coastguard Worker   Instruction::Code return_opcode = return_instruction->Opcode();
657*795d594fSAndroid Build Coastguard Worker   uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
658*795d594fSAndroid Build Coastguard Worker   uint16_t return_arg_plus1 = 0u;
659*795d594fSAndroid Build Coastguard Worker   if (return_opcode != Instruction::RETURN_VOID) {
660*795d594fSAndroid Build Coastguard Worker     if (return_opcode != Instruction::RETURN &&
661*795d594fSAndroid Build Coastguard Worker         return_opcode != Instruction::RETURN_OBJECT &&
662*795d594fSAndroid Build Coastguard Worker         return_opcode != Instruction::RETURN_WIDE) {
663*795d594fSAndroid Build Coastguard Worker       return false;
664*795d594fSAndroid Build Coastguard Worker     }
665*795d594fSAndroid Build Coastguard Worker     // Returning an argument.
666*795d594fSAndroid Build Coastguard Worker     uint32_t return_reg = return_instruction->VRegA_11x();
667*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(return_reg, arg_start);
668*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg,
669*795d594fSAndroid Build Coastguard Worker               code_item->RegistersSize());
670*795d594fSAndroid Build Coastguard Worker     return_arg_plus1 = return_reg - arg_start + 1u;
671*795d594fSAndroid Build Coastguard Worker   }
672*795d594fSAndroid Build Coastguard Worker 
673*795d594fSAndroid Build Coastguard Worker   uint32_t src_reg = instruction->VRegA_22c();
674*795d594fSAndroid Build Coastguard Worker   uint32_t object_reg = instruction->VRegB_22c();
675*795d594fSAndroid Build Coastguard Worker   uint32_t field_idx = instruction->VRegC_22c();
676*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(object_reg, arg_start);
677*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(object_reg, code_item->RegistersSize());
678*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(src_reg, arg_start);
679*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->RegistersSize());
680*795d594fSAndroid Build Coastguard Worker   uint32_t object_arg = object_reg - arg_start;
681*795d594fSAndroid Build Coastguard Worker   uint32_t src_arg = src_reg - arg_start;
682*795d594fSAndroid Build Coastguard Worker 
683*795d594fSAndroid Build Coastguard Worker   // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide.
684*795d594fSAndroid Build Coastguard Worker   static constexpr uint16_t kMaxObjectArg = 15u;
685*795d594fSAndroid Build Coastguard Worker   static constexpr uint16_t kMaxSrcArg = 15u;
686*795d594fSAndroid Build Coastguard Worker   static constexpr uint16_t kMaxReturnArgPlus1 = 15u;
687*795d594fSAndroid Build Coastguard Worker   if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) {
688*795d594fSAndroid Build Coastguard Worker     return false;
689*795d594fSAndroid Build Coastguard Worker   }
690*795d594fSAndroid Build Coastguard Worker 
691*795d594fSAndroid Build Coastguard Worker   bool is_static = method->IsStatic();
692*795d594fSAndroid Build Coastguard Worker   if (is_static || object_arg != 0u) {
693*795d594fSAndroid Build Coastguard Worker     // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE).
694*795d594fSAndroid Build Coastguard Worker     // Allow synthetic accessors. We don't care about losing their stack frame in NPE.
695*795d594fSAndroid Build Coastguard Worker     if (!IsSyntheticAccessor(method)) {
696*795d594fSAndroid Build Coastguard Worker       return false;
697*795d594fSAndroid Build Coastguard Worker     }
698*795d594fSAndroid Build Coastguard Worker   }
699*795d594fSAndroid Build Coastguard Worker 
700*795d594fSAndroid Build Coastguard Worker   DCHECK(result != nullptr);
701*795d594fSAndroid Build Coastguard Worker   InlineIGetIPutData* data = &result->d.ifield_data;
702*795d594fSAndroid Build Coastguard Worker   if (!ComputeSpecialAccessorInfo(method, field_idx, true, data)) {
703*795d594fSAndroid Build Coastguard Worker     return false;
704*795d594fSAndroid Build Coastguard Worker   }
705*795d594fSAndroid Build Coastguard Worker   result->opcode = kInlineOpIPut;
706*795d594fSAndroid Build Coastguard Worker   data->op_variant = enum_cast<uint16_t>(IPutMemAccessType(opcode));
707*795d594fSAndroid Build Coastguard Worker   data->method_is_static = is_static ? 1u : 0u;
708*795d594fSAndroid Build Coastguard Worker   data->object_arg = object_arg;  // Allow IPUT on any register, not just "this".
709*795d594fSAndroid Build Coastguard Worker   data->src_arg = src_arg;
710*795d594fSAndroid Build Coastguard Worker   data->return_arg_plus1 = return_arg_plus1;
711*795d594fSAndroid Build Coastguard Worker   return true;
712*795d594fSAndroid Build Coastguard Worker }
713*795d594fSAndroid Build Coastguard Worker 
ComputeSpecialAccessorInfo(ArtMethod * method,uint32_t field_idx,bool is_put,InlineIGetIPutData * result)714*795d594fSAndroid Build Coastguard Worker bool InlineMethodAnalyser::ComputeSpecialAccessorInfo(ArtMethod* method,
715*795d594fSAndroid Build Coastguard Worker                                                       uint32_t field_idx,
716*795d594fSAndroid Build Coastguard Worker                                                       bool is_put,
717*795d594fSAndroid Build Coastguard Worker                                                       InlineIGetIPutData* result) {
718*795d594fSAndroid Build Coastguard Worker   if (method == nullptr) {
719*795d594fSAndroid Build Coastguard Worker     return false;
720*795d594fSAndroid Build Coastguard Worker   }
721*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::DexCache> dex_cache = method->GetDexCache();
722*795d594fSAndroid Build Coastguard Worker   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
723*795d594fSAndroid Build Coastguard Worker   ArtField* field = class_linker->LookupResolvedField(field_idx, method, /* is_static= */ false);
724*795d594fSAndroid Build Coastguard Worker   if (field == nullptr || field->IsStatic()) {
725*795d594fSAndroid Build Coastguard Worker     return false;
726*795d594fSAndroid Build Coastguard Worker   }
727*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> method_class = method->GetDeclaringClass();
728*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> field_class = field->GetDeclaringClass();
729*795d594fSAndroid Build Coastguard Worker   if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
730*795d594fSAndroid Build Coastguard Worker       (is_put && field->IsFinal() && method_class != field_class)) {
731*795d594fSAndroid Build Coastguard Worker     return false;
732*795d594fSAndroid Build Coastguard Worker   }
733*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(field->GetOffset().Int32Value(), 0);
734*795d594fSAndroid Build Coastguard Worker   // Historical note: We made sure not to interleave function calls with bit field writes to
735*795d594fSAndroid Build Coastguard Worker   // placate Valgrind. Bug: 27552451.
736*795d594fSAndroid Build Coastguard Worker   uint32_t field_offset = field->GetOffset().Uint32Value();
737*795d594fSAndroid Build Coastguard Worker   bool is_volatile = field->IsVolatile();
738*795d594fSAndroid Build Coastguard Worker   result->field_idx = field_idx;
739*795d594fSAndroid Build Coastguard Worker   result->field_offset = field_offset;
740*795d594fSAndroid Build Coastguard Worker   result->is_volatile = is_volatile ? 1u : 0u;
741*795d594fSAndroid Build Coastguard Worker   return true;
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker 
744*795d594fSAndroid Build Coastguard Worker }  // namespace art
745