Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Unified Diff: test/cctest/test-field-type-tracking.cc

Issue 2015513002: [runtime] Ensure that all elements kind transitions are chained to the root map. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebasing Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects-inl.h ('k') | test/mjsunit/regress/regress-v8-5009.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-field-type-tracking.cc
diff --git a/test/cctest/test-field-type-tracking.cc b/test/cctest/test-field-type-tracking.cc
index b3f8cc5ab47747eec71826c625b07f2ab5b770a9..9709f87597943c79c82f91f9c96eae082075b5ca 100644
--- a/test/cctest/test-field-type-tracking.cc
+++ b/test/cctest/test-field-type-tracking.cc
@@ -86,6 +86,7 @@ static bool EqualDetails(DescriptorArray* descriptors, int descriptor,
class Expectations {
static const int MAX_PROPERTIES = 10;
Isolate* isolate_;
+ ElementsKind elements_kind_;
PropertyType types_[MAX_PROPERTIES];
PropertyAttributes attributes_[MAX_PROPERTIES];
Representation representations_[MAX_PROPERTIES];
@@ -97,8 +98,15 @@ class Expectations {
int number_of_properties_;
public:
+ explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
+ : isolate_(isolate),
+ elements_kind_(elements_kind),
+ number_of_properties_(0) {}
+
explicit Expectations(Isolate* isolate)
- : isolate_(isolate), number_of_properties_(0) {}
+ : Expectations(
+ isolate,
+ isolate->object_function()->initial_map()->elements_kind()) {}
void Init(int index, PropertyType type, PropertyAttributes attributes,
Representation representation, Handle<Object> value) {
@@ -143,6 +151,10 @@ class Expectations {
os << "\n";
}
+ void SetElementsKind(ElementsKind elements_kind) {
+ elements_kind_ = elements_kind;
+ }
+
Handle<FieldType> GetFieldType(int index) {
CHECK(index < MAX_PROPERTIES);
CHECK(types_[index] == DATA || types_[index] == ACCESSOR);
@@ -252,6 +264,7 @@ class Expectations {
}
bool Check(Map* map, int expected_nof) const {
+ CHECK_EQ(elements_kind_, map->elements_kind());
CHECK(number_of_properties_ <= MAX_PROPERTIES);
CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
CHECK(!map->is_dictionary_map());
@@ -279,6 +292,13 @@ class Expectations {
// given |map|.
//
+ Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
+ elements_kind_ = elements_kind;
+ map = Map::AsElementsKind(map, elements_kind);
+ CHECK_EQ(elements_kind_, map->elements_kind());
+ return map;
+ }
+
Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
Representation representation,
Handle<FieldType> heap_type) {
@@ -1522,6 +1542,271 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
////////////////////////////////////////////////////////////////////////////////
+// A set of tests for elements kind reconfiguration case.
+//
+
+// This test ensures that representation/field type generalization is correctly
+// propagated from one branch of transition tree (|map2) to another (|map|).
+//
+// + - p0 - p1 - p2A - p3 - p4: |map|
+// |
+// ek
+// |
+// {} - p0 - p1 - p2B - p3 - p4: |map2|
+//
+// where "p2A" and "p2B" differ only in the representation/field type.
+//
+static void TestReconfigureElementsKind_GeneralizeRepresentation(
+ Representation from_representation, Handle<FieldType> from_type,
+ Representation to_representation, Handle<FieldType> to_type,
+ Representation expected_representation, Handle<FieldType> expected_type) {
+ Isolate* isolate = CcTest::i_isolate();
+
+ Expectations expectations(isolate, FAST_SMI_ELEMENTS);
+
+ // Create a map, add required properties to it and initialize expectations.
+ Handle<Map> initial_map = Map::Create(isolate, 0);
+ initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
+
+ Handle<Map> map = initial_map;
+ map = expectations.AsElementsKind(map, FAST_ELEMENTS);
+ for (int i = 0; i < kPropCount; i++) {
+ map = expectations.AddDataField(map, NONE, from_representation, from_type);
+ }
+ CHECK(!map->is_deprecated());
+ CHECK(map->is_stable());
+ CHECK(expectations.Check(*map));
+
+ // Create another branch in transition tree (property at index |kDiffProp|
+ // has different representatio/field type), initialize expectations.
+ const int kDiffProp = kPropCount / 2;
+ Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
+
+ Handle<Map> map2 = initial_map;
+ for (int i = 0; i < kPropCount; i++) {
+ if (i == kDiffProp) {
+ map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
+ } else {
+ map2 = expectations2.AddDataField(map2, NONE, from_representation,
+ from_type);
+ }
+ }
+ CHECK(!map2->is_deprecated());
+ CHECK(map2->is_stable());
+ CHECK(expectations2.Check(*map2));
+
+ Zone zone(isolate->allocator());
+ Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
+ CompilationInfo info(ArrayVector("testing"), isolate, &zone);
+ CHECK(!info.dependencies()->HasAborted());
+ info.dependencies()->AssumeFieldType(field_owner);
+
+ // Reconfigure elements kinds of |map2|, which should generalize
+ // representations in |map|.
+ Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
+
+ // |map2| should be left unchanged but marked unstable.
+ CHECK(!map2->is_stable());
+ CHECK(!map2->is_deprecated());
+ CHECK_NE(*map2, *new_map);
+ CHECK(expectations2.Check(*map2));
+
+ // |map| should be deprecated and |new_map| should match new expectations.
+ expectations.SetDataField(kDiffProp, expected_representation, expected_type);
+
+ CHECK(map->is_deprecated());
+ CHECK(!info.dependencies()->HasAborted());
+ info.dependencies()->Rollback(); // Properly cleanup compilation info.
+ CHECK_NE(*map, *new_map);
+
+ CHECK(!new_map->is_deprecated());
+ CHECK(expectations.Check(*new_map));
+
+ // Update deprecated |map|, it should become |new_map|.
+ Handle<Map> updated_map = Map::Update(map);
+ CHECK_EQ(*new_map, *updated_map);
+
+ // Ensure Map::FindElementsKindTransitionedMap() is able to find the
+ // transitioned map.
+ {
+ MapHandleList map_list;
+ map_list.Add(updated_map);
+ Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
+ CHECK_EQ(*updated_map, transitioned_map);
+ }
+}
+
+// This test ensures that trivial representation/field type generalization
+// (from HeapObject to HeapObject) is correctly propagated from one branch of
+// transition tree (|map2|) to another (|map|).
+//
+// + - p0 - p1 - p2A - p3 - p4: |map|
+// |
+// ek
+// |
+// {} - p0 - p1 - p2B - p3 - p4: |map2|
+//
+// where "p2A" and "p2B" differ only in the representation/field type.
+//
+static void TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+ Representation from_representation, Handle<FieldType> from_type,
+ Representation to_representation, Handle<FieldType> to_type,
+ Representation expected_representation, Handle<FieldType> expected_type,
+ bool expected_field_type_dependency = true) {
+ Isolate* isolate = CcTest::i_isolate();
+
+ Expectations expectations(isolate, FAST_SMI_ELEMENTS);
+
+ // Create a map, add required properties to it and initialize expectations.
+ Handle<Map> initial_map = Map::Create(isolate, 0);
+ initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
+
+ Handle<Map> map = initial_map;
+ map = expectations.AsElementsKind(map, FAST_ELEMENTS);
+ for (int i = 0; i < kPropCount; i++) {
+ map = expectations.AddDataField(map, NONE, from_representation, from_type);
+ }
+ CHECK(!map->is_deprecated());
+ CHECK(map->is_stable());
+ CHECK(expectations.Check(*map));
+
+ // Create another branch in transition tree (property at index |kDiffProp|
+ // has different attributes), initialize expectations.
+ const int kDiffProp = kPropCount / 2;
+ Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
+
+ Handle<Map> map2 = initial_map;
+ for (int i = 0; i < kPropCount; i++) {
+ if (i == kDiffProp) {
+ map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
+ } else {
+ map2 = expectations2.AddDataField(map2, NONE, from_representation,
+ from_type);
+ }
+ }
+ CHECK(!map2->is_deprecated());
+ CHECK(map2->is_stable());
+ CHECK(expectations2.Check(*map2));
+
+ Zone zone(isolate->allocator());
+ Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
+ CompilationInfo info(ArrayVector("testing"), isolate, &zone);
+ CHECK(!info.dependencies()->HasAborted());
+ info.dependencies()->AssumeFieldType(field_owner);
+
+ // Reconfigure elements kinds of |map2|, which should generalize
+ // representations in |map|.
+ Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
+
+ // |map2| should be left unchanged but marked unstable.
+ CHECK(!map2->is_stable());
+ CHECK(!map2->is_deprecated());
+ CHECK_NE(*map2, *new_map);
+ CHECK(expectations2.Check(*map2));
+
+ // In trivial case |map| should be returned as a result of the elements
+ // kind reconfiguration, respective field types should be generalized and
+ // respective code dependencies should be invalidated. |map| should be NOT
+ // deprecated and it should match new expectations.
+ expectations.SetDataField(kDiffProp, expected_representation, expected_type);
+ CHECK(!map->is_deprecated());
+ CHECK_EQ(*map, *new_map);
+ CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
+ info.dependencies()->Rollback(); // Properly cleanup compilation info.
+
+ CHECK(!new_map->is_deprecated());
+ CHECK(expectations.Check(*new_map));
+
+ Handle<Map> updated_map = Map::Update(map);
+ CHECK_EQ(*new_map, *updated_map);
+
+ // Ensure Map::FindElementsKindTransitionedMap() is able to find the
+ // transitioned map.
+ {
+ MapHandleList map_list;
+ map_list.Add(updated_map);
+ Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
+ CHECK_EQ(*updated_map, transitioned_map);
+ }
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToDouble) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
+
+ TestReconfigureElementsKind_GeneralizeRepresentation(
+ Representation::Smi(), any_type, Representation::Double(), any_type,
+ Representation::Double(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToTagged) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
+ Handle<FieldType> value_type =
+ FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ TestReconfigureElementsKind_GeneralizeRepresentation(
+ Representation::Smi(), any_type, Representation::HeapObject(), value_type,
+ Representation::Tagged(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationDoubleToTagged) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
+ Handle<FieldType> value_type =
+ FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ TestReconfigureElementsKind_GeneralizeRepresentation(
+ Representation::Double(), any_type, Representation::HeapObject(),
+ value_type, Representation::Tagged(), any_type);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjToHeapObj) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
+
+ Handle<FieldType> current_type =
+ FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ Handle<FieldType> new_type =
+ FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ Handle<FieldType> expected_type = any_type;
+
+ TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+ Representation::HeapObject(), current_type, Representation::HeapObject(),
+ new_type, Representation::HeapObject(), expected_type);
+ current_type = expected_type;
+
+ new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
+ Representation::HeapObject(), any_type, Representation::HeapObject(),
+ new_type, Representation::HeapObject(), any_type, false);
+}
+
+TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjectToTagged) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
+ Handle<FieldType> value_type =
+ FieldType::Class(Map::Create(isolate, 0), isolate);
+
+ TestReconfigureElementsKind_GeneralizeRepresentation(
+ Representation::HeapObject(), value_type, Representation::Smi(), any_type,
+ Representation::Tagged(), any_type);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// A set of tests checking split map deprecation.
//
@@ -1637,15 +1922,16 @@ static void TestGeneralizeRepresentationWithSpecialTransition(
CHECK(map->is_stable());
CHECK(expectations.Check(*map));
+ Expectations expectations2 = expectations;
+
// Apply some special transition to |map|.
CHECK(map->owns_descriptors());
- Handle<Map> map2 = config.Transition(map);
+ Handle<Map> map2 = config.Transition(map, expectations2);
// |map| should still match expectations.
CHECK(!map->is_deprecated());
CHECK(expectations.Check(*map));
- Expectations expectations2 = expectations;
if (config.generalizes_representations()) {
for (int i = 0; i < kPropCount; i++) {
expectations2.GeneralizeRepresentation(i);
@@ -1717,13 +2003,15 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) {
FieldType::Class(Map::Create(isolate, 0), isolate);
struct TestConfig {
- Handle<Map> Transition(Handle<Map> map) {
- return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS,
- INSERT_TRANSITION);
+ Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
+ Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
+ expectations.SetElementsKind(DICTIONARY_ELEMENTS);
+ return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
+ "CopyForPreventExtensions");
}
// TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
bool generalizes_representations() const { return false; }
- bool is_non_equevalent_transition() const { return false; }
+ bool is_non_equevalent_transition() const { return true; }
};
TestConfig config;
TestGeneralizeRepresentationWithSpecialTransition(
@@ -1741,7 +2029,7 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
FieldType::Class(Map::Create(isolate, 0), isolate);
struct TestConfig {
- Handle<Map> Transition(Handle<Map> map) {
+ Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
Isolate* isolate = CcTest::i_isolate();
Handle<FieldType> any_type = FieldType::Any(isolate);
@@ -1753,12 +2041,14 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
.ToHandleChecked();
CHECK(!map->owns_descriptors());
- return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS,
- INSERT_TRANSITION);
+ Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
+ expectations.SetElementsKind(DICTIONARY_ELEMENTS);
+ return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
+ "CopyForPreventExtensions");
}
// TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
bool generalizes_representations() const { return false; }
- bool is_non_equevalent_transition() const { return false; }
+ bool is_non_equevalent_transition() const { return true; }
};
TestConfig config;
TestGeneralizeRepresentationWithSpecialTransition(
@@ -1785,7 +2075,7 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) {
prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
}
- Handle<Map> Transition(Handle<Map> map) {
+ Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE);
}
// TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
@@ -1819,7 +2109,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
}
- Handle<Map> Transition(Handle<Map> map) {
+ Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
Isolate* isolate = CcTest::i_isolate();
Handle<FieldType> any_type = FieldType::Any(isolate);
« no previous file with comments | « src/objects-inl.h ('k') | test/mjsunit/regress/regress-v8-5009.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698