Home | History | Annotate | Download | only in quick
      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:
     31   bool IsReturnAReference() const { return shorty_[0] == 'L'; }
     32 
     33   Primitive::Type GetReturnType() const {
     34     return Primitive::GetType(shorty_[0]);
     35   }
     36 
     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.
     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.
     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 
     69   virtual ~CallingConvention() {}
     70 
     71  protected:
     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 
    104   bool IsStatic() const {
    105     return is_static_;
    106   }
    107   bool IsSynchronized() const {
    108     return is_synchronized_;
    109   }
    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   }
    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   }
    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   }
    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 false;  // this argument
    145     }
    146     return shorty_[param] == 'J';
    147   }
    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   }
    157   size_t NumArgs() const {
    158     return num_args_;
    159   }
    160   size_t NumLongOrDoubleArgs() const {
    161     return num_long_or_double_args_;
    162   }
    163   size_t NumFloatOrDoubleArgs() const {
    164     return num_float_or_double_args_;
    165   }
    166   size_t NumReferenceArgs() const {
    167     return num_ref_args_;
    168   }
    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 sizeof(mirror::HeapReference<mirror::Object>);  // 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   }
    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 pointer.
    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 
    246   virtual ~ManagedRuntimeCallingConvention() {}
    247 
    248   // Registers to spill to caller's out registers on entry.
    249   virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
    250 
    251  protected:
    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
    322   FrameOffset HandleScopeOffset() const {
    323     return FrameOffset(this->displacement_.Int32Value() + frame_pointer_size_);
    324     // above Method reference
    325   }
    326 
    327   FrameOffset HandleScopeLinkOffset() const {
    328     return FrameOffset(HandleScopeOffset().Int32Value() +
    329                        HandleScope::LinkOffset(frame_pointer_size_));
    330   }
    331 
    332   FrameOffset HandleScopeNumRefsOffset() const {
    333     return FrameOffset(HandleScopeOffset().Int32Value() +
    334                        HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
    335   }
    336 
    337   FrameOffset HandleReferencesOffset() const {
    338     return FrameOffset(HandleScopeOffset().Int32Value() +
    339                        HandleScope::ReferencesOffset(frame_pointer_size_));
    340   }
    341 
    342   virtual ~JniCallingConvention() {}
    343 
    344  protected:
    345   // Named iterator positions
    346   enum IteratorPos {
    347     kJniEnv = 0,
    348     kObjectOrClass = 1
    349   };
    350 
    351   explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
    352                                 size_t frame_pointer_size)
    353       : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
    354 
    355   // Number of stack slots for outgoing arguments, above which the handle scope is
    356   // located
    357   virtual size_t NumberOfOutgoingStackArgs() = 0;
    358 
    359  protected:
    360   size_t NumberOfExtraArgumentsForJni();
    361 };
    362 
    363 }  // namespace art
    364 
    365 #endif  // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
    366