safepoint-table.h 8.27 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_SAFEPOINT_TABLE_H_
#define V8_SAFEPOINT_TABLE_H_

8
#include "src/allocation.h"
9 10
#include "src/assert-scope.h"
#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 16 17

namespace v8 {
namespace internal {

18
class Register;
19 20

class SafepointEntry BASE_EMBEDDED {
21
 public:
22
  SafepointEntry() : info_(0), bits_(nullptr), trampoline_pc_(-1) {}
23

24 25
  SafepointEntry(unsigned info, uint8_t* bits, int trampoline_pc)
      : info_(info), bits_(bits), trampoline_pc_(trampoline_pc) {
26
    DCHECK(is_valid());
27
  }
28

29
  bool is_valid() const { return bits_ != nullptr; }
30 31 32

  bool Equals(const SafepointEntry& other) const {
    return info_ == other.info_ && bits_ == other.bits_;
33 34
  }

35 36
  void Reset() {
    info_ = 0;
37
    bits_ = nullptr;
38 39
  }

40
  int deoptimization_index() const {
41
    DCHECK(is_valid());
42
    return DeoptimizationIndexField::decode(info_);
43 44
  }

45 46 47 48
  int trampoline_pc() { return trampoline_pc_; }

  void set_trampoline_pc(int trampoline_pc) { trampoline_pc_ = trampoline_pc; }

49 50 51 52
  static const int kArgumentsFieldBits = 3;
  static const int kSaveDoublesFieldBits = 1;
  static const int kDeoptIndexBits =
      32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
53

54 55 56 57 58 59 60 61 62 63
  class DeoptimizationIndexField:
    public BitField<int, 0, kDeoptIndexBits> {};  // NOLINT
  class ArgumentsField:
    public BitField<unsigned,
                    kDeoptIndexBits,
                    kArgumentsFieldBits> {};  // NOLINT
  class SaveDoublesField:
    public BitField<bool,
                    kDeoptIndexBits + kArgumentsFieldBits,
                    kSaveDoublesFieldBits> { }; // NOLINT
64

65
  int argument_count() const {
66
    DCHECK(is_valid());
67 68 69
    return ArgumentsField::decode(info_);
  }

70
  bool has_doubles() const {
71
    DCHECK(is_valid());
72 73 74
    return SaveDoublesField::decode(info_);
  }

75
  uint8_t* bits() {
76
    DCHECK(is_valid());
77 78 79 80 81 82 83 84 85
    return bits_;
  }

  bool HasRegisters() const;
  bool HasRegisterAt(int reg_index) const;

 private:
  unsigned info_;
  uint8_t* bits_;
86 87
  // It needs to be an integer as it is -1 for eager deoptimizations.
  int trampoline_pc_;
88 89 90 91 92 93
};


class SafepointTable BASE_EMBEDDED {
 public:
  explicit SafepointTable(Code* code);
94 95 96
  explicit SafepointTable(Address instruction_start,
                          size_t safepoint_table_offset, uint32_t stack_slots,
                          bool has_deopt = false);
97

98
  int size() const {
99
    return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_));
100
  }
101 102 103 104
  unsigned length() const { return length_; }
  unsigned entry_size() const { return entry_size_; }

  unsigned GetPcOffset(unsigned index) const {
105
    DCHECK(index < length_);
106 107 108
    return Memory::uint32_at(GetPcOffsetLocation(index));
  }

109
  int GetTrampolinePcOffset(unsigned index) const {
110 111 112 113
    DCHECK(index < length_);
    return Memory::int_at(GetTrampolineLocation(index));
  }

114 115
  unsigned find_return_pc(unsigned pc_offset);

116
  SafepointEntry GetEntry(unsigned index) const {
117
    DCHECK(index < length_);
118 119
    unsigned info = Memory::uint32_at(GetInfoLocation(index));
    uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
120 121
    int trampoline_pc =
        has_deopt_ ? Memory::int_at(GetTrampolineLocation(index)) : -1;
122
    return SafepointEntry(info, bits, trampoline_pc);
123 124 125 126
  }

  // Returns the entry for the given pc.
  SafepointEntry FindEntry(Address pc) const;
127

128
  void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
129 130 131 132

 private:
  static const uint8_t kNoRegisters = 0xFF;

133
  // Layout information
134 135 136
  static const int kLengthOffset = 0;
  static const int kEntrySizeOffset = kLengthOffset + kIntSize;
  static const int kHeaderSize = kEntrySizeOffset + kIntSize;
137 138 139 140
  static const int kPcOffset = 0;
  static const int kDeoptimizationIndexOffset = kPcOffset + kIntSize;
  static const int kTrampolinePcOffset = kDeoptimizationIndexOffset + kIntSize;
  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 149 150 151 152
    return GetPcOffsetLocation(index) + kDeoptimizationIndexOffset;
  }

  Address GetTrampolineLocation(unsigned index) const {
    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 160
  Address instruction_start_;
  uint32_t stack_slots_;
161 162 163 164 165
  unsigned length_;
  unsigned entry_size_;

  Address pc_and_deoptimization_indexes_;
  Address entries_;
166
  bool has_deopt_;
167 168

  friend class SafepointTableBuilder;
169 170 171
  friend class SafepointEntry;

  DISALLOW_COPY_AND_ASSIGN(SafepointTable);
172 173 174 175 176
};


class Safepoint BASE_EMBEDDED {
 public:
177 178 179 180 181 182 183
  typedef enum {
    kSimple = 0,
    kWithRegisters = 1 << 0,
    kWithDoubles = 1 << 1,
    kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
  } Kind;

184 185 186 187 188
  enum DeoptMode {
    kNoLazyDeopt,
    kLazyDeopt
  };

189
  static const int kNoDeoptimizationIndex =
190
      (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
191

192 193
  void DefinePointerSlot(int index) { indexes_->push_back(index); }
  void DefinePointerRegister(Register reg);
194 195

 private:
196
  Safepoint(ZoneChunkList<int>* indexes, ZoneChunkList<int>* registers)
197
      : indexes_(indexes), registers_(registers) {}
198 199
  ZoneChunkList<int>* const indexes_;
  ZoneChunkList<int>* const registers_;
200 201 202 203 204 205 206

  friend class SafepointTableBuilder;
};


class SafepointTableBuilder BASE_EMBEDDED {
 public:
207 208
  explicit SafepointTableBuilder(Zone* zone)
      : deoptimization_info_(32, zone),
209
        emitted_(false),
210 211
        last_lazy_safepoint_(0),
        zone_(zone) { }
212 213 214 215 216

  // Get the offset of the emitted safepoint table in the code.
  unsigned GetCodeOffset() const;

  // Define a new safepoint for the current position in the body.
217 218 219
  Safepoint DefineSafepoint(Assembler* assembler,
                            Safepoint::Kind kind,
                            int arguments,
220
                            Safepoint::DeoptMode mode);
221

222 223 224
  // Record deoptimization index for lazy deoptimization for the last
  // outstanding safepoints.
  void RecordLazyDeoptimizationIndex(int index);
225
  void BumpLastLazySafepointIndex() {
226
    last_lazy_safepoint_ = deoptimization_info_.length();
227
  }
lrn@chromium.org's avatar
lrn@chromium.org committed
228

229 230 231 232
  // Emit the safepoint table after the body. The number of bits per
  // entry must be enough to hold all the pointer indexes.
  void Emit(Assembler* assembler, int bits_per_entry);

233 234 235 236
  // Find the Deoptimization Info with pc offset {pc} and update its
  // trampoline field. Calling this function ensures that the safepoint
  // table contains the trampoline PC (trampoline} that replaced the
  // return PC {pc} on the stack.
237
  int UpdateDeoptimizationInfo(int pc, int trampoline, int start);
238

239 240 241
 private:
  struct DeoptimizationInfo {
    unsigned pc;
242
    unsigned arguments;
243
    bool has_doubles;
244
    int trampoline;
245 246
    ZoneChunkList<int>* indexes;
    ZoneChunkList<int>* registers;
247 248 249 250 251 252 253
    unsigned deopt_index;
    DeoptimizationInfo(Zone* zone, unsigned pc, unsigned arguments,
                       Safepoint::Kind kind)
        : pc(pc),
          arguments(arguments),
          has_doubles(kind & Safepoint::kWithDoubles),
          trampoline(-1),
254 255
          indexes(new (zone) ZoneChunkList<int>(
              zone, ZoneChunkList<int>::StartMode::kSmall)),
256
          registers(kind & Safepoint::kWithRegisters
257 258
                        ? new (zone) ZoneChunkList<int>(
                              zone, ZoneChunkList<int>::StartMode::kSmall)
259 260
                        : nullptr),
          deopt_index(Safepoint::kNoDeoptimizationIndex) {}
261 262
  };

263
  uint32_t EncodeExceptPC(const DeoptimizationInfo&);
264

265 266
  bool IsIdenticalExceptForPc(const DeoptimizationInfo&,
                              const DeoptimizationInfo&) const;
267 268 269
  // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
  void RemoveDuplicates();

270 271 272
  ZoneList<DeoptimizationInfo> deoptimization_info_;

  unsigned offset_;
273
  bool emitted_;
274
  int last_lazy_safepoint_;
275

276 277
  Zone* zone_;

278 279 280
  DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
};

281 282
}  // namespace internal
}  // namespace v8
283 284

#endif  // V8_SAFEPOINT_TABLE_H_