xref: /aosp_15_r20/art/runtime/jit/small_pattern_matcher.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright 2023 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 "small_pattern_matcher.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "entrypoints/entrypoint_utils-inl.h"
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
24*795d594fSAndroid Build Coastguard Worker namespace jit {
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker // The following methods will be directly invoked by our own JIT/AOT compiled
27*795d594fSAndroid Build Coastguard Worker // code.
28*795d594fSAndroid Build Coastguard Worker 
EmptyMethod()29*795d594fSAndroid Build Coastguard Worker static void EmptyMethod() {}
ReturnZero()30*795d594fSAndroid Build Coastguard Worker static int32_t ReturnZero() { return 0; }
ReturnOne()31*795d594fSAndroid Build Coastguard Worker static int32_t ReturnOne() { return 1; }
ReturnFirstArgMethod(ArtMethod * method,int32_t first_arg)32*795d594fSAndroid Build Coastguard Worker static int32_t ReturnFirstArgMethod([[maybe_unused]] ArtMethod* method, int32_t first_arg) {
33*795d594fSAndroid Build Coastguard Worker   return first_arg;
34*795d594fSAndroid Build Coastguard Worker }
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker template <int offset, typename T>
ReturnFieldAt(ArtMethod * method,mirror::Object * obj)37*795d594fSAndroid Build Coastguard Worker static std::conditional_t<(sizeof(T) < sizeof(int32_t)), int32_t, T> ReturnFieldAt(
38*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] ArtMethod* method, mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
39*795d594fSAndroid Build Coastguard Worker   return obj->GetFieldPrimitive<T, /* kIsVolatile= */ false>(
40*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + sizeof(mirror::Object)));
41*795d594fSAndroid Build Coastguard Worker }
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker template <int offset, typename unused>
ReturnFieldObjectAt(ArtMethod * method,mirror::Object * obj)44*795d594fSAndroid Build Coastguard Worker static mirror::Object* ReturnFieldObjectAt([[maybe_unused]] ArtMethod* method, mirror::Object* obj)
45*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
46*795d594fSAndroid Build Coastguard Worker   return obj->GetFieldObject<mirror::Object>(MemberOffset(offset + sizeof(mirror::Object)));
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker template <int offset, typename T>
ReturnStaticFieldAt(ArtMethod * method)50*795d594fSAndroid Build Coastguard Worker static std::conditional_t<(sizeof(T) < sizeof(int32_t)), int32_t, T> ReturnStaticFieldAt(
51*795d594fSAndroid Build Coastguard Worker     ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
52*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> cls = method->GetDeclaringClass();
53*795d594fSAndroid Build Coastguard Worker   MemberOffset first_field_offset = cls->GetFirstReferenceStaticFieldOffset(kRuntimePointerSize);
54*795d594fSAndroid Build Coastguard Worker   return cls->GetFieldPrimitive<T, /* kIsVolatile= */ false>(
55*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + first_field_offset.Int32Value()));
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker template <int offset, typename unused>
ReturnStaticFieldObjectAt(ArtMethod * method)59*795d594fSAndroid Build Coastguard Worker static mirror::Object* ReturnStaticFieldObjectAt(ArtMethod* method)
60*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
61*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> cls = method->GetDeclaringClass();
62*795d594fSAndroid Build Coastguard Worker   MemberOffset first_field_offset = cls->GetFirstReferenceStaticFieldOffset(kRuntimePointerSize);
63*795d594fSAndroid Build Coastguard Worker   return cls->GetFieldObject<mirror::Object>(
64*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + first_field_offset.Int32Value()));
65*795d594fSAndroid Build Coastguard Worker }
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker template <int offset, typename T>
SetFieldAt(ArtMethod * method,mirror::Object * obj,T value)68*795d594fSAndroid Build Coastguard Worker static void SetFieldAt([[maybe_unused]] ArtMethod* method, mirror::Object* obj, T value)
69*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
70*795d594fSAndroid Build Coastguard Worker   obj->SetFieldPrimitive<T, /* kIsVolatile= */ false>(
71*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + sizeof(mirror::Object)), value);
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker template <int offset, typename unused>
SetFieldObjectAt(ArtMethod * method,mirror::Object * obj,mirror::Object * value)75*795d594fSAndroid Build Coastguard Worker static void SetFieldObjectAt([[maybe_unused]] ArtMethod* method,
76*795d594fSAndroid Build Coastguard Worker                              mirror::Object* obj,
77*795d594fSAndroid Build Coastguard Worker                              mirror::Object* value)
78*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
79*795d594fSAndroid Build Coastguard Worker   obj->SetFieldObject</* kTransactionActive */ false>(
80*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + sizeof(mirror::Object)), value);
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker template <int offset, typename T>
ConstructorSetFieldAt(ArtMethod * method,mirror::Object * obj,T value)84*795d594fSAndroid Build Coastguard Worker static void ConstructorSetFieldAt([[maybe_unused]] ArtMethod* method, mirror::Object* obj, T value)
85*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
86*795d594fSAndroid Build Coastguard Worker   obj->SetFieldPrimitive<T, /* kIsVolatile= */ false>(
87*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + sizeof(mirror::Object)), value);
88*795d594fSAndroid Build Coastguard Worker   QuasiAtomic::ThreadFenceForConstructor();
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker template <int offset, typename unused>
ConstructorSetFieldObjectAt(ArtMethod * method,mirror::Object * obj,mirror::Object * value)92*795d594fSAndroid Build Coastguard Worker static void ConstructorSetFieldObjectAt([[maybe_unused]] ArtMethod* method,
93*795d594fSAndroid Build Coastguard Worker                                         mirror::Object* obj,
94*795d594fSAndroid Build Coastguard Worker                                         mirror::Object* value)
95*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
96*795d594fSAndroid Build Coastguard Worker   obj->SetFieldObject</* kTransactionActive */ false>(
97*795d594fSAndroid Build Coastguard Worker       MemberOffset(offset + sizeof(mirror::Object)), value);
98*795d594fSAndroid Build Coastguard Worker   QuasiAtomic::ThreadFenceForConstructor();
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker #define SWITCH_CASE(offset, func, type) \
102*795d594fSAndroid Build Coastguard Worker   case offset:                          \
103*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<void*>(&func<offset, type>);  // NOLINT [bugprone-macro-parentheses]
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker #define DO_SWITCH_OFFSET(offset, F, T) \
106*795d594fSAndroid Build Coastguard Worker   switch (offset) { \
107*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(0, F, T) \
108*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(4, F, T) \
109*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(8, F, T) \
110*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(12, F, T) \
111*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(16, F, T) \
112*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(20, F, T) \
113*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(24, F, T) \
114*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(28, F, T) \
115*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(32, F, T) \
116*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(36, F, T) \
117*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(40, F, T) \
118*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(44, F, T) \
119*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(48, F, T) \
120*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(52, F, T) \
121*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(56, F, T) \
122*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(60, F, T) \
123*795d594fSAndroid Build Coastguard Worker     SWITCH_CASE(64, F, T) \
124*795d594fSAndroid Build Coastguard Worker     default: return nullptr; \
125*795d594fSAndroid Build Coastguard Worker   }
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker #define DO_SWITCH(offset, O, P, K)                  \
128*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(is_object, (K) == Primitive::kPrimNot); \
129*795d594fSAndroid Build Coastguard Worker   switch (K) {                                      \
130*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimBoolean:                   \
131*795d594fSAndroid Build Coastguard Worker       DO_SWITCH_OFFSET(offset, P, uint8_t);         \
132*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimInt:                       \
133*795d594fSAndroid Build Coastguard Worker       DO_SWITCH_OFFSET(offset, P, int32_t);         \
134*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimLong:                      \
135*795d594fSAndroid Build Coastguard Worker       DO_SWITCH_OFFSET(offset, P, int64_t);         \
136*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimNot:                       \
137*795d594fSAndroid Build Coastguard Worker       DO_SWITCH_OFFSET(offset, O, mirror::Object*); \
138*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimFloat:                     \
139*795d594fSAndroid Build Coastguard Worker       if (kRuntimeISA == InstructionSet::kArm64) {  \
140*795d594fSAndroid Build Coastguard Worker         DO_SWITCH_OFFSET(offset, P, float);         \
141*795d594fSAndroid Build Coastguard Worker       } else {                                      \
142*795d594fSAndroid Build Coastguard Worker         return nullptr;                             \
143*795d594fSAndroid Build Coastguard Worker       }                                             \
144*795d594fSAndroid Build Coastguard Worker     case Primitive::kPrimDouble:                    \
145*795d594fSAndroid Build Coastguard Worker       if (kRuntimeISA == InstructionSet::kArm64) {  \
146*795d594fSAndroid Build Coastguard Worker         DO_SWITCH_OFFSET(offset, P, double);        \
147*795d594fSAndroid Build Coastguard Worker       } else {                                      \
148*795d594fSAndroid Build Coastguard Worker         return nullptr;                             \
149*795d594fSAndroid Build Coastguard Worker       }                                             \
150*795d594fSAndroid Build Coastguard Worker     default:                                        \
151*795d594fSAndroid Build Coastguard Worker       return nullptr;                               \
152*795d594fSAndroid Build Coastguard Worker   }
153*795d594fSAndroid Build Coastguard Worker 
TryMatch(ArtMethod * method)154*795d594fSAndroid Build Coastguard Worker const void* SmallPatternMatcher::TryMatch(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
155*795d594fSAndroid Build Coastguard Worker   CodeItemDataAccessor accessor(*method->GetDexFile(), method->GetCodeItem());
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker   bool is_recognizable_constructor =
160*795d594fSAndroid Build Coastguard Worker       method->IsConstructor() &&
161*795d594fSAndroid Build Coastguard Worker       !method->IsStatic() &&
162*795d594fSAndroid Build Coastguard Worker       method->GetDeclaringClass()->GetSuperClass() != nullptr &&
163*795d594fSAndroid Build Coastguard Worker       method->GetDeclaringClass()->GetSuperClass()->IsObjectClass();
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker   size_t insns_size = accessor.InsnsSizeInCodeUnits();
166*795d594fSAndroid Build Coastguard Worker   if (insns_size >= 4u) {
167*795d594fSAndroid Build Coastguard Worker     if (!is_recognizable_constructor) {
168*795d594fSAndroid Build Coastguard Worker       return nullptr;
169*795d594fSAndroid Build Coastguard Worker     }
170*795d594fSAndroid Build Coastguard Worker     // We can recognize a constructor with 6 or 4 code units.
171*795d594fSAndroid Build Coastguard Worker     if (insns_size != 4u && insns_size != 6u) {
172*795d594fSAndroid Build Coastguard Worker       return nullptr;
173*795d594fSAndroid Build Coastguard Worker     }
174*795d594fSAndroid Build Coastguard Worker   }
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker   auto is_object_init_invoke = [&](const Instruction& instruction)
177*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
178*795d594fSAndroid Build Coastguard Worker     uint16_t method_idx = instruction.VRegB_35c();
179*795d594fSAndroid Build Coastguard Worker     Thread* self = Thread::Current();
180*795d594fSAndroid Build Coastguard Worker     ArtMethod* target_method = class_linker->ResolveMethodId(method_idx, method);
181*795d594fSAndroid Build Coastguard Worker     if (target_method == nullptr) {
182*795d594fSAndroid Build Coastguard Worker       self->ClearException();
183*795d594fSAndroid Build Coastguard Worker       return false;
184*795d594fSAndroid Build Coastguard Worker     }
185*795d594fSAndroid Build Coastguard Worker     if (!target_method->GetDeclaringClass()->IsObjectClass()) {
186*795d594fSAndroid Build Coastguard Worker       return false;
187*795d594fSAndroid Build Coastguard Worker     }
188*795d594fSAndroid Build Coastguard Worker     DCHECK(target_method->GetDeclaringClass()->IsVerified());
189*795d594fSAndroid Build Coastguard Worker     CodeItemDataAccessor accessor(*target_method->GetDexFile(), target_method->GetCodeItem());
190*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(accessor.InsnsSizeInCodeUnits(), 1u);
191*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(accessor.begin().Inst().Opcode(), Instruction::RETURN_VOID);
192*795d594fSAndroid Build Coastguard Worker     return true;
193*795d594fSAndroid Build Coastguard Worker   };
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker   // Recognize a constructor of the form:
196*795d594fSAndroid Build Coastguard Worker   //   invoke-direct v0, j.l.Object.<init>
197*795d594fSAndroid Build Coastguard Worker   //   return-void
198*795d594fSAndroid Build Coastguard Worker   if (insns_size == 4u) {
199*795d594fSAndroid Build Coastguard Worker     DCHECK(is_recognizable_constructor);
200*795d594fSAndroid Build Coastguard Worker     const Instruction& instruction = accessor.begin().Inst();
201*795d594fSAndroid Build Coastguard Worker     if (instruction.Opcode() == Instruction::INVOKE_DIRECT &&
202*795d594fSAndroid Build Coastguard Worker         is_object_init_invoke(instruction)) {
203*795d594fSAndroid Build Coastguard Worker       return reinterpret_cast<void*>(&EmptyMethod);
204*795d594fSAndroid Build Coastguard Worker     }
205*795d594fSAndroid Build Coastguard Worker     return nullptr;
206*795d594fSAndroid Build Coastguard Worker   }
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker   // Recognize:
209*795d594fSAndroid Build Coastguard Worker   //   return-void
210*795d594fSAndroid Build Coastguard Worker   // Or:
211*795d594fSAndroid Build Coastguard Worker   //   return-object v0
212*795d594fSAndroid Build Coastguard Worker   if (insns_size == 1u) {
213*795d594fSAndroid Build Coastguard Worker     const Instruction& instruction = accessor.begin().Inst();
214*795d594fSAndroid Build Coastguard Worker     if (instruction.Opcode() == Instruction::RETURN_VOID) {
215*795d594fSAndroid Build Coastguard Worker       return reinterpret_cast<void*>(&EmptyMethod);
216*795d594fSAndroid Build Coastguard Worker     }
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker     if (instruction.Opcode() == Instruction::RETURN_OBJECT) {
219*795d594fSAndroid Build Coastguard Worker       uint16_t number_of_vregs = accessor.RegistersSize();
220*795d594fSAndroid Build Coastguard Worker       uint16_t number_of_parameters = accessor.InsSize();
221*795d594fSAndroid Build Coastguard Worker       uint16_t obj_reg = number_of_vregs - number_of_parameters;
222*795d594fSAndroid Build Coastguard Worker       if (obj_reg == instruction.VRegA_11x()) {
223*795d594fSAndroid Build Coastguard Worker         return reinterpret_cast<void*>(&ReturnFirstArgMethod);
224*795d594fSAndroid Build Coastguard Worker       }
225*795d594fSAndroid Build Coastguard Worker     }
226*795d594fSAndroid Build Coastguard Worker     return nullptr;
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker   // Recognize:
230*795d594fSAndroid Build Coastguard Worker   //   const vX, 0/1
231*795d594fSAndroid Build Coastguard Worker   //   return{-object} vX
232*795d594fSAndroid Build Coastguard Worker   if (insns_size == 2u) {
233*795d594fSAndroid Build Coastguard Worker     if (method->GetReturnTypePrimitive() == Primitive::kPrimFloat) {
234*795d594fSAndroid Build Coastguard Worker       // Too rare to bother.
235*795d594fSAndroid Build Coastguard Worker       return nullptr;
236*795d594fSAndroid Build Coastguard Worker     }
237*795d594fSAndroid Build Coastguard Worker     int32_t register_index = -1;
238*795d594fSAndroid Build Coastguard Worker     int32_t constant = -1;
239*795d594fSAndroid Build Coastguard Worker     for (DexInstructionPcPair pair : accessor) {
240*795d594fSAndroid Build Coastguard Worker       const Instruction& instruction = pair.Inst();
241*795d594fSAndroid Build Coastguard Worker       switch (pair->Opcode()) {
242*795d594fSAndroid Build Coastguard Worker         case Instruction::CONST_4: {
243*795d594fSAndroid Build Coastguard Worker           register_index = instruction.VRegA_11n();
244*795d594fSAndroid Build Coastguard Worker           constant = instruction.VRegB_11n();
245*795d594fSAndroid Build Coastguard Worker           if (constant != 0 && constant != 1) {
246*795d594fSAndroid Build Coastguard Worker             return nullptr;
247*795d594fSAndroid Build Coastguard Worker           }
248*795d594fSAndroid Build Coastguard Worker           break;
249*795d594fSAndroid Build Coastguard Worker         }
250*795d594fSAndroid Build Coastguard Worker         case Instruction::CONST_16: {
251*795d594fSAndroid Build Coastguard Worker           register_index = instruction.VRegA_21s();
252*795d594fSAndroid Build Coastguard Worker           constant = instruction.VRegB_21s();
253*795d594fSAndroid Build Coastguard Worker           if (constant != 0 && constant != 1) {
254*795d594fSAndroid Build Coastguard Worker             return nullptr;
255*795d594fSAndroid Build Coastguard Worker           }
256*795d594fSAndroid Build Coastguard Worker           break;
257*795d594fSAndroid Build Coastguard Worker         }
258*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN:
259*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN_OBJECT: {
260*795d594fSAndroid Build Coastguard Worker           if (register_index == instruction.VRegA_11x()) {
261*795d594fSAndroid Build Coastguard Worker             if (constant == 0) {
262*795d594fSAndroid Build Coastguard Worker               return reinterpret_cast<void*>(&ReturnZero);
263*795d594fSAndroid Build Coastguard Worker             } else if (constant == 1) {
264*795d594fSAndroid Build Coastguard Worker               return reinterpret_cast<void*>(&ReturnOne);
265*795d594fSAndroid Build Coastguard Worker             }
266*795d594fSAndroid Build Coastguard Worker           }
267*795d594fSAndroid Build Coastguard Worker           return nullptr;
268*795d594fSAndroid Build Coastguard Worker         }
269*795d594fSAndroid Build Coastguard Worker         default:
270*795d594fSAndroid Build Coastguard Worker           return nullptr;
271*795d594fSAndroid Build Coastguard Worker       }
272*795d594fSAndroid Build Coastguard Worker     }
273*795d594fSAndroid Build Coastguard Worker     return nullptr;
274*795d594fSAndroid Build Coastguard Worker   }
275*795d594fSAndroid Build Coastguard Worker 
276*795d594fSAndroid Build Coastguard Worker   // Recognize:
277*795d594fSAndroid Build Coastguard Worker   //   iget-{object,wide,boolean} vX, v0, field
278*795d594fSAndroid Build Coastguard Worker   //   return-{object} vX
279*795d594fSAndroid Build Coastguard Worker   // Or:
280*795d594fSAndroid Build Coastguard Worker   //   iput-{object,wide,boolean} v1, v0, field
281*795d594fSAndroid Build Coastguard Worker   //   return-void
282*795d594fSAndroid Build Coastguard Worker   // Or:
283*795d594fSAndroid Build Coastguard Worker   //   sget-object vX, field
284*795d594fSAndroid Build Coastguard Worker   //   return-object vX
285*795d594fSAndroid Build Coastguard Worker   // Or:
286*795d594fSAndroid Build Coastguard Worker   //   iput-{object,wide,boolean} v1, v0, field
287*795d594fSAndroid Build Coastguard Worker   //   invoke-direct v0, j.l.Object.<init>
288*795d594fSAndroid Build Coastguard Worker   //   return-void
289*795d594fSAndroid Build Coastguard Worker   // Or:
290*795d594fSAndroid Build Coastguard Worker   //   invoke-direct v0, j.l.Object.<init>
291*795d594fSAndroid Build Coastguard Worker   //   iput-{object,wide,boolean} v1, v0, field
292*795d594fSAndroid Build Coastguard Worker   //   return-void
293*795d594fSAndroid Build Coastguard Worker   if (insns_size == 3u || insns_size == 6u) {
294*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(insns_size == 6u, is_recognizable_constructor);
295*795d594fSAndroid Build Coastguard Worker     uint16_t number_of_vregs = accessor.RegistersSize();
296*795d594fSAndroid Build Coastguard Worker     uint16_t number_of_parameters = accessor.InsSize();
297*795d594fSAndroid Build Coastguard Worker     uint16_t obj_reg = number_of_vregs - number_of_parameters;
298*795d594fSAndroid Build Coastguard Worker     uint16_t first_param_reg = number_of_vregs - number_of_parameters + 1;
299*795d594fSAndroid Build Coastguard Worker     uint16_t dest_reg = -1;
300*795d594fSAndroid Build Coastguard Worker     uint32_t offset = -1;
301*795d594fSAndroid Build Coastguard Worker     bool is_object = false;
302*795d594fSAndroid Build Coastguard Worker     bool is_put = false;
303*795d594fSAndroid Build Coastguard Worker     bool is_static = false;
304*795d594fSAndroid Build Coastguard Worker     bool is_final = false;
305*795d594fSAndroid Build Coastguard Worker     Primitive::Type field_type;
306*795d594fSAndroid Build Coastguard Worker     for (DexInstructionPcPair pair : accessor) {
307*795d594fSAndroid Build Coastguard Worker       const Instruction& instruction = pair.Inst();
308*795d594fSAndroid Build Coastguard Worker       switch (pair->Opcode()) {
309*795d594fSAndroid Build Coastguard Worker         case Instruction::INVOKE_DIRECT:
310*795d594fSAndroid Build Coastguard Worker           if (!is_recognizable_constructor || !is_object_init_invoke(instruction)) {
311*795d594fSAndroid Build Coastguard Worker             return nullptr;
312*795d594fSAndroid Build Coastguard Worker           }
313*795d594fSAndroid Build Coastguard Worker           break;
314*795d594fSAndroid Build Coastguard Worker         case Instruction::SGET_OBJECT:
315*795d594fSAndroid Build Coastguard Worker           is_static = true;
316*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
317*795d594fSAndroid Build Coastguard Worker         case Instruction::IPUT_OBJECT:
318*795d594fSAndroid Build Coastguard Worker         case Instruction::IGET_OBJECT:
319*795d594fSAndroid Build Coastguard Worker           is_object = true;
320*795d594fSAndroid Build Coastguard Worker           FALLTHROUGH_INTENDED;
321*795d594fSAndroid Build Coastguard Worker         case Instruction::IPUT:
322*795d594fSAndroid Build Coastguard Worker         case Instruction::IGET:
323*795d594fSAndroid Build Coastguard Worker         case Instruction::IGET_BOOLEAN:
324*795d594fSAndroid Build Coastguard Worker         case Instruction::IPUT_BOOLEAN:
325*795d594fSAndroid Build Coastguard Worker         case Instruction::IGET_WIDE:
326*795d594fSAndroid Build Coastguard Worker         case Instruction::IPUT_WIDE: {
327*795d594fSAndroid Build Coastguard Worker           is_put = (pair->Opcode() == Instruction::IPUT ||
328*795d594fSAndroid Build Coastguard Worker                     pair->Opcode() == Instruction::IPUT_OBJECT ||
329*795d594fSAndroid Build Coastguard Worker                     pair->Opcode() == Instruction::IPUT_BOOLEAN ||
330*795d594fSAndroid Build Coastguard Worker                     pair->Opcode() == Instruction::IPUT_WIDE);
331*795d594fSAndroid Build Coastguard Worker           if (!is_static && obj_reg != instruction.VRegB_22c()) {
332*795d594fSAndroid Build Coastguard Worker             // The field access is not on the first parameter.
333*795d594fSAndroid Build Coastguard Worker             return nullptr;
334*795d594fSAndroid Build Coastguard Worker           }
335*795d594fSAndroid Build Coastguard Worker           if (!is_static && method->IsStatic()) {
336*795d594fSAndroid Build Coastguard Worker             // Getting/setting an instance field on an object that can be null.
337*795d594fSAndroid Build Coastguard Worker             // Our stubs cannot handle implicit null checks.
338*795d594fSAndroid Build Coastguard Worker             return nullptr;
339*795d594fSAndroid Build Coastguard Worker           }
340*795d594fSAndroid Build Coastguard Worker           if (is_put) {
341*795d594fSAndroid Build Coastguard Worker             if (first_param_reg != instruction.VRegA_22c()) {
342*795d594fSAndroid Build Coastguard Worker               // The value being stored is not the first parameter after 'this'.
343*795d594fSAndroid Build Coastguard Worker               return nullptr;
344*795d594fSAndroid Build Coastguard Worker             }
345*795d594fSAndroid Build Coastguard Worker           } else {
346*795d594fSAndroid Build Coastguard Worker             dest_reg = is_static ? instruction.VRegA_21c() : instruction.VRegA_22c();
347*795d594fSAndroid Build Coastguard Worker           }
348*795d594fSAndroid Build Coastguard Worker           uint16_t field_index = is_static ? instruction.VRegB_21c() : instruction.VRegC_22c();
349*795d594fSAndroid Build Coastguard Worker           Thread* self = Thread::Current();
350*795d594fSAndroid Build Coastguard Worker           ArtField* field =
351*795d594fSAndroid Build Coastguard Worker               ResolveFieldWithAccessChecks(Thread::Current(),
352*795d594fSAndroid Build Coastguard Worker                                            class_linker,
353*795d594fSAndroid Build Coastguard Worker                                            field_index,
354*795d594fSAndroid Build Coastguard Worker                                            method,
355*795d594fSAndroid Build Coastguard Worker                                            is_static,
356*795d594fSAndroid Build Coastguard Worker                                            is_put,
357*795d594fSAndroid Build Coastguard Worker                                            /* resolve_field_type= */ is_put && is_object);
358*795d594fSAndroid Build Coastguard Worker           if (field == nullptr) {
359*795d594fSAndroid Build Coastguard Worker             self->ClearException();
360*795d594fSAndroid Build Coastguard Worker             return nullptr;
361*795d594fSAndroid Build Coastguard Worker           }
362*795d594fSAndroid Build Coastguard Worker           if (field->IsVolatile()) {
363*795d594fSAndroid Build Coastguard Worker             return nullptr;
364*795d594fSAndroid Build Coastguard Worker           }
365*795d594fSAndroid Build Coastguard Worker           if (is_static && field->GetDeclaringClass() != method->GetDeclaringClass()) {
366*795d594fSAndroid Build Coastguard Worker             return nullptr;
367*795d594fSAndroid Build Coastguard Worker           }
368*795d594fSAndroid Build Coastguard Worker           offset = field->GetOffset().Int32Value();
369*795d594fSAndroid Build Coastguard Worker           if (is_static) {
370*795d594fSAndroid Build Coastguard Worker             // We subtract the start of reference fields to share more stubs.
371*795d594fSAndroid Build Coastguard Worker             MemberOffset first_field_offset =
372*795d594fSAndroid Build Coastguard Worker                 field->GetDeclaringClass()->GetFirstReferenceStaticFieldOffset(kRuntimePointerSize);
373*795d594fSAndroid Build Coastguard Worker             offset = offset - first_field_offset.Int32Value();
374*795d594fSAndroid Build Coastguard Worker           } else {
375*795d594fSAndroid Build Coastguard Worker             offset = offset - sizeof(mirror::Object);
376*795d594fSAndroid Build Coastguard Worker           }
377*795d594fSAndroid Build Coastguard Worker           if (offset > 64) {
378*795d594fSAndroid Build Coastguard Worker             return nullptr;
379*795d594fSAndroid Build Coastguard Worker           }
380*795d594fSAndroid Build Coastguard Worker           field_type = field->GetTypeAsPrimitiveType();
381*795d594fSAndroid Build Coastguard Worker           is_final = field->IsFinal();
382*795d594fSAndroid Build Coastguard Worker           break;
383*795d594fSAndroid Build Coastguard Worker         }
384*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN_OBJECT:
385*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN_WIDE:
386*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN: {
387*795d594fSAndroid Build Coastguard Worker           if (is_put || dest_reg != instruction.VRegA_11x()) {
388*795d594fSAndroid Build Coastguard Worker             // The returned value is not the fetched field.
389*795d594fSAndroid Build Coastguard Worker             return nullptr;
390*795d594fSAndroid Build Coastguard Worker           }
391*795d594fSAndroid Build Coastguard Worker           if (is_static) {
392*795d594fSAndroid Build Coastguard Worker             DO_SWITCH(offset, ReturnStaticFieldObjectAt, ReturnStaticFieldAt, field_type);
393*795d594fSAndroid Build Coastguard Worker           } else {
394*795d594fSAndroid Build Coastguard Worker             DO_SWITCH(offset, ReturnFieldObjectAt, ReturnFieldAt, field_type);
395*795d594fSAndroid Build Coastguard Worker           }
396*795d594fSAndroid Build Coastguard Worker         }
397*795d594fSAndroid Build Coastguard Worker         case Instruction::RETURN_VOID: {
398*795d594fSAndroid Build Coastguard Worker           if (!is_put) {
399*795d594fSAndroid Build Coastguard Worker             return nullptr;
400*795d594fSAndroid Build Coastguard Worker           }
401*795d594fSAndroid Build Coastguard Worker           if (is_final) {
402*795d594fSAndroid Build Coastguard Worker             DCHECK(is_recognizable_constructor);
403*795d594fSAndroid Build Coastguard Worker             DO_SWITCH(offset,  ConstructorSetFieldObjectAt, ConstructorSetFieldAt, field_type);
404*795d594fSAndroid Build Coastguard Worker           } else {
405*795d594fSAndroid Build Coastguard Worker             DO_SWITCH(offset, SetFieldObjectAt, SetFieldAt, field_type);
406*795d594fSAndroid Build Coastguard Worker           }
407*795d594fSAndroid Build Coastguard Worker         }
408*795d594fSAndroid Build Coastguard Worker         default:
409*795d594fSAndroid Build Coastguard Worker           return nullptr;
410*795d594fSAndroid Build Coastguard Worker       }
411*795d594fSAndroid Build Coastguard Worker     }
412*795d594fSAndroid Build Coastguard Worker   }
413*795d594fSAndroid Build Coastguard Worker 
414*795d594fSAndroid Build Coastguard Worker   return nullptr;
415*795d594fSAndroid Build Coastguard Worker }
416*795d594fSAndroid Build Coastguard Worker 
417*795d594fSAndroid Build Coastguard Worker }  // namespace jit
418*795d594fSAndroid Build Coastguard Worker }  // namespace art
419