| OLD | NEW |
| 1 // Copyright 2016 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/objects-inl.h" | 7 #include "src/objects-inl.h" |
| 8 #include "src/objects.h" | 8 #include "src/objects.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace interpreter { | 12 namespace interpreter { |
| 13 | 13 |
| 14 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( | 14 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( |
| 15 BytecodePipelineStage* next_stage) | 15 BytecodePipelineStage* next_stage) |
| 16 : next_stage_(next_stage), last_(Bytecode::kIllegal, BytecodeSourceInfo()) { | 16 : next_stage_(next_stage), |
| 17 last_(BytecodeNode::Illegal(BytecodeSourceInfo())) { |
| 17 InvalidateLast(); | 18 InvalidateLast(); |
| 18 } | 19 } |
| 19 | 20 |
| 20 // override | 21 // override |
| 21 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( | 22 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( |
| 22 Isolate* isolate, int register_count, int parameter_count, | 23 Isolate* isolate, int register_count, int parameter_count, |
| 23 Handle<FixedArray> handler_table) { | 24 Handle<FixedArray> handler_table) { |
| 24 Flush(); | 25 Flush(); |
| 25 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, | 26 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, |
| 26 handler_table); | 27 handler_table); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 } | 59 } |
| 59 | 60 |
| 60 void BytecodePeepholeOptimizer::Flush() { | 61 void BytecodePeepholeOptimizer::Flush() { |
| 61 if (LastIsValid()) { | 62 if (LastIsValid()) { |
| 62 next_stage_->Write(&last_); | 63 next_stage_->Write(&last_); |
| 63 InvalidateLast(); | 64 InvalidateLast(); |
| 64 } | 65 } |
| 65 } | 66 } |
| 66 | 67 |
| 67 void BytecodePeepholeOptimizer::InvalidateLast() { | 68 void BytecodePeepholeOptimizer::InvalidateLast() { |
| 68 last_.set_bytecode(Bytecode::kIllegal); | 69 last_ = BytecodeNode::Illegal(BytecodeSourceInfo()); |
| 69 } | 70 } |
| 70 | 71 |
| 71 bool BytecodePeepholeOptimizer::LastIsValid() const { | 72 bool BytecodePeepholeOptimizer::LastIsValid() const { |
| 72 return last_.bytecode() != Bytecode::kIllegal; | 73 return last_.bytecode() != Bytecode::kIllegal; |
| 73 } | 74 } |
| 74 | 75 |
| 75 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { | 76 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { |
| 76 // An action shouldn't leave a NOP as last bytecode unless it has | 77 // An action shouldn't leave a NOP as last bytecode unless it has |
| 77 // source position information. NOP without source information can | 78 // source position information. NOP without source information can |
| 78 // always be elided. | 79 // always be elided. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 109 // default, the upstream bytecode generator filters out unneeded | 110 // default, the upstream bytecode generator filters out unneeded |
| 110 // expression position information so there is neglible benefit to | 111 // expression position information so there is neglible benefit to |
| 111 // handling MAYBE specially. Hence MAYBE is treated the same as NO. | 112 // handling MAYBE specially. Hence MAYBE is treated the same as NO. |
| 112 // | 113 // |
| 113 return (!last_.source_info().is_valid() || | 114 return (!last_.source_info().is_valid() || |
| 114 !current->source_info().is_valid()); | 115 !current->source_info().is_valid()); |
| 115 } | 116 } |
| 116 | 117 |
| 117 namespace { | 118 namespace { |
| 118 | 119 |
| 119 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, | 120 BytecodeNode TransformLdaSmiBinaryOpToBinaryOpWithSmi( |
| 120 BytecodeNode* const last, | 121 Bytecode new_bytecode, BytecodeNode* const last, |
| 121 BytecodeNode* const current) { | 122 BytecodeNode* const current) { |
| 122 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); | 123 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); |
| 123 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0), | 124 BytecodeNode node(new_bytecode, last->operand(0), current->operand(0), |
| 124 current->operand(1)); | 125 current->operand(1), current->source_info()); |
| 125 if (last->source_info().is_valid()) { | 126 if (last->source_info().is_valid()) { |
| 126 current->set_source_info(last->source_info()); | 127 node.set_source_info(last->source_info()); |
| 127 } | 128 } |
| 129 return node; |
| 128 } | 130 } |
| 129 | 131 |
| 130 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, | 132 BytecodeNode TransformLdaZeroBinaryOpToBinaryOpWithZero( |
| 131 BytecodeNode* const last, | 133 Bytecode new_bytecode, BytecodeNode* const last, |
| 132 BytecodeNode* const current) { | 134 BytecodeNode* const current) { |
| 133 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); | 135 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); |
| 134 current->set_bytecode(new_bytecode, 0, current->operand(0), | 136 BytecodeNode node(new_bytecode, 0, current->operand(0), current->operand(1), |
| 135 current->operand(1)); | 137 current->source_info()); |
| 136 if (last->source_info().is_valid()) { | 138 if (last->source_info().is_valid()) { |
| 137 current->set_source_info(last->source_info()); | 139 node.set_source_info(last->source_info()); |
| 138 } | 140 } |
| 141 return node; |
| 139 } | 142 } |
| 140 | 143 |
| 141 void TransformEqualityWithNullOrUndefinedToTestUndetectable( | 144 BytecodeNode TransformEqualityWithNullOrUndefinedToTestUndetectable( |
| 142 BytecodeNode* const last, BytecodeNode* const current) { | 145 BytecodeNode* const last, BytecodeNode* const current) { |
| 143 DCHECK((last->bytecode() == Bytecode::kLdaNull) || | 146 DCHECK((last->bytecode() == Bytecode::kLdaNull) || |
| 144 (last->bytecode() == Bytecode::kLdaUndefined)); | 147 (last->bytecode() == Bytecode::kLdaUndefined)); |
| 145 DCHECK_EQ(current->bytecode(), Bytecode::kTestEqual); | 148 DCHECK_EQ(current->bytecode(), Bytecode::kTestEqual); |
| 146 current->set_bytecode(Bytecode::kTestUndetectable, current->operand(0)); | 149 BytecodeNode node(BytecodeNode::TestUndetectable(current->source_info(), |
| 150 current->operand(0))); |
| 147 if (last->source_info().is_valid()) { | 151 if (last->source_info().is_valid()) { |
| 148 current->set_source_info(last->source_info()); | 152 node.set_source_info(last->source_info()); |
| 149 } | 153 } |
| 154 return node; |
| 150 } | 155 } |
| 151 | 156 |
| 152 } // namespace | 157 } // namespace |
| 153 | 158 |
| 154 void BytecodePeepholeOptimizer::DefaultAction( | 159 void BytecodePeepholeOptimizer::DefaultAction( |
| 155 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 160 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 156 DCHECK(LastIsValid()); | 161 DCHECK(LastIsValid()); |
| 157 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 162 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 158 | 163 |
| 159 next_stage()->Write(last()); | 164 next_stage()->Write(last()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 179 } | 184 } |
| 180 | 185 |
| 181 void BytecodePeepholeOptimizer::ElideCurrentAction( | 186 void BytecodePeepholeOptimizer::ElideCurrentAction( |
| 182 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 187 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 183 DCHECK(LastIsValid()); | 188 DCHECK(LastIsValid()); |
| 184 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 189 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 185 | 190 |
| 186 if (node->source_info().is_valid()) { | 191 if (node->source_info().is_valid()) { |
| 187 // Preserve the source information by replacing the node bytecode | 192 // Preserve the source information by replacing the node bytecode |
| 188 // with a no op bytecode. | 193 // with a no op bytecode. |
| 189 node->set_bytecode(Bytecode::kNop); | 194 BytecodeNode new_node(BytecodeNode::Nop(node->source_info())); |
| 190 DefaultAction(node); | 195 DefaultAction(&new_node); |
| 191 } else { | 196 } else { |
| 192 // Nothing to do, keep last and wait for next bytecode to pair with it. | 197 // Nothing to do, keep last and wait for next bytecode to pair with it. |
| 193 } | 198 } |
| 194 } | 199 } |
| 195 | 200 |
| 196 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( | 201 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( |
| 197 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 202 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 198 DCHECK(LastIsValid()); | 203 DCHECK(LastIsValid()); |
| 199 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 204 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 200 | 205 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 DefaultAction(node); | 237 DefaultAction(node); |
| 233 } | 238 } |
| 234 | 239 |
| 235 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction( | 240 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction( |
| 236 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 241 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 237 DCHECK(LastIsValid()); | 242 DCHECK(LastIsValid()); |
| 238 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 243 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 239 | 244 |
| 240 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | 245 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { |
| 241 // Fused last and current into current. | 246 // Fused last and current into current. |
| 242 TransformLdaSmiBinaryOpToBinaryOpWithSmi(action_data->bytecode, last(), | 247 BytecodeNode new_node(TransformLdaSmiBinaryOpToBinaryOpWithSmi( |
| 243 node); | 248 action_data->bytecode, last(), node)); |
| 244 SetLast(node); | 249 SetLast(&new_node); |
| 245 } else { | 250 } else { |
| 246 DefaultAction(node); | 251 DefaultAction(node); |
| 247 } | 252 } |
| 248 } | 253 } |
| 249 | 254 |
| 250 void BytecodePeepholeOptimizer:: | 255 void BytecodePeepholeOptimizer:: |
| 251 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction( | 256 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction( |
| 252 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 257 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 253 DCHECK(LastIsValid()); | 258 DCHECK(LastIsValid()); |
| 254 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 259 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 255 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | 260 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { |
| 256 // Fused last and current into current. | 261 // Fused last and current into current. |
| 257 TransformLdaZeroBinaryOpToBinaryOpWithZero(action_data->bytecode, last(), | 262 BytecodeNode new_node(TransformLdaZeroBinaryOpToBinaryOpWithZero( |
| 258 node); | 263 action_data->bytecode, last(), node)); |
| 259 SetLast(node); | 264 SetLast(&new_node); |
| 260 } else { | 265 } else { |
| 261 DefaultAction(node); | 266 DefaultAction(node); |
| 262 } | 267 } |
| 263 } | 268 } |
| 264 | 269 |
| 265 void BytecodePeepholeOptimizer:: | 270 void BytecodePeepholeOptimizer:: |
| 266 TransformEqualityWithNullOrUndefinedToTestUndetectableAction( | 271 TransformEqualityWithNullOrUndefinedToTestUndetectableAction( |
| 267 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 272 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 268 DCHECK(LastIsValid()); | 273 DCHECK(LastIsValid()); |
| 269 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 274 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 270 // Fused last and current into current. | 275 // Fused last and current into current. |
| 271 TransformEqualityWithNullOrUndefinedToTestUndetectable(last(), node); | 276 BytecodeNode new_node( |
| 272 SetLast(node); | 277 TransformEqualityWithNullOrUndefinedToTestUndetectable(last(), node)); |
| 278 SetLast(&new_node); |
| 273 } | 279 } |
| 274 | 280 |
| 275 void BytecodePeepholeOptimizer::DefaultJumpAction( | 281 void BytecodePeepholeOptimizer::DefaultJumpAction( |
| 276 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 282 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 277 DCHECK(LastIsValid()); | 283 DCHECK(LastIsValid()); |
| 278 DCHECK(Bytecodes::IsJump(node->bytecode())); | 284 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 279 | 285 |
| 280 next_stage()->Write(last()); | 286 next_stage()->Write(last()); |
| 281 InvalidateLast(); | 287 InvalidateLast(); |
| 282 } | 288 } |
| 283 | 289 |
| 284 void BytecodePeepholeOptimizer::UpdateLastJumpAction( | 290 void BytecodePeepholeOptimizer::UpdateLastJumpAction( |
| 285 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 291 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 286 DCHECK(!LastIsValid()); | 292 DCHECK(!LastIsValid()); |
| 287 DCHECK(Bytecodes::IsJump(node->bytecode())); | 293 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 288 } | 294 } |
| 289 | 295 |
| 290 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction( | 296 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction( |
| 291 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 297 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 292 DCHECK(LastIsValid()); | 298 DCHECK(LastIsValid()); |
| 293 DCHECK(Bytecodes::IsJump(node->bytecode())); | 299 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 294 | 300 |
| 295 next_stage()->Write(last()); | 301 next_stage()->Write(last()); |
| 296 InvalidateLast(); | 302 InvalidateLast(); |
| 297 node->set_bytecode(action_data->bytecode, node->operand(0)); | 303 node->replace_bytecode(action_data->bytecode); |
| 298 } | 304 } |
| 299 | 305 |
| 300 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( | 306 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( |
| 301 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 307 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 302 DCHECK(LastIsValid()); | 308 DCHECK(LastIsValid()); |
| 303 DCHECK(Bytecodes::IsJump(node->bytecode())); | 309 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 304 | 310 |
| 305 if (!CanElideLastBasedOnSourcePosition(node)) { | 311 if (!CanElideLastBasedOnSourcePosition(node)) { |
| 306 next_stage()->Write(last()); | 312 next_stage()->Write(last()); |
| 307 } else if (!node->source_info().is_valid()) { | 313 } else if (!node->source_info().is_valid()) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 327 #undef CASE | 333 #undef CASE |
| 328 default: | 334 default: |
| 329 UNREACHABLE(); | 335 UNREACHABLE(); |
| 330 break; | 336 break; |
| 331 } | 337 } |
| 332 } | 338 } |
| 333 | 339 |
| 334 } // namespace interpreter | 340 } // namespace interpreter |
| 335 } // namespace internal | 341 } // namespace internal |
| 336 } // namespace v8 | 342 } // namespace v8 |
| OLD | NEW |