OLD | NEW |
---|---|
1 // Copyright 2015 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/interpreter/bytecode-peephole-optimizer.h" | 5 #include "src/interpreter/bytecode-peephole-optimizer.h" |
6 | 6 |
7 #include "src/interpreter/constant-array-builder.h" | 7 #include "src/interpreter/constant-array-builder.h" |
8 #include "src/objects-inl.h" | 8 #include "src/objects-inl.h" |
9 #include "src/objects.h" | 9 #include "src/objects.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
(...skipping 10 matching lines...) Expand all Loading... | |
22 // override | 22 // override |
23 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( | 23 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( |
24 int fixed_register_count, int parameter_count, | 24 int fixed_register_count, int parameter_count, |
25 Handle<FixedArray> handler_table) { | 25 Handle<FixedArray> handler_table) { |
26 Flush(); | 26 Flush(); |
27 return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count, | 27 return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count, |
28 handler_table); | 28 handler_table); |
29 } | 29 } |
30 | 30 |
31 // override | 31 // override |
32 void BytecodePeepholeOptimizer::Write(BytecodeNode* node) { | |
33 node = OptimizeAndEmitLast(node); | |
34 if (node != nullptr) { | |
35 SetLast(node); | |
36 } | |
37 } | |
38 | |
39 // override | |
40 void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node, | |
41 BytecodeLabel* label) { | |
42 node = OptimizeAndEmitLast(node); | |
43 next_stage_->WriteJump(node, label); | |
44 } | |
45 | |
46 // override | |
47 void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) { | 32 void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) { |
48 Flush(); | 33 Flush(); |
49 next_stage_->BindLabel(label); | 34 next_stage_->BindLabel(label); |
50 } | 35 } |
51 | 36 |
52 // override | 37 // override |
53 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target, | 38 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target, |
54 BytecodeLabel* label) { | 39 BytecodeLabel* label) { |
55 // There is no need to flush here, it will have been flushed when |target| | 40 // There is no need to flush here, it will have been flushed when |
56 // was bound. | 41 // |target| was bound. |
57 next_stage_->BindLabel(target, label); | 42 next_stage_->BindLabel(target, label); |
58 } | 43 } |
59 | 44 |
45 // override | |
46 void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node, | |
47 BytecodeLabel* label) { | |
48 Optimize(node); | |
49 next_stage()->WriteJump(node, label); | |
50 } | |
51 | |
52 // override | |
53 void BytecodePeepholeOptimizer::Write(BytecodeNode* node) { Optimize(node); } | |
rmcilroy
2016/07/13 13:51:41
Could we give this a new name, since it does the o
oth
2016/07/15 13:09:40
Renamed ApplyPeepholeAction().
The answer to the
rmcilroy
2016/07/15 15:31:48
I see, right enough forgot about the label. Ok wor
| |
54 | |
60 void BytecodePeepholeOptimizer::Flush() { | 55 void BytecodePeepholeOptimizer::Flush() { |
61 // TODO(oth/rmcilroy): We could check CanElideLast() here to potentially | |
62 // eliminate last rather than writing it. | |
rmcilroy
2016/07/13 13:51:40
No longer relevent?
oth
2016/07/15 13:09:40
CanElideLast() is gone.
There's no information ab
rmcilroy
2016/07/15 15:31:48
Great, thanks!
| |
63 if (LastIsValid()) { | 56 if (LastIsValid()) { |
64 next_stage_->Write(&last_); | 57 next_stage_->Write(&last_); |
65 InvalidateLast(); | 58 InvalidateLast(); |
66 } | 59 } |
67 } | 60 } |
68 | 61 |
69 void BytecodePeepholeOptimizer::InvalidateLast() { | 62 void BytecodePeepholeOptimizer::InvalidateLast() { |
70 last_.set_bytecode(Bytecode::kIllegal); | 63 last_.set_bytecode(Bytecode::kIllegal); |
71 } | 64 } |
72 | 65 |
73 bool BytecodePeepholeOptimizer::LastIsValid() const { | 66 bool BytecodePeepholeOptimizer::LastIsValid() const { |
74 return last_.bytecode() != Bytecode::kIllegal; | 67 return last_.bytecode() != Bytecode::kIllegal; |
75 } | 68 } |
76 | 69 |
77 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { | 70 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { |
78 last_.Clone(node); | 71 last_.Clone(node); |
79 } | 72 } |
80 | 73 |
81 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand( | 74 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand( |
82 const BytecodeNode* const node, int index) const { | 75 const BytecodeNode* const node, int index) const { |
83 DCHECK_LE(index, node->operand_count()); | 76 DCHECK_LE(index, node->operand_count()); |
84 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx); | 77 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx); |
85 uint32_t index_operand = node->operand(0); | 78 uint32_t index_operand = node->operand(0); |
86 return constant_array_builder_->At(index_operand); | 79 return constant_array_builder_->At(index_operand); |
87 } | 80 } |
88 | 81 |
89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { | |
90 DCHECK(LastIsValid()); | |
91 return (last_.bytecode() == Bytecode::kTypeOf || | |
92 last_.bytecode() == Bytecode::kToName || | |
93 (last_.bytecode() == Bytecode::kLdaConstant && | |
94 GetConstantForIndexOperand(&last_, 0)->IsName())); | |
95 } | |
96 | |
97 void BytecodePeepholeOptimizer::TryToRemoveLastExpressionPosition( | |
98 const BytecodeNode* const current) { | |
99 if (current->source_info().is_valid() && | |
100 last_.source_info().is_expression() && | |
101 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { | |
102 // The last bytecode has been marked as expression. It has no | |
103 // external effects so can't throw and the current bytecode is a | |
104 // source position. Remove the expression position on the last | |
105 // bytecode to open up potential peephole optimizations and to | |
106 // save the memory and perf cost of storing the unneeded | |
107 // expression position. | |
108 last_.source_info().set_invalid(); | |
109 } | |
110 } | |
111 | |
112 bool BytecodePeepholeOptimizer::CanElideCurrent( | |
113 const BytecodeNode* const current) const { | |
114 if (Bytecodes::IsLdarOrStar(last_.bytecode()) && | |
115 Bytecodes::IsLdarOrStar(current->bytecode()) && | |
116 current->operand(0) == last_.operand(0)) { | |
117 // Ldar and Star make the accumulator and register hold equivalent | |
118 // values. Only the first bytecode is needed if there's a sequence | |
119 // of back-to-back Ldar and Star bytecodes with the same operand. | |
120 return true; | |
121 } else if (current->bytecode() == Bytecode::kToName && | |
122 LastBytecodePutsNameInAccumulator()) { | |
123 // If the previous bytecode ensured a name was in the accumulator, | |
124 // the type coercion ToName() can be elided. | |
125 return true; | |
126 } else { | |
127 // Additional candidates for eliding current: | |
128 // (i) current is Nop. | |
129 // (ii) ToNumber if the last puts a number in the accumulator. | |
130 return false; | |
131 } | |
132 } | |
133 | |
134 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( | 82 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( |
135 const BytecodeNode* const current) const { | 83 const BytecodeNode* const current) const { |
136 // | 84 // |
137 // The rules for allowing the elision of the last bytecode based | 85 // The rules for allowing the elision of the last bytecode based |
138 // on source position are: | 86 // on source position are: |
139 // | 87 // |
140 // C U R R E N T | 88 // C U R R E N T |
141 // +--------+--------+--------+ | 89 // +--------+--------+--------+ |
142 // | None | Expr | Stmt | | 90 // | None | Expr | Stmt | |
143 // L +--------+--------+--------+--------+ | 91 // L +--------+--------+--------+--------+ |
144 // | None | YES | YES | YES | | 92 // | None | YES | YES | YES | |
145 // A +--------+--------+--------+--------+ | 93 // A +--------+--------+--------+--------+ |
146 // | Expr | YES | MAYBE | MAYBE | | 94 // | Expr | YES | MAYBE | MAYBE | |
147 // S +--------+--------+--------+--------+ | 95 // S +--------+--------+--------+--------+ |
148 // | Stmt | YES | NO | NO | | 96 // | Stmt | YES | NO | NO | |
149 // T +--------+--------+--------+--------+ | 97 // T +--------+--------+--------+--------+ |
150 // | 98 // |
151 // The goal is not lose any statement positions and not lose useful | 99 // The goal is not lose any statement positions and not lose useful |
152 // expression positions. Whenever the last bytecode is elided it's | 100 // expression positions. Whenever the last bytecode is elided it's |
153 // source position information is applied to the current node | 101 // source position information is applied to the current node |
154 // updating it if necessary. | 102 // updating it if necessary. |
155 // | 103 // |
156 // The last bytecode can be elided for the MAYBE cases if the last | 104 // The last bytecode can be elided for the MAYBE cases if the last |
rmcilroy
2016/07/13 13:51:41
What do we do with the MAYBE cases now? AFAIKT we
oth
2016/07/15 13:09:40
Done. Hopefully clearer now. We've not treated MAY
rmcilroy
2016/07/15 15:31:48
SGTM, thanks.
| |
157 // bytecode is known not to throw. If it throws, the system would | 105 // bytecode is known not to throw. If it throws, the system would |
158 // not have correct stack trace information. The appropriate check | 106 // not have correct stack trace information. The appropriate check |
159 // for this would be Bytecodes::IsWithoutExternalSideEffects(), | 107 // for this would be Bytecodes::IsWithoutExternalSideEffects(). |
160 // which is checked in | |
161 // BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes() to | |
162 // keep the check here simple. | |
163 // | 108 // |
164 // In rare cases, bytecode generation produces consecutive bytecodes | 109 // In rare cases, bytecode generation produces consecutive bytecodes |
165 // with the same expression positions. In principle, the latter of | 110 // with the same expression positions. In principle, the latter of |
166 // these can be elided, but would make this function more expensive. | 111 // these can be elided, but would make this function more expensive. |
167 // | 112 // |
168 return (!last_.source_info().is_valid() || | 113 return (!last_.source_info().is_valid() || |
169 !current->source_info().is_valid()); | 114 !current->source_info().is_valid()); |
170 } | 115 } |
171 | 116 |
172 namespace { | 117 namespace { |
173 | 118 |
174 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last, | 119 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last, |
175 BytecodeNode* const current) { | 120 BytecodeNode* const current) { |
176 DCHECK_EQ(current->bytecode(), Bytecode::kStar); | 121 DCHECK_EQ(current->bytecode(), Bytecode::kStar); |
177 | 122 |
178 // | 123 // |
179 // An example transformation here would be: | 124 // An example transformation here would be: |
180 // | 125 // |
181 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R | 126 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R |
182 // Star R ====/ Ldar R | 127 // Star R ====/ Ldar R |
183 // | 128 // |
184 // which loads a global value into both a register and the | 129 // which loads a global value into both a register and the |
185 // accumulator. However, in the second form the Ldar can often be | 130 // accumulator. However, in the second form the Ldar can often be |
186 // peephole optimized away unlike the Star in the first form. | 131 // peephole optimized away unlike the Star in the first form. |
187 // | 132 // |
188 last->Transform(new_bytecode, current->operand(0)); | 133 last->Transform(new_bytecode, current->operand(0)); |
189 current->set_bytecode(Bytecode::kLdar, current->operand(0)); | 134 current->set_bytecode(Bytecode::kLdar, current->operand(0)); |
190 } | 135 } |
191 | 136 |
192 void TransformToBinaryOpWithSmiOnRhs(Bytecode new_bytecode, | 137 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, |
193 BytecodeNode* const last, | 138 BytecodeNode* const last, |
194 BytecodeNode* const current) { | 139 BytecodeNode* const current) { |
195 DCHECK(Bytecodes::IsLdaSmiOrLdaZero(last->bytecode())); | 140 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); |
196 uint32_t imm_operand = | 141 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0)); |
197 last->bytecode() == Bytecode::kLdaSmi ? last->operand(0) : 0; | |
198 current->set_bytecode(new_bytecode, imm_operand, current->operand(0)); | |
199 if (last->source_info().is_valid()) { | 142 if (last->source_info().is_valid()) { |
200 current->source_info().Clone(last->source_info()); | 143 current->source_info().Clone(last->source_info()); |
201 } | 144 } |
145 } | |
146 | |
147 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, | |
148 BytecodeNode* const last, | |
149 BytecodeNode* const current) { | |
150 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); | |
151 current->set_bytecode(new_bytecode, 0, current->operand(0)); | |
152 if (last->source_info().is_valid()) { | |
153 current->source_info().Clone(last->source_info()); | |
154 } | |
202 } | 155 } |
203 | 156 |
204 } // namespace | 157 } // namespace |
205 | 158 |
206 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( | 159 void BytecodePeepholeOptimizer::DefaultAction( |
207 BytecodeNode* const current) { | 160 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
208 if (current->bytecode() == Bytecode::kStar && | 161 DCHECK(LastIsValid()); |
209 !current->source_info().is_statement()) { | 162 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
210 // Note: If the Star is tagged with a statement position, we can't | |
211 // perform this transform as the store to the register will | |
212 // have the wrong ordering for stepping in the debugger. | |
213 switch (last_.bytecode()) { | |
214 case Bytecode::kLdaNamedProperty: | |
215 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); | |
216 return true; | |
217 case Bytecode::kLdaKeyedProperty: | |
218 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); | |
219 return true; | |
220 case Bytecode::kLdaGlobal: | |
221 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); | |
222 return true; | |
223 case Bytecode::kLdaContextSlot: | |
224 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); | |
225 return true; | |
226 case Bytecode::kLdaUndefined: | |
227 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); | |
228 return true; | |
229 default: | |
230 break; | |
231 } | |
232 } else if (Bytecodes::IsLdaSmiOrLdaZero(last_.bytecode()) && | |
233 (!last_.source_info().is_valid() || | |
234 !current->source_info().is_valid())) { | |
235 switch (current->bytecode()) { | |
236 case Bytecode::kAdd: | |
237 TransformToBinaryOpWithSmiOnRhs(Bytecode::kAddSmi, &last_, current); | |
238 InvalidateLast(); | |
239 return true; | |
240 case Bytecode::kSub: | |
241 TransformToBinaryOpWithSmiOnRhs(Bytecode::kSubSmi, &last_, current); | |
242 InvalidateLast(); | |
243 return true; | |
244 case Bytecode::kBitwiseOr: | |
245 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseOrSmi, &last_, | |
246 current); | |
247 InvalidateLast(); | |
248 return true; | |
249 case Bytecode::kBitwiseAnd: | |
250 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseAndSmi, &last_, | |
251 current); | |
252 InvalidateLast(); | |
253 return true; | |
254 case Bytecode::kShiftLeft: | |
255 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftLeftSmi, &last_, | |
256 current); | |
257 InvalidateLast(); | |
258 return true; | |
259 case Bytecode::kShiftRight: | |
260 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftRightSmi, &last_, | |
261 current); | |
262 InvalidateLast(); | |
263 return true; | |
264 default: | |
265 break; | |
266 } | |
267 } | |
268 | 163 |
269 return false; | 164 next_stage()->Write(last()); |
165 SetLast(node); | |
270 } | 166 } |
271 | 167 |
272 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( | 168 void BytecodePeepholeOptimizer::UpdateLastAction( |
273 BytecodeNode* const current) { | 169 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
274 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | 170 DCHECK(!LastIsValid()); |
275 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | 171 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
276 if (can_remove) { | 172 |
277 // Conditional jumps with boolean conditions are emiitted in | 173 SetLast(node); |
278 // ToBoolean form by the bytecode array builder, | |
279 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean | |
280 // element can be removed if the previous bytecode put a boolean | |
281 // value in the accumulator. | |
282 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode()); | |
283 current->set_bytecode(jump, current->operand(0)); | |
284 } | |
285 return can_remove; | |
286 } | 174 } |
287 | 175 |
288 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot( | 176 void BytecodePeepholeOptimizer::ElideCurrentAction( |
289 BytecodeNode* const current) { | 177 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
290 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot && | 178 DCHECK(LastIsValid()); |
291 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | 179 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
292 if (can_remove) { | |
293 // Logical-nots are emitted in ToBoolean form by the bytecode array | |
294 // builder, The ToBoolean element can be removed if the previous bytecode | |
295 // put a boolean value in the accumulator. | |
296 current->set_bytecode(Bytecode::kLogicalNot); | |
297 } | |
298 return can_remove; | |
299 } | |
300 | 180 |
301 bool BytecodePeepholeOptimizer::TransformCurrentBytecode( | 181 if (node->source_info().is_valid()) { |
302 BytecodeNode* const current) { | 182 // Preserve the source information by replacing the node bytecode |
303 return RemoveToBooleanFromJump(current) || | 183 // with a no op bytecode. |
304 RemoveToBooleanFromLogicalNot(current); | 184 node->set_bytecode(Bytecode::kNop); |
305 } | 185 DefaultAction(node); |
306 | |
307 bool BytecodePeepholeOptimizer::CanElideLast( | |
308 const BytecodeNode* const current) const { | |
309 if (last_.bytecode() == Bytecode::kNop) { | |
310 // Nop are placeholders for holding source position information. | |
311 return true; | |
312 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && | |
313 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | |
314 // The accumulator is invisible to the debugger. If there is a sequence of | |
315 // consecutive accumulator loads (that don't have side effects) then only | |
316 // the final load is potentially visible. | |
317 return true; | |
318 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) == | |
319 AccumulatorUse::kWrite && | |
320 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | |
321 // The current instruction clobbers the accumulator without reading it. The | |
322 // load in the last instruction can be elided as it has no effect. | |
323 return true; | |
324 } else { | 186 } else { |
325 return false; | 187 // Nothing to do, keep last and wait for next bytecode to pair with it. |
326 } | 188 } |
327 } | 189 } |
328 | 190 |
329 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { | 191 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( |
330 TryToRemoveLastExpressionPosition(current); | 192 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
331 if (TransformCurrentBytecode(current) || | 193 DCHECK(LastIsValid()); |
332 TransformLastAndCurrentBytecodes(current)) { | 194 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
333 return current; | 195 |
196 if (last()->operand(0) == node->operand(0)) { | |
197 ElideCurrentAction(node); | |
198 } else { | |
199 DefaultAction(node); | |
334 } | 200 } |
335 | |
336 if (CanElideCurrent(current)) { | |
337 if (current->source_info().is_valid()) { | |
338 // Preserve the source information by replacing the current bytecode | |
339 // with a no op bytecode. | |
340 current->set_bytecode(Bytecode::kNop); | |
341 } else { | |
342 current = nullptr; | |
343 } | |
344 return current; | |
345 } | |
346 | |
347 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) { | |
348 if (last_.source_info().is_valid()) { | |
349 // Current can not be valid per CanElideLastBasedOnSourcePosition(). | |
350 current->source_info().Clone(last_.source_info()); | |
351 } | |
352 InvalidateLast(); | |
353 return current; | |
354 } | |
355 | |
356 return current; | |
357 } | 201 } |
358 | 202 |
359 BytecodeNode* BytecodePeepholeOptimizer::OptimizeAndEmitLast( | 203 void BytecodePeepholeOptimizer::ElideCurrentIfLoadingNameConstantAction( |
360 BytecodeNode* current) { | 204 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
361 // Attempt optimization if there is an earlier node to optimize with. | 205 DCHECK_EQ(last()->bytecode(), Bytecode::kLdaConstant); |
362 if (LastIsValid()) { | 206 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
363 current = Optimize(current); | 207 |
364 // Only output the last node if it wasn't invalidated by the optimization. | 208 if (GetConstantForIndexOperand(last(), 0)->IsName()) { |
365 if (LastIsValid()) { | 209 ElideCurrentAction(node); |
366 next_stage_->Write(&last_); | 210 } else { |
367 InvalidateLast(); | 211 DefaultAction(node); |
212 } | |
213 } | |
214 | |
215 void BytecodePeepholeOptimizer::ElideLastAction( | |
216 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
217 DCHECK(LastIsValid()); | |
218 DCHECK(!Bytecodes::IsJump(node->bytecode())); | |
219 | |
220 if (CanElideLastBasedOnSourcePosition(node)) { | |
221 if (last()->source_info().is_valid()) { | |
222 // Node can not be valid per CanElideLastBasedOnSourcePosition(). | |
rmcilroy
2016/07/13 13:51:41
Can we DCHECK this?
oth
2016/07/15 13:09:40
Hey! The code has just called CanElideLastBasedOnS
rmcilroy
2016/07/15 15:31:48
Right, sorry I was confused since the comment soun
oth
2016/07/15 17:27:25
Definitely. Updated the comment.
| |
223 node->source_info().Clone(last()->source_info()); | |
368 } | 224 } |
225 SetLast(node); | |
226 } else { | |
227 DefaultAction(node); | |
369 } | 228 } |
370 return current; | 229 } |
230 | |
231 void BytecodePeepholeOptimizer::ChangeBytecodeAction( | |
232 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
233 DCHECK(LastIsValid()); | |
234 DCHECK(!Bytecodes::IsJump(node->bytecode())); | |
235 | |
236 node->set_bytecode(action_data->bytecode); | |
237 DefaultAction(node); | |
238 } | |
239 | |
240 void BytecodePeepholeOptimizer::TransformLdaStarToLdrLdarAction( | |
241 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
242 DCHECK(LastIsValid()); | |
243 DCHECK(!Bytecodes::IsJump(node->bytecode())); | |
244 | |
245 if (!node->source_info().is_statement()) { | |
246 TransformLdaStarToLdrLdar(action_data->bytecode, last(), node); | |
247 } | |
248 DefaultAction(node); | |
249 } | |
250 | |
251 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction( | |
252 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
253 DCHECK(LastIsValid()); | |
254 DCHECK(!Bytecodes::IsJump(node->bytecode())); | |
255 | |
256 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | |
257 // Fused last and current into current. | |
258 TransformLdaSmiBinaryOpToBinaryOpWithSmi(action_data->bytecode, last(), | |
259 node); | |
260 // Discard last. | |
261 InvalidateLast(); | |
262 // Immediately emit current node as nothing fuses with AddSmi, SubSmi, etc. | |
rmcilroy
2016/07/13 13:51:41
Could we not do this, we might want to fuse with A
oth
2016/07/15 13:09:40
How about adapting this when the future change is
rmcilroy
2016/07/15 15:31:48
I'd rather not do this since it would not be immed
oth
2016/07/15 17:27:26
Done.
| |
263 next_stage()->Write(node); | |
264 } else { | |
265 DefaultAction(node); | |
266 } | |
267 } | |
268 | |
269 void BytecodePeepholeOptimizer:: | |
270 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction( | |
271 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
272 DCHECK(LastIsValid()); | |
273 DCHECK(!Bytecodes::IsJump(node->bytecode())); | |
274 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | |
275 // Fused last and current into current. | |
276 TransformLdaZeroBinaryOpToBinaryOpWithZero(action_data->bytecode, last(), | |
277 node); | |
278 // Discard last. | |
279 InvalidateLast(); | |
280 // Immediately emit current node as nothing fuses with AddSmi, SubSmi, etc. | |
rmcilroy
2016/07/13 13:51:41
ditto
oth
2016/07/15 13:09:40
Same here, propose only changing when needed.
oth
2016/07/15 17:27:25
Done.
| |
281 next_stage()->Write(node); | |
282 } else { | |
283 DefaultAction(node); | |
284 } | |
285 } | |
286 | |
287 void BytecodePeepholeOptimizer::DefaultJumpAction( | |
288 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
289 DCHECK(LastIsValid()); | |
290 DCHECK(Bytecodes::IsJump(node->bytecode())); | |
291 | |
292 next_stage()->Write(last()); | |
293 InvalidateLast(); | |
294 } | |
295 | |
296 void BytecodePeepholeOptimizer::UpdateLastJumpAction( | |
297 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
298 DCHECK(!LastIsValid()); | |
299 DCHECK(Bytecodes::IsJump(node->bytecode())); | |
300 } | |
301 | |
302 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction( | |
303 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
304 DCHECK(LastIsValid()); | |
305 DCHECK(Bytecodes::IsJump(node->bytecode())); | |
306 | |
307 next_stage()->Write(last()); | |
308 InvalidateLast(); | |
309 node->set_bytecode(action_data->bytecode, node->operand(0)); | |
310 } | |
311 | |
312 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( | |
313 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | |
314 DCHECK(LastIsValid()); | |
315 DCHECK(Bytecodes::IsJump(node->bytecode())); | |
316 | |
rmcilroy
2016/07/13 13:51:41
Should we be calling CanElideLastBasedOnSourcePosi
oth
2016/07/15 13:09:40
Added a DCHECK as there is an assumption that this
| |
317 if (!node->source_info().is_valid()) { | |
318 node->source_info().Clone(last()->source_info()); | |
319 } else { | |
320 next_stage()->Write(last()); | |
321 } | |
322 InvalidateLast(); | |
323 } | |
324 | |
325 void BytecodePeepholeOptimizer::Optimize(BytecodeNode* const node) { | |
326 // A single table is used for looking up peephole optimization | |
327 // matches as it is observed to have better performance. This is | |
328 // inspite of the fact that jump bytecodes and non-jump bytecodes | |
329 // have different processing logic, in particular a jump bytecode | |
330 // always needs to emit the jump via WriteJump(). | |
331 const PeepholeActionAndData* const action_data = | |
332 PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode()); | |
333 switch (action_data->action) { | |
334 #define CASE(Action) \ | |
335 case PeepholeAction::k##Action: \ | |
336 Action(node, action_data); \ | |
337 break; | |
338 PEEPHOLE_ACTION_LIST(CASE) | |
339 #undef CASE | |
340 default: | |
341 UNREACHABLE(); | |
342 break; | |
343 } | |
371 } | 344 } |
372 | 345 |
373 } // namespace interpreter | 346 } // namespace interpreter |
374 } // namespace internal | 347 } // namespace internal |
375 } // namespace v8 | 348 } // namespace v8 |
OLD | NEW |