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 // 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,
     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 
    108   bool IsStatic() const {
    109     return is_static_;
    110   }
    111   bool IsSynchronized() const {
    112     return is_synchronized_;
    113   }
    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   }
    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   }
    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   }
    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   }
    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   }
    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).
    167   size_t NumImplicitArgs() const {
    168     return IsStatic() ? 0 : 1;
    169   }
    170   size_t NumLongOrDoubleArgs() const {
    171     return num_long_or_double_args_;
    172   }
    173   size_t NumFloatOrDoubleArgs() const {
    174     return num_float_or_double_args_;
    175   }
    176   size_t NumReferenceArgs() const {
    177     return num_ref_args_;
    178   }
    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   }
    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* allocator,
    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 
    258   virtual ~ManagedRuntimeCallingConvention() {}
    259 
    260   // Registers to spill to caller's out registers on entry.
    261   virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
    262 
    263  protected:
    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* allocator,
    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();
    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
    344   FrameOffset HandleScopeOffset() const {
    345     return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
    346     // above Method reference
    347   }
    348 
    349   FrameOffset HandleScopeLinkOffset() const {
    350     return FrameOffset(HandleScopeOffset().Int32Value() +
    351                        HandleScope::LinkOffset(frame_pointer_size_));
    352   }
    353 
    354   FrameOffset HandleScopeNumRefsOffset() const {
    355     return FrameOffset(HandleScopeOffset().Int32Value() +
    356                        HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
    357   }
    358 
    359   FrameOffset HandleReferencesOffset() const {
    360     return FrameOffset(HandleScopeOffset().Int32Value() +
    361                        HandleScope::ReferencesOffset(frame_pointer_size_));
    362   }
    363 
    364   virtual ~JniCallingConvention() {}
    365 
    366  protected:
    367   // Named iterator positions
    368   enum IteratorPos {
    369     kJniEnv = 0,
    370     kObjectOrClass = 1
    371   };
    372 
    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