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 "handle_scope.h" 22 #include "primitive.h" 23 #include "thread.h" 24 #include "utils/managed_register.h" 25 26 namespace art { 27 28 // Top-level abstraction for different calling conventions. 29 class CallingConvention { 30 public: IsReturnAReference()31 bool IsReturnAReference() const { return shorty_[0] == 'L'; } 32 GetReturnType()33 Primitive::Type GetReturnType() const { 34 return Primitive::GetType(shorty_[0]); 35 } 36 SizeOfReturnValue()37 size_t SizeOfReturnValue() const { 38 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0])); 39 if (result >= 1 && result < 4) { 40 result = 4; 41 } 42 return result; 43 } 44 45 // Register that holds result of this method invocation. 46 virtual ManagedRegister ReturnRegister() = 0; 47 // Register reserved for scratch usage during procedure calls. 48 virtual ManagedRegister InterproceduralScratchRegister() = 0; 49 50 // Offset of Method within the frame. MethodStackOffset()51 FrameOffset MethodStackOffset() { 52 return displacement_; 53 } 54 55 // Iterator interface 56 57 // Place iterator at start of arguments. The displacement is applied to 58 // frame offset methods to account for frames which may be on the stack 59 // below the one being iterated over. ResetIterator(FrameOffset displacement)60 void ResetIterator(FrameOffset displacement) { 61 displacement_ = displacement; 62 itr_slots_ = 0; 63 itr_args_ = 0; 64 itr_refs_ = 0; 65 itr_longs_and_doubles_ = 0; 66 itr_float_and_doubles_ = 0; 67 } 68 ~CallingConvention()69 virtual ~CallingConvention() {} 70 71 protected: CallingConvention(bool is_static,bool is_synchronized,const char * shorty,size_t frame_pointer_size)72 CallingConvention(bool is_static, bool is_synchronized, const char* shorty, 73 size_t frame_pointer_size) 74 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0), 75 itr_float_and_doubles_(0), displacement_(0), 76 frame_pointer_size_(frame_pointer_size), 77 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)), 78 is_static_(is_static), is_synchronized_(is_synchronized), 79 shorty_(shorty) { 80 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1; 81 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer. 82 num_float_or_double_args_ = 0; 83 num_long_or_double_args_ = 0; 84 for (size_t i = 1; i < strlen(shorty); i++) { 85 char ch = shorty_[i]; 86 switch (ch) { 87 case 'L': 88 num_ref_args_++; 89 break; 90 case 'J': 91 num_long_or_double_args_++; 92 break; 93 case 'D': 94 num_long_or_double_args_++; 95 num_float_or_double_args_++; 96 break; 97 case 'F': 98 num_float_or_double_args_++; 99 break; 100 } 101 } 102 } 103 IsStatic()104 bool IsStatic() const { 105 return is_static_; 106 } IsSynchronized()107 bool IsSynchronized() const { 108 return is_synchronized_; 109 } IsParamALongOrDouble(unsigned int param)110 bool IsParamALongOrDouble(unsigned int param) const { 111 DCHECK_LT(param, NumArgs()); 112 if (IsStatic()) { 113 param++; // 0th argument must skip return value at start of the shorty 114 } else if (param == 0) { 115 return false; // this argument 116 } 117 char ch = shorty_[param]; 118 return (ch == 'J' || ch == 'D'); 119 } IsParamAFloatOrDouble(unsigned int param)120 bool IsParamAFloatOrDouble(unsigned int param) const { 121 DCHECK_LT(param, NumArgs()); 122 if (IsStatic()) { 123 param++; // 0th argument must skip return value at start of the shorty 124 } else if (param == 0) { 125 return false; // this argument 126 } 127 char ch = shorty_[param]; 128 return (ch == 'F' || ch == 'D'); 129 } IsParamADouble(unsigned int param)130 bool IsParamADouble(unsigned int param) const { 131 DCHECK_LT(param, NumArgs()); 132 if (IsStatic()) { 133 param++; // 0th argument must skip return value at start of the shorty 134 } else if (param == 0) { 135 return false; // this argument 136 } 137 return shorty_[param] == 'D'; 138 } IsParamALong(unsigned int param)139 bool IsParamALong(unsigned int param) const { 140 DCHECK_LT(param, NumArgs()); 141 if (IsStatic()) { 142 param++; // 0th argument must skip return value at start of the shorty 143 } else if (param == 0) { 144 return true; // this argument 145 } 146 return shorty_[param] == 'J'; 147 } IsParamAReference(unsigned int param)148 bool IsParamAReference(unsigned int param) const { 149 DCHECK_LT(param, NumArgs()); 150 if (IsStatic()) { 151 param++; // 0th argument must skip return value at start of the shorty 152 } else if (param == 0) { 153 return true; // this argument 154 } 155 return shorty_[param] == 'L'; 156 } NumArgs()157 size_t NumArgs() const { 158 return num_args_; 159 } NumLongOrDoubleArgs()160 size_t NumLongOrDoubleArgs() const { 161 return num_long_or_double_args_; 162 } NumFloatOrDoubleArgs()163 size_t NumFloatOrDoubleArgs() const { 164 return num_float_or_double_args_; 165 } NumReferenceArgs()166 size_t NumReferenceArgs() const { 167 return num_ref_args_; 168 } ParamSize(unsigned int param)169 size_t ParamSize(unsigned int param) const { 170 DCHECK_LT(param, NumArgs()); 171 if (IsStatic()) { 172 param++; // 0th argument must skip return value at start of the shorty 173 } else if (param == 0) { 174 return frame_pointer_size_; // this argument 175 } 176 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param])); 177 if (result >= 1 && result < 4) { 178 result = 4; 179 } 180 return result; 181 } GetShorty()182 const char* GetShorty() const { 183 return shorty_.c_str(); 184 } 185 // The slot number for current calling_convention argument. 186 // Note that each slot is 32-bit. When the current argument is bigger 187 // than 32 bits, return the first slot number for this argument. 188 unsigned int itr_slots_; 189 // The number of references iterated past. 190 unsigned int itr_refs_; 191 // The argument number along argument list for current argument. 192 unsigned int itr_args_; 193 // Number of longs and doubles seen along argument list. 194 unsigned int itr_longs_and_doubles_; 195 // Number of float and doubles seen along argument list. 196 unsigned int itr_float_and_doubles_; 197 // Space for frames below this on the stack. 198 FrameOffset displacement_; 199 // The size of a reference. 200 const size_t frame_pointer_size_; 201 // The size of a reference entry within the handle scope. 202 const size_t handle_scope_pointer_size_; 203 204 private: 205 const bool is_static_; 206 const bool is_synchronized_; 207 std::string shorty_; 208 size_t num_args_; 209 size_t num_ref_args_; 210 size_t num_float_or_double_args_; 211 size_t num_long_or_double_args_; 212 }; 213 214 // Abstraction for managed code's calling conventions 215 // | { Incoming stack args } | 216 // | { Prior Method* } | <-- Prior SP 217 // | { Return address } | 218 // | { Callee saves } | 219 // | { Spills ... } | 220 // | { Outgoing stack args } | 221 // | { Method* } | <-- SP 222 class ManagedRuntimeCallingConvention : public CallingConvention { 223 public: 224 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized, 225 const char* shorty, 226 InstructionSet instruction_set); 227 228 // Register that holds the incoming method argument 229 virtual ManagedRegister MethodRegister() = 0; 230 231 // Iterator interface 232 bool HasNext(); 233 void Next(); 234 bool IsCurrentParamAReference(); 235 bool IsCurrentParamAFloatOrDouble(); 236 bool IsCurrentParamADouble(); 237 bool IsCurrentParamALong(); 238 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this 239 bool IsCurrentArgPossiblyNull(); 240 size_t CurrentParamSize(); 241 virtual bool IsCurrentParamInRegister() = 0; 242 virtual bool IsCurrentParamOnStack() = 0; 243 virtual ManagedRegister CurrentParamRegister() = 0; 244 virtual FrameOffset CurrentParamStackOffset() = 0; 245 ~ManagedRuntimeCallingConvention()246 virtual ~ManagedRuntimeCallingConvention() {} 247 248 // Registers to spill to caller's out registers on entry. 249 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0; 250 251 protected: ManagedRuntimeCallingConvention(bool is_static,bool is_synchronized,const char * shorty,size_t frame_pointer_size)252 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty, 253 size_t frame_pointer_size) 254 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {} 255 }; 256 257 // Abstraction for JNI calling conventions 258 // | { Incoming stack args } | <-- Prior SP 259 // | { Return address } | 260 // | { Callee saves } | ([1]) 261 // | { Return value spill } | (live on return slow paths) 262 // | { Local Ref. Table State } | 263 // | { Stack Indirect Ref. Table | 264 // | num. refs./link } | (here to prior SP is frame size) 265 // | { Method* } | <-- Anchor SP written to thread 266 // | { Outgoing stack args } | <-- SP at point of call 267 // | Native frame | 268 // 269 // [1] We must save all callee saves here to enable any exception throws to restore 270 // callee saves for frames above this one. 271 class JniCallingConvention : public CallingConvention { 272 public: 273 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty, 274 InstructionSet instruction_set); 275 276 // Size of frame excluding space for outgoing args (its assumed Method* is 277 // always at the bottom of a frame, but this doesn't work for outgoing 278 // native args). Includes alignment. 279 virtual size_t FrameSize() = 0; 280 // Size of outgoing arguments, including alignment 281 virtual size_t OutArgSize() = 0; 282 // Number of references in stack indirect reference table 283 size_t ReferenceCount() const; 284 // Location where the segment state of the local indirect reference table is saved 285 FrameOffset SavedLocalReferenceCookieOffset() const; 286 // Location where the return value of a call can be squirreled if another 287 // call is made following the native call 288 FrameOffset ReturnValueSaveLocation() const; 289 // Register that holds result if it is integer. 290 virtual ManagedRegister IntReturnRegister() = 0; 291 // Whether the compiler needs to ensure zero-/sign-extension of a small result type 292 virtual bool RequiresSmallResultTypeExtension() const = 0; 293 294 // Callee save registers to spill prior to native code (which may clobber) 295 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0; 296 297 // Spill mask values 298 virtual uint32_t CoreSpillMask() const = 0; 299 virtual uint32_t FpSpillMask() const = 0; 300 301 // An extra scratch register live after the call 302 virtual ManagedRegister ReturnScratchRegister() const = 0; 303 304 // Iterator interface 305 bool HasNext(); 306 virtual void Next(); 307 bool IsCurrentParamAReference(); 308 bool IsCurrentParamAFloatOrDouble(); 309 bool IsCurrentParamADouble(); 310 bool IsCurrentParamALong(); 311 bool IsCurrentParamJniEnv(); 312 size_t CurrentParamSize(); 313 virtual bool IsCurrentParamInRegister() = 0; 314 virtual bool IsCurrentParamOnStack() = 0; 315 virtual ManagedRegister CurrentParamRegister() = 0; 316 virtual FrameOffset CurrentParamStackOffset() = 0; 317 318 // Iterator interface extension for JNI 319 FrameOffset CurrentParamHandleScopeEntryOffset(); 320 321 // Position of handle scope and interior fields HandleScopeOffset()322 FrameOffset HandleScopeOffset() const { 323 return FrameOffset(this->displacement_.Int32Value() + sizeof(StackReference<mirror::ArtMethod>)); 324 // above Method reference 325 } 326 HandleScopeLinkOffset()327 FrameOffset HandleScopeLinkOffset() const { 328 return FrameOffset(HandleScopeOffset().Int32Value() + HandleScope::LinkOffset(frame_pointer_size_)); 329 } 330 HandleScopeNumRefsOffset()331 FrameOffset HandleScopeNumRefsOffset() const { 332 return FrameOffset(HandleScopeOffset().Int32Value() + 333 HandleScope::NumberOfReferencesOffset(frame_pointer_size_)); 334 } 335 HandleerencesOffset()336 FrameOffset HandleerencesOffset() const { 337 return FrameOffset(HandleScopeOffset().Int32Value() + 338 HandleScope::ReferencesOffset(frame_pointer_size_)); 339 } 340 ~JniCallingConvention()341 virtual ~JniCallingConvention() {} 342 343 protected: 344 // Named iterator positions 345 enum IteratorPos { 346 kJniEnv = 0, 347 kObjectOrClass = 1 348 }; 349 JniCallingConvention(bool is_static,bool is_synchronized,const char * shorty,size_t frame_pointer_size)350 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty, 351 size_t frame_pointer_size) 352 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {} 353 354 // Number of stack slots for outgoing arguments, above which the handle scope is 355 // located 356 virtual size_t NumberOfOutgoingStackArgs() = 0; 357 358 protected: 359 size_t NumberOfExtraArgumentsForJni(); 360 }; 361 362 } // namespace art 363 364 #endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ 365