| 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/factory.h" | 7 #include "src/factory.h" |
| 8 #include "src/interpreter/bytecode-label.h" |
| 8 #include "src/interpreter/bytecode-peephole-optimizer.h" | 9 #include "src/interpreter/bytecode-peephole-optimizer.h" |
| 9 #include "src/interpreter/constant-array-builder.h" | 10 #include "src/interpreter/constant-array-builder.h" |
| 10 #include "src/objects-inl.h" | 11 #include "src/objects-inl.h" |
| 11 #include "src/objects.h" | 12 #include "src/objects.h" |
| 12 #include "test/unittests/test-utils.h" | 13 #include "test/unittests/test-utils.h" |
| 13 | 14 |
| 14 namespace v8 { | 15 namespace v8 { |
| 15 namespace internal { | 16 namespace internal { |
| 16 namespace interpreter { | 17 namespace interpreter { |
| 17 | 18 |
| 18 class BytecodePeepholeOptimizerTest : public BytecodePipelineStage, | 19 class BytecodePeepholeOptimizerTest : public BytecodePipelineStage, |
| 19 public TestWithIsolateAndZone { | 20 public TestWithIsolateAndZone { |
| 20 public: | 21 public: |
| 21 BytecodePeepholeOptimizerTest() | 22 BytecodePeepholeOptimizerTest() |
| 22 : constant_array_builder_(isolate(), zone()), | 23 : constant_array_builder_(isolate(), zone()), |
| 23 peephole_optimizer_(&constant_array_builder_, this) {} | 24 peephole_optimizer_(&constant_array_builder_, this) {} |
| 24 ~BytecodePeepholeOptimizerTest() override {} | 25 ~BytecodePeepholeOptimizerTest() override {} |
| 25 | 26 |
| 26 size_t FlushForOffset() override { | |
| 27 flush_for_offset_count_++; | |
| 28 return 0; | |
| 29 }; | |
| 30 | |
| 31 void FlushBasicBlock() override { flush_basic_block_count_++; } | |
| 32 | |
| 33 void Write(BytecodeNode* node) override { | 27 void Write(BytecodeNode* node) override { |
| 34 write_count_++; | 28 write_count_++; |
| 35 last_written_.Clone(node); | 29 last_written_.Clone(node); |
| 36 } | 30 } |
| 37 | 31 |
| 32 void WriteJump(BytecodeNode* node, BytecodeLabel* label) override { |
| 33 write_count_++; |
| 34 last_written_.Clone(node); |
| 35 } |
| 36 |
| 37 void BindLabel(BytecodeLabel* label) override {} |
| 38 void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {} |
| 39 Handle<BytecodeArray> ToBytecodeArray( |
| 40 int fixed_register_count, int parameter_count, |
| 41 Handle<FixedArray> handle_table) override { |
| 42 return Handle<BytecodeArray>(); |
| 43 } |
| 44 |
| 45 void Flush() { |
| 46 optimizer()->ToBytecodeArray(0, 0, factory()->empty_fixed_array()); |
| 47 } |
| 48 |
| 38 BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; } | 49 BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; } |
| 39 ConstantArrayBuilder* constant_array() { return &constant_array_builder_; } | 50 ConstantArrayBuilder* constant_array() { return &constant_array_builder_; } |
| 40 | 51 |
| 41 int flush_for_offset_count() const { return flush_for_offset_count_; } | |
| 42 int flush_basic_block_count() const { return flush_basic_block_count_; } | |
| 43 int write_count() const { return write_count_; } | 52 int write_count() const { return write_count_; } |
| 44 const BytecodeNode& last_written() const { return last_written_; } | 53 const BytecodeNode& last_written() const { return last_written_; } |
| 45 | 54 |
| 46 private: | 55 private: |
| 47 ConstantArrayBuilder constant_array_builder_; | 56 ConstantArrayBuilder constant_array_builder_; |
| 48 BytecodePeepholeOptimizer peephole_optimizer_; | 57 BytecodePeepholeOptimizer peephole_optimizer_; |
| 49 | 58 |
| 50 int flush_for_offset_count_ = 0; | |
| 51 int flush_basic_block_count_ = 0; | |
| 52 int write_count_ = 0; | 59 int write_count_ = 0; |
| 53 BytecodeNode last_written_; | 60 BytecodeNode last_written_; |
| 54 }; | 61 }; |
| 55 | 62 |
| 56 // Sanity tests. | 63 // Sanity tests. |
| 57 | 64 |
| 58 TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetPassThrough) { | 65 TEST_F(BytecodePeepholeOptimizerTest, FlushOnJump) { |
| 59 CHECK_EQ(flush_for_offset_count(), 0); | 66 CHECK_EQ(write_count(), 0); |
| 60 CHECK_EQ(optimizer()->FlushForOffset(), 0); | 67 |
| 61 CHECK_EQ(flush_for_offset_count(), 1); | 68 BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), |
| 69 OperandScale::kSingle); |
| 70 optimizer()->Write(&add); |
| 71 CHECK_EQ(write_count(), 0); |
| 72 |
| 73 BytecodeLabel target; |
| 74 BytecodeNode jump(Bytecode::kJump, 0, OperandScale::kSingle); |
| 75 optimizer()->WriteJump(&jump, &target); |
| 76 CHECK_EQ(write_count(), 2); |
| 77 CHECK_EQ(jump, last_written()); |
| 62 } | 78 } |
| 63 | 79 |
| 64 TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetRightSize) { | 80 TEST_F(BytecodePeepholeOptimizerTest, FlushOnBind) { |
| 65 BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(), | |
| 66 OperandScale::kQuadruple); | |
| 67 optimizer()->Write(&node); | |
| 68 CHECK_EQ(optimizer()->FlushForOffset(), node.Size()); | |
| 69 CHECK_EQ(flush_for_offset_count(), 1); | |
| 70 CHECK_EQ(write_count(), 0); | 81 CHECK_EQ(write_count(), 0); |
| 82 |
| 83 BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), |
| 84 OperandScale::kSingle); |
| 85 optimizer()->Write(&add); |
| 86 CHECK_EQ(write_count(), 0); |
| 87 |
| 88 BytecodeLabel target; |
| 89 optimizer()->BindLabel(&target); |
| 90 CHECK_EQ(write_count(), 1); |
| 91 CHECK_EQ(add, last_written()); |
| 71 } | 92 } |
| 72 | 93 |
| 73 TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNop) { | 94 // Nop elimination tests. |
| 74 BytecodeNode node(Bytecode::kNop); | 95 |
| 75 optimizer()->Write(&node); | 96 TEST_F(BytecodePeepholeOptimizerTest, ElideEmptyNop) { |
| 76 CHECK_EQ(optimizer()->FlushForOffset(), 0); | 97 BytecodeNode nop(Bytecode::kNop); |
| 77 CHECK_EQ(flush_for_offset_count(), 1); | 98 optimizer()->Write(&nop); |
| 78 CHECK_EQ(write_count(), 0); | 99 BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), |
| 100 OperandScale::kSingle); |
| 101 optimizer()->Write(&add); |
| 102 Flush(); |
| 103 CHECK_EQ(write_count(), 1); |
| 104 CHECK_EQ(add, last_written()); |
| 79 } | 105 } |
| 80 | 106 |
| 81 TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopExpression) { | 107 TEST_F(BytecodePeepholeOptimizerTest, ElideExpressionNop) { |
| 82 BytecodeNode node(Bytecode::kNop); | 108 BytecodeNode nop(Bytecode::kNop); |
| 83 node.source_info().Update({3, false}); | 109 nop.source_info().Update({3, false}); |
| 84 optimizer()->Write(&node); | 110 optimizer()->Write(&nop); |
| 85 CHECK_EQ(optimizer()->FlushForOffset(), 0); | 111 BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), |
| 86 CHECK_EQ(flush_for_offset_count(), 1); | 112 OperandScale::kSingle); |
| 87 CHECK_EQ(write_count(), 0); | 113 optimizer()->Write(&add); |
| 114 Flush(); |
| 115 CHECK_EQ(write_count(), 1); |
| 116 CHECK_EQ(add, last_written()); |
| 88 } | 117 } |
| 89 | 118 |
| 90 TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopStatement) { | 119 TEST_F(BytecodePeepholeOptimizerTest, KeepStatementNop) { |
| 91 BytecodeNode node(Bytecode::kNop); | 120 BytecodeNode nop(Bytecode::kNop); |
| 92 node.source_info().Update({3, true}); | 121 nop.source_info().Update({3, true}); |
| 93 optimizer()->Write(&node); | 122 optimizer()->Write(&nop); |
| 94 CHECK_EQ(optimizer()->FlushForOffset(), node.Size()); | 123 BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), |
| 95 CHECK_EQ(flush_for_offset_count(), 1); | 124 OperandScale::kSingle); |
| 96 CHECK_EQ(write_count(), 0); | 125 add.source_info().Update({3, false}); |
| 97 } | 126 optimizer()->Write(&add); |
| 98 | 127 Flush(); |
| 99 TEST_F(BytecodePeepholeOptimizerTest, FlushBasicBlockPassThrough) { | 128 CHECK_EQ(write_count(), 2); |
| 100 CHECK_EQ(flush_basic_block_count(), 0); | 129 CHECK_EQ(add, last_written()); |
| 101 optimizer()->FlushBasicBlock(); | |
| 102 CHECK_EQ(flush_basic_block_count(), 1); | |
| 103 CHECK_EQ(write_count(), 0); | |
| 104 } | |
| 105 | |
| 106 TEST_F(BytecodePeepholeOptimizerTest, WriteOneFlushBasicBlock) { | |
| 107 BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(), | |
| 108 OperandScale::kQuadruple); | |
| 109 optimizer()->Write(&node); | |
| 110 CHECK_EQ(write_count(), 0); | |
| 111 optimizer()->FlushBasicBlock(); | |
| 112 CHECK_EQ(write_count(), 1); | |
| 113 CHECK_EQ(node, last_written()); | |
| 114 } | 130 } |
| 115 | 131 |
| 116 // Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode(). | 132 // Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode(). |
| 117 | 133 |
| 118 TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) { | 134 TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) { |
| 119 BytecodeNode first(Bytecode::kLdaNull); | 135 BytecodeNode first(Bytecode::kLdaNull); |
| 120 BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle); | 136 BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle); |
| 121 optimizer()->Write(&first); | 137 optimizer()->Write(&first); |
| 122 CHECK_EQ(write_count(), 0); | 138 CHECK_EQ(write_count(), 0); |
| 123 optimizer()->Write(&second); | 139 optimizer()->Write(&second); |
| 124 CHECK_EQ(write_count(), 1); | 140 CHECK_EQ(write_count(), 1); |
| 125 CHECK_EQ(last_written(), first); | 141 CHECK_EQ(last_written(), first); |
| 126 optimizer()->FlushBasicBlock(); | 142 Flush(); |
| 127 CHECK_EQ(write_count(), 2); | 143 CHECK_EQ(write_count(), 2); |
| 128 CHECK_EQ(last_written(), second); | 144 CHECK_EQ(last_written(), second); |
| 129 } | 145 } |
| 130 | 146 |
| 131 TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) { | 147 TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) { |
| 132 BytecodeNode first(Bytecode::kLdaTrue); | 148 BytecodeNode first(Bytecode::kLdaTrue); |
| 133 BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle); | 149 BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle); |
| 134 optimizer()->Write(&first); | 150 optimizer()->Write(&first); |
| 135 CHECK_EQ(write_count(), 0); | 151 CHECK_EQ(write_count(), 0); |
| 136 optimizer()->Write(&second); | 152 optimizer()->Write(&second); |
| 137 CHECK_EQ(write_count(), 1); | 153 CHECK_EQ(write_count(), 1); |
| 138 CHECK_EQ(last_written(), first); | 154 CHECK_EQ(last_written(), first); |
| 139 optimizer()->FlushBasicBlock(); | 155 Flush(); |
| 140 CHECK_EQ(write_count(), 2); | 156 CHECK_EQ(write_count(), 2); |
| 141 CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue); | 157 CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue); |
| 142 CHECK_EQ(last_written().operand(0), second.operand(0)); | 158 CHECK_EQ(last_written().operand(0), second.operand(0)); |
| 143 } | 159 } |
| 144 | 160 |
| 145 TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) { | 161 TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) { |
| 146 BytecodeNode first(Bytecode::kLdaNull); | 162 BytecodeNode first(Bytecode::kLdaNull); |
| 147 BytecodeNode second(Bytecode::kToBooleanLogicalNot); | 163 BytecodeNode second(Bytecode::kToBooleanLogicalNot); |
| 148 optimizer()->Write(&first); | 164 optimizer()->Write(&first); |
| 149 CHECK_EQ(write_count(), 0); | 165 CHECK_EQ(write_count(), 0); |
| 150 optimizer()->Write(&second); | 166 optimizer()->Write(&second); |
| 151 CHECK_EQ(write_count(), 1); | 167 CHECK_EQ(write_count(), 1); |
| 152 CHECK_EQ(last_written(), first); | 168 CHECK_EQ(last_written(), first); |
| 153 optimizer()->FlushBasicBlock(); | 169 Flush(); |
| 154 CHECK_EQ(write_count(), 2); | 170 CHECK_EQ(write_count(), 2); |
| 155 CHECK_EQ(last_written(), second); | 171 CHECK_EQ(last_written(), second); |
| 156 } | 172 } |
| 157 | 173 |
| 158 TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) { | 174 TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) { |
| 159 BytecodeNode first(Bytecode::kLdaTrue); | 175 BytecodeNode first(Bytecode::kLdaTrue); |
| 160 BytecodeNode second(Bytecode::kToBooleanLogicalNot); | 176 BytecodeNode second(Bytecode::kToBooleanLogicalNot); |
| 161 optimizer()->Write(&first); | 177 optimizer()->Write(&first); |
| 162 CHECK_EQ(write_count(), 0); | 178 CHECK_EQ(write_count(), 0); |
| 163 optimizer()->Write(&second); | 179 optimizer()->Write(&second); |
| 164 CHECK_EQ(write_count(), 1); | 180 CHECK_EQ(write_count(), 1); |
| 165 CHECK_EQ(last_written(), first); | 181 CHECK_EQ(last_written(), first); |
| 166 optimizer()->FlushBasicBlock(); | 182 Flush(); |
| 167 CHECK_EQ(write_count(), 2); | 183 CHECK_EQ(write_count(), 2); |
| 168 CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot); | 184 CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot); |
| 169 } | 185 } |
| 170 | 186 |
| 171 // Tests covering BytecodePeepholeOptimizer::CanElideCurrent(). | 187 // Tests covering BytecodePeepholeOptimizer::CanElideCurrent(). |
| 172 | 188 |
| 173 TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRy) { | 189 TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRy) { |
| 174 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), | 190 BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(), |
| 175 OperandScale::kSingle); | 191 OperandScale::kSingle); |
| 176 BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand(), | 192 BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand(), |
| 177 OperandScale::kSingle); | 193 OperandScale::kSingle); |
| 178 optimizer()->Write(&first); | 194 optimizer()->Write(&first); |
| 179 optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|. | |
| 180 CHECK_EQ(write_count(), 0); | 195 CHECK_EQ(write_count(), 0); |
| 181 optimizer()->Write(&second); | 196 optimizer()->Write(&second); |
| 182 CHECK_EQ(write_count(), 1); | 197 CHECK_EQ(write_count(), 1); |
| 183 CHECK_EQ(last_written(), first); | 198 CHECK_EQ(last_written(), first); |
| 184 optimizer()->FlushBasicBlock(); | 199 Flush(); |
| 185 CHECK_EQ(write_count(), 2); | 200 CHECK_EQ(write_count(), 2); |
| 186 CHECK_EQ(last_written(), second); | 201 CHECK_EQ(last_written(), second); |
| 187 } | 202 } |
| 188 | 203 |
| 189 TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRx) { | 204 TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRx) { |
| 190 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), | 205 BytecodeLabel label; |
| 206 BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(), |
| 191 OperandScale::kSingle); | 207 OperandScale::kSingle); |
| 192 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), | 208 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), |
| 193 OperandScale::kSingle); | 209 OperandScale::kSingle); |
| 194 optimizer()->Write(&first); | 210 optimizer()->Write(&first); |
| 195 CHECK_EQ(write_count(), 0); | 211 CHECK_EQ(write_count(), 0); |
| 196 optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|. | |
| 197 optimizer()->Write(&second); | 212 optimizer()->Write(&second); |
| 198 CHECK_EQ(write_count(), 1); | 213 CHECK_EQ(write_count(), 1); |
| 199 CHECK_EQ(last_written(), first); | 214 CHECK_EQ(last_written(), first); |
| 200 optimizer()->FlushBasicBlock(); | 215 Flush(); |
| 201 CHECK_EQ(write_count(), 1); | 216 CHECK_EQ(write_count(), 1); |
| 202 } | 217 } |
| 203 | 218 |
| 204 TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatement) { | 219 TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatement) { |
| 205 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), | 220 BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(), |
| 206 OperandScale::kSingle); | 221 OperandScale::kSingle); |
| 207 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), | 222 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), |
| 208 OperandScale::kSingle); | 223 OperandScale::kSingle); |
| 209 second.source_info().Update({0, true}); | 224 second.source_info().Update({0, true}); |
| 210 optimizer()->Write(&first); | 225 optimizer()->Write(&first); |
| 211 CHECK_EQ(write_count(), 0); | 226 CHECK_EQ(write_count(), 0); |
| 212 optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|. | |
| 213 optimizer()->Write(&second); | 227 optimizer()->Write(&second); |
| 214 CHECK_EQ(write_count(), 1); | 228 CHECK_EQ(write_count(), 1); |
| 215 CHECK_EQ(last_written(), first); | 229 CHECK_EQ(last_written(), first); |
| 216 optimizer()->FlushBasicBlock(); | 230 Flush(); |
| 217 CHECK_EQ(write_count(), 2); | 231 CHECK_EQ(write_count(), 2); |
| 218 CHECK_EQ(last_written().bytecode(), Bytecode::kNop); | 232 CHECK_EQ(last_written().bytecode(), Bytecode::kNop); |
| 219 CHECK_EQ(last_written().source_info(), second.source_info()); | 233 CHECK_EQ(last_written().source_info(), second.source_info()); |
| 220 } | 234 } |
| 221 | 235 |
| 222 TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatementStarRy) { | 236 TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatementStarRy) { |
| 223 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), | 237 BytecodeLabel label; |
| 238 BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(), |
| 224 OperandScale::kSingle); | 239 OperandScale::kSingle); |
| 225 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), | 240 BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), |
| 226 OperandScale::kSingle); | 241 OperandScale::kSingle); |
| 227 BytecodeNode third(Bytecode::kStar, Register(3).ToOperand(), | 242 BytecodeNode third(Bytecode::kStar, Register(3).ToOperand(), |
| 228 OperandScale::kSingle); | 243 OperandScale::kSingle); |
| 229 second.source_info().Update({0, true}); | 244 second.source_info().Update({0, true}); |
| 230 optimizer()->Write(&first); | 245 optimizer()->Write(&first); |
| 231 CHECK_EQ(write_count(), 0); | 246 CHECK_EQ(write_count(), 0); |
| 232 optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|. | |
| 233 optimizer()->Write(&second); | 247 optimizer()->Write(&second); |
| 234 CHECK_EQ(write_count(), 1); | 248 CHECK_EQ(write_count(), 1); |
| 235 CHECK_EQ(last_written(), first); | 249 CHECK_EQ(last_written(), first); |
| 236 optimizer()->Write(&third); | 250 optimizer()->Write(&third); |
| 237 CHECK_EQ(write_count(), 1); | 251 CHECK_EQ(write_count(), 1); |
| 238 optimizer()->FlushBasicBlock(); | 252 Flush(); |
| 239 CHECK_EQ(write_count(), 2); | 253 CHECK_EQ(write_count(), 2); |
| 240 // Source position should move |second| to |third| when |second| is elided. | 254 // Source position should move |second| to |third| when |second| is elided. |
| 241 third.source_info().Update(second.source_info()); | 255 third.source_info().Update(second.source_info()); |
| 242 CHECK_EQ(last_written(), third); | 256 CHECK_EQ(last_written(), third); |
| 243 } | 257 } |
| 244 | 258 |
| 245 TEST_F(BytecodePeepholeOptimizerTest, LdarToName) { | 259 TEST_F(BytecodePeepholeOptimizerTest, LdarToName) { |
| 246 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), | 260 BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), |
| 247 OperandScale::kSingle); | 261 OperandScale::kSingle); |
| 248 BytecodeNode second(Bytecode::kToName); | 262 BytecodeNode second(Bytecode::kToName); |
| 249 optimizer()->Write(&first); | 263 optimizer()->Write(&first); |
| 250 CHECK_EQ(write_count(), 0); | 264 CHECK_EQ(write_count(), 0); |
| 251 optimizer()->Write(&second); | 265 optimizer()->Write(&second); |
| 252 CHECK_EQ(write_count(), 1); | 266 CHECK_EQ(write_count(), 1); |
| 253 CHECK_EQ(last_written(), first); | 267 CHECK_EQ(last_written(), first); |
| 254 optimizer()->FlushBasicBlock(); | 268 Flush(); |
| 255 CHECK_EQ(write_count(), 2); | 269 CHECK_EQ(write_count(), 2); |
| 256 CHECK_EQ(last_written(), second); | 270 CHECK_EQ(last_written(), second); |
| 257 } | 271 } |
| 258 | 272 |
| 259 TEST_F(BytecodePeepholeOptimizerTest, ToNameToName) { | 273 TEST_F(BytecodePeepholeOptimizerTest, ToNameToName) { |
| 260 BytecodeNode first(Bytecode::kToName); | 274 BytecodeNode first(Bytecode::kToName); |
| 261 BytecodeNode second(Bytecode::kToName); | 275 BytecodeNode second(Bytecode::kToName); |
| 262 optimizer()->Write(&first); | 276 optimizer()->Write(&first); |
| 263 CHECK_EQ(write_count(), 0); | 277 CHECK_EQ(write_count(), 0); |
| 264 optimizer()->Write(&second); | 278 optimizer()->Write(&second); |
| 265 CHECK_EQ(write_count(), 1); | 279 CHECK_EQ(write_count(), 1); |
| 266 CHECK_EQ(last_written(), first); | 280 CHECK_EQ(last_written(), first); |
| 267 optimizer()->FlushBasicBlock(); | 281 Flush(); |
| 268 CHECK_EQ(write_count(), 1); | 282 CHECK_EQ(write_count(), 1); |
| 269 } | 283 } |
| 270 | 284 |
| 271 TEST_F(BytecodePeepholeOptimizerTest, TypeOfToName) { | 285 TEST_F(BytecodePeepholeOptimizerTest, TypeOfToName) { |
| 272 BytecodeNode first(Bytecode::kTypeOf); | 286 BytecodeNode first(Bytecode::kTypeOf); |
| 273 BytecodeNode second(Bytecode::kToName); | 287 BytecodeNode second(Bytecode::kToName); |
| 274 optimizer()->Write(&first); | 288 optimizer()->Write(&first); |
| 275 CHECK_EQ(write_count(), 0); | 289 CHECK_EQ(write_count(), 0); |
| 276 optimizer()->Write(&second); | 290 optimizer()->Write(&second); |
| 277 CHECK_EQ(write_count(), 1); | 291 CHECK_EQ(write_count(), 1); |
| 278 CHECK_EQ(last_written(), first); | 292 CHECK_EQ(last_written(), first); |
| 279 optimizer()->FlushBasicBlock(); | 293 Flush(); |
| 280 CHECK_EQ(write_count(), 1); | 294 CHECK_EQ(write_count(), 1); |
| 281 } | 295 } |
| 282 | 296 |
| 283 TEST_F(BytecodePeepholeOptimizerTest, LdaConstantStringToName) { | 297 TEST_F(BytecodePeepholeOptimizerTest, LdaConstantStringToName) { |
| 284 Handle<Object> word = | 298 Handle<Object> word = |
| 285 isolate()->factory()->NewStringFromStaticChars("optimizing"); | 299 isolate()->factory()->NewStringFromStaticChars("optimizing"); |
| 286 size_t index = constant_array()->Insert(word); | 300 size_t index = constant_array()->Insert(word); |
| 287 BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index), | 301 BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index), |
| 288 OperandScale::kSingle); | 302 OperandScale::kSingle); |
| 289 BytecodeNode second(Bytecode::kToName); | 303 BytecodeNode second(Bytecode::kToName); |
| 290 optimizer()->Write(&first); | 304 optimizer()->Write(&first); |
| 291 CHECK_EQ(write_count(), 0); | 305 CHECK_EQ(write_count(), 0); |
| 292 optimizer()->Write(&second); | 306 optimizer()->Write(&second); |
| 293 CHECK_EQ(write_count(), 1); | 307 CHECK_EQ(write_count(), 1); |
| 294 CHECK_EQ(last_written(), first); | 308 CHECK_EQ(last_written(), first); |
| 295 optimizer()->FlushBasicBlock(); | 309 Flush(); |
| 296 CHECK_EQ(write_count(), 1); | 310 CHECK_EQ(write_count(), 1); |
| 297 } | 311 } |
| 298 | 312 |
| 299 TEST_F(BytecodePeepholeOptimizerTest, LdaConstantNumberToName) { | 313 TEST_F(BytecodePeepholeOptimizerTest, LdaConstantNumberToName) { |
| 300 Handle<Object> word = isolate()->factory()->NewNumber(0.380); | 314 Handle<Object> word = isolate()->factory()->NewNumber(0.380); |
| 301 size_t index = constant_array()->Insert(word); | 315 size_t index = constant_array()->Insert(word); |
| 302 BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index), | 316 BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index), |
| 303 OperandScale::kSingle); | 317 OperandScale::kSingle); |
| 304 BytecodeNode second(Bytecode::kToName); | 318 BytecodeNode second(Bytecode::kToName); |
| 305 optimizer()->Write(&first); | 319 optimizer()->Write(&first); |
| 306 CHECK_EQ(write_count(), 0); | 320 CHECK_EQ(write_count(), 0); |
| 307 optimizer()->Write(&second); | 321 optimizer()->Write(&second); |
| 308 CHECK_EQ(write_count(), 1); | 322 CHECK_EQ(write_count(), 1); |
| 309 CHECK_EQ(last_written(), first); | 323 CHECK_EQ(last_written(), first); |
| 310 optimizer()->FlushBasicBlock(); | 324 Flush(); |
| 311 CHECK_EQ(write_count(), 2); | 325 CHECK_EQ(write_count(), 2); |
| 312 CHECK_EQ(last_written(), second); | 326 CHECK_EQ(last_written(), second); |
| 313 } | 327 } |
| 314 | 328 |
| 315 // Tests covering BytecodePeepholeOptimizer::CanElideLast(). | 329 // Tests covering BytecodePeepholeOptimizer::CanElideLast(). |
| 316 | 330 |
| 317 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalseNotDiscardable) { | |
| 318 BytecodeNode first(Bytecode::kLdaTrue); | |
| 319 BytecodeNode second(Bytecode::kLdaFalse); | |
| 320 optimizer()->Write(&first); | |
| 321 optimizer()->FlushForOffset(); // Prevent discarding of |first|. | |
| 322 CHECK_EQ(write_count(), 0); | |
| 323 optimizer()->Write(&second); | |
| 324 CHECK_EQ(write_count(), 1); | |
| 325 CHECK_EQ(last_written(), first); | |
| 326 optimizer()->FlushBasicBlock(); | |
| 327 CHECK_EQ(write_count(), 2); | |
| 328 CHECK_EQ(last_written(), second); | |
| 329 } | |
| 330 | |
| 331 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) { | 331 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) { |
| 332 BytecodeNode first(Bytecode::kLdaTrue); | 332 BytecodeNode first(Bytecode::kLdaTrue); |
| 333 BytecodeNode second(Bytecode::kLdaFalse); | 333 BytecodeNode second(Bytecode::kLdaFalse); |
| 334 optimizer()->Write(&first); | 334 optimizer()->Write(&first); |
| 335 CHECK_EQ(write_count(), 0); | 335 CHECK_EQ(write_count(), 0); |
| 336 optimizer()->Write(&second); | 336 optimizer()->Write(&second); |
| 337 CHECK_EQ(write_count(), 0); | 337 CHECK_EQ(write_count(), 0); |
| 338 optimizer()->FlushBasicBlock(); | 338 Flush(); |
| 339 CHECK_EQ(write_count(), 1); | 339 CHECK_EQ(write_count(), 1); |
| 340 CHECK_EQ(last_written(), second); | 340 CHECK_EQ(last_written(), second); |
| 341 } | 341 } |
| 342 | 342 |
| 343 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) { | 343 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) { |
| 344 BytecodeNode first(Bytecode::kLdaTrue); | 344 BytecodeNode first(Bytecode::kLdaTrue); |
| 345 first.source_info().Update({3, false}); | 345 first.source_info().Update({3, false}); |
| 346 BytecodeNode second(Bytecode::kLdaFalse); | 346 BytecodeNode second(Bytecode::kLdaFalse); |
| 347 optimizer()->Write(&first); | 347 optimizer()->Write(&first); |
| 348 CHECK_EQ(write_count(), 0); | 348 CHECK_EQ(write_count(), 0); |
| 349 optimizer()->Write(&second); | 349 optimizer()->Write(&second); |
| 350 CHECK_EQ(write_count(), 0); | 350 CHECK_EQ(write_count(), 0); |
| 351 optimizer()->FlushBasicBlock(); | 351 Flush(); |
| 352 CHECK_EQ(write_count(), 1); | 352 CHECK_EQ(write_count(), 1); |
| 353 second.source_info().Update(first.source_info()); | 353 second.source_info().Update(first.source_info()); |
| 354 CHECK_EQ(last_written(), second); | 354 CHECK_EQ(last_written(), second); |
| 355 } | 355 } |
| 356 | 356 |
| 357 TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) { | 357 TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) { |
| 358 BytecodeNode first(Bytecode::kNop); | 358 BytecodeNode first(Bytecode::kNop); |
| 359 BytecodeNode second(Bytecode::kStackCheck); | 359 BytecodeNode second(Bytecode::kStackCheck); |
| 360 optimizer()->Write(&first); | 360 optimizer()->Write(&first); |
| 361 CHECK_EQ(write_count(), 0); | 361 CHECK_EQ(write_count(), 0); |
| 362 optimizer()->Write(&second); | 362 optimizer()->Write(&second); |
| 363 CHECK_EQ(write_count(), 0); | 363 CHECK_EQ(write_count(), 0); |
| 364 optimizer()->FlushBasicBlock(); | 364 Flush(); |
| 365 CHECK_EQ(write_count(), 1); | 365 CHECK_EQ(write_count(), 1); |
| 366 CHECK_EQ(last_written(), second); | 366 CHECK_EQ(last_written(), second); |
| 367 } | 367 } |
| 368 | 368 |
| 369 TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) { | 369 TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) { |
| 370 BytecodeNode first(Bytecode::kNop); | 370 BytecodeNode first(Bytecode::kNop); |
| 371 first.source_info().Update({3, false}); | 371 first.source_info().Update({3, false}); |
| 372 BytecodeNode second(Bytecode::kStackCheck); | 372 BytecodeNode second(Bytecode::kStackCheck); |
| 373 optimizer()->Write(&first); | 373 optimizer()->Write(&first); |
| 374 CHECK_EQ(write_count(), 0); | 374 CHECK_EQ(write_count(), 0); |
| 375 optimizer()->Write(&second); | 375 optimizer()->Write(&second); |
| 376 CHECK_EQ(write_count(), 0); | 376 CHECK_EQ(write_count(), 0); |
| 377 optimizer()->FlushBasicBlock(); | 377 Flush(); |
| 378 CHECK_EQ(write_count(), 1); | 378 CHECK_EQ(write_count(), 1); |
| 379 second.source_info().Update(first.source_info()); | 379 second.source_info().Update(first.source_info()); |
| 380 CHECK_EQ(last_written(), second); | 380 CHECK_EQ(last_written(), second); |
| 381 } | 381 } |
| 382 | 382 |
| 383 // Tests covering BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes(). | 383 // Tests covering BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes(). |
| 384 | 384 |
| 385 TEST_F(BytecodePeepholeOptimizerTest, MergeLoadICStar) { | 385 TEST_F(BytecodePeepholeOptimizerTest, MergeLoadICStar) { |
| 386 const uint32_t operands[] = { | 386 const uint32_t operands[] = { |
| 387 static_cast<uint32_t>(Register(31).ToOperand()), 32, 33, | 387 static_cast<uint32_t>(Register(31).ToOperand()), 32, 33, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 399 CHECK_EQ(last_written().operand_count(), expected_operand_count); | 399 CHECK_EQ(last_written().operand_count(), expected_operand_count); |
| 400 for (int i = 0; i < expected_operand_count; ++i) { | 400 for (int i = 0; i < expected_operand_count; ++i) { |
| 401 CHECK_EQ(last_written().operand(i), operands[i]); | 401 CHECK_EQ(last_written().operand(i), operands[i]); |
| 402 } | 402 } |
| 403 CHECK_EQ(last_written().operand_scale(), | 403 CHECK_EQ(last_written().operand_scale(), |
| 404 std::max(first.operand_scale(), second.operand_scale())); | 404 std::max(first.operand_scale(), second.operand_scale())); |
| 405 optimizer()->Write(&third); | 405 optimizer()->Write(&third); |
| 406 CHECK_EQ(write_count(), 2); | 406 CHECK_EQ(write_count(), 2); |
| 407 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); | 407 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); |
| 408 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); | 408 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); |
| 409 optimizer()->FlushBasicBlock(); | 409 Flush(); |
| 410 CHECK_EQ(last_written().bytecode(), third.bytecode()); | 410 CHECK_EQ(last_written().bytecode(), third.bytecode()); |
| 411 } | 411 } |
| 412 | 412 |
| 413 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaKeyedPropertyStar) { | 413 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaKeyedPropertyStar) { |
| 414 const uint32_t operands[] = {static_cast<uint32_t>(Register(31).ToOperand()), | 414 const uint32_t operands[] = {static_cast<uint32_t>(Register(31).ToOperand()), |
| 415 9999997, | 415 9999997, |
| 416 static_cast<uint32_t>(Register(1).ToOperand())}; | 416 static_cast<uint32_t>(Register(1).ToOperand())}; |
| 417 const int expected_operand_count = static_cast<int>(arraysize(operands)); | 417 const int expected_operand_count = static_cast<int>(arraysize(operands)); |
| 418 | 418 |
| 419 BytecodeNode first(Bytecode::kLdaKeyedProperty, operands[0], operands[1], | 419 BytecodeNode first(Bytecode::kLdaKeyedProperty, operands[0], operands[1], |
| 420 OperandScale::kQuadruple); | 420 OperandScale::kQuadruple); |
| 421 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); | 421 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); |
| 422 BytecodeNode third(Bytecode::kReturn); | 422 BytecodeNode third(Bytecode::kReturn); |
| 423 optimizer()->Write(&first); | 423 optimizer()->Write(&first); |
| 424 optimizer()->Write(&second); | 424 optimizer()->Write(&second); |
| 425 CHECK_EQ(write_count(), 1); | 425 CHECK_EQ(write_count(), 1); |
| 426 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrKeyedProperty); | 426 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrKeyedProperty); |
| 427 CHECK_EQ(last_written().operand_count(), expected_operand_count); | 427 CHECK_EQ(last_written().operand_count(), expected_operand_count); |
| 428 for (int i = 0; i < expected_operand_count; ++i) { | 428 for (int i = 0; i < expected_operand_count; ++i) { |
| 429 CHECK_EQ(last_written().operand(i), operands[i]); | 429 CHECK_EQ(last_written().operand(i), operands[i]); |
| 430 } | 430 } |
| 431 CHECK_EQ(last_written().operand_scale(), | 431 CHECK_EQ(last_written().operand_scale(), |
| 432 std::max(first.operand_scale(), second.operand_scale())); | 432 std::max(first.operand_scale(), second.operand_scale())); |
| 433 optimizer()->Write(&third); | 433 optimizer()->Write(&third); |
| 434 CHECK_EQ(write_count(), 2); | 434 CHECK_EQ(write_count(), 2); |
| 435 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); | 435 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); |
| 436 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); | 436 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); |
| 437 optimizer()->FlushBasicBlock(); | 437 Flush(); |
| 438 CHECK_EQ(last_written().bytecode(), third.bytecode()); | 438 CHECK_EQ(last_written().bytecode(), third.bytecode()); |
| 439 } | 439 } |
| 440 | 440 |
| 441 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaGlobalStar) { | 441 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaGlobalStar) { |
| 442 const uint32_t operands[] = {54321, 19191, | 442 const uint32_t operands[] = {54321, 19191, |
| 443 static_cast<uint32_t>(Register(1).ToOperand())}; | 443 static_cast<uint32_t>(Register(1).ToOperand())}; |
| 444 const int expected_operand_count = static_cast<int>(arraysize(operands)); | 444 const int expected_operand_count = static_cast<int>(arraysize(operands)); |
| 445 | 445 |
| 446 BytecodeNode first(Bytecode::kLdaGlobal, operands[0], operands[1], | 446 BytecodeNode first(Bytecode::kLdaGlobal, operands[0], operands[1], |
| 447 OperandScale::kDouble); | 447 OperandScale::kDouble); |
| 448 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); | 448 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); |
| 449 BytecodeNode third(Bytecode::kReturn); | 449 BytecodeNode third(Bytecode::kReturn); |
| 450 optimizer()->Write(&first); | 450 optimizer()->Write(&first); |
| 451 optimizer()->Write(&second); | 451 optimizer()->Write(&second); |
| 452 CHECK_EQ(write_count(), 1); | 452 CHECK_EQ(write_count(), 1); |
| 453 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrGlobal); | 453 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrGlobal); |
| 454 CHECK_EQ(last_written().operand_count(), expected_operand_count); | 454 CHECK_EQ(last_written().operand_count(), expected_operand_count); |
| 455 for (int i = 0; i < expected_operand_count; ++i) { | 455 for (int i = 0; i < expected_operand_count; ++i) { |
| 456 CHECK_EQ(last_written().operand(i), operands[i]); | 456 CHECK_EQ(last_written().operand(i), operands[i]); |
| 457 } | 457 } |
| 458 CHECK_EQ(last_written().operand_scale(), | 458 CHECK_EQ(last_written().operand_scale(), |
| 459 std::max(first.operand_scale(), second.operand_scale())); | 459 std::max(first.operand_scale(), second.operand_scale())); |
| 460 optimizer()->Write(&third); | 460 optimizer()->Write(&third); |
| 461 CHECK_EQ(write_count(), 2); | 461 CHECK_EQ(write_count(), 2); |
| 462 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); | 462 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); |
| 463 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); | 463 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); |
| 464 optimizer()->FlushBasicBlock(); | 464 Flush(); |
| 465 CHECK_EQ(last_written().bytecode(), third.bytecode()); | 465 CHECK_EQ(last_written().bytecode(), third.bytecode()); |
| 466 } | 466 } |
| 467 | 467 |
| 468 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaContextSlotStar) { | 468 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaContextSlotStar) { |
| 469 const uint32_t operands[] = { | 469 const uint32_t operands[] = { |
| 470 static_cast<uint32_t>(Register(200000).ToOperand()), 55005500, | 470 static_cast<uint32_t>(Register(200000).ToOperand()), 55005500, |
| 471 static_cast<uint32_t>(Register(1).ToOperand())}; | 471 static_cast<uint32_t>(Register(1).ToOperand())}; |
| 472 const int expected_operand_count = static_cast<int>(arraysize(operands)); | 472 const int expected_operand_count = static_cast<int>(arraysize(operands)); |
| 473 | 473 |
| 474 BytecodeNode first(Bytecode::kLdaContextSlot, operands[0], operands[1], | 474 BytecodeNode first(Bytecode::kLdaContextSlot, operands[0], operands[1], |
| 475 OperandScale::kQuadruple); | 475 OperandScale::kQuadruple); |
| 476 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); | 476 BytecodeNode second(Bytecode::kStar, operands[2], OperandScale::kSingle); |
| 477 BytecodeNode third(Bytecode::kReturn); | 477 BytecodeNode third(Bytecode::kReturn); |
| 478 optimizer()->Write(&first); | 478 optimizer()->Write(&first); |
| 479 optimizer()->Write(&second); | 479 optimizer()->Write(&second); |
| 480 CHECK_EQ(write_count(), 1); | 480 CHECK_EQ(write_count(), 1); |
| 481 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrContextSlot); | 481 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrContextSlot); |
| 482 CHECK_EQ(last_written().operand_count(), expected_operand_count); | 482 CHECK_EQ(last_written().operand_count(), expected_operand_count); |
| 483 for (int i = 0; i < expected_operand_count; ++i) { | 483 for (int i = 0; i < expected_operand_count; ++i) { |
| 484 CHECK_EQ(last_written().operand(i), operands[i]); | 484 CHECK_EQ(last_written().operand(i), operands[i]); |
| 485 } | 485 } |
| 486 CHECK_EQ(last_written().operand_scale(), | 486 CHECK_EQ(last_written().operand_scale(), |
| 487 std::max(first.operand_scale(), second.operand_scale())); | 487 std::max(first.operand_scale(), second.operand_scale())); |
| 488 optimizer()->Write(&third); | 488 optimizer()->Write(&third); |
| 489 CHECK_EQ(write_count(), 2); | 489 CHECK_EQ(write_count(), 2); |
| 490 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); | 490 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); |
| 491 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); | 491 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); |
| 492 optimizer()->FlushBasicBlock(); | 492 Flush(); |
| 493 CHECK_EQ(last_written().bytecode(), third.bytecode()); | 493 CHECK_EQ(last_written().bytecode(), third.bytecode()); |
| 494 } | 494 } |
| 495 | 495 |
| 496 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaUndefinedStar) { | 496 TEST_F(BytecodePeepholeOptimizerTest, MergeLdaUndefinedStar) { |
| 497 const uint32_t operands[] = { | 497 const uint32_t operands[] = { |
| 498 static_cast<uint32_t>(Register(100000).ToOperand())}; | 498 static_cast<uint32_t>(Register(100000).ToOperand())}; |
| 499 const int expected_operand_count = static_cast<int>(arraysize(operands)); | 499 const int expected_operand_count = static_cast<int>(arraysize(operands)); |
| 500 | 500 |
| 501 BytecodeNode first(Bytecode::kLdaUndefined); | 501 BytecodeNode first(Bytecode::kLdaUndefined); |
| 502 BytecodeNode second(Bytecode::kStar, operands[0], OperandScale::kQuadruple); | 502 BytecodeNode second(Bytecode::kStar, operands[0], OperandScale::kQuadruple); |
| 503 BytecodeNode third(Bytecode::kReturn); | 503 BytecodeNode third(Bytecode::kReturn); |
| 504 optimizer()->Write(&first); | 504 optimizer()->Write(&first); |
| 505 optimizer()->Write(&second); | 505 optimizer()->Write(&second); |
| 506 CHECK_EQ(write_count(), 1); | 506 CHECK_EQ(write_count(), 1); |
| 507 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrUndefined); | 507 CHECK_EQ(last_written().bytecode(), Bytecode::kLdrUndefined); |
| 508 CHECK_EQ(last_written().operand_count(), expected_operand_count); | 508 CHECK_EQ(last_written().operand_count(), expected_operand_count); |
| 509 for (int i = 0; i < expected_operand_count; ++i) { | 509 for (int i = 0; i < expected_operand_count; ++i) { |
| 510 CHECK_EQ(last_written().operand(i), operands[i]); | 510 CHECK_EQ(last_written().operand(i), operands[i]); |
| 511 } | 511 } |
| 512 CHECK_EQ(last_written().operand_scale(), | 512 CHECK_EQ(last_written().operand_scale(), |
| 513 std::max(first.operand_scale(), second.operand_scale())); | 513 std::max(first.operand_scale(), second.operand_scale())); |
| 514 optimizer()->Write(&third); | 514 optimizer()->Write(&third); |
| 515 CHECK_EQ(write_count(), 2); | 515 CHECK_EQ(write_count(), 2); |
| 516 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); | 516 CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); |
| 517 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); | 517 CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); |
| 518 optimizer()->FlushBasicBlock(); | 518 Flush(); |
| 519 CHECK_EQ(last_written().bytecode(), third.bytecode()); | 519 CHECK_EQ(last_written().bytecode(), third.bytecode()); |
| 520 } | 520 } |
| 521 | 521 |
| 522 } // namespace interpreter | 522 } // namespace interpreter |
| 523 } // namespace internal | 523 } // namespace internal |
| 524 } // namespace v8 | 524 } // namespace v8 |
| OLD | NEW |