Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(559)

Side by Side Diff: src/compiler/bytecode-analysis.cc

Issue 2523893003: Reland of [ignition/turbo] Perform liveness analysis on the bytecodes (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/bytecode-analysis.h" 5 #include "src/compiler/bytecode-analysis.h"
6 6
7 #include "src/interpreter/bytecode-array-reverse-iterator.h" 7 #include "src/interpreter/bytecode-array-reverse-iterator.h"
8 #include "src/objects-inl.h" 8 #include "src/objects-inl.h"
9 9
10 namespace v8 { 10 namespace v8 {
11 namespace internal { 11 namespace internal {
12 namespace compiler { 12 namespace compiler {
13 13
14 using namespace interpreter;
15
14 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, 16 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
15 Zone* zone) 17 Zone* zone)
16 : bytecode_array_(bytecode_array), 18 : bytecode_array_(bytecode_array),
17 zone_(zone), 19 zone_(zone),
18 loop_stack_(zone), 20 loop_stack_(zone),
19 end_to_header_(zone), 21 end_to_header_(zone),
20 header_to_parent_(zone) {} 22 header_to_parent_(zone),
23 liveness_(
24 base::bits::RoundUpToPowerOfTwo32(bytecode_array->length() / 4 + 1),
25 base::KeyEqualityMatcher<int>(), ZoneAllocationPolicy(zone)) {}
26
27 namespace {
28
29 uint32_t OffsetHash(int offset) { return offset; }
30
31 const BitVector* GetInLiveness(
32 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) {
33 return liveness_map.Lookup(offset, OffsetHash(offset))->value.in;
34 }
35
36 const BitVector* GetOutLiveness(
37 int offset, const BytecodeAnalysis::LivenessMap& liveness_map) {
38 return liveness_map.Lookup(offset, OffsetHash(offset))->value.out;
39 }
40
41 template <int index, OperandType... operandTypes>
42 struct LivenessHelper;
43
44 template <int index, OperandType otherOperandType, OperandType... operandTypes>
45 struct LivenessHelper<index, otherOperandType, operandTypes...> {
46 static void AddReads(BitVector& liveness,
47 const BytecodeArrayAccessor& accessor) {
48 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
49 }
50 static void KillWrites(BitVector& liveness,
51 const BytecodeArrayAccessor& accessor) {
52 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
53 }
54 };
55
56 template <int index>
57 struct LivenessHelper<index> {
58 static void AddReads(BitVector& liveness,
59 const BytecodeArrayAccessor& accessor) {}
60 static void KillWrites(BitVector& liveness,
61 const BytecodeArrayAccessor& accessor) {}
62 };
63
64 template <int index, OperandType... operandTypes>
65 struct LivenessHelper<index, OperandType::kReg, operandTypes...> {
66 static void AddReads(BitVector& liveness,
67 const BytecodeArrayAccessor& accessor) {
68 interpreter::Register r = accessor.GetRegisterOperand(index);
69 if (!r.is_parameter()) {
70 liveness.Add(r.index());
71 }
72
73 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
74 }
75 static void KillWrites(BitVector& liveness,
76 const BytecodeArrayAccessor& accessor) {
77 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
78 }
79 };
80
81 template <int index, OperandType... operandTypes>
82 struct LivenessHelper<index, OperandType::kRegList, OperandType::kRegCount,
83 operandTypes...> {
84 static void AddReads(BitVector& liveness,
85 const BytecodeArrayAccessor& accessor) {
86 interpreter::Register r = accessor.GetRegisterOperand(index);
87 if (!r.is_parameter()) {
88 int count = accessor.GetRegisterCountOperand(index + 1);
89 for (int i = 0; i < count; ++i) {
90 liveness.Add(r.index() + i);
91 }
92 }
93
94 LivenessHelper<index + 2, operandTypes...>::AddReads(liveness, accessor);
95 }
96 static void KillWrites(BitVector& liveness,
97 const BytecodeArrayAccessor& accessor) {
98 LivenessHelper<index + 2, operandTypes...>::KillWrites(liveness, accessor);
99 }
100 };
101
102 template <int index, OperandType otherOperandType, OperandType... operandTypes>
103 struct LivenessHelper<index, OperandType::kRegList, otherOperandType,
104 operandTypes...> {};
105
106 template <int index, OperandType... operandTypes>
107 struct LivenessHelper<index, OperandType::kRegPair, operandTypes...> {
108 static void AddReads(BitVector& liveness,
109 const BytecodeArrayAccessor& accessor) {
110 interpreter::Register r = accessor.GetRegisterOperand(index);
111 if (!r.is_parameter()) {
112 liveness.Add(r.index());
113 liveness.Add(r.index() + 1);
114 }
115
116 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
117 }
118 static void KillWrites(BitVector& liveness,
119 const BytecodeArrayAccessor& accessor) {
120 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
121 }
122 };
123
124 template <int index, OperandType... operandTypes>
125 struct LivenessHelper<index, OperandType::kRegOut, operandTypes...> {
126 static void AddReads(BitVector& liveness,
127 const BytecodeArrayAccessor& accessor) {
128 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
129 }
130 static void KillWrites(BitVector& liveness,
131 const BytecodeArrayAccessor& accessor) {
132 interpreter::Register r = accessor.GetRegisterOperand(index);
133 if (!r.is_parameter()) {
134 liveness.Remove(r.index());
135 }
136
137 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
138 }
139 };
140
141 template <int index, OperandType... operandTypes>
142 struct LivenessHelper<index, OperandType::kRegOutPair, operandTypes...> {
143 static void AddReads(BitVector& liveness,
144 const BytecodeArrayAccessor& accessor) {
145 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
146 }
147 static void KillWrites(BitVector& liveness,
148 const BytecodeArrayAccessor& accessor) {
149 interpreter::Register r = accessor.GetRegisterOperand(index);
150 if (!r.is_parameter()) {
151 liveness.Remove(r.index());
152 liveness.Remove(r.index() + 1);
153 }
154
155 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
156 }
157 };
158
159 template <int index, OperandType... operandTypes>
160 struct LivenessHelper<index, OperandType::kRegOutTriple, operandTypes...> {
161 static void AddReads(BitVector& liveness,
162 const BytecodeArrayAccessor& accessor) {
163 LivenessHelper<index + 1, operandTypes...>::AddReads(liveness, accessor);
164 }
165 static void KillWrites(BitVector& liveness,
166 const BytecodeArrayAccessor& accessor) {
167 interpreter::Register r = accessor.GetRegisterOperand(index);
168 if (!r.is_parameter()) {
169 liveness.Remove(r.index());
170 liveness.Remove(r.index() + 1);
171 liveness.Remove(r.index() + 2);
172 }
173
174 LivenessHelper<index + 1, operandTypes...>::KillWrites(liveness, accessor);
175 }
176 };
177
178 template <Bytecode bytecode, AccumulatorUse accumulatorUse,
179 OperandType... operandsTypes>
Jarin 2016/11/24 12:47:17 Oh, my eyes, my eyes! Does the heavy use of templ
Leszek Swirski 2016/11/25 17:31:27 Beauty is in the eye of the beholder ;) Unfortuna
180 void UpdateLiveness(BytecodeAnalysis::Liveness liveness,
181 const BytecodeArrayAccessor& accessor,
182 const BytecodeAnalysis::LivenessMap& liveness_map) {
183 int current_offset = accessor.current_offset();
184 const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array();
185
186 BitVector& in_liveness = *liveness.in;
187 BitVector& out_liveness = *liveness.out;
188
189 if (Bytecodes::IsJump(bytecode)) {
190 int target_offset = accessor.GetJumpTargetOffset();
191 out_liveness.Union(*GetInLiveness(target_offset, liveness_map));
192 }
193
194 if (!Bytecodes::IsJump(bytecode) || Bytecodes::IsConditionalJump(bytecode)) {
195 int next_offset = current_offset + accessor.current_bytecode_size();
196 if (next_offset < bytecode_array->length()) {
197 out_liveness.Union(*GetInLiveness(next_offset, liveness_map));
198 }
199 }
200
201 if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
202 int handler_context;
203 int handler_offset = bytecode_array->LookupRangeInHandlerTable(
204 current_offset, &handler_context, nullptr);
205
206 if (handler_offset != -1) {
207 out_liveness.Union(*GetInLiveness(handler_offset, liveness_map));
208 out_liveness.Add(handler_context);
209 }
210 }
211
212 in_liveness.CopyFrom(out_liveness);
213
214 if (accumulatorUse == AccumulatorUse::kWrite) {
215 in_liveness.Remove(in_liveness.length() - 1);
216 }
217 LivenessHelper<0, operandsTypes...>::KillWrites(in_liveness, accessor);
218
219 if (accumulatorUse == AccumulatorUse::kRead) {
220 in_liveness.Add(in_liveness.length() - 1);
221 }
222 LivenessHelper<0, operandsTypes...>::AddReads(in_liveness, accessor);
223 }
224 } // namespace
225
226 BytecodeAnalysis::Liveness::Liveness(int size, Zone* zone)
227 : in(new (zone) BitVector(size, zone)),
228 out(new (zone) BitVector(size, zone)) {}
21 229
22 void BytecodeAnalysis::Analyze() { 230 void BytecodeAnalysis::Analyze() {
23 loop_stack_.push(-1); 231 loop_stack_.push(-1);
24 232
25 interpreter::BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); 233 BytecodeArrayReverseIterator iterator(bytecode_array(), zone());
26 while (!iterator.done()) { 234 while (!iterator.done()) {
27 interpreter::Bytecode bytecode = iterator.current_bytecode(); 235 Bytecode bytecode = iterator.current_bytecode();
28 if (bytecode == interpreter::Bytecode::kJumpLoop) { 236 int current_offset = iterator.current_offset();
29 PushLoop(iterator.GetJumpTargetOffset(), iterator.current_offset()); 237
30 } else if (iterator.current_offset() == loop_stack_.top()) { 238 if (bytecode == Bytecode::kJumpLoop) {
239 PushLoop(iterator.GetJumpTargetOffset(), current_offset);
240 } else if (current_offset == loop_stack_.top()) {
31 loop_stack_.pop(); 241 loop_stack_.pop();
32 } 242 }
243
244 liveness_.LookupOrInsert(
245 current_offset, OffsetHash(current_offset),
246 [&]() {
247 return Liveness(bytecode_array()->register_count() + 1, zone());
248 },
249 ZoneAllocationPolicy(zone()));
250
33 iterator.Advance(); 251 iterator.Advance();
34 } 252 }
35 253
36 DCHECK_EQ(loop_stack_.size(), 1u); 254 DCHECK_EQ(loop_stack_.size(), 1u);
37 DCHECK_EQ(loop_stack_.top(), -1); 255 DCHECK_EQ(loop_stack_.top(), -1);
256
257 // Hoist previous_in_liveness out of the loop so that we don't trash the zone
258 // with allocations.
259 BitVector previous_in_liveness(bytecode_array()->register_count() + 1,
260 zone());
261
262 bool liveness_changed = true;
263 while (liveness_changed) {
264 liveness_changed = false;
265 iterator.Reset();
266 while (!iterator.done()) {
267 Liveness current_liveness =
268 liveness_
269 .Lookup(iterator.current_offset(),
270 OffsetHash(iterator.current_offset()))
271 ->value;
272 previous_in_liveness.CopyFrom(*current_liveness.in);
273
274 switch (iterator.current_bytecode()) {
275 #define CASE(NAME, ...) \
276 case Bytecode::k##NAME: { \
277 UpdateLiveness<Bytecode::k##NAME, __VA_ARGS__>(current_liveness, iterator, \
278 liveness_); \
279 break; \
280 }
281
282 BYTECODE_LIST(CASE)
283 #undef CASE
284 }
285
286 if (!liveness_changed &&
287 !current_liveness.in->Equals(previous_in_liveness)) {
288 liveness_changed = true;
289 }
290
291 iterator.Advance();
292 }
293 }
38 } 294 }
39 295
40 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { 296 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) {
41 DCHECK(loop_header < loop_end); 297 DCHECK(loop_header < loop_end);
42 DCHECK(loop_stack_.top() < loop_header); 298 DCHECK(loop_stack_.top() < loop_header);
43 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); 299 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end());
44 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); 300 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end());
45 301
46 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); 302 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header));
47 header_to_parent_.insert( 303 header_to_parent_.insert(
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 341
86 return header_to_parent_.upper_bound(offset)->second; 342 return header_to_parent_.upper_bound(offset)->second;
87 } 343 }
88 344
89 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { 345 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const {
90 DCHECK(IsLoopHeader(header_offset)); 346 DCHECK(IsLoopHeader(header_offset));
91 347
92 return header_to_parent_.find(header_offset)->second; 348 return header_to_parent_.find(header_offset)->second;
93 } 349 }
94 350
351 const BitVector* BytecodeAnalysis::GetInLivenessFor(int offset) const {
352 return GetInLiveness(offset, liveness_);
353 }
354
355 const BitVector* BytecodeAnalysis::GetOutLivenessFor(int offset) const {
356 return GetOutLiveness(offset, liveness_);
357 }
358
95 } // namespace compiler 359 } // namespace compiler
96 } // namespace internal 360 } // namespace internal
97 } // namespace v8 361 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698