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
<< pre_allocated_property_fields() << "\n";
os << " - unused property fields: " << unused_property_fields() << "\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_prototype_map()) {
os << " - prototype_map\n";
......
......@@ -2565,6 +2565,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
target_descriptors->GetFieldType(modify_index)));
}
#endif
if (*target_map != *old_map) {
old_map->NotifyLeafMapLayoutChange();
}
return target_map;
}
......@@ -2818,13 +2821,6 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
split_kind, old_descriptors->GetKey(split_nof), split_attributes,
*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
// already contains entry for given descriptor. This means that the transition
// 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,
"GenAll_CantHaveMoreTransitions");
}
old_map->NotifyLeafMapLayoutChange();
if (FLAG_trace_generalization && modify_index >= 0) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
......
......@@ -437,9 +437,9 @@ TEST(ReconfigureAccessorToNonExistingDataField) {
Handle<Map> new_map = Map::ReconfigureProperty(
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_stable());
CHECK(!map->is_stable());
CHECK(expectations.Check(*map));
expectations.SetDataField(0, NONE, Representation::None(), none_type);
......@@ -600,12 +600,14 @@ static void TestGeneralizeRepresentation(
CHECK(expectations.Check(*new_map));
if (is_detached_map) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated());
CHECK_NE(*map, *new_map);
CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
info.dependencies()->HasAborted());
} else if (expected_deprecation) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated());
CHECK(field_owner->is_deprecated());
CHECK_NE(*map, *new_map);
......@@ -613,6 +615,7 @@ static void TestGeneralizeRepresentation(
} else {
CHECK(!field_owner->is_deprecated());
CHECK(map->is_stable()); // Map did not change, must be left stable.
CHECK_EQ(*map, *new_map);
CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
......@@ -653,6 +656,12 @@ static void TestGeneralizeRepresentation(
to_type, expected_representation, expected_type, expected_deprecation,
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) {
expectations.SetDataField(i, Representation::Double(), any_type);
CHECK(!map->is_stable());
CHECK(map->is_deprecated());
CHECK_NE(*map, *new_map);
CHECK(i == 0 || maps[i - 1]->is_deprecated());
......@@ -961,7 +971,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
Handle<Map> new_map =
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_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2));
......@@ -1046,7 +1057,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
Handle<Map> new_map =
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_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2));
......@@ -1182,6 +1194,8 @@ struct CheckDeprecated {
struct CheckSameMap {
void Check(Handle<Map> map, Handle<Map> new_map,
const Expectations& expectations) {
// |map| was not reconfigured, therefore it should stay stable.
CHECK(map->is_stable());
CHECK(!map->is_deprecated());
CHECK_EQ(*map, *new_map);
......@@ -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
// copy-generalize-all-representations.
struct CheckCopyGeneralizeAllRepresentations {
......@@ -1288,7 +1317,8 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
Handle<Map> new_map =
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_NE(*map2, *new_map);
CHECK(expectations2.Check(*map2));
......@@ -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) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
......@@ -1381,9 +1445,8 @@ TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
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.
return false;
}
};
......@@ -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.
//
......@@ -1486,6 +1580,7 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
// transition tree.
CHECK(map->is_deprecated());
CHECK(!split_map->is_deprecated());
CHECK(map2->is_stable());
CHECK(!map2->is_deprecated());
// Fill in transition tree of |map2| so that it can't have more transitions.
......@@ -1931,7 +2026,8 @@ struct FieldGeneralizationChecker {
Handle<Map> updated_map = Map::Update(map1);
CHECK_EQ(*map2, *updated_map);
expectations2.SetDataField(descriptor_, representation_, heap_type_);
expectations2.SetDataField(descriptor_, attributes_, representation_,
heap_type_);
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