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

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: Undo experimental in last 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
« no previous file with comments | « src/interpreter/bytecode-peephole-optimizer.h ('k') | src/interpreter/bytecodes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 namespace interpreter { 13 namespace interpreter {
14 14
15 namespace {
16
17 // Actions to take when a pair of bytes is encountered. A handler
18 // exists for each action.
19 enum class PeepholeAction : uint8_t {
20 // Actions for non-jump bytecodes.
21 kDefaultAction,
22 kUpdateLastAction,
23 kElideCurrentAction,
24 kElideCurrentIfOperand0MatchesAction,
25 kElideCurrentIfLoadingNameConstantAction,
26 kElideLastAction,
27 kChangeBytecodeAction,
28 kTransformLdaStarToLdrLdarAction,
29
30 // Actions for jump bytecodes.
31 kDefaultJumpAction,
32 kUpdateLastJumpAction,
33 kChangeJumpBytecodeAction,
34 kElideLastBeforeJumpAction,
35 };
36
37 // Tuple of action to take when pair of bytecodes is encountered and
38 // optional data to invoke handler with.
39 struct PeepholeActionAndData final {
40 // Action to take when tuple of bytecodes encountered.
41 PeepholeAction action;
42
43 // Replacement bytecode (if valid).
44 Bytecode bytecode;
45 };
46
47 class PeepholeActionTable final {
48 public:
49 static void Initialize();
50
51 static const PeepholeActionAndData* const Lookup(Bytecode last,
52 Bytecode current) {
53 size_t index = ToIndex(last, current);
54 return &table_[index];
55 }
56
57 static bool initialized() { return initialized_; }
58
59 private:
60 static const size_t kNumberOfBytecodes =
61 static_cast<size_t>(Bytecode::kLast) + 1;
62 static const size_t kTableSize = kNumberOfBytecodes * kNumberOfBytecodes;
63
64 static PeepholeActionAndData LookupActionAndData(Bytecode last,
65 Bytecode current);
66 static void InsertActionAndData(Bytecode last, Bytecode current,
67 PeepholeActionAndData action_data);
68 static Bytecode NextBytecode(Bytecode bytecode);
69 static size_t ToIndex(Bytecode last, Bytecode current);
70
71 static bool initialized_;
72 static PeepholeActionAndData table_[kTableSize];
73 };
74
75 bool PeepholeActionTable::initialized_ = false;
76 PeepholeActionAndData PeepholeActionTable::table_[kTableSize];
77
78 // static
79 void PeepholeActionTable::Initialize() {
80 DCHECK(!initialized_);
81 for (Bytecode last = Bytecode::kWide; last <= Bytecode::kLast;
82 last = NextBytecode(last)) {
83 for (Bytecode current = Bytecode::kWide; current <= Bytecode::kLast;
84 current = NextBytecode(current)) {
85 PeepholeActionAndData action_data = LookupActionAndData(last, current);
86 InsertActionAndData(last, current, action_data);
87 }
88 }
89 initialized_ = true;
90 }
91
92 // static
93 Bytecode PeepholeActionTable::NextBytecode(Bytecode bytecode) {
94 return static_cast<Bytecode>(static_cast<size_t>(bytecode) + 1);
95 }
96
97 // static
98 size_t PeepholeActionTable::ToIndex(Bytecode last, Bytecode current) {
99 return static_cast<size_t>(last) * kNumberOfBytecodes +
100 static_cast<size_t>(current);
101 }
102
103 // static
104 void PeepholeActionTable::InsertActionAndData(
105 Bytecode last, Bytecode current, PeepholeActionAndData action_data) {
106 size_t index = ToIndex(last, current);
107 table_[index] = action_data;
108 }
109
110 // static
111 PeepholeActionAndData PeepholeActionTable::LookupActionAndData(
112 Bytecode last, Bytecode current) {
113 // TODO(oth): Investigate generating this table at compile time.
114
115 // Optimize various accumulator loads followed by store accumulator
116 // to an equivalent register load and loading the accumulator with
117 // the register. The latter accumulator load can often be elided as
118 // it is side-effect free and often followed by another accumulator
119 // load so can be elided.
120 if (current == Bytecode::kStar && last == Bytecode::kLdaNamedProperty) {
121 return {PeepholeAction::kTransformLdaStarToLdrLdarAction,
122 Bytecode::kLdrNamedProperty};
123 } else if (current == Bytecode::kStar &&
124 last == Bytecode::kLdaKeyedProperty) {
125 return {PeepholeAction::kTransformLdaStarToLdrLdarAction,
126 Bytecode::kLdrKeyedProperty};
127 } else if (current == Bytecode::kStar && last == Bytecode::kLdaGlobal) {
128 return {PeepholeAction::kTransformLdaStarToLdrLdarAction,
129 Bytecode::kLdrGlobal};
130 } else if (current == Bytecode::kStar && last == Bytecode::kLdaContextSlot) {
131 return {PeepholeAction::kTransformLdaStarToLdrLdarAction,
132 Bytecode::kLdrContextSlot};
133 } else if (current == Bytecode::kStar && last == Bytecode::kLdaUndefined) {
134 return {PeepholeAction::kTransformLdaStarToLdrLdarAction,
135 Bytecode::kLdrUndefined};
136 }
137
138 // ToName optimizations: remove unnecessary ToName bytecodes.
139 if (last == Bytecode::kLdaConstant && current == Bytecode::kToName) {
140 return {PeepholeAction::kElideCurrentIfLoadingNameConstantAction,
141 Bytecode::kIllegal};
142 } else if (Bytecodes::PutsNameInAccumulator(last) &&
143 current == Bytecode::kToName) {
144 return {PeepholeAction::kElideCurrentAction, Bytecode::kIllegal};
145 }
146
147 // Nop are placeholders for holding source position information and can be
148 // elided if there is no source information.
149 if (last == Bytecode::kNop) {
150 if (Bytecodes::IsJump(current)) {
151 return {PeepholeAction::kElideLastBeforeJumpAction, Bytecode::kIllegal};
152 } else {
153 return {PeepholeAction::kElideLastAction, Bytecode::kIllegal};
154 }
155 }
156
157 // The accumulator is invisible to the debugger. If there is a sequence
158 // of consecutive accumulator loads (that don't have side effects) then
159 // only the final load is potentially visible.
160 if (Bytecodes::IsAccumulatorLoadWithoutEffects(last) &&
161 Bytecodes::IsAccumulatorLoadWithoutEffects(current)) {
162 return {PeepholeAction::kElideLastAction, Bytecode::kIllegal};
163 }
164
165 // The current instruction clobbers the accumulator without reading
166 // it. The load in the last instruction can be elided as it has no
167 // effect.
168 if (Bytecodes::IsAccumulatorLoadWithoutEffects(last) &&
169 Bytecodes::GetAccumulatorUse(current) == AccumulatorUse::kWrite) {
170 return {PeepholeAction::kElideLastAction, Bytecode::kIllegal};
171 }
172
173 // Ldar and Star make the accumulator and register hold equivalent
174 // values. Only the first bytecode is needed if there's a sequence
175 // of back-to-back Ldar and Star bytecodes with the same operand.
176 if (Bytecodes::IsLdarOrStar(last) && Bytecodes::IsLdarOrStar(current)) {
177 return {PeepholeAction::kElideCurrentIfOperand0MatchesAction,
178 Bytecode::kIllegal};
179 }
180
181 // Remove ToBoolean coercion from conditional jumps where possible.
182 if (Bytecodes::WritesBooleanToAccumulator(last) &&
183 Bytecodes::IsJumpIfToBoolean(current)) {
184 return {PeepholeAction::kChangeJumpBytecodeAction,
185 Bytecodes::GetJumpWithoutToBoolean(current)};
186 } else if (Bytecodes::WritesBooleanToAccumulator(last) &&
187 current == Bytecode::kToBooleanLogicalNot) {
188 return {PeepholeAction::kChangeBytecodeAction, Bytecode::kLogicalNot};
189 }
190
191 // If there is no last bytecode to optimize against, store the incoming
192 // bytecode or for jumps emit incoming bytecode immediately.
193 if (last == Bytecode::kIllegal) {
194 if (Bytecodes::IsJump(current)) {
195 return {PeepholeAction::kUpdateLastJumpAction, Bytecode::kIllegal};
196 } else {
197 return {PeepholeAction::kUpdateLastAction, Bytecode::kIllegal};
198 }
199 }
200
201 // No matches, take the default action.
202 if (Bytecodes::IsJump(current)) {
203 return {PeepholeAction::kDefaultJumpAction, Bytecode::kIllegal};
204 } else {
205 return {PeepholeAction::kDefaultAction, Bytecode::kIllegal};
206 }
207 }
208
209 } // namespace
210
15 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( 211 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer(
16 ConstantArrayBuilder* constant_array_builder, 212 ConstantArrayBuilder* constant_array_builder,
17 BytecodePipelineStage* next_stage) 213 BytecodePipelineStage* next_stage)
18 : constant_array_builder_(constant_array_builder), next_stage_(next_stage) { 214 : constant_array_builder_(constant_array_builder), next_stage_(next_stage) {
215 if (!PeepholeActionTable::initialized()) {
216 PeepholeActionTable::Initialize();
rmcilroy 2016/07/04 12:45:46 How does this play with threading? There could be
217 }
19 InvalidateLast(); 218 InvalidateLast();
20 } 219 }
21 220
22 // override 221 // override
23 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( 222 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray(
24 int fixed_register_count, int parameter_count, 223 int fixed_register_count, int parameter_count,
25 Handle<FixedArray> handler_table) { 224 Handle<FixedArray> handler_table) {
26 Flush(); 225 Flush();
27 return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count, 226 return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count,
28 handler_table); 227 handler_table);
29 } 228 }
30 229
31 // override 230 // 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) { 231 void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) {
48 Flush(); 232 Flush();
49 next_stage_->BindLabel(label); 233 next_stage_->BindLabel(label);
50 } 234 }
51 235
52 // override 236 // override
53 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target, 237 void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target,
54 BytecodeLabel* label) { 238 BytecodeLabel* label) {
55 // There is no need to flush here, it will have been flushed when |target| 239 // There is no need to flush here, it will have been flushed when
56 // was bound. 240 // |target| was bound.
57 next_stage_->BindLabel(target, label); 241 next_stage_->BindLabel(target, label);
58 } 242 }
59 243
244 // override
245 void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node,
246 BytecodeLabel* label) {
247 Optimize(node);
248 next_stage()->WriteJump(node, label);
249 }
250
251 // override
252 void BytecodePeepholeOptimizer::Write(BytecodeNode* node) { Optimize(node); }
253
60 void BytecodePeepholeOptimizer::Flush() { 254 void BytecodePeepholeOptimizer::Flush() {
61 // TODO(oth/rmcilroy): We could check CanElideLast() here to potentially
62 // eliminate last rather than writing it.
63 if (LastIsValid()) { 255 if (LastIsValid()) {
64 next_stage_->Write(&last_); 256 next_stage_->Write(&last_);
65 InvalidateLast(); 257 InvalidateLast();
66 } 258 }
67 } 259 }
68 260
69 void BytecodePeepholeOptimizer::InvalidateLast() { 261 void BytecodePeepholeOptimizer::InvalidateLast() {
70 last_.set_bytecode(Bytecode::kIllegal); 262 last_.set_bytecode(Bytecode::kIllegal);
71 } 263 }
72 264
73 bool BytecodePeepholeOptimizer::LastIsValid() const { 265 bool BytecodePeepholeOptimizer::LastIsValid() const {
74 return last_.bytecode() != Bytecode::kIllegal; 266 return last_.bytecode() != Bytecode::kIllegal;
75 } 267 }
76 268
77 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { 269 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) {
78 last_.Clone(node); 270 last_.Clone(node);
79 } 271 }
80 272
81 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand( 273 Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand(
82 const BytecodeNode* const node, int index) const { 274 const BytecodeNode* const node, int index) const {
83 DCHECK_LE(index, node->operand_count()); 275 DCHECK_LE(index, node->operand_count());
84 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx); 276 DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx);
85 uint32_t index_operand = node->operand(0); 277 uint32_t index_operand = node->operand(0);
86 return constant_array_builder_->At(index_operand); 278 return constant_array_builder_->At(index_operand);
87 } 279 }
88 280
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) ToNumber if the last puts a number in the accumulator.
129 return false;
130 }
131 }
132
133 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( 281 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition(
134 const BytecodeNode* const current) const { 282 const BytecodeNode* const current) const {
135 // 283 //
136 // The rules for allowing the elision of the last bytecode based 284 // The rules for allowing the elision of the last bytecode based
137 // on source position are: 285 // on source position are:
138 // 286 //
139 // C U R R E N T 287 // C U R R E N T
140 // +--------+--------+--------+ 288 // +--------+--------+--------+
141 // | None | Expr | Stmt | 289 // | None | Expr | Stmt |
142 // L +--------+--------+--------+--------+ 290 // L +--------+--------+--------+--------+
143 // | None | YES | YES | YES | 291 // | None | YES | YES | YES |
144 // A +--------+--------+--------+--------+ 292 // A +--------+--------+--------+--------+
145 // | Expr | YES | MAYBE | MAYBE | 293 // | Expr | YES | MAYBE | MAYBE |
146 // S +--------+--------+--------+--------+ 294 // S +--------+--------+--------+--------+
147 // | Stmt | YES | NO | NO | 295 // | Stmt | YES | NO | NO |
148 // T +--------+--------+--------+--------+ 296 // T +--------+--------+--------+--------+
149 // 297 //
150 // The goal is not lose any statement positions and not lose useful 298 // The goal is not lose any statement positions and not lose useful
151 // expression positions. Whenever the last bytecode is elided it's 299 // expression positions. Whenever the last bytecode is elided it's
152 // source position information is applied to the current node 300 // source position information is applied to the current node
153 // updating it if necessary. 301 // updating it if necessary.
154 // 302 //
155 // The last bytecode can be elided for the MAYBE cases if the last 303 // The last bytecode can be elided for the MAYBE cases if the last
156 // bytecode is known not to throw. If it throws, the system would 304 // bytecode is known not to throw. If it throws, the system would
157 // not have correct stack trace information. The appropriate check 305 // not have correct stack trace information. The appropriate check
158 // for this would be Bytecodes::IsWithoutExternalSideEffects(), 306 // for this would be Bytecodes::IsWithoutExternalSideEffects().
159 // which is checked in
160 // BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes() to
161 // keep the check here simple.
162 // 307 //
163 // In rare cases, bytecode generation produces consecutive bytecodes 308 // In rare cases, bytecode generation produces consecutive bytecodes
164 // with the same expression positions. In principle, the latter of 309 // with the same expression positions. In principle, the latter of
165 // these can be elided, but would make this function more expensive. 310 // these can be elided, but would make this function more expensive.
166 // 311 //
167 return (!last_.source_info().is_valid() || 312 return (!last_.source_info().is_valid() ||
168 !current->source_info().is_valid()); 313 !current->source_info().is_valid());
169 } 314 }
170 315
171 namespace { 316 namespace {
(...skipping 11 matching lines...) Expand all
183 // which loads a global value into both a register and the 328 // which loads a global value into both a register and the
184 // accumulator. However, in the second form the Ldar can often be 329 // accumulator. However, in the second form the Ldar can often be
185 // peephole optimized away unlike the Star in the first form. 330 // peephole optimized away unlike the Star in the first form.
186 // 331 //
187 last->Transform(new_bytecode, current->operand(0)); 332 last->Transform(new_bytecode, current->operand(0));
188 current->set_bytecode(Bytecode::kLdar, current->operand(0)); 333 current->set_bytecode(Bytecode::kLdar, current->operand(0));
189 } 334 }
190 335
191 } // namespace 336 } // namespace
192 337
193 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( 338 void BytecodePeepholeOptimizer::DefaultAction(BytecodeNode* const node) {
194 BytecodeNode* const current) { 339 DCHECK(LastIsValid());
195 if (current->bytecode() == Bytecode::kStar && 340 DCHECK(!Bytecodes::IsJump(node->bytecode()));
196 !current->source_info().is_statement()) { 341
197 // Note: If the Star is tagged with a statement position, we can't 342 next_stage()->Write(last());
198 // perform this transform as the store to the register will 343 SetLast(node);
199 // have the wrong ordering for stepping in the debugger.
200 switch (last_.bytecode()) {
201 case Bytecode::kLdaNamedProperty:
202 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current);
203 return true;
204 case Bytecode::kLdaKeyedProperty:
205 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current);
206 return true;
207 case Bytecode::kLdaGlobal:
208 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current);
209 return true;
210 case Bytecode::kLdaContextSlot:
211 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current);
212 return true;
213 case Bytecode::kLdaUndefined:
214 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current);
215 return true;
216 default:
217 break;
218 }
219 }
220 return false;
221 } 344 }
222 345
223 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( 346 void BytecodePeepholeOptimizer::UpdateLastAction(BytecodeNode* const node) {
224 BytecodeNode* const current) { 347 DCHECK(!LastIsValid());
225 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && 348 DCHECK(!Bytecodes::IsJump(node->bytecode()));
226 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); 349
227 if (can_remove) { 350 SetLast(node);
228 // Conditional jumps with boolean conditions are emiitted in
229 // ToBoolean form by the bytecode array builder,
230 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
231 // element can be removed if the previous bytecode put a boolean
232 // value in the accumulator.
233 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
234 current->set_bytecode(jump, current->operand(0));
235 }
236 return can_remove;
237 } 351 }
238 352
239 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot( 353 void BytecodePeepholeOptimizer::ElideCurrentAction(BytecodeNode* const node) {
240 BytecodeNode* const current) { 354 DCHECK(LastIsValid());
241 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot && 355 DCHECK(!Bytecodes::IsJump(node->bytecode()));
242 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
243 if (can_remove) {
244 // Logical-nots are emitted in ToBoolean form by the bytecode array
245 // builder, The ToBoolean element can be removed if the previous bytecode
246 // put a boolean value in the accumulator.
247 current->set_bytecode(Bytecode::kLogicalNot);
248 }
249 return can_remove;
250 }
251 356
252 bool BytecodePeepholeOptimizer::TransformCurrentBytecode( 357 if (node->source_info().is_valid()) {
253 BytecodeNode* const current) { 358 // Preserve the source information by replacing the node bytecode
254 return RemoveToBooleanFromJump(current) || 359 // with a no op bytecode.
255 RemoveToBooleanFromLogicalNot(current); 360 node->set_bytecode(Bytecode::kNop);
256 } 361 DefaultAction(node);
257
258 bool BytecodePeepholeOptimizer::CanElideLast(
259 const BytecodeNode* const current) const {
260 if (last_.bytecode() == Bytecode::kNop) {
261 // Nop are placeholders for holding source position information.
262 return true;
263 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
264 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
265 // The accumulator is invisible to the debugger. If there is a sequence of
266 // consecutive accumulator loads (that don't have side effects) then only
267 // the final load is potentially visible.
268 return true;
269 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
270 AccumulatorUse::kWrite &&
271 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
272 // The current instruction clobbers the accumulator without reading it. The
273 // load in the last instruction can be elided as it has no effect.
274 return true;
275 } else { 362 } else {
276 return false; 363 // Nothing to do, keep last and wait for next bytecode to pair with it.
277 } 364 }
278 } 365 }
279 366
280 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { 367 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction(
281 TryToRemoveLastExpressionPosition(current); 368 BytecodeNode* const node) {
369 DCHECK(LastIsValid());
370 DCHECK(!Bytecodes::IsJump(node->bytecode()));
282 371
283 if (TransformCurrentBytecode(current) || 372 if (last()->operand(0) == node->operand(0)) {
284 TransformLastAndCurrentBytecodes(current)) { 373 ElideCurrentAction(node);
285 return current; 374 } else {
375 DefaultAction(node);
286 } 376 }
287
288 if (CanElideCurrent(current)) {
289 if (current->source_info().is_valid()) {
290 // Preserve the source information by replacing the current bytecode
291 // with a no op bytecode.
292 current->set_bytecode(Bytecode::kNop);
293 } else {
294 current = nullptr;
295 }
296 return current;
297 }
298
299 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) {
300 if (last_.source_info().is_valid()) {
301 // Current can not be valid per CanElideLastBasedOnSourcePosition().
302 current->source_info().Clone(last_.source_info());
303 }
304 InvalidateLast();
305 return current;
306 }
307
308 return current;
309 } 377 }
310 378
311 BytecodeNode* BytecodePeepholeOptimizer::OptimizeAndEmitLast( 379 void BytecodePeepholeOptimizer::ElideCurrentIfLoadingNameConstantAction(
312 BytecodeNode* current) { 380 BytecodeNode* const node) {
313 // Attempt optimization if there is an earlier node to optimize with. 381 DCHECK_EQ(last()->bytecode(), Bytecode::kLdaConstant);
314 if (LastIsValid()) { 382 DCHECK(!Bytecodes::IsJump(node->bytecode()));
315 current = Optimize(current); 383
316 // Only output the last node if it wasn't invalidated by the optimization. 384 if (GetConstantForIndexOperand(last(), 0)->IsName()) {
317 if (LastIsValid()) { 385 ElideCurrentAction(node);
318 next_stage_->Write(&last_); 386 } else {
319 InvalidateLast(); 387 DefaultAction(node);
388 }
389 }
390
391 void BytecodePeepholeOptimizer::ElideLastAction(BytecodeNode* const node) {
392 DCHECK(LastIsValid());
393 DCHECK(!Bytecodes::IsJump(node->bytecode()));
394
395 if (CanElideLastBasedOnSourcePosition(node)) {
396 if (last()->source_info().is_valid()) {
397 // Node can not be valid per CanElideLastBasedOnSourcePosition().
398 node->source_info().Clone(last()->source_info());
320 } 399 }
400 SetLast(node);
401 } else {
402 DefaultAction(node);
321 } 403 }
322 return current; 404 }
405
406 void BytecodePeepholeOptimizer::ChangeBytecodeAction(BytecodeNode* node,
407 Bytecode replacement) {
408 DCHECK(LastIsValid());
409 DCHECK(!Bytecodes::IsJump(node->bytecode()));
410
411 node->set_bytecode(replacement);
412 DefaultAction(node);
413 }
414
415 void BytecodePeepholeOptimizer::TransformLdaStarToLdrLdarAction(
416 BytecodeNode* node, Bytecode replacement) {
417 DCHECK(LastIsValid());
418 DCHECK(!Bytecodes::IsJump(node->bytecode()));
419
420 if (!node->source_info().is_statement()) {
421 TransformLdaStarToLdrLdar(replacement, last(), node);
422 }
423 DefaultAction(node);
424 }
425
426 void BytecodePeepholeOptimizer::DefaultJumpAction(BytecodeNode* node) {
427 DCHECK(LastIsValid());
428 DCHECK(Bytecodes::IsJump(node->bytecode()));
429
430 next_stage()->Write(last());
431 InvalidateLast();
432 }
433
434 void BytecodePeepholeOptimizer::UpdateLastJumpAction(BytecodeNode* node) {
435 DCHECK(!LastIsValid());
436 DCHECK(Bytecodes::IsJump(node->bytecode()));
437 }
438
439 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction(BytecodeNode* node,
440 Bytecode replacement) {
441 DCHECK(LastIsValid());
442 DCHECK(Bytecodes::IsJump(node->bytecode()));
443
444 next_stage()->Write(last());
445 InvalidateLast();
446 node->set_bytecode(replacement, node->operand(0));
447 }
448
449 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction(BytecodeNode* node) {
450 DCHECK(LastIsValid());
451 DCHECK(Bytecodes::IsJump(node->bytecode()));
452
453 if (!node->source_info().is_valid()) {
454 node->source_info().Clone(last()->source_info());
455 } else {
456 next_stage()->Write(last());
457 }
458 InvalidateLast();
459 }
460
461 void BytecodePeepholeOptimizer::Optimize(BytecodeNode* const node) {
462 // A single table is used for looking up peephole optimization
463 // matches as it is observed to have better performance. This is
464 // inspite of the fact that jump bytecodes and non-jump bytecodes
465 // have different processing logic, in particular a jump bytecode
466 // always needs to emit the jump via WriteJump().
467 const PeepholeActionAndData* const action_data =
468 PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode());
rmcilroy 2016/07/04 12:45:46 You could possibly store function pointers in the
469 switch (action_data->action) {
470 case PeepholeAction::kDefaultAction:
471 DefaultAction(node);
472 break;
473 case PeepholeAction::kUpdateLastAction:
474 UpdateLastAction(node);
475 break;
476 case PeepholeAction::kElideCurrentAction:
477 ElideCurrentAction(node);
478 break;
479 case PeepholeAction::kElideCurrentIfOperand0MatchesAction:
480 ElideCurrentIfOperand0MatchesAction(node);
481 break;
482 case PeepholeAction::kElideCurrentIfLoadingNameConstantAction:
483 ElideCurrentIfLoadingNameConstantAction(node);
484 break;
485 case PeepholeAction::kElideLastAction:
486 ElideLastAction(node);
487 break;
488 case PeepholeAction::kChangeBytecodeAction:
489 ChangeBytecodeAction(node, action_data->bytecode);
490 break;
491 case PeepholeAction::kTransformLdaStarToLdrLdarAction:
492 TransformLdaStarToLdrLdarAction(node, action_data->bytecode);
493 break;
494 case PeepholeAction::kDefaultJumpAction:
495 DefaultJumpAction(node);
496 break;
497 case PeepholeAction::kUpdateLastJumpAction:
498 UpdateLastJumpAction(node);
499 break;
500 case PeepholeAction::kChangeJumpBytecodeAction:
501 ChangeJumpBytecodeAction(node, action_data->bytecode);
502 break;
503 case PeepholeAction::kElideLastBeforeJumpAction:
504 ElideLastBeforeJumpAction(node);
505 break;
506 default:
507 UNREACHABLE();
508 break;
509 }
323 } 510 }
324 511
325 } // namespace interpreter 512 } // namespace interpreter
326 } // namespace internal 513 } // namespace internal
327 } // namespace v8 514 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-peephole-optimizer.h ('k') | src/interpreter/bytecodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698