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

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

Issue 1985753002: [interpreter] Introduce fused bytecodes for common sequences. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase onto oth-0058-peephole-fix. Created 4 years, 7 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 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
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(
rmcilroy 2016/05/24 10:53:56 nit MaybeRemoveLastExpressionPosition
oth 2016/05/24 13:37:12 IMO The prefix TryTo better fits what the function
rmcilroy 2016/05/24 14:00:10 Acknowledged.
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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 // The last bytecode can be elided for the MAYBE cases if the last 155 // The last bytecode can be elided for the MAYBE cases if the last
173 // bytecode is known not to throw. If it throws, the system would 156 // bytecode is known not to throw. If it throws, the system would
174 // not have correct stack trace information. The appropriate check 157 // not have correct stack trace information. The appropriate check
175 // for this would be Bytecodes::IsWithoutExternalSideEffects(), but 158 // for this would be Bytecodes::IsWithoutExternalSideEffects(), but
176 // this is not performed here to keep the check simple. 159 // this is not performed here to keep the check simple.
177 // 160 //
178 return (!last_.source_info().is_valid() || 161 return (!last_.source_info().is_valid() ||
179 !current->source_info().is_valid()); 162 !current->source_info().is_valid());
180 } 163 }
181 164
165 void BytecodePeepholeOptimizer::ChangeLoadStarToLdrLdar(
166 Bytecode new_bytecode, BytecodeNode* const current) {
167 last_.Transform(new_bytecode, current->operand(0), current->operand_scale());
168 current->set_bytecode(Bytecode::kLdar, current->operand(0),
169 current->operand_scale());
170 if (current->source_info().is_valid()) {
171 last_.source_info().Update(current->source_info());
rmcilroy 2016/05/24 10:53:56 nit - comment on why you move the source position
oth 2016/05/24 13:37:12 Done.
172 current->source_info().set_invalid();
173 }
174 }
175
176 bool BytecodePeepholeOptimizer::ChangeLoadToLdr(BytecodeNode* const current) {
177 if (current->bytecode() == Bytecode::kStar) {
178 switch (last_.bytecode()) {
179 case Bytecode::kLoadIC:
180 ChangeLoadStarToLdrLdar(Bytecode::kLdrNamedProperty, current);
181 return true;
182 case Bytecode::kKeyedLoadIC:
183 ChangeLoadStarToLdrLdar(Bytecode::kLdrKeyedProperty, current);
184 return true;
185 case Bytecode::kLdaGlobal:
186 ChangeLoadStarToLdrLdar(Bytecode::kLdrGlobal, current);
187 return true;
188 case Bytecode::kLdaContextSlot:
189 ChangeLoadStarToLdrLdar(Bytecode::kLdrContextSlot, current);
190 return true;
191 case Bytecode::kLdaUndefined:
192 ChangeLoadStarToLdrLdar(Bytecode::kLdrUndefined, current);
193 return true;
194 default:
195 break;
196 }
197 }
198 return false;
199 }
200
201 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
202 BytecodeNode* const current) {
203 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
204 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
205 if (can_remove) {
206 // Conditional jumps with boolean conditions are emiitted in
207 // ToBoolean form by the bytecode array builder,
208 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
209 // element can be removed if the previous bytecode put a boolean
210 // value in the accumulator.
211 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
212 current->set_bytecode(jump, current->operand(0), current->operand_scale());
213 }
214 return can_remove;
215 }
216
217 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
218 BytecodeNode* const current) {
219 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
220 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
221 if (can_remove) {
222 // Logical-nots are emitted in ToBoolean form by the bytecode array
223 // builder, The ToBoolean element can be removed if the previous bytecode
224 // put a boolean value in the accumulator.
225 current->set_bytecode(Bytecode::kLogicalNot);
226 }
227 return can_remove;
228 }
229
230 bool BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes(
rmcilroy 2016/05/24 10:53:56 nit - s/UpdateLastAndCurrentBytecodes/CanTransform
oth 2016/05/24 13:37:12 The prefix 'Can' suggests testing a property of th
rmcilroy 2016/05/24 14:00:10 OK, agree on "Can". I would still prefer Update is
oth 2016/05/24 15:07:14 Done.
231 BytecodeNode* const current) {
232 return RemoveToBooleanFromJump(current) ||
233 RemoveToBooleanFromLogicalNot(current) || ChangeLoadToLdr(current);
234 }
235
182 bool BytecodePeepholeOptimizer::CanElideLast( 236 bool BytecodePeepholeOptimizer::CanElideLast(
183 const BytecodeNode* const current) const { 237 const BytecodeNode* const current) const {
184 if (!last_is_discardable_) { 238 if (!last_is_discardable_) {
185 return false; 239 return false;
186 } 240 }
187 241
188 if (last_.bytecode() == Bytecode::kNop) { 242 if (last_.bytecode() == Bytecode::kNop) {
189 // Nop are placeholders for holding source position information. 243 // Nop are placeholders for holding source position information.
190 return true; 244 return true;
191 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && 245 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
192 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { 246 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
193 // The accumulator is invisible to the debugger. If there is a sequence of 247 // The accumulator is invisible to the debugger. If there is a sequence of
194 // consecutive accumulator loads (that don't have side effects) then only 248 // consecutive accumulator loads (that don't have side effects) then only
195 // the final load is potentially visible. 249 // the final load is potentially visible.
196 return true; 250 return true;
251 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
252 AccumulatorUse::kWrite &&
253 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
254 // The current instruction clobbers the accumulator without reading it. The
255 // load in the last instruction can be elided as it has no effect.
256 return true;
197 } else { 257 } else {
198 return false; 258 return false;
199 } 259 }
200 } 260 }
201 261
202 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { 262 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
203 UpdateLastAndCurrentBytecodes(current); 263 TryToRemoveLastExpressionPosition(current);
204 if (CanElideCurrent(current)) { 264
205 if (current->source_info().is_valid()) { 265 if (!UpdateLastAndCurrentBytecodes(current)) {
rmcilroy 2016/05/24 10:53:56 nit - rather than if nesting, how about early retu
oth 2016/05/24 13:37:12 Done generally have a mild leaning towards single
rmcilroy 2016/05/24 14:00:10 I agree in the general case, however I think this
206 current->set_bytecode(Bytecode::kNop); 266 if (CanElideCurrent(current)) {
207 } else { 267 if (current->source_info().is_valid()) {
208 current = nullptr; 268 current->set_bytecode(Bytecode::kNop);
269 } else {
270 current = nullptr;
271 }
272 } else if (CanElideLast(current) &&
273 CanElideLastBasedOnSourcePosition(current)) {
274 current->source_info().Update(last_.source_info());
275 InvalidateLast();
209 } 276 }
210 } else if (CanElideLast(current) &&
211 CanElideLastBasedOnSourcePosition(current)) {
212 current->source_info().Update(last_.source_info());
213 InvalidateLast();
214 } 277 }
215 return current; 278 return current;
216 } 279 }
217 280
218 } // namespace interpreter 281 } // namespace interpreter
219 } // namespace internal 282 } // namespace internal
220 } // namespace v8 283 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698