| 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 "src/interpreter/bytecode-register-allocator.h" | 9 #include "src/interpreter/bytecode-register-allocator.h" |
| 10 #include "test/unittests/test-utils.h" | 10 #include "test/unittests/test-utils.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 namespace interpreter { | 14 namespace interpreter { |
| 15 | 15 |
| 16 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { | 16 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { |
| 17 public: | 17 public: |
| 18 BytecodeArrayBuilderTest() {} | 18 BytecodeArrayBuilderTest() {} |
| 19 ~BytecodeArrayBuilderTest() override {} | 19 ~BytecodeArrayBuilderTest() override {} |
| 20 }; | 20 }; |
| 21 | 21 |
| 22 | 22 |
| 23 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { | 23 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { |
| 24 BytecodeArrayBuilder builder(isolate(), zone()); | 24 BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131); |
| 25 | 25 |
| 26 builder.set_locals_count(131); | |
| 27 builder.set_context_count(1); | |
| 28 builder.set_parameter_count(0); | |
| 29 CHECK_EQ(builder.locals_count(), 131); | 26 CHECK_EQ(builder.locals_count(), 131); |
| 30 CHECK_EQ(builder.context_count(), 1); | 27 CHECK_EQ(builder.context_count(), 1); |
| 31 CHECK_EQ(builder.fixed_register_count(), 132); | 28 CHECK_EQ(builder.fixed_register_count(), 132); |
| 32 | 29 |
| 33 // Emit constant loads. | 30 // Emit constant loads. |
| 34 builder.LoadLiteral(Smi::FromInt(0)) | 31 builder.LoadLiteral(Smi::FromInt(0)) |
| 35 .LoadLiteral(Smi::FromInt(8)) | 32 .LoadLiteral(Smi::FromInt(8)) |
| 36 .LoadLiteral(Smi::FromInt(10000000)) | 33 .LoadLiteral(Smi::FromInt(10000000)) |
| 37 .LoadUndefined() | 34 .LoadUndefined() |
| 38 .LoadNull() | 35 .LoadNull() |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); | 302 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); |
| 306 BYTECODE_LIST(CHECK_BYTECODE_PRESENT) | 303 BYTECODE_LIST(CHECK_BYTECODE_PRESENT) |
| 307 #undef CHECK_BYTECODE_PRESENT | 304 #undef CHECK_BYTECODE_PRESENT |
| 308 } | 305 } |
| 309 | 306 |
| 310 | 307 |
| 311 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { | 308 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { |
| 312 for (int locals = 0; locals < 5; locals++) { | 309 for (int locals = 0; locals < 5; locals++) { |
| 313 for (int contexts = 0; contexts < 4; contexts++) { | 310 for (int contexts = 0; contexts < 4; contexts++) { |
| 314 for (int temps = 0; temps < 3; temps++) { | 311 for (int temps = 0; temps < 3; temps++) { |
| 315 BytecodeArrayBuilder builder(isolate(), zone()); | 312 BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals); |
| 316 builder.set_parameter_count(0); | 313 BytecodeRegisterAllocator temporaries( |
| 317 builder.set_locals_count(locals); | 314 zone(), builder.temporary_register_allocator()); |
| 318 builder.set_context_count(contexts); | |
| 319 | |
| 320 BytecodeRegisterAllocator temporaries(&builder); | |
| 321 for (int i = 0; i < temps; i++) { | 315 for (int i = 0; i < temps; i++) { |
| 322 builder.StoreAccumulatorInRegister(temporaries.NewRegister()); | 316 builder.StoreAccumulatorInRegister(temporaries.NewRegister()); |
| 323 } | 317 } |
| 324 builder.Return(); | 318 builder.Return(); |
| 325 | 319 |
| 326 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); | 320 Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); |
| 327 int total_registers = locals + contexts + temps; | 321 int total_registers = locals + contexts + temps; |
| 328 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); | 322 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); |
| 329 } | 323 } |
| 330 } | 324 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 341 | 335 |
| 342 int actual_operand = the_register.ToOperand(); | 336 int actual_operand = the_register.ToOperand(); |
| 343 CHECK_EQ(actual_operand, operand); | 337 CHECK_EQ(actual_operand, operand); |
| 344 | 338 |
| 345 int actual_index = Register::FromOperand(actual_operand).index(); | 339 int actual_index = Register::FromOperand(actual_operand).index(); |
| 346 CHECK_EQ(actual_index, index); | 340 CHECK_EQ(actual_index, index); |
| 347 } | 341 } |
| 348 | 342 |
| 349 | 343 |
| 350 TEST_F(BytecodeArrayBuilderTest, Parameters) { | 344 TEST_F(BytecodeArrayBuilderTest, Parameters) { |
| 351 BytecodeArrayBuilder builder(isolate(), zone()); | 345 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0); |
| 352 builder.set_parameter_count(10); | |
| 353 builder.set_locals_count(0); | |
| 354 builder.set_context_count(0); | |
| 355 | |
| 356 Register param0(builder.Parameter(0)); | 346 Register param0(builder.Parameter(0)); |
| 357 Register param9(builder.Parameter(9)); | 347 Register param9(builder.Parameter(9)); |
| 358 CHECK_EQ(param9.index() - param0.index(), 9); | 348 CHECK_EQ(param9.index() - param0.index(), 9); |
| 359 } | 349 } |
| 360 | 350 |
| 361 | 351 |
| 362 TEST_F(BytecodeArrayBuilderTest, RegisterType) { | 352 TEST_F(BytecodeArrayBuilderTest, RegisterType) { |
| 363 BytecodeArrayBuilder builder(isolate(), zone()); | 353 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3); |
| 364 builder.set_parameter_count(10); | 354 BytecodeRegisterAllocator register_allocator( |
| 365 builder.set_locals_count(3); | 355 zone(), builder.temporary_register_allocator()); |
| 366 builder.set_context_count(0); | |
| 367 | |
| 368 BytecodeRegisterAllocator register_allocator(&builder); | |
| 369 Register temp0 = register_allocator.NewRegister(); | 356 Register temp0 = register_allocator.NewRegister(); |
| 370 Register param0(builder.Parameter(0)); | 357 Register param0(builder.Parameter(0)); |
| 371 Register param9(builder.Parameter(9)); | 358 Register param9(builder.Parameter(9)); |
| 372 Register temp1 = register_allocator.NewRegister(); | 359 Register temp1 = register_allocator.NewRegister(); |
| 373 Register reg0(0); | 360 Register reg0(0); |
| 374 Register reg1(1); | 361 Register reg1(1); |
| 375 Register reg2(2); | 362 Register reg2(2); |
| 376 Register temp2 = register_allocator.NewRegister(); | 363 Register temp2 = register_allocator.NewRegister(); |
| 377 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false); | 364 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false); |
| 378 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false); | 365 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false); |
| 379 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false); | 366 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false); |
| 380 CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true); | 367 CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true); |
| 381 CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true); | 368 CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true); |
| 382 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true); | 369 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true); |
| 383 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true); | 370 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true); |
| 384 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true); | 371 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true); |
| 385 } | 372 } |
| 386 | 373 |
| 387 | 374 |
| 388 TEST_F(BytecodeArrayBuilderTest, Constants) { | 375 TEST_F(BytecodeArrayBuilderTest, Constants) { |
| 389 BytecodeArrayBuilder builder(isolate(), zone()); | 376 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); |
| 390 builder.set_parameter_count(0); | |
| 391 builder.set_locals_count(0); | |
| 392 builder.set_context_count(0); | |
| 393 | |
| 394 Factory* factory = isolate()->factory(); | 377 Factory* factory = isolate()->factory(); |
| 395 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); | 378 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); |
| 396 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); | 379 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); |
| 397 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate()); | 380 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate()); |
| 398 Handle<HeapObject> heap_num_2_copy(*heap_num_2); | 381 Handle<HeapObject> heap_num_2_copy(*heap_num_2); |
| 399 builder.LoadLiteral(heap_num_1) | 382 builder.LoadLiteral(heap_num_1) |
| 400 .LoadLiteral(heap_num_2) | 383 .LoadLiteral(heap_num_2) |
| 401 .LoadLiteral(large_smi) | 384 .LoadLiteral(large_smi) |
| 402 .LoadLiteral(heap_num_1) | 385 .LoadLiteral(heap_num_1) |
| 403 .LoadLiteral(heap_num_1) | 386 .LoadLiteral(heap_num_1) |
| 404 .LoadLiteral(heap_num_2_copy); | 387 .LoadLiteral(heap_num_2_copy); |
| 405 | 388 |
| 406 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 389 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
| 407 // Should only have one entry for each identical constant. | 390 // Should only have one entry for each identical constant. |
| 408 CHECK_EQ(array->constant_pool()->length(), 3); | 391 CHECK_EQ(array->constant_pool()->length(), 3); |
| 409 } | 392 } |
| 410 | 393 |
| 411 | 394 |
| 412 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { | 395 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { |
| 413 static const int kFarJumpDistance = 256; | 396 static const int kFarJumpDistance = 256; |
| 414 | 397 |
| 415 BytecodeArrayBuilder builder(isolate(), zone()); | 398 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); |
| 416 builder.set_parameter_count(0); | |
| 417 builder.set_locals_count(1); | |
| 418 builder.set_context_count(0); | |
| 419 | |
| 420 Register reg(0); | 399 Register reg(0); |
| 421 BytecodeLabel far0, far1, far2, far3, far4; | 400 BytecodeLabel far0, far1, far2, far3, far4; |
| 422 BytecodeLabel near0, near1, near2, near3, near4; | 401 BytecodeLabel near0, near1, near2, near3, near4; |
| 423 | 402 |
| 424 builder.Jump(&near0) | 403 builder.Jump(&near0) |
| 425 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) | 404 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 426 .JumpIfTrue(&near1) | 405 .JumpIfTrue(&near1) |
| 427 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) | 406 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 428 .JumpIfFalse(&near2) | 407 .JumpIfFalse(&near2) |
| 429 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) | 408 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 | 500 |
| 522 CHECK_EQ(iterator.current_bytecode(), | 501 CHECK_EQ(iterator.current_bytecode(), |
| 523 Bytecode::kJumpIfToBooleanFalseConstant); | 502 Bytecode::kJumpIfToBooleanFalseConstant); |
| 524 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), | 503 CHECK_EQ(*iterator.GetConstantForIndexOperand(0), |
| 525 Smi::FromInt(kFarJumpDistance - 16)); | 504 Smi::FromInt(kFarJumpDistance - 16)); |
| 526 iterator.Advance(); | 505 iterator.Advance(); |
| 527 } | 506 } |
| 528 | 507 |
| 529 | 508 |
| 530 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { | 509 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { |
| 531 BytecodeArrayBuilder builder(isolate(), zone()); | 510 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); |
| 532 builder.set_parameter_count(0); | |
| 533 builder.set_locals_count(1); | |
| 534 builder.set_context_count(0); | |
| 535 Register reg(0); | 511 Register reg(0); |
| 536 | 512 |
| 537 BytecodeLabel label0, label1, label2, label3, label4; | 513 BytecodeLabel label0, label1, label2, label3, label4; |
| 538 builder.Bind(&label0) | 514 builder.Bind(&label0) |
| 539 .Jump(&label0) | 515 .Jump(&label0) |
| 540 .Bind(&label1) | 516 .Bind(&label1) |
| 541 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) | 517 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| 542 .JumpIfTrue(&label1) | 518 .JumpIfTrue(&label1) |
| 543 .Bind(&label2) | 519 .Bind(&label2) |
| 544 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) | 520 .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); | 593 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); |
| 618 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160); | 594 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160); |
| 619 iterator.Advance(); | 595 iterator.Advance(); |
| 620 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 596 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
| 621 iterator.Advance(); | 597 iterator.Advance(); |
| 622 CHECK(iterator.done()); | 598 CHECK(iterator.done()); |
| 623 } | 599 } |
| 624 | 600 |
| 625 | 601 |
| 626 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { | 602 TEST_F(BytecodeArrayBuilderTest, LabelReuse) { |
| 627 BytecodeArrayBuilder builder(isolate(), zone()); | 603 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); |
| 628 builder.set_parameter_count(0); | |
| 629 builder.set_locals_count(0); | |
| 630 builder.set_context_count(0); | |
| 631 | 604 |
| 632 // Labels can only have 1 forward reference, but | 605 // Labels can only have 1 forward reference, but |
| 633 // can be referred to mulitple times once bound. | 606 // can be referred to mulitple times once bound. |
| 634 BytecodeLabel label; | 607 BytecodeLabel label; |
| 635 | 608 |
| 636 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return(); | 609 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return(); |
| 637 | 610 |
| 638 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 611 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
| 639 BytecodeArrayIterator iterator(array); | 612 BytecodeArrayIterator iterator(array); |
| 640 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 613 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 641 CHECK_EQ(iterator.GetImmediateOperand(0), 2); | 614 CHECK_EQ(iterator.GetImmediateOperand(0), 2); |
| 642 iterator.Advance(); | 615 iterator.Advance(); |
| 643 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 616 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 644 CHECK_EQ(iterator.GetImmediateOperand(0), 0); | 617 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
| 645 iterator.Advance(); | 618 iterator.Advance(); |
| 646 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 619 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 647 CHECK_EQ(iterator.GetImmediateOperand(0), -2); | 620 CHECK_EQ(iterator.GetImmediateOperand(0), -2); |
| 648 iterator.Advance(); | 621 iterator.Advance(); |
| 649 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 622 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
| 650 iterator.Advance(); | 623 iterator.Advance(); |
| 651 CHECK(iterator.done()); | 624 CHECK(iterator.done()); |
| 652 } | 625 } |
| 653 | 626 |
| 654 | 627 |
| 655 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { | 628 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { |
| 656 static const int kRepeats = 3; | 629 static const int kRepeats = 3; |
| 657 | 630 |
| 658 BytecodeArrayBuilder builder(isolate(), zone()); | 631 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); |
| 659 builder.set_parameter_count(0); | |
| 660 builder.set_locals_count(0); | |
| 661 builder.set_context_count(0); | |
| 662 | |
| 663 for (int i = 0; i < kRepeats; i++) { | 632 for (int i = 0; i < kRepeats; i++) { |
| 664 BytecodeLabel label; | 633 BytecodeLabel label; |
| 665 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); | 634 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); |
| 666 } | 635 } |
| 667 | |
| 668 builder.Return(); | 636 builder.Return(); |
| 669 | 637 |
| 670 Handle<BytecodeArray> array = builder.ToBytecodeArray(); | 638 Handle<BytecodeArray> array = builder.ToBytecodeArray(); |
| 671 BytecodeArrayIterator iterator(array); | 639 BytecodeArrayIterator iterator(array); |
| 672 for (int i = 0; i < kRepeats; i++) { | 640 for (int i = 0; i < kRepeats; i++) { |
| 673 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 641 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 674 CHECK_EQ(iterator.GetImmediateOperand(0), 2); | 642 CHECK_EQ(iterator.GetImmediateOperand(0), 2); |
| 675 iterator.Advance(); | 643 iterator.Advance(); |
| 676 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 644 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 677 CHECK_EQ(iterator.GetImmediateOperand(0), 0); | 645 CHECK_EQ(iterator.GetImmediateOperand(0), 0); |
| 678 iterator.Advance(); | 646 iterator.Advance(); |
| 679 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); | 647 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); |
| 680 CHECK_EQ(iterator.GetImmediateOperand(0), -2); | 648 CHECK_EQ(iterator.GetImmediateOperand(0), -2); |
| 681 iterator.Advance(); | 649 iterator.Advance(); |
| 682 } | 650 } |
| 683 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); | 651 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); |
| 684 iterator.Advance(); | 652 iterator.Advance(); |
| 685 CHECK(iterator.done()); | 653 CHECK(iterator.done()); |
| 686 } | 654 } |
| 687 | 655 |
| 688 } // namespace interpreter | 656 } // namespace interpreter |
| 689 } // namespace internal | 657 } // namespace internal |
| 690 } // namespace v8 | 658 } // namespace v8 |
| OLD | NEW |