xref: /aosp_15_r20/art/compiler/jni/quick/calling_convention.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "base/arena_object.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/primitive.h"
25*795d594fSAndroid Build Coastguard Worker #include "thread.h"
26*795d594fSAndroid Build Coastguard Worker #include "utils/managed_register.h"
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker enum class InstructionSet;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker // Top-level abstraction for different calling conventions.
33*795d594fSAndroid Build Coastguard Worker class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
34*795d594fSAndroid Build Coastguard Worker  public:
IsReturnAReference()35*795d594fSAndroid Build Coastguard Worker   bool IsReturnAReference() const { return shorty_[0] == 'L'; }
36*795d594fSAndroid Build Coastguard Worker 
GetReturnType()37*795d594fSAndroid Build Coastguard Worker   Primitive::Type GetReturnType() const {
38*795d594fSAndroid Build Coastguard Worker     return Primitive::GetType(shorty_[0]);
39*795d594fSAndroid Build Coastguard Worker   }
40*795d594fSAndroid Build Coastguard Worker 
SizeOfReturnValue()41*795d594fSAndroid Build Coastguard Worker   size_t SizeOfReturnValue() const {
42*795d594fSAndroid Build Coastguard Worker     size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
43*795d594fSAndroid Build Coastguard Worker     if (result >= 1 && result < 4) {
44*795d594fSAndroid Build Coastguard Worker       result = 4;
45*795d594fSAndroid Build Coastguard Worker     }
46*795d594fSAndroid Build Coastguard Worker     return result;
47*795d594fSAndroid Build Coastguard Worker   }
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker   // Register that holds result of this method invocation.
50*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister ReturnRegister() const = 0;
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker   // Iterator interface
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker   // Place iterator at start of arguments. The displacement is applied to
55*795d594fSAndroid Build Coastguard Worker   // frame offset methods to account for frames which may be on the stack
56*795d594fSAndroid Build Coastguard Worker   // below the one being iterated over.
ResetIterator(FrameOffset displacement)57*795d594fSAndroid Build Coastguard Worker   virtual void ResetIterator(FrameOffset displacement) {
58*795d594fSAndroid Build Coastguard Worker     displacement_ = displacement;
59*795d594fSAndroid Build Coastguard Worker     itr_slots_ = 0;
60*795d594fSAndroid Build Coastguard Worker     itr_args_ = 0;
61*795d594fSAndroid Build Coastguard Worker     itr_refs_ = 0;
62*795d594fSAndroid Build Coastguard Worker     itr_longs_and_doubles_ = 0;
63*795d594fSAndroid Build Coastguard Worker     itr_float_and_doubles_ = 0;
64*795d594fSAndroid Build Coastguard Worker   }
65*795d594fSAndroid Build Coastguard Worker 
GetDisplacement()66*795d594fSAndroid Build Coastguard Worker   FrameOffset GetDisplacement() const {
67*795d594fSAndroid Build Coastguard Worker     return displacement_;
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker 
GetFramePointerSize()70*795d594fSAndroid Build Coastguard Worker   PointerSize GetFramePointerSize() const {
71*795d594fSAndroid Build Coastguard Worker     return frame_pointer_size_;
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker 
~CallingConvention()74*795d594fSAndroid Build Coastguard Worker   virtual ~CallingConvention() {}
75*795d594fSAndroid Build Coastguard Worker 
76*795d594fSAndroid Build Coastguard Worker  protected:
CallingConvention(bool is_static,bool is_synchronized,std::string_view shorty,PointerSize frame_pointer_size)77*795d594fSAndroid Build Coastguard Worker   CallingConvention(bool is_static,
78*795d594fSAndroid Build Coastguard Worker                     bool is_synchronized,
79*795d594fSAndroid Build Coastguard Worker                     std::string_view shorty,
80*795d594fSAndroid Build Coastguard Worker                     PointerSize frame_pointer_size)
81*795d594fSAndroid Build Coastguard Worker       : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
82*795d594fSAndroid Build Coastguard Worker         itr_float_and_doubles_(0), displacement_(0),
83*795d594fSAndroid Build Coastguard Worker         frame_pointer_size_(frame_pointer_size),
84*795d594fSAndroid Build Coastguard Worker         is_static_(is_static), is_synchronized_(is_synchronized),
85*795d594fSAndroid Build Coastguard Worker         shorty_(shorty) {
86*795d594fSAndroid Build Coastguard Worker     num_args_ = (is_static ? 0 : 1) + shorty.length() - 1;
87*795d594fSAndroid Build Coastguard Worker     num_ref_args_ = is_static ? 0 : 1;  // The implicit this pointer.
88*795d594fSAndroid Build Coastguard Worker     num_float_or_double_args_ = 0;
89*795d594fSAndroid Build Coastguard Worker     num_long_or_double_args_ = 0;
90*795d594fSAndroid Build Coastguard Worker     for (size_t i = 1; i < shorty.length(); i++) {
91*795d594fSAndroid Build Coastguard Worker       char ch = shorty[i];
92*795d594fSAndroid Build Coastguard Worker       switch (ch) {
93*795d594fSAndroid Build Coastguard Worker       case 'L':
94*795d594fSAndroid Build Coastguard Worker         num_ref_args_++;
95*795d594fSAndroid Build Coastguard Worker         break;
96*795d594fSAndroid Build Coastguard Worker       case 'J':
97*795d594fSAndroid Build Coastguard Worker         num_long_or_double_args_++;
98*795d594fSAndroid Build Coastguard Worker         break;
99*795d594fSAndroid Build Coastguard Worker       case 'D':
100*795d594fSAndroid Build Coastguard Worker         num_long_or_double_args_++;
101*795d594fSAndroid Build Coastguard Worker         num_float_or_double_args_++;
102*795d594fSAndroid Build Coastguard Worker         break;
103*795d594fSAndroid Build Coastguard Worker       case 'F':
104*795d594fSAndroid Build Coastguard Worker         num_float_or_double_args_++;
105*795d594fSAndroid Build Coastguard Worker         break;
106*795d594fSAndroid Build Coastguard Worker       }
107*795d594fSAndroid Build Coastguard Worker     }
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
IsStatic()110*795d594fSAndroid Build Coastguard Worker   bool IsStatic() const {
111*795d594fSAndroid Build Coastguard Worker     return is_static_;
112*795d594fSAndroid Build Coastguard Worker   }
IsSynchronized()113*795d594fSAndroid Build Coastguard Worker   bool IsSynchronized() const {
114*795d594fSAndroid Build Coastguard Worker     return is_synchronized_;
115*795d594fSAndroid Build Coastguard Worker   }
IsParamALongOrDouble(unsigned int param)116*795d594fSAndroid Build Coastguard Worker   bool IsParamALongOrDouble(unsigned int param) const {
117*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
118*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
119*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
120*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
121*795d594fSAndroid Build Coastguard Worker       return false;  // this argument
122*795d594fSAndroid Build Coastguard Worker     }
123*795d594fSAndroid Build Coastguard Worker     char ch = shorty_[param];
124*795d594fSAndroid Build Coastguard Worker     return (ch == 'J' || ch == 'D');
125*795d594fSAndroid Build Coastguard Worker   }
IsParamAFloatOrDouble(unsigned int param)126*795d594fSAndroid Build Coastguard Worker   bool IsParamAFloatOrDouble(unsigned int param) const {
127*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
128*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
129*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
130*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
131*795d594fSAndroid Build Coastguard Worker       return false;  // this argument
132*795d594fSAndroid Build Coastguard Worker     }
133*795d594fSAndroid Build Coastguard Worker     char ch = shorty_[param];
134*795d594fSAndroid Build Coastguard Worker     return (ch == 'F' || ch == 'D');
135*795d594fSAndroid Build Coastguard Worker   }
IsParamADouble(unsigned int param)136*795d594fSAndroid Build Coastguard Worker   bool IsParamADouble(unsigned int param) const {
137*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
138*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
139*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
140*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
141*795d594fSAndroid Build Coastguard Worker       return false;  // this argument
142*795d594fSAndroid Build Coastguard Worker     }
143*795d594fSAndroid Build Coastguard Worker     return shorty_[param] == 'D';
144*795d594fSAndroid Build Coastguard Worker   }
IsParamALong(unsigned int param)145*795d594fSAndroid Build Coastguard Worker   bool IsParamALong(unsigned int param) const {
146*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
147*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
148*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
149*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
150*795d594fSAndroid Build Coastguard Worker       return false;  // this argument
151*795d594fSAndroid Build Coastguard Worker     }
152*795d594fSAndroid Build Coastguard Worker     return shorty_[param] == 'J';
153*795d594fSAndroid Build Coastguard Worker   }
IsParamAReference(unsigned int param)154*795d594fSAndroid Build Coastguard Worker   bool IsParamAReference(unsigned int param) const {
155*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
156*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
157*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
158*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
159*795d594fSAndroid Build Coastguard Worker       return true;  // this argument
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker     return shorty_[param] == 'L';
162*795d594fSAndroid Build Coastguard Worker   }
NumArgs()163*795d594fSAndroid Build Coastguard Worker   size_t NumArgs() const {
164*795d594fSAndroid Build Coastguard Worker     return num_args_;
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker   // Implicit argument count: 1 for instance functions, 0 for static functions.
167*795d594fSAndroid Build Coastguard Worker   // (The implicit argument is only relevant to the shorty, i.e.
168*795d594fSAndroid Build Coastguard Worker   // the 0th arg is not in the shorty if it's implicit).
NumImplicitArgs()169*795d594fSAndroid Build Coastguard Worker   size_t NumImplicitArgs() const {
170*795d594fSAndroid Build Coastguard Worker     return IsStatic() ? 0 : 1;
171*795d594fSAndroid Build Coastguard Worker   }
NumLongOrDoubleArgs()172*795d594fSAndroid Build Coastguard Worker   size_t NumLongOrDoubleArgs() const {
173*795d594fSAndroid Build Coastguard Worker     return num_long_or_double_args_;
174*795d594fSAndroid Build Coastguard Worker   }
NumFloatOrDoubleArgs()175*795d594fSAndroid Build Coastguard Worker   size_t NumFloatOrDoubleArgs() const {
176*795d594fSAndroid Build Coastguard Worker     return num_float_or_double_args_;
177*795d594fSAndroid Build Coastguard Worker   }
NumReferenceArgs()178*795d594fSAndroid Build Coastguard Worker   size_t NumReferenceArgs() const {
179*795d594fSAndroid Build Coastguard Worker     return num_ref_args_;
180*795d594fSAndroid Build Coastguard Worker   }
ParamSize(size_t param,size_t reference_size)181*795d594fSAndroid Build Coastguard Worker   size_t ParamSize(size_t param, size_t reference_size) const {
182*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(param, NumArgs());
183*795d594fSAndroid Build Coastguard Worker     if (IsStatic()) {
184*795d594fSAndroid Build Coastguard Worker       param++;  // 0th argument must skip return value at start of the shorty
185*795d594fSAndroid Build Coastguard Worker     } else if (param == 0) {
186*795d594fSAndroid Build Coastguard Worker       return reference_size;  // this argument
187*795d594fSAndroid Build Coastguard Worker     }
188*795d594fSAndroid Build Coastguard Worker     Primitive::Type type = Primitive::GetType(shorty_[param]);
189*795d594fSAndroid Build Coastguard Worker     if (type == Primitive::kPrimNot) {
190*795d594fSAndroid Build Coastguard Worker       return reference_size;
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker     size_t result = Primitive::ComponentSize(type);
193*795d594fSAndroid Build Coastguard Worker     if (result >= 1 && result < 4) {
194*795d594fSAndroid Build Coastguard Worker       result = 4;
195*795d594fSAndroid Build Coastguard Worker     }
196*795d594fSAndroid Build Coastguard Worker     return result;
197*795d594fSAndroid Build Coastguard Worker   }
GetShorty()198*795d594fSAndroid Build Coastguard Worker   std::string_view GetShorty() const {
199*795d594fSAndroid Build Coastguard Worker     return shorty_;
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker   // The slot number for current calling_convention argument.
202*795d594fSAndroid Build Coastguard Worker   // Note that each slot is 32-bit. When the current argument is bigger
203*795d594fSAndroid Build Coastguard Worker   // than 32 bits, return the first slot number for this argument.
204*795d594fSAndroid Build Coastguard Worker   unsigned int itr_slots_;
205*795d594fSAndroid Build Coastguard Worker   // The number of references iterated past.
206*795d594fSAndroid Build Coastguard Worker   unsigned int itr_refs_;
207*795d594fSAndroid Build Coastguard Worker   // The argument number along argument list for current argument.
208*795d594fSAndroid Build Coastguard Worker   unsigned int itr_args_;
209*795d594fSAndroid Build Coastguard Worker   // Number of longs and doubles seen along argument list.
210*795d594fSAndroid Build Coastguard Worker   unsigned int itr_longs_and_doubles_;
211*795d594fSAndroid Build Coastguard Worker   // Number of float and doubles seen along argument list.
212*795d594fSAndroid Build Coastguard Worker   unsigned int itr_float_and_doubles_;
213*795d594fSAndroid Build Coastguard Worker   // Space for frames below this on the stack.
214*795d594fSAndroid Build Coastguard Worker   FrameOffset displacement_;
215*795d594fSAndroid Build Coastguard Worker   // The size of a pointer.
216*795d594fSAndroid Build Coastguard Worker   const PointerSize frame_pointer_size_;
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker  private:
219*795d594fSAndroid Build Coastguard Worker   const bool is_static_;
220*795d594fSAndroid Build Coastguard Worker   const bool is_synchronized_;
221*795d594fSAndroid Build Coastguard Worker   std::string shorty_;
222*795d594fSAndroid Build Coastguard Worker   size_t num_args_;
223*795d594fSAndroid Build Coastguard Worker   size_t num_ref_args_;
224*795d594fSAndroid Build Coastguard Worker   size_t num_float_or_double_args_;
225*795d594fSAndroid Build Coastguard Worker   size_t num_long_or_double_args_;
226*795d594fSAndroid Build Coastguard Worker };
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker // Abstraction for managed code's calling conventions
229*795d594fSAndroid Build Coastguard Worker // | { Incoming stack args } |
230*795d594fSAndroid Build Coastguard Worker // | { Prior Method* }       | <-- Prior SP
231*795d594fSAndroid Build Coastguard Worker // | { Return address }      |
232*795d594fSAndroid Build Coastguard Worker // | { Callee saves }        |
233*795d594fSAndroid Build Coastguard Worker // | { Spills ... }          |
234*795d594fSAndroid Build Coastguard Worker // | { Outgoing stack args } |
235*795d594fSAndroid Build Coastguard Worker // | { Method* }             | <-- SP
236*795d594fSAndroid Build Coastguard Worker class ManagedRuntimeCallingConvention : public CallingConvention {
237*795d594fSAndroid Build Coastguard Worker  public:
238*795d594fSAndroid Build Coastguard Worker   static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* allocator,
239*795d594fSAndroid Build Coastguard Worker                                                                  bool is_static,
240*795d594fSAndroid Build Coastguard Worker                                                                  bool is_synchronized,
241*795d594fSAndroid Build Coastguard Worker                                                                  std::string_view shorty,
242*795d594fSAndroid Build Coastguard Worker                                                                  InstructionSet instruction_set);
243*795d594fSAndroid Build Coastguard Worker 
244*795d594fSAndroid Build Coastguard Worker   // Offset of Method within the managed frame.
MethodStackOffset()245*795d594fSAndroid Build Coastguard Worker   FrameOffset MethodStackOffset() {
246*795d594fSAndroid Build Coastguard Worker     return FrameOffset(0u);
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker   // Register that holds the incoming method argument
250*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister MethodRegister() = 0;
251*795d594fSAndroid Build Coastguard Worker 
252*795d594fSAndroid Build Coastguard Worker   // Register that is used to pass frame size for method exit hook call. This
253*795d594fSAndroid Build Coastguard Worker   // shouldn't be the same as the return register since method exit hook also expects
254*795d594fSAndroid Build Coastguard Worker   // return values in the return register.
255*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister ArgumentRegisterForMethodExitHook() = 0;
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker   // Iterator interface
258*795d594fSAndroid Build Coastguard Worker   bool HasNext();
259*795d594fSAndroid Build Coastguard Worker   virtual void Next();
260*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamAReference();
261*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamAFloatOrDouble();
262*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamADouble();
263*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamALong();
IsCurrentParamALongOrDouble()264*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamALongOrDouble() {
265*795d594fSAndroid Build Coastguard Worker     return IsCurrentParamALong() || IsCurrentParamADouble();
266*795d594fSAndroid Build Coastguard Worker   }
267*795d594fSAndroid Build Coastguard Worker   bool IsCurrentArgExplicit();  // ie a non-implict argument such as this
268*795d594fSAndroid Build Coastguard Worker   bool IsCurrentArgPossiblyNull();
269*795d594fSAndroid Build Coastguard Worker   size_t CurrentParamSize();
270*795d594fSAndroid Build Coastguard Worker   virtual bool IsCurrentParamInRegister() = 0;
271*795d594fSAndroid Build Coastguard Worker   virtual bool IsCurrentParamOnStack() = 0;
272*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister CurrentParamRegister() = 0;
273*795d594fSAndroid Build Coastguard Worker   virtual FrameOffset CurrentParamStackOffset() = 0;
274*795d594fSAndroid Build Coastguard Worker 
~ManagedRuntimeCallingConvention()275*795d594fSAndroid Build Coastguard Worker   virtual ~ManagedRuntimeCallingConvention() {}
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker  protected:
ManagedRuntimeCallingConvention(bool is_static,bool is_synchronized,std::string_view shorty,PointerSize frame_pointer_size)278*795d594fSAndroid Build Coastguard Worker   ManagedRuntimeCallingConvention(bool is_static,
279*795d594fSAndroid Build Coastguard Worker                                   bool is_synchronized,
280*795d594fSAndroid Build Coastguard Worker                                   std::string_view shorty,
281*795d594fSAndroid Build Coastguard Worker                                   PointerSize frame_pointer_size)
282*795d594fSAndroid Build Coastguard Worker       : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
283*795d594fSAndroid Build Coastguard Worker };
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker // Abstraction for JNI calling conventions
286*795d594fSAndroid Build Coastguard Worker // | { Incoming stack args }         | <-- Prior SP
287*795d594fSAndroid Build Coastguard Worker // | { Return address }              |
288*795d594fSAndroid Build Coastguard Worker // | { Callee saves }                |     ([1])
289*795d594fSAndroid Build Coastguard Worker // | { Return value spill }          |     (live on return slow paths)
290*795d594fSAndroid Build Coastguard Worker // | { Local Ref. Table State }      |
291*795d594fSAndroid Build Coastguard Worker // | { Stack Indirect Ref. Table     |
292*795d594fSAndroid Build Coastguard Worker // |   num. refs./link }             |     (here to prior SP is frame size)
293*795d594fSAndroid Build Coastguard Worker // | { Method* }                     | <-- Anchor SP written to thread
294*795d594fSAndroid Build Coastguard Worker // | { Outgoing stack args }         | <-- SP at point of call
295*795d594fSAndroid Build Coastguard Worker // | Native frame                    |
296*795d594fSAndroid Build Coastguard Worker //
297*795d594fSAndroid Build Coastguard Worker // [1] We must save all callee saves here to enable any exception throws to restore
298*795d594fSAndroid Build Coastguard Worker // callee saves for frames above this one.
299*795d594fSAndroid Build Coastguard Worker class JniCallingConvention : public CallingConvention {
300*795d594fSAndroid Build Coastguard Worker  public:
301*795d594fSAndroid Build Coastguard Worker   static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* allocator,
302*795d594fSAndroid Build Coastguard Worker                                                       bool is_static,
303*795d594fSAndroid Build Coastguard Worker                                                       bool is_synchronized,
304*795d594fSAndroid Build Coastguard Worker                                                       bool is_fast_native,
305*795d594fSAndroid Build Coastguard Worker                                                       bool is_critical_native,
306*795d594fSAndroid Build Coastguard Worker                                                       std::string_view shorty,
307*795d594fSAndroid Build Coastguard Worker                                                       InstructionSet instruction_set);
308*795d594fSAndroid Build Coastguard Worker 
309*795d594fSAndroid Build Coastguard Worker   // Size of frame excluding space for outgoing args (its assumed Method* is
310*795d594fSAndroid Build Coastguard Worker   // always at the bottom of a frame, but this doesn't work for outgoing
311*795d594fSAndroid Build Coastguard Worker   // native args). Includes alignment.
312*795d594fSAndroid Build Coastguard Worker   virtual size_t FrameSize() const = 0;
313*795d594fSAndroid Build Coastguard Worker   // Size of outgoing frame, i.e. stack arguments, @CriticalNative return PC if needed, alignment.
314*795d594fSAndroid Build Coastguard Worker   // -- Arguments that are passed via registers are excluded from this size.
315*795d594fSAndroid Build Coastguard Worker   virtual size_t OutFrameSize() const = 0;
316*795d594fSAndroid Build Coastguard Worker   // Number of references in stack indirect reference table
317*795d594fSAndroid Build Coastguard Worker   size_t ReferenceCount() const;
318*795d594fSAndroid Build Coastguard Worker   // Register that holds result if it is integer.
319*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister IntReturnRegister() const = 0;
320*795d594fSAndroid Build Coastguard Worker   // Whether the compiler needs to ensure zero-/sign-extension of a small result type
321*795d594fSAndroid Build Coastguard Worker   virtual bool RequiresSmallResultTypeExtension() const = 0;
322*795d594fSAndroid Build Coastguard Worker 
323*795d594fSAndroid Build Coastguard Worker   // Callee save registers to spill prior to native code (which may clobber)
324*795d594fSAndroid Build Coastguard Worker   virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
325*795d594fSAndroid Build Coastguard Worker 
326*795d594fSAndroid Build Coastguard Worker   // Subset of core callee save registers that can be used for arbitrary purposes after
327*795d594fSAndroid Build Coastguard Worker   // constructing the JNI transition frame. These should be both managed and native callee-saves.
328*795d594fSAndroid Build Coastguard Worker   // These should not include special purpose registers such as thread register.
329*795d594fSAndroid Build Coastguard Worker   // JNI compiler currently requires at least 4 callee save scratch registers, except for x86
330*795d594fSAndroid Build Coastguard Worker   // where we have only 3 such registers but all args are passed on stack, so the method register
331*795d594fSAndroid Build Coastguard Worker   // is never clobbered by argument moves and does not need to be preserved elsewhere.
332*795d594fSAndroid Build Coastguard Worker   virtual ArrayRef<const ManagedRegister> CalleeSaveScratchRegisters() const = 0;
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   // Subset of core argument registers that can be used for arbitrary purposes after
335*795d594fSAndroid Build Coastguard Worker   // calling the native function. These should exclude the return register(s).
336*795d594fSAndroid Build Coastguard Worker   virtual ArrayRef<const ManagedRegister> ArgumentScratchRegisters() const = 0;
337*795d594fSAndroid Build Coastguard Worker 
338*795d594fSAndroid Build Coastguard Worker   // Spill mask values
339*795d594fSAndroid Build Coastguard Worker   virtual uint32_t CoreSpillMask() const = 0;
340*795d594fSAndroid Build Coastguard Worker   virtual uint32_t FpSpillMask() const = 0;
341*795d594fSAndroid Build Coastguard Worker 
342*795d594fSAndroid Build Coastguard Worker   // Iterator interface
343*795d594fSAndroid Build Coastguard Worker   bool HasNext();
344*795d594fSAndroid Build Coastguard Worker   virtual void Next();
345*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamAReference();
346*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamAFloatOrDouble();
347*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamADouble();
348*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamALong();
IsCurrentParamALongOrDouble()349*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamALongOrDouble() {
350*795d594fSAndroid Build Coastguard Worker     return IsCurrentParamALong() || IsCurrentParamADouble();
351*795d594fSAndroid Build Coastguard Worker   }
352*795d594fSAndroid Build Coastguard Worker   bool IsCurrentParamJniEnv();
353*795d594fSAndroid Build Coastguard Worker   virtual size_t CurrentParamSize() const;
354*795d594fSAndroid Build Coastguard Worker   virtual bool IsCurrentParamInRegister() = 0;
355*795d594fSAndroid Build Coastguard Worker   virtual bool IsCurrentParamOnStack() = 0;
356*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister CurrentParamRegister() = 0;
357*795d594fSAndroid Build Coastguard Worker   virtual FrameOffset CurrentParamStackOffset() = 0;
358*795d594fSAndroid Build Coastguard Worker 
~JniCallingConvention()359*795d594fSAndroid Build Coastguard Worker   virtual ~JniCallingConvention() {}
360*795d594fSAndroid Build Coastguard Worker 
IsFastNative()361*795d594fSAndroid Build Coastguard Worker   bool IsFastNative() const {
362*795d594fSAndroid Build Coastguard Worker     return is_fast_native_;
363*795d594fSAndroid Build Coastguard Worker   }
364*795d594fSAndroid Build Coastguard Worker 
IsCriticalNative()365*795d594fSAndroid Build Coastguard Worker   bool IsCriticalNative() const {
366*795d594fSAndroid Build Coastguard Worker     return is_critical_native_;
367*795d594fSAndroid Build Coastguard Worker   }
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker   // Does the transition have a method pointer in the stack frame?
SpillsMethod()370*795d594fSAndroid Build Coastguard Worker   bool SpillsMethod() const {
371*795d594fSAndroid Build Coastguard Worker     // Exclude method pointer for @CriticalNative methods for optimization speed.
372*795d594fSAndroid Build Coastguard Worker     return !IsCriticalNative();
373*795d594fSAndroid Build Coastguard Worker   }
374*795d594fSAndroid Build Coastguard Worker 
375*795d594fSAndroid Build Coastguard Worker   // Locking argument register, used to pass the synchronization object for calls
376*795d594fSAndroid Build Coastguard Worker   // to `JniLockObject()` and `JniUnlockObject()`.
377*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister LockingArgumentRegister() const = 0;
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker   // Hidden argument register, used to pass the method pointer for @CriticalNative call.
380*795d594fSAndroid Build Coastguard Worker   virtual ManagedRegister HiddenArgumentRegister() const = 0;
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker   // Whether to use tail call (used only for @CriticalNative).
383*795d594fSAndroid Build Coastguard Worker   virtual bool UseTailCall() const = 0;
384*795d594fSAndroid Build Coastguard Worker 
385*795d594fSAndroid Build Coastguard Worker   // Whether the return type is small. Used for RequiresSmallResultTypeExtension()
386*795d594fSAndroid Build Coastguard Worker   // on architectures that require the sign/zero extension.
HasSmallReturnType()387*795d594fSAndroid Build Coastguard Worker   bool HasSmallReturnType() const {
388*795d594fSAndroid Build Coastguard Worker     Primitive::Type return_type = GetReturnType();
389*795d594fSAndroid Build Coastguard Worker     return return_type == Primitive::kPrimByte ||
390*795d594fSAndroid Build Coastguard Worker            return_type == Primitive::kPrimShort ||
391*795d594fSAndroid Build Coastguard Worker            return_type == Primitive::kPrimBoolean ||
392*795d594fSAndroid Build Coastguard Worker            return_type == Primitive::kPrimChar;
393*795d594fSAndroid Build Coastguard Worker   }
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker  protected:
396*795d594fSAndroid Build Coastguard Worker   // Named iterator positions
397*795d594fSAndroid Build Coastguard Worker   enum IteratorPos {
398*795d594fSAndroid Build Coastguard Worker     kJniEnv = 0,
399*795d594fSAndroid Build Coastguard Worker     kObjectOrClass = 1
400*795d594fSAndroid Build Coastguard Worker   };
401*795d594fSAndroid Build Coastguard Worker 
JniCallingConvention(bool is_static,bool is_synchronized,bool is_fast_native,bool is_critical_native,std::string_view shorty,PointerSize frame_pointer_size)402*795d594fSAndroid Build Coastguard Worker   JniCallingConvention(bool is_static,
403*795d594fSAndroid Build Coastguard Worker                        bool is_synchronized,
404*795d594fSAndroid Build Coastguard Worker                        bool is_fast_native,
405*795d594fSAndroid Build Coastguard Worker                        bool is_critical_native,
406*795d594fSAndroid Build Coastguard Worker                        std::string_view shorty,
407*795d594fSAndroid Build Coastguard Worker                        PointerSize frame_pointer_size)
408*795d594fSAndroid Build Coastguard Worker       : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size),
409*795d594fSAndroid Build Coastguard Worker         is_fast_native_(is_fast_native),
410*795d594fSAndroid Build Coastguard Worker         is_critical_native_(is_critical_native) {}
411*795d594fSAndroid Build Coastguard Worker 
412*795d594fSAndroid Build Coastguard Worker  protected:
413*795d594fSAndroid Build Coastguard Worker   size_t NumberOfExtraArgumentsForJni() const;
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker   // Does the transition have a local reference segment state?
HasLocalReferenceSegmentState()416*795d594fSAndroid Build Coastguard Worker   bool HasLocalReferenceSegmentState() const {
417*795d594fSAndroid Build Coastguard Worker     // Exclude local reference segment states for @CriticalNative methods for optimization speed.
418*795d594fSAndroid Build Coastguard Worker     return !IsCriticalNative();
419*795d594fSAndroid Build Coastguard Worker   }
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker   // Are there extra JNI arguments (JNIEnv* and maybe jclass)?
HasExtraArgumentsForJni()422*795d594fSAndroid Build Coastguard Worker   bool HasExtraArgumentsForJni() const {
423*795d594fSAndroid Build Coastguard Worker     // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
424*795d594fSAndroid Build Coastguard Worker     return !IsCriticalNative();
425*795d594fSAndroid Build Coastguard Worker   }
426*795d594fSAndroid Build Coastguard Worker 
427*795d594fSAndroid Build Coastguard Worker   // Has a JNIEnv* parameter implicitly?
HasJniEnv()428*795d594fSAndroid Build Coastguard Worker   bool HasJniEnv() const {
429*795d594fSAndroid Build Coastguard Worker     // Exclude "JNIEnv*" parameter for @CriticalNative methods.
430*795d594fSAndroid Build Coastguard Worker     return HasExtraArgumentsForJni();
431*795d594fSAndroid Build Coastguard Worker   }
432*795d594fSAndroid Build Coastguard Worker 
433*795d594fSAndroid Build Coastguard Worker   // Has a 'jclass' parameter implicitly?
434*795d594fSAndroid Build Coastguard Worker   bool HasSelfClass() const;
435*795d594fSAndroid Build Coastguard Worker 
436*795d594fSAndroid Build Coastguard Worker   // Returns the position of itr_args_, fixed up by removing the offset of extra JNI arguments.
437*795d594fSAndroid Build Coastguard Worker   size_t GetIteratorPositionWithinShorty() const;
438*795d594fSAndroid Build Coastguard Worker 
439*795d594fSAndroid Build Coastguard Worker   // Is the current argument (at the iterator) an extra argument for JNI?
440*795d594fSAndroid Build Coastguard Worker   bool IsCurrentArgExtraForJni() const;
441*795d594fSAndroid Build Coastguard Worker 
442*795d594fSAndroid Build Coastguard Worker   const bool is_fast_native_;
443*795d594fSAndroid Build Coastguard Worker   const bool is_critical_native_;
444*795d594fSAndroid Build Coastguard Worker 
445*795d594fSAndroid Build Coastguard Worker  private:
446*795d594fSAndroid Build Coastguard Worker   // Shorthand for switching on the switch value but only IF there are extra JNI arguments.
447*795d594fSAndroid Build Coastguard Worker   //
448*795d594fSAndroid Build Coastguard Worker   // Puts the case value into return_value.
449*795d594fSAndroid Build Coastguard Worker   // * (switch_value == kJniEnv) => case_jni_env
450*795d594fSAndroid Build Coastguard Worker   // * (switch_value == kObjectOrClass) => case_object_or_class
451*795d594fSAndroid Build Coastguard Worker   //
452*795d594fSAndroid Build Coastguard Worker   // Returns false otherwise (or if there are no extra JNI arguments).
453*795d594fSAndroid Build Coastguard Worker   bool SwitchExtraJniArguments(size_t switch_value,
454*795d594fSAndroid Build Coastguard Worker                                bool case_jni_env,
455*795d594fSAndroid Build Coastguard Worker                                bool case_object_or_class,
456*795d594fSAndroid Build Coastguard Worker                                /* out parameters */
457*795d594fSAndroid Build Coastguard Worker                                bool* return_value) const;
458*795d594fSAndroid Build Coastguard Worker };
459*795d594fSAndroid Build Coastguard Worker 
460*795d594fSAndroid Build Coastguard Worker }  // namespace art
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
463