2014-12-10 15:18:44 +00:00
|
|
|
// 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.
|
|
|
|
|
2022-07-18 10:54:58 +00:00
|
|
|
#include "test/cctest/test-transitions.h"
|
|
|
|
|
2014-12-10 15:18:44 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2022-07-18 10:54:58 +00:00
|
|
|
#include <utility>
|
2014-12-10 15:18:44 +00:00
|
|
|
|
|
|
|
#include "src/codegen/compilation-cache.h"
|
|
|
|
#include "src/execution/execution.h"
|
2018-04-09 19:11:22 +00:00
|
|
|
#include "src/heap/factory.h"
|
2016-02-16 13:28:12 +00:00
|
|
|
#include "src/objects/field-type.h"
|
2019-02-07 20:27:25 +00:00
|
|
|
#include "src/objects/objects-inl.h"
|
|
|
|
#include "src/objects/transitions-inl.h"
|
2014-12-10 15:18:44 +00:00
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
|
2017-08-11 11:22:28 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2014-12-10 15:18:44 +00:00
|
|
|
|
|
|
|
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 =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name1, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2016-01-26 15:03:40 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
Handle<Map> map2 =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name2, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2016-01-26 15:03:40 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
|
2015-03-06 14:08:33 +00:00
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
|
2017-07-28 07:01:59 +00:00
|
|
|
{
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name1, map1,
|
|
|
|
SIMPLE_PROPERTY_TRANSITION);
|
2017-07-28 07:01:59 +00:00
|
|
|
}
|
|
|
|
{
|
2022-02-14 09:17:28 +00:00
|
|
|
{
|
|
|
|
TestTransitionsAccessor transitions(isolate, map0);
|
|
|
|
CHECK(transitions.IsWeakRefEncoding());
|
|
|
|
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
|
|
|
attributes));
|
|
|
|
CHECK_EQ(1, transitions.NumberOfTransitions());
|
|
|
|
CHECK_EQ(*name1, transitions.GetKey(0));
|
|
|
|
CHECK_EQ(*map1, transitions.GetTarget(0));
|
|
|
|
}
|
2017-07-28 07:01:59 +00:00
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name2, map2,
|
|
|
|
SIMPLE_PROPERTY_TRANSITION);
|
2015-03-06 14:08:33 +00:00
|
|
|
}
|
2017-07-28 07:01:59 +00:00
|
|
|
{
|
2018-06-05 10:21:35 +00:00
|
|
|
TestTransitionsAccessor transitions(isolate, map0);
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK(transitions.IsFullTransitionArrayEncoding());
|
|
|
|
|
2021-11-11 22:26:35 +00:00
|
|
|
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
|
|
|
attributes));
|
|
|
|
CHECK_EQ(*map2, transitions.SearchTransition(*name2, PropertyKind::kData,
|
|
|
|
attributes));
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK_EQ(2, transitions.NumberOfTransitions());
|
|
|
|
for (int i = 0; i < 2; i++) {
|
2018-11-27 00:48:42 +00:00
|
|
|
Name key = transitions.GetKey(i);
|
2018-11-13 06:16:42 +00:00
|
|
|
Map target = transitions.GetTarget(i);
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK((key == *name1 && target == *map1) ||
|
|
|
|
(key == *name2 && target == *map2));
|
|
|
|
}
|
2015-03-06 14:08:33 +00:00
|
|
|
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions.IsSortedNoDuplicates());
|
2017-07-28 07:01:59 +00:00
|
|
|
}
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name1, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2016-01-26 15:03:40 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
Handle<Map> map2 =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name2, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2016-01-26 15:03:40 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
|
2015-03-06 14:08:33 +00:00
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
|
|
|
|
2017-07-28 07:01:59 +00:00
|
|
|
{
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name1, map1,
|
|
|
|
PROPERTY_TRANSITION);
|
2015-03-06 14:08:33 +00:00
|
|
|
}
|
2017-07-28 07:01:59 +00:00
|
|
|
{
|
2022-02-14 09:17:28 +00:00
|
|
|
{
|
|
|
|
TestTransitionsAccessor transitions(isolate, map0);
|
|
|
|
CHECK(transitions.IsFullTransitionArrayEncoding());
|
|
|
|
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
|
|
|
attributes));
|
|
|
|
CHECK_EQ(1, transitions.NumberOfTransitions());
|
|
|
|
CHECK_EQ(*name1, transitions.GetKey(0));
|
|
|
|
CHECK_EQ(*map1, transitions.GetTarget(0));
|
|
|
|
}
|
2017-07-28 07:01:59 +00:00
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name2, map2,
|
|
|
|
PROPERTY_TRANSITION);
|
2017-07-28 07:01:59 +00:00
|
|
|
}
|
|
|
|
{
|
2018-06-05 10:21:35 +00:00
|
|
|
TestTransitionsAccessor transitions(isolate, map0);
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK(transitions.IsFullTransitionArrayEncoding());
|
|
|
|
|
2021-11-11 22:26:35 +00:00
|
|
|
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
|
|
|
attributes));
|
|
|
|
CHECK_EQ(*map2, transitions.SearchTransition(*name2, PropertyKind::kData,
|
|
|
|
attributes));
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK_EQ(2, transitions.NumberOfTransitions());
|
|
|
|
for (int i = 0; i < 2; i++) {
|
2018-11-27 00:48:42 +00:00
|
|
|
Name key = transitions.GetKey(i);
|
2018-11-13 06:16:42 +00:00
|
|
|
Map target = transitions.GetTarget(i);
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK((key == *name1 && target == *map1) ||
|
|
|
|
(key == *name2 && target == *map2));
|
|
|
|
}
|
2015-03-05 20:41:47 +00:00
|
|
|
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions.IsSortedNoDuplicates());
|
2017-07-28 07:01:59 +00:00
|
|
|
}
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2015-03-06 14:08:33 +00:00
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
2014-12-10 15:18:44 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
2021-06-17 15:43:55 +00:00
|
|
|
base::EmbeddedVector<char, 64> buffer;
|
2014-12-10 15:18:44 +00:00
|
|
|
SNPrintF(buffer, "prop%d", i);
|
2019-04-29 11:06:49 +00:00
|
|
|
Handle<String> name = factory->InternalizeUtf8String(buffer.begin());
|
2017-02-10 08:05:25 +00:00
|
|
|
Handle<Map> map =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
2018-05-28 15:44:58 +00:00
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2017-02-10 08:05:25 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
names[i] = name;
|
|
|
|
maps[i] = map;
|
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor transitions(isolate, *map0);
|
2014-12-10 15:18:44 +00:00
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
2021-11-11 22:26:35 +00:00
|
|
|
CHECK_EQ(*maps[i], transitions.SearchTransition(
|
|
|
|
*names[i], PropertyKind::kData, attributes));
|
2015-03-06 14:08:33 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
2018-11-27 00:48:42 +00:00
|
|
|
Name key = transitions.GetKey(i);
|
2018-11-13 06:16:42 +00:00
|
|
|
Map target = transitions.GetTarget(i);
|
2015-03-06 14:08:33 +00:00
|
|
|
for (int j = 0; j < PROPS_COUNT; j++) {
|
|
|
|
if (*names[i] == key) {
|
|
|
|
CHECK_EQ(*maps[i], target);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions.IsSortedNoDuplicates());
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2015-03-06 14:08:33 +00:00
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
2014-12-10 15:18:44 +00:00
|
|
|
|
|
|
|
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
2022-05-13 09:19:09 +00:00
|
|
|
static_assert(ATTRS_COUNT == 8);
|
2014-12-10 15:18:44 +00:00
|
|
|
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++) {
|
2022-03-09 10:11:40 +00:00
|
|
|
auto attributes = PropertyAttributesFromInt(i);
|
2014-12-10 15:18:44 +00:00
|
|
|
|
2017-02-10 08:05:25 +00:00
|
|
|
Handle<Map> map =
|
2018-06-19 09:00:37 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
2018-05-28 15:44:58 +00:00
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2017-02-10 08:05:25 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
attr_maps[i] = map;
|
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that transitions for |name| field are valid.
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor transitions(isolate, *map0);
|
2014-12-10 15:18:44 +00:00
|
|
|
for (int i = 0; i < ATTRS_COUNT; i++) {
|
2022-03-09 10:11:40 +00:00
|
|
|
auto attributes = PropertyAttributesFromInt(i);
|
2021-11-11 22:26:35 +00:00
|
|
|
CHECK_EQ(*attr_maps[i], transitions.SearchTransition(
|
|
|
|
*name, PropertyKind::kData, attributes));
|
2015-03-06 14:08:33 +00:00
|
|
|
// All transitions use the same key, so this check doesn't need to
|
|
|
|
// care about ordering.
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK_EQ(*name, transitions.GetKey(i));
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions.IsSortedNoDuplicates());
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2015-03-06 14:08:33 +00:00
|
|
|
CHECK(map0->raw_transitions()->IsSmi());
|
2014-12-10 15:18:44 +00:00
|
|
|
|
|
|
|
// Some number of fields.
|
|
|
|
for (int i = 0; i < PROPS_COUNT; i++) {
|
2021-06-17 15:43:55 +00:00
|
|
|
base::EmbeddedVector<char, 64> buffer;
|
2014-12-10 15:18:44 +00:00
|
|
|
SNPrintF(buffer, "prop%d", i);
|
2019-04-29 11:06:49 +00:00
|
|
|
Handle<String> name = factory->InternalizeUtf8String(buffer.begin());
|
2014-12-10 15:18:44 +00:00
|
|
|
Handle<Map> map =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate), NONE,
|
2018-05-28 15:44:58 +00:00
|
|
|
PropertyConstness::kMutable,
|
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2016-01-26 15:03:40 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
names[i] = name;
|
|
|
|
maps[i] = map;
|
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
2022-05-13 09:19:09 +00:00
|
|
|
static_assert(ATTRS_COUNT == 8);
|
2014-12-10 15:18:44 +00:00
|
|
|
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++) {
|
2022-03-09 10:11:40 +00:00
|
|
|
auto attributes = PropertyAttributesFromInt(i);
|
2014-12-10 15:18:44 +00:00
|
|
|
|
2017-02-10 08:05:25 +00:00
|
|
|
Handle<Map> map =
|
2018-11-06 01:39:48 +00:00
|
|
|
Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate),
|
|
|
|
attributes, PropertyConstness::kMutable,
|
2018-05-28 15:44:58 +00:00
|
|
|
Representation::Tagged(), OMIT_TRANSITION)
|
2017-02-10 08:05:25 +00:00
|
|
|
.ToHandleChecked();
|
2014-12-10 15:18:44 +00:00
|
|
|
attr_maps[i] = map;
|
|
|
|
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that transitions for |name| field are valid.
|
2022-02-14 09:17:28 +00:00
|
|
|
TransitionsAccessor transitions(isolate, *map0);
|
2014-12-10 15:18:44 +00:00
|
|
|
for (int i = 0; i < ATTRS_COUNT; i++) {
|
2022-03-09 10:11:40 +00:00
|
|
|
auto attr = PropertyAttributesFromInt(i);
|
2021-11-11 22:26:35 +00:00
|
|
|
CHECK_EQ(*attr_maps[i],
|
|
|
|
transitions.SearchTransition(*name, PropertyKind::kData, attr));
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that info about the other fields still valid.
|
2017-07-28 07:01:59 +00:00
|
|
|
CHECK_EQ(PROPS_COUNT + ATTRS_COUNT, transitions.NumberOfTransitions());
|
2015-03-06 14:08:33 +00:00
|
|
|
for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) {
|
2018-11-27 00:48:42 +00:00
|
|
|
Name key = transitions.GetKey(i);
|
2018-11-13 06:16:42 +00:00
|
|
|
Map target = transitions.GetTarget(i);
|
2015-03-06 14:08:33 +00:00
|
|
|
if (key == *name) {
|
|
|
|
// Attributes transition.
|
|
|
|
PropertyAttributes attributes =
|
2019-07-02 12:25:13 +00:00
|
|
|
target.GetLastDescriptorDetails(isolate).attributes();
|
2015-03-06 14:08:33 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions.IsSortedNoDuplicates());
|
2014-12-10 15:18:44 +00:00
|
|
|
}
|
2017-08-11 11:22:28 +00:00
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|