Commit 47421760 authored by ishell's avatar ishell Committed by Commit bot

Map::ReconfigureProperty() should mark map as unstable when it returns a different map.

BUG=chromium:502930
LOG=N

Review URL: https://codereview.chromium.org/1200003002

Cr-Commit-Position: refs/heads/master@{#29226}
parent 64d6ab45
...@@ -416,6 +416,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT ...@@ -416,6 +416,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
<< pre_allocated_property_fields() << "\n"; << pre_allocated_property_fields() << "\n";
os << " - unused property fields: " << unused_property_fields() << "\n"; os << " - unused property fields: " << unused_property_fields() << "\n";
if (is_deprecated()) os << " - deprecated_map\n"; if (is_deprecated()) os << " - deprecated_map\n";
if (is_stable()) os << " - stable_map\n";
if (is_dictionary_map()) os << " - dictionary_map\n"; if (is_dictionary_map()) os << " - dictionary_map\n";
if (is_prototype_map()) { if (is_prototype_map()) {
os << " - prototype_map\n"; os << " - prototype_map\n";
......
...@@ -2565,6 +2565,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, ...@@ -2565,6 +2565,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
target_descriptors->GetFieldType(modify_index))); target_descriptors->GetFieldType(modify_index)));
} }
#endif #endif
if (*target_map != *old_map) {
old_map->NotifyLeafMapLayoutChange();
}
return target_map; return target_map;
} }
...@@ -2818,13 +2821,6 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, ...@@ -2818,13 +2821,6 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
split_kind, old_descriptors->GetKey(split_nof), split_attributes, split_kind, old_descriptors->GetKey(split_nof), split_attributes,
*new_descriptors, *new_layout_descriptor); *new_descriptors, *new_layout_descriptor);
if (from_kind != to_kind) {
// There was an elements kind change in the middle of transition tree and
// we reconstructed the tree so that all elements kind transitions are
// done at the beginning, therefore the |old_map| is no longer stable.
old_map->NotifyLeafMapLayoutChange();
}
// If |transition_target_deprecated| is true then the transition array // If |transition_target_deprecated| is true then the transition array
// already contains entry for given descriptor. This means that the transition // already contains entry for given descriptor. This means that the transition
// could be inserted regardless of whether transitions array is full or not. // could be inserted regardless of whether transitions array is full or not.
...@@ -2835,6 +2831,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, ...@@ -2835,6 +2831,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
"GenAll_CantHaveMoreTransitions"); "GenAll_CantHaveMoreTransitions");
} }
old_map->NotifyLeafMapLayoutChange();
if (FLAG_trace_generalization && modify_index >= 0) { if (FLAG_trace_generalization && modify_index >= 0) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index); PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PropertyDetails new_details = new_descriptors->GetDetails(modify_index); PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
......
...@@ -437,9 +437,9 @@ TEST(ReconfigureAccessorToNonExistingDataField) { ...@@ -437,9 +437,9 @@ TEST(ReconfigureAccessorToNonExistingDataField) {
Handle<Map> new_map = Map::ReconfigureProperty( Handle<Map> new_map = Map::ReconfigureProperty(
map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD); map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD);
// |map| did not change. // |map| did not change except marked unstable.
CHECK(!map->is_deprecated()); CHECK(!map->is_deprecated());
CHECK(map->is_stable()); CHECK(!map->is_stable());
CHECK(expectations.Check(*map)); CHECK(expectations.Check(*map));
expectations.SetDataField(0, NONE, Representation::None(), none_type); expectations.SetDataField(0, NONE, Representation::None(), none_type);
...@@ -600,12 +600,14 @@ static void TestGeneralizeRepresentation( ...@@ -600,12 +600,14 @@ static void TestGeneralizeRepresentation(
CHECK(expectations.Check(*new_map)); CHECK(expectations.Check(*new_map));
if (is_detached_map) { if (is_detached_map) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated()); CHECK(map->is_deprecated());
CHECK_NE(*map, *new_map); CHECK_NE(*map, *new_map);
CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(), CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
info.dependencies()->HasAborted()); info.dependencies()->HasAborted());
} else if (expected_deprecation) { } else if (expected_deprecation) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated()); CHECK(map->is_deprecated());
CHECK(field_owner->is_deprecated()); CHECK(field_owner->is_deprecated());
CHECK_NE(*map, *new_map); CHECK_NE(*map, *new_map);
...@@ -613,6 +615,7 @@ static void TestGeneralizeRepresentation( ...@@ -613,6 +615,7 @@ static void TestGeneralizeRepresentation(
} else { } else {
CHECK(!field_owner->is_deprecated()); CHECK(!field_owner->is_deprecated());
CHECK(map->is_stable()); // Map did not change, must be left stable.
CHECK_EQ(*map, *new_map); CHECK_EQ(*map, *new_map);
CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted()); CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
...@@ -653,6 +656,12 @@ static void TestGeneralizeRepresentation( ...@@ -653,6 +656,12 @@ static void TestGeneralizeRepresentation(
to_type, expected_representation, expected_type, expected_deprecation, to_type, expected_representation, expected_type, expected_deprecation,
expected_field_type_dependency); expected_field_type_dependency);
} }
// Check that reconfiguration to the very same field works correctly.
Representation representation = from_representation;
Handle<HeapType> type = from_type;
TestGeneralizeRepresentation(-1, 2, representation, type, representation,
type, representation, type, false, false);
} }
} }
...@@ -876,6 +885,7 @@ TEST(GeneralizeRepresentationWithAccessorProperties) { ...@@ -876,6 +885,7 @@ TEST(GeneralizeRepresentationWithAccessorProperties) {
expectations.SetDataField(i, Representation::Double(), any_type); expectations.SetDataField(i, Representation::Double(), any_type);
CHECK(!map->is_stable());
CHECK(map->is_deprecated()); CHECK(map->is_deprecated());
CHECK_NE(*map, *new_map); CHECK_NE(*map, *new_map);
CHECK(i == 0 || maps[i - 1]->is_deprecated()); CHECK(i == 0 || maps[i - 1]->is_deprecated());
...@@ -961,7 +971,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation( ...@@ -961,7 +971,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
Handle<Map> new_map = Handle<Map> new_map =
Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
// |map2| should be left unchanged. // |map2| should be left unchanged but marked unstable.
CHECK(!map2->is_stable());
CHECK(!map2->is_deprecated()); CHECK(!map2->is_deprecated());
CHECK_NE(*map2, *new_map); CHECK_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2)); CHECK(expectations2.Check(*map2));
...@@ -1046,7 +1057,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( ...@@ -1046,7 +1057,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
Handle<Map> new_map = Handle<Map> new_map =
Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
// |map2| should be left unchanged. // |map2| should be left unchanged but marked unstable.
CHECK(!map2->is_stable());
CHECK(!map2->is_deprecated()); CHECK(!map2->is_deprecated());
CHECK_NE(*map2, *new_map); CHECK_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2)); CHECK(expectations2.Check(*map2));
...@@ -1182,6 +1194,8 @@ struct CheckDeprecated { ...@@ -1182,6 +1194,8 @@ struct CheckDeprecated {
struct CheckSameMap { struct CheckSameMap {
void Check(Handle<Map> map, Handle<Map> new_map, void Check(Handle<Map> map, Handle<Map> new_map,
const Expectations& expectations) { const Expectations& expectations) {
// |map| was not reconfigured, therefore it should stay stable.
CHECK(map->is_stable());
CHECK(!map->is_deprecated()); CHECK(!map->is_deprecated());
CHECK_EQ(*map, *new_map); CHECK_EQ(*map, *new_map);
...@@ -1195,6 +1209,21 @@ struct CheckSameMap { ...@@ -1195,6 +1209,21 @@ struct CheckSameMap {
}; };
// Checks that given |map| is NOT deprecated and matches expectations.
// |new_map| is unrelated to |map|.
struct CheckUnrelated {
void Check(Handle<Map> map, Handle<Map> new_map,
const Expectations& expectations) {
CHECK(!map->is_deprecated());
CHECK_NE(*map, *new_map);
CHECK(expectations.Check(*map));
CHECK(new_map->is_stable());
CHECK(!new_map->is_deprecated());
}
};
// Checks that given |map| is NOT deprecated, and |new_map| is a result of // Checks that given |map| is NOT deprecated, and |new_map| is a result of
// copy-generalize-all-representations. // copy-generalize-all-representations.
struct CheckCopyGeneralizeAllRepresentations { struct CheckCopyGeneralizeAllRepresentations {
...@@ -1288,7 +1317,8 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap( ...@@ -1288,7 +1317,8 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
Handle<Map> new_map = Handle<Map> new_map =
Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
// |map2| should be left unchanged. // |map2| should be left unchanged but marked unstable.
CHECK(!map2->is_stable());
CHECK(!map2->is_deprecated()); CHECK(!map2->is_deprecated());
CHECK_NE(*map2, *new_map); CHECK_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2)); CHECK(expectations2.Check(*map2));
...@@ -1365,6 +1395,40 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) { ...@@ -1365,6 +1395,40 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
} }
TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
struct TestConfig {
Handle<JSFunction> js_func_;
Handle<AccessorPair> pair_;
TestConfig() {
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
js_func_ = factory->NewFunction(factory->empty_string());
pair_ = CreateAccessorPair(true, true);
}
Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
Handle<Map> map) {
CHECK(branch_id == 1 || branch_id == 2);
if (branch_id == 1) {
return expectations.AddDataConstant(map, NONE, js_func_);
} else {
return expectations.AddAccessorConstant(map, NONE, pair_);
}
}
void UpdateExpectations(int property_index, Expectations& expectations) {}
};
TestConfig config;
// These are completely separate branches in transition tree.
CheckUnrelated checker;
TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
}
TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) { TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
...@@ -1381,9 +1445,8 @@ TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) { ...@@ -1381,9 +1445,8 @@ TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
return expectations.AddAccessorConstant(map, NONE, pair_); return expectations.AddAccessorConstant(map, NONE, pair_);
} }
bool UpdateExpectations(int property_index, Expectations& expectations) { void UpdateExpectations(int property_index, Expectations& expectations) {
// Two branches are "compatible" so the |map1| should NOT be deprecated. // Two branches are "compatible" so the |map1| should NOT be deprecated.
return false;
} }
}; };
...@@ -1435,6 +1498,37 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) { ...@@ -1435,6 +1498,37 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
} }
TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
struct TestConfig {
Handle<AccessorPair> pair_;
TestConfig() { pair_ = CreateAccessorPair(true, true); }
Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
Handle<Map> map) {
CHECK(branch_id == 1 || branch_id == 2);
if (branch_id == 1) {
return expectations.AddAccessorConstant(map, NONE, pair_);
} else {
Isolate* isolate = CcTest::i_isolate();
Handle<HeapType> any_type = HeapType::Any(isolate);
return expectations.AddDataField(map, NONE, Representation::Smi(),
any_type);
}
}
void UpdateExpectations(int property_index, Expectations& expectations) {}
};
TestConfig config;
// These are completely separate branches in transition tree.
CheckUnrelated checker;
TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// A set of tests checking split map deprecation. // A set of tests checking split map deprecation.
// //
...@@ -1486,6 +1580,7 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { ...@@ -1486,6 +1580,7 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
// transition tree. // transition tree.
CHECK(map->is_deprecated()); CHECK(map->is_deprecated());
CHECK(!split_map->is_deprecated()); CHECK(!split_map->is_deprecated());
CHECK(map2->is_stable());
CHECK(!map2->is_deprecated()); CHECK(!map2->is_deprecated());
// Fill in transition tree of |map2| so that it can't have more transitions. // Fill in transition tree of |map2| so that it can't have more transitions.
...@@ -1931,7 +2026,8 @@ struct FieldGeneralizationChecker { ...@@ -1931,7 +2026,8 @@ struct FieldGeneralizationChecker {
Handle<Map> updated_map = Map::Update(map1); Handle<Map> updated_map = Map::Update(map1);
CHECK_EQ(*map2, *updated_map); CHECK_EQ(*map2, *updated_map);
expectations2.SetDataField(descriptor_, representation_, heap_type_); expectations2.SetDataField(descriptor_, attributes_, representation_,
heap_type_);
CHECK(expectations2.Check(*map2)); CHECK(expectations2.Check(*map2));
} }
}; };
......
// Copyright 2015 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.
var accessor_to_data_case = (function() {
var v = {};
Object.defineProperty(v, "foo", { get: function() { return 42; }, configurable: true});
var obj = {};
obj["boom"] = v;
Object.defineProperty(v, "foo", { value: 0, writable: true, configurable: true });
return obj;
})();
var data_to_accessor_case = (function() {
var v = {};
Object.defineProperty(v, "bar", { value: 0, writable: true, configurable: true });
var obj = {};
obj["bam"] = v;
Object.defineProperty(v, "bar", { get: function() { return 42; }, configurable: true});
return obj;
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment