From 672056ac88137662c3c63b4634b27767f3ee6d33 Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Thu, 31 Jan 2013 10:50:42 +0000 Subject: [PATCH] Only mark the descriptor that is valid for the map in question. If this map transitioned from a map with a different descriptor array (or has no back pointer), mark all valid descriptors from the start. This fixes the following memory leak: Map A shares a descriptor array with map B. Map B adds constant function c that in its scope holds on to an instance of B. If the descriptor array of A would keep all the shared descriptors alive, including c, this keeps alive both A and c indefinitely. This CL also fixes a bug in descriptor array trimming. When trimming descriptor arrays we need to trim off the slack as well (thus the entire storage); and since we are trimming a descriptor array, we need to trim * kDescriptorSize. Review URL: https://chromiumcodereview.appspot.com/12084066 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13566 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/objects-inl.h | 10 ++++++++++ src/objects-visiting-inl.h | 27 +++++++++++++++++++++++++++ src/objects.cc | 7 ++++--- src/objects.h | 2 ++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/objects-inl.h b/src/objects-inl.h index 28d8762..18894c1 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2142,6 +2142,16 @@ Object** DescriptorArray::GetKeySlot(int descriptor_number) { } +Object** DescriptorArray::GetDescriptorStartSlot(int descriptor_number) { + return GetKeySlot(descriptor_number); +} + + +Object** DescriptorArray::GetDescriptorEndSlot(int descriptor_number) { + return GetValueSlot(descriptor_number - 1) + 1; +} + + String* DescriptorArray::GetKey(int descriptor_number) { ASSERT(descriptor_number < number_of_descriptors()); return String::cast(get(ToKeyIndex(descriptor_number))); diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h index 7332a0c..4fabba4 100644 --- a/src/objects-visiting-inl.h +++ b/src/objects-visiting-inl.h @@ -396,6 +396,33 @@ void StaticMarkingVisitor::MarkMapContents( ASSERT(transitions->IsMap() || transitions->IsUndefined()); } + // Since descriptor arrays are potentially shared, ensure that only the + // descriptors that appeared for this map are marked. The first time a + // non-empty descriptor array is marked, its header is also visited. The slot + // holding the descriptor array will be implicitly recorded when the pointer + // fields of this map are visited. + DescriptorArray* descriptors = map->instance_descriptors(); + if (StaticVisitor::MarkObjectWithoutPush(heap, descriptors) && + descriptors->length() > 0) { + StaticVisitor::VisitPointers(heap, + descriptors->GetFirstElementAddress(), + descriptors->GetDescriptorEndSlot(0)); + } + int start = 0; + int end = map->NumberOfOwnDescriptors(); + Object* back_pointer = map->GetBackPointer(); + if (!back_pointer->IsUndefined()) { + Map* parent_map = Map::cast(back_pointer); + if (descriptors == parent_map->instance_descriptors()) { + start = parent_map->NumberOfOwnDescriptors(); + } + } + if (start < end) { + StaticVisitor::VisitPointers(heap, + descriptors->GetDescriptorStartSlot(start), + descriptors->GetDescriptorEndSlot(end)); + } + // Mark prototype dependent codes array but do not push it onto marking // stack, this will make references from it weak. We will clean dead // codes when we iterate over maps in ClearNonLiveTransitions. diff --git a/src/objects.cc b/src/objects.cc index 1d2cca3..fb8c704 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -7646,11 +7646,12 @@ static void TrimDescriptorArray(Heap* heap, Map* map, DescriptorArray* descriptors, int number_of_own_descriptors) { - int number_of_descriptors = descriptors->number_of_descriptors(); + int number_of_descriptors = descriptors->number_of_descriptors_storage(); int to_trim = number_of_descriptors - number_of_own_descriptors; - if (to_trim <= 0) return; + if (to_trim == 0) return; - RightTrimFixedArray(heap, descriptors, to_trim); + RightTrimFixedArray( + heap, descriptors, to_trim * DescriptorArray::kDescriptorSize); descriptors->SetNumberOfDescriptors(number_of_own_descriptors); if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors); diff --git a/src/objects.h b/src/objects.h index 975fdf8..10f74fc 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2609,6 +2609,8 @@ class DescriptorArray: public FixedArray { inline Object** GetKeySlot(int descriptor_number); inline Object* GetValue(int descriptor_number); inline Object** GetValueSlot(int descriptor_number); + inline Object** GetDescriptorStartSlot(int descriptor_number); + inline Object** GetDescriptorEndSlot(int descriptor_number); inline PropertyDetails GetDetails(int descriptor_number); inline PropertyType GetType(int descriptor_number); inline int GetFieldIndex(int descriptor_number); -- 2.7.4