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 GetBytesPerGprSpillLocation(InstructionSet isa) {
    129   switch (isa) {
    130     case kArm:
    131       // Fall-through.
    132     case kThumb2:
    133       return 4;
    134     case kArm64:
    135       return 8;
    136     case kX86:
    137       return 4;
    138     case kX86_64:
    139       return 8;
    140     case kMips:
    141       return 4;
    142     case kNone:
    143       LOG(FATAL) << "ISA kNone does not have spills.";
    144       return 0;
    145     default:
    146       LOG(FATAL) << "Unknown ISA " << isa;
    147       return 0;
    148   }
    149 }
    150 
    151 static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
    152   switch (isa) {
    153     case kArm:
    154       // Fall-through.
    155     case kThumb2:
    156       return 4;
    157     case kArm64:
    158       return 8;
    159     case kX86:
    160       return 8;
    161     case kX86_64:
    162       return 8;
    163     case kMips:
    164       return 4;
    165     case kNone:
    166       LOG(FATAL) << "ISA kNone does not have spills.";
    167       return 0;
    168     default:
    169       LOG(FATAL) << "Unknown ISA " << isa;
    170       return 0;
    171   }
    172 }
    173 
    174 size_t GetStackOverflowReservedBytes(InstructionSet isa);
    175 
    176 enum InstructionFeatures {
    177   kHwDiv  = 0x1,              // Supports hardware divide.
    178   kHwLpae = 0x2,              // Supports Large Physical Address Extension.
    179 };
    180 
    181 // This is a bitmask of supported features per architecture.
    182 class PACKED(4) InstructionSetFeatures {
    183  public:
    184   InstructionSetFeatures() : mask_(0) {}
    185   explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
    186 
    187   static InstructionSetFeatures GuessInstructionSetFeatures();
    188 
    189   bool HasDivideInstruction() const {
    190       return (mask_ & kHwDiv) != 0;
    191   }
    192 
    193   void SetHasDivideInstruction(bool v) {
    194     mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
    195   }
    196 
    197   bool HasLpae() const {
    198     return (mask_ & kHwLpae) != 0;
    199   }
    200 
    201   void SetHasLpae(bool v) {
    202     mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
    203   }
    204 
    205   std::string GetFeatureString() const;
    206 
    207   // Other features in here.
    208 
    209   bool operator==(const InstructionSetFeatures &peer) const {
    210     return mask_ == peer.mask_;
    211   }
    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_) == mask_;
    219   }
    220 
    221  private:
    222   uint32_t mask_;
    223 };
    224 
    225 // The following definitions create return types for two word-sized entities that will be passed
    226 // in registers so that memory operations for the interface trampolines can be avoided. The entities
    227 // are the resolved method and the pointer to the code to be invoked.
    228 //
    229 // On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
    230 // uint64_t or long long int.
    231 //
    232 // On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
    233 // size_t-sized values.
    234 //
    235 // We need two operations:
    236 //
    237 // 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
    238 //    GetTwoWordFailureValue() will return a value that has lower part == 0.
    239 //
    240 // 2) A value that combines two word-sized values.
    241 //    GetTwoWordSuccessValue() constructs this.
    242 //
    243 // IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
    244 //            that the object does not move or the value is updated. Simple use of this is NOT SAFE
    245 //            when the garbage collector can move objects concurrently. Ensure that required locks
    246 //            are held when using!
    247 
    248 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
    249 typedef uint64_t TwoWordReturn;
    250 
    251 // Encodes method_ptr==nullptr and code_ptr==nullptr
    252 static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
    253   return 0;
    254 }
    255 
    256 // Use the lower 32b for the method pointer and the upper 32b for the code pointer.
    257 static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
    258   uint32_t lo32 = static_cast<uint32_t>(lo);
    259   uint64_t hi64 = static_cast<uint64_t>(hi);
    260   return ((hi64 << 32) | lo32);
    261 }
    262 
    263 #elif defined(__x86_64__) || defined(__aarch64__)
    264 struct TwoWordReturn {
    265   uintptr_t lo;
    266   uintptr_t hi;
    267 };
    268 
    269 // Encodes method_ptr==nullptr. Leaves random value in code pointer.
    270 static inline TwoWordReturn GetTwoWordFailureValue() {
    271   TwoWordReturn ret;
    272   ret.lo = 0;
    273   return ret;
    274 }
    275 
    276 // Write values into their respective members.
    277 static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
    278   TwoWordReturn ret;
    279   ret.lo = lo;
    280   ret.hi = hi;
    281   return ret;
    282 }
    283 #else
    284 #error "Unsupported architecture"
    285 #endif
    286 
    287 }  // namespace art
    288 
    289 #endif  // ART_RUNTIME_INSTRUCTION_SET_H_
    290