Commit 1dcd8b23 authored by ishell's avatar ishell Committed by Commit bot

[runtime] Add PropertyConstness bit to PropertyDetails.

Currently PropertyConstness is still in sync with PropertyLocation.

BUG=v8:5495

Review-Url: https://codereview.chromium.org/2591233002
Cr-Commit-Position: refs/heads/master@{#42497}
parent a8f28907
......@@ -687,6 +687,7 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
property_details_, *value);
} else {
DCHECK_EQ(kDescriptor, property_details_.location());
DCHECK_EQ(kConst, property_details_.constness());
}
} else if (holder->IsJSGlobalObject()) {
GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary();
......
......@@ -22,10 +22,6 @@ inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
return false;
}
inline bool LocationFitsInto(PropertyLocation what, PropertyLocation where) {
return where == kField || what == kDescriptor;
}
} // namespace
Name* MapUpdater::GetKey(int descriptor) const {
......@@ -36,7 +32,7 @@ PropertyDetails MapUpdater::GetDetails(int descriptor) const {
DCHECK_LE(0, descriptor);
if (descriptor == modified_descriptor_) {
return PropertyDetails(new_kind_, new_attributes_, new_location_,
new_representation_);
new_constness_, new_representation_);
}
return old_descriptors_->GetDetails(descriptor);
}
......@@ -98,8 +94,6 @@ Handle<Map> MapUpdater::ReconfigureToDataField(int 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_);
......@@ -107,16 +101,25 @@ Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
// If property kind is not reconfigured merge the result with
// representation/field type from the old descriptor.
if (old_details.kind() == new_kind_) {
new_constness_ = old_details.constness();
Representation old_representation = old_details.representation();
new_representation_ = new_representation_.generalize(old_representation);
new_representation_ = 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_);
new_field_type_ =
Map::GeneralizeFieldType(old_representation, old_field_type,
new_representation_, field_type, isolate_);
} else {
// We don't know if this is a first property kind reconfiguration
// and we don't know which value was in this property previously
// therefore we can't treat such a property as constant.
new_constness_ = kMutable;
new_representation_ = representation;
new_field_type_ = field_type;
}
if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
......@@ -228,10 +231,11 @@ MapUpdater::State MapUpdater::FindRootMap() {
old_details.attributes() != new_attributes_) {
return CopyGeneralizeAllFields("GenAll_RootModification1");
}
if (!new_representation_.fits_into(old_details.representation())) {
if (old_details.location() != kField) {
return CopyGeneralizeAllFields("GenAll_RootModification2");
}
if (old_details.location() != kField) {
DCHECK_EQ(kMutable, old_details.constness());
if (!new_representation_.fits_into(old_details.representation())) {
return CopyGeneralizeAllFields("GenAll_RootModification3");
}
DCHECK_EQ(kData, old_details.kind());
......@@ -276,8 +280,12 @@ MapUpdater::State MapUpdater::FindTargetMap() {
// TODO(ishell): mutable accessors are not implemented yet.
return CopyGeneralizeAllFields("GenAll_Incompatible");
}
// Check if old constness fits into tmp constness.
if (!IsGeneralizableTo(old_details.constness(), tmp_details.constness())) {
break;
}
// Check if old location fits into tmp location.
if (!LocationFitsInto(old_details.location(), tmp_details.location())) {
if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
break;
}
......@@ -341,7 +349,6 @@ MapUpdater::State MapUpdater::FindTargetMap() {
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);
......@@ -404,6 +411,14 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
PropertyKind next_kind = old_details.kind();
PropertyAttributes next_attributes = old_details.attributes();
DCHECK_EQ(next_kind, target_details.kind());
DCHECK_EQ(next_attributes, target_details.attributes());
PropertyConstness next_constness = GeneralizeConstness(
old_details.constness(), target_details.constness());
// Note: failed values equality check does not invalidate per-object
// property constness.
PropertyLocation next_location =
old_details.location() == kField ||
target_details.location() == kField ||
......@@ -412,13 +427,15 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
? kField
: kDescriptor;
// TODO(ishell): remove once constant field tracking is done.
if (next_location == kField) next_constness = kMutable;
// Ensure that mutable values are stored in fields.
DCHECK_IMPLIES(next_constness == kMutable, next_location == kField);
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);
......@@ -434,8 +451,9 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
Descriptor d;
if (next_kind == kData) {
d = Descriptor::DataField(key, current_offset, wrapped_type,
next_attributes, next_representation);
d = Descriptor::DataField(key, current_offset, next_attributes,
next_constness, next_representation,
wrapped_type);
} else {
// TODO(ishell): mutable accessors are not implemented yet.
UNIMPLEMENTED();
......@@ -444,6 +462,7 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
new_descriptors->Set(i, &d);
} else {
DCHECK_EQ(kDescriptor, next_location);
DCHECK_EQ(kConst, next_constness);
Handle<Object> value(GetValue(i), isolate_);
Descriptor d;
......@@ -465,19 +484,22 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
PropertyKind next_kind = old_details.kind();
PropertyAttributes next_attributes = old_details.attributes();
PropertyConstness next_constness = old_details.constness();
PropertyLocation next_location = old_details.location();
Representation next_representation = old_details.representation();
Descriptor d;
if (next_location == kField) {
DCHECK_EQ(kMutable, next_constness);
Handle<FieldType> old_field_type =
GetOrComputeFieldType(i, old_details.location(), next_representation);
Handle<Object> wrapped_type(Map::WrapFieldType(old_field_type));
Descriptor d;
if (next_kind == kData) {
d = Descriptor::DataField(key, current_offset, wrapped_type,
next_attributes, next_representation);
d = Descriptor::DataField(key, current_offset, next_attributes,
next_constness, next_representation,
wrapped_type);
} else {
// TODO(ishell): mutable accessors are not implemented yet.
UNIMPLEMENTED();
......@@ -486,6 +508,7 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
new_descriptors->Set(i, &d);
} else {
DCHECK_EQ(kDescriptor, next_location);
DCHECK_EQ(kConst, next_constness);
Handle<Object> value(GetValue(i), isolate_);
if (next_kind == kData) {
......@@ -518,6 +541,7 @@ Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
PropertyDetails next_details = next_descriptors->GetDetails(i);
DCHECK_EQ(details.kind(), next_details.kind());
DCHECK_EQ(details.attributes(), next_details.attributes());
if (details.constness() != next_details.constness()) break;
if (details.location() != next_details.location()) break;
if (!details.representation().Equals(next_details.representation())) break;
......
......@@ -157,6 +157,7 @@ class MapUpdater {
int modified_descriptor_ = -1;
PropertyKind new_kind_ = kData;
PropertyAttributes new_attributes_ = NONE;
PropertyConstness new_constness_ = kMutable;
PropertyLocation new_location_ = kField;
Representation new_representation_ = Representation::None();
......
......@@ -3390,8 +3390,8 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
Handle<Object> wrapped_type(WrapFieldType(type));
Descriptor d = Descriptor::DataField(name, index, wrapped_type, attributes,
representation);
Descriptor d = Descriptor::DataField(name, index, attributes, kMutable,
representation, wrapped_type);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
......@@ -4092,8 +4092,8 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
// Skip if already updated the shared descriptor.
if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
Descriptor d = Descriptor::DataField(
name, descriptors->GetFieldIndex(descriptor), new_wrapped_type,
details.attributes(), new_representation);
name, descriptors->GetFieldIndex(descriptor), details.attributes(),
kMutable, new_representation, new_wrapped_type);
descriptors->Replace(descriptor, &d);
}
}
......@@ -4260,6 +4260,10 @@ Map* Map::TryReplayPropertyTransitions(Map* old_map) {
PropertyDetails new_details = new_descriptors->GetDetails(i);
DCHECK_EQ(old_details.kind(), new_details.kind());
DCHECK_EQ(old_details.attributes(), new_details.attributes());
if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
return nullptr;
}
DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
if (!old_details.representation().fits_into(new_details.representation())) {
return nullptr;
}
......@@ -5777,6 +5781,8 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Object* value = dictionary->ValueAt(index);
PropertyDetails details = dictionary->DetailsAt(index);
DCHECK_EQ(kField, details.location());
DCHECK_EQ(kMutable, details.constness());
int enumeration_index = details.dictionary_index();
Descriptor d;
......@@ -9155,6 +9161,7 @@ namespace {
bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
PropertyDetails details = descriptors->GetDetails(descriptor);
if (details.location() == kField) {
DCHECK_EQ(kMutable, details.constness());
if (details.kind() == kData) {
return value->FitsRepresentation(details.representation()) &&
descriptors->GetFieldType(descriptor)->NowContains(value);
......@@ -9166,6 +9173,7 @@ bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
} else {
DCHECK_EQ(kDescriptor, details.location());
DCHECK_EQ(kConst, details.constness());
if (details.kind() == kData) {
DCHECK(descriptors->GetValue(descriptor) != value ||
value->FitsRepresentation(details.representation()));
......
......@@ -72,6 +72,10 @@ enum PropertyKind { kData = 0, kAccessor = 1 };
// Must fit in the BitField PropertyDetails::LocationField.
enum PropertyLocation { kField = 0, kDescriptor = 1 };
// Order of modes is significant.
// Must fit in the BitField PropertyDetails::ConstnessField.
enum PropertyConstness { kMutable = 0, kConst = 1 };
class Representation {
public:
enum Kind {
......@@ -231,10 +235,11 @@ class PropertyDetails BASE_EMBEDDED {
// Property details for fast mode properties.
PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyLocation location, Representation representation,
int field_index = 0) {
value_ = KindField::encode(kind) | LocationField::encode(location) |
AttributesField::encode(attributes) |
PropertyLocation location, PropertyConstness constness,
Representation representation, int field_index = 0) {
value_ = KindField::encode(kind) | AttributesField::encode(attributes) |
LocationField::encode(location) |
ConstnessField::encode(constness) |
RepresentationField::encode(EncodeRepresentation(representation)) |
FieldIndexField::encode(field_index);
}
......@@ -285,6 +290,7 @@ class PropertyDetails BASE_EMBEDDED {
PropertyKind kind() const { return KindField::decode(value_); }
PropertyLocation location() const { return LocationField::decode(value_); }
PropertyConstness constness() const { return ConstnessField::decode(value_); }
PropertyAttributes attributes() const {
return AttributesField::decode(value_);
......@@ -317,22 +323,30 @@ class PropertyDetails BASE_EMBEDDED {
// Bit fields in value_ (type, shift, size). Must be public so the
// constants can be embedded in generated code.
class KindField : public BitField<PropertyKind, 0, 1> {};
class LocationField : public BitField<PropertyLocation, 1, 1> {};
class AttributesField : public BitField<PropertyAttributes, 2, 3> {};
class LocationField : public BitField<PropertyLocation, KindField::kNext, 1> {
};
class ConstnessField
: public BitField<PropertyConstness, LocationField::kNext, 1> {};
class AttributesField
: public BitField<PropertyAttributes, ConstnessField::kNext, 3> {};
static const int kAttributesReadOnlyMask =
(READ_ONLY << AttributesField::kShift);
// Bit fields for normalized objects.
class PropertyCellTypeField : public BitField<PropertyCellType, 5, 2> {};
class DictionaryStorageField : public BitField<uint32_t, 7, 24> {};
class PropertyCellTypeField
: public BitField<PropertyCellType, AttributesField::kNext, 2> {};
class DictionaryStorageField
: public BitField<uint32_t, PropertyCellTypeField::kNext, 23> {};
// Bit fields for fast objects.
class RepresentationField : public BitField<uint32_t, 5, 4> {};
class RepresentationField
: public BitField<uint32_t, AttributesField::kNext, 4> {};
class DescriptorPointer
: public BitField<uint32_t, 9, kDescriptorIndexBitCount> {}; // NOLINT
class FieldIndexField
: public BitField<uint32_t, 9 + kDescriptorIndexBitCount,
: public BitField<uint32_t, RepresentationField::kNext,
kDescriptorIndexBitCount> {}; // NOLINT
class FieldIndexField : public BitField<uint32_t, DescriptorPointer::kNext,
kDescriptorIndexBitCount> {
}; // NOLINT
// All bits for both fast and slow objects must fit in a smi.
STATIC_ASSERT(DictionaryStorageField::kNext <= 31);
......@@ -373,6 +387,22 @@ class PropertyDetails BASE_EMBEDDED {
uint32_t value_;
};
// kField location is more general than kDescriptor, kDescriptor generalizes
// only to itself.
inline bool IsGeneralizableTo(PropertyLocation a, PropertyLocation b) {
return b == kField || a == kDescriptor;
}
// kMutable constness is more general than kConst, kConst generalizes only to
// itself.
inline bool IsGeneralizableTo(PropertyConstness a, PropertyConstness b) {
return b == kMutable || a == kConst;
}
inline PropertyConstness GeneralizeConstness(PropertyConstness a,
PropertyConstness b) {
return a == kMutable ? kMutable : b;
}
std::ostream& operator<<(std::ostream& os,
const PropertyAttributes& attributes);
......
......@@ -25,13 +25,25 @@ std::ostream& operator<<(std::ostream& os,
Descriptor Descriptor::DataField(Handle<Name> key, int field_index,
PropertyAttributes attributes,
Representation representation) {
return DataField(key, field_index, FieldType::Any(key->GetIsolate()),
attributes, representation);
return DataField(key, field_index, attributes, kMutable, representation,
FieldType::Any(key->GetIsolate()));
}
Descriptor Descriptor::DataField(Handle<Name> key, int field_index,
PropertyAttributes attributes,
PropertyConstness constness,
Representation representation,
Handle<Object> wrapped_field_type) {
DCHECK(wrapped_field_type->IsSmi() || wrapped_field_type->IsWeakCell());
PropertyDetails details(kData, attributes, kField, constness, representation,
field_index);
return Descriptor(key, wrapped_field_type, details);
}
// Outputs PropertyDetails as a dictionary details.
void PropertyDetails::PrintAsSlowTo(std::ostream& os) {
os << "(";
if (constness() == kConst) os << "const ";
os << (kind() == kData ? "data" : "accessor");
os << ", dictionary_index: " << dictionary_index();
os << ", attrs: " << attributes() << ")";
......@@ -40,6 +52,7 @@ void PropertyDetails::PrintAsSlowTo(std::ostream& os) {
// Outputs PropertyDetails as a descriptor array details.
void PropertyDetails::PrintAsFastTo(std::ostream& os, PrintMode mode) {
os << "(";
if (constness() == kConst) os << "const ";
os << (kind() == kData ? "data" : "accessor");
if (location() == kField) {
os << " field";
......
......@@ -33,24 +33,21 @@ class Descriptor final BASE_EMBEDDED {
Representation representation);
static Descriptor DataField(Handle<Name> key, int field_index,
Handle<Object> wrapped_field_type,
PropertyAttributes attributes,
Representation representation) {
DCHECK(wrapped_field_type->IsSmi() || wrapped_field_type->IsWeakCell());
return Descriptor(key, wrapped_field_type, kData, attributes, kField,
representation, field_index);
}
PropertyConstness constness,
Representation representation,
Handle<Object> wrapped_field_type);
static Descriptor DataConstant(Handle<Name> key, Handle<Object> value,
PropertyAttributes attributes) {
return Descriptor(key, value, kData, attributes, kDescriptor,
value->OptimalRepresentation());
return Descriptor(key, value, kData, attributes, kDescriptor, kConst,
value->OptimalRepresentation(), 0);
}
static Descriptor AccessorConstant(Handle<Name> key, Handle<Object> foreign,
PropertyAttributes attributes) {
return Descriptor(key, foreign, kAccessor, attributes, kDescriptor,
Representation::Tagged());
return Descriptor(key, foreign, kAccessor, attributes, kDescriptor, kConst,
Representation::Tagged(), 0);
}
private:
......@@ -75,10 +72,12 @@ class Descriptor final BASE_EMBEDDED {
Descriptor(Handle<Name> key, Handle<Object> value, PropertyKind kind,
PropertyAttributes attributes, PropertyLocation location,
Representation representation, int field_index = 0)
PropertyConstness constness, Representation representation,
int field_index)
: key_(key),
value_(value),
details_(kind, attributes, location, representation, field_index) {
details_(kind, attributes, location, constness, representation,
field_index) {
DCHECK(key->IsUniqueName());
DCHECK_IMPLIES(key->IsPrivate(), !details_.IsEnumerable());
}
......
This diff is collapsed.
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