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