1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ 18 #define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ 19 20 #include <vector> 21 #include "stack_indirect_reference_table.h" 22 #include "thread.h" 23 #include "utils/managed_register.h" 24 25 namespace art { 26 27 // Top-level abstraction for different calling conventions 28 class CallingConvention { 29 public: 30 bool IsReturnAReference() const { return shorty_[0] == 'L'; } 31 32 Primitive::Type GetReturnType() const { 33 return Primitive::GetType(shorty_[0]); 34 } 35 36 size_t SizeOfReturnValue() const { 37 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0])); 38 if (result >= 1 && result < 4) { 39 result = 4; 40 } 41 return result; 42 } 43 44 // Register that holds result of this method invocation. 45 virtual ManagedRegister ReturnRegister() = 0; 46 // Register reserved for scratch usage during procedure calls. 47 virtual ManagedRegister InterproceduralScratchRegister() = 0; 48 49 // Offset of Method within the frame 50 FrameOffset MethodStackOffset(); 51 52 // Iterator interface 53 54 // Place iterator at start of arguments. The displacement is applied to 55 // frame offset methods to account for frames which may be on the stack 56 // below the one being iterated over. 57 void ResetIterator(FrameOffset displacement) { 58 displacement_ = displacement; 59 itr_slots_ = 0; 60 itr_args_ = 0; 61 itr_refs_ = 0; 62 itr_longs_and_doubles_ = 0; 63 } 64 65 virtual ~CallingConvention() {} 66 67 protected: 68 CallingConvention(bool is_static, bool is_synchronized, const char* shorty) 69 : displacement_(0), is_static_(is_static), is_synchronized_(is_synchronized), 70 shorty_(shorty) { 71 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1; 72 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer. 73 num_long_or_double_args_ = 0; 74 for (size_t i = 1; i < strlen(shorty); i++) { 75 char ch = shorty_[i]; 76 if (ch == 'L') { 77 num_ref_args_++; 78 } else if ((ch == 'D') || (ch == 'J')) { 79 num_long_or_double_args_++; 80 } 81 } 82 } 83 84 bool IsStatic() const { 85 return is_static_; 86 } 87 bool IsSynchronized() const { 88 return is_synchronized_; 89 } 90 bool IsParamALongOrDouble(unsigned int param) const { 91 DCHECK_LT(param, NumArgs()); 92 if (IsStatic()) { 93 param++; // 0th argument must skip return value at start of the shorty 94 } else if (param == 0) { 95 return false; // this argument 96 } 97 char ch = shorty_[param]; 98 return (ch == 'J' || ch == 'D'); 99 } 100 bool IsParamAReference(unsigned int param) const { 101 DCHECK_LT(param, NumArgs()); 102 if (IsStatic()) { 103 param++; // 0th argument must skip return value at start of the shorty 104 } else if (param == 0) { 105 return true; // this argument 106 } 107 return shorty_[param] == 'L'; 108 } 109 size_t NumArgs() const { 110 return num_args_; 111 } 112 size_t NumLongOrDoubleArgs() const { 113 return num_long_or_double_args_; 114 } 115 size_t NumReferenceArgs() const { 116 return num_ref_args_; 117 } 118 size_t ParamSize(unsigned int param) const { 119 DCHECK_LT(param, NumArgs()); 120 if (IsStatic()) { 121 param++; // 0th argument must skip return value at start of the shorty 122 } else if (param == 0) { 123 return kPointerSize; // this argument 124 } 125 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param])); 126 if (result >= 1 && result < 4) { 127 result = 4; 128 } 129 return result; 130 } 131 const char* GetShorty() const { 132 return shorty_.c_str(); 133 } 134 // The slot number for current calling_convention argument. 135 // Note that each slot is 32-bit. When the current argument is bigger 136 // than 32 bits, return the first slot number for this argument. 137 unsigned int itr_slots_; 138 // The number of references iterated past 139 unsigned int itr_refs_; 140 // The argument number along argument list for current argument 141 unsigned int itr_args_; 142 // Number of longs and doubles seen along argument list 143 unsigned int itr_longs_and_doubles_; 144 // Space for frames below this on the stack 145 FrameOffset displacement_; 146 147 private: 148 const bool is_static_; 149 const bool is_synchronized_; 150 std::string shorty_; 151 size_t num_args_; 152 size_t num_ref_args_; 153 size_t num_long_or_double_args_; 154 }; 155 156 // Abstraction for managed code's calling conventions 157 // | { Incoming stack args } | 158 // | { Prior Method* } | <-- Prior SP 159 // | { Return address } | 160 // | { Callee saves } | 161 // | { Spills ... } | 162 // | { Outgoing stack args } | 163 // | { Method* } | <-- SP 164 class ManagedRuntimeCallingConvention : public CallingConvention { 165 public: 166 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized, 167 const char* shorty, 168 InstructionSet instruction_set); 169 170 // Register that holds the incoming method argument 171 virtual ManagedRegister MethodRegister() = 0; 172 173 // Iterator interface 174 bool HasNext(); 175 void Next(); 176 bool IsCurrentParamAReference(); 177 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this 178 bool IsCurrentArgPossiblyNull(); 179 size_t CurrentParamSize(); 180 virtual bool IsCurrentParamInRegister() = 0; 181 virtual bool IsCurrentParamOnStack() = 0; 182 virtual ManagedRegister CurrentParamRegister() = 0; 183 virtual FrameOffset CurrentParamStackOffset() = 0; 184 185 virtual ~ManagedRuntimeCallingConvention() {} 186 187 // Registers to spill to caller's out registers on entry. 188 virtual const std::vector<ManagedRegister>& EntrySpills() = 0; 189 190 protected: 191 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) 192 : CallingConvention(is_static, is_synchronized, shorty) {} 193 }; 194 195 // Abstraction for JNI calling conventions 196 // | { Incoming stack args } | <-- Prior SP 197 // | { Return address } | 198 // | { Callee saves } | ([1]) 199 // | { Return value spill } | (live on return slow paths) 200 // | { Local Ref. Table State } | 201 // | { Stack Indirect Ref. Table | 202 // | num. refs./link } | (here to prior SP is frame size) 203 // | { Method* } | <-- Anchor SP written to thread 204 // | { Outgoing stack args } | <-- SP at point of call 205 // | Native frame | 206 // 207 // [1] We must save all callee saves here to enable any exception throws to restore 208 // callee saves for frames above this one. 209 class JniCallingConvention : public CallingConvention { 210 public: 211 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty, 212 InstructionSet instruction_set); 213 214 // Size of frame excluding space for outgoing args (its assumed Method* is 215 // always at the bottom of a frame, but this doesn't work for outgoing 216 // native args). Includes alignment. 217 virtual size_t FrameSize() = 0; 218 // Size of outgoing arguments, including alignment 219 virtual size_t OutArgSize() = 0; 220 // Number of references in stack indirect reference table 221 size_t ReferenceCount() const; 222 // Location where the segment state of the local indirect reference table is saved 223 FrameOffset SavedLocalReferenceCookieOffset() const; 224 // Location where the return value of a call can be squirreled if another 225 // call is made following the native call 226 FrameOffset ReturnValueSaveLocation() const; 227 // Register that holds result if it is integer. 228 virtual ManagedRegister IntReturnRegister() = 0; 229 230 // Callee save registers to spill prior to native code (which may clobber) 231 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0; 232 233 // Spill mask values 234 virtual uint32_t CoreSpillMask() const = 0; 235 virtual uint32_t FpSpillMask() const = 0; 236 237 // An extra scratch register live after the call 238 virtual ManagedRegister ReturnScratchRegister() const = 0; 239 240 // Iterator interface 241 bool HasNext(); 242 virtual void Next(); 243 bool IsCurrentParamAReference(); 244 size_t CurrentParamSize(); 245 virtual bool IsCurrentParamInRegister() = 0; 246 virtual bool IsCurrentParamOnStack() = 0; 247 virtual ManagedRegister CurrentParamRegister() = 0; 248 virtual FrameOffset CurrentParamStackOffset() = 0; 249 250 // Iterator interface extension for JNI 251 FrameOffset CurrentParamSirtEntryOffset(); 252 253 // Position of SIRT and interior fields 254 FrameOffset SirtOffset() const { 255 return FrameOffset(displacement_.Int32Value() + 256 kPointerSize); // above Method* 257 } 258 FrameOffset SirtNumRefsOffset() const { 259 return FrameOffset(SirtOffset().Int32Value() + 260 StackIndirectReferenceTable::NumberOfReferencesOffset()); 261 } 262 FrameOffset SirtLinkOffset() const { 263 return FrameOffset(SirtOffset().Int32Value() + 264 StackIndirectReferenceTable::LinkOffset()); 265 } 266 267 virtual ~JniCallingConvention() {} 268 269 protected: 270 // Named iterator positions 271 enum IteratorPos { 272 kJniEnv = 0, 273 kObjectOrClass = 1 274 }; 275 276 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty) 277 : CallingConvention(is_static, is_synchronized, shorty) {} 278 279 // Number of stack slots for outgoing arguments, above which the SIRT is 280 // located 281 virtual size_t NumberOfOutgoingStackArgs() = 0; 282 283 protected: 284 size_t NumberOfExtraArgumentsForJni(); 285 }; 286 287 } // namespace art 288 289 #endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ 290