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