| Index: src/interpreter/bytecode-peephole-optimizer.cc
|
| diff --git a/src/interpreter/bytecode-peephole-optimizer.cc b/src/interpreter/bytecode-peephole-optimizer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5621d2981b29699230c31ab995c1c7a4c0b452b2
|
| --- /dev/null
|
| +++ b/src/interpreter/bytecode-peephole-optimizer.cc
|
| @@ -0,0 +1,123 @@
|
| +// Copyright 2015 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/interpreter/bytecode-peephole-optimizer.h"
|
| +
|
| +#include "src/interpreter/constant-array-builder.h"
|
| +#include "src/objects-inl.h"
|
| +#include "src/objects.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace interpreter {
|
| +
|
| +BytecodePeepholeOptimizer::BytecodePeepholeOptimizer(
|
| + ConstantArrayBuilder* constant_array_builder, BytecodeWriter* output_writer)
|
| + : constant_array_builder_(constant_array_builder),
|
| + output_writer_(output_writer),
|
| + last_(nullptr),
|
| + last_is_discardable_(true) {}
|
| +
|
| +// override
|
| +size_t BytecodePeepholeOptimizer::FlushForOffset() {
|
| + size_t buffered_size = output_writer_->FlushForOffset();
|
| + if (last_ != nullptr) {
|
| + if (last_->bytecode() == Bytecode::kNop &&
|
| + !last_->source_info().is_statement()) {
|
| + last_->Release();
|
| + last_ = nullptr;
|
| + } else {
|
| + buffered_size += last_->Size();
|
| + last_is_discardable_ = false;
|
| + }
|
| + }
|
| + return buffered_size;
|
| +}
|
| +
|
| +// override
|
| +void BytecodePeepholeOptimizer::LeaveBasicBlock() {
|
| + if (last_ != nullptr) {
|
| + output_writer_->Write(last_);
|
| + last_ = nullptr;
|
| + }
|
| + last_is_discardable_ = false;
|
| + output_writer_->LeaveBasicBlock();
|
| +}
|
| +
|
| +// override
|
| +void BytecodePeepholeOptimizer::Write(BytecodeNode* node) {
|
| + // Attempt optimization if there is an earlier node to optimize with.
|
| + if (last_ != nullptr) {
|
| + node = Optimize(node);
|
| + }
|
| +
|
| + // Only output if optimization did not remove earlier node.
|
| + if (last_ != nullptr) {
|
| + output_writer_->Write(last_);
|
| + }
|
| +
|
| + last_ = node;
|
| + last_is_discardable_ = true;
|
| +}
|
| +
|
| +Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand(
|
| + const BytecodeNode* const node, int index) const {
|
| + DCHECK_LE(index, node->operand_count());
|
| + DCHECK_EQ(Bytecodes::GetOperandType(node->bytecode(), 0), OperandType::kIdx);
|
| + uint32_t index_operand = node->operands()[0];
|
| + return constant_array_builder_->At(index_operand);
|
| +}
|
| +
|
| +BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
|
| + DCHECK_NE(current, last_);
|
| +
|
| + // The current node can always be discarded here. The last node
|
| + // can only be discarded if last_is_discardable_ == true.
|
| + if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
|
| + Bytecodes::WritesAccumulatorWithBoolean(last_->bytecode())) {
|
| + current->set_bytecode(
|
| + Bytecodes::GetJumpWithoutToBoolean(current->bytecode()),
|
| + current->operands()[0], current->operand_scale());
|
| + return current;
|
| + } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
|
| + Bytecodes::IsAccumulatorLoadWithoutEffects(last_->bytecode()) &&
|
| + last_is_discardable_) {
|
| + last_->Release();
|
| + last_ = nullptr;
|
| + } else if ((last_->bytecode() == Bytecode::kLdar ||
|
| + last_->bytecode() == Bytecode::kStar) &&
|
| + (current->bytecode() == Bytecode::kLdar ||
|
| + current->bytecode() == Bytecode::kStar) &&
|
| + current->operands()[0] == last_->operands()[0]) {
|
| + // The current operation is moot as the last has performed desired effect.
|
| + // If current bytecode has a source position, change it to a nop, else it
|
| + // can be discarded. The next call to Optimize will try to remove the nop.
|
| + if (current->source_info().is_valid()) {
|
| + current->set_bytecode(Bytecode::kNop);
|
| + } else {
|
| + current->Release();
|
| + current = nullptr;
|
| + }
|
| + } else if (last_->bytecode() == Bytecode::kNop && last_is_discardable_) {
|
| + if (last_->source_info().is_valid()) {
|
| + current->source_info().Update(last_->source_info());
|
| + }
|
| + last_->Release();
|
| + last_ = nullptr;
|
| + } else if (current->bytecode() == Bytecode::kToName &&
|
| + !current->source_info().is_statement()) {
|
| + if (last_->bytecode() == Bytecode::kToName ||
|
| + last_->bytecode() == Bytecode::kTypeOf ||
|
| + (last_->bytecode() == Bytecode::kLdaConstant &&
|
| + GetConstantForIndexOperand(last_, 0)->IsName())) {
|
| + current->Release();
|
| + current = nullptr;
|
| + }
|
| + }
|
| + return current;
|
| +}
|
| +
|
| +} // namespace interpreter
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|