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")
DEFINE_VALUE_IMPLICATION(trace_ic, ic_stats, 1)
DEFINE_BOOL_READONLY(track_constant_fields, false,
"enable constant field tracking")
DEFINE_BOOL_READONLY(modify_map_inplace, false, "enable in-place map updates")
// macro-assembler-ia32.cc
DEFINE_BOOL(native_code_counters, false,
......
......@@ -252,7 +252,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
if (old_map.is_identical_to(new_map)) {
// Update the property details if the representation was None.
if (representation().IsNone()) {
if (constness() != new_constness || representation().IsNone()) {
property_details_ =
new_map->instance_descriptors()->GetDetails(descriptor_number());
}
......
......@@ -255,7 +255,8 @@ MapUpdater::State MapUpdater::FindRootMap() {
if (old_details.location() != kField) {
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");
}
if (!new_representation_.fits_into(old_details.representation())) {
......@@ -270,6 +271,19 @@ MapUpdater::State MapUpdater::FindRootMap() {
if (!new_field_type_->NowIs(old_field_type)) {
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.
......@@ -305,7 +319,8 @@ MapUpdater::State MapUpdater::FindTargetMap() {
return CopyGeneralizeAllFields("GenAll_Incompatible");
}
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;
}
if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
......@@ -319,7 +334,9 @@ MapUpdater::State MapUpdater::FindTargetMap() {
if (tmp_details.location() == kField) {
Handle<FieldType> old_field_type =
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);
} else {
// kDescriptor: Check that the value matches.
......
......@@ -4005,14 +4005,16 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
PropertyDetails details = descriptors->GetDetails(descriptor);
// 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.
DCHECK(details.representation().Equals(new_representation) ||
details.representation().IsNone());
// 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);
Descriptor d = Descriptor::DataField(
name, descriptors->GetFieldIndex(descriptor), details.attributes(),
......@@ -4060,7 +4062,11 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index,
Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
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) &&
!FieldTypeIsCleared(new_representation, *new_field_type) &&
// Checking old_field_type for being cleared is not necessary because
......@@ -4081,6 +4087,9 @@ void Map::GeneralizeField(Handle<Map> map, int modify_index,
new_field_type =
Map::GeneralizeFieldType(old_representation, old_field_type,
new_representation, new_field_type, isolate);
if (FLAG_modify_map_inplace) {
new_constness = GeneralizeConstness(old_constness, new_constness);
}
PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index));
......
......@@ -1221,13 +1221,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), expected_type});
// Currently, kConst to kMutable migration causes map change, therefore
if (FLAG_modify_map_inplace) {
// kConst to kMutable migration does not create a new map, therefore
// trivial generalization.
TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kConst, Representation::HeapObject(), current_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(
{kMutable, Representation::HeapObject(), current_type},
{kConst, Representation::HeapObject(), new_type},
......@@ -1248,13 +1256,21 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), any_type}, false);
// Currently, kConst to kMutable migration causes map change, therefore
if (FLAG_modify_map_inplace) {
// kConst to kMutable migration does not create a new map, therefore
// trivial generalization.
TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
{kConst, 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(
{kMutable, Representation::HeapObject(), any_type},
{kConst, Representation::HeapObject(), new_type},
......@@ -1963,13 +1979,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), expected_type});
// Currently, kConst to kMutable migration causes map change, therefore
if (FLAG_modify_map_inplace) {
// kConst to kMutable migration does not create a new map, therefore
// trivial generalization.
TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kConst, Representation::HeapObject(), current_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(
{kMutable, Representation::HeapObject(), current_type},
{kConst, Representation::HeapObject(), new_type},
......@@ -1990,12 +2014,21 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), any_type}, false);
// Currently, kConst to kMutable migration causes map change, therefore
if (FLAG_modify_map_inplace) {
// kConst to kMutable migration does not create a new map, therefore
// trivial generalization.
TestReconfigureElementsKind_GeneralizeFieldTrivial(
{kConst, 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(
{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