OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 } | 87 } |
88 | 88 |
89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { | 89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { |
90 DCHECK(LastIsValid()); | 90 DCHECK(LastIsValid()); |
91 return (last_.bytecode() == Bytecode::kTypeOf || | 91 return (last_.bytecode() == Bytecode::kTypeOf || |
92 last_.bytecode() == Bytecode::kToName || | 92 last_.bytecode() == Bytecode::kToName || |
93 (last_.bytecode() == Bytecode::kLdaConstant && | 93 (last_.bytecode() == Bytecode::kLdaConstant && |
94 GetConstantForIndexOperand(&last_, 0)->IsName())); | 94 GetConstantForIndexOperand(&last_, 0)->IsName())); |
95 } | 95 } |
96 | 96 |
97 void BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( | 97 void BytecodePeepholeOptimizer::TryToRemoveLastExpressionPosition( |
98 BytecodeNode* current) { | 98 const BytecodeNode* const current) { |
99 if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | |
100 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) { | |
101 // Conditional jumps with boolean conditions are emitted in | |
102 // ToBoolean form by the bytecode array builder, | |
103 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean element | |
104 // can be removed if the previous bytecode put a boolean value in | |
105 // the accumulator. | |
106 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode()); | |
107 current->set_bytecode(jump, current->operand(0), current->operand_scale()); | |
108 } else if (current->bytecode() == Bytecode::kToBooleanLogicalNot && | |
109 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) { | |
110 // Logical-nots are emitted in ToBoolean form by the bytecode array | |
111 // builder, The ToBoolean element can be removed if the previous bytecode | |
112 // put a boolean value in the accumulator. | |
113 current->set_bytecode(Bytecode::kLogicalNot); | |
114 } | |
115 | |
116 if (current->source_info().is_statement() && | 99 if (current->source_info().is_statement() && |
117 last_.source_info().is_expression() && | 100 last_.source_info().is_expression() && |
118 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { | 101 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { |
119 // The last bytecode has been marked as expression. It has no | 102 // The last bytecode has been marked as expression. It has no |
120 // external effects so can't throw and the current bytecode is a | 103 // external effects so can't throw and the current bytecode is a |
121 // source position. Remove the expression position on the last | 104 // source position. Remove the expression position on the last |
122 // bytecode to open up potential peephole optimizations and to | 105 // bytecode to open up potential peephole optimizations and to |
123 // save the memory and perf cost of storing the unneeded | 106 // save the memory and perf cost of storing the unneeded |
124 // expression position. | 107 // expression position. |
125 last_.source_info().set_invalid(); | 108 last_.source_info().set_invalid(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 // to keep the check here simple. | 161 // to keep the check here simple. |
179 // | 162 // |
180 // In rare cases, bytecode generation produces consecutive bytecodes | 163 // In rare cases, bytecode generation produces consecutive bytecodes |
181 // with the same expression positions. In principle, the latter of | 164 // with the same expression positions. In principle, the latter of |
182 // these can be elided, but would make this function more expensive. | 165 // these can be elided, but would make this function more expensive. |
183 // | 166 // |
184 return (!last_.source_info().is_valid() || | 167 return (!last_.source_info().is_valid() || |
185 !current->source_info().is_valid()); | 168 !current->source_info().is_valid()); |
186 } | 169 } |
187 | 170 |
171 namespace { | |
rmcilroy
2016/05/24 14:00:11
nit - newline after {
oth
2016/05/24 15:07:14
Done.
| |
172 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last, | |
173 BytecodeNode* const current) { | |
174 DCHECK_EQ(current->bytecode(), Bytecodes::kStar); | |
175 // | |
176 // An example transformation here would be: | |
177 // | |
178 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R | |
179 // Star R ====/ Ldar R | |
180 // | |
181 // which loads a global value into both a register and the | |
182 // accumulator. However, in the second form the Ldar can often be | |
183 // peephole optimized away unlike the Star in the first form. | |
184 // | |
185 last->Transform(new_bytecode, current->operand(0), current->operand_scale()); | |
186 current->set_bytecode(Bytecode::kLdar, current->operand(0), | |
187 current->operand_scale()); | |
188 | |
189 // If there was a source position on |current| transfer it to the | |
190 // updated |last| to maintain the debugger's causal view. ie. if an | |
191 // expression position LdrGlobal is the bytecode that could throw | |
192 // and if a statement position it needs to be placed before the | |
193 // store to R occurs. | |
194 last->source_info().Update(current->source_info()); | |
195 current->source_info().set_invalid(); | |
196 } | |
197 } // namespace | |
rmcilroy
2016/05/24 14:00:11
nit - newline above
oth
2016/05/24 15:07:15
Done.
| |
198 | |
199 bool BytecodePeepholeOptimizer::ChangeLdaToLdr(BytecodeNode* const current) { | |
200 if (current->bytecode() == Bytecode::kStar) { | |
201 switch (last_.bytecode()) { | |
202 case Bytecode::kLoadIC: | |
203 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); | |
204 return true; | |
205 case Bytecode::kKeyedLoadIC: | |
206 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); | |
207 return true; | |
208 case Bytecode::kLdaGlobal: | |
209 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); | |
210 return true; | |
211 case Bytecode::kLdaContextSlot: | |
212 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); | |
213 return true; | |
214 case Bytecode::kLdaUndefined: | |
215 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); | |
216 return true; | |
217 default: | |
218 break; | |
219 } | |
220 } | |
221 return false; | |
222 } | |
223 | |
224 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( | |
225 BytecodeNode* const current) { | |
226 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | |
227 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | |
228 if (can_remove) { | |
229 // Conditional jumps with boolean conditions are emiitted in | |
230 // ToBoolean form by the bytecode array builder, | |
231 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean | |
232 // element can be removed if the previous bytecode put a boolean | |
233 // value in the accumulator. | |
234 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode()); | |
235 current->set_bytecode(jump, current->operand(0), current->operand_scale()); | |
236 } | |
237 return can_remove; | |
238 } | |
239 | |
240 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot( | |
241 BytecodeNode* const current) { | |
242 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot && | |
243 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | |
244 if (can_remove) { | |
245 // Logical-nots are emitted in ToBoolean form by the bytecode array | |
246 // builder, The ToBoolean element can be removed if the previous bytecode | |
247 // put a boolean value in the accumulator. | |
248 current->set_bytecode(Bytecode::kLogicalNot); | |
249 } | |
250 return can_remove; | |
251 } | |
252 | |
253 bool BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( | |
254 BytecodeNode* const current) { | |
255 return RemoveToBooleanFromJump(current) || | |
256 RemoveToBooleanFromLogicalNot(current) || ChangeLdaToLdr(current); | |
257 } | |
258 | |
188 bool BytecodePeepholeOptimizer::CanElideLast( | 259 bool BytecodePeepholeOptimizer::CanElideLast( |
189 const BytecodeNode* const current) const { | 260 const BytecodeNode* const current) const { |
190 if (!last_is_discardable_) { | 261 if (!last_is_discardable_) { |
191 return false; | 262 return false; |
192 } | 263 } |
193 | 264 |
194 if (last_.bytecode() == Bytecode::kNop) { | 265 if (last_.bytecode() == Bytecode::kNop) { |
195 // Nop are placeholders for holding source position information. | 266 // Nop are placeholders for holding source position information. |
196 return true; | 267 return true; |
197 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && | 268 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && |
198 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | 269 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { |
199 // The accumulator is invisible to the debugger. If there is a sequence of | 270 // The accumulator is invisible to the debugger. If there is a sequence of |
200 // consecutive accumulator loads (that don't have side effects) then only | 271 // consecutive accumulator loads (that don't have side effects) then only |
201 // the final load is potentially visible. | 272 // the final load is potentially visible. |
202 return true; | 273 return true; |
274 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) == | |
275 AccumulatorUse::kWrite && | |
276 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | |
277 // The current instruction clobbers the accumulator without reading it. The | |
278 // load in the last instruction can be elided as it has no effect. | |
279 return true; | |
203 } else { | 280 } else { |
204 return false; | 281 return false; |
205 } | 282 } |
206 } | 283 } |
207 | 284 |
208 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { | 285 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { |
209 UpdateLastAndCurrentBytecodes(current); | 286 TryToRemoveLastExpressionPosition(current); |
287 | |
288 if (UpdateLastAndCurrentBytecodes(current)) { | |
289 return current; | |
290 } | |
291 | |
210 if (CanElideCurrent(current)) { | 292 if (CanElideCurrent(current)) { |
211 if (current->source_info().is_valid()) { | 293 if (current->source_info().is_valid()) { |
294 // Preserve the source information by replacing the current bytecode | |
295 // with a no op bytecode. | |
212 current->set_bytecode(Bytecode::kNop); | 296 current->set_bytecode(Bytecode::kNop); |
213 } else { | 297 } else { |
214 current = nullptr; | 298 current = nullptr; |
215 } | 299 } |
216 } else if (CanElideLast(current) && | 300 return current; |
217 CanElideLastBasedOnSourcePosition(current)) { | 301 } |
302 | |
303 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) { | |
218 current->source_info().Update(last_.source_info()); | 304 current->source_info().Update(last_.source_info()); |
219 InvalidateLast(); | 305 InvalidateLast(); |
rmcilroy
2016/05/24 14:00:11
Please add "return current" here too ensure we don
oth
2016/05/24 15:07:15
Done.
| |
220 } | 306 } |
221 return current; | 307 return current; |
222 } | 308 } |
223 | 309 |
224 } // namespace interpreter | 310 } // namespace interpreter |
225 } // namespace internal | 311 } // namespace internal |
226 } // namespace v8 | 312 } // namespace v8 |
OLD | NEW |