| // Copyright 2016 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/v8.h" |
| |
| #include "src/interpreter/bytecode-dead-code-optimizer.h" |
| #include "src/interpreter/bytecode-label.h" |
| #include "src/objects.h" |
| #include "test/unittests/test-utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace interpreter { |
| |
| class BytecodeDeadCodeOptimizerTest : public BytecodePipelineStage, |
| public TestWithIsolateAndZone { |
| public: |
| BytecodeDeadCodeOptimizerTest() : dead_code_optimizer_(this) {} |
| ~BytecodeDeadCodeOptimizerTest() override {} |
| |
| void Write(BytecodeNode* node) override { |
| write_count_++; |
| last_written_.Clone(node); |
| } |
| |
| void WriteJump(BytecodeNode* node, BytecodeLabel* label) override { |
| write_count_++; |
| last_written_.Clone(node); |
| } |
| |
| void BindLabel(BytecodeLabel* label) override {} |
| void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {} |
| Handle<BytecodeArray> ToBytecodeArray( |
| int fixed_register_count, int parameter_count, |
| Handle<FixedArray> handle_table) override { |
| return Handle<BytecodeArray>(); |
| } |
| |
| BytecodeDeadCodeOptimizer* optimizer() { return &dead_code_optimizer_; } |
| |
| int write_count() const { return write_count_; } |
| const BytecodeNode& last_written() const { return last_written_; } |
| |
| private: |
| BytecodeDeadCodeOptimizer dead_code_optimizer_; |
| |
| int write_count_ = 0; |
| BytecodeNode last_written_; |
| }; |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, LiveCodeKept) { |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(add, last_written()); |
| |
| BytecodeLabel target; |
| BytecodeNode jump(Bytecode::kJump, 0); |
| optimizer()->WriteJump(&jump, &target); |
| CHECK_EQ(write_count(), 2); |
| CHECK_EQ(jump, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterReturnEliminated) { |
| BytecodeNode ret(Bytecode::kReturn); |
| optimizer()->Write(&ret); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterThrowEliminated) { |
| BytecodeNode thrw(Bytecode::kThrow); |
| optimizer()->Write(&thrw); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(thrw, last_written()); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(thrw, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterReThrowEliminated) { |
| BytecodeNode rethrow(Bytecode::kReThrow); |
| optimizer()->Write(&rethrow); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(rethrow, last_written()); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(rethrow, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterJumpEliminated) { |
| BytecodeLabel target; |
| BytecodeNode jump(Bytecode::kJump, 0); |
| optimizer()->WriteJump(&jump, &target); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(jump, last_written()); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(jump, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeStillDeadAfterConditinalJump) { |
| BytecodeNode ret(Bytecode::kReturn); |
| optimizer()->Write(&ret); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| |
| BytecodeLabel target; |
| BytecodeNode jump(Bytecode::kJumpIfTrue, 0); |
| optimizer()->WriteJump(&jump, &target); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| } |
| |
| TEST_F(BytecodeDeadCodeOptimizerTest, CodeLiveAfterLabelBind) { |
| BytecodeNode ret(Bytecode::kReturn); |
| optimizer()->Write(&ret); |
| CHECK_EQ(write_count(), 1); |
| CHECK_EQ(ret, last_written()); |
| |
| BytecodeLabel target; |
| optimizer()->BindLabel(&target); |
| |
| BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand()); |
| optimizer()->Write(&add); |
| CHECK_EQ(write_count(), 2); |
| CHECK_EQ(add, last_written()); |
| } |
| |
| } // namespace interpreter |
| } // namespace internal |
| } // namespace v8 |