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

Side by Side Diff: src/interpreter/bytecode-peephole-optimizer.cc

Issue 2118183002: [interpeter] Move to table based peephole optimizer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Minor renaming and re-grouping. Created 4 years, 5 months 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 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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698