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-label.h" |
9 #include "src/interpreter/bytecode-register-optimizer.h" | 9 #include "src/interpreter/bytecode-register-optimizer.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
11 #include "src/objects.h" | 11 #include "src/objects.h" |
12 #include "test/unittests/test-utils.h" | 12 #include "test/unittests/test-utils.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 namespace interpreter { | 16 namespace interpreter { |
17 | 17 |
18 class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, | 18 class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, |
19 public TestWithIsolateAndZone { | 19 public TestWithIsolateAndZone { |
20 public: | 20 public: |
21 BytecodeRegisterOptimizerTest() {} | 21 BytecodeRegisterOptimizerTest() {} |
22 ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; } | 22 ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; } |
23 | 23 |
24 void Initialize(int number_of_parameters, int number_of_locals) { | 24 void Initialize(int number_of_parameters, int number_of_locals) { |
25 register_allocator_ = | 25 register_allocator_ = new BytecodeRegisterAllocator(number_of_locals); |
26 new TemporaryRegisterAllocator(zone(), number_of_locals); | 26 register_optimizer_ = new (zone()) |
27 register_optimizer_ = new (zone()) BytecodeRegisterOptimizer( | 27 BytecodeRegisterOptimizer(zone(), register_allocator_, number_of_locals, |
28 zone(), register_allocator_, number_of_parameters, this); | 28 number_of_parameters, this); |
29 } | 29 } |
30 | 30 |
31 void Write(BytecodeNode* node) override { output_.push_back(*node); } | 31 void Write(BytecodeNode* node) override { output_.push_back(*node); } |
32 void WriteJump(BytecodeNode* node, BytecodeLabel* label) override { | 32 void WriteJump(BytecodeNode* node, BytecodeLabel* label) override { |
33 output_.push_back(*node); | 33 output_.push_back(*node); |
34 } | 34 } |
35 void BindLabel(BytecodeLabel* label) override {} | 35 void BindLabel(BytecodeLabel* label) override {} |
36 void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {} | 36 void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {} |
37 Handle<BytecodeArray> ToBytecodeArray( | 37 Handle<BytecodeArray> ToBytecodeArray( |
38 Isolate* isolate, int fixed_register_count, int parameter_count, | 38 Isolate* isolate, int fixed_register_count, int parameter_count, |
39 Handle<FixedArray> handle_table) override { | 39 Handle<FixedArray> handle_table) override { |
40 return Handle<BytecodeArray>(); | 40 return Handle<BytecodeArray>(); |
41 } | 41 } |
42 | 42 |
43 TemporaryRegisterAllocator* allocator() { return register_allocator_; } | 43 BytecodeRegisterAllocator* allocator() { return register_allocator_; } |
44 BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } | 44 BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } |
45 | 45 |
46 Register NewTemporary() { | 46 Register NewTemporary() { return allocator()->NewRegister(); } |
47 return Register(allocator()->BorrowTemporaryRegister()); | |
48 } | |
49 | 47 |
50 void KillTemporary(Register reg) { | 48 void ReleaseTemporaries(Register reg) { |
51 allocator()->ReturnTemporaryRegister(reg.index()); | 49 allocator()->ReleaseRegisters(reg.index()); |
52 } | 50 } |
53 | 51 |
54 size_t write_count() const { return output_.size(); } | 52 size_t write_count() const { return output_.size(); } |
55 const BytecodeNode& last_written() const { return output_.back(); } | 53 const BytecodeNode& last_written() const { return output_.back(); } |
56 const std::vector<BytecodeNode>* output() { return &output_; } | 54 const std::vector<BytecodeNode>* output() { return &output_; } |
57 | 55 |
58 private: | 56 private: |
59 TemporaryRegisterAllocator* register_allocator_; | 57 BytecodeRegisterAllocator* register_allocator_; |
60 BytecodeRegisterOptimizer* register_optimizer_; | 58 BytecodeRegisterOptimizer* register_optimizer_; |
61 | 59 |
62 std::vector<BytecodeNode> output_; | 60 std::vector<BytecodeNode> output_; |
63 }; | 61 }; |
64 | 62 |
65 // Sanity tests. | 63 // Sanity tests. |
66 | 64 |
67 TEST_F(BytecodeRegisterOptimizerTest, WriteNop) { | 65 TEST_F(BytecodeRegisterOptimizerTest, WriteNop) { |
68 Initialize(1, 1); | 66 Initialize(1, 1); |
69 BytecodeNode node(Bytecode::kNop); | 67 BytecodeNode node(Bytecode::kNop); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { | 121 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { |
124 Initialize(3, 1); | 122 Initialize(3, 1); |
125 Register parameter = Register::FromParameterIndex(1, 3); | 123 Register parameter = Register::FromParameterIndex(1, 3); |
126 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 124 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); |
127 optimizer()->Write(&node0); | 125 optimizer()->Write(&node0); |
128 CHECK_EQ(write_count(), 0); | 126 CHECK_EQ(write_count(), 0); |
129 Register temp = NewTemporary(); | 127 Register temp = NewTemporary(); |
130 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); | 128 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); |
131 optimizer()->Write(&node1); | 129 optimizer()->Write(&node1); |
132 CHECK_EQ(write_count(), 0); | 130 CHECK_EQ(write_count(), 0); |
133 KillTemporary(temp); | 131 ReleaseTemporaries(temp); |
134 CHECK_EQ(write_count(), 0); | 132 CHECK_EQ(write_count(), 0); |
135 BytecodeNode node2(Bytecode::kReturn); | 133 BytecodeNode node2(Bytecode::kReturn); |
136 optimizer()->Write(&node2); | 134 optimizer()->Write(&node2); |
137 CHECK_EQ(write_count(), 2); | 135 CHECK_EQ(write_count(), 2); |
138 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); | 136 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); |
139 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); | 137 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); |
140 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); | 138 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); |
141 } | 139 } |
142 | 140 |
| 141 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { |
| 142 Initialize(3, 1); |
| 143 BytecodeNode node0(Bytecode::kLdaSmi, 3); |
| 144 optimizer()->Write(&node0); |
| 145 CHECK_EQ(write_count(), 1); |
| 146 Register temp0 = NewTemporary(); |
| 147 Register temp1 = NewTemporary(); |
| 148 BytecodeNode node1(Bytecode::kStar, temp1.ToOperand()); |
| 149 optimizer()->Write(&node1); |
| 150 CHECK_EQ(write_count(), 1); |
| 151 BytecodeNode node2(Bytecode::kLdaSmi, 1); |
| 152 optimizer()->Write(&node2); |
| 153 CHECK_EQ(write_count(), 3); |
| 154 BytecodeNode node3(Bytecode::kMov, temp1.ToOperand(), temp0.ToOperand()); |
| 155 optimizer()->Write(&node3); |
| 156 CHECK_EQ(write_count(), 3); |
| 157 ReleaseTemporaries(temp1); |
| 158 CHECK_EQ(write_count(), 3); |
| 159 BytecodeNode node4(Bytecode::kLdar, temp0.ToOperand()); |
| 160 optimizer()->Write(&node4); |
| 161 CHECK_EQ(write_count(), 3); |
| 162 BytecodeNode node5(Bytecode::kReturn); |
| 163 optimizer()->Write(&node5); |
| 164 CHECK_EQ(write_count(), 5); |
| 165 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kLdar); |
| 166 CHECK_EQ(output()->at(3).operand(0), temp1.ToOperand()); |
| 167 CHECK_EQ(output()->at(4).bytecode(), Bytecode::kReturn); |
| 168 } |
| 169 |
| 170 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { |
| 171 Initialize(3, 1); |
| 172 BytecodeNode node0(Bytecode::kLdaSmi, 3); |
| 173 optimizer()->Write(&node0); |
| 174 CHECK_EQ(write_count(), 1); |
| 175 Register temp0 = NewTemporary(); |
| 176 Register temp1 = NewTemporary(); |
| 177 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); |
| 178 optimizer()->Write(&node1); |
| 179 CHECK_EQ(write_count(), 1); |
| 180 BytecodeNode node2(Bytecode::kStar, temp1.ToOperand()); |
| 181 optimizer()->Write(&node2); |
| 182 CHECK_EQ(write_count(), 1); |
| 183 ReleaseTemporaries(temp1); |
| 184 BytecodeLabel label; |
| 185 BytecodeNode jump(Bytecode::kJump, 0, nullptr); |
| 186 optimizer()->WriteJump(&jump, &label); |
| 187 BytecodeNode node3(Bytecode::kReturn); |
| 188 optimizer()->Write(&node3); |
| 189 CHECK_EQ(write_count(), 4); |
| 190 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); |
| 191 CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); |
| 192 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kJump); |
| 193 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kReturn); |
| 194 } |
| 195 |
143 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { | 196 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { |
144 Initialize(3, 1); | 197 Initialize(3, 1); |
145 Register parameter = Register::FromParameterIndex(1, 3); | 198 Register parameter = Register::FromParameterIndex(1, 3); |
146 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 199 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); |
147 optimizer()->Write(&node0); | 200 optimizer()->Write(&node0); |
148 CHECK_EQ(write_count(), 0); | 201 CHECK_EQ(write_count(), 0); |
149 Register local = Register(0); | 202 Register local = Register(0); |
150 BytecodeNode node1(Bytecode::kStar, local.ToOperand()); | 203 BytecodeNode node1(Bytecode::kStar, local.ToOperand()); |
151 optimizer()->Write(&node1); | 204 optimizer()->Write(&node1); |
152 CHECK_EQ(write_count(), 1); | 205 CHECK_EQ(write_count(), 1); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 | 263 |
211 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime); | 264 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime); |
212 CHECK_EQ(output()->at(3).operand(0), 0); | 265 CHECK_EQ(output()->at(3).operand(0), 0); |
213 CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand()); | 266 CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand()); |
214 CHECK_EQ(output()->at(3).operand(2), 2); | 267 CHECK_EQ(output()->at(3).operand(2), 2); |
215 } | 268 } |
216 | 269 |
217 } // namespace interpreter | 270 } // namespace interpreter |
218 } // namespace internal | 271 } // namespace internal |
219 } // namespace v8 | 272 } // namespace v8 |
OLD | NEW |