OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/interpreter/bytecode-array-builder.h" | 7 #include "src/interpreter/bytecode-array-builder.h" |
8 #include "src/interpreter/bytecode-array-iterator.h" | 8 #include "src/interpreter/bytecode-array-iterator.h" |
9 #include "test/unittests/test-utils.h" | 9 #include "test/unittests/test-utils.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 namespace interpreter { | 13 namespace interpreter { |
14 | 14 |
15 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { | 15 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { |
16 public: | 16 public: |
17 BytecodeArrayBuilderTest() {} | 17 BytecodeArrayBuilderTest() {} |
18 ~BytecodeArrayBuilderTest() override {} | 18 ~BytecodeArrayBuilderTest() override {} |
19 }; | 19 }; |
20 | 20 |
21 | 21 |
22 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { | 22 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { |
23 BytecodeArrayBuilder builder(isolate(), zone()); | 23 BytecodeArrayBuilder builder(isolate(), zone()); |
24 | 24 |
25 builder.set_locals_count(1); | 25 builder.set_locals_count(1); |
| 26 builder.set_context_count(1); |
26 builder.set_parameter_count(0); | 27 builder.set_parameter_count(0); |
27 CHECK_EQ(builder.locals_count(), 1); | 28 CHECK_EQ(builder.locals_count(), 1); |
| 29 CHECK_EQ(builder.context_count(), 1); |
| 30 CHECK_EQ(builder.fixed_register_count(), 2); |
28 | 31 |
29 // Emit constant loads. | 32 // Emit constant loads. |
30 builder.LoadLiteral(Smi::FromInt(0)) | 33 builder.LoadLiteral(Smi::FromInt(0)) |
31 .LoadLiteral(Smi::FromInt(8)) | 34 .LoadLiteral(Smi::FromInt(8)) |
32 .LoadLiteral(Smi::FromInt(10000000)) | 35 .LoadLiteral(Smi::FromInt(10000000)) |
33 .LoadUndefined() | 36 .LoadUndefined() |
34 .LoadNull() | 37 .LoadNull() |
35 .LoadTheHole() | 38 .LoadTheHole() |
36 .LoadTrue() | 39 .LoadTrue() |
37 .LoadFalse(); | 40 .LoadFalse(); |
38 | 41 |
39 // Emit accumulator transfers. | 42 // Emit accumulator transfers. |
40 Register reg(0); | 43 Register reg(0); |
41 builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg); | 44 builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg); |
42 | 45 |
43 // Emit global load / store operations. | 46 // Emit global load / store operations. |
44 builder.LoadGlobal(1); | 47 builder.LoadGlobal(1); |
45 builder.StoreGlobal(1, LanguageMode::SLOPPY); | 48 builder.StoreGlobal(1, LanguageMode::SLOPPY); |
46 | 49 |
47 // Emit context operations. | 50 // Emit context operations. |
48 builder.PushContext(reg); | 51 builder.PushContext(reg); |
49 builder.PopContext(reg); | 52 builder.PopContext(reg); |
50 builder.LoadContextSlot(reg, 1); | 53 builder.LoadContextSlot(reg, 1); |
| 54 builder.StoreContextSlot(reg, 1); |
51 | 55 |
52 // Emit load / store property operations. | 56 // Emit load / store property operations. |
53 builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY) | 57 builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY) |
54 .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY) | 58 .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY) |
55 .StoreNamedProperty(reg, reg, 0, LanguageMode::SLOPPY) | 59 .StoreNamedProperty(reg, reg, 0, LanguageMode::SLOPPY) |
56 .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY) | 60 .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY) |
57 .LoadNamedProperty(reg, 0, LanguageMode::STRICT) | 61 .LoadNamedProperty(reg, 0, LanguageMode::STRICT) |
58 .LoadKeyedProperty(reg, 0, LanguageMode::STRICT) | 62 .LoadKeyedProperty(reg, 0, LanguageMode::STRICT) |
59 .StoreNamedProperty(reg, reg, 0, LanguageMode::STRICT) | 63 .StoreNamedProperty(reg, reg, 0, LanguageMode::STRICT) |
60 .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); | 64 .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 // Longer jumps requiring Constant operand | 127 // Longer jumps requiring Constant operand |
124 builder.Jump(&start) | 128 builder.Jump(&start) |
125 .JumpIfTrue(&start) | 129 .JumpIfTrue(&start) |
126 .JumpIfFalse(&start) | 130 .JumpIfFalse(&start) |
127 .JumpIfToBooleanTrue(&start) | 131 .JumpIfToBooleanTrue(&start) |
128 .JumpIfToBooleanFalse(&start); | 132 .JumpIfToBooleanFalse(&start); |
129 builder.Return(); | 133 builder.Return(); |
130 | 134 |
131 // Generate BytecodeArray. | 135 // Generate BytecodeArray. |
132 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); | 136 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); |
133 CHECK_EQ(the_array->frame_size(), builder.locals_count() * kPointerSize); | 137 CHECK_EQ(the_array->frame_size(), |
| 138 builder.fixed_register_count() * kPointerSize); |
134 | 139 |
135 // Build scorecard of bytecodes encountered in the BytecodeArray. | 140 // Build scorecard of bytecodes encountered in the BytecodeArray. |
136 std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); | 141 std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); |
137 Bytecode final_bytecode = Bytecode::kLdaZero; | 142 Bytecode final_bytecode = Bytecode::kLdaZero; |
138 int i = 0; | 143 int i = 0; |
139 while (i < the_array->length()) { | 144 while (i < the_array->length()) { |
140 uint8_t code = the_array->get(i); | 145 uint8_t code = the_array->get(i); |
141 scorecard[code] += 1; | 146 scorecard[code] += 1; |
142 final_bytecode = Bytecodes::FromByte(code); | 147 final_bytecode = Bytecodes::FromByte(code); |
143 i += Bytecodes::Size(Bytecodes::FromByte(code)); | 148 i += Bytecodes::Size(Bytecodes::FromByte(code)); |
144 } | 149 } |
145 | 150 |
146 // Check return occurs at the end and only once in the BytecodeArray. | 151 // Check return occurs at the end and only once in the BytecodeArray. |
147 CHECK_EQ(final_bytecode, Bytecode::kReturn); | 152 CHECK_EQ(final_bytecode, Bytecode::kReturn); |
148 CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1); | 153 CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1); |
149 | 154 |
150 #define CHECK_BYTECODE_PRESENT(Name, ...) \ | 155 #define CHECK_BYTECODE_PRESENT(Name, ...) \ |
151 /* Check Bytecode is marked in scorecard */ \ | 156 /* Check Bytecode is marked in scorecard */ \ |
152 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); | 157 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); |
153 BYTECODE_LIST(CHECK_BYTECODE_PRESENT) | 158 BYTECODE_LIST(CHECK_BYTECODE_PRESENT) |
154 #undef CHECK_BYTECODE_PRESENT | 159 #undef CHECK_BYTECODE_PRESENT |
155 } | 160 } |
156 | 161 |
157 | 162 |
158 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { | 163 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { |
159 for (int locals = 0; locals < 5; locals++) { | 164 for (int locals = 0; locals < 5; locals++) { |
160 for (int temps = 0; temps < 3; temps++) { | 165 for (int contexts = 0; contexts < 4; contexts++) { |
161 BytecodeArrayBuilder builder(isolate(), zone()); | 166 for (int temps = 0; temps < 3; temps++) { |
162 builder.set_parameter_count(0); | 167 BytecodeArrayBuilder builder(isolate(), zone()); |
163 builder.set_locals_count(locals); | 168 builder.set_parameter_count(0); |
164 builder.Return(); | 169 builder.set_locals_count(locals); |
| 170 builder.set_context_count(contexts); |
| 171 builder.Return(); |
165 | 172 |
166 TemporaryRegisterScope temporaries(&builder); | 173 TemporaryRegisterScope temporaries(&builder); |
167 for (int i = 0; i < temps; i++) { | 174 for (int i = 0; i < temps; i++) { |
168 temporaries.NewRegister(); | 175 temporaries.NewRegister(); |
| 176 } |
| 177 |
| 178 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); |
| 179 int total_registers = locals + contexts + temps; |
| 180 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); |
169 } | 181 } |
170 | |
171 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); | |
172 int total_registers = locals + temps; | |
173 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); | |
174 } | 182 } |
175 } | 183 } |
176 } | 184 } |
177 | 185 |
178 | 186 |
179 TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) { | 187 TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) { |
180 BytecodeArrayBuilder builder(isolate(), zone()); | 188 BytecodeArrayBuilder builder(isolate(), zone()); |
181 builder.set_parameter_count(0); | 189 builder.set_parameter_count(0); |
182 builder.set_locals_count(0); | 190 builder.set_locals_count(0); |
| 191 builder.set_context_count(0); |
183 builder.Return(); | 192 builder.Return(); |
184 | 193 |
185 int first; | 194 int first; |
186 { | 195 { |
187 TemporaryRegisterScope temporaries(&builder); | 196 TemporaryRegisterScope temporaries(&builder); |
188 first = temporaries.NewRegister().index(); | 197 first = temporaries.NewRegister().index(); |
189 temporaries.NewRegister(); | 198 temporaries.NewRegister(); |
190 temporaries.NewRegister(); | 199 temporaries.NewRegister(); |
191 temporaries.NewRegister(); | 200 temporaries.NewRegister(); |
192 } | 201 } |
(...skipping 20 matching lines...) Expand all Loading... |
213 | 222 |
214 int actual_index = Register::FromOperand(actual_operand).index(); | 223 int actual_index = Register::FromOperand(actual_operand).index(); |
215 CHECK_EQ(actual_index, index); | 224 CHECK_EQ(actual_index, index); |
216 } | 225 } |
217 | 226 |
218 | 227 |
219 TEST_F(BytecodeArrayBuilderTest, Parameters) { | 228 TEST_F(BytecodeArrayBuilderTest, Parameters) { |
220 BytecodeArrayBuilder builder(isolate(), zone()); | 229 BytecodeArrayBuilder builder(isolate(), zone()); |
221 builder.set_parameter_count(10); | 230 builder.set_parameter_count(10); |
222 builder.set_locals_count(0); | 231 builder.set_locals_count(0); |
| 232 builder.set_context_count(0); |
223 | 233 |
224 Register param0(builder.Parameter(0)); | 234 Register param0(builder.Parameter(0)); |
225 Register param9(builder.Parameter(9)); | 235 Register param9(builder.Parameter(9)); |
226 CHECK_EQ(param9.index() - param0.index(), 9); | 236 CHECK_EQ(param9.index() - param0.index(), 9); |
227 } | 237 } |
228 | 238 |
229 | 239 |
230 TEST_F(BytecodeArrayBuilderTest, Constants) { | 240 TEST_F(BytecodeArrayBuilderTest, Constants) { |
231 BytecodeArrayBuilder builder(isolate(), zone()); | 241 BytecodeArrayBuilder builder(isolate(), zone()); |
232 builder.set_parameter_count(0); | 242 builder.set_parameter_count(0); |
233 builder.set_locals_count(0); | 243 builder.set_locals_count(0); |
| 244 builder.set_context_count(0); |
234 | 245 |
235 Factory* factory = isolate()->factory(); | 246 Factory* factory = isolate()->factory(); |
236 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); | 247 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); |
237 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); | 248 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); |
238 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate()); | 249 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate()); |
239 Handle<HeapObject> heap_num_2_copy(*heap_num_2); | 250 Handle<HeapObject> heap_num_2_copy(*heap_num_2); |
240 builder.LoadLiteral(heap_num_1) | 251 builder.LoadLiteral(heap_num_1) |
241 .LoadLiteral(heap_num_2) | 252 .LoadLiteral(heap_num_2) |
242 .LoadLiteral(large_smi) | 253 .LoadLiteral(large_smi) |
243 .LoadLiteral(heap_num_1) | 254 .LoadLiteral(heap_num_1) |
244 .LoadLiteral(heap_num_1) | 255 .LoadLiteral(heap_num_1) |
245 .LoadLiteral(heap_num_2_copy); | 256 .LoadLiteral(heap_num_2_copy); |
246 | 257 |
247 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 258 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
248 // Should only have one entry for each identical constant. | 259 // Should only have one entry for each identical constant. |
249 CHECK_EQ(array->constant_pool()->length(), 3); | 260 CHECK_EQ(array->constant_pool()->length(), 3); |
250 } | 261 } |
251 | 262 |
252 | 263 |
253 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { | 264 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { |
254 static const int kFarJumpDistance = 256; | 265 static const int kFarJumpDistance = 256; |
255 | 266 |
256 BytecodeArrayBuilder builder(isolate(), zone()); | 267 BytecodeArrayBuilder builder(isolate(), zone()); |
257 builder.set_parameter_count(0); | 268 builder.set_parameter_count(0); |
258 builder.set_locals_count(0); | 269 builder.set_locals_count(0); |
| 270 builder.set_context_count(0); |
259 | 271 |
260 BytecodeLabel far0, far1, far2; | 272 BytecodeLabel far0, far1, far2; |
261 BytecodeLabel near0, near1, near2; | 273 BytecodeLabel near0, near1, near2; |
262 | 274 |
263 builder.Jump(&near0) | 275 builder.Jump(&near0) |
264 .JumpIfTrue(&near1) | 276 .JumpIfTrue(&near1) |
265 .JumpIfFalse(&near2) | 277 .JumpIfFalse(&near2) |
266 .Bind(&near0) | 278 .Bind(&near0) |
267 .Bind(&near1) | 279 .Bind(&near1) |
268 .Bind(&near2) | 280 .Bind(&near2) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 Smi::cast(*iterator.GetConstantForIndexOperand(0))->value()), | 329 Smi::cast(*iterator.GetConstantForIndexOperand(0))->value()), |
318 Bytecodes::ToByte(Bytecode::kReturn)); | 330 Bytecodes::ToByte(Bytecode::kReturn)); |
319 iterator.Advance(); | 331 iterator.Advance(); |
320 } | 332 } |
321 | 333 |
322 | 334 |
323 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { | 335 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { |
324 BytecodeArrayBuilder builder(isolate(), zone()); | 336 BytecodeArrayBuilder builder(isolate(), zone()); |
325 builder.set_parameter_count(0); | 337 builder.set_parameter_count(0); |
326 builder.set_locals_count(0); | 338 builder.set_locals_count(0); |
| 339 builder.set_context_count(0); |
327 | 340 |
328 BytecodeLabel label0, label1, label2; | 341 BytecodeLabel label0, label1, label2; |
329 builder.Bind(&label0) | 342 builder.Bind(&label0) |
330 .Jump(&label0) | 343 .Jump(&label0) |
331 .Bind(&label1) | 344 .Bind(&label1) |
332 .JumpIfTrue(&label1) | 345 .JumpIfTrue(&label1) |
333 .Bind(&label2) | 346 .Bind(&label2) |
334 .JumpIfFalse(&label2); | 347 .JumpIfFalse(&label2); |
335 for (int i = 0; i < 64; i++) { | 348 for (int i = 0; i < 64; i++) { |
336 builder.Jump(&label2); | 349 builder.Jump(&label2); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 381 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
369 iterator.Advance(); | 382 iterator.Advance(); |
370 CHECK(iterator.done()); | 383 CHECK(iterator.done()); |
371 } | 384 } |
372 | 385 |
373 | 386 |
374 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { | 387 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { |
375 BytecodeArrayBuilder builder(isolate(), zone()); | 388 BytecodeArrayBuilder builder(isolate(), zone()); |
376 builder.set_parameter_count(0); | 389 builder.set_parameter_count(0); |
377 builder.set_locals_count(0); | 390 builder.set_locals_count(0); |
| 391 builder.set_context_count(0); |
378 | 392 |
379 // Labels can only have 1 forward reference, but | 393 // Labels can only have 1 forward reference, but |
380 // can be referred to mulitple times once bound. | 394 // can be referred to mulitple times once bound. |
381 BytecodeLabel label; | 395 BytecodeLabel label; |
382 | 396 |
383 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return(); | 397 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return(); |
384 | 398 |
385 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 399 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
386 BytecodeArrayIterator iterator(array); | 400 BytecodeArrayIterator iterator(array); |
387 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 401 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
(...skipping 10 matching lines...) Expand all Loading... |
398 CHECK(iterator.done()); | 412 CHECK(iterator.done()); |
399 } | 413 } |
400 | 414 |
401 | 415 |
402 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { | 416 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { |
403 static const int kRepeats = 3; | 417 static const int kRepeats = 3; |
404 | 418 |
405 BytecodeArrayBuilder builder(isolate(), zone()); | 419 BytecodeArrayBuilder builder(isolate(), zone()); |
406 builder.set_parameter_count(0); | 420 builder.set_parameter_count(0); |
407 builder.set_locals_count(0); | 421 builder.set_locals_count(0); |
| 422 builder.set_context_count(0); |
408 | 423 |
409 for (int i = 0; i < kRepeats; i++) { | 424 for (int i = 0; i < kRepeats; i++) { |
410 BytecodeLabel label; | 425 BytecodeLabel label; |
411 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); | 426 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); |
412 } | 427 } |
413 | 428 |
414 builder.Return(); | 429 builder.Return(); |
415 | 430 |
416 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 431 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
417 BytecodeArrayIterator iterator(array); | 432 BytecodeArrayIterator iterator(array); |
(...skipping 11 matching lines...) Expand all Loading... |
429 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 444 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
430 iterator.Advance(); | 445 iterator.Advance(); |
431 CHECK(iterator.done()); | 446 CHECK(iterator.done()); |
432 } | 447 } |
433 | 448 |
434 | 449 |
435 TEST_F(BytecodeArrayBuilderTest, ToBoolean) { | 450 TEST_F(BytecodeArrayBuilderTest, ToBoolean) { |
436 BytecodeArrayBuilder builder(isolate(), zone()); | 451 BytecodeArrayBuilder builder(isolate(), zone()); |
437 builder.set_parameter_count(0); | 452 builder.set_parameter_count(0); |
438 builder.set_locals_count(0); | 453 builder.set_locals_count(0); |
| 454 builder.set_context_count(0); |
439 | 455 |
440 // Check ToBoolean emitted at start of block. | 456 // Check ToBoolean emitted at start of block. |
441 builder.EnterBlock().CastAccumulatorToBoolean(); | 457 builder.EnterBlock().CastAccumulatorToBoolean(); |
442 | 458 |
443 // Check ToBoolean emitted preceding bytecode is non-boolean. | 459 // Check ToBoolean emitted preceding bytecode is non-boolean. |
444 builder.LoadNull().CastAccumulatorToBoolean(); | 460 builder.LoadNull().CastAccumulatorToBoolean(); |
445 | 461 |
446 // Check ToBoolean omitted if preceding bytecode is boolean. | 462 // Check ToBoolean omitted if preceding bytecode is boolean. |
447 builder.LoadFalse().CastAccumulatorToBoolean(); | 463 builder.LoadFalse().CastAccumulatorToBoolean(); |
448 | 464 |
(...skipping 26 matching lines...) Expand all Loading... |
475 | 491 |
476 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 492 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
477 iterator.Advance(); | 493 iterator.Advance(); |
478 CHECK(iterator.done()); | 494 CHECK(iterator.done()); |
479 } | 495 } |
480 | 496 |
481 | 497 |
482 } // namespace interpreter | 498 } // namespace interpreter |
483 } // namespace internal | 499 } // namespace internal |
484 } // namespace v8 | 500 } // namespace v8 |
OLD | NEW |