// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "src/v8.h" #include "src/compilation-cache.h" #include "src/execution.h" #include "src/factory.h" #include "src/global-handles.h" #include "test/cctest/cctest.h" using namespace v8::internal; // // Helper functions. // static void ConnectTransition(Handle parent, Handle transitions, Handle child) { if (!parent->HasTransitionArray() || *transitions != parent->transitions()) { parent->set_transitions(*transitions); } child->SetBackPointer(*parent); } static void CheckPropertyDetailsFieldsConsistency(PropertyType type, PropertyKind kind, PropertyLocation location) { int type_value = PropertyDetails::TypeField::encode(type); int kind_location_value = PropertyDetails::KindField::encode(kind) | PropertyDetails::LocationField::encode(location); CHECK_EQ(type_value, kind_location_value); } TEST(PropertyDetailsFieldsConsistency) { CheckPropertyDetailsFieldsConsistency(DATA, kData, kField); CheckPropertyDetailsFieldsConsistency(DATA_CONSTANT, kData, kDescriptor); CheckPropertyDetailsFieldsConsistency(ACCESSOR, kAccessor, kField); CheckPropertyDetailsFieldsConsistency(ACCESSOR_CONSTANT, kAccessor, kDescriptor); } TEST(TransitionArray_SimpleFieldTransitions) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); Handle name1 = factory->InternalizeUtf8String("foo"); Handle name2 = factory->InternalizeUtf8String("bar"); PropertyAttributes attributes = NONE; Handle map0 = Map::Create(isolate, 0); Handle map1 = Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); Handle map2 = Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); CHECK(!map0->HasTransitionArray()); Handle transitions = TransitionArray::Allocate(isolate, 0); CHECK(transitions->IsFullTransitionArray()); int transition; transitions = transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map1); CHECK(transitions->IsSimpleTransition()); transition = transitions->Search(kData, *name1, attributes); CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition); CHECK_EQ(*name1, transitions->GetKey(transition)); CHECK_EQ(*map1, transitions->GetTarget(transition)); transitions = transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map2); CHECK(transitions->IsFullTransitionArray()); transition = transitions->Search(kData, *name1, attributes); CHECK_EQ(*name1, transitions->GetKey(transition)); CHECK_EQ(*map1, transitions->GetTarget(transition)); transition = transitions->Search(kData, *name2, attributes); CHECK_EQ(*name2, transitions->GetKey(transition)); CHECK_EQ(*map2, transitions->GetTarget(transition)); DCHECK(transitions->IsSortedNoDuplicates()); } TEST(TransitionArray_FullFieldTransitions) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); Handle name1 = factory->InternalizeUtf8String("foo"); Handle name2 = factory->InternalizeUtf8String("bar"); PropertyAttributes attributes = NONE; Handle map0 = Map::Create(isolate, 0); Handle map1 = Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); Handle map2 = Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); CHECK(!map0->HasTransitionArray()); Handle transitions = TransitionArray::Allocate(isolate, 0); CHECK(transitions->IsFullTransitionArray()); int transition; transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map1); CHECK(transitions->IsFullTransitionArray()); transition = transitions->Search(kData, *name1, attributes); CHECK_EQ(*name1, transitions->GetKey(transition)); CHECK_EQ(*map1, transitions->GetTarget(transition)); transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map2); CHECK(transitions->IsFullTransitionArray()); transition = transitions->Search(kData, *name1, attributes); CHECK_EQ(*name1, transitions->GetKey(transition)); CHECK_EQ(*map1, transitions->GetTarget(transition)); transition = transitions->Search(kData, *name2, attributes); CHECK_EQ(*name2, transitions->GetKey(transition)); CHECK_EQ(*map2, transitions->GetTarget(transition)); DCHECK(transitions->IsSortedNoDuplicates()); } TEST(TransitionArray_DifferentFieldNames) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); const int PROPS_COUNT = 10; Handle names[PROPS_COUNT]; Handle maps[PROPS_COUNT]; PropertyAttributes attributes = NONE; Handle map0 = Map::Create(isolate, 0); CHECK(!map0->HasTransitionArray()); Handle transitions = TransitionArray::Allocate(isolate, 0); CHECK(transitions->IsFullTransitionArray()); for (int i = 0; i < PROPS_COUNT; i++) { EmbeddedVector buffer; SNPrintF(buffer, "prop%d", i); Handle name = factory->InternalizeUtf8String(buffer.start()); Handle map = Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); names[i] = name; maps[i] = map; transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map); } for (int i = 0; i < PROPS_COUNT; i++) { int transition = transitions->Search(kData, *names[i], attributes); CHECK_EQ(*names[i], transitions->GetKey(transition)); CHECK_EQ(*maps[i], transitions->GetTarget(transition)); } DCHECK(transitions->IsSortedNoDuplicates()); } TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); Handle map0 = Map::Create(isolate, 0); CHECK(!map0->HasTransitionArray()); Handle transitions = TransitionArray::Allocate(isolate, 0); CHECK(transitions->IsFullTransitionArray()); const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; STATIC_ASSERT(ATTRS_COUNT == 8); Handle attr_maps[ATTRS_COUNT]; Handle name = factory->InternalizeUtf8String("foo"); // Add transitions for same field name but different attributes. for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast(i); Handle map = Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); attr_maps[i] = map; transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map); } // Ensure that transitions for |name| field are valid. for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast(i); int transition = transitions->Search(kData, *name, attributes); CHECK_EQ(*name, transitions->GetKey(transition)); CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition)); } DCHECK(transitions->IsSortedNoDuplicates()); } TEST(TransitionArray_SameFieldNamesDifferentAttributes) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); const int PROPS_COUNT = 10; Handle names[PROPS_COUNT]; Handle maps[PROPS_COUNT]; Handle map0 = Map::Create(isolate, 0); CHECK(!map0->HasTransitionArray()); Handle transitions = TransitionArray::Allocate(isolate, 0); CHECK(transitions->IsFullTransitionArray()); // Some number of fields. for (int i = 0; i < PROPS_COUNT; i++) { EmbeddedVector buffer; SNPrintF(buffer, "prop%d", i); Handle name = factory->InternalizeUtf8String(buffer.start()); Handle map = Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), NONE, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); names[i] = name; maps[i] = map; transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map); } const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; STATIC_ASSERT(ATTRS_COUNT == 8); Handle attr_maps[ATTRS_COUNT]; Handle name = factory->InternalizeUtf8String("foo"); // Add transitions for same field name but different attributes. for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast(i); Handle map = Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); attr_maps[i] = map; transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); ConnectTransition(map0, transitions, map); } // Ensure that transitions for |name| field are valid. for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast(i); int transition = transitions->Search(kData, *name, attributes); CHECK_EQ(*name, transitions->GetKey(transition)); CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition)); } // Ensure that info about the other fields still valid. for (int i = 0; i < PROPS_COUNT; i++) { int transition = transitions->Search(kData, *names[i], NONE); CHECK_EQ(*names[i], transitions->GetKey(transition)); CHECK_EQ(*maps[i], transitions->GetTarget(transition)); } DCHECK(transitions->IsSortedNoDuplicates()); }