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 "base/arena_object.h" 21 #include "base/array_ref.h" 22 #include "base/enums.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,PointerSize frame_pointer_size)74 CallingConvention(bool is_static, 75 bool is_synchronized, 76 const char* shorty, 77 PointerSize frame_pointer_size) 78 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0), 79 itr_float_and_doubles_(0), displacement_(0), 80 frame_pointer_size_(frame_pointer_size), 81 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)), 82 is_static_(is_static), is_synchronized_(is_synchronized), 83 shorty_(shorty) { 84 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1; 85 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer. 86 num_float_or_double_args_ = 0; 87 num_long_or_double_args_ = 0; 88 for (size_t i = 1; i < strlen(shorty); i++) { 89 char ch = shorty_[i]; 90 switch (ch) { 91 case 'L': 92 num_ref_args_++; 93 break; 94 case 'J': 95 num_long_or_double_args_++; 96 break; 97 case 'D': 98 num_long_or_double_args_++; 99 num_float_or_double_args_++; 100 break; 101 case 'F': 102 num_float_or_double_args_++; 103 break; 104 } 105 } 106 } 107 IsStatic()108 bool IsStatic() const { 109 return is_static_; 110 } IsSynchronized()111 bool IsSynchronized() const { 112 return is_synchronized_; 113 } IsParamALongOrDouble(unsigned int param)114 bool IsParamALongOrDouble(unsigned int param) const { 115 DCHECK_LT(param, NumArgs()); 116 if (IsStatic()) { 117 param++; // 0th argument must skip return value at start of the shorty 118 } else if (param == 0) { 119 return false; // this argument 120 } 121 char ch = shorty_[param]; 122 return (ch == 'J' || ch == 'D'); 123 } IsParamAFloatOrDouble(unsigned int param)124 bool IsParamAFloatOrDouble(unsigned int param) const { 125 DCHECK_LT(param, NumArgs()); 126 if (IsStatic()) { 127 param++; // 0th argument must skip return value at start of the shorty 128 } else if (param == 0) { 129 return false; // this argument 130 } 131 char ch = shorty_[param]; 132 return (ch == 'F' || ch == 'D'); 133 } IsParamADouble(unsigned int param)134 bool IsParamADouble(unsigned int param) const { 135 DCHECK_LT(param, NumArgs()); 136 if (IsStatic()) { 137 param++; // 0th argument must skip return value at start of the shorty 138 } else if (param == 0) { 139 return false; // this argument 140 } 141 return shorty_[param] == 'D'; 142 } IsParamALong(unsigned int param)143 bool IsParamALong(unsigned int param) const { 144 DCHECK_LT(param, NumArgs()); 145 if (IsStatic()) { 146 param++; // 0th argument must skip return value at start of the shorty 147 } else if (param == 0) { 148 return false; // this argument 149 } 150 return shorty_[param] == 'J'; 151 } IsParamAReference(unsigned int param)152 bool IsParamAReference(unsigned int param) const { 153 DCHECK_LT(param, NumArgs()); 154 if (IsStatic()) { 155 param++; // 0th argument must skip return value at start of the shorty 156 } else if (param == 0) { 157 return true; // this argument 158 } 159 return shorty_[param] == 'L'; 160 } NumArgs()161 size_t NumArgs() const { 162 return num_args_; 163 } 164 // Implicit argument count: 1 for instance functions, 0 for static functions. 165 // (The implicit argument is only relevant to the shorty, i.e. 166 // the 0th arg is not in the shorty if it's implicit). NumImplicitArgs()167 size_t NumImplicitArgs() const { 168 return IsStatic() ? 0 : 1; 169 } NumLongOrDoubleArgs()170 size_t NumLongOrDoubleArgs() const { 171 return num_long_or_double_args_; 172 } NumFloatOrDoubleArgs()173 size_t NumFloatOrDoubleArgs() const { 174 return num_float_or_double_args_; 175 } NumReferenceArgs()176 size_t NumReferenceArgs() const { 177 return num_ref_args_; 178 } ParamSize(unsigned int param)179 size_t ParamSize(unsigned int param) const { 180 DCHECK_LT(param, NumArgs()); 181 if (IsStatic()) { 182 param++; // 0th argument must skip return value at start of the shorty 183 } else if (param == 0) { 184 return sizeof(mirror::HeapReference<mirror::Object>); // this argument 185 } 186 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param])); 187 if (result >= 1 && result < 4) { 188 result = 4; 189 } 190 return result; 191 } GetShorty()192 const char* GetShorty() const { 193 return shorty_.c_str(); 194 } 195 // The slot number for current calling_convention argument. 196 // Note that each slot is 32-bit. When the current argument is bigger 197 // than 32 bits, return the first slot number for this argument. 198 unsigned int itr_slots_; 199 // The number of references iterated past. 200 unsigned int itr_refs_; 201 // The argument number along argument list for current argument. 202 unsigned int itr_args_; 203 // Number of longs and doubles seen along argument list. 204 unsigned int itr_longs_and_doubles_; 205 // Number of float and doubles seen along argument list. 206 unsigned int itr_float_and_doubles_; 207 // Space for frames below this on the stack. 208 FrameOffset displacement_; 209 // The size of a pointer. 210 const PointerSize frame_pointer_size_; 211 // The size of a reference entry within the handle scope. 212 const size_t handle_scope_pointer_size_; 213 214 private: 215 const bool is_static_; 216 const bool is_synchronized_; 217 std::string shorty_; 218 size_t num_args_; 219 size_t num_ref_args_; 220 size_t num_float_or_double_args_; 221 size_t num_long_or_double_args_; 222 }; 223 224 // Abstraction for managed code's calling conventions 225 // | { Incoming stack args } | 226 // | { Prior Method* } | <-- Prior SP 227 // | { Return address } | 228 // | { Callee saves } | 229 // | { Spills ... } | 230 // | { Outgoing stack args } | 231 // | { Method* } | <-- SP 232 class ManagedRuntimeCallingConvention : public CallingConvention { 233 public: 234 static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* arena, 235 bool is_static, 236 bool is_synchronized, 237 const char* shorty, 238 InstructionSet instruction_set); 239 240 // Register that holds the incoming method argument 241 virtual ManagedRegister MethodRegister() = 0; 242 243 // Iterator interface 244 bool HasNext(); 245 void Next(); 246 bool IsCurrentParamAReference(); 247 bool IsCurrentParamAFloatOrDouble(); 248 bool IsCurrentParamADouble(); 249 bool IsCurrentParamALong(); 250 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this 251 bool IsCurrentArgPossiblyNull(); 252 size_t CurrentParamSize(); 253 virtual bool IsCurrentParamInRegister() = 0; 254 virtual bool IsCurrentParamOnStack() = 0; 255 virtual ManagedRegister CurrentParamRegister() = 0; 256 virtual FrameOffset CurrentParamStackOffset() = 0; 257 ~ManagedRuntimeCallingConvention()258 virtual ~ManagedRuntimeCallingConvention() {} 259 260 // Registers to spill to caller's out registers on entry. 261 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0; 262 263 protected: ManagedRuntimeCallingConvention(bool is_static,bool is_synchronized,const char * shorty,PointerSize frame_pointer_size)264 ManagedRuntimeCallingConvention(bool is_static, 265 bool is_synchronized, 266 const char* shorty, 267 PointerSize frame_pointer_size) 268 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {} 269 }; 270 271 // Abstraction for JNI calling conventions 272 // | { Incoming stack args } | <-- Prior SP 273 // | { Return address } | 274 // | { Callee saves } | ([1]) 275 // | { Return value spill } | (live on return slow paths) 276 // | { Local Ref. Table State } | 277 // | { Stack Indirect Ref. Table | 278 // | num. refs./link } | (here to prior SP is frame size) 279 // | { Method* } | <-- Anchor SP written to thread 280 // | { Outgoing stack args } | <-- SP at point of call 281 // | Native frame | 282 // 283 // [1] We must save all callee saves here to enable any exception throws to restore 284 // callee saves for frames above this one. 285 class JniCallingConvention : public CallingConvention { 286 public: 287 static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* arena, 288 bool is_static, 289 bool is_synchronized, 290 bool is_critical_native, 291 const char* shorty, 292 InstructionSet instruction_set); 293 294 // Size of frame excluding space for outgoing args (its assumed Method* is 295 // always at the bottom of a frame, but this doesn't work for outgoing 296 // native args). Includes alignment. 297 virtual size_t FrameSize() = 0; 298 // Size of outgoing arguments (stack portion), including alignment. 299 // -- Arguments that are passed via registers are excluded from this size. 300 virtual size_t OutArgSize() = 0; 301 // Number of references in stack indirect reference table 302 size_t ReferenceCount() const; 303 // Location where the segment state of the local indirect reference table is saved 304 FrameOffset SavedLocalReferenceCookieOffset() const; 305 // Location where the return value of a call can be squirreled if another 306 // call is made following the native call 307 FrameOffset ReturnValueSaveLocation() const; 308 // Register that holds result if it is integer. 309 virtual ManagedRegister IntReturnRegister() = 0; 310 // Whether the compiler needs to ensure zero-/sign-extension of a small result type 311 virtual bool RequiresSmallResultTypeExtension() const = 0; 312 313 // Callee save registers to spill prior to native code (which may clobber) 314 virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0; 315 316 // Spill mask values 317 virtual uint32_t CoreSpillMask() const = 0; 318 virtual uint32_t FpSpillMask() const = 0; 319 320 // An extra scratch register live after the call 321 virtual ManagedRegister ReturnScratchRegister() const = 0; 322 323 // Iterator interface 324 bool HasNext(); 325 virtual void Next(); 326 bool IsCurrentParamAReference(); 327 bool IsCurrentParamAFloatOrDouble(); 328 bool IsCurrentParamADouble(); 329 bool IsCurrentParamALong(); IsCurrentParamALongOrDouble()330 bool IsCurrentParamALongOrDouble() { 331 return IsCurrentParamALong() || IsCurrentParamADouble(); 332 } 333 bool IsCurrentParamJniEnv(); 334 size_t CurrentParamSize() const; 335 virtual bool IsCurrentParamInRegister() = 0; 336 virtual bool IsCurrentParamOnStack() = 0; 337 virtual ManagedRegister CurrentParamRegister() = 0; 338 virtual FrameOffset CurrentParamStackOffset() = 0; 339 340 // Iterator interface extension for JNI 341 FrameOffset CurrentParamHandleScopeEntryOffset(); 342 343 // Position of handle scope and interior fields HandleScopeOffset()344 FrameOffset HandleScopeOffset() const { 345 return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_)); 346 // above Method reference 347 } 348 HandleScopeLinkOffset()349 FrameOffset HandleScopeLinkOffset() const { 350 return FrameOffset(HandleScopeOffset().Int32Value() + 351 HandleScope::LinkOffset(frame_pointer_size_)); 352 } 353 HandleScopeNumRefsOffset()354 FrameOffset HandleScopeNumRefsOffset() const { 355 return FrameOffset(HandleScopeOffset().Int32Value() + 356 HandleScope::NumberOfReferencesOffset(frame_pointer_size_)); 357 } 358 HandleReferencesOffset()359 FrameOffset HandleReferencesOffset() const { 360 return FrameOffset(HandleScopeOffset().Int32Value() + 361 HandleScope::ReferencesOffset(frame_pointer_size_)); 362 } 363 ~JniCallingConvention()364 virtual ~JniCallingConvention() {} 365 366 protected: 367 // Named iterator positions 368 enum IteratorPos { 369 kJniEnv = 0, 370 kObjectOrClass = 1 371 }; 372 JniCallingConvention(bool is_static,bool is_synchronized,bool is_critical_native,const char * shorty,PointerSize frame_pointer_size)373 JniCallingConvention(bool is_static, 374 bool is_synchronized, 375 bool is_critical_native, 376 const char* shorty, 377 PointerSize frame_pointer_size) 378 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size), 379 is_critical_native_(is_critical_native) {} 380 381 // Number of stack slots for outgoing arguments, above which the handle scope is 382 // located 383 virtual size_t NumberOfOutgoingStackArgs() = 0; 384 385 protected: 386 size_t NumberOfExtraArgumentsForJni() const; 387 388 // Does the transition have a StackHandleScope? 389 bool HasHandleScope() const; 390 // Does the transition have a local reference segment state? 391 bool HasLocalReferenceSegmentState() const; 392 // Has a JNIEnv* parameter implicitly? 393 bool HasJniEnv() const; 394 // Has a 'jclass' parameter implicitly? 395 bool HasSelfClass() const; 396 397 // Are there extra JNI arguments (JNIEnv* and maybe jclass)? 398 bool HasExtraArgumentsForJni() const; 399 400 // Returns the position of itr_args_, fixed up by removing the offset of extra JNI arguments. 401 unsigned int GetIteratorPositionWithinShorty() const; 402 403 // Is the current argument (at the iterator) an extra argument for JNI? 404 bool IsCurrentArgExtraForJni() const; 405 406 const bool is_critical_native_; 407 408 private: 409 // Shorthand for switching on the switch value but only IF there are extra JNI arguments. 410 // 411 // Puts the case value into return_value. 412 // * (switch_value == kJniEnv) => case_jni_env 413 // * (switch_value == kObjectOrClass) => case_object_or_class 414 // 415 // Returns false otherwise (or if there are no extra JNI arguments). 416 bool SwitchExtraJniArguments(size_t switch_value, 417 bool case_jni_env, 418 bool case_object_or_class, 419 /* out parameters */ 420 bool* return_value) const; 421 }; 422 423 } // namespace art 424 425 #endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ 426