Commit c03c7b73 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[runtime] Prototype const-to-mutable field migrations without deprecating maps.

It depends on constant field tracking and currently disabled.

BUG=v8:5495

Change-Id: I6202cddfc2d32b5a06c5ab00c42caa6e276a3eb1
Reviewed-on: https://chromium-review.googlesource.com/451639
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43687}
parent 5002a4a9
...@@ -904,6 +904,7 @@ DEFINE_INT(ic_stats, 0, "inline cache state transitions statistics") ...@@ -904,6 +904,7 @@ DEFINE_INT(ic_stats, 0, "inline cache state transitions statistics")
DEFINE_VALUE_IMPLICATION(trace_ic, ic_stats, 1) DEFINE_VALUE_IMPLICATION(trace_ic, ic_stats, 1)
DEFINE_BOOL_READONLY(track_constant_fields, false, DEFINE_BOOL_READONLY(track_constant_fields, false,
"enable constant field tracking") "enable constant field tracking")
DEFINE_BOOL_READONLY(modify_map_inplace, false, "enable in-place map updates")
// macro-assembler-ia32.cc // macro-assembler-ia32.cc
DEFINE_BOOL(native_code_counters, false, DEFINE_BOOL(native_code_counters, false,
......
...@@ -252,7 +252,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { ...@@ -252,7 +252,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
if (old_map.is_identical_to(new_map)) { if (old_map.is_identical_to(new_map)) {
// Update the property details if the representation was None. // Update the property details if the representation was None.
if (representation().IsNone()) { if (constness() != new_constness || representation().IsNone()) {
property_details_ = property_details_ =
new_map->instance_descriptors()->GetDetails(descriptor_number()); new_map->instance_descriptors()->GetDetails(descriptor_number());
} }
......
...@@ -255,7 +255,8 @@ MapUpdater::State MapUpdater::FindRootMap() { ...@@ -255,7 +255,8 @@ MapUpdater::State MapUpdater::FindRootMap() {
if (old_details.location() != kField) { if (old_details.location() != kField) {
return CopyGeneralizeAllFields("GenAll_RootModification2"); return CopyGeneralizeAllFields("GenAll_RootModification2");
} }
if (new_constness_ != old_details.constness()) { if (new_constness_ != old_details.constness() &&
(!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
return CopyGeneralizeAllFields("GenAll_RootModification3"); return CopyGeneralizeAllFields("GenAll_RootModification3");
} }
if (!new_representation_.fits_into(old_details.representation())) { if (!new_representation_.fits_into(old_details.representation())) {
...@@ -270,6 +271,19 @@ MapUpdater::State MapUpdater::FindRootMap() { ...@@ -270,6 +271,19 @@ MapUpdater::State MapUpdater::FindRootMap() {
if (!new_field_type_->NowIs(old_field_type)) { if (!new_field_type_->NowIs(old_field_type)) {
return CopyGeneralizeAllFields("GenAll_RootModification5"); return CopyGeneralizeAllFields("GenAll_RootModification5");
} }
// Modify root map in-place.
if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
// Only prototype root maps are allowed to be updated in-place.
// TODO(ishell): fix all the stubs that use prototype map check to
// ensure that the prototype was not modified.
DCHECK(old_map_->is_prototype_map());
DCHECK(old_map_->is_stable());
DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
GeneralizeField(old_map_, modified_descriptor_, new_constness_,
old_details.representation(),
handle(old_field_type, isolate_));
}
} }
// From here on, use the map with correct elements kind as root map. // From here on, use the map with correct elements kind as root map.
...@@ -305,7 +319,8 @@ MapUpdater::State MapUpdater::FindTargetMap() { ...@@ -305,7 +319,8 @@ MapUpdater::State MapUpdater::FindTargetMap() {
return CopyGeneralizeAllFields("GenAll_Incompatible"); return CopyGeneralizeAllFields("GenAll_Incompatible");
} }
PropertyConstness tmp_constness = tmp_details.constness(); PropertyConstness tmp_constness = tmp_details.constness();
if (!IsGeneralizableTo(old_details.constness(), tmp_constness)) { if (!FLAG_modify_map_inplace &&
!IsGeneralizableTo(old_details.constness(), tmp_constness)) {
break; break;
} }
if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) { if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
...@@ -319,7 +334,9 @@ MapUpdater::State MapUpdater::FindTargetMap() { ...@@ -319,7 +334,9 @@ MapUpdater::State MapUpdater::FindTargetMap() {
if (tmp_details.location() == kField) { if (tmp_details.location() == kField) {
Handle<FieldType> old_field_type = Handle<FieldType> old_field_type =
GetOrComputeFieldType(i, old_details.location(), tmp_representation); GetOrComputeFieldType(i, old_details.location(), tmp_representation);
GeneralizeField(tmp_map, i, tmp_constness, tmp_representation, PropertyConstness constness =
FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
GeneralizeField(tmp_map, i, constness, tmp_representation,
old_field_type); old_field_type);
} else { } else {
// kDescriptor: Check that the value matches. // kDescriptor: Check that the value matches.
......
...@@ -4005,14 +4005,16 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name, ...@@ -4005,14 +4005,16 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
PropertyDetails details = descriptors->GetDetails(descriptor); PropertyDetails details = descriptors->GetDetails(descriptor);
// Currently constness change implies map change. // Currently constness change implies map change.
DCHECK_EQ(new_constness, details.constness()); DCHECK_IMPLIES(new_constness != details.constness(),
FLAG_modify_map_inplace);
// It is allowed to change representation here only from None to something. // It is allowed to change representation here only from None to something.
DCHECK(details.representation().Equals(new_representation) || DCHECK(details.representation().Equals(new_representation) ||
details.representation().IsNone()); details.representation().IsNone());
// Skip if already updated the shared descriptor. // Skip if already updated the shared descriptor.
if (descriptors->GetValue(descriptor) != *new_wrapped_type) { if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
descriptors->GetValue(descriptor) != *new_wrapped_type) {
DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable); DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
Descriptor d = Descriptor::DataField( Descriptor d = Descriptor::DataField(
name, descriptors->GetFieldIndex(descriptor), details.attributes(), name, descriptors->GetFieldIndex(descriptor), details.attributes(),
...@@ -4060,7 +4062,11 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index, ...@@ -4060,7 +4062,11 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index,
Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
isolate); isolate);
if (old_constness == new_constness && // Return if the current map is general enough to hold requested contness and
// representation/field type.
if (((FLAG_modify_map_inplace &&
IsGeneralizableTo(new_constness, old_constness)) ||
(!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
old_representation.Equals(new_representation) && old_representation.Equals(new_representation) &&
!FieldTypeIsCleared(new_representation, *new_field_type) && !FieldTypeIsCleared(new_representation, *new_field_type) &&
// Checking old_field_type for being cleared is not necessary because // Checking old_field_type for being cleared is not necessary because
...@@ -4081,6 +4087,9 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index, ...@@ -4081,6 +4087,9 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index,
new_field_type = new_field_type =
Map::GeneralizeFieldType(old_representation, old_field_type, Map::GeneralizeFieldType(old_representation, old_field_type,
new_representation, new_field_type, isolate); new_representation, new_field_type, isolate);
if (FLAG_modify_map_inplace) {
new_constness = GeneralizeConstness(old_constness, new_constness);
}
PropertyDetails details = descriptors->GetDetails(modify_index); PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index)); Handle<Name> name(descriptors->GetKey(modify_index));
......
...@@ -1221,13 +1221,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) { ...@@ -1221,13 +1221,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), expected_type}); {kConst, Representation::HeapObject(), expected_type});
// Currently, kConst to kMutable migration causes map change, therefore if (FLAG_modify_map_inplace) {
// non-trivial generalization. // kConst to kMutable migration does not create a new map, therefore
TestReconfigureDataFieldAttribute_GeneralizeField( // trivial generalization.
{kConst, Representation::HeapObject(), current_type}, TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), current_type},
{kMutable, Representation::HeapObject(), expected_type}); {kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), expected_type});
} else {
// kConst to kMutable migration causes map change, therefore
// non-trivial generalization.
TestReconfigureDataFieldAttribute_GeneralizeField(
{kConst, Representation::HeapObject(), current_type},
{kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), expected_type});
}
TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial( TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), current_type}, {kMutable, Representation::HeapObject(), current_type},
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
...@@ -1248,13 +1256,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) { ...@@ -1248,13 +1256,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), any_type}, false); {kConst, Representation::HeapObject(), any_type}, false);
// Currently, kConst to kMutable migration causes map change, therefore if (FLAG_modify_map_inplace) {
// non-trivial generalization. // kConst to kMutable migration does not create a new map, therefore
TestReconfigureDataFieldAttribute_GeneralizeField( // trivial generalization.
{kConst, Representation::HeapObject(), any_type}, TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), any_type},
{kMutable, Representation::HeapObject(), any_type}); {kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), any_type});
} else {
// kConst to kMutable migration causes map change, therefore
// non-trivial generalization.
TestReconfigureDataFieldAttribute_GeneralizeField(
{kConst, Representation::HeapObject(), any_type},
{kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), any_type});
}
TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial( TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), any_type}, {kMutable, Representation::HeapObject(), any_type},
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
...@@ -1963,13 +1979,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) { ...@@ -1963,13 +1979,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), expected_type}); {kConst, Representation::HeapObject(), expected_type});
// Currently, kConst to kMutable migration causes map change, therefore if (FLAG_modify_map_inplace) {
// non-trivial generalization. // kConst to kMutable migration does not create a new map, therefore
TestReconfigureElementsKind_GeneralizeField( // trivial generalization.
{kConst, Representation::HeapObject(), current_type}, TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), current_type},
{kMutable, Representation::HeapObject(), expected_type}); {kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), expected_type});
} else {
// kConst to kMutable migration causes map change, therefore
// non-trivial generalization.
TestReconfigureElementsKind_GeneralizeField(
{kConst, Representation::HeapObject(), current_type},
{kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), expected_type});
}
TestReconfigureElementsKind_GeneralizeFieldTrivial( TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), current_type}, {kMutable, Representation::HeapObject(), current_type},
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
...@@ -1990,12 +2014,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) { ...@@ -1990,12 +2014,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), any_type}, false); {kConst, Representation::HeapObject(), any_type}, false);
// Currently, kConst to kMutable migration causes map change, therefore if (FLAG_modify_map_inplace) {
// non-trivial generalization. // kConst to kMutable migration does not create a new map, therefore
TestReconfigureElementsKind_GeneralizeField( // trivial generalization.
{kConst, Representation::HeapObject(), any_type}, TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), new_type}, {kConst, Representation::HeapObject(), any_type},
{kMutable, Representation::HeapObject(), any_type}); {kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), any_type});
} else {
// kConst to kMutable migration causes map change, therefore
// non-trivial generalization.
TestReconfigureElementsKind_GeneralizeField(
{kConst, Representation::HeapObject(), any_type},
{kMutable, Representation::HeapObject(), new_type},
{kMutable, Representation::HeapObject(), any_type});
}
TestReconfigureElementsKind_GeneralizeFieldTrivial( TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kMutable, Representation::HeapObject(), any_type}, {kMutable, Representation::HeapObject(), any_type},
......
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