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

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

Issue 2161563002: Revert of [interpeter] Move to table based peephole optimizer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: 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 2016 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
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
32 void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) { 47 void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) {
33 Flush(); 48 Flush();
34 next_stage_->BindLabel(label); 49 next_stage_->BindLabel(label);
35 } 50 }
36 51
37 // override 52 // override
38 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target, 53 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target,
39 BytecodeLabel* label) { 54 BytecodeLabel* label) {
40 // There is no need to flush here, it will have been flushed when 55 // There is no need to flush here, it will have been flushed when |target|
41 // |target| was bound. 56 // was bound.
42 next_stage_->BindLabel(target, label); 57 next_stage_->BindLabel(target, label);
43 } 58 }
44 59
45 // override
46 void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node,
47 BytecodeLabel* label) {
48 // Handlers for jump bytecodes do not emit |node| as WriteJump()
49 // requires the |label| and having a label argument in all action
50 // handlers results in dead work in the non-jump case.
51 ApplyPeepholeAction(node);
52 next_stage()->WriteJump(node, label);
53 }
54
55 // override
56 void BytecodePeepholeOptimizer::Write(BytecodeNode* node) {
57 // Handlers for non-jump bytecodes run to completion emitting
58 // bytecode to next stage as appropriate.
59 ApplyPeepholeAction(node);
60 }
61
62 void BytecodePeepholeOptimizer::Flush() { 60 void BytecodePeepholeOptimizer::Flush() {
61 // TODO(oth/rmcilroy): We could check CanElideLast() here to potentially
62 // eliminate last rather than writing it.
63 if (LastIsValid()) { 63 if (LastIsValid()) {
64 next_stage_->Write(&last_); 64 next_stage_->Write(&last_);
65 InvalidateLast(); 65 InvalidateLast();
66 } 66 }
67 } 67 }
68 68
69 void BytecodePeepholeOptimizer::InvalidateLast() { 69 void BytecodePeepholeOptimizer::InvalidateLast() {
70 last_.set_bytecode(Bytecode::kIllegal); 70 last_.set_bytecode(Bytecode::kIllegal);
71 } 71 }
72 72
73 bool BytecodePeepholeOptimizer::LastIsValid() const { 73 bool BytecodePeepholeOptimizer::LastIsValid() const {
74 return last_.bytecode() != Bytecode::kIllegal; 74 return last_.bytecode() != Bytecode::kIllegal;
75 } 75 }
76 76
77 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { 77 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) {
78 // An action shouldn't leave a NOP as last bytecode unless it has
79 // source position information. NOP without source information can
80 // always be elided.
81 DCHECK(node->bytecode() != Bytecode::kNop || node->source_info().is_valid());
82
83 last_.Clone(node); 78 last_.Clone(node);
84 } 79 }
85 80
86 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand( 81 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand(
87 const BytecodeNode* const node, int index) const { 82 const BytecodeNode* const node, int index) const {
88 DCHECK_LE(index, node->operand_count()); 83 DCHECK_LE(index, node->operand_count());
89 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx); 84 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx);
90 uint32_t index_operand = node->operand(0); 85 uint32_t index_operand = node->operand(0);
91 return constant_array_builder_->At(index_operand); 86 return constant_array_builder_->At(index_operand);
92 } 87 }
93 88
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
94 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( 134 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition(
95 const BytecodeNode* const current) const { 135 const BytecodeNode* const current) const {
96 // 136 //
97 // The rules for allowing the elision of the last bytecode based 137 // The rules for allowing the elision of the last bytecode based
98 // on source position are: 138 // on source position are:
99 // 139 //
100 // C U R R E N T 140 // C U R R E N T
101 // +--------+--------+--------+ 141 // +--------+--------+--------+
102 // | None | Expr | Stmt | 142 // | None | Expr | Stmt |
103 // L +--------+--------+--------+--------+ 143 // L +--------+--------+--------+--------+
104 // | None | YES | YES | YES | 144 // | None | YES | YES | YES |
105 // A +--------+--------+--------+--------+ 145 // A +--------+--------+--------+--------+
106 // | Expr | YES | MAYBE | MAYBE | 146 // | Expr | YES | MAYBE | MAYBE |
107 // S +--------+--------+--------+--------+ 147 // S +--------+--------+--------+--------+
108 // | Stmt | YES | NO | NO | 148 // | Stmt | YES | NO | NO |
109 // T +--------+--------+--------+--------+ 149 // T +--------+--------+--------+--------+
110 // 150 //
111 // The goal is not lose any statement positions and not lose useful 151 // The goal is not lose any statement positions and not lose useful
112 // expression positions. Whenever the last bytecode is elided it's 152 // expression positions. Whenever the last bytecode is elided it's
113 // source position information is applied to the current node 153 // source position information is applied to the current node
114 // updating it if necessary. 154 // updating it if necessary.
115 // 155 //
116 // The last bytecode could be elided for the MAYBE cases if the last 156 // The last bytecode can be elided for the MAYBE cases if the last
117 // bytecode is known not to throw. If it throws, the system would 157 // bytecode is known not to throw. If it throws, the system would
118 // not have correct stack trace information. The appropriate check 158 // not have correct stack trace information. The appropriate check
119 // for this would be Bytecodes::IsWithoutExternalSideEffects(). By 159 // for this would be Bytecodes::IsWithoutExternalSideEffects(),
120 // default, the upstream bytecode generator filters out unneeded 160 // which is checked in
121 // expression position information so there is neglible benefit to 161 // BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes() to
122 // handling MAYBE specially. Hence MAYBE is treated the same as NO. 162 // keep the check here simple.
163 //
164 // In rare cases, bytecode generation produces consecutive bytecodes
165 // with the same expression positions. In principle, the latter of
166 // these can be elided, but would make this function more expensive.
123 // 167 //
124 return (!last_.source_info().is_valid() || 168 return (!last_.source_info().is_valid() ||
125 !current->source_info().is_valid()); 169 !current->source_info().is_valid());
126 } 170 }
127 171
128 namespace { 172 namespace {
129 173
130 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last, 174 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last,
131 BytecodeNode* const current) { 175 BytecodeNode* const current) {
132 DCHECK_EQ(current->bytecode(), Bytecode::kStar); 176 DCHECK_EQ(current->bytecode(), Bytecode::kStar);
133 177
134 // 178 //
135 // An example transformation here would be: 179 // An example transformation here would be:
136 // 180 //
137 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R 181 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R
138 // Star R ====/ Ldar R 182 // Star R ====/ Ldar R
139 // 183 //
140 // which loads a global value into both a register and the 184 // which loads a global value into both a register and the
141 // accumulator. However, in the second form the Ldar can often be 185 // accumulator. However, in the second form the Ldar can often be
142 // peephole optimized away unlike the Star in the first form. 186 // peephole optimized away unlike the Star in the first form.
143 // 187 //
144 last->Transform(new_bytecode, current->operand(0)); 188 last->Transform(new_bytecode, current->operand(0));
145 current->set_bytecode(Bytecode::kLdar, current->operand(0)); 189 current->set_bytecode(Bytecode::kLdar, current->operand(0));
146 } 190 }
147 191
148 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, 192 void TransformToBinaryOpWithSmiOnRhs(Bytecode new_bytecode,
149 BytecodeNode* const last, 193 BytecodeNode* const last,
150 BytecodeNode* const current) { 194 BytecodeNode* const current) {
151 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); 195 DCHECK(Bytecodes::IsLdaSmiOrLdaZero(last->bytecode()));
152 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0)); 196 uint32_t imm_operand =
153 if (last->source_info().is_valid()) { 197 last->bytecode() == Bytecode::kLdaSmi ? last->operand(0) : 0;
154 current->source_info().Clone(last->source_info()); 198 current->set_bytecode(new_bytecode, imm_operand, current->operand(0));
155 }
156 }
157
158 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode,
159 BytecodeNode* const last,
160 BytecodeNode* const current) {
161 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero);
162 current->set_bytecode(new_bytecode, 0, current->operand(0));
163 if (last->source_info().is_valid()) { 199 if (last->source_info().is_valid()) {
164 current->source_info().Clone(last->source_info()); 200 current->source_info().Clone(last->source_info());
165 } 201 }
166 } 202 }
167 203
168 } // namespace 204 } // namespace
169 205
170 void BytecodePeepholeOptimizer::DefaultAction( 206 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes(
171 BytecodeNode* const node, const PeepholeActionAndData* action_data) { 207 BytecodeNode* const current) {
172 DCHECK(LastIsValid()); 208 if (current->bytecode() == Bytecode::kStar &&
173 DCHECK(!Bytecodes::IsJump(node->bytecode())); 209 !current->source_info().is_statement()) {
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 }
174 268
175 next_stage()->Write(last()); 269 return false;
176 SetLast(node);
177 } 270 }
178 271
179 void BytecodePeepholeOptimizer::UpdateLastAction( 272 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
180 BytecodeNode* const node, const PeepholeActionAndData* action_data) { 273 BytecodeNode* const current) {
181 DCHECK(!LastIsValid()); 274 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
182 DCHECK(!Bytecodes::IsJump(node->bytecode())); 275 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
183 276 if (can_remove) {
184 SetLast(node); 277 // Conditional jumps with boolean conditions are emiitted in
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;
185 } 286 }
186 287
187 void BytecodePeepholeOptimizer::UpdateLastIfSourceInfoPresentAction( 288 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
188 BytecodeNode* const node, const PeepholeActionAndData* action_data) { 289 BytecodeNode* const current) {
189 DCHECK(!LastIsValid()); 290 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
190 DCHECK(!Bytecodes::IsJump(node->bytecode())); 291 Bytecodes::WritesBooleanToAccumulator(last_.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 }
191 300
192 if (node->source_info().is_valid()) { 301 bool BytecodePeepholeOptimizer::TransformCurrentBytecode(
193 SetLast(node); 302 BytecodeNode* const current) {
303 return RemoveToBooleanFromJump(current) ||
304 RemoveToBooleanFromLogicalNot(current);
305 }
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 {
325 return false;
194 } 326 }
195 } 327 }
196 328
197 void BytecodePeepholeOptimizer::ElideCurrentAction( 329 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
198 BytecodeNode* const node, const PeepholeActionAndData* action_data) { 330 TryToRemoveLastExpressionPosition(current);
199 DCHECK(LastIsValid()); 331 if (TransformCurrentBytecode(current) ||
200 DCHECK(!Bytecodes::IsJump(node->bytecode())); 332 TransformLastAndCurrentBytecodes(current)) {
333 return current;
334 }
201 335
202 if (node->source_info().is_valid()) { 336 if (CanElideCurrent(current)) {
203 // Preserve the source information by replacing the node bytecode 337 if (current->source_info().is_valid()) {
204 // with a no op bytecode. 338 // Preserve the source information by replacing the current bytecode
205 node->set_bytecode(Bytecode::kNop); 339 // with a no op bytecode.
206 DefaultAction(node); 340 current->set_bytecode(Bytecode::kNop);
207 } else { 341 } else {
208 // Nothing to do, keep last and wait for next bytecode to pair with it. 342 current = nullptr;
343 }
344 return current;
209 } 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;
210 } 357 }
211 358
212 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( 359 BytecodeNode* BytecodePeepholeOptimizer::OptimizeAndEmitLast(
213 BytecodeNode* const node, const PeepholeActionAndData* action_data) { 360 BytecodeNode* current) {
214 DCHECK(LastIsValid()); 361 // Attempt optimization if there is an earlier node to optimize with.
215 DCHECK(!Bytecodes::IsJump(node->bytecode())); 362 if (LastIsValid()) {
216 363 current = Optimize(current);
217 if (last()->operand(0) == node->operand(0)) { 364 // Only output the last node if it wasn't invalidated by the optimization.
218 ElideCurrentAction(node); 365 if (LastIsValid()) {
219 } else { 366 next_stage_->Write(&last_);
220 DefaultAction(node); 367 InvalidateLast();
368 }
221 } 369 }
222 } 370 return current;
223
224 void BytecodePeepholeOptimizer::ElideCurrentIfLoadingNameConstantAction(
225 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
226 DCHECK_EQ(last()->bytecode(), Bytecode::kLdaConstant);
227 DCHECK(!Bytecodes::IsJump(node->bytecode()));
228
229 if (GetConstantForIndexOperand(last(), 0)->IsName()) {
230 ElideCurrentAction(node);
231 } else {
232 DefaultAction(node);
233 }
234 }
235
236 void BytecodePeepholeOptimizer::ElideLastAction(
237 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
238 DCHECK(LastIsValid());
239 DCHECK(!Bytecodes::IsJump(node->bytecode()));
240
241 if (CanElideLastBasedOnSourcePosition(node)) {
242 if (last()->source_info().is_valid()) {
243 // |node| can not have a valid source position if the source
244 // position of last() is valid (per rules in
245 // CanElideLastBasedOnSourcePosition()).
246 node->source_info().Clone(last()->source_info());
247 }
248 SetLast(node);
249 } else {
250 DefaultAction(node);
251 }
252 }
253
254 void BytecodePeepholeOptimizer::ChangeBytecodeAction(
255 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
256 DCHECK(LastIsValid());
257 DCHECK(!Bytecodes::IsJump(node->bytecode()));
258
259 node->set_bytecode(action_data->bytecode);
260 DefaultAction(node);
261 }
262
263 void BytecodePeepholeOptimizer::TransformLdaStarToLdrLdarAction(
264 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
265 DCHECK(LastIsValid());
266 DCHECK(!Bytecodes::IsJump(node->bytecode()));
267
268 if (!node->source_info().is_statement()) {
269 TransformLdaStarToLdrLdar(action_data->bytecode, last(), node);
270 }
271 DefaultAction(node);
272 }
273
274 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction(
275 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
276 DCHECK(LastIsValid());
277 DCHECK(!Bytecodes::IsJump(node->bytecode()));
278
279 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) {
280 // Fused last and current into current.
281 TransformLdaSmiBinaryOpToBinaryOpWithSmi(action_data->bytecode, last(),
282 node);
283 SetLast(node);
284 } else {
285 DefaultAction(node);
286 }
287 }
288
289 void BytecodePeepholeOptimizer::
290 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction(
291 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
292 DCHECK(LastIsValid());
293 DCHECK(!Bytecodes::IsJump(node->bytecode()));
294 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) {
295 // Fused last and current into current.
296 TransformLdaZeroBinaryOpToBinaryOpWithZero(action_data->bytecode, last(),
297 node);
298 SetLast(node);
299 } else {
300 DefaultAction(node);
301 }
302 }
303
304 void BytecodePeepholeOptimizer::DefaultJumpAction(
305 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
306 DCHECK(LastIsValid());
307 DCHECK(Bytecodes::IsJump(node->bytecode()));
308
309 next_stage()->Write(last());
310 InvalidateLast();
311 }
312
313 void BytecodePeepholeOptimizer::UpdateLastJumpAction(
314 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
315 DCHECK(!LastIsValid());
316 DCHECK(Bytecodes::IsJump(node->bytecode()));
317 }
318
319 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction(
320 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
321 DCHECK(LastIsValid());
322 DCHECK(Bytecodes::IsJump(node->bytecode()));
323
324 next_stage()->Write(last());
325 InvalidateLast();
326 node->set_bytecode(action_data->bytecode, node->operand(0));
327 }
328
329 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction(
330 BytecodeNode* const node, const PeepholeActionAndData* action_data) {
331 DCHECK(LastIsValid());
332 DCHECK(Bytecodes::IsJump(node->bytecode()));
333 DCHECK(CanElideLastBasedOnSourcePosition(node));
334
335 if (!node->source_info().is_valid()) {
336 node->source_info().Clone(last()->source_info());
337 } else {
338 next_stage()->Write(last());
339 }
340 InvalidateLast();
341 }
342
343 void BytecodePeepholeOptimizer::ApplyPeepholeAction(BytecodeNode* const node) {
344 // A single table is used for looking up peephole optimization
345 // matches as it is observed to have better performance. This is
346 // inspite of the fact that jump bytecodes and non-jump bytecodes
347 // have different processing logic, in particular a jump bytecode
348 // always needs to emit the jump via WriteJump().
349 const PeepholeActionAndData* const action_data =
350 PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode());
351 switch (action_data->action) {
352 #define CASE(Action) \
353 case PeepholeAction::k##Action: \
354 Action(node, action_data); \
355 break;
356 PEEPHOLE_ACTION_LIST(CASE)
357 #undef CASE
358 default:
359 UNREACHABLE();
360 break;
361 }
362 } 371 }
363 372
364 } // namespace interpreter 373 } // namespace interpreter
365 } // namespace internal 374 } // namespace internal
366 } // namespace v8 375 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-peephole-optimizer.h ('k') | src/interpreter/bytecode-peephole-table.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698