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