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" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 | 55 |
56 private: | 56 private: |
57 BytecodeRegisterAllocator* register_allocator_; | 57 BytecodeRegisterAllocator* register_allocator_; |
58 BytecodeRegisterOptimizer* register_optimizer_; | 58 BytecodeRegisterOptimizer* register_optimizer_; |
59 | 59 |
60 std::vector<BytecodeNode> output_; | 60 std::vector<BytecodeNode> output_; |
61 }; | 61 }; |
62 | 62 |
63 // Sanity tests. | 63 // Sanity tests. |
64 | 64 |
65 TEST_F(BytecodeRegisterOptimizerTest, WriteNop) { | 65 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForFlush) { |
66 Initialize(1, 1); | 66 Initialize(1, 1); |
67 BytecodeNode node(Bytecode::kNop); | 67 Register temp = NewTemporary(); |
68 optimizer()->Write(&node); | 68 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
| 69 CHECK_EQ(write_count(), 0); |
| 70 optimizer()->Flush(); |
69 CHECK_EQ(write_count(), 1); | 71 CHECK_EQ(write_count(), 1); |
70 CHECK_EQ(node, last_written()); | 72 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
71 } | 73 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); |
72 | |
73 TEST_F(BytecodeRegisterOptimizerTest, WriteNopExpression) { | |
74 Initialize(1, 1); | |
75 BytecodeSourceInfo source_info(3, false); | |
76 BytecodeNode node(Bytecode::kNop, &source_info); | |
77 optimizer()->Write(&node); | |
78 CHECK_EQ(write_count(), 1); | |
79 CHECK_EQ(node, last_written()); | |
80 } | |
81 | |
82 TEST_F(BytecodeRegisterOptimizerTest, WriteNopStatement) { | |
83 Initialize(1, 1); | |
84 BytecodeSourceInfo source_info(3, true); | |
85 BytecodeNode node(Bytecode::kNop); | |
86 optimizer()->Write(&node); | |
87 CHECK_EQ(write_count(), 1); | |
88 CHECK_EQ(node, last_written()); | |
89 } | 74 } |
90 | 75 |
91 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) { | 76 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) { |
92 Initialize(1, 1); | 77 Initialize(1, 1); |
93 Register temp = NewTemporary(); | 78 Register temp = NewTemporary(); |
94 BytecodeNode node(Bytecode::kStar, temp.ToOperand()); | 79 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
95 optimizer()->Write(&node); | |
96 CHECK_EQ(write_count(), 0); | 80 CHECK_EQ(write_count(), 0); |
97 BytecodeLabel label; | 81 optimizer()->PrepareForBytecode(Bytecode::kJump); |
98 BytecodeNode jump(Bytecode::kJump, 0, nullptr); | |
99 optimizer()->WriteJump(&jump, &label); | |
100 CHECK_EQ(write_count(), 2); | |
101 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); | |
102 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); | |
103 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kJump); | |
104 } | |
105 | |
106 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForBind) { | |
107 Initialize(1, 1); | |
108 Register temp = NewTemporary(); | |
109 BytecodeNode node(Bytecode::kStar, temp.ToOperand()); | |
110 optimizer()->Write(&node); | |
111 CHECK_EQ(write_count(), 0); | |
112 BytecodeLabel label; | |
113 optimizer()->BindLabel(&label); | |
114 CHECK_EQ(write_count(), 1); | 82 CHECK_EQ(write_count(), 1); |
115 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); | 83 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
116 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); | 84 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); |
117 } | 85 } |
118 | 86 |
119 // Basic Register Optimizations | 87 // Basic Register Optimizations |
120 | 88 |
121 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { | 89 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { |
122 Initialize(3, 1); | 90 Initialize(3, 1); |
123 Register parameter = Register::FromParameterIndex(1, 3); | 91 Register parameter = Register::FromParameterIndex(1, 3); |
124 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 92 optimizer()->DoLdar(parameter, BytecodeSourceInfo()); |
125 optimizer()->Write(&node0); | |
126 CHECK_EQ(write_count(), 0); | 93 CHECK_EQ(write_count(), 0); |
127 Register temp = NewTemporary(); | 94 Register temp = NewTemporary(); |
| 95 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
128 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); | 96 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); |
129 optimizer()->Write(&node1); | |
130 CHECK_EQ(write_count(), 0); | |
131 ReleaseTemporaries(temp); | 97 ReleaseTemporaries(temp); |
132 CHECK_EQ(write_count(), 0); | 98 CHECK_EQ(write_count(), 0); |
133 BytecodeNode node2(Bytecode::kReturn); | 99 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
134 optimizer()->Write(&node2); | |
135 CHECK_EQ(write_count(), 2); | |
136 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); | 100 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); |
137 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); | 101 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); |
138 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); | |
139 } | 102 } |
140 | 103 |
141 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { | 104 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { |
142 Initialize(3, 1); | 105 Initialize(3, 1); |
143 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 106 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
144 optimizer()->Write(&node0); | |
145 CHECK_EQ(write_count(), 1); | |
146 Register temp0 = NewTemporary(); | 107 Register temp0 = NewTemporary(); |
147 Register temp1 = NewTemporary(); | 108 Register temp1 = NewTemporary(); |
148 BytecodeNode node1(Bytecode::kStar, temp1.ToOperand()); | 109 optimizer()->DoStar(temp1, BytecodeSourceInfo()); |
149 optimizer()->Write(&node1); | 110 CHECK_EQ(write_count(), 0); |
| 111 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
150 CHECK_EQ(write_count(), 1); | 112 CHECK_EQ(write_count(), 1); |
151 BytecodeNode node2(Bytecode::kLdaSmi, 1); | 113 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
152 optimizer()->Write(&node2); | 114 CHECK_EQ(output()->at(0).operand(0), temp1.ToOperand()); |
153 CHECK_EQ(write_count(), 3); | 115 optimizer()->DoMov(temp1, temp0, BytecodeSourceInfo()); |
154 BytecodeNode node3(Bytecode::kMov, temp1.ToOperand(), temp0.ToOperand()); | 116 CHECK_EQ(write_count(), 1); |
155 optimizer()->Write(&node3); | |
156 CHECK_EQ(write_count(), 3); | |
157 ReleaseTemporaries(temp1); | 117 ReleaseTemporaries(temp1); |
158 CHECK_EQ(write_count(), 3); | 118 CHECK_EQ(write_count(), 1); |
159 BytecodeNode node4(Bytecode::kLdar, temp0.ToOperand()); | 119 optimizer()->DoLdar(temp0, BytecodeSourceInfo()); |
160 optimizer()->Write(&node4); | 120 CHECK_EQ(write_count(), 1); |
161 CHECK_EQ(write_count(), 3); | 121 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
162 BytecodeNode node5(Bytecode::kReturn); | 122 CHECK_EQ(write_count(), 2); |
163 optimizer()->Write(&node5); | 123 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); |
164 CHECK_EQ(write_count(), 5); | 124 CHECK_EQ(output()->at(1).operand(0), temp1.ToOperand()); |
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 } | 125 } |
169 | 126 |
170 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { | 127 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { |
171 Initialize(3, 1); | 128 Initialize(3, 1); |
172 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 129 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
173 optimizer()->Write(&node0); | |
174 CHECK_EQ(write_count(), 1); | |
175 Register temp0 = NewTemporary(); | 130 Register temp0 = NewTemporary(); |
176 Register temp1 = NewTemporary(); | 131 Register temp1 = NewTemporary(); |
177 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); | 132 optimizer()->DoStar(temp0, BytecodeSourceInfo()); |
178 optimizer()->Write(&node1); | 133 CHECK_EQ(write_count(), 0); |
| 134 optimizer()->DoStar(temp1, BytecodeSourceInfo()); |
| 135 CHECK_EQ(write_count(), 0); |
| 136 ReleaseTemporaries(temp1); |
| 137 optimizer()->Flush(); |
179 CHECK_EQ(write_count(), 1); | 138 CHECK_EQ(write_count(), 1); |
180 BytecodeNode node2(Bytecode::kStar, temp1.ToOperand()); | 139 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
181 optimizer()->Write(&node2); | 140 CHECK_EQ(output()->at(0).operand(0), temp0.ToOperand()); |
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 } | 141 } |
195 | 142 |
196 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { | 143 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { |
197 Initialize(3, 1); | 144 Initialize(3, 1); |
198 Register parameter = Register::FromParameterIndex(1, 3); | 145 Register parameter = Register::FromParameterIndex(1, 3); |
199 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 146 optimizer()->DoLdar(parameter, BytecodeSourceInfo()); |
200 optimizer()->Write(&node0); | |
201 CHECK_EQ(write_count(), 0); | 147 CHECK_EQ(write_count(), 0); |
202 Register local = Register(0); | 148 Register local = Register(0); |
203 BytecodeNode node1(Bytecode::kStar, local.ToOperand()); | 149 optimizer()->DoStar(local, BytecodeSourceInfo()); |
204 optimizer()->Write(&node1); | |
205 CHECK_EQ(write_count(), 1); | 150 CHECK_EQ(write_count(), 1); |
206 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov); | 151 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov); |
207 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); | 152 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); |
208 CHECK_EQ(output()->at(0).operand(1), local.ToOperand()); | 153 CHECK_EQ(output()->at(0).operand(1), local.ToOperand()); |
209 | 154 |
210 BytecodeNode node2(Bytecode::kReturn); | 155 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
211 optimizer()->Write(&node2); | 156 CHECK_EQ(write_count(), 2); |
212 CHECK_EQ(write_count(), 3); | |
213 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); | 157 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); |
214 CHECK_EQ(output()->at(1).operand(0), local.ToOperand()); | 158 CHECK_EQ(output()->at(1).operand(0), local.ToOperand()); |
215 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kReturn); | |
216 } | 159 } |
217 | 160 |
218 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotMaterializedForInput) { | 161 TEST_F(BytecodeRegisterOptimizerTest, SingleTemporaryNotMaterializedForInput) { |
219 Initialize(3, 1); | 162 Initialize(3, 1); |
220 Register parameter = Register::FromParameterIndex(1, 3); | 163 Register parameter = Register::FromParameterIndex(1, 3); |
221 Register temp0 = NewTemporary(); | 164 Register temp0 = NewTemporary(); |
222 Register temp1 = NewTemporary(); | 165 Register temp1 = NewTemporary(); |
223 BytecodeNode node0(Bytecode::kMov, parameter.ToOperand(), temp0.ToOperand()); | 166 optimizer()->DoMov(parameter, temp0, BytecodeSourceInfo()); |
224 optimizer()->Write(&node0); | 167 optimizer()->DoMov(parameter, temp1, BytecodeSourceInfo()); |
225 BytecodeNode node1(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); | |
226 optimizer()->Write(&node1); | |
227 CHECK_EQ(write_count(), 0); | 168 CHECK_EQ(write_count(), 0); |
228 BytecodeNode node2(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 1); | 169 |
229 optimizer()->Write(&node2); | 170 Register reg = optimizer()->GetInputRegister(temp0); |
230 CHECK_EQ(write_count(), 1); | 171 RegisterList reg_list = |
231 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kCallJSRuntime); | 172 optimizer()->GetInputRegisterList(RegisterList(temp0.index(), 1)); |
232 CHECK_EQ(output()->at(0).operand(0), 0); | 173 CHECK_EQ(write_count(), 0); |
233 CHECK_EQ(output()->at(0).operand(1), parameter.ToOperand()); | 174 CHECK_EQ(parameter.index(), reg.index()); |
234 CHECK_EQ(output()->at(0).operand(2), 1); | 175 CHECK_EQ(parameter.index(), reg_list.first_register().index()); |
| 176 CHECK_EQ(1, reg_list.register_count()); |
235 } | 177 } |
236 | 178 |
237 TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) { | 179 TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) { |
238 Initialize(3, 1); | 180 Initialize(3, 1); |
239 Register parameter = Register::FromParameterIndex(1, 3); | 181 Register parameter = Register::FromParameterIndex(1, 3); |
240 Register temp0 = NewTemporary(); | 182 Register temp0 = NewTemporary(); |
241 Register temp1 = NewTemporary(); | 183 Register temp1 = NewTemporary(); |
242 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 184 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
243 optimizer()->Write(&node0); | 185 optimizer()->DoStar(temp0, BytecodeSourceInfo()); |
244 CHECK_EQ(write_count(), 1); | 186 optimizer()->DoMov(parameter, temp1, BytecodeSourceInfo()); |
245 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); | 187 CHECK_EQ(write_count(), 0); |
246 optimizer()->Write(&node1); | |
247 BytecodeNode node2(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); | |
248 optimizer()->Write(&node2); | |
249 CHECK_EQ(write_count(), 1); | |
250 BytecodeNode node3(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 2); | |
251 optimizer()->Write(&node3); | |
252 CHECK_EQ(write_count(), 4); | |
253 | 188 |
254 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdaSmi); | 189 optimizer()->PrepareForBytecode(Bytecode::kCallJSRuntime); |
255 CHECK_EQ(output()->at(0).operand(0), 3); | 190 RegisterList reg_list = |
256 | 191 optimizer()->GetInputRegisterList(RegisterList(temp0.index(), 2)); |
257 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); | 192 CHECK_EQ(temp0.index(), reg_list.first_register().index()); |
258 CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); | 193 CHECK_EQ(2, reg_list.register_count()); |
259 | 194 CHECK_EQ(write_count(), 2); |
260 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kMov); | 195 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
261 CHECK_EQ(output()->at(2).operand(0), parameter.ToOperand()); | 196 CHECK_EQ(output()->at(0).operand(0), temp0.ToOperand()); |
262 CHECK_EQ(output()->at(2).operand(1), temp1.ToOperand()); | 197 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kMov); |
263 | 198 CHECK_EQ(output()->at(1).operand(0), parameter.ToOperand()); |
264 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime); | 199 CHECK_EQ(output()->at(1).operand(1), temp1.ToOperand()); |
265 CHECK_EQ(output()->at(3).operand(0), 0); | |
266 CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand()); | |
267 CHECK_EQ(output()->at(3).operand(2), 2); | |
268 } | 200 } |
269 | 201 |
270 } // namespace interpreter | 202 } // namespace interpreter |
271 } // namespace internal | 203 } // namespace internal |
272 } // namespace v8 | 204 } // namespace v8 |
OLD | NEW |