safepoint-table.h 6.28 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.h"
13 14 15 16

namespace v8 {
namespace internal {

17 18 19
struct Register;

class SafepointEntry BASE_EMBEDDED {
20
 public:
21
  SafepointEntry() : info_(0), bits_(NULL) {}
22

23
  SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) {
24
    DCHECK(is_valid());
25
  }
26

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

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

33 34 35
  void Reset() {
    info_ = 0;
    bits_ = NULL;
36 37
  }

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

43 44 45 46 47 48 49 50 51 52 53 54 55 56
  static const int kArgumentsFieldBits = 3;
  static const int kSaveDoublesFieldBits = 1;
  static const int kDeoptIndexBits =
      32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
  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
57

58
  int argument_count() const {
59
    DCHECK(is_valid());
60 61 62
    return ArgumentsField::decode(info_);
  }

63
  bool has_doubles() const {
64
    DCHECK(is_valid());
65 66 67
    return SaveDoublesField::decode(info_);
  }

68
  uint8_t* bits() {
69
    DCHECK(is_valid());
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    return bits_;
  }

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

 private:
  unsigned info_;
  uint8_t* bits_;
};


class SafepointTable BASE_EMBEDDED {
 public:
  explicit SafepointTable(Code* code);
85

86 87
  int size() const {
    return kHeaderSize +
88
           (length_ * (kPcAndDeoptimizationIndexSize + entry_size_));
89
  }
90 91 92 93
  unsigned length() const { return length_; }
  unsigned entry_size() const { return entry_size_; }

  unsigned GetPcOffset(unsigned index) const {
94
    DCHECK(index < length_);
95 96 97 98
    return Memory::uint32_at(GetPcOffsetLocation(index));
  }

  SafepointEntry GetEntry(unsigned index) const {
99
    DCHECK(index < length_);
100 101
    unsigned info = Memory::uint32_at(GetInfoLocation(index));
    uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
102
    return SafepointEntry(info, bits);
103 104 105 106
  }

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

108
  void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
109 110 111 112 113 114 115 116 117 118

 private:
  static const uint8_t kNoRegisters = 0xFF;

  static const int kLengthOffset = 0;
  static const int kEntrySizeOffset = kLengthOffset + kIntSize;
  static const int kHeaderSize = kEntrySizeOffset + kIntSize;

  static const int kPcSize = kIntSize;
  static const int kDeoptimizationIndexSize = kIntSize;
119 120
  static const int kPcAndDeoptimizationIndexSize =
      kPcSize + kDeoptimizationIndexSize;
121 122 123

  Address GetPcOffsetLocation(unsigned index) const {
    return pc_and_deoptimization_indexes_ +
124
           (index * kPcAndDeoptimizationIndexSize);
125 126
  }

127
  Address GetInfoLocation(unsigned index) const {
128 129 130
    return GetPcOffsetLocation(index) + kPcSize;
  }

131
  static void PrintBits(std::ostream& os,  // NOLINT
132
                        uint8_t byte, int digits);
133

134
  DisallowHeapAllocation no_allocation_;
135 136 137 138 139 140 141 142
  Code* code_;
  unsigned length_;
  unsigned entry_size_;

  Address pc_and_deoptimization_indexes_;
  Address entries_;

  friend class SafepointTableBuilder;
143 144 145
  friend class SafepointEntry;

  DISALLOW_COPY_AND_ASSIGN(SafepointTable);
146 147 148 149 150
};


class Safepoint BASE_EMBEDDED {
 public:
151 152 153 154 155 156 157
  typedef enum {
    kSimple = 0,
    kWithRegisters = 1 << 0,
    kWithDoubles = 1 << 1,
    kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
  } Kind;

158 159 160 161 162
  enum DeoptMode {
    kNoLazyDeopt,
    kLazyDeopt
  };

163
  static const int kNoDeoptimizationIndex =
164
      (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
165

166
  void DefinePointerSlot(int index, Zone* zone) { indexes_->Add(index, zone); }
167
  void DefinePointerRegister(Register reg, Zone* zone);
168 169

 private:
170 171
  Safepoint(ZoneList<int>* indexes, ZoneList<int>* registers)
      : indexes_(indexes), registers_(registers) {}
172 173 174 175 176 177 178 179 180
  ZoneList<int>* indexes_;
  ZoneList<int>* registers_;

  friend class SafepointTableBuilder;
};


class SafepointTableBuilder BASE_EMBEDDED {
 public:
181 182 183 184 185
  explicit SafepointTableBuilder(Zone* zone)
      : deoptimization_info_(32, zone),
        deopt_index_list_(32, zone),
        indexes_(32, zone),
        registers_(32, zone),
186
        emitted_(false),
187 188
        last_lazy_safepoint_(0),
        zone_(zone) { }
189 190 191 192 193

  // 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.
194 195 196
  Safepoint DefineSafepoint(Assembler* assembler,
                            Safepoint::Kind kind,
                            int arguments,
197
                            Safepoint::DeoptMode mode);
198

199 200 201
  // Record deoptimization index for lazy deoptimization for the last
  // outstanding safepoints.
  void RecordLazyDeoptimizationIndex(int index);
202 203 204
  void BumpLastLazySafepointIndex() {
    last_lazy_safepoint_ = deopt_index_list_.length();
  }
lrn@chromium.org's avatar
lrn@chromium.org committed
205

206 207 208 209
  // 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);

210

211 212 213
 private:
  struct DeoptimizationInfo {
    unsigned pc;
214
    unsigned arguments;
215
    bool has_doubles;
216 217
  };

218
  uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index);
219

220 221 222 223
  bool IsIdenticalExceptForPc(int index1, int index2) const;
  // If all entries are identical, replace them by 1 entry with pc = kMaxUInt32.
  void RemoveDuplicates();

224
  ZoneList<DeoptimizationInfo> deoptimization_info_;
225
  ZoneList<unsigned> deopt_index_list_;
226 227 228 229
  ZoneList<ZoneList<int>*> indexes_;
  ZoneList<ZoneList<int>*> registers_;

  unsigned offset_;
230
  bool emitted_;
231
  int last_lazy_safepoint_;
232

233 234
  Zone* zone_;

235 236 237
  DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
};

238 239
}  // namespace internal
}  // namespace v8
240 241

#endif  // V8_SAFEPOINT_TABLE_H_