xref: /aosp_15_r20/art/runtime/oat/jni_stub_hash_map.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2024 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 "jni_stub_hash_map.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/jni_frame_arm64.h"
20*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
21*795d594fSAndroid Build Coastguard Worker #include "arch/riscv64/jni_frame_riscv64.h"
22*795d594fSAndroid Build Coastguard Worker #include "arch/x86_64/jni_frame_x86_64.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/modifiers.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker 
TranslateArgToJniShorty(char ch)28*795d594fSAndroid Build Coastguard Worker static char TranslateArgToJniShorty(char ch) {
29*795d594fSAndroid Build Coastguard Worker   // Byte, char, int, short, boolean are treated the same(e.g., Wx registers for arm64) when
30*795d594fSAndroid Build Coastguard Worker   // generating JNI stub, so their JNI shorty characters are same.
31*795d594fSAndroid Build Coastguard Worker   //                                       ABCDEFGHIJKLMNOPQRSTUVWXYZ
32*795d594fSAndroid Build Coastguard Worker   static constexpr char kTranslations[] = ".PPD.F..PJ.L......P......P";
33*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(ch, 'A');
34*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(ch, 'Z');
35*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(kTranslations[ch - 'A'], '.');
36*795d594fSAndroid Build Coastguard Worker   return kTranslations[ch - 'A'];
37*795d594fSAndroid Build Coastguard Worker }
38*795d594fSAndroid Build Coastguard Worker 
TranslateReturnTypeToJniShorty(char ch,InstructionSet isa=InstructionSet::kNone)39*795d594fSAndroid Build Coastguard Worker static char TranslateReturnTypeToJniShorty(char ch, InstructionSet isa = InstructionSet::kNone) {
40*795d594fSAndroid Build Coastguard Worker   // For all archs, reference type has a different JNI shorty character than others as it needs to
41*795d594fSAndroid Build Coastguard Worker   // be decoded in stub.
42*795d594fSAndroid Build Coastguard Worker   // For arm64, small return types need sign-/zero-extended.
43*795d594fSAndroid Build Coastguard Worker   // For x86_64, small return types need sign-/zero-extended, and RAX needs to be preserved and
44*795d594fSAndroid Build Coastguard Worker   // restored when thread state changes.
45*795d594fSAndroid Build Coastguard Worker   // Other archs keeps untranslated for simplicity.
46*795d594fSAndroid Build Coastguard Worker   // TODO: support riscv64 with an optimized version.
47*795d594fSAndroid Build Coastguard Worker   //                                             ABCDEFGHIJKLMNOPQRSTUVWXYZ
48*795d594fSAndroid Build Coastguard Worker   static constexpr char kArm64Translations[] =  ".BCP.P..PP.L......S..P...Z";
49*795d594fSAndroid Build Coastguard Worker   static constexpr char kX86_64Translations[] = ".BCP.P..RR.L......S..P...Z";
50*795d594fSAndroid Build Coastguard Worker   static constexpr char kOtherTranslations[] =  ".BCD.F..IJ.L......S..V...Z";
51*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(ch, 'A');
52*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(ch, 'Z');
53*795d594fSAndroid Build Coastguard Worker   switch (isa) {
54*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
55*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(kArm64Translations[ch - 'A'], '.');
56*795d594fSAndroid Build Coastguard Worker       return kArm64Translations[ch - 'A'];
57*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
58*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(kX86_64Translations[ch - 'A'], '.');
59*795d594fSAndroid Build Coastguard Worker       return kX86_64Translations[ch - 'A'];
60*795d594fSAndroid Build Coastguard Worker     default:
61*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(kOtherTranslations[ch - 'A'], '.');
62*795d594fSAndroid Build Coastguard Worker       return kOtherTranslations[ch - 'A'];
63*795d594fSAndroid Build Coastguard Worker   }
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker 
GetMaxIntLikeRegisterArgs(InstructionSet isa)66*795d594fSAndroid Build Coastguard Worker static constexpr size_t GetMaxIntLikeRegisterArgs(InstructionSet isa) {
67*795d594fSAndroid Build Coastguard Worker   switch (isa) {
68*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
69*795d594fSAndroid Build Coastguard Worker       return arm64::kMaxIntLikeRegisterArguments;
70*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
71*795d594fSAndroid Build Coastguard Worker       return x86_64::kMaxIntLikeRegisterArguments;
72*795d594fSAndroid Build Coastguard Worker     default:
73*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unrecognized isa: " << isa << " for " << __FUNCTION__;
74*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker 
GetMaxFloatOrDoubleRegisterArgs(InstructionSet isa)78*795d594fSAndroid Build Coastguard Worker static constexpr size_t GetMaxFloatOrDoubleRegisterArgs(InstructionSet isa) {
79*795d594fSAndroid Build Coastguard Worker   switch (isa) {
80*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
81*795d594fSAndroid Build Coastguard Worker       return arm64::kMaxFloatOrDoubleRegisterArguments;
82*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
83*795d594fSAndroid Build Coastguard Worker       return x86_64::kMaxFloatOrDoubleRegisterArguments;
84*795d594fSAndroid Build Coastguard Worker     default:
85*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unrecognized isa: " << isa << " for " << __FUNCTION__;
86*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
87*795d594fSAndroid Build Coastguard Worker   }
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker 
StackOffset(char ch)90*795d594fSAndroid Build Coastguard Worker static size_t StackOffset(char ch) {
91*795d594fSAndroid Build Coastguard Worker   if (ch == 'J' || ch == 'D') {
92*795d594fSAndroid Build Coastguard Worker     return 8;
93*795d594fSAndroid Build Coastguard Worker   } else {
94*795d594fSAndroid Build Coastguard Worker     return 4;
95*795d594fSAndroid Build Coastguard Worker   }
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker 
IsFloatOrDoubleArg(char ch)98*795d594fSAndroid Build Coastguard Worker static bool IsFloatOrDoubleArg(char ch) {
99*795d594fSAndroid Build Coastguard Worker   return ch == 'F' || ch == 'D';
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker 
IsIntegralArg(char ch)102*795d594fSAndroid Build Coastguard Worker static bool IsIntegralArg(char ch) {
103*795d594fSAndroid Build Coastguard Worker   return ch == 'B' || ch == 'C' || ch == 'I' || ch == 'J' || ch == 'S' || ch == 'Z';
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker 
IsReferenceArg(char ch)106*795d594fSAndroid Build Coastguard Worker static bool IsReferenceArg(char ch) {
107*795d594fSAndroid Build Coastguard Worker   return ch == 'L';
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker template<InstructionSet kIsa>
JniStubKeyOptimizedHash(const JniStubKey & key)111*795d594fSAndroid Build Coastguard Worker size_t JniStubKeyOptimizedHash(const JniStubKey& key) {
112*795d594fSAndroid Build Coastguard Worker   bool is_static = key.Flags() & kAccStatic;
113*795d594fSAndroid Build Coastguard Worker   std::string_view shorty = key.Shorty();
114*795d594fSAndroid Build Coastguard Worker   size_t result = key.Flags();
115*795d594fSAndroid Build Coastguard Worker   result ^= TranslateReturnTypeToJniShorty(shorty[0], kIsa);
116*795d594fSAndroid Build Coastguard Worker   constexpr size_t kMaxFloatOrDoubleRegisterArgs = GetMaxFloatOrDoubleRegisterArgs(kIsa);
117*795d594fSAndroid Build Coastguard Worker   constexpr size_t kMaxIntLikeRegisterArgs = GetMaxIntLikeRegisterArgs(kIsa);
118*795d594fSAndroid Build Coastguard Worker   size_t float_or_double_args = 0;
119*795d594fSAndroid Build Coastguard Worker   // ArtMethod* and 'Object* this' for non-static method.
120*795d594fSAndroid Build Coastguard Worker   // ArtMethod* for static method.
121*795d594fSAndroid Build Coastguard Worker   size_t int_like_args = is_static ? 1 : 2;
122*795d594fSAndroid Build Coastguard Worker   size_t stack_offset = 0;
123*795d594fSAndroid Build Coastguard Worker   for (char c : shorty.substr(1u)) {
124*795d594fSAndroid Build Coastguard Worker     bool stack_offset_matters = false;
125*795d594fSAndroid Build Coastguard Worker     stack_offset += StackOffset(c);
126*795d594fSAndroid Build Coastguard Worker     if (IsFloatOrDoubleArg(c)) {
127*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args;
128*795d594fSAndroid Build Coastguard Worker       if (float_or_double_args > kMaxFloatOrDoubleRegisterArgs) {
129*795d594fSAndroid Build Coastguard Worker         // Stack offset matters if we run out of float-like (float, double) argument registers
130*795d594fSAndroid Build Coastguard Worker         // because the subsequent float-like args should be passed on the stack.
131*795d594fSAndroid Build Coastguard Worker         stack_offset_matters = true;
132*795d594fSAndroid Build Coastguard Worker       } else {
133*795d594fSAndroid Build Coastguard Worker         // Floating-point register arguments are not touched when generating JNI stub, so could be
134*795d594fSAndroid Build Coastguard Worker         // ignored when calculating hash value.
135*795d594fSAndroid Build Coastguard Worker         continue;
136*795d594fSAndroid Build Coastguard Worker       }
137*795d594fSAndroid Build Coastguard Worker     } else {
138*795d594fSAndroid Build Coastguard Worker       ++int_like_args;
139*795d594fSAndroid Build Coastguard Worker       if (int_like_args > kMaxIntLikeRegisterArgs || IsReferenceArg(c)) {
140*795d594fSAndroid Build Coastguard Worker         // Stack offset matters if we run out of integer-like (pointer, object, long, int, short,
141*795d594fSAndroid Build Coastguard Worker         // bool, etc) argument registers because the subsequent integer-like args should be passed
142*795d594fSAndroid Build Coastguard Worker         // on the stack. It also matters if current arg is reference type because it needs to be
143*795d594fSAndroid Build Coastguard Worker         // spilled as raw data even if it's in a register.
144*795d594fSAndroid Build Coastguard Worker         stack_offset_matters = true;
145*795d594fSAndroid Build Coastguard Worker       } else if (!is_static) {
146*795d594fSAndroid Build Coastguard Worker         // For non-static method, two managed arguments 'ArtMethod*' and 'Object* this' correspond
147*795d594fSAndroid Build Coastguard Worker         // to two native arguments 'JNIEnv*' and 'jobject'. So trailing integral (long, int, short,
148*795d594fSAndroid Build Coastguard Worker         // bool, etc) arguments will remain in the same registers, which do not need any generated
149*795d594fSAndroid Build Coastguard Worker         // code.
150*795d594fSAndroid Build Coastguard Worker         // But for static method, we have only one leading managed argument 'ArtMethod*' but two
151*795d594fSAndroid Build Coastguard Worker         // native arguments 'JNIEnv*' and 'jclass'. So trailing integral arguments are always
152*795d594fSAndroid Build Coastguard Worker         // shuffled around and affect the generated code.
153*795d594fSAndroid Build Coastguard Worker         continue;
154*795d594fSAndroid Build Coastguard Worker       }
155*795d594fSAndroid Build Coastguard Worker     }
156*795d594fSAndroid Build Coastguard Worker     // int_like_args is needed for reference type because it will determine from which register
157*795d594fSAndroid Build Coastguard Worker     // we take the value to construct jobject.
158*795d594fSAndroid Build Coastguard Worker     if (IsReferenceArg(c)) {
159*795d594fSAndroid Build Coastguard Worker       result = result * 31u * int_like_args ^ TranslateArgToJniShorty(c);
160*795d594fSAndroid Build Coastguard Worker     } else {
161*795d594fSAndroid Build Coastguard Worker       result = result * 31u ^ TranslateArgToJniShorty(c);
162*795d594fSAndroid Build Coastguard Worker     }
163*795d594fSAndroid Build Coastguard Worker     if (stack_offset_matters) {
164*795d594fSAndroid Build Coastguard Worker       result += stack_offset;
165*795d594fSAndroid Build Coastguard Worker     }
166*795d594fSAndroid Build Coastguard Worker   }
167*795d594fSAndroid Build Coastguard Worker   return result;
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker 
JniStubKeyGenericHash(const JniStubKey & key)170*795d594fSAndroid Build Coastguard Worker size_t JniStubKeyGenericHash(const JniStubKey& key) {
171*795d594fSAndroid Build Coastguard Worker   std::string_view shorty = key.Shorty();
172*795d594fSAndroid Build Coastguard Worker   size_t result = key.Flags();
173*795d594fSAndroid Build Coastguard Worker   result ^= TranslateReturnTypeToJniShorty(shorty[0]);
174*795d594fSAndroid Build Coastguard Worker   for (char c : shorty.substr(1u)) {
175*795d594fSAndroid Build Coastguard Worker     result = result * 31u ^ TranslateArgToJniShorty(c);
176*795d594fSAndroid Build Coastguard Worker   }
177*795d594fSAndroid Build Coastguard Worker   return result;
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker 
JniStubKeyHash(InstructionSet isa)180*795d594fSAndroid Build Coastguard Worker JniStubKeyHash::JniStubKeyHash(InstructionSet isa) {
181*795d594fSAndroid Build Coastguard Worker   switch (isa) {
182*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm:
183*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kThumb2:
184*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kRiscv64:
185*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86:
186*795d594fSAndroid Build Coastguard Worker       hash_func_ = JniStubKeyGenericHash;
187*795d594fSAndroid Build Coastguard Worker       break;
188*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
189*795d594fSAndroid Build Coastguard Worker       hash_func_ = JniStubKeyOptimizedHash<InstructionSet::kArm64>;
190*795d594fSAndroid Build Coastguard Worker       break;
191*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
192*795d594fSAndroid Build Coastguard Worker       hash_func_ = JniStubKeyOptimizedHash<InstructionSet::kX86_64>;
193*795d594fSAndroid Build Coastguard Worker       break;
194*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kNone:
195*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "No instruction set given for " << __FUNCTION__;
196*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker }
199*795d594fSAndroid Build Coastguard Worker 
200*795d594fSAndroid Build Coastguard Worker template<InstructionSet kIsa>
JniStubKeyOptimizedEquals(const JniStubKey & lhs,const JniStubKey & rhs)201*795d594fSAndroid Build Coastguard Worker bool JniStubKeyOptimizedEquals(const JniStubKey& lhs, const JniStubKey& rhs) {
202*795d594fSAndroid Build Coastguard Worker   if (lhs.Flags() != rhs.Flags()) {
203*795d594fSAndroid Build Coastguard Worker     return false;
204*795d594fSAndroid Build Coastguard Worker   }
205*795d594fSAndroid Build Coastguard Worker   std::string_view shorty_lhs = lhs.Shorty();
206*795d594fSAndroid Build Coastguard Worker   std::string_view shorty_rhs = rhs.Shorty();
207*795d594fSAndroid Build Coastguard Worker   if (TranslateReturnTypeToJniShorty(shorty_lhs[0], kIsa) !=
208*795d594fSAndroid Build Coastguard Worker       TranslateReturnTypeToJniShorty(shorty_rhs[0], kIsa)) {
209*795d594fSAndroid Build Coastguard Worker     return false;
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker   bool is_static = lhs.Flags() & kAccStatic;
212*795d594fSAndroid Build Coastguard Worker   constexpr size_t kMaxFloatOrDoubleRegisterArgs = GetMaxFloatOrDoubleRegisterArgs(kIsa);
213*795d594fSAndroid Build Coastguard Worker   constexpr size_t kMaxIntLikeRegisterArgs = GetMaxIntLikeRegisterArgs(kIsa);
214*795d594fSAndroid Build Coastguard Worker   size_t float_or_double_args_lhs = 0;
215*795d594fSAndroid Build Coastguard Worker   size_t float_or_double_args_rhs = 0;
216*795d594fSAndroid Build Coastguard Worker   size_t int_like_args_lhs = is_static ? 1 : 2;
217*795d594fSAndroid Build Coastguard Worker   size_t int_like_args_rhs = is_static ? 1 : 2;
218*795d594fSAndroid Build Coastguard Worker   size_t stack_offset_lhs = 0;
219*795d594fSAndroid Build Coastguard Worker   size_t stack_offset_rhs = 0;
220*795d594fSAndroid Build Coastguard Worker   size_t i = 1;
221*795d594fSAndroid Build Coastguard Worker   size_t j = 1;
222*795d594fSAndroid Build Coastguard Worker   while (i < shorty_lhs.length() && j < shorty_rhs.length()) {
223*795d594fSAndroid Build Coastguard Worker     bool should_skip = false;
224*795d594fSAndroid Build Coastguard Worker     bool stack_offset_matters = false;
225*795d594fSAndroid Build Coastguard Worker     char ch_lhs = shorty_lhs[i];
226*795d594fSAndroid Build Coastguard Worker     char ch_rhs = shorty_rhs[j];
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker     if (IsFloatOrDoubleArg(ch_lhs) &&
229*795d594fSAndroid Build Coastguard Worker         float_or_double_args_lhs < kMaxFloatOrDoubleRegisterArgs) {
230*795d594fSAndroid Build Coastguard Worker       // Skip float-like register arguments.
231*795d594fSAndroid Build Coastguard Worker       ++i;
232*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args_lhs;
233*795d594fSAndroid Build Coastguard Worker       stack_offset_lhs += StackOffset(ch_lhs);
234*795d594fSAndroid Build Coastguard Worker       should_skip = true;
235*795d594fSAndroid Build Coastguard Worker     } else if (IsIntegralArg(ch_lhs) &&
236*795d594fSAndroid Build Coastguard Worker         int_like_args_lhs < kMaxIntLikeRegisterArgs) {
237*795d594fSAndroid Build Coastguard Worker       if (!is_static) {
238*795d594fSAndroid Build Coastguard Worker         // Skip integral register arguments for non-static method.
239*795d594fSAndroid Build Coastguard Worker         ++i;
240*795d594fSAndroid Build Coastguard Worker         ++int_like_args_lhs;
241*795d594fSAndroid Build Coastguard Worker         stack_offset_lhs += StackOffset(ch_lhs);
242*795d594fSAndroid Build Coastguard Worker         should_skip = true;
243*795d594fSAndroid Build Coastguard Worker       }
244*795d594fSAndroid Build Coastguard Worker     } else {
245*795d594fSAndroid Build Coastguard Worker       stack_offset_matters = true;
246*795d594fSAndroid Build Coastguard Worker     }
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker     if (IsFloatOrDoubleArg(ch_rhs) &&
249*795d594fSAndroid Build Coastguard Worker         float_or_double_args_rhs < kMaxFloatOrDoubleRegisterArgs) {
250*795d594fSAndroid Build Coastguard Worker       // Skip float-like register arguments.
251*795d594fSAndroid Build Coastguard Worker       ++j;
252*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args_rhs;
253*795d594fSAndroid Build Coastguard Worker       stack_offset_rhs += StackOffset(ch_rhs);
254*795d594fSAndroid Build Coastguard Worker       should_skip = true;
255*795d594fSAndroid Build Coastguard Worker     } else if (IsIntegralArg(ch_rhs) &&
256*795d594fSAndroid Build Coastguard Worker         int_like_args_rhs < kMaxIntLikeRegisterArgs) {
257*795d594fSAndroid Build Coastguard Worker       if (!is_static) {
258*795d594fSAndroid Build Coastguard Worker         // Skip integral register arguments for non-static method.
259*795d594fSAndroid Build Coastguard Worker         ++j;
260*795d594fSAndroid Build Coastguard Worker         ++int_like_args_rhs;
261*795d594fSAndroid Build Coastguard Worker         stack_offset_rhs += StackOffset(ch_rhs);
262*795d594fSAndroid Build Coastguard Worker         should_skip = true;
263*795d594fSAndroid Build Coastguard Worker       }
264*795d594fSAndroid Build Coastguard Worker     } else {
265*795d594fSAndroid Build Coastguard Worker       stack_offset_matters = true;
266*795d594fSAndroid Build Coastguard Worker     }
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker     if (should_skip) {
269*795d594fSAndroid Build Coastguard Worker       continue;
270*795d594fSAndroid Build Coastguard Worker     }
271*795d594fSAndroid Build Coastguard Worker     if (TranslateArgToJniShorty(ch_lhs) != TranslateArgToJniShorty(ch_rhs)) {
272*795d594fSAndroid Build Coastguard Worker       return false;
273*795d594fSAndroid Build Coastguard Worker     }
274*795d594fSAndroid Build Coastguard Worker     if (stack_offset_matters && stack_offset_lhs != stack_offset_rhs) {
275*795d594fSAndroid Build Coastguard Worker       return false;
276*795d594fSAndroid Build Coastguard Worker     }
277*795d594fSAndroid Build Coastguard Worker     // int_like_args needs to be compared for reference type because it will determine from
278*795d594fSAndroid Build Coastguard Worker     // which register we take the value to construct jobject.
279*795d594fSAndroid Build Coastguard Worker     if (IsReferenceArg(ch_lhs) && int_like_args_lhs != int_like_args_rhs) {
280*795d594fSAndroid Build Coastguard Worker       return false;
281*795d594fSAndroid Build Coastguard Worker     }
282*795d594fSAndroid Build Coastguard Worker     // Passed character comparison.
283*795d594fSAndroid Build Coastguard Worker     ++i;
284*795d594fSAndroid Build Coastguard Worker     ++j;
285*795d594fSAndroid Build Coastguard Worker     stack_offset_lhs += StackOffset(ch_lhs);
286*795d594fSAndroid Build Coastguard Worker     stack_offset_rhs += StackOffset(ch_rhs);
287*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(IsFloatOrDoubleArg(ch_lhs), IsFloatOrDoubleArg(ch_rhs));
288*795d594fSAndroid Build Coastguard Worker     if (IsFloatOrDoubleArg(ch_lhs)) {
289*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args_lhs;
290*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args_rhs;
291*795d594fSAndroid Build Coastguard Worker     } else {
292*795d594fSAndroid Build Coastguard Worker       ++int_like_args_lhs;
293*795d594fSAndroid Build Coastguard Worker       ++int_like_args_rhs;
294*795d594fSAndroid Build Coastguard Worker     }
295*795d594fSAndroid Build Coastguard Worker   }
296*795d594fSAndroid Build Coastguard Worker   auto remaining_shorty =
297*795d594fSAndroid Build Coastguard Worker       i < shorty_lhs.length() ? shorty_lhs.substr(i) : shorty_rhs.substr(j);
298*795d594fSAndroid Build Coastguard Worker   size_t float_or_double_args =
299*795d594fSAndroid Build Coastguard Worker       i < shorty_lhs.length() ? float_or_double_args_lhs : float_or_double_args_rhs;
300*795d594fSAndroid Build Coastguard Worker   size_t int_like_args = i < shorty_lhs.length() ? int_like_args_lhs : int_like_args_rhs;
301*795d594fSAndroid Build Coastguard Worker   for (char c : remaining_shorty) {
302*795d594fSAndroid Build Coastguard Worker     if (IsFloatOrDoubleArg(c) && float_or_double_args < kMaxFloatOrDoubleRegisterArgs) {
303*795d594fSAndroid Build Coastguard Worker       ++float_or_double_args;
304*795d594fSAndroid Build Coastguard Worker       continue;
305*795d594fSAndroid Build Coastguard Worker     }
306*795d594fSAndroid Build Coastguard Worker     if (!is_static && IsIntegralArg(c) && int_like_args < kMaxIntLikeRegisterArgs) {
307*795d594fSAndroid Build Coastguard Worker       ++int_like_args;
308*795d594fSAndroid Build Coastguard Worker       continue;
309*795d594fSAndroid Build Coastguard Worker     }
310*795d594fSAndroid Build Coastguard Worker     return false;
311*795d594fSAndroid Build Coastguard Worker   }
312*795d594fSAndroid Build Coastguard Worker   return true;
313*795d594fSAndroid Build Coastguard Worker }
314*795d594fSAndroid Build Coastguard Worker 
JniStubKeyGenericEquals(const JniStubKey & lhs,const JniStubKey & rhs)315*795d594fSAndroid Build Coastguard Worker bool JniStubKeyGenericEquals(const JniStubKey& lhs, const JniStubKey& rhs) {
316*795d594fSAndroid Build Coastguard Worker   if (lhs.Flags() != rhs.Flags()) {
317*795d594fSAndroid Build Coastguard Worker     return false;
318*795d594fSAndroid Build Coastguard Worker   }
319*795d594fSAndroid Build Coastguard Worker   std::string_view shorty_lhs = lhs.Shorty();
320*795d594fSAndroid Build Coastguard Worker   std::string_view shorty_rhs = rhs.Shorty();
321*795d594fSAndroid Build Coastguard Worker   if (TranslateReturnTypeToJniShorty(shorty_lhs[0]) !=
322*795d594fSAndroid Build Coastguard Worker       TranslateReturnTypeToJniShorty(shorty_rhs[0])) {
323*795d594fSAndroid Build Coastguard Worker     return false;
324*795d594fSAndroid Build Coastguard Worker   }
325*795d594fSAndroid Build Coastguard Worker   if (shorty_lhs.length() != shorty_rhs.length()) {
326*795d594fSAndroid Build Coastguard Worker     return false;
327*795d594fSAndroid Build Coastguard Worker   }
328*795d594fSAndroid Build Coastguard Worker   for (size_t i = 1; i < shorty_lhs.length(); ++i) {
329*795d594fSAndroid Build Coastguard Worker     if (TranslateArgToJniShorty(shorty_lhs[i]) != TranslateArgToJniShorty(shorty_rhs[i])) {
330*795d594fSAndroid Build Coastguard Worker       return false;
331*795d594fSAndroid Build Coastguard Worker     }
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker   return true;
334*795d594fSAndroid Build Coastguard Worker }
335*795d594fSAndroid Build Coastguard Worker 
JniStubKeyEquals(InstructionSet isa)336*795d594fSAndroid Build Coastguard Worker JniStubKeyEquals::JniStubKeyEquals(InstructionSet isa) {
337*795d594fSAndroid Build Coastguard Worker   switch (isa) {
338*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm:
339*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kThumb2:
340*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kRiscv64:
341*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86:
342*795d594fSAndroid Build Coastguard Worker       equals_func_ = JniStubKeyGenericEquals;
343*795d594fSAndroid Build Coastguard Worker       break;
344*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
345*795d594fSAndroid Build Coastguard Worker       equals_func_ = JniStubKeyOptimizedEquals<InstructionSet::kArm64>;
346*795d594fSAndroid Build Coastguard Worker       break;
347*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
348*795d594fSAndroid Build Coastguard Worker       equals_func_ = JniStubKeyOptimizedEquals<InstructionSet::kX86_64>;
349*795d594fSAndroid Build Coastguard Worker       break;
350*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kNone:
351*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "No instruction set given for " << __FUNCTION__;
352*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
353*795d594fSAndroid Build Coastguard Worker   }
354*795d594fSAndroid Build Coastguard Worker }
355*795d594fSAndroid Build Coastguard Worker 
356*795d594fSAndroid Build Coastguard Worker }  // namespace art
357