Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_SAFEPOINT_TABLE_H_
      6 #define V8_SAFEPOINT_TABLE_H_
      7 
      8 #include "src/allocation.h"
      9 #include "src/assert-scope.h"
     10 #include "src/utils.h"
     11 #include "src/v8memory.h"
     12 #include "src/zone/zone-chunk-list.h"
     13 #include "src/zone/zone.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 class Register;
     19 
     20 class SafepointEntry BASE_EMBEDDED {
     21  public:
     22   SafepointEntry() : info_(0), bits_(nullptr), trampoline_pc_(-1) {}
     23 
     24   SafepointEntry(unsigned info, uint8_t* bits, int trampoline_pc)
     25       : info_(info), bits_(bits), trampoline_pc_(trampoline_pc) {
     26     DCHECK(is_valid());
     27   }
     28 
     29   bool is_valid() const { return bits_ != nullptr; }
     30 
     31   bool Equals(const SafepointEntry& other) const {
     32     return info_ == other.info_ && bits_ == other.bits_;
     33   }
     34 
     35   void Reset() {
     36     info_ = 0;
     37     bits_ = nullptr;
     38   }
     39 
     40   int deoptimization_index() const {
     41     DCHECK(is_valid());
     42     return DeoptimizationIndexField::decode(info_);
     43   }
     44 
     45   int trampoline_pc() { return trampoline_pc_; }
     46 
     47   void set_trampoline_pc(int trampoline_pc) { trampoline_pc_ = trampoline_pc; }
     48 
     49   static const int kArgumentsFieldBits = 3;
     50   static const int kSaveDoublesFieldBits = 1;
     51   static const int kDeoptIndexBits =
     52       32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
     53 
     54   class DeoptimizationIndexField:
     55     public BitField<int, 0, kDeoptIndexBits> {};  // NOLINT
     56   class ArgumentsField:
     57     public BitField<unsigned,
     58                     kDeoptIndexBits,
     59                     kArgumentsFieldBits> {};  // NOLINT
     60   class SaveDoublesField:
     61     public BitField<bool,
     62                     kDeoptIndexBits + kArgumentsFieldBits,
     63                     kSaveDoublesFieldBits> { }; // NOLINT
     64 
     65   int argument_count() const {
     66     DCHECK(is_valid());
     67     return ArgumentsField::decode(info_);
     68   }
     69 
     70   bool has_doubles() const {
     71     DCHECK(is_valid());
     72     return SaveDoublesField::decode(info_);
     73   }
     74 
     75   uint8_t* bits() {
     76     DCHECK(is_valid());
     77     return bits_;
     78   }
     79 
     80   bool HasRegisters() const;
     81   bool HasRegisterAt(int reg_index) const;
     82 
     83  private:
     84   unsigned info_;
     85   uint8_t* bits_;
     86   // It needs to be an integer as it is -1 for eager deoptimizations.
     87   int trampoline_pc_;
     88 };
     89 
     90 
     91 class SafepointTable BASE_EMBEDDED {
     92  public:
     93   explicit SafepointTable(Code* code);
     94   explicit SafepointTable(Address instruction_start,
     95                           size_t safepoint_table_offset, uint32_t stack_slots,
     96                           bool has_deopt = false);
     97 
     98   int size() const {
     99     return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_));
    100   }
    101   unsigned length() const { return length_; }
    102   unsigned entry_size() const { return entry_size_; }
    103 
    104   unsigned GetPcOffset(unsigned index) const {
    105     DCHECK(index < length_);
    106     return Memory<uint32_t>(GetPcOffsetLocation(index));
    107   }
    108 
    109   int GetTrampolinePcOffset(unsigned index) const {
    110     DCHECK(index < length_);
    111     return Memory<int>(GetTrampolineLocation(index));
    112   }
    113 
    114   unsigned find_return_pc(unsigned pc_offset);
    115 
    116   SafepointEntry GetEntry(unsigned index) const {
    117     DCHECK(index < length_);
    118     unsigned info = Memory<uint32_t>(GetInfoLocation(index));
    119     uint8_t* bits = &Memory<uint8_t>(entries_ + (index * entry_size_));
    120     int trampoline_pc =
    121         has_deopt_ ? Memory<int>(GetTrampolineLocation(index)) : -1;
    122     return SafepointEntry(info, bits, trampoline_pc);
    123   }
    124 
    125   // Returns the entry for the given pc.
    126   SafepointEntry FindEntry(Address pc) const;
    127 
    128   void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
    129 
    130  private:
    131   static const uint8_t kNoRegisters = 0xFF;
    132 
    133   // Layout information
    134   static const int kLengthOffset = 0;
    135   static const int kEntrySizeOffset = kLengthOffset + kIntSize;
    136   static const int kHeaderSize = kEntrySizeOffset + kIntSize;
    137   static const int kPcOffset = 0;
    138   static const int kDeoptimizationIndexOffset = kPcOffset + kIntSize;
    139   static const int kTrampolinePcOffset = kDeoptimizationIndexOffset + kIntSize;
    140   static const int kFixedEntrySize = kTrampolinePcOffset + kIntSize;
    141 
    142   Address GetPcOffsetLocation(unsigned index) const {
    143     return pc_and_deoptimization_indexes_ + (index * kFixedEntrySize);
    144   }
    145 
    146   // TODO(juliana): rename this to GetDeoptimizationIndexLocation
    147   Address GetInfoLocation(unsigned index) const {
    148     return GetPcOffsetLocation(index) + kDeoptimizationIndexOffset;
    149   }
    150 
    151   Address GetTrampolineLocation(unsigned index) const {
    152     return GetPcOffsetLocation(index) + kTrampolinePcOffset;
    153   }
    154 
    155   static void PrintBits(std::ostream& os,  // NOLINT
    156                         uint8_t byte, int digits);
    157 
    158   DisallowHeapAllocation no_allocation_;
    159   Address instruction_start_;
    160   uint32_t stack_slots_;
    161   unsigned length_;
    162   unsigned entry_size_;
    163 
    164   Address pc_and_deoptimization_indexes_;
    165   Address entries_;
    166   bool has_deopt_;
    167 
    168   friend class SafepointTableBuilder;
    169   friend class SafepointEntry;
    170 
    171   DISALLOW_COPY_AND_ASSIGN(SafepointTable);
    172 };
    173 
    174 
    175 class Safepoint BASE_EMBEDDED {
    176  public:
    177   typedef enum {
    178     kSimple = 0,
    179     kWithRegisters = 1 << 0,
    180     kWithDoubles = 1 << 1,
    181     kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
    182   } Kind;
    183 
    184   enum DeoptMode {
    185     kNoLazyDeopt,
    186     kLazyDeopt
    187   };
    188 
    189   static const int kNoDeoptimizationIndex =
    190       (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
    191 
    192   void DefinePointerSlot(int index) { indexes_->push_back(index); }
    193   void DefinePointerRegister(Register reg);
    194 
    195  private:
    196   Safepoint(ZoneChunkList<int>* indexes, ZoneChunkList<int>* registers)
    197       : indexes_(indexes), registers_(registers) {}
    198   ZoneChunkList<int>* const indexes_;
    199   ZoneChunkList<int>* const registers_;
    200 
    201   friend class SafepointTableBuilder;
    202 };
    203 
    204 
    205 class SafepointTableBuilder BASE_EMBEDDED {
    206  public:
    207   explicit SafepointTableBuilder(Zone* zone)
    208       : deoptimization_info_(zone),
    209         emitted_(false),
    210         last_lazy_safepoint_(0),
    211         zone_(zone) {}
    212 
    213   // Get the offset of the emitted safepoint table in the code.
    214   unsigned GetCodeOffset() const;
    215 
    216   // Define a new safepoint for the current position in the body.
    217   Safepoint DefineSafepoint(Assembler* assembler,
    218                             Safepoint::Kind kind,
    219                             int arguments,
    220                             Safepoint::DeoptMode mode);
    221 
    222   // Record deoptimization index for lazy deoptimization for the last
    223   // outstanding safepoints.
    224   void RecordLazyDeoptimizationIndex(int index);
    225   void BumpLastLazySafepointIndex() {
    226     last_lazy_safepoint_ = deoptimization_info_.size();
    227   }
    228 
    229   // Emit the safepoint table after the body. The number of bits per
    230   // entry must be enough to hold all the pointer indexes.
    231   void Emit(Assembler* assembler, int bits_per_entry);
    232 
    233   // Find the Deoptimization Info with pc offset {pc} and update its
    234   // trampoline field. Calling this function ensures that the safepoint
    235   // table contains the trampoline PC (trampoline} that replaced the
    236   // return PC {pc} on the stack.
    237   int UpdateDeoptimizationInfo(int pc, int trampoline, int start);
    238 
    239  private:
    240   struct DeoptimizationInfo {
    241     unsigned pc;
    242     unsigned arguments;
    243     bool has_doubles;
    244     int trampoline;
    245     ZoneChunkList<int>* indexes;
    246     ZoneChunkList<int>* registers;
    247     unsigned deopt_index;
    248     DeoptimizationInfo(Zone* zone, unsigned pc, unsigned arguments,
    249                        Safepoint::Kind kind)
    250         : pc(pc),
    251           arguments(arguments),
    252           has_doubles(kind & Safepoint::kWithDoubles),
    253           trampoline(-1),
    254           indexes(new (zone) ZoneChunkList<int>(
    255               zone, ZoneChunkList<int>::StartMode::kSmall)),
    256           registers(kind & Safepoint::kWithRegisters
    257                         ? new (zone) ZoneChunkList<int>(
    258                               zone, ZoneChunkList<int>::StartMode::kSmall)
    259                         : nullptr),
    260           deopt_index(Safepoint::kNoDeoptimizationIndex) {}
    261   };
    262 
    263   uint32_t EncodeExceptPC(const DeoptimizationInfo&);
    264 
    265   bool IsIdenticalExceptForPc(const DeoptimizationInfo&,
    266                               const DeoptimizationInfo&) const;
    267   // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
    268   void RemoveDuplicates();
    269 
    270   ZoneChunkList<DeoptimizationInfo> deoptimization_info_;
    271 
    272   unsigned offset_;
    273   bool emitted_;
    274   size_t last_lazy_safepoint_;
    275 
    276   Zone* zone_;
    277 
    278   DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
    279 };
    280 
    281 }  // namespace internal
    282 }  // namespace v8
    283 
    284 #endif  // V8_SAFEPOINT_TABLE_H_
    285