8e7241fdde
Rebuilding (after touching certain files) is crazy slow because includes are out of control. Many of these files we need to rebuild are cctests which pull in more includes than they need. BUG=v8:5294 Review-Url: https://codereview.chromium.org/2304553002 Cr-Commit-Position: refs/heads/master@{#39080}
319 lines
11 KiB
C++
319 lines
11 KiB
C++
// 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 <stdlib.h>
|
|
#include <utility>
|
|
|
|
#include "src/v8.h"
|
|
|
|
#include "src/compilation-cache.h"
|
|
#include "src/execution.h"
|
|
#include "src/factory.h"
|
|
#include "src/field-type.h"
|
|
#include "src/global-handles.h"
|
|
// FIXME(mstarzinger, marja): This is weird, but required because of the missing
|
|
// (disallowed) include: src/field-type.h -> src/objects-inl.h
|
|
#include "src/objects-inl.h"
|
|
#include "src/transitions.h"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
using namespace v8::internal;
|
|
|
|
|
|
//
|
|
// Helper functions.
|
|
//
|
|
|
|
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<String> name1 = factory->InternalizeUtf8String("foo");
|
|
Handle<String> name2 = factory->InternalizeUtf8String("bar");
|
|
PropertyAttributes attributes = NONE;
|
|
|
|
Handle<Map> map0 = Map::Create(isolate, 0);
|
|
Handle<Map> map1 =
|
|
Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
Handle<Map> map2 =
|
|
Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
TransitionArray::Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
|
|
CHECK(TransitionArray::IsSimpleTransition(map0->raw_transitions()));
|
|
CHECK_EQ(*map1,
|
|
TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
|
|
CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
|
|
CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
|
|
CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
|
|
|
|
TransitionArray::Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
|
|
CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
|
|
|
|
CHECK_EQ(*map1,
|
|
TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
|
|
CHECK_EQ(*map2,
|
|
TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
|
|
CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
|
|
for (int i = 0; i < 2; i++) {
|
|
Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
|
|
Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
|
|
CHECK((key == *name1 && target == *map1) ||
|
|
(key == *name2 && target == *map2));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CHECK(TransitionArray::IsSortedNoDuplicates(*map0));
|
|
#endif
|
|
}
|
|
|
|
|
|
TEST(TransitionArray_FullFieldTransitions) {
|
|
CcTest::InitializeVM();
|
|
v8::HandleScope scope(CcTest::isolate());
|
|
Isolate* isolate = CcTest::i_isolate();
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<String> name1 = factory->InternalizeUtf8String("foo");
|
|
Handle<String> name2 = factory->InternalizeUtf8String("bar");
|
|
PropertyAttributes attributes = NONE;
|
|
|
|
Handle<Map> map0 = Map::Create(isolate, 0);
|
|
Handle<Map> map1 =
|
|
Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
Handle<Map> map2 =
|
|
Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
TransitionArray::Insert(map0, name1, map1, PROPERTY_TRANSITION);
|
|
CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
|
|
CHECK_EQ(*map1,
|
|
TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
|
|
CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
|
|
CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
|
|
CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
|
|
|
|
TransitionArray::Insert(map0, name2, map2, PROPERTY_TRANSITION);
|
|
CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
|
|
|
|
CHECK_EQ(*map1,
|
|
TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
|
|
CHECK_EQ(*map2,
|
|
TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
|
|
CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
|
|
for (int i = 0; i < 2; i++) {
|
|
Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
|
|
Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
|
|
CHECK((key == *name1 && target == *map1) ||
|
|
(key == *name2 && target == *map2));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CHECK(TransitionArray::IsSortedNoDuplicates(*map0));
|
|
#endif
|
|
}
|
|
|
|
|
|
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<String> names[PROPS_COUNT];
|
|
Handle<Map> maps[PROPS_COUNT];
|
|
PropertyAttributes attributes = NONE;
|
|
|
|
Handle<Map> map0 = Map::Create(isolate, 0);
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
|
EmbeddedVector<char, 64> buffer;
|
|
SNPrintF(buffer, "prop%d", i);
|
|
Handle<String> name = factory->InternalizeUtf8String(buffer.start());
|
|
Handle<Map> map = Map::CopyWithField(
|
|
map0, name, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
names[i] = name;
|
|
maps[i] = map;
|
|
|
|
TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
|
|
}
|
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
|
CHECK_EQ(*maps[i], TransitionArray::SearchTransition(
|
|
*map0, kData, *names[i], attributes));
|
|
}
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
|
Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
|
|
Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
|
|
for (int j = 0; j < PROPS_COUNT; j++) {
|
|
if (*names[i] == key) {
|
|
CHECK_EQ(*maps[i], target);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CHECK(TransitionArray::IsSortedNoDuplicates(*map0));
|
|
#endif
|
|
}
|
|
|
|
|
|
TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
|
|
CcTest::InitializeVM();
|
|
v8::HandleScope scope(CcTest::isolate());
|
|
Isolate* isolate = CcTest::i_isolate();
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<Map> map0 = Map::Create(isolate, 0);
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
|
STATIC_ASSERT(ATTRS_COUNT == 8);
|
|
Handle<Map> attr_maps[ATTRS_COUNT];
|
|
Handle<String> 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<PropertyAttributes>(i);
|
|
|
|
Handle<Map> map = Map::CopyWithField(
|
|
map0, name, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
attr_maps[i] = map;
|
|
|
|
TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
|
|
}
|
|
|
|
// Ensure that transitions for |name| field are valid.
|
|
for (int i = 0; i < ATTRS_COUNT; i++) {
|
|
PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
|
|
CHECK_EQ(*attr_maps[i], TransitionArray::SearchTransition(
|
|
*map0, kData, *name, attributes));
|
|
// All transitions use the same key, so this check doesn't need to
|
|
// care about ordering.
|
|
CHECK_EQ(*name, TransitionArray::GetKey(map0->raw_transitions(), i));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CHECK(TransitionArray::IsSortedNoDuplicates(*map0));
|
|
#endif
|
|
}
|
|
|
|
|
|
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<String> names[PROPS_COUNT];
|
|
Handle<Map> maps[PROPS_COUNT];
|
|
|
|
Handle<Map> map0 = Map::Create(isolate, 0);
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
// Some number of fields.
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
|
EmbeddedVector<char, 64> buffer;
|
|
SNPrintF(buffer, "prop%d", i);
|
|
Handle<String> name = factory->InternalizeUtf8String(buffer.start());
|
|
Handle<Map> map =
|
|
Map::CopyWithField(map0, name, handle(FieldType::Any(), isolate), NONE,
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
names[i] = name;
|
|
maps[i] = map;
|
|
|
|
TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
|
|
}
|
|
|
|
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
|
STATIC_ASSERT(ATTRS_COUNT == 8);
|
|
Handle<Map> attr_maps[ATTRS_COUNT];
|
|
Handle<String> 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<PropertyAttributes>(i);
|
|
|
|
Handle<Map> map = Map::CopyWithField(
|
|
map0, name, handle(FieldType::Any(), isolate),
|
|
attributes, Representation::Tagged(), OMIT_TRANSITION)
|
|
.ToHandleChecked();
|
|
attr_maps[i] = map;
|
|
|
|
TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
|
|
}
|
|
|
|
// Ensure that transitions for |name| field are valid.
|
|
for (int i = 0; i < ATTRS_COUNT; i++) {
|
|
PropertyAttributes attr = static_cast<PropertyAttributes>(i);
|
|
CHECK_EQ(*attr_maps[i],
|
|
TransitionArray::SearchTransition(*map0, kData, *name, attr));
|
|
}
|
|
|
|
// Ensure that info about the other fields still valid.
|
|
CHECK_EQ(PROPS_COUNT + ATTRS_COUNT,
|
|
TransitionArray::NumberOfTransitions(map0->raw_transitions()));
|
|
for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) {
|
|
Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
|
|
Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
|
|
if (key == *name) {
|
|
// Attributes transition.
|
|
PropertyAttributes attributes =
|
|
target->GetLastDescriptorDetails().attributes();
|
|
CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target);
|
|
} else {
|
|
for (int j = 0; j < PROPS_COUNT; j++) {
|
|
if (*names[j] == key) {
|
|
CHECK_EQ(*maps[j], target);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
CHECK(TransitionArray::IsSortedNoDuplicates(*map0));
|
|
#endif
|
|
}
|