Home | History | Annotate | Download | only in quick
      1 /*
      2  * Copyright (C) 2014 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_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
     18 #define ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
     19 
     20 #include "base/macros.h"
     21 #include "base/mutex.h"
     22 #include "dex_file.h"
     23 #include "dex_instruction.h"
     24 #include "method_reference.h"
     25 
     26 /*
     27  * NOTE: This code is part of the quick compiler. It lives in the runtime
     28  * only to allow the debugger to check whether a method has been inlined.
     29  */
     30 
     31 namespace art {
     32 
     33 namespace verifier {
     34 class MethodVerifier;
     35 }  // namespace verifier
     36 
     37 enum InlineMethodOpcode : uint16_t {
     38   kIntrinsicDoubleCvt,
     39   kIntrinsicFloatCvt,
     40   kIntrinsicFloat2Int,
     41   kIntrinsicDouble2Long,
     42   kIntrinsicFloatIsInfinite,
     43   kIntrinsicDoubleIsInfinite,
     44   kIntrinsicFloatIsNaN,
     45   kIntrinsicDoubleIsNaN,
     46   kIntrinsicReverseBits,
     47   kIntrinsicReverseBytes,
     48   kIntrinsicBitCount,
     49   kIntrinsicCompare,
     50   kIntrinsicHighestOneBit,
     51   kIntrinsicLowestOneBit,
     52   kIntrinsicNumberOfLeadingZeros,
     53   kIntrinsicNumberOfTrailingZeros,
     54   kIntrinsicRotateRight,
     55   kIntrinsicRotateLeft,
     56   kIntrinsicSignum,
     57   kIntrinsicAbsInt,
     58   kIntrinsicAbsLong,
     59   kIntrinsicAbsFloat,
     60   kIntrinsicAbsDouble,
     61   kIntrinsicMinMaxInt,
     62   kIntrinsicMinMaxLong,
     63   kIntrinsicMinMaxFloat,
     64   kIntrinsicMinMaxDouble,
     65   kIntrinsicCos,
     66   kIntrinsicSin,
     67   kIntrinsicAcos,
     68   kIntrinsicAsin,
     69   kIntrinsicAtan,
     70   kIntrinsicAtan2,
     71   kIntrinsicCbrt,
     72   kIntrinsicCosh,
     73   kIntrinsicExp,
     74   kIntrinsicExpm1,
     75   kIntrinsicHypot,
     76   kIntrinsicLog,
     77   kIntrinsicLog10,
     78   kIntrinsicNextAfter,
     79   kIntrinsicSinh,
     80   kIntrinsicTan,
     81   kIntrinsicTanh,
     82   kIntrinsicSqrt,
     83   kIntrinsicCeil,
     84   kIntrinsicFloor,
     85   kIntrinsicRint,
     86   kIntrinsicRoundFloat,
     87   kIntrinsicRoundDouble,
     88   kIntrinsicReferenceGetReferent,
     89   kIntrinsicCharAt,
     90   kIntrinsicCompareTo,
     91   kIntrinsicEquals,
     92   kIntrinsicGetCharsNoCheck,
     93   kIntrinsicIsEmptyOrLength,
     94   kIntrinsicIndexOf,
     95   kIntrinsicNewStringFromBytes,
     96   kIntrinsicNewStringFromChars,
     97   kIntrinsicNewStringFromString,
     98   kIntrinsicCurrentThread,
     99   kIntrinsicPeek,
    100   kIntrinsicPoke,
    101   kIntrinsicCas,
    102   kIntrinsicUnsafeGet,
    103   kIntrinsicUnsafePut,
    104 
    105   // 1.8.
    106   kIntrinsicUnsafeGetAndAddInt,
    107   kIntrinsicUnsafeGetAndAddLong,
    108   kIntrinsicUnsafeGetAndSetInt,
    109   kIntrinsicUnsafeGetAndSetLong,
    110   kIntrinsicUnsafeGetAndSetObject,
    111   kIntrinsicUnsafeLoadFence,
    112   kIntrinsicUnsafeStoreFence,
    113   kIntrinsicUnsafeFullFence,
    114 
    115   kIntrinsicSystemArrayCopyCharArray,
    116   kIntrinsicSystemArrayCopy,
    117 
    118   kInlineOpNop,
    119   kInlineOpReturnArg,
    120   kInlineOpNonWideConst,
    121   kInlineOpIGet,
    122   kInlineOpIPut,
    123   kInlineOpConstructor,
    124   kInlineStringInit,
    125 };
    126 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
    127 
    128 enum InlineMethodFlags : uint16_t {
    129   kNoInlineMethodFlags = 0x0000,
    130   kInlineIntrinsic     = 0x0001,
    131   kInlineSpecial       = 0x0002,
    132 };
    133 
    134 // IntrinsicFlags are stored in InlineMethod::d::raw_data
    135 enum IntrinsicFlags {
    136   kIntrinsicFlagNone = 0,
    137 
    138   // kIntrinsicMinMaxInt
    139   kIntrinsicFlagMax = kIntrinsicFlagNone,
    140   kIntrinsicFlagMin = 1,
    141 
    142   // kIntrinsicIsEmptyOrLength
    143   kIntrinsicFlagLength  = kIntrinsicFlagNone,
    144   kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
    145 
    146   // kIntrinsicIndexOf
    147   kIntrinsicFlagBase0 = kIntrinsicFlagMin,
    148 
    149   // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
    150   kIntrinsicFlagIsLong     = kIntrinsicFlagMin,
    151   // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
    152   kIntrinsicFlagIsVolatile = 2,
    153   // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
    154   kIntrinsicFlagIsObject   = 4,
    155   // kIntrinsicUnsafePut
    156   kIntrinsicFlagIsOrdered  = 8,
    157 
    158   // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
    159   kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
    160 };
    161 
    162 struct InlineIGetIPutData {
    163   // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
    164   uint16_t op_variant : 3;
    165   uint16_t method_is_static : 1;
    166   uint16_t object_arg : 4;
    167   uint16_t src_arg : 4;  // iput only
    168   uint16_t return_arg_plus1 : 4;  // iput only, method argument to return + 1, 0 = return void.
    169   uint16_t field_idx;
    170   uint32_t is_volatile : 1;
    171   uint32_t field_offset : 31;
    172 };
    173 static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
    174 
    175 struct InlineReturnArgData {
    176   uint16_t arg;
    177   uint16_t is_wide : 1;
    178   uint16_t is_object : 1;
    179   uint16_t reserved : 14;
    180   uint32_t reserved2;
    181 };
    182 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
    183               "Invalid size of InlineReturnArgData");
    184 
    185 struct InlineConstructorData {
    186   // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
    187   uint16_t iput0_field_index;
    188   uint16_t iput1_field_index;
    189   uint16_t iput2_field_index;
    190   uint16_t iput0_arg : 4;
    191   uint16_t iput1_arg : 4;
    192   uint16_t iput2_arg : 4;
    193   uint16_t reserved : 4;
    194 };
    195 static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
    196               "Invalid size of InlineConstructorData");
    197 
    198 struct InlineMethod {
    199   InlineMethodOpcode opcode;
    200   InlineMethodFlags flags;
    201   union {
    202     uint64_t data;
    203     InlineIGetIPutData ifield_data;
    204     InlineReturnArgData return_data;
    205     InlineConstructorData constructor_data;
    206   } d;
    207 };
    208 
    209 class InlineMethodAnalyser {
    210  public:
    211   /**
    212    * Analyse method code to determine if the method is a candidate for inlining.
    213    * If it is, record the inlining data.
    214    *
    215    * @param verifier the method verifier holding data about the method to analyse.
    216    * @param method placeholder for the inline method data.
    217    * @return true if the method is a candidate for inlining, false otherwise.
    218    */
    219   static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result)
    220       SHARED_REQUIRES(Locks::mutator_lock_);
    221   static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result)
    222       SHARED_REQUIRES(Locks::mutator_lock_);
    223 
    224   static constexpr bool IsInstructionIGet(Instruction::Code opcode) {
    225     return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT;
    226   }
    227 
    228   static constexpr bool IsInstructionIPut(Instruction::Code opcode) {
    229     return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT;
    230   }
    231 
    232   static constexpr uint16_t IGetVariant(Instruction::Code opcode) {
    233     return opcode - Instruction::IGET;
    234   }
    235 
    236   static constexpr uint16_t IPutVariant(Instruction::Code opcode) {
    237     return opcode - Instruction::IPUT;
    238   }
    239 
    240   // Determines whether the method is a synthetic accessor (method name starts with "access$").
    241   static bool IsSyntheticAccessor(MethodReference ref);
    242 
    243  private:
    244   static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
    245                                 const MethodReference& method_ref,
    246                                 bool is_static,
    247                                 ArtMethod* method,
    248                                 InlineMethod* result)
    249       SHARED_REQUIRES(Locks::mutator_lock_);
    250   static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
    251   static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
    252   static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
    253                                 const MethodReference& method_ref,
    254                                 bool is_static,
    255                                 ArtMethod* method,
    256                                 InlineMethod* result)
    257       SHARED_REQUIRES(Locks::mutator_lock_);
    258   static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
    259                                 const MethodReference& method_ref,
    260                                 bool is_static,
    261                                 ArtMethod* method,
    262                                 InlineMethod* result)
    263       SHARED_REQUIRES(Locks::mutator_lock_);
    264 
    265   // Can we fast path instance field access in a verified accessor?
    266   // If yes, computes field's offset and volatility and whether the method is static or not.
    267   static bool ComputeSpecialAccessorInfo(ArtMethod* method,
    268                                          uint32_t field_idx,
    269                                          bool is_put,
    270                                          InlineIGetIPutData* result)
    271       SHARED_REQUIRES(Locks::mutator_lock_);
    272 };
    273 
    274 }  // namespace art
    275 
    276 #endif  // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_
    277