safepoint-table.h 6.41 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
#ifndef V8_CODEGEN_SAFEPOINT_TABLE_H_
#define V8_CODEGEN_SAFEPOINT_TABLE_H_
7

8
#include "src/base/memory.h"
9
#include "src/common/assert-scope.h"
10 11
#include "src/utils/allocation.h"
#include "src/utils/utils.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 SafepointEntry {
19
 public:
20
  SafepointEntry() : deopt_index_(0), bits_(nullptr), trampoline_pc_(-1) {}
21

22 23
  SafepointEntry(unsigned deopt_index, uint8_t* bits, int trampoline_pc)
      : deopt_index_(deopt_index), bits_(bits), trampoline_pc_(trampoline_pc) {
24
    DCHECK(is_valid());
25
  }
26

27
  bool is_valid() const { return bits_ != nullptr; }
28 29

  bool Equals(const SafepointEntry& other) const {
30
    return deopt_index_ == other.deopt_index_ && bits_ == other.bits_;
31 32
  }

33
  void Reset() {
34
    deopt_index_ = 0;
35
    bits_ = nullptr;
36 37
  }

38 39
  int trampoline_pc() { return trampoline_pc_; }

40
  static const unsigned kNoDeoptIndex = kMaxUInt32;
41 42 43

  int deoptimization_index() const {
    DCHECK(is_valid() && has_deoptimization_index());
44
    return deopt_index_;
45 46 47 48
  }

  bool has_deoptimization_index() const {
    DCHECK(is_valid());
49
    return deopt_index_ != kNoDeoptIndex;
50 51
  }

52
  uint8_t* bits() {
53
    DCHECK(is_valid());
54 55 56 57
    return bits_;
  }

 private:
58
  unsigned deopt_index_;
59
  uint8_t* bits_;
60 61
  // It needs to be an integer as it is -1 for eager deoptimizations.
  int trampoline_pc_;
62 63
};

64
class SafepointTable {
65
 public:
66
  explicit SafepointTable(Code code);
67 68 69
  explicit SafepointTable(Address instruction_start,
                          size_t safepoint_table_offset, uint32_t stack_slots,
                          bool has_deopt = false);
70

71
  int size() const {
72
    return kHeaderSize + (length_ * (kFixedEntrySize + entry_size_));
73
  }
74 75 76 77
  unsigned length() const { return length_; }
  unsigned entry_size() const { return entry_size_; }

  unsigned GetPcOffset(unsigned index) const {
78
    DCHECK(index < length_);
79
    return base::Memory<uint32_t>(GetPcOffsetLocation(index));
80 81
  }

82
  int GetTrampolinePcOffset(unsigned index) const {
83
    DCHECK(index < length_);
84
    return base::Memory<int>(GetTrampolineLocation(index));
85 86
  }

87 88
  unsigned find_return_pc(unsigned pc_offset);

89
  SafepointEntry GetEntry(unsigned index) const {
90
    DCHECK(index < length_);
91 92 93
    unsigned deopt_index =
        base::Memory<uint32_t>(GetEncodedInfoLocation(index));
    uint8_t* bits = &base::Memory<uint8_t>(entries_ + (index * entry_size_));
94
    int trampoline_pc =
95
        has_deopt_ ? base::Memory<int>(GetTrampolineLocation(index)) : -1;
96
    return SafepointEntry(deopt_index, bits, trampoline_pc);
97 98 99 100
  }

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

102
  void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
103 104 105 106

 private:
  static const uint8_t kNoRegisters = 0xFF;

107
  // Layout information
108 109 110
  static const int kLengthOffset = 0;
  static const int kEntrySizeOffset = kLengthOffset + kIntSize;
  static const int kHeaderSize = kEntrySizeOffset + kIntSize;
111
  static const int kPcOffset = 0;
112 113
  static const int kEncodedInfoOffset = kPcOffset + kIntSize;
  static const int kTrampolinePcOffset = kEncodedInfoOffset + kIntSize;
114
  static const int kFixedEntrySize = kTrampolinePcOffset + kIntSize;
115 116

  Address GetPcOffsetLocation(unsigned index) const {
117
    return pc_and_deoptimization_indexes_ + (index * kFixedEntrySize);
118 119
  }

120 121
  Address GetEncodedInfoLocation(unsigned index) const {
    return GetPcOffsetLocation(index) + kEncodedInfoOffset;
122 123 124 125
  }

  Address GetTrampolineLocation(unsigned index) const {
    return GetPcOffsetLocation(index) + kTrampolinePcOffset;
126 127
  }

128
  static void PrintBits(std::ostream& os,  // NOLINT
129
                        uint8_t byte, int digits);
130

131
  DISALLOW_HEAP_ALLOCATION(no_allocation_)
132 133
  Address instruction_start_;
  uint32_t stack_slots_;
134 135 136 137 138
  unsigned length_;
  unsigned entry_size_;

  Address pc_and_deoptimization_indexes_;
  Address entries_;
139
  bool has_deopt_;
140 141

  friend class SafepointTableBuilder;
142 143 144
  friend class SafepointEntry;

  DISALLOW_COPY_AND_ASSIGN(SafepointTable);
145 146
};

147
class Safepoint {
148
 public:
149
  enum DeoptMode { kNoLazyDeopt, kLazyDeopt };
150

151
  static const int kNoDeoptimizationIndex = SafepointEntry::kNoDeoptIndex;
152

153
  void DefinePointerSlot(int index) { indexes_->push_back(index); }
154 155

 private:
156
  explicit Safepoint(ZoneChunkList<int>* indexes) : indexes_(indexes) {}
157
  ZoneChunkList<int>* const indexes_;
158 159 160 161

  friend class SafepointTableBuilder;
};

162
class SafepointTableBuilder {
163
 public:
164
  explicit SafepointTableBuilder(Zone* zone)
165
      : deoptimization_info_(zone),
166
        emitted_(false),
167
        zone_(zone) {}
168 169 170 171 172

  // 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.
173
  Safepoint DefineSafepoint(Assembler* assembler, Safepoint::DeoptMode mode);
174 175 176

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

179 180
  // Find the Deoptimization Info with pc offset {pc} and update its
  // trampoline field. Calling this function ensures that the safepoint
181
  // table contains the trampoline PC {trampoline} that replaced the
182
  // return PC {pc} on the stack.
183 184
  int UpdateDeoptimizationInfo(int pc, int trampoline, int start,
                               unsigned deopt_index);
185

186 187 188
 private:
  struct DeoptimizationInfo {
    unsigned pc;
189
    unsigned deopt_index;
190
    int trampoline;
191
    ZoneChunkList<int>* indexes;
192
    DeoptimizationInfo(Zone* zone, unsigned pc)
193
        : pc(pc),
194
          deopt_index(Safepoint::kNoDeoptimizationIndex),
195
          trampoline(-1),
196
          indexes(new (zone) ZoneChunkList<int>(
197
              zone, ZoneChunkList<int>::StartMode::kSmall)) {}
198 199
  };

200
  // Compares all fields of a {DeoptimizationInfo} except {pc} and {trampoline}.
201 202
  bool IsIdenticalExceptForPc(const DeoptimizationInfo&,
                              const DeoptimizationInfo&) const;
203

204 205 206
  // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
  void RemoveDuplicates();

207
  ZoneChunkList<DeoptimizationInfo> deoptimization_info_;
208 209

  unsigned offset_;
210
  bool emitted_;
211

212 213
  Zone* zone_;

214 215 216
  DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
};

217 218
}  // namespace internal
}  // namespace v8
219

220
#endif  // V8_CODEGEN_SAFEPOINT_TABLE_H_