Commit c56fa736 authored by ulan's avatar ulan Committed by Commit bot

Reland "Fix memory leak caused by field type in descriptor array."

BUG=v8:3877
LOG=NO

Review URL: https://codereview.chromium.org/1018283002

Cr-Commit-Position: refs/heads/master@{#27362}
parent b9ef7d42
...@@ -289,9 +289,11 @@ void JSObject::JSObjectVerify() { ...@@ -289,9 +289,11 @@ void JSObject::JSObjectVerify() {
if (r.IsSmi()) DCHECK(value->IsSmi()); if (r.IsSmi()) DCHECK(value->IsSmi());
if (r.IsHeapObject()) DCHECK(value->IsHeapObject()); if (r.IsHeapObject()) DCHECK(value->IsHeapObject());
HeapType* field_type = descriptors->GetFieldType(i); HeapType* field_type = descriptors->GetFieldType(i);
bool type_is_none = field_type->Is(HeapType::None());
bool type_is_any = field_type->Is(HeapType::Any());
if (r.IsNone()) { if (r.IsNone()) {
CHECK(field_type->Is(HeapType::None())); CHECK(type_is_none);
} else if (!HeapType::Any()->Is(field_type)) { } else if (!type_is_any && !(type_is_none && r.IsHeapObject())) {
CHECK(!field_type->NowStable() || field_type->NowContains(value)); CHECK(!field_type->NowStable() || field_type->NowContains(value));
} }
} }
......
...@@ -3148,7 +3148,12 @@ int DescriptorArray::GetFieldIndex(int descriptor_number) { ...@@ -3148,7 +3148,12 @@ int DescriptorArray::GetFieldIndex(int descriptor_number) {
HeapType* DescriptorArray::GetFieldType(int descriptor_number) { HeapType* DescriptorArray::GetFieldType(int descriptor_number) {
DCHECK(GetDetails(descriptor_number).location() == kField); DCHECK(GetDetails(descriptor_number).location() == kField);
return HeapType::cast(GetValue(descriptor_number)); Object* value = GetValue(descriptor_number);
if (value->IsWeakCell()) {
if (WeakCell::cast(value)->cleared()) return HeapType::None();
value = WeakCell::cast(value)->value();
}
return HeapType::cast(value);
} }
......
...@@ -1699,6 +1699,12 @@ String* JSReceiver::constructor_name() { ...@@ -1699,6 +1699,12 @@ String* JSReceiver::constructor_name() {
} }
static Handle<Object> WrapType(Handle<HeapType> type) {
if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()->Map());
return type;
}
MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
Handle<Name> name, Handle<Name> name,
Handle<HeapType> type, Handle<HeapType> type,
...@@ -1724,7 +1730,10 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, ...@@ -1724,7 +1730,10 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
type = HeapType::Any(isolate); type = HeapType::Any(isolate);
} }
DataDescriptor new_field_desc(name, index, type, attributes, representation); Handle<Object> wrapped_type(WrapType(type));
DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
representation);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag); Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1; int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) { if (unused_property_fields < 0) {
...@@ -2298,7 +2307,8 @@ Map* Map::FindFieldOwner(int descriptor) { ...@@ -2298,7 +2307,8 @@ Map* Map::FindFieldOwner(int descriptor) {
void Map::UpdateFieldType(int descriptor, Handle<Name> name, void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Representation new_representation, Representation new_representation,
Handle<HeapType> new_type) { Handle<Object> new_wrapped_type) {
DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
PropertyDetails details = instance_descriptors()->GetDetails(descriptor); PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
if (details.type() != DATA) return; if (details.type() != DATA) return;
...@@ -2306,16 +2316,17 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name, ...@@ -2306,16 +2316,17 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
int num_transitions = TransitionArray::NumberOfTransitions(transitions); int num_transitions = TransitionArray::NumberOfTransitions(transitions);
for (int i = 0; i < num_transitions; ++i) { for (int i = 0; i < num_transitions; ++i) {
Map* target = TransitionArray::GetTarget(transitions, i); Map* target = TransitionArray::GetTarget(transitions, i);
target->UpdateFieldType(descriptor, name, new_representation, new_type); target->UpdateFieldType(descriptor, name, new_representation,
new_wrapped_type);
} }
// It is allowed to change representation here only from None to something. // It is allowed to change representation here only from None to something.
DCHECK(details.representation().Equals(new_representation) || DCHECK(details.representation().Equals(new_representation) ||
details.representation().IsNone()); details.representation().IsNone());
// Skip if already updated the shared descriptor. // Skip if already updated the shared descriptor.
if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return; if (instance_descriptors()->GetValue(descriptor) == *new_wrapped_type) return;
DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor), DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
new_type, details.attributes(), new_representation); new_wrapped_type, details.attributes(), new_representation);
instance_descriptors()->Replace(descriptor, &d); instance_descriptors()->Replace(descriptor, &d);
} }
...@@ -2363,8 +2374,10 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index, ...@@ -2363,8 +2374,10 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
PropertyDetails details = descriptors->GetDetails(modify_index); PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index)); Handle<Name> name(descriptors->GetKey(modify_index));
Handle<Object> wrapped_type(WrapType(new_field_type));
field_owner->UpdateFieldType(modify_index, name, new_representation, field_owner->UpdateFieldType(modify_index, name, new_representation,
new_field_type); wrapped_type);
field_owner->dependent_code()->DeoptimizeDependentCodeGroup( field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kFieldTypeGroup); isolate, DependentCode::kFieldTypeGroup);
...@@ -2757,7 +2770,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, ...@@ -2757,7 +2770,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
next_field_type = next_field_type =
GeneralizeFieldType(target_field_type, old_field_type, isolate); GeneralizeFieldType(target_field_type, old_field_type, isolate);
} }
DataDescriptor d(target_key, current_offset, next_field_type, Handle<Object> wrapped_type(WrapType(next_field_type));
DataDescriptor d(target_key, current_offset, wrapped_type,
next_attributes, next_representation); next_attributes, next_representation);
current_offset += d.GetDetails().field_width_in_words(); current_offset += d.GetDetails().field_width_in_words();
new_descriptors->Set(i, &d); new_descriptors->Set(i, &d);
...@@ -2825,8 +2839,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, ...@@ -2825,8 +2839,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
next_field_type = old_field_type; next_field_type = old_field_type;
} }
DataDescriptor d(old_key, current_offset, next_field_type, Handle<Object> wrapped_type(WrapType(next_field_type));
next_attributes, next_representation);
DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
next_representation);
current_offset += d.GetDetails().field_width_in_words(); current_offset += d.GetDetails().field_width_in_words();
new_descriptors->Set(i, &d); new_descriptors->Set(i, &d);
} else { } else {
...@@ -2958,33 +2974,41 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) { ...@@ -2958,33 +2974,41 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
if (!old_details.representation().fits_into(new_details.representation())) { if (!old_details.representation().fits_into(new_details.representation())) {
return MaybeHandle<Map>(); return MaybeHandle<Map>();
} }
Object* new_value = new_descriptors->GetValue(i);
Object* old_value = old_descriptors->GetValue(i);
switch (new_details.type()) { switch (new_details.type()) {
case DATA: { case DATA: {
PropertyType old_type = old_details.type(); HeapType* new_type = new_descriptors->GetFieldType(i);
if (old_type == DATA) { PropertyType old_property_type = old_details.type();
if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) { if (old_property_type == DATA) {
HeapType* old_type = old_descriptors->GetFieldType(i);
if (!old_type->NowIs(new_type)) {
return MaybeHandle<Map>(); return MaybeHandle<Map>();
} }
} else { } else {
DCHECK(old_type == DATA_CONSTANT); DCHECK(old_property_type == DATA_CONSTANT);
if (!HeapType::cast(new_value)->NowContains(old_value)) { Object* old_value = old_descriptors->GetValue(i);
if (!new_type->NowContains(old_value)) {
return MaybeHandle<Map>(); return MaybeHandle<Map>();
} }
} }
break; break;
} }
case ACCESSOR: case ACCESSOR: {
DCHECK(HeapType::Any()->Is(HeapType::cast(new_value))); #ifdef DEBUG
HeapType* new_type = new_descriptors->GetFieldType(i);
DCHECK(HeapType::Any()->Is(new_type));
#endif
break; break;
}
case DATA_CONSTANT: case DATA_CONSTANT:
case ACCESSOR_CONSTANT: case ACCESSOR_CONSTANT: {
Object* old_value = old_descriptors->GetValue(i);
Object* new_value = new_descriptors->GetValue(i);
if (old_details.location() == kField || old_value != new_value) { if (old_details.location() == kField || old_value != new_value) {
return MaybeHandle<Map>(); return MaybeHandle<Map>();
} }
break; break;
}
} }
} }
if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>(); if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
......
...@@ -6478,9 +6478,12 @@ class Map: public HeapObject { ...@@ -6478,9 +6478,12 @@ class Map: public HeapObject {
Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors); 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.
void UpdateFieldType(int descriptor_number, Handle<Name> name, void UpdateFieldType(int descriptor_number, Handle<Name> name,
Representation new_representation, Representation new_representation,
Handle<HeapType> new_type); Handle<Object> new_wrapped_type);
void PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind, void PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
PropertyAttributes attributes); PropertyAttributes attributes);
......
...@@ -79,10 +79,14 @@ class DataDescriptor FINAL : public Descriptor { ...@@ -79,10 +79,14 @@ class DataDescriptor FINAL : public Descriptor {
PropertyAttributes attributes, Representation representation) PropertyAttributes attributes, Representation representation)
: Descriptor(key, HeapType::Any(key->GetIsolate()), attributes, DATA, : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes, DATA,
representation, field_index) {} representation, field_index) {}
DataDescriptor(Handle<Name> key, int field_index, Handle<HeapType> field_type, // The field type is either a simple type or a map wrapped in a weak cell.
DataDescriptor(Handle<Name> key, int field_index,
Handle<Object> wrapped_field_type,
PropertyAttributes attributes, Representation representation) PropertyAttributes attributes, Representation representation)
: Descriptor(key, field_type, attributes, DATA, representation, : Descriptor(key, wrapped_field_type, attributes, DATA, representation,
field_index) {} field_index) {
DCHECK(wrapped_field_type->IsSmi() || wrapped_field_type->IsWeakCell());
}
}; };
......
...@@ -5062,6 +5062,40 @@ TEST(NumberStringCacheSize) { ...@@ -5062,6 +5062,40 @@ TEST(NumberStringCacheSize) {
} }
TEST(Regress3877) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
CompileRun("function cls() { this.x = 10; }");
Handle<WeakCell> weak_prototype;
{
HandleScope inner_scope(isolate);
v8::Local<v8::Value> result = CompileRun("cls.prototype");
Handle<JSObject> proto =
v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
weak_prototype = inner_scope.CloseAndEscape(factory->NewWeakCell(proto));
}
CHECK(!weak_prototype->cleared());
CompileRun(
"var a = { };"
"a.x = new cls();"
"cls.prototype = null;");
for (int i = 0; i < 4; i++) {
heap->CollectAllGarbage(Heap::kNoGCFlags);
}
// The map of a.x keeps prototype alive
CHECK(!weak_prototype->cleared());
// Change the map of a.x and make the previous map garbage collectable.
CompileRun("a.x.__proto__ = {};");
for (int i = 0; i < 4; i++) {
heap->CollectAllGarbage(Heap::kNoGCFlags);
}
CHECK(weak_prototype->cleared());
}
void CheckMapRetainingFor(int n) { void CheckMapRetainingFor(int n) {
FLAG_retain_maps_for_n_gc = n; FLAG_retain_maps_for_n_gc = n;
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
......
...@@ -233,12 +233,14 @@ class Expectations { ...@@ -233,12 +233,14 @@ class Expectations {
representations_[descriptor])) { representations_[descriptor])) {
return false; return false;
} }
Object* expected_value = *values_[descriptor];
Object* value = descriptors->GetValue(descriptor); Object* value = descriptors->GetValue(descriptor);
Object* expected_value = *values_[descriptor];
switch (type) { switch (type) {
case DATA: case DATA:
case ACCESSOR: case ACCESSOR: {
return HeapType::cast(expected_value)->Equals(HeapType::cast(value)); HeapType* type = descriptors->GetFieldType(descriptor);
return HeapType::cast(expected_value)->Equals(type);
}
case DATA_CONSTANT: case DATA_CONSTANT:
return value == expected_value; return value == expected_value;
......
...@@ -243,6 +243,10 @@ ...@@ -243,6 +243,10 @@
# Issue 3723. # Issue 3723.
'regress/regress-3717': [SKIP], 'regress/regress-3717': [SKIP],
# Issue 3924.
'mjsunit/debug-clearbreakpointgroup': [SKIP],
# Issue 3969.
'mjsunit/debug-references': [SKIP],
}], # 'gc_stress == True' }], # 'gc_stress == True'
############################################################################## ##############################################################################
......
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