1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
#define V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
#include <string>
#include "src/utils/bit-vector.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
class Zone;
namespace compiler {
class BytecodeLivenessState : public ZoneObject {
public:
class Iterator {
public:
int operator*() const {
// Subtract one to compensate for the accumulator at the start of the
// bit vector.
return *it_ - 1;
}
void operator++() { return ++it_; }
bool operator!=(const Iterator& other) const { return it_ != other.it_; }
private:
static constexpr struct StartTag {
} kStartTag = {};
static constexpr struct EndTag {
} kEndTag = {};
explicit Iterator(const BytecodeLivenessState& liveness, StartTag)
: it_(liveness.bit_vector_.begin()) {
// If we're not at the end, and the current value is the accumulator, skip
// over it.
if (it_ != liveness.bit_vector_.end() && *it_ == 0) {
++it_;
}
}
explicit Iterator(const BytecodeLivenessState& liveness, EndTag)
: it_(liveness.bit_vector_.end()) {}
BitVector::Iterator it_;
friend class BytecodeLivenessState;
};
BytecodeLivenessState(int register_count, Zone* zone)
: bit_vector_(register_count + 1, zone) {}
BytecodeLivenessState(const BytecodeLivenessState&) = delete;
BytecodeLivenessState& operator=(const BytecodeLivenessState&) = delete;
BytecodeLivenessState(const BytecodeLivenessState& other, Zone* zone)
: bit_vector_(other.bit_vector_, zone) {}
bool RegisterIsLive(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, bit_vector_.length() - 1);
return bit_vector_.Contains(index + 1);
}
bool AccumulatorIsLive() const { return bit_vector_.Contains(0); }
bool Equals(const BytecodeLivenessState& other) const {
return bit_vector_.Equals(other.bit_vector_);
}
void MarkRegisterLive(int index) {
DCHECK_GE(index, 0);
DCHECK_LT(index, bit_vector_.length() - 1);
bit_vector_.Add(index + 1);
}
void MarkRegisterDead(int index) {
DCHECK_GE(index, 0);
DCHECK_LT(index, bit_vector_.length() - 1);
bit_vector_.Remove(index + 1);
}
void MarkAccumulatorLive() { bit_vector_.Add(0); }
void MarkAccumulatorDead() { bit_vector_.Remove(0); }
void MarkAllLive() { bit_vector_.AddAll(); }
void Union(const BytecodeLivenessState& other) {
bit_vector_.Union(other.bit_vector_);
}
bool UnionIsChanged(const BytecodeLivenessState& other) {
return bit_vector_.UnionIsChanged(other.bit_vector_);
}
void CopyFrom(const BytecodeLivenessState& other) {
bit_vector_.CopyFrom(other.bit_vector_);
}
int register_count() const { return bit_vector_.length() - 1; }
// Number of live values, including the accumulator.
int live_value_count() const { return bit_vector_.Count(); }
Iterator begin() const { return Iterator(*this, Iterator::kStartTag); }
Iterator end() const { return Iterator(*this, Iterator::kEndTag); }
private:
BitVector bit_vector_;
};
struct BytecodeLiveness {
BytecodeLivenessState* in;
BytecodeLivenessState* out;
};
class V8_EXPORT_PRIVATE BytecodeLivenessMap {
public:
BytecodeLivenessMap(int bytecode_size, Zone* zone)
: liveness_(zone->NewArray<BytecodeLiveness>(bytecode_size))
#ifdef DEBUG
,
size_(bytecode_size)
#endif
{
}
BytecodeLiveness& InsertNewLiveness(int offset) {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
#ifdef DEBUG
// Null out the in/out liveness, so that later DCHECKs know whether these
// have been correctly initialised or not. That code does initialise them
// unconditionally though, so we can skip the nulling out in release.
liveness_[offset].in = nullptr;
liveness_[offset].out = nullptr;
#endif
return liveness_[offset];
}
BytecodeLiveness& GetLiveness(int offset) {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
return liveness_[offset];
}
const BytecodeLiveness& GetLiveness(int offset) const {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
return liveness_[offset];
}
BytecodeLivenessState* GetInLiveness(int offset) {
return GetLiveness(offset).in;
}
const BytecodeLivenessState* GetInLiveness(int offset) const {
return GetLiveness(offset).in;
}
BytecodeLivenessState* GetOutLiveness(int offset) {
return GetLiveness(offset).out;
}
const BytecodeLivenessState* GetOutLiveness(int offset) const {
return GetLiveness(offset).out;
}
private:
BytecodeLiveness* liveness_;
#ifdef DEBUG
size_t size_;
#endif
};
V8_EXPORT_PRIVATE std::string ToString(const BytecodeLivenessState& liveness);
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
|