[runtime] Add MapUpdater class that manages all kinds of map updates.
... including property reconfiguring, elements kind change and migration of a map to an up-to-date non-deprecated version. BUG=v8:5495 Review-Url: https://codereview.chromium.org/2601643002 Cr-Commit-Position: refs/heads/master@{#42177}
This commit is contained in:
parent
8dfea24e3d
commit
0f159f5973
2
BUILD.gn
2
BUILD.gn
@ -1539,6 +1539,8 @@ v8_source_set("v8_base") {
|
||||
"src/machine-type.cc",
|
||||
"src/machine-type.h",
|
||||
"src/macro-assembler.h",
|
||||
"src/map-updater.cc",
|
||||
"src/map-updater.h",
|
||||
"src/messages.cc",
|
||||
"src/messages.h",
|
||||
"src/msan.h",
|
||||
|
@ -399,8 +399,8 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
|
||||
->NowContains(value)) {
|
||||
Handle<FieldType> value_type(
|
||||
value->OptimalType(isolate(), expected_representation));
|
||||
Map::GeneralizeFieldType(target, descriptor,
|
||||
expected_representation, value_type);
|
||||
Map::GeneralizeField(target, descriptor, expected_representation,
|
||||
value_type);
|
||||
}
|
||||
DCHECK(target->instance_descriptors()
|
||||
->GetFieldType(descriptor)
|
||||
|
615
src/map-updater.cc
Normal file
615
src/map-updater.cc
Normal file
@ -0,0 +1,615 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#include "src/map-updater.h"
|
||||
|
||||
#include "src/field-type.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/transitions.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
|
||||
if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
|
||||
// TODO(ishell): compare AccessorPairs.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Name* MapUpdater::GetKey(int descriptor) const {
|
||||
return old_descriptors_->GetKey(descriptor);
|
||||
}
|
||||
|
||||
PropertyDetails MapUpdater::GetDetails(int descriptor) const {
|
||||
DCHECK_LE(0, descriptor);
|
||||
if (descriptor == modified_descriptor_) {
|
||||
return PropertyDetails(new_kind_, new_attributes_, new_location_,
|
||||
new_representation_);
|
||||
}
|
||||
return old_descriptors_->GetDetails(descriptor);
|
||||
}
|
||||
|
||||
Object* MapUpdater::GetValue(int descriptor) const {
|
||||
DCHECK_LE(0, descriptor);
|
||||
if (descriptor == modified_descriptor_) {
|
||||
DCHECK_EQ(kDescriptor, new_location_);
|
||||
return *new_value_;
|
||||
}
|
||||
DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
|
||||
return old_descriptors_->GetValue(descriptor);
|
||||
}
|
||||
|
||||
FieldType* MapUpdater::GetFieldType(int descriptor) const {
|
||||
DCHECK_LE(0, descriptor);
|
||||
if (descriptor == modified_descriptor_) {
|
||||
DCHECK_EQ(kField, new_location_);
|
||||
return *new_field_type_;
|
||||
}
|
||||
DCHECK_EQ(kField, GetDetails(descriptor).location());
|
||||
return old_descriptors_->GetFieldType(descriptor);
|
||||
}
|
||||
|
||||
Handle<FieldType> MapUpdater::GetOrComputeFieldType(
|
||||
int descriptor, PropertyLocation location,
|
||||
Representation representation) const {
|
||||
DCHECK_LE(0, descriptor);
|
||||
// |location| is just a pre-fetched GetDetails(descriptor).location().
|
||||
DCHECK_EQ(location, GetDetails(descriptor).location());
|
||||
if (location == kField) {
|
||||
return handle(GetFieldType(descriptor), isolate_);
|
||||
} else {
|
||||
return GetValue(descriptor)->OptimalType(isolate_, representation);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<FieldType> MapUpdater::GetOrComputeFieldType(
|
||||
Handle<DescriptorArray> descriptors, int descriptor,
|
||||
PropertyLocation location, Representation representation) {
|
||||
// |location| is just a pre-fetched GetDetails(descriptor).location().
|
||||
DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
|
||||
if (location == kField) {
|
||||
return handle(descriptors->GetFieldType(descriptor), isolate_);
|
||||
} else {
|
||||
return descriptors->GetValue(descriptor)
|
||||
->OptimalType(isolate_, representation);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
|
||||
PropertyAttributes attributes,
|
||||
Representation representation,
|
||||
Handle<FieldType> field_type) {
|
||||
DCHECK_EQ(kInitialized, state_);
|
||||
DCHECK_LE(0, descriptor);
|
||||
DCHECK(!old_map_->is_dictionary_map());
|
||||
modified_descriptor_ = descriptor;
|
||||
new_kind_ = kData;
|
||||
new_attributes_ = attributes;
|
||||
new_location_ = kField;
|
||||
new_representation_ = representation;
|
||||
new_field_type_ = field_type;
|
||||
|
||||
PropertyDetails old_details =
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
|
||||
// If property kind is not reconfigured merge the result with
|
||||
// representation/field type from the old descriptor.
|
||||
if (old_details.kind() == new_kind_) {
|
||||
Representation old_representation = old_details.representation();
|
||||
new_representation_ = new_representation_.generalize(old_representation);
|
||||
|
||||
Handle<FieldType> old_field_type =
|
||||
GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
|
||||
old_details.location(), new_representation_);
|
||||
|
||||
new_field_type_ = Map::GeneralizeFieldType(
|
||||
old_representation, old_field_type, new_representation_,
|
||||
new_field_type_, isolate_);
|
||||
}
|
||||
|
||||
if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
|
||||
if (FindRootMap() == kEnd) return result_map_;
|
||||
if (FindTargetMap() == kEnd) return result_map_;
|
||||
ConstructNewMap();
|
||||
DCHECK_EQ(kEnd, state_);
|
||||
return result_map_;
|
||||
}
|
||||
|
||||
Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
|
||||
DCHECK_EQ(kInitialized, state_);
|
||||
new_elements_kind_ = elements_kind;
|
||||
|
||||
if (FindRootMap() == kEnd) return result_map_;
|
||||
if (FindTargetMap() == kEnd) return result_map_;
|
||||
ConstructNewMap();
|
||||
DCHECK_EQ(kEnd, state_);
|
||||
return result_map_;
|
||||
}
|
||||
|
||||
Handle<Map> MapUpdater::Update() {
|
||||
DCHECK_EQ(kInitialized, state_);
|
||||
DCHECK(old_map_->is_deprecated());
|
||||
|
||||
if (FindRootMap() == kEnd) return result_map_;
|
||||
if (FindTargetMap() == kEnd) return result_map_;
|
||||
ConstructNewMap();
|
||||
DCHECK_EQ(kEnd, state_);
|
||||
return result_map_;
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::CopyGeneralizeAllRepresentations(
|
||||
const char* reason) {
|
||||
StoreMode store_mode =
|
||||
modified_descriptor_ >= 0 ? FORCE_FIELD : ALLOW_IN_DESCRIPTOR;
|
||||
result_map_ = Map::CopyGeneralizeAllRepresentations(
|
||||
old_map_, new_elements_kind_, modified_descriptor_, store_mode, new_kind_,
|
||||
new_attributes_, reason);
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
|
||||
// If it's just a representation generalization case (i.e. property kind and
|
||||
// attributes stays unchanged) it's fine to transition from None to anything
|
||||
// but double without any modification to the object, because the default
|
||||
// uninitialized value for representation None can be overwritten by both
|
||||
// smi and tagged values. Doubles, however, would require a box allocation.
|
||||
if (new_representation_.IsNone() || new_representation_.IsDouble()) {
|
||||
return state_; // Not done yet.
|
||||
}
|
||||
|
||||
PropertyDetails old_details =
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
Representation old_representation = old_details.representation();
|
||||
if (!old_representation.IsNone()) {
|
||||
return state_; // Not done yet.
|
||||
}
|
||||
|
||||
DCHECK_EQ(new_kind_, old_details.kind());
|
||||
DCHECK_EQ(new_attributes_, old_details.attributes());
|
||||
DCHECK_EQ(kField, old_details.location());
|
||||
if (FLAG_trace_generalization) {
|
||||
old_map_->PrintGeneralization(
|
||||
stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_,
|
||||
false, old_representation, new_representation_,
|
||||
handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
|
||||
MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
|
||||
}
|
||||
Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_),
|
||||
isolate_);
|
||||
|
||||
Map::GeneralizeField(field_owner, modified_descriptor_, new_representation_,
|
||||
new_field_type_);
|
||||
// Check that the descriptor array was updated.
|
||||
DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
|
||||
.representation()
|
||||
.Equals(new_representation_));
|
||||
DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
|
||||
->NowIs(new_field_type_));
|
||||
|
||||
result_map_ = old_map_;
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::FindRootMap() {
|
||||
DCHECK_EQ(kInitialized, state_);
|
||||
// Check the state of the root map.
|
||||
root_map_ = handle(old_map_->FindRootMap(), isolate_);
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
if (!old_map_->EquivalentToForTransition(*root_map_)) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_NotEquivalent");
|
||||
}
|
||||
|
||||
ElementsKind from_kind = root_map_->elements_kind();
|
||||
ElementsKind to_kind = new_elements_kind_;
|
||||
// TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
|
||||
if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
|
||||
to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
|
||||
to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
|
||||
!(IsTransitionableFastElementsKind(from_kind) &&
|
||||
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_InvalidElementsTransition");
|
||||
}
|
||||
|
||||
if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
|
||||
PropertyDetails old_details =
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
if (old_details.kind() != new_kind_ ||
|
||||
old_details.attributes() != new_attributes_) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_RootModification1");
|
||||
}
|
||||
if (!new_representation_.fits_into(old_details.representation())) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_RootModification2");
|
||||
}
|
||||
if (old_details.location() != kField) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_RootModification3");
|
||||
}
|
||||
DCHECK_EQ(kData, old_details.kind());
|
||||
DCHECK_EQ(kData, new_kind_);
|
||||
DCHECK_EQ(kField, new_location_);
|
||||
FieldType* old_field_type =
|
||||
old_descriptors_->GetFieldType(modified_descriptor_);
|
||||
if (!new_field_type_->NowIs(old_field_type)) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_RootModification4");
|
||||
}
|
||||
}
|
||||
|
||||
// From here on, use the map with correct elements kind as root map.
|
||||
if (from_kind != to_kind) {
|
||||
root_map_ = Map::AsElementsKind(root_map_, to_kind);
|
||||
}
|
||||
state_ = kAtRootMap;
|
||||
return state_; // Not done yet.
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
DCHECK_EQ(kAtRootMap, state_);
|
||||
target_map_ = root_map_;
|
||||
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
for (int i = root_nof; i < old_nof_; ++i) {
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
Map* transition = TransitionArray::SearchTransition(
|
||||
*target_map_, old_details.kind(), GetKey(i), old_details.attributes());
|
||||
if (transition == NULL) break;
|
||||
Handle<Map> tmp_map(transition, isolate_);
|
||||
|
||||
Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
|
||||
isolate_);
|
||||
|
||||
// Check if target map is incompatible.
|
||||
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(old_details.kind(), tmp_details.kind());
|
||||
DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
|
||||
if (old_details.kind() == kAccessor &&
|
||||
!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
|
||||
// TODO(ishell): mutable accessors are not implemented yet.
|
||||
return CopyGeneralizeAllRepresentations("GenAll_Incompatible");
|
||||
}
|
||||
// Check if old location fits into tmp location.
|
||||
if (old_details.location() == kField &&
|
||||
tmp_details.location() == kDescriptor) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if old representation fits into tmp representation.
|
||||
Representation tmp_representation = tmp_details.representation();
|
||||
if (!old_details.representation().fits_into(tmp_representation)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp_details.location() == kField) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetOrComputeFieldType(i, old_details.location(), tmp_representation);
|
||||
Map::GeneralizeField(tmp_map, i, tmp_representation, old_field_type);
|
||||
} else {
|
||||
// kDescriptor: Check that the value matches.
|
||||
if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCHECK(!tmp_map->is_deprecated());
|
||||
target_map_ = tmp_map;
|
||||
}
|
||||
|
||||
// Directly change the map if the target map is more general.
|
||||
int target_nof = target_map_->NumberOfOwnDescriptors();
|
||||
if (target_nof == old_nof_) {
|
||||
#ifdef DEBUG
|
||||
if (modified_descriptor_ >= 0) {
|
||||
DescriptorArray* target_descriptors = target_map_->instance_descriptors();
|
||||
PropertyDetails details =
|
||||
target_descriptors->GetDetails(modified_descriptor_);
|
||||
DCHECK_EQ(new_kind_, details.kind());
|
||||
DCHECK_EQ(new_attributes_, details.attributes());
|
||||
DCHECK_EQ(new_location_, details.location());
|
||||
DCHECK(new_representation_.fits_into(details.representation()));
|
||||
if (new_location_ == kField) {
|
||||
DCHECK_EQ(kField, details.location());
|
||||
DCHECK(new_field_type_->NowIs(
|
||||
target_descriptors->GetFieldType(modified_descriptor_)));
|
||||
} else {
|
||||
DCHECK(details.location() == kField ||
|
||||
EqualImmutableValues(*new_value_, target_descriptors->GetValue(
|
||||
modified_descriptor_)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (*target_map_ != *old_map_) {
|
||||
old_map_->NotifyLeafMapLayoutChange();
|
||||
}
|
||||
result_map_ = target_map_;
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
|
||||
// Find the last compatible target map in the transition tree.
|
||||
for (int i = target_nof; i < old_nof_; ++i) {
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
Map* transition = TransitionArray::SearchTransition(
|
||||
*target_map_, old_details.kind(), GetKey(i), old_details.attributes());
|
||||
if (transition == NULL) break;
|
||||
Handle<Map> tmp_map(transition, isolate_);
|
||||
Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
|
||||
isolate_);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check that target map is compatible.
|
||||
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(old_details.kind(), tmp_details.kind());
|
||||
DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
|
||||
#endif
|
||||
if (old_details.kind() == kAccessor &&
|
||||
!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_Incompatible");
|
||||
}
|
||||
DCHECK(!tmp_map->is_deprecated());
|
||||
target_map_ = tmp_map;
|
||||
}
|
||||
|
||||
state_ = kAtTargetMap;
|
||||
return state_; // Not done yet.
|
||||
}
|
||||
|
||||
Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
|
||||
int target_nof = target_map_->NumberOfOwnDescriptors();
|
||||
Handle<DescriptorArray> target_descriptors(
|
||||
target_map_->instance_descriptors(), isolate_);
|
||||
|
||||
// Allocate a new descriptor array large enough to hold the required
|
||||
// descriptors, with minimally the exact same size as the old descriptor
|
||||
// array.
|
||||
int new_slack =
|
||||
Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_;
|
||||
Handle<DescriptorArray> new_descriptors =
|
||||
DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
|
||||
DCHECK(new_descriptors->length() > target_descriptors->length() ||
|
||||
new_descriptors->NumberOfSlackDescriptors() > 0 ||
|
||||
new_descriptors->number_of_descriptors() ==
|
||||
old_descriptors_->number_of_descriptors());
|
||||
DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
|
||||
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
|
||||
// Given that we passed root modification check in FindRootMap() so
|
||||
// the root descriptors are either not modified at all or already more
|
||||
// general than we requested. Take |root_nof| entries as is.
|
||||
// 0 -> |root_nof|
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < root_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors_->GetDetails(i);
|
||||
if (old_details.location() == kField) {
|
||||
current_offset += old_details.field_width_in_words();
|
||||
}
|
||||
Descriptor d(handle(GetKey(i), isolate_),
|
||||
handle(old_descriptors_->GetValue(i), isolate_), old_details);
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
|
||||
// Merge "updated" old_descriptor entries with target_descriptor entries.
|
||||
// |root_nof| -> |target_nof|
|
||||
for (int i = root_nof; i < target_nof; ++i) {
|
||||
Handle<Name> key(GetKey(i), isolate_);
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
PropertyDetails target_details = target_descriptors->GetDetails(i);
|
||||
|
||||
PropertyKind next_kind = old_details.kind();
|
||||
PropertyAttributes next_attributes = old_details.attributes();
|
||||
PropertyLocation next_location =
|
||||
old_details.location() == kField ||
|
||||
target_details.location() == kField ||
|
||||
!EqualImmutableValues(target_descriptors->GetValue(i),
|
||||
GetValue(i))
|
||||
? kField
|
||||
: kDescriptor;
|
||||
|
||||
Representation next_representation =
|
||||
old_details.representation().generalize(
|
||||
target_details.representation());
|
||||
|
||||
DCHECK_EQ(next_kind, target_details.kind());
|
||||
DCHECK_EQ(next_attributes, target_details.attributes());
|
||||
|
||||
if (next_location == kField) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetOrComputeFieldType(i, old_details.location(), next_representation);
|
||||
|
||||
Handle<FieldType> target_field_type =
|
||||
GetOrComputeFieldType(target_descriptors, i,
|
||||
target_details.location(), next_representation);
|
||||
|
||||
Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
|
||||
old_details.representation(), old_field_type, next_representation,
|
||||
target_field_type, isolate_);
|
||||
|
||||
Handle<Object> wrapped_type(Map::WrapType(next_field_type));
|
||||
Descriptor d;
|
||||
if (next_kind == kData) {
|
||||
d = Descriptor::DataField(key, current_offset, wrapped_type,
|
||||
next_attributes, next_representation);
|
||||
} else {
|
||||
// TODO(ishell): mutable accessors are not implemented yet.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
DCHECK_EQ(kDescriptor, next_location);
|
||||
|
||||
Handle<Object> value(GetValue(i), isolate_);
|
||||
Descriptor d;
|
||||
if (next_kind == kData) {
|
||||
d = Descriptor::DataConstant(key, value, next_attributes);
|
||||
} else {
|
||||
DCHECK_EQ(kAccessor, next_kind);
|
||||
d = Descriptor::AccessorConstant(key, value, next_attributes);
|
||||
}
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
}
|
||||
|
||||
// Take "updated" old_descriptor entries.
|
||||
// |target_nof| -> |old_nof|
|
||||
for (int i = target_nof; i < old_nof_; ++i) {
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
Handle<Name> key(GetKey(i), isolate_);
|
||||
|
||||
PropertyKind next_kind = old_details.kind();
|
||||
PropertyAttributes next_attributes = old_details.attributes();
|
||||
PropertyLocation next_location = old_details.location();
|
||||
Representation next_representation = old_details.representation();
|
||||
|
||||
Descriptor d;
|
||||
if (next_location == kField) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetOrComputeFieldType(i, old_details.location(), next_representation);
|
||||
|
||||
Handle<Object> wrapped_type(Map::WrapType(old_field_type));
|
||||
Descriptor d;
|
||||
if (next_kind == kData) {
|
||||
d = Descriptor::DataField(key, current_offset, wrapped_type,
|
||||
next_attributes, next_representation);
|
||||
} else {
|
||||
// TODO(ishell): mutable accessors are not implemented yet.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
DCHECK_EQ(kDescriptor, next_location);
|
||||
|
||||
Handle<Object> value(GetValue(i), isolate_);
|
||||
if (next_kind == kData) {
|
||||
d = Descriptor::DataConstant(key, value, next_attributes);
|
||||
} else {
|
||||
DCHECK_EQ(kAccessor, next_kind);
|
||||
d = Descriptor::AccessorConstant(key, value, next_attributes);
|
||||
}
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
}
|
||||
|
||||
new_descriptors->Sort();
|
||||
return new_descriptors;
|
||||
}
|
||||
|
||||
Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
Map* current = *root_map_;
|
||||
for (int i = root_nof; i < old_nof_; i++) {
|
||||
Name* name = descriptors->GetKey(i);
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
|
||||
details.attributes());
|
||||
if (next == NULL) break;
|
||||
DescriptorArray* next_descriptors = next->instance_descriptors();
|
||||
|
||||
PropertyDetails next_details = next_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(details.kind(), next_details.kind());
|
||||
DCHECK_EQ(details.attributes(), next_details.attributes());
|
||||
if (details.location() != next_details.location()) break;
|
||||
if (!details.representation().Equals(next_details.representation())) break;
|
||||
|
||||
if (next_details.location() == kField) {
|
||||
FieldType* next_field_type = next_descriptors->GetFieldType(i);
|
||||
if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!EqualImmutableValues(descriptors->GetValue(i),
|
||||
next_descriptors->GetValue(i))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return handle(current, isolate_);
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::ConstructNewMap() {
|
||||
Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
|
||||
|
||||
Handle<Map> split_map = FindSplitMap(new_descriptors);
|
||||
int split_nof = split_map->NumberOfOwnDescriptors();
|
||||
DCHECK_NE(old_nof_, split_nof);
|
||||
|
||||
PropertyDetails split_details = GetDetails(split_nof);
|
||||
|
||||
// Invalidate a transition target at |key|.
|
||||
Map* maybe_transition = TransitionArray::SearchTransition(
|
||||
*split_map, split_details.kind(), GetKey(split_nof),
|
||||
split_details.attributes());
|
||||
if (maybe_transition != NULL) {
|
||||
maybe_transition->DeprecateTransitionTree();
|
||||
}
|
||||
|
||||
// If |maybe_transition| is not NULL 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.
|
||||
if (maybe_transition == NULL &&
|
||||
!TransitionArray::CanHaveMoreTransitions(split_map)) {
|
||||
return CopyGeneralizeAllRepresentations("GenAll_CantHaveMoreTransitions");
|
||||
}
|
||||
|
||||
old_map_->NotifyLeafMapLayoutChange();
|
||||
|
||||
if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
|
||||
PropertyDetails old_details =
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
PropertyDetails new_details =
|
||||
new_descriptors->GetDetails(modified_descriptor_);
|
||||
MaybeHandle<FieldType> old_field_type;
|
||||
MaybeHandle<FieldType> new_field_type;
|
||||
MaybeHandle<Object> old_value;
|
||||
MaybeHandle<Object> new_value;
|
||||
if (old_details.type() == DATA) {
|
||||
old_field_type = handle(
|
||||
old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
|
||||
} else {
|
||||
old_value =
|
||||
handle(old_descriptors_->GetValue(modified_descriptor_), isolate_);
|
||||
}
|
||||
if (new_details.type() == DATA) {
|
||||
new_field_type =
|
||||
handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
|
||||
} else {
|
||||
new_value =
|
||||
handle(new_descriptors->GetValue(modified_descriptor_), isolate_);
|
||||
}
|
||||
|
||||
old_map_->PrintGeneralization(
|
||||
stdout, "", modified_descriptor_, split_nof, old_nof_,
|
||||
old_details.location() == kDescriptor && new_location_ == kField,
|
||||
old_details.representation(), new_details.representation(),
|
||||
old_field_type, old_value, new_field_type, new_value);
|
||||
}
|
||||
|
||||
Handle<LayoutDescriptor> new_layout_descriptor =
|
||||
LayoutDescriptor::New(split_map, new_descriptors, old_nof_);
|
||||
|
||||
Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors,
|
||||
new_layout_descriptor);
|
||||
|
||||
// Deprecated part of the transition tree is no longer reachable, so replace
|
||||
// current instance descriptors in the "survived" part of the tree with
|
||||
// the new descriptors to maintain descriptors sharing invariant.
|
||||
split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
|
||||
|
||||
result_map_ = new_map;
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
173
src/map-updater.h
Normal file
173
src/map-updater.h
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_MAP_RECONFIGURER_H_
|
||||
#define V8_MAP_RECONFIGURER_H_
|
||||
|
||||
#include "src/elements-kind.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/property-details.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The |MapUpdater| class implements all sorts of map reconfigurations
|
||||
// including changes of elements kind, property attributes, property kind,
|
||||
// property location and field representations/type changes. It ensures that
|
||||
// the reconfigured map and all the intermediate maps are properly integrated
|
||||
// into the exising transition tree.
|
||||
//
|
||||
// To avoid high degrees over polymorphism, and to stabilize quickly, on every
|
||||
// rewrite the new type is deduced by merging the current type with any
|
||||
// potential new (partial) version of the type in the transition tree.
|
||||
// To do this, on each rewrite:
|
||||
// - Search the root of the transition tree using FindRootMap.
|
||||
// - Find/create a |root_map| with requested |new_elements_kind|.
|
||||
// - Find |target_map|, the newest matching version of this map using the
|
||||
// "updated" |old_map|'s descriptor array (i.e. whose entry at |modify_index|
|
||||
// is considered to be of |new_kind| and having |new_attributes|) to walk
|
||||
// the transition tree.
|
||||
// - Merge/generalize the "updated" descriptor array of the |old_map| and
|
||||
// descriptor array of the |target_map|.
|
||||
// - Generalize the |modify_index| descriptor using |new_representation| and
|
||||
// |new_field_type|.
|
||||
// - Walk the tree again starting from the root towards |target_map|. Stop at
|
||||
// |split_map|, the first map who's descriptor array does not match the merged
|
||||
// descriptor array.
|
||||
// - If |target_map| == |split_map|, |target_map| is in the expected state.
|
||||
// Return it.
|
||||
// - Otherwise, invalidate the outdated transition target from |target_map|, and
|
||||
// replace its transition tree with a new branch for the updated descriptors.
|
||||
class MapUpdater {
|
||||
public:
|
||||
MapUpdater(Isolate* isolate, Handle<Map> old_map)
|
||||
: isolate_(isolate),
|
||||
old_map_(old_map),
|
||||
old_descriptors_(old_map->instance_descriptors(), isolate_),
|
||||
old_nof_(old_map_->NumberOfOwnDescriptors()),
|
||||
new_elements_kind_(old_map_->elements_kind()) {}
|
||||
|
||||
// Prepares for reconfiguring of a property at |descriptor| to data field
|
||||
// with given |attributes| and |representation|/|field_type| and
|
||||
// performs the steps 1-5.
|
||||
Handle<Map> ReconfigureToDataField(int descriptor,
|
||||
PropertyAttributes attributes,
|
||||
Representation representation,
|
||||
Handle<FieldType> field_type);
|
||||
|
||||
// Prepares for reconfiguring elements kind and performs the steps 1-5.
|
||||
Handle<Map> ReconfigureElementsKind(ElementsKind elements_kind);
|
||||
|
||||
// Prepares for updating deprecated map to most up-to-date non-deprecated
|
||||
// version and performs the steps 1-5.
|
||||
Handle<Map> Update();
|
||||
|
||||
private:
|
||||
enum State { kInitialized, kAtRootMap, kAtTargetMap, kEnd };
|
||||
|
||||
// Try to reconfigure property in-place without rebuilding transition tree
|
||||
// and creating new maps. See implementation for details.
|
||||
State TryRecofigureToDataFieldInplace();
|
||||
|
||||
// Step 1.
|
||||
// - Search the root of the transition tree using FindRootMap.
|
||||
// - Find/create a |root_map_| with requested |new_elements_kind_|.
|
||||
State FindRootMap();
|
||||
|
||||
// Step 2.
|
||||
// - Find |target_map_|, the newest matching version of this map using the
|
||||
// "updated" |old_map|'s descriptor array (i.e. whose entry at
|
||||
// |modified_descriptor_| is considered to be of |new_kind| and having
|
||||
// |new_attributes|) to walk the transition tree.
|
||||
State FindTargetMap();
|
||||
|
||||
// Step 3.
|
||||
// - Merge/generalize the "updated" descriptor array of the |old_map_| and
|
||||
// descriptor array of the |target_map_|.
|
||||
// - Generalize the |modified_descriptor_| using |new_representation| and
|
||||
// |new_field_type_|.
|
||||
Handle<DescriptorArray> BuildDescriptorArray();
|
||||
|
||||
// Step 4.
|
||||
// - Walk the tree again starting from the root towards |target_map|. Stop at
|
||||
// |split_map|, the first map who's descriptor array does not match the
|
||||
// merged descriptor array.
|
||||
Handle<Map> FindSplitMap(Handle<DescriptorArray> descriptors);
|
||||
|
||||
// Step 5.
|
||||
// - If |target_map| == |split_map|, |target_map| is in the expected state.
|
||||
// Return it.
|
||||
// - Otherwise, invalidate the outdated transition target from |target_map|,
|
||||
// and replace its transition tree with a new branch for the updated
|
||||
// descriptors.
|
||||
State ConstructNewMap();
|
||||
|
||||
// When a requested reconfiguration can not be done the result is a copy
|
||||
// of |old_map_| where every field has |Tagged| representation and |Any|
|
||||
// field type. This map is disconnected from the transition tree.
|
||||
State CopyGeneralizeAllRepresentations(const char* reason);
|
||||
|
||||
// Returns name of a |descriptor| property.
|
||||
inline Name* GetKey(int descriptor) const;
|
||||
|
||||
// Returns property details of a |descriptor| in "updated" |old_descrtiptors_|
|
||||
// array.
|
||||
inline PropertyDetails GetDetails(int descriptor) const;
|
||||
|
||||
// Returns value of a |descriptor| with kDescriptor location in "updated"
|
||||
// |old_descrtiptors_| array.
|
||||
inline Object* GetValue(int descriptor) const;
|
||||
|
||||
// Returns field type for a |descriptor| with kField location in "updated"
|
||||
// |old_descrtiptors_| array.
|
||||
inline FieldType* GetFieldType(int descriptor) const;
|
||||
|
||||
// If a |descriptor| property in "updated" |old_descriptors_| has kField
|
||||
// location then returns it's field type otherwise computes optimal field
|
||||
// type for the descriptor's value and |representation|. The |location|
|
||||
// value must be a pre-fetched location for |descriptor|.
|
||||
inline Handle<FieldType> GetOrComputeFieldType(
|
||||
int descriptor, PropertyLocation location,
|
||||
Representation representation) const;
|
||||
|
||||
// If a |descriptor| property in given |descriptors| array has kField
|
||||
// location then returns it's field type otherwise computes optimal field
|
||||
// type for the descriptor's value and |representation|.
|
||||
// The |location| value must be a pre-fetched location for |descriptor|.
|
||||
inline Handle<FieldType> GetOrComputeFieldType(
|
||||
Handle<DescriptorArray> descriptors, int descriptor,
|
||||
PropertyLocation location, Representation representation);
|
||||
|
||||
Isolate* isolate_;
|
||||
Handle<Map> old_map_;
|
||||
Handle<DescriptorArray> old_descriptors_;
|
||||
Handle<Map> root_map_;
|
||||
Handle<Map> target_map_;
|
||||
Handle<Map> result_map_;
|
||||
int old_nof_;
|
||||
|
||||
State state_ = kInitialized;
|
||||
ElementsKind new_elements_kind_;
|
||||
|
||||
// If |modified_descriptor_| is not equal to -1 them the fields below form
|
||||
// an "update" of the |old_map_|'s descriptors.
|
||||
int modified_descriptor_ = -1;
|
||||
PropertyKind new_kind_ = kData;
|
||||
PropertyAttributes new_attributes_ = NONE;
|
||||
PropertyLocation new_location_ = kField;
|
||||
Representation new_representation_ = Representation::None();
|
||||
|
||||
// Data specific to kField location.
|
||||
Handle<FieldType> new_field_type_;
|
||||
|
||||
// Data specific to kDescriptor location.
|
||||
Handle<Object> new_value_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_MAP_RECONFIGURER_H_
|
@ -3040,26 +3040,6 @@ FixedArrayBase* Map::GetInitialElements() {
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
|
||||
PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type,
|
||||
StoreMode store_mode) {
|
||||
return Reconfigure(map, map->elements_kind(), modify_index, new_kind,
|
||||
new_attributes, new_representation, new_field_type,
|
||||
store_mode);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
|
||||
ElementsKind new_elements_kind) {
|
||||
return Reconfigure(map, new_elements_kind, -1, kData, NONE,
|
||||
Representation::None(), FieldType::None(map->GetIsolate()),
|
||||
ALLOW_IN_DESCRIPTOR);
|
||||
}
|
||||
|
||||
Object** DescriptorArray::GetKeySlot(int descriptor_number) {
|
||||
DCHECK(descriptor_number < number_of_descriptors());
|
||||
return RawFieldOfElementAt(ToKeyIndex(descriptor_number));
|
||||
|
665
src/objects.cc
665
src/objects.cc
@ -49,6 +49,7 @@
|
||||
#include "src/log.h"
|
||||
#include "src/lookup.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/map-updater.h"
|
||||
#include "src/messages.h"
|
||||
#include "src/objects-body-descriptors-inl.h"
|
||||
#include "src/property-descriptor.h"
|
||||
@ -3326,7 +3327,7 @@ Context* JSReceiver::GetCreationContext() {
|
||||
return function->context()->native_context();
|
||||
}
|
||||
|
||||
static Handle<Object> WrapType(Handle<FieldType> type) {
|
||||
Handle<Object> Map::WrapType(Handle<FieldType> type) {
|
||||
if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
|
||||
return type;
|
||||
}
|
||||
@ -3969,13 +3970,6 @@ void Map::DeprecateTransitionTree() {
|
||||
}
|
||||
|
||||
|
||||
static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
|
||||
if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
|
||||
// TODO(ishell): compare AccessorPairs.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Installs |new_descriptors| over the current instance_descriptors to ensure
|
||||
// proper sharing of descriptor arrays.
|
||||
void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
|
||||
@ -4018,47 +4012,6 @@ Map* Map::FindRootMap() {
|
||||
}
|
||||
|
||||
|
||||
Map* Map::FindLastMatchMap(int verbatim,
|
||||
int length,
|
||||
DescriptorArray* descriptors) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
|
||||
// This can only be called on roots of transition trees.
|
||||
DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
|
||||
|
||||
Map* current = this;
|
||||
|
||||
for (int i = verbatim; i < length; i++) {
|
||||
Name* name = descriptors->GetKey(i);
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
|
||||
details.attributes());
|
||||
if (next == NULL) break;
|
||||
DescriptorArray* next_descriptors = next->instance_descriptors();
|
||||
|
||||
PropertyDetails next_details = next_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(details.kind(), next_details.kind());
|
||||
DCHECK_EQ(details.attributes(), next_details.attributes());
|
||||
if (details.location() != next_details.location()) break;
|
||||
if (!details.representation().Equals(next_details.representation())) break;
|
||||
|
||||
if (next_details.location() == kField) {
|
||||
FieldType* next_field_type = next_descriptors->GetFieldType(i);
|
||||
if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!EqualImmutableValues(descriptors->GetValue(i),
|
||||
next_descriptors->GetValue(i))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
Map* Map::FindFieldOwner(int descriptor) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
|
||||
@ -4139,9 +4092,9 @@ Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
|
||||
|
||||
|
||||
// static
|
||||
void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type) {
|
||||
void Map::GeneralizeField(Handle<Map> map, int modify_index,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type) {
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
|
||||
// Check if we actually need to generalize the field type at all.
|
||||
@ -4156,8 +4109,8 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
|
||||
// Checking old_field_type for being cleared is not necessary because
|
||||
// the NowIs check below would fail anyway in that case.
|
||||
new_field_type->NowIs(old_field_type)) {
|
||||
DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
|
||||
new_representation, new_field_type, isolate)
|
||||
DCHECK(GeneralizeFieldType(old_representation, old_field_type,
|
||||
new_representation, new_field_type, isolate)
|
||||
->NowIs(old_field_type));
|
||||
return;
|
||||
}
|
||||
@ -4190,579 +4143,41 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
|
||||
}
|
||||
}
|
||||
|
||||
static inline Handle<FieldType> GetFieldType(
|
||||
Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
|
||||
PropertyLocation location, Representation representation) {
|
||||
#ifdef DEBUG
|
||||
PropertyDetails details = descriptors->GetDetails(descriptor);
|
||||
DCHECK_EQ(kData, details.kind());
|
||||
DCHECK_EQ(details.location(), location);
|
||||
#endif
|
||||
if (location == kField) {
|
||||
return handle(descriptors->GetFieldType(descriptor), isolate);
|
||||
} else {
|
||||
return descriptors->GetValue(descriptor)
|
||||
->OptimalType(isolate, representation);
|
||||
}
|
||||
// TODO(ishell): remove.
|
||||
// static
|
||||
Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
|
||||
PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type,
|
||||
StoreMode store_mode) {
|
||||
DCHECK_EQ(kData, new_kind); // Only kData case is supported.
|
||||
MapUpdater mu(map->GetIsolate(), map);
|
||||
return mu.ReconfigureToDataField(modify_index, new_attributes,
|
||||
new_representation, new_field_type);
|
||||
}
|
||||
|
||||
// Reconfigures elements kind to |new_elements_kind| and/or property at
|
||||
// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
|
||||
// |new_representation|/|new_field_type|.
|
||||
// If |modify_index| is negative then no properties are reconfigured but the
|
||||
// map is migrated to the up-to-date non-deprecated state.
|
||||
//
|
||||
// This method rewrites or completes the transition tree to reflect the new
|
||||
// change. To avoid high degrees over polymorphism, and to stabilize quickly,
|
||||
// on every rewrite the new type is deduced by merging the current type with
|
||||
// any potential new (partial) version of the type in the transition tree.
|
||||
// To do this, on each rewrite:
|
||||
// - Search the root of the transition tree using FindRootMap.
|
||||
// - Find/create a |root_map| with requested |new_elements_kind|.
|
||||
// - Find |target_map|, the newest matching version of this map using the
|
||||
// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
|
||||
// |modify_index| is considered to be of |new_kind| and having
|
||||
// |new_attributes|) to walk the transition tree.
|
||||
// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
|
||||
// descriptor array of the |target_map|.
|
||||
// - Generalize the |modify_index| descriptor using |new_representation| and
|
||||
// |new_field_type|.
|
||||
// - Walk the tree again starting from the root towards |target_map|. Stop at
|
||||
// |split_map|, the first map who's descriptor array does not match the merged
|
||||
// descriptor array.
|
||||
// - If |target_map| == |split_map|, |target_map| is in the expected state.
|
||||
// Return it.
|
||||
// - Otherwise, invalidate the outdated transition target from |target_map|, and
|
||||
// replace its transition tree with a new branch for the updated descriptors.
|
||||
Handle<Map> Map::Reconfigure(Handle<Map> old_map,
|
||||
ElementsKind new_elements_kind, int modify_index,
|
||||
PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type,
|
||||
StoreMode store_mode) {
|
||||
DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
|
||||
DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
|
||||
Isolate* isolate = old_map->GetIsolate();
|
||||
|
||||
Handle<DescriptorArray> old_descriptors(
|
||||
old_map->instance_descriptors(), isolate);
|
||||
int old_nof = old_map->NumberOfOwnDescriptors();
|
||||
|
||||
// If it's just a representation generalization case (i.e. property kind and
|
||||
// attributes stays unchanged) it's fine to transition from None to anything
|
||||
// but double without any modification to the object, because the default
|
||||
// uninitialized value for representation None can be overwritten by both
|
||||
// smi and tagged values. Doubles, however, would require a box allocation.
|
||||
if (modify_index >= 0 && !new_representation.IsNone() &&
|
||||
!new_representation.IsDouble() &&
|
||||
old_map->elements_kind() == new_elements_kind) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
||||
Representation old_representation = old_details.representation();
|
||||
|
||||
if (old_representation.IsNone()) {
|
||||
DCHECK_EQ(new_kind, old_details.kind());
|
||||
DCHECK_EQ(new_attributes, old_details.attributes());
|
||||
DCHECK_EQ(DATA, old_details.type());
|
||||
if (FLAG_trace_generalization) {
|
||||
old_map->PrintGeneralization(
|
||||
stdout, "uninitialized field", modify_index,
|
||||
old_map->NumberOfOwnDescriptors(),
|
||||
old_map->NumberOfOwnDescriptors(), false, old_representation,
|
||||
new_representation,
|
||||
handle(old_descriptors->GetFieldType(modify_index), isolate),
|
||||
MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
|
||||
}
|
||||
Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
|
||||
|
||||
GeneralizeFieldType(field_owner, modify_index, new_representation,
|
||||
new_field_type);
|
||||
DCHECK(old_descriptors->GetDetails(modify_index)
|
||||
.representation()
|
||||
.Equals(new_representation));
|
||||
DCHECK(
|
||||
old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
|
||||
return old_map;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the state of the root map.
|
||||
Handle<Map> root_map(old_map->FindRootMap(), isolate);
|
||||
if (!old_map->EquivalentToForTransition(*root_map)) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, new_elements_kind, modify_index, store_mode, new_kind,
|
||||
new_attributes, "GenAll_NotEquivalent");
|
||||
}
|
||||
|
||||
ElementsKind from_kind = root_map->elements_kind();
|
||||
ElementsKind to_kind = new_elements_kind;
|
||||
// TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
|
||||
if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
|
||||
to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
|
||||
to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
|
||||
!(IsTransitionableFastElementsKind(from_kind) &&
|
||||
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"GenAll_InvalidElementsTransition");
|
||||
}
|
||||
int root_nof = root_map->NumberOfOwnDescriptors();
|
||||
if (modify_index >= 0 && modify_index < root_nof) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
||||
if (old_details.kind() != new_kind ||
|
||||
old_details.attributes() != new_attributes) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"GenAll_RootModification1");
|
||||
}
|
||||
if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
|
||||
(old_details.type() == DATA &&
|
||||
(!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
|
||||
!new_representation.fits_into(old_details.representation())))) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"GenAll_RootModification2");
|
||||
}
|
||||
}
|
||||
|
||||
// From here on, use the map with correct elements kind as root map.
|
||||
if (from_kind != to_kind) {
|
||||
root_map = Map::AsElementsKind(root_map, to_kind);
|
||||
}
|
||||
|
||||
Handle<Map> target_map = root_map;
|
||||
for (int i = root_nof; i < old_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
PropertyKind next_kind;
|
||||
PropertyLocation next_location;
|
||||
PropertyAttributes next_attributes;
|
||||
Representation next_representation;
|
||||
bool property_kind_reconfiguration = false;
|
||||
|
||||
if (modify_index == i) {
|
||||
DCHECK_EQ(FORCE_FIELD, store_mode);
|
||||
property_kind_reconfiguration = old_details.kind() != new_kind;
|
||||
|
||||
next_kind = new_kind;
|
||||
next_location = kField;
|
||||
next_attributes = new_attributes;
|
||||
// If property kind is not reconfigured merge the result with
|
||||
// representation/field type from the old descriptor.
|
||||
next_representation = new_representation;
|
||||
if (!property_kind_reconfiguration) {
|
||||
next_representation =
|
||||
next_representation.generalize(old_details.representation());
|
||||
}
|
||||
|
||||
} else {
|
||||
next_kind = old_details.kind();
|
||||
next_location = old_details.location();
|
||||
next_attributes = old_details.attributes();
|
||||
next_representation = old_details.representation();
|
||||
}
|
||||
Map* transition = TransitionArray::SearchTransition(
|
||||
*target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
|
||||
if (transition == NULL) break;
|
||||
Handle<Map> tmp_map(transition, isolate);
|
||||
|
||||
Handle<DescriptorArray> tmp_descriptors = handle(
|
||||
tmp_map->instance_descriptors(), isolate);
|
||||
|
||||
// Check if target map is incompatible.
|
||||
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(next_kind, tmp_details.kind());
|
||||
DCHECK_EQ(next_attributes, tmp_details.attributes());
|
||||
if (next_kind == kAccessor &&
|
||||
!EqualImmutableValues(old_descriptors->GetValue(i),
|
||||
tmp_descriptors->GetValue(i))) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"GenAll_Incompatible");
|
||||
}
|
||||
if (next_location == kField && tmp_details.location() == kDescriptor) break;
|
||||
|
||||
Representation tmp_representation = tmp_details.representation();
|
||||
if (!next_representation.fits_into(tmp_representation)) break;
|
||||
|
||||
PropertyLocation old_location = old_details.location();
|
||||
PropertyLocation tmp_location = tmp_details.location();
|
||||
if (tmp_location == kField) {
|
||||
if (next_kind == kData) {
|
||||
Handle<FieldType> next_field_type;
|
||||
if (modify_index == i) {
|
||||
next_field_type = new_field_type;
|
||||
if (!property_kind_reconfiguration) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i,
|
||||
old_details.location(), tmp_representation);
|
||||
Representation old_representation = old_details.representation();
|
||||
next_field_type = GeneralizeFieldType(
|
||||
old_representation, old_field_type, new_representation,
|
||||
next_field_type, isolate);
|
||||
}
|
||||
} else {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
||||
tmp_representation);
|
||||
next_field_type = old_field_type;
|
||||
}
|
||||
GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
|
||||
}
|
||||
} else if (old_location == kField ||
|
||||
!EqualImmutableValues(old_descriptors->GetValue(i),
|
||||
tmp_descriptors->GetValue(i))) {
|
||||
break;
|
||||
}
|
||||
DCHECK(!tmp_map->is_deprecated());
|
||||
target_map = tmp_map;
|
||||
}
|
||||
|
||||
// Directly change the map if the target map is more general.
|
||||
Handle<DescriptorArray> target_descriptors(
|
||||
target_map->instance_descriptors(), isolate);
|
||||
int target_nof = target_map->NumberOfOwnDescriptors();
|
||||
if (target_nof == old_nof &&
|
||||
(store_mode != FORCE_FIELD ||
|
||||
(modify_index >= 0 &&
|
||||
target_descriptors->GetDetails(modify_index).location() == kField))) {
|
||||
#ifdef DEBUG
|
||||
if (modify_index >= 0) {
|
||||
PropertyDetails details = target_descriptors->GetDetails(modify_index);
|
||||
DCHECK_EQ(new_kind, details.kind());
|
||||
DCHECK_EQ(new_attributes, details.attributes());
|
||||
DCHECK(new_representation.fits_into(details.representation()));
|
||||
DCHECK(details.location() != kField ||
|
||||
new_field_type->NowIs(
|
||||
target_descriptors->GetFieldType(modify_index)));
|
||||
}
|
||||
#endif
|
||||
if (*target_map != *old_map) {
|
||||
old_map->NotifyLeafMapLayoutChange();
|
||||
}
|
||||
return target_map;
|
||||
}
|
||||
|
||||
// Find the last compatible target map in the transition tree.
|
||||
for (int i = target_nof; i < old_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
PropertyKind next_kind;
|
||||
PropertyAttributes next_attributes;
|
||||
if (modify_index == i) {
|
||||
next_kind = new_kind;
|
||||
next_attributes = new_attributes;
|
||||
} else {
|
||||
next_kind = old_details.kind();
|
||||
next_attributes = old_details.attributes();
|
||||
}
|
||||
Map* transition = TransitionArray::SearchTransition(
|
||||
*target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
|
||||
if (transition == NULL) break;
|
||||
Handle<Map> tmp_map(transition, isolate);
|
||||
Handle<DescriptorArray> tmp_descriptors(
|
||||
tmp_map->instance_descriptors(), isolate);
|
||||
|
||||
// Check if target map is compatible.
|
||||
#ifdef DEBUG
|
||||
PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
||||
DCHECK_EQ(next_kind, tmp_details.kind());
|
||||
DCHECK_EQ(next_attributes, tmp_details.attributes());
|
||||
#endif
|
||||
if (next_kind == kAccessor &&
|
||||
!EqualImmutableValues(old_descriptors->GetValue(i),
|
||||
tmp_descriptors->GetValue(i))) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"GenAll_Incompatible");
|
||||
}
|
||||
DCHECK(!tmp_map->is_deprecated());
|
||||
target_map = tmp_map;
|
||||
}
|
||||
target_nof = target_map->NumberOfOwnDescriptors();
|
||||
target_descriptors = handle(target_map->instance_descriptors(), isolate);
|
||||
|
||||
// Allocate a new descriptor array large enough to hold the required
|
||||
// descriptors, with minimally the exact same size as the old descriptor
|
||||
// array.
|
||||
int new_slack = Max(
|
||||
old_nof, old_descriptors->number_of_descriptors()) - old_nof;
|
||||
Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
|
||||
isolate, old_nof, new_slack);
|
||||
DCHECK(new_descriptors->length() > target_descriptors->length() ||
|
||||
new_descriptors->NumberOfSlackDescriptors() > 0 ||
|
||||
new_descriptors->number_of_descriptors() ==
|
||||
old_descriptors->number_of_descriptors());
|
||||
DCHECK(new_descriptors->number_of_descriptors() == old_nof);
|
||||
|
||||
// 0 -> |root_nof|
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < root_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
if (old_details.location() == kField) {
|
||||
current_offset += old_details.field_width_in_words();
|
||||
}
|
||||
Descriptor d(handle(old_descriptors->GetKey(i), isolate),
|
||||
handle(old_descriptors->GetValue(i), isolate),
|
||||
old_details);
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
|
||||
// |root_nof| -> |target_nof|
|
||||
for (int i = root_nof; i < target_nof; ++i) {
|
||||
Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
PropertyDetails target_details = target_descriptors->GetDetails(i);
|
||||
|
||||
PropertyKind next_kind;
|
||||
PropertyAttributes next_attributes;
|
||||
PropertyLocation next_location;
|
||||
Representation next_representation;
|
||||
bool property_kind_reconfiguration = false;
|
||||
|
||||
if (modify_index == i) {
|
||||
DCHECK_EQ(FORCE_FIELD, store_mode);
|
||||
property_kind_reconfiguration = old_details.kind() != new_kind;
|
||||
|
||||
next_kind = new_kind;
|
||||
next_attributes = new_attributes;
|
||||
next_location = kField;
|
||||
|
||||
// Merge new representation/field type with ones from the target
|
||||
// descriptor. If property kind is not reconfigured merge the result with
|
||||
// representation/field type from the old descriptor.
|
||||
next_representation =
|
||||
new_representation.generalize(target_details.representation());
|
||||
if (!property_kind_reconfiguration) {
|
||||
next_representation =
|
||||
next_representation.generalize(old_details.representation());
|
||||
}
|
||||
} else {
|
||||
// Merge old_descriptor and target_descriptor entries.
|
||||
DCHECK_EQ(target_details.kind(), old_details.kind());
|
||||
next_kind = target_details.kind();
|
||||
next_attributes = target_details.attributes();
|
||||
next_location =
|
||||
old_details.location() == kField ||
|
||||
target_details.location() == kField ||
|
||||
!EqualImmutableValues(target_descriptors->GetValue(i),
|
||||
old_descriptors->GetValue(i))
|
||||
? kField
|
||||
: kDescriptor;
|
||||
|
||||
next_representation = old_details.representation().generalize(
|
||||
target_details.representation());
|
||||
}
|
||||
DCHECK_EQ(next_kind, target_details.kind());
|
||||
DCHECK_EQ(next_attributes, target_details.attributes());
|
||||
|
||||
if (next_location == kField) {
|
||||
if (next_kind == kData) {
|
||||
Handle<FieldType> target_field_type =
|
||||
GetFieldType(isolate, target_descriptors, i,
|
||||
target_details.location(), next_representation);
|
||||
|
||||
Handle<FieldType> next_field_type;
|
||||
if (modify_index == i) {
|
||||
next_field_type = GeneralizeFieldType(
|
||||
target_details.representation(), target_field_type,
|
||||
new_representation, new_field_type, isolate);
|
||||
if (!property_kind_reconfiguration) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i,
|
||||
old_details.location(), next_representation);
|
||||
next_field_type = GeneralizeFieldType(
|
||||
old_details.representation(), old_field_type,
|
||||
next_representation, next_field_type, isolate);
|
||||
}
|
||||
} else {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
||||
next_representation);
|
||||
next_field_type = GeneralizeFieldType(
|
||||
old_details.representation(), old_field_type, next_representation,
|
||||
target_field_type, isolate);
|
||||
}
|
||||
Handle<Object> wrapped_type(WrapType(next_field_type));
|
||||
Descriptor d =
|
||||
Descriptor::DataField(target_key, current_offset, wrapped_type,
|
||||
next_attributes, next_representation);
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
UNIMPLEMENTED(); // TODO(ishell): implement.
|
||||
}
|
||||
} else {
|
||||
PropertyDetails details(next_attributes, next_kind, next_location,
|
||||
next_representation);
|
||||
Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
|
||||
details);
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
}
|
||||
|
||||
// |target_nof| -> |old_nof|
|
||||
for (int i = target_nof; i < old_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
|
||||
|
||||
// Merge old_descriptor entry and modified details together.
|
||||
PropertyKind next_kind;
|
||||
PropertyAttributes next_attributes;
|
||||
PropertyLocation next_location;
|
||||
Representation next_representation;
|
||||
bool property_kind_reconfiguration = false;
|
||||
|
||||
if (modify_index == i) {
|
||||
DCHECK_EQ(FORCE_FIELD, store_mode);
|
||||
// In case of property kind reconfiguration it is not necessary to
|
||||
// take into account representation/field type of the old descriptor.
|
||||
property_kind_reconfiguration = old_details.kind() != new_kind;
|
||||
|
||||
next_kind = new_kind;
|
||||
next_attributes = new_attributes;
|
||||
next_location = kField;
|
||||
next_representation = new_representation;
|
||||
if (!property_kind_reconfiguration) {
|
||||
next_representation =
|
||||
next_representation.generalize(old_details.representation());
|
||||
}
|
||||
} else {
|
||||
next_kind = old_details.kind();
|
||||
next_attributes = old_details.attributes();
|
||||
next_location = old_details.location();
|
||||
next_representation = old_details.representation();
|
||||
}
|
||||
|
||||
if (next_location == kField) {
|
||||
if (next_kind == kData) {
|
||||
Handle<FieldType> next_field_type;
|
||||
if (modify_index == i) {
|
||||
next_field_type = new_field_type;
|
||||
if (!property_kind_reconfiguration) {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i,
|
||||
old_details.location(), next_representation);
|
||||
next_field_type = GeneralizeFieldType(
|
||||
old_details.representation(), old_field_type,
|
||||
next_representation, next_field_type, isolate);
|
||||
}
|
||||
} else {
|
||||
Handle<FieldType> old_field_type =
|
||||
GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
||||
next_representation);
|
||||
next_field_type = old_field_type;
|
||||
}
|
||||
|
||||
Handle<Object> wrapped_type(WrapType(next_field_type));
|
||||
|
||||
Descriptor d =
|
||||
Descriptor::DataField(old_key, current_offset, wrapped_type,
|
||||
next_attributes, next_representation);
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
UNIMPLEMENTED(); // TODO(ishell): implement.
|
||||
}
|
||||
} else {
|
||||
PropertyDetails details(next_attributes, next_kind, next_location,
|
||||
next_representation);
|
||||
Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
|
||||
details);
|
||||
new_descriptors->Set(i, &d);
|
||||
}
|
||||
}
|
||||
|
||||
new_descriptors->Sort();
|
||||
|
||||
DCHECK(store_mode != FORCE_FIELD ||
|
||||
new_descriptors->GetDetails(modify_index).location() == kField);
|
||||
|
||||
Handle<Map> split_map(root_map->FindLastMatchMap(
|
||||
root_nof, old_nof, *new_descriptors), isolate);
|
||||
int split_nof = split_map->NumberOfOwnDescriptors();
|
||||
DCHECK_NE(old_nof, split_nof);
|
||||
|
||||
PropertyKind split_kind;
|
||||
PropertyAttributes split_attributes;
|
||||
if (modify_index == split_nof) {
|
||||
split_kind = new_kind;
|
||||
split_attributes = new_attributes;
|
||||
} else {
|
||||
PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
|
||||
split_kind = split_prop_details.kind();
|
||||
split_attributes = split_prop_details.attributes();
|
||||
}
|
||||
|
||||
// Invalidate a transition target at |key|.
|
||||
Map* maybe_transition = TransitionArray::SearchTransition(
|
||||
*split_map, split_kind, old_descriptors->GetKey(split_nof),
|
||||
split_attributes);
|
||||
if (maybe_transition != NULL) {
|
||||
maybe_transition->DeprecateTransitionTree();
|
||||
}
|
||||
|
||||
// If |maybe_transition| is not NULL 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.
|
||||
if (maybe_transition == NULL &&
|
||||
!TransitionArray::CanHaveMoreTransitions(split_map)) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
||||
"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);
|
||||
MaybeHandle<FieldType> old_field_type;
|
||||
MaybeHandle<FieldType> new_field_type;
|
||||
MaybeHandle<Object> old_value;
|
||||
MaybeHandle<Object> new_value;
|
||||
if (old_details.type() == DATA) {
|
||||
old_field_type =
|
||||
handle(old_descriptors->GetFieldType(modify_index), isolate);
|
||||
} else {
|
||||
old_value = handle(old_descriptors->GetValue(modify_index), isolate);
|
||||
}
|
||||
if (new_details.type() == DATA) {
|
||||
new_field_type =
|
||||
handle(new_descriptors->GetFieldType(modify_index), isolate);
|
||||
} else {
|
||||
new_value = handle(new_descriptors->GetValue(modify_index), isolate);
|
||||
}
|
||||
|
||||
old_map->PrintGeneralization(
|
||||
stdout, "", modify_index, split_nof, old_nof,
|
||||
old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
|
||||
old_details.representation(), new_details.representation(),
|
||||
old_field_type, old_value, new_field_type, new_value);
|
||||
}
|
||||
|
||||
Handle<LayoutDescriptor> new_layout_descriptor =
|
||||
LayoutDescriptor::New(split_map, new_descriptors, old_nof);
|
||||
|
||||
Handle<Map> new_map =
|
||||
AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
|
||||
|
||||
// Deprecated part of the transition tree is no longer reachable, so replace
|
||||
// current instance descriptors in the "survived" part of the tree with
|
||||
// the new descriptors to maintain descriptors sharing invariant.
|
||||
split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
|
||||
return new_map;
|
||||
// TODO(ishell): remove.
|
||||
// static
|
||||
Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
|
||||
ElementsKind new_elements_kind) {
|
||||
MapUpdater mu(map->GetIsolate(), map);
|
||||
return mu.ReconfigureElementsKind(new_elements_kind);
|
||||
}
|
||||
|
||||
|
||||
// Generalize the representation of all DATA descriptors.
|
||||
Handle<Map> Map::GeneralizeAllFieldRepresentations(
|
||||
Handle<Map> map) {
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<DescriptorArray> descriptors(map->instance_descriptors());
|
||||
for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.type() == DATA) {
|
||||
map = ReconfigureProperty(map, i, kData, details.attributes(),
|
||||
Representation::Tagged(),
|
||||
FieldType::Any(map->GetIsolate()), FORCE_FIELD);
|
||||
MapUpdater mu(isolate, map);
|
||||
map = mu.ReconfigureToDataField(i, details.attributes(),
|
||||
Representation::Tagged(), any_type);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
@ -4869,9 +4284,8 @@ Map* Map::TryReplayPropertyTransitions(Map* old_map) {
|
||||
// static
|
||||
Handle<Map> Map::Update(Handle<Map> map) {
|
||||
if (!map->is_deprecated()) return map;
|
||||
return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
|
||||
FieldType::None(map->GetIsolate()),
|
||||
ALLOW_IN_DESCRIPTOR);
|
||||
MapUpdater mu(map->GetIsolate(), map);
|
||||
return mu.Update();
|
||||
}
|
||||
|
||||
Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
|
||||
@ -9718,8 +9132,9 @@ Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
|
||||
Representation representation = value->OptimalRepresentation();
|
||||
Handle<FieldType> type = value->OptimalType(isolate, representation);
|
||||
|
||||
return Map::ReconfigureProperty(map, descriptor, kData, attributes,
|
||||
representation, type, FORCE_FIELD);
|
||||
MapUpdater mu(isolate, map);
|
||||
return mu.ReconfigureToDataField(descriptor, attributes, representation,
|
||||
type);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -9812,9 +9227,11 @@ Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
|
||||
}
|
||||
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
Handle<Map> new_map = ReconfigureProperty(
|
||||
map, descriptor, kind, attributes, Representation::None(),
|
||||
FieldType::None(isolate), FORCE_FIELD);
|
||||
|
||||
MapUpdater mu(isolate, map);
|
||||
DCHECK_EQ(kData, kind); // Only kData case is supported so far.
|
||||
Handle<Map> new_map = mu.ReconfigureToDataField(
|
||||
descriptor, attributes, Representation::None(), FieldType::None(isolate));
|
||||
return new_map;
|
||||
}
|
||||
|
||||
|
@ -6059,17 +6059,19 @@ class Map: public HeapObject {
|
||||
MUST_USE_RESULT static Handle<FieldType> GeneralizeFieldType(
|
||||
Representation rep1, Handle<FieldType> type1, Representation rep2,
|
||||
Handle<FieldType> type2, Isolate* isolate);
|
||||
static void GeneralizeFieldType(Handle<Map> map, int modify_index,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type);
|
||||
static void GeneralizeField(Handle<Map> map, int modify_index,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type);
|
||||
|
||||
static inline Handle<Map> ReconfigureProperty(
|
||||
Handle<Map> map, int modify_index, PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes, Representation new_representation,
|
||||
Handle<FieldType> new_field_type, StoreMode store_mode);
|
||||
static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index,
|
||||
PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type,
|
||||
StoreMode store_mode);
|
||||
|
||||
static inline Handle<Map> ReconfigureElementsKind(
|
||||
Handle<Map> map, ElementsKind new_elements_kind);
|
||||
static Handle<Map> ReconfigureElementsKind(Handle<Map> map,
|
||||
ElementsKind new_elements_kind);
|
||||
|
||||
static Handle<Map> PrepareForDataProperty(Handle<Map> old_map,
|
||||
int descriptor_number,
|
||||
@ -6192,6 +6194,8 @@ class Map: public HeapObject {
|
||||
Descriptor* descriptor,
|
||||
TransitionFlag flag);
|
||||
|
||||
static Handle<Object> WrapType(Handle<FieldType> type);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Map> CopyWithField(
|
||||
Handle<Map> map, Handle<Name> name, Handle<FieldType> type,
|
||||
PropertyAttributes attributes, Representation representation,
|
||||
@ -6504,14 +6508,7 @@ class Map: public HeapObject {
|
||||
static Handle<Map> CopyNormalized(Handle<Map> map,
|
||||
PropertyNormalizationMode mode);
|
||||
|
||||
static Handle<Map> Reconfigure(Handle<Map> map,
|
||||
ElementsKind new_elements_kind,
|
||||
int modify_index, PropertyKind new_kind,
|
||||
PropertyAttributes new_attributes,
|
||||
Representation new_representation,
|
||||
Handle<FieldType> new_field_type,
|
||||
StoreMode store_mode);
|
||||
|
||||
// TODO(ishell): Move to MapUpdater.
|
||||
static Handle<Map> CopyGeneralizeAllRepresentations(
|
||||
Handle<Map> map, ElementsKind elements_kind, int modify_index,
|
||||
StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
|
||||
@ -6528,8 +6525,6 @@ class Map: public HeapObject {
|
||||
LayoutDescriptor* new_layout_descriptor);
|
||||
|
||||
|
||||
Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
|
||||
|
||||
// Update field type of the given descriptor to new representation and new
|
||||
// type. The type must be prepared for storing in descriptor array:
|
||||
// it must be either a simple type or a map wrapped in a weak cell.
|
||||
@ -6537,8 +6532,10 @@ class Map: public HeapObject {
|
||||
Representation new_representation,
|
||||
Handle<Object> new_wrapped_type);
|
||||
|
||||
// TODO(ishell): Move to MapUpdater.
|
||||
void PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
|
||||
PropertyAttributes attributes);
|
||||
// TODO(ishell): Move to MapUpdater.
|
||||
void PrintGeneralization(FILE* file, const char* reason, int modify_index,
|
||||
int split, int descriptors, bool constant_to_field,
|
||||
Representation old_representation,
|
||||
@ -6547,10 +6544,11 @@ class Map: public HeapObject {
|
||||
MaybeHandle<Object> old_value,
|
||||
MaybeHandle<FieldType> new_field_type,
|
||||
MaybeHandle<Object> new_value);
|
||||
|
||||
static const int kFastPropertiesSoftLimit = 12;
|
||||
static const int kMaxFastProperties = 128;
|
||||
|
||||
friend class MapUpdater;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
|
||||
};
|
||||
|
||||
|
@ -254,7 +254,7 @@ class PropertyDetails BASE_EMBEDDED {
|
||||
| FieldIndexField::encode(field_index);
|
||||
}
|
||||
|
||||
PropertyDetails(PropertyAttributes attributes, PropertyKind kind,
|
||||
PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
|
||||
PropertyLocation location, Representation representation,
|
||||
int field_index = 0) {
|
||||
value_ = KindField::encode(kind) | LocationField::encode(location) |
|
||||
|
@ -85,6 +85,7 @@ class Descriptor final BASE_EMBEDDED {
|
||||
|
||||
friend class DescriptorArray;
|
||||
friend class Map;
|
||||
friend class MapUpdater;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Descriptor& d);
|
||||
|
@ -1060,6 +1060,8 @@
|
||||
'lookup-cache.h',
|
||||
'lookup.cc',
|
||||
'lookup.h',
|
||||
'map-updater.cc',
|
||||
'map-updater.h',
|
||||
'macro-assembler.h',
|
||||
'machine-type.cc',
|
||||
'machine-type.h',
|
||||
|
@ -1664,8 +1664,8 @@ Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
|
||||
->NowContains(value)) {
|
||||
Handle<FieldType> value_type =
|
||||
value->OptimalType(isolate_, expected_representation);
|
||||
Map::GeneralizeFieldType(target, descriptor,
|
||||
expected_representation, value_type);
|
||||
Map::GeneralizeField(target, descriptor, expected_representation,
|
||||
value_type);
|
||||
}
|
||||
DCHECK(target->instance_descriptors()
|
||||
->GetFieldType(descriptor)
|
||||
|
Loading…
Reference in New Issue
Block a user