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 
     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:
     33   bool IsReturnAReference() const { return shorty_[0] == 'L'; }
     34 
     35   Primitive::Type GetReturnType() const {
     36     return Primitive::GetType(shorty_[0]);
     37   }
     38 
     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.
     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.
     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 
     71   virtual ~CallingConvention() {}
     72 
     73  protected:
     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 
    106   bool IsStatic() const {
    107     return is_static_;
    108   }
    109   bool IsSynchronized() const {
    110     return is_synchronized_;
    111   }
    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   }
    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   }
    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   }
    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   }
    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   }
    159   size_t NumArgs() const {
    160     return num_args_;
    161   }
    162   size_t NumLongOrDoubleArgs() const {
    163     return num_long_or_double_args_;
    164   }
    165   size_t NumFloatOrDoubleArgs() const {
    166     return num_float_or_double_args_;
    167   }
    168   size_t NumReferenceArgs() const {
    169     return num_ref_args_;
    170   }
    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   }
    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 
    250   virtual ~ManagedRuntimeCallingConvention() {}
    251 
    252   // Registers to spill to caller's out registers on entry.
    253   virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
    254 
    255  protected:
    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
    331   FrameOffset HandleScopeOffset() const {
    332     return FrameOffset(this->displacement_.Int32Value() + frame_pointer_size_);
    333     // above Method reference
    334   }
    335 
    336   FrameOffset HandleScopeLinkOffset() const {
    337     return FrameOffset(HandleScopeOffset().Int32Value() +
    338                        HandleScope::LinkOffset(frame_pointer_size_));
    339   }
    340 
    341   FrameOffset HandleScopeNumRefsOffset() const {
    342     return FrameOffset(HandleScopeOffset().Int32Value() +
    343                        HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
    344   }
    345 
    346   FrameOffset HandleReferencesOffset() const {
    347     return FrameOffset(HandleScopeOffset().Int32Value() +
    348                        HandleScope::ReferencesOffset(frame_pointer_size_));
    349   }
    350 
    351   virtual ~JniCallingConvention() {}
    352 
    353  protected:
    354   // Named iterator positions
    355   enum IteratorPos {
    356     kJniEnv = 0,
    357     kObjectOrClass = 1
    358   };
    359 
    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