OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/base/utils/random-number-generator.h" |
5 #include "src/interface-descriptors.h" | 6 #include "src/interface-descriptors.h" |
6 #include "src/isolate.h" | 7 #include "src/isolate.h" |
7 #include "test/cctest/compiler/function-tester.h" | 8 #include "test/cctest/compiler/function-tester.h" |
8 | 9 |
9 namespace v8 { | 10 namespace v8 { |
10 namespace internal { | 11 namespace internal { |
11 | 12 |
12 using compiler::FunctionTester; | 13 using compiler::FunctionTester; |
13 using compiler::Node; | 14 using compiler::Node; |
14 | 15 |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 | 390 |
390 a = m.UndefinedConstant(); | 391 a = m.UndefinedConstant(); |
391 CHECK(!m.ToInt32Constant(a, value32)); | 392 CHECK(!m.ToInt32Constant(a, value32)); |
392 CHECK(!m.ToInt64Constant(a, value64)); | 393 CHECK(!m.ToInt64Constant(a, value64)); |
393 | 394 |
394 a = m.UndefinedConstant(); | 395 a = m.UndefinedConstant(); |
395 CHECK(!m.ToInt32Constant(a, value32)); | 396 CHECK(!m.ToInt32Constant(a, value32)); |
396 CHECK(!m.ToInt64Constant(a, value64)); | 397 CHECK(!m.ToInt64Constant(a, value64)); |
397 } | 398 } |
398 | 399 |
| 400 TEST(ComputeIntegerHash) { |
| 401 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 402 const int param_count = 2; |
| 403 CodeStubAssemblerTester m(isolate, param_count); |
| 404 m.Return(m.SmiFromWord32(m.ComputeIntegerHash( |
| 405 m.SmiToWord32(m.Parameter(0)), m.SmiToWord32(m.Parameter(1))))); |
| 406 |
| 407 Handle<Code> code = m.GenerateCode(); |
| 408 FunctionTester ft(code, param_count); |
| 409 |
| 410 Handle<Smi> hash_seed = isolate->factory()->hash_seed(); |
| 411 |
| 412 base::RandomNumberGenerator rand_gen(FLAG_random_seed); |
| 413 |
| 414 for (int i = 0; i < 1024; i++) { |
| 415 int k = rand_gen.NextInt(Smi::kMaxValue); |
| 416 |
| 417 Handle<Smi> key(Smi::FromInt(k), isolate); |
| 418 Handle<Object> result = ft.Call(key, hash_seed).ToHandleChecked(); |
| 419 |
| 420 uint32_t hash = ComputeIntegerHash(k, hash_seed->value()); |
| 421 Smi* expected = Smi::FromInt(hash & Smi::kMaxValue); |
| 422 CHECK_EQ(expected, Smi::cast(*result)); |
| 423 } |
| 424 } |
| 425 |
| 426 TEST(TryToName) { |
| 427 typedef CodeStubAssembler::Label Label; |
| 428 typedef CodeStubAssembler::Variable Variable; |
| 429 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 430 |
| 431 const int param_count = 3; |
| 432 CodeStubAssemblerTester m(isolate, param_count); |
| 433 |
| 434 enum Result { kKeyIsIndex, kKeyIsUnique, kBailout }; |
| 435 { |
| 436 Node* key = m.Parameter(0); |
| 437 Node* expected_result = m.Parameter(1); |
| 438 Node* expected_arg = m.Parameter(2); |
| 439 |
| 440 Label passed(&m), failed(&m); |
| 441 Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m); |
| 442 Variable var_index(&m, MachineRepresentation::kWord32); |
| 443 |
| 444 m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout); |
| 445 |
| 446 m.Bind(&if_keyisindex); |
| 447 m.GotoUnless( |
| 448 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))), |
| 449 &failed); |
| 450 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_index.value()), |
| 451 &passed, &failed); |
| 452 |
| 453 m.Bind(&if_keyisunique); |
| 454 m.GotoUnless( |
| 455 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsUnique))), |
| 456 &failed); |
| 457 m.Branch(m.WordEqual(expected_arg, key), &passed, &failed); |
| 458 |
| 459 m.Bind(&if_bailout); |
| 460 m.Branch( |
| 461 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), |
| 462 &passed, &failed); |
| 463 |
| 464 m.Bind(&passed); |
| 465 m.Return(m.BooleanConstant(true)); |
| 466 |
| 467 m.Bind(&failed); |
| 468 m.Return(m.BooleanConstant(false)); |
| 469 } |
| 470 |
| 471 Handle<Code> code = m.GenerateCode(); |
| 472 FunctionTester ft(code, param_count); |
| 473 |
| 474 Handle<Object> expect_index(Smi::FromInt(kKeyIsIndex), isolate); |
| 475 Handle<Object> expect_unique(Smi::FromInt(kKeyIsUnique), isolate); |
| 476 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); |
| 477 |
| 478 { |
| 479 // TryToName(<zero smi>) => if_keyisindex: smi value. |
| 480 Handle<Object> key(Smi::FromInt(0), isolate); |
| 481 ft.CheckTrue(key, expect_index, key); |
| 482 } |
| 483 |
| 484 { |
| 485 // TryToName(<positive smi>) => if_keyisindex: smi value. |
| 486 Handle<Object> key(Smi::FromInt(153), isolate); |
| 487 ft.CheckTrue(key, expect_index, key); |
| 488 } |
| 489 |
| 490 { |
| 491 // TryToName(<negative smi>) => bailout. |
| 492 Handle<Object> key(Smi::FromInt(-1), isolate); |
| 493 ft.CheckTrue(key, expect_bailout); |
| 494 } |
| 495 |
| 496 { |
| 497 // TryToName(<symbol>) => if_keyisunique: <symbol>. |
| 498 Handle<Object> key = isolate->factory()->NewSymbol(); |
| 499 ft.CheckTrue(key, expect_unique, key); |
| 500 } |
| 501 |
| 502 { |
| 503 // TryToName(<internalized string>) => if_keyisunique: <internalized string> |
| 504 Handle<Object> key = isolate->factory()->InternalizeUtf8String("test"); |
| 505 ft.CheckTrue(key, expect_unique, key); |
| 506 } |
| 507 |
| 508 { |
| 509 // TryToName(<internalized number string>) => if_keyisindex: number. |
| 510 Handle<Object> key = isolate->factory()->InternalizeUtf8String("153"); |
| 511 Handle<Object> index(Smi::FromInt(153), isolate); |
| 512 ft.CheckTrue(key, expect_index, index); |
| 513 } |
| 514 |
| 515 { |
| 516 // TryToName(<non-internalized string>) => bailout. |
| 517 Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test"); |
| 518 ft.CheckTrue(key, expect_bailout); |
| 519 } |
| 520 } |
| 521 |
| 522 namespace { |
| 523 |
| 524 template <typename Dictionary> |
| 525 void TestNameDictionaryLookup() { |
| 526 typedef CodeStubAssembler::Label Label; |
| 527 typedef CodeStubAssembler::Variable Variable; |
| 528 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 529 |
| 530 const int param_count = 4; |
| 531 CodeStubAssemblerTester m(isolate, param_count); |
| 532 |
| 533 enum Result { kFound, kNotFound }; |
| 534 { |
| 535 Node* dictionary = m.Parameter(0); |
| 536 Node* unique_name = m.Parameter(1); |
| 537 Node* expected_result = m.Parameter(2); |
| 538 Node* expected_arg = m.Parameter(3); |
| 539 |
| 540 Label passed(&m), failed(&m); |
| 541 Label if_found(&m), if_not_found(&m); |
| 542 Variable var_entry(&m, MachineRepresentation::kWord32); |
| 543 |
| 544 m.NameDictionaryLookup<Dictionary>(dictionary, unique_name, &if_found, |
| 545 &var_entry, &if_not_found); |
| 546 m.Bind(&if_found); |
| 547 m.GotoUnless( |
| 548 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), |
| 549 &failed); |
| 550 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()), |
| 551 &passed, &failed); |
| 552 |
| 553 m.Bind(&if_not_found); |
| 554 m.Branch( |
| 555 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), |
| 556 &passed, &failed); |
| 557 |
| 558 m.Bind(&passed); |
| 559 m.Return(m.BooleanConstant(true)); |
| 560 |
| 561 m.Bind(&failed); |
| 562 m.Return(m.BooleanConstant(false)); |
| 563 } |
| 564 |
| 565 Handle<Code> code = m.GenerateCode(); |
| 566 FunctionTester ft(code, param_count); |
| 567 |
| 568 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); |
| 569 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); |
| 570 |
| 571 Handle<Dictionary> dictionary = Dictionary::New(isolate, 40); |
| 572 PropertyDetails fake_details = PropertyDetails::Empty(); |
| 573 |
| 574 Factory* factory = isolate->factory(); |
| 575 Handle<Name> keys[] = { |
| 576 factory->InternalizeUtf8String("0"), |
| 577 factory->InternalizeUtf8String("42"), |
| 578 factory->InternalizeUtf8String("-153"), |
| 579 factory->InternalizeUtf8String("0.0"), |
| 580 factory->InternalizeUtf8String("4.2"), |
| 581 factory->InternalizeUtf8String(""), |
| 582 factory->InternalizeUtf8String("name"), |
| 583 factory->NewSymbol(), |
| 584 factory->NewPrivateSymbol(), |
| 585 }; |
| 586 |
| 587 for (size_t i = 0; i < arraysize(keys); i++) { |
| 588 Handle<Object> value = factory->NewPropertyCell(); |
| 589 dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details); |
| 590 } |
| 591 |
| 592 for (size_t i = 0; i < arraysize(keys); i++) { |
| 593 int entry = dictionary->FindEntry(keys[i]); |
| 594 CHECK_NE(Dictionary::kNotFound, entry); |
| 595 |
| 596 Handle<Object> expected_entry(Smi::FromInt(entry), isolate); |
| 597 ft.CheckTrue(dictionary, keys[i], expect_found, expected_entry); |
| 598 } |
| 599 |
| 600 Handle<Name> non_existing_keys[] = { |
| 601 factory->InternalizeUtf8String("1"), |
| 602 factory->InternalizeUtf8String("-42"), |
| 603 factory->InternalizeUtf8String("153"), |
| 604 factory->InternalizeUtf8String("-1.0"), |
| 605 factory->InternalizeUtf8String("1.3"), |
| 606 factory->InternalizeUtf8String("a"), |
| 607 factory->InternalizeUtf8String("boom"), |
| 608 factory->NewSymbol(), |
| 609 factory->NewPrivateSymbol(), |
| 610 }; |
| 611 |
| 612 for (size_t i = 0; i < arraysize(non_existing_keys); i++) { |
| 613 int entry = dictionary->FindEntry(non_existing_keys[i]); |
| 614 CHECK_EQ(Dictionary::kNotFound, entry); |
| 615 |
| 616 ft.CheckTrue(dictionary, non_existing_keys[i], expect_not_found); |
| 617 } |
| 618 } |
| 619 |
| 620 } // namespace |
| 621 |
| 622 TEST(NameDictionaryLookup) { TestNameDictionaryLookup<NameDictionary>(); } |
| 623 |
| 624 TEST(GlobalDictionaryLookup) { TestNameDictionaryLookup<GlobalDictionary>(); } |
| 625 |
| 626 namespace { |
| 627 |
| 628 template <typename Dictionary> |
| 629 void TestNumberDictionaryLookup() { |
| 630 typedef CodeStubAssembler::Label Label; |
| 631 typedef CodeStubAssembler::Variable Variable; |
| 632 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 633 |
| 634 const int param_count = 4; |
| 635 CodeStubAssemblerTester m(isolate, param_count); |
| 636 |
| 637 enum Result { kFound, kNotFound }; |
| 638 { |
| 639 Node* dictionary = m.Parameter(0); |
| 640 Node* key = m.SmiToWord32(m.Parameter(1)); |
| 641 Node* expected_result = m.Parameter(2); |
| 642 Node* expected_arg = m.Parameter(3); |
| 643 |
| 644 Label passed(&m), failed(&m); |
| 645 Label if_found(&m), if_not_found(&m); |
| 646 Variable var_entry(&m, MachineRepresentation::kWord32); |
| 647 |
| 648 m.NumberDictionaryLookup<Dictionary>(dictionary, key, &if_found, &var_entry, |
| 649 &if_not_found); |
| 650 m.Bind(&if_found); |
| 651 m.GotoUnless( |
| 652 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), |
| 653 &failed); |
| 654 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()), |
| 655 &passed, &failed); |
| 656 |
| 657 m.Bind(&if_not_found); |
| 658 m.Branch( |
| 659 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), |
| 660 &passed, &failed); |
| 661 |
| 662 m.Bind(&passed); |
| 663 m.Return(m.BooleanConstant(true)); |
| 664 |
| 665 m.Bind(&failed); |
| 666 m.Return(m.BooleanConstant(false)); |
| 667 } |
| 668 |
| 669 Handle<Code> code = m.GenerateCode(); |
| 670 FunctionTester ft(code, param_count); |
| 671 |
| 672 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); |
| 673 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); |
| 674 |
| 675 const int kKeysCount = 1000; |
| 676 Handle<Dictionary> dictionary = Dictionary::New(isolate, kKeysCount); |
| 677 uint32_t keys[kKeysCount]; |
| 678 |
| 679 Handle<Object> fake_value(Smi::FromInt(42), isolate); |
| 680 PropertyDetails fake_details = PropertyDetails::Empty(); |
| 681 |
| 682 base::RandomNumberGenerator rand_gen(FLAG_random_seed); |
| 683 |
| 684 for (int i = 0; i < kKeysCount; i++) { |
| 685 int random_key = rand_gen.NextInt(Smi::kMaxValue); |
| 686 keys[i] = static_cast<uint32_t>(random_key); |
| 687 |
| 688 dictionary = Dictionary::Add(dictionary, keys[i], fake_value, fake_details); |
| 689 } |
| 690 |
| 691 // Now try querying existing keys. |
| 692 for (int i = 0; i < kKeysCount; i++) { |
| 693 int entry = dictionary->FindEntry(keys[i]); |
| 694 CHECK_NE(Dictionary::kNotFound, entry); |
| 695 |
| 696 Handle<Object> key(Smi::FromInt(keys[i]), isolate); |
| 697 Handle<Object> expected_entry(Smi::FromInt(entry), isolate); |
| 698 ft.CheckTrue(dictionary, key, expect_found, expected_entry); |
| 699 } |
| 700 |
| 701 // Now try querying random keys which do not exist in the dictionary. |
| 702 for (int i = 0; i < kKeysCount;) { |
| 703 int random_key = rand_gen.NextInt(Smi::kMaxValue); |
| 704 int entry = dictionary->FindEntry(random_key); |
| 705 if (entry != Dictionary::kNotFound) continue; |
| 706 i++; |
| 707 |
| 708 Handle<Object> key(Smi::FromInt(random_key), isolate); |
| 709 ft.CheckTrue(dictionary, key, expect_not_found); |
| 710 } |
| 711 } |
| 712 |
| 713 } // namespace |
| 714 |
| 715 TEST(SeededNumberDictionaryLookup) { |
| 716 TestNumberDictionaryLookup<SeededNumberDictionary>(); |
| 717 } |
| 718 |
| 719 TEST(UnseededNumberDictionaryLookup) { |
| 720 TestNumberDictionaryLookup<UnseededNumberDictionary>(); |
| 721 } |
| 722 |
| 723 namespace { |
| 724 |
| 725 void AddProperties(Handle<JSObject> object, Handle<Name> names[], |
| 726 size_t count) { |
| 727 Handle<Object> value(Smi::FromInt(42), object->GetIsolate()); |
| 728 for (size_t i = 0; i < count; i++) { |
| 729 JSObject::AddProperty(object, names[i], value, NONE); |
| 730 } |
| 731 } |
| 732 |
| 733 } // namespace |
| 734 |
| 735 TEST(TryLookupProperty) { |
| 736 typedef CodeStubAssembler::Label Label; |
| 737 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 738 |
| 739 const int param_count = 4; |
| 740 CodeStubAssemblerTester m(isolate, param_count); |
| 741 |
| 742 enum Result { kFound, kNotFound, kBailout }; |
| 743 { |
| 744 Node* object = m.Parameter(0); |
| 745 Node* unique_name = m.Parameter(1); |
| 746 Node* expected_result = m.Parameter(2); |
| 747 |
| 748 Label passed(&m), failed(&m); |
| 749 Label if_found(&m), if_not_found(&m), if_bailout(&m); |
| 750 |
| 751 Node* map = m.LoadMap(object); |
| 752 Node* instance_type = m.LoadMapInstanceType(map); |
| 753 |
| 754 m.TryLookupProperty(object, map, instance_type, unique_name, &if_found, |
| 755 &if_not_found, &if_bailout); |
| 756 |
| 757 m.Bind(&if_found); |
| 758 m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), |
| 759 &passed, &failed); |
| 760 |
| 761 m.Bind(&if_not_found); |
| 762 m.Branch( |
| 763 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), |
| 764 &passed, &failed); |
| 765 |
| 766 m.Bind(&if_bailout); |
| 767 m.Branch( |
| 768 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), |
| 769 &passed, &failed); |
| 770 |
| 771 m.Bind(&passed); |
| 772 m.Return(m.BooleanConstant(true)); |
| 773 |
| 774 m.Bind(&failed); |
| 775 m.Return(m.BooleanConstant(false)); |
| 776 } |
| 777 |
| 778 Handle<Code> code = m.GenerateCode(); |
| 779 FunctionTester ft(code, param_count); |
| 780 |
| 781 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); |
| 782 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); |
| 783 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); |
| 784 |
| 785 Factory* factory = isolate->factory(); |
| 786 Handle<Name> names[] = { |
| 787 factory->InternalizeUtf8String("a"), |
| 788 factory->InternalizeUtf8String("bb"), |
| 789 factory->InternalizeUtf8String("ccc"), |
| 790 factory->InternalizeUtf8String("dddd"), |
| 791 factory->InternalizeUtf8String("eeeee"), |
| 792 factory->InternalizeUtf8String(""), |
| 793 factory->InternalizeUtf8String("name"), |
| 794 factory->NewSymbol(), |
| 795 factory->NewPrivateSymbol(), |
| 796 }; |
| 797 |
| 798 std::vector<Handle<JSObject>> objects; |
| 799 |
| 800 { |
| 801 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); |
| 802 Handle<JSObject> object = factory->NewJSObject(function); |
| 803 AddProperties(object, names, arraysize(names)); |
| 804 CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); |
| 805 CHECK(!object->map()->is_dictionary_map()); |
| 806 objects.push_back(object); |
| 807 } |
| 808 |
| 809 { |
| 810 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); |
| 811 Handle<JSObject> object = factory->NewJSObject(function); |
| 812 AddProperties(object, names, arraysize(names)); |
| 813 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test"); |
| 814 CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); |
| 815 CHECK(object->map()->is_dictionary_map()); |
| 816 objects.push_back(object); |
| 817 } |
| 818 |
| 819 { |
| 820 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); |
| 821 JSFunction::EnsureHasInitialMap(function); |
| 822 function->initial_map()->set_instance_type(JS_GLOBAL_OBJECT_TYPE); |
| 823 function->initial_map()->set_is_prototype_map(true); |
| 824 function->initial_map()->set_dictionary_map(true); |
| 825 Handle<JSObject> object = factory->NewJSGlobalObject(function); |
| 826 AddProperties(object, names, arraysize(names)); |
| 827 CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); |
| 828 CHECK(object->map()->is_dictionary_map()); |
| 829 objects.push_back(object); |
| 830 } |
| 831 |
| 832 { |
| 833 for (Handle<JSObject> object : objects) { |
| 834 for (size_t name_index = 0; name_index < arraysize(names); name_index++) { |
| 835 Handle<Name> name = names[name_index]; |
| 836 CHECK(JSReceiver::HasProperty(object, name).FromJust()); |
| 837 ft.CheckTrue(object, name, expect_found); |
| 838 } |
| 839 } |
| 840 } |
| 841 |
| 842 { |
| 843 Handle<Name> non_existing_names[] = { |
| 844 factory->InternalizeUtf8String("ne_a"), |
| 845 factory->InternalizeUtf8String("ne_bb"), |
| 846 factory->InternalizeUtf8String("ne_ccc"), |
| 847 factory->InternalizeUtf8String("ne_dddd"), |
| 848 }; |
| 849 for (Handle<JSObject> object : objects) { |
| 850 for (size_t key_index = 0; key_index < arraysize(non_existing_names); |
| 851 key_index++) { |
| 852 Handle<Name> key = non_existing_names[key_index]; |
| 853 CHECK(!JSReceiver::HasProperty(object, key).FromJust()); |
| 854 ft.CheckTrue(object, key, expect_not_found); |
| 855 } |
| 856 } |
| 857 } |
| 858 |
| 859 { |
| 860 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); |
| 861 Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]); |
| 862 CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); |
| 863 ft.CheckTrue(object, names[0], expect_bailout); |
| 864 } |
| 865 |
| 866 { |
| 867 Handle<JSObject> object = isolate->global_proxy(); |
| 868 CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); |
| 869 ft.CheckTrue(object, names[0], expect_bailout); |
| 870 } |
| 871 } |
| 872 |
| 873 namespace { |
| 874 |
| 875 void AddElement(Handle<JSObject> object, uint32_t index, Handle<Object> value, |
| 876 PropertyAttributes attributes = NONE) { |
| 877 JSObject::AddDataElement(object, index, value, attributes).ToHandleChecked(); |
| 878 } |
| 879 |
| 880 } // namespace |
| 881 |
| 882 TEST(TryLookupElement) { |
| 883 typedef CodeStubAssembler::Label Label; |
| 884 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 885 |
| 886 const int param_count = 4; |
| 887 CodeStubAssemblerTester m(isolate, param_count); |
| 888 |
| 889 enum Result { kFound, kNotFound, kBailout }; |
| 890 { |
| 891 Node* object = m.Parameter(0); |
| 892 Node* index = m.SmiToWord32(m.Parameter(1)); |
| 893 Node* expected_result = m.Parameter(2); |
| 894 |
| 895 Label passed(&m), failed(&m); |
| 896 Label if_found(&m), if_not_found(&m), if_bailout(&m); |
| 897 |
| 898 Node* map = m.LoadMap(object); |
| 899 Node* instance_type = m.LoadMapInstanceType(map); |
| 900 |
| 901 m.TryLookupElement(object, map, instance_type, index, &if_found, |
| 902 &if_not_found, &if_bailout); |
| 903 |
| 904 m.Bind(&if_found); |
| 905 m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), |
| 906 &passed, &failed); |
| 907 |
| 908 m.Bind(&if_not_found); |
| 909 m.Branch( |
| 910 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), |
| 911 &passed, &failed); |
| 912 |
| 913 m.Bind(&if_bailout); |
| 914 m.Branch( |
| 915 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), |
| 916 &passed, &failed); |
| 917 |
| 918 m.Bind(&passed); |
| 919 m.Return(m.BooleanConstant(true)); |
| 920 |
| 921 m.Bind(&failed); |
| 922 m.Return(m.BooleanConstant(false)); |
| 923 } |
| 924 |
| 925 Handle<Code> code = m.GenerateCode(); |
| 926 FunctionTester ft(code, param_count); |
| 927 |
| 928 Factory* factory = isolate->factory(); |
| 929 Handle<Object> smi0(Smi::FromInt(0), isolate); |
| 930 Handle<Object> smi1(Smi::FromInt(1), isolate); |
| 931 Handle<Object> smi7(Smi::FromInt(7), isolate); |
| 932 Handle<Object> smi13(Smi::FromInt(13), isolate); |
| 933 Handle<Object> smi42(Smi::FromInt(42), isolate); |
| 934 |
| 935 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); |
| 936 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); |
| 937 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); |
| 938 |
| 939 #define CHECK_FOUND(object, index) \ |
| 940 CHECK(JSReceiver::HasElement(object, index).FromJust()); \ |
| 941 ft.CheckTrue(object, smi##index, expect_found); |
| 942 |
| 943 #define CHECK_NOT_FOUND(object, index) \ |
| 944 CHECK(!JSReceiver::HasElement(object, index).FromJust()); \ |
| 945 ft.CheckTrue(object, smi##index, expect_not_found); |
| 946 |
| 947 { |
| 948 Handle<JSArray> object = factory->NewJSArray(0, FAST_SMI_ELEMENTS); |
| 949 AddElement(object, 0, smi0); |
| 950 AddElement(object, 1, smi0); |
| 951 CHECK_EQ(FAST_SMI_ELEMENTS, object->map()->elements_kind()); |
| 952 |
| 953 CHECK_FOUND(object, 0); |
| 954 CHECK_FOUND(object, 1); |
| 955 CHECK_NOT_FOUND(object, 7); |
| 956 CHECK_NOT_FOUND(object, 13); |
| 957 CHECK_NOT_FOUND(object, 42); |
| 958 } |
| 959 |
| 960 { |
| 961 Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); |
| 962 AddElement(object, 0, smi0); |
| 963 AddElement(object, 13, smi0); |
| 964 CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, object->map()->elements_kind()); |
| 965 |
| 966 CHECK_FOUND(object, 0); |
| 967 CHECK_NOT_FOUND(object, 1); |
| 968 CHECK_NOT_FOUND(object, 7); |
| 969 CHECK_FOUND(object, 13); |
| 970 CHECK_NOT_FOUND(object, 42); |
| 971 } |
| 972 |
| 973 { |
| 974 Handle<JSArray> object = factory->NewJSArray(0, FAST_ELEMENTS); |
| 975 AddElement(object, 0, smi0); |
| 976 AddElement(object, 1, smi0); |
| 977 CHECK_EQ(FAST_ELEMENTS, object->map()->elements_kind()); |
| 978 |
| 979 CHECK_FOUND(object, 0); |
| 980 CHECK_FOUND(object, 1); |
| 981 CHECK_NOT_FOUND(object, 7); |
| 982 CHECK_NOT_FOUND(object, 13); |
| 983 CHECK_NOT_FOUND(object, 42); |
| 984 } |
| 985 |
| 986 { |
| 987 Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_ELEMENTS); |
| 988 AddElement(object, 0, smi0); |
| 989 AddElement(object, 13, smi0); |
| 990 CHECK_EQ(FAST_HOLEY_ELEMENTS, object->map()->elements_kind()); |
| 991 |
| 992 CHECK_FOUND(object, 0); |
| 993 CHECK_NOT_FOUND(object, 1); |
| 994 CHECK_NOT_FOUND(object, 7); |
| 995 CHECK_FOUND(object, 13); |
| 996 CHECK_NOT_FOUND(object, 42); |
| 997 } |
| 998 |
| 999 { |
| 1000 Handle<JSFunction> constructor = isolate->string_function(); |
| 1001 Handle<JSObject> object = factory->NewJSObject(constructor); |
| 1002 Handle<String> str = factory->InternalizeUtf8String("ab"); |
| 1003 Handle<JSValue>::cast(object)->set_value(*str); |
| 1004 AddElement(object, 13, smi0); |
| 1005 CHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); |
| 1006 |
| 1007 CHECK_FOUND(object, 0); |
| 1008 CHECK_FOUND(object, 1); |
| 1009 CHECK_NOT_FOUND(object, 7); |
| 1010 CHECK_FOUND(object, 13); |
| 1011 CHECK_NOT_FOUND(object, 42); |
| 1012 } |
| 1013 |
| 1014 { |
| 1015 Handle<JSFunction> constructor = isolate->string_function(); |
| 1016 Handle<JSObject> object = factory->NewJSObject(constructor); |
| 1017 Handle<String> str = factory->InternalizeUtf8String("ab"); |
| 1018 Handle<JSValue>::cast(object)->set_value(*str); |
| 1019 AddElement(object, 13, smi0); |
| 1020 JSObject::NormalizeElements(object); |
| 1021 CHECK_EQ(SLOW_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); |
| 1022 |
| 1023 CHECK_FOUND(object, 0); |
| 1024 CHECK_FOUND(object, 1); |
| 1025 CHECK_NOT_FOUND(object, 7); |
| 1026 CHECK_FOUND(object, 13); |
| 1027 CHECK_NOT_FOUND(object, 42); |
| 1028 } |
| 1029 |
| 1030 // TODO(ishell): uncomment once NO_ELEMENTS kind is supported. |
| 1031 // { |
| 1032 // Handle<Map> map = Map::Create(isolate, 0); |
| 1033 // map->set_elements_kind(NO_ELEMENTS); |
| 1034 // Handle<JSObject> object = factory->NewJSObjectFromMap(map); |
| 1035 // CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind()); |
| 1036 // |
| 1037 // CHECK_NOT_FOUND(object, 0); |
| 1038 // CHECK_NOT_FOUND(object, 1); |
| 1039 // CHECK_NOT_FOUND(object, 7); |
| 1040 // CHECK_NOT_FOUND(object, 13); |
| 1041 // CHECK_NOT_FOUND(object, 42); |
| 1042 // } |
| 1043 |
| 1044 #undef CHECK_FOUND |
| 1045 #undef CHECK_NOT_FOUND |
| 1046 |
| 1047 { |
| 1048 Handle<JSArray> handler = factory->NewJSArray(0); |
| 1049 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); |
| 1050 Handle<JSProxy> object = factory->NewJSProxy(function, handler); |
| 1051 CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); |
| 1052 ft.CheckTrue(object, smi0, expect_bailout); |
| 1053 } |
| 1054 |
| 1055 { |
| 1056 Handle<JSObject> object = isolate->global_object(); |
| 1057 CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); |
| 1058 ft.CheckTrue(object, smi0, expect_bailout); |
| 1059 } |
| 1060 |
| 1061 { |
| 1062 Handle<JSObject> object = isolate->global_proxy(); |
| 1063 CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); |
| 1064 ft.CheckTrue(object, smi0, expect_bailout); |
| 1065 } |
| 1066 } |
| 1067 |
399 } // namespace internal | 1068 } // namespace internal |
400 } // namespace v8 | 1069 } // namespace v8 |
OLD | NEW |