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

[runtime] Prepare for turning constant field tracking on.

This CL ensures that elements kind transitions don't cause silent
mutable-to-constant field migrations when the following options
are enabled: --track_constant_fields --modify_map_inplace.

Bug: v8:5495, v8:6980
Change-Id: Ie28daab84f91d424110e71504b025a2e465bfe16
Reviewed-on: https://chromium-review.googlesource.com/753087
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49133}
parent 6414e17d
......@@ -694,8 +694,8 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
break;
}
Handle<Map> map =
isolate->factory()->NewMap(type, instance_size, HOLEY_SMI_ELEMENTS);
Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
TERMINAL_FAST_ELEMENTS_KIND);
JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
// Mark as undetectable if needed.
......
......@@ -1633,9 +1633,11 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
array_function->shared()->SetConstructStub(*code);
// Set up %ArrayPrototype%.
// The %ArrayPrototype% has TERMINAL_FAST_ELEMENTS_KIND in order to ensure
// that constant functions stay constant after turning prototype to setup
// mode and back when constant field tracking is enabled.
Handle<JSArray> proto =
Handle<JSArray>::cast(factory->NewJSObject(array_function, TENURED));
JSArray::Initialize(proto, 0);
factory->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND, TENURED);
JSFunction::SetPrototype(array_function, proto);
native_context()->set_initial_array_prototype(*proto);
......
......@@ -1651,7 +1651,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
NewFunction(name, code, prototype, language_mode, prototype_mutability);
ElementsKind elements_kind =
type == JS_ARRAY_TYPE ? PACKED_SMI_ELEMENTS : HOLEY_SMI_ELEMENTS;
type == JS_ARRAY_TYPE ? PACKED_SMI_ELEMENTS : TERMINAL_FAST_ELEMENTS_KIND;
Handle<Map> initial_map =
NewMap(type, instance_size, elements_kind, inobject_properties);
// TODO(littledan): Why do we have this is_generator test when
......
......@@ -94,21 +94,9 @@ LookupIterator LookupIterator::ForTransitionHandler(
has_property);
if (!transition_map->is_dictionary_map()) {
PropertyConstness new_constness = kConst;
if (FLAG_track_constant_fields) {
if (it.constness() == kConst) {
DCHECK_EQ(kData, it.property_details_.kind());
// Check that current value matches new value otherwise we should make
// the property mutable.
if (!it.IsConstFieldValueEqualTo(*value)) new_constness = kMutable;
}
} else {
new_constness = kMutable;
}
int descriptor_number = transition_map->LastAdded();
Handle<Map> new_map = Map::PrepareForDataProperty(
transition_map, descriptor_number, new_constness, value);
transition_map, descriptor_number, kConst, value);
// Reload information; this is no-op if nothing changed.
it.property_details_ =
new_map->instance_descriptors()->GetDetails(descriptor_number);
......
......@@ -123,8 +123,9 @@ Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
new_field_type_ = field_type;
}
GeneralizeIfTransitionableFastElementsKind(
&new_constness_, &new_representation_, &new_field_type_);
Map::GeneralizeIfTransitionableFastElementsKind(
isolate_, new_elements_kind_, &new_constness_, &new_representation_,
&new_field_type_);
if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
if (FindRootMap() == kEnd) return result_map_;
......@@ -158,28 +159,6 @@ Handle<Map> MapUpdater::Update() {
return result_map_;
}
void MapUpdater::GeneralizeIfTransitionableFastElementsKind(
PropertyConstness* constness, Representation* representation,
Handle<FieldType>* field_type) {
DCHECK_EQ(is_transitionable_fast_elements_kind_,
IsTransitionableFastElementsKind(new_elements_kind_));
if (is_transitionable_fast_elements_kind_ &&
Map::IsInplaceGeneralizableField(*constness, *representation,
**field_type)) {
// We don't support propagation of field generalization through elements
// kind transitions because they are inserted into the transition tree
// before field transitions. In order to avoid complexity of handling
// such a case we ensure that all maps with transitionable elements kinds
// do not have fields that can be generalized in-place (without creation
// of a new map).
if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
*constness = kMutable;
}
DCHECK(representation->IsHeapObject());
*field_type = FieldType::Any(isolate_);
}
}
void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
PropertyConstness new_constness,
Representation new_representation,
......@@ -518,8 +497,9 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
old_details.representation(), old_field_type, next_representation,
target_field_type, isolate_);
GeneralizeIfTransitionableFastElementsKind(
&next_constness, &next_representation, &next_field_type);
Map::GeneralizeIfTransitionableFastElementsKind(
isolate_, new_elements_kind_, &next_constness, &next_representation,
&next_field_type);
Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
Descriptor d;
......
......@@ -148,10 +148,6 @@ class MapUpdater {
Handle<DescriptorArray> descriptors, int descriptor,
PropertyLocation location, Representation representation);
inline void GeneralizeIfTransitionableFastElementsKind(
PropertyConstness* constness, Representation* representation,
Handle<FieldType>* field_type);
void GeneralizeField(Handle<Map> map, int modify_index,
PropertyConstness new_constness,
Representation new_representation,
......
......@@ -3735,20 +3735,14 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
int index = map->NextFreePropertyIndex();
if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
constness = kMutable;
representation = Representation::Tagged();
type = FieldType::Any(isolate);
} else if (IsTransitionableFastElementsKind(map->elements_kind()) &&
IsInplaceGeneralizableField(constness, representation, *type)) {
// We don't support propagation of field generalization through elements
// kind transitions because they are inserted into the transition tree
// before field transitions. In order to avoid complexity of handling
// such a case we ensure that all maps with transitionable elements kinds
// do not have fields that can be generalized in-place (without creation
// of a new map).
DCHECK(representation.IsHeapObject());
type = FieldType::Any(isolate);
}
Map::GeneralizeIfTransitionableFastElementsKind(
isolate, map->elements_kind(), &constness, &representation, &type);
Handle<Object> wrapped_type(WrapFieldType(type));
DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
......@@ -6250,6 +6244,9 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Handle<PropertyArray> fields =
factory->NewPropertyArray(number_of_allocated_fields);
bool is_transitionable_elements_kind =
IsTransitionableFastElementsKind(old_map->elements_kind());
// Fill in the instance descriptor and the fields.
int current_offset = 0;
for (int i = 0; i < instance_descriptor_length; i++) {
......@@ -6277,8 +6274,14 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
d = Descriptor::DataConstant(key, handle(value, isolate),
details.attributes());
} else {
// Ensure that we make constant field only when elements kind is not
// transitionable.
PropertyConstness constness =
FLAG_track_constant_fields && !is_transitionable_elements_kind
? kConst
: kMutable;
d = Descriptor::DataField(
key, current_offset, details.attributes(), kDefaultFieldConstness,
key, current_offset, details.attributes(), constness,
// TODO(verwaest): value->OptimalRepresentation();
Representation::Tagged(), FieldType::Any(isolate));
}
......
......@@ -42,6 +42,30 @@ bool Map::IsInplaceGeneralizableField(PropertyConstness constness,
return false;
}
// static
void Map::GeneralizeIfTransitionableFastElementsKind(
Isolate* isolate, ElementsKind elements_kind, PropertyConstness* constness,
Representation* representation, Handle<FieldType>* field_type) {
if (IsTransitionableFastElementsKind(elements_kind)) {
// We don't support propagation of field generalization through elements
// kind transitions because they are inserted into the transition tree
// before field transitions. In order to avoid complexity of handling
// such a case we ensure that all maps with transitionable elements kinds
// do not have fields that can be generalized in-place (without creation
// of a new map).
if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
// The constness is either already kMutable or should become kMutable if
// it was kConst.
*constness = kMutable;
}
if (representation->IsHeapObject()) {
// The field type is either already Any or should become Any if it was
// something else.
*field_type = FieldType::Any(isolate);
}
}
}
int NormalizedMapCache::GetIndex(Handle<Map> map) {
return map->Hash() % NormalizedMapCache::kEntries;
}
......
......@@ -465,6 +465,17 @@ class Map : public HeapObject {
Representation representation,
FieldType* field_type);
// Generalizes constness, representation and field_type if the given elements
// kind is a fast and transitionable by stubs / optimized code.
// This generalization is necessary in order to ensure that elements kind
// transitions performed by stubs / optimized code don't silently transition
// kMutable fields back to kConst state or fields with HeapObject
// representation and "Any" type back to "Class" type.
static inline void GeneralizeIfTransitionableFastElementsKind(
Isolate* isolate, ElementsKind elements_kind,
PropertyConstness* constness, Representation* representation,
Handle<FieldType>* field_type);
static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index,
PropertyKind new_kind,
PropertyAttributes new_attributes,
......
......@@ -110,6 +110,20 @@ class Expectations {
CHECK(index < MAX_PROPERTIES);
kinds_[index] = kind;
locations_[index] = location;
if (kind == kData && location == kField &&
IsTransitionableFastElementsKind(elements_kind_) &&
Map::IsInplaceGeneralizableField(constness, representation,
FieldType::cast(*value))) {
// Maps with transitionable elements kinds must have non in-place
// generalizable fields.
if (FLAG_track_constant_fields && FLAG_modify_map_inplace &&
constness == kConst) {
constness = kMutable;
}
if (representation.IsHeapObject() && !FieldType::cast(*value)->IsAny()) {
value = FieldType::Any(isolate_);
}
}
constnesses_[index] = constness;
attributes_[index] = attributes;
representations_[index] = representation;
......@@ -318,27 +332,14 @@ class Expectations {
Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
PropertyConstness constness,
Representation representation,
Handle<FieldType> heap_type) {
Handle<FieldType> field_type) {
CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
int property_index = number_of_properties_++;
PropertyConstness expected_constness = constness;
Representation expected_representation = representation;
Handle<FieldType> expected_heap_type = heap_type;
if (IsTransitionableFastElementsKind(map->elements_kind())) {
// Maps with transitionable elements kinds must have non in-place
// generalizable fields.
if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
expected_constness = kMutable;
}
if (representation.IsHeapObject() && heap_type->IsClass()) {
expected_heap_type = FieldType::Any(isolate_);
}
}
SetDataField(property_index, attributes, expected_constness,
expected_representation, expected_heap_type);
SetDataField(property_index, attributes, constness, representation,
field_type);
Handle<String> name = MakeName("prop", property_index);
return Map::CopyWithField(map, name, heap_type, attributes, constness,
return Map::CopyWithField(map, name, field_type, attributes, constness,
representation, INSERT_TRANSITION)
.ToHandleChecked();
}
......@@ -1991,7 +1992,6 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
{kConst, Representation::HeapObject(), current_type},
{kConst, Representation::HeapObject(), new_type},
{kConst, Representation::HeapObject(), expected_type});
if (FLAG_modify_map_inplace) {
// kConst to kMutable migration does not create a new map, therefore
// trivial generalization.
......
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