Home | History | Annotate | Download | only in runtime
      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_RUNTIME_INSTRUCTION_SET_H_
     18 #define ART_RUNTIME_INSTRUCTION_SET_H_
     19 
     20 #include <iosfwd>
     21 #include <string>
     22 
     23 #include "base/logging.h"  // Logging is required for FATAL in the helper functions.
     24 #include "base/macros.h"
     25 #include "globals.h"       // For KB.
     26 
     27 namespace art {
     28 
     29 enum InstructionSet {
     30   kNone,
     31   kArm,
     32   kArm64,
     33   kThumb2,
     34   kX86,
     35   kX86_64,
     36   kMips,
     37   kMips64
     38 };
     39 std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
     40 
     41 #if defined(__arm__)
     42 static constexpr InstructionSet kRuntimeISA = kArm;
     43 #elif defined(__aarch64__)
     44 static constexpr InstructionSet kRuntimeISA = kArm64;
     45 #elif defined(__mips__)
     46 static constexpr InstructionSet kRuntimeISA = kMips;
     47 #elif defined(__i386__)
     48 static constexpr InstructionSet kRuntimeISA = kX86;
     49 #elif defined(__x86_64__)
     50 static constexpr InstructionSet kRuntimeISA = kX86_64;
     51 #else
     52 static constexpr InstructionSet kRuntimeISA = kNone;
     53 #endif
     54 
     55 // Architecture-specific pointer sizes
     56 static constexpr size_t kArmPointerSize = 4;
     57 static constexpr size_t kArm64PointerSize = 8;
     58 static constexpr size_t kMipsPointerSize = 4;
     59 static constexpr size_t kX86PointerSize = 4;
     60 static constexpr size_t kX86_64PointerSize = 8;
     61 
     62 // ARM instruction alignment. ARM processors require code to be 4-byte aligned,
     63 // but ARM ELF requires 8..
     64 static constexpr size_t kArmAlignment = 8;
     65 
     66 // ARM64 instruction alignment. This is the recommended alignment for maximum performance.
     67 static constexpr size_t kArm64Alignment = 16;
     68 
     69 // MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
     70 // TODO: Can this be 4?
     71 static constexpr size_t kMipsAlignment = 8;
     72 
     73 // X86 instruction alignment. This is the recommended alignment for maximum performance.
     74 static constexpr size_t kX86Alignment = 16;
     75 
     76 
     77 const char* GetInstructionSetString(InstructionSet isa);
     78 
     79 // Note: Returns kNone when the string cannot be parsed to a known value.
     80 InstructionSet GetInstructionSetFromString(const char* instruction_set);
     81 
     82 static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
     83   switch (isa) {
     84     case kArm:
     85       // Fall-through.
     86     case kThumb2:
     87       return kArmPointerSize;
     88     case kArm64:
     89       return kArm64PointerSize;
     90     case kX86:
     91       return kX86PointerSize;
     92     case kX86_64:
     93       return kX86_64PointerSize;
     94     case kMips:
     95       return kMipsPointerSize;
     96     case kNone:
     97       LOG(FATAL) << "ISA kNone does not have pointer size.";
     98       return 0;
     99     default:
    100       LOG(FATAL) << "Unknown ISA " << isa;
    101       return 0;
    102   }
    103 }
    104 
    105 size_t GetInstructionSetAlignment(InstructionSet isa);
    106 
    107 static inline bool Is64BitInstructionSet(InstructionSet isa) {
    108   switch (isa) {
    109     case kArm:
    110     case kThumb2:
    111     case kX86:
    112     case kMips:
    113       return false;
    114 
    115     case kArm64:
    116     case kX86_64:
    117       return true;
    118 
    119     case kNone:
    120       LOG(FATAL) << "ISA kNone does not have bit width.";
    121       return 0;
    122     default:
    123       LOG(FATAL) << "Unknown ISA " << isa;
    124       return 0;
    125   }
    126 }
    127 
    128 static inline size_t InstructionSetPointerSize(InstructionSet isa) {
    129   return Is64BitInstructionSet(isa) ? 8U : 4U;
    130 }
    131 
    132 static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
    133   switch (isa) {
    134     case kArm:
    135       // Fall-through.
    136     case kThumb2:
    137       return 4;
    138     case kArm64:
    139       return 8;
    140     case kX86:
    141       return 4;
    142     case kX86_64:
    143       return 8;
    144     case kMips:
    145       return 4;
    146     case kNone:
    147       LOG(FATAL) << "ISA kNone does not have spills.";
    148       return 0;
    149     default:
    150       LOG(FATAL) << "Unknown ISA " << isa;
    151       return 0;
    152   }
    153 }
    154 
    155 static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
    156   switch (isa) {
    157     case kArm:
    158       // Fall-through.
    159     case kThumb2:
    160       return 4;
    161     case kArm64:
    162       return 8;
    163     case kX86:
    164       return 8;
    165     case kX86_64:
    166       return 8;
    167     case kMips:
    168       return 4;
    169     case kNone:
    170       LOG(FATAL) << "ISA kNone does not have spills.";
    171       return 0;
    172     default:
    173       LOG(FATAL) << "Unknown ISA " << isa;
    174       return 0;
    175   }
    176 }
    177 
    178 size_t GetStackOverflowReservedBytes(InstructionSet isa);
    179 
    180 enum InstructionFeatures {
    181   kHwDiv  = 0x1,              // Supports hardware divide.
    182   kHwLpae = 0x2,              // Supports Large Physical Address Extension.
    183 };
    184 
    185 // This is a bitmask of supported features per architecture.
    186 class PACKED(4) InstructionSetFeatures {
    187  public:
    188   InstructionSetFeatures() : mask_(0) {}
    189   explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
    190 
    191   static InstructionSetFeatures GuessInstructionSetFeatures();
    192 
    193   bool HasDivideInstruction() const {
    194       return (mask_ & kHwDiv) != 0;
    195   }
    196 
    197   void SetHasDivideInstruction(bool v) {
    198     mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
    199   }
    200 
    201   bool HasLpae() const {
    202     return (mask_ & kHwLpae) != 0;
    203   }
    204 
    205   void SetHasLpae(bool v) {
    206     mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
    207   }
    208 
    209   std::string GetFeatureString() const;
    210 
    211   // Other features in here.
    212 
    213   bool operator==(const InstructionSetFeatures &peer) const {
    214     return mask_ == peer.mask_;
    215   }
    216 
    217   bool operator!=(const InstructionSetFeatures &peer) const {
    218     return mask_ != peer.mask_;
    219   }
    220 
    221   bool operator<=(const InstructionSetFeatures &peer) const {
    222     return (mask_ & peer.mask_) == mask_;
    223   }
    224 
    225  private:
    226   uint32_t mask_;
    227 };
    228 
    229 // The following definitions create return types for two word-sized entities that will be passed
    230 // in registers so that memory operations for the interface trampolines can be avoided. The entities
    231 // are the resolved method and the pointer to the code to be invoked.
    232 //
    233 // On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
    234 // uint64_t or long long int.
    235 //
    236 // On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
    237 // size_t-sized values.
    238 //
    239 // We need two operations:
    240 //
    241 // 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
    242 //    GetTwoWordFailureValue() will return a value that has lower part == 0.
    243 //
    244 // 2) A value that combines two word-sized values.
    245 //    GetTwoWordSuccessValue() constructs this.
    246 //
    247 // IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
    248 //            that the object does not move or the value is updated. Simple use of this is NOT SAFE
    249 //            when the garbage collector can move objects concurrently. Ensure that required locks
    250 //            are held when using!
    251 
    252 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
    253 typedef uint64_t TwoWordReturn;
    254 
    255 // Encodes method_ptr==nullptr and code_ptr==nullptr
    256 static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
    257   return 0;
    258 }
    259 
    260 // Use the lower 32b for the method pointer and the upper 32b for the code pointer.
    261 static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
    262   uint32_t lo32 = static_cast<uint32_t>(lo);
    263   uint64_t hi64 = static_cast<uint64_t>(hi);
    264   return ((hi64 << 32) | lo32);
    265 }
    266 
    267 #elif defined(__x86_64__) || defined(__aarch64__)
    268 struct TwoWordReturn {
    269   uintptr_t lo;
    270   uintptr_t hi;
    271 };
    272 
    273 // Encodes method_ptr==nullptr. Leaves random value in code pointer.
    274 static inline TwoWordReturn GetTwoWordFailureValue() {
    275   TwoWordReturn ret;
    276   ret.lo = 0;
    277   return ret;
    278 }
    279 
    280 // Write values into their respective members.
    281 static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
    282   TwoWordReturn ret;
    283   ret.lo = lo;
    284   ret.hi = hi;
    285   return ret;
    286 }
    287 #else
    288 #error "Unsupported architecture"
    289 #endif
    290 
    291 }  // namespace art
    292 
    293 #endif  // ART_RUNTIME_INSTRUCTION_SET_H_
    294