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 "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