From 912a3ea20b29acc12ee7ff88f69a0ff4c42a4e7f Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Mon, 20 Jun 2016 07:29:54 -0700 Subject: [PATCH 1/4] deps: cherry-pick d800a65 from V8 upstream Original commit message: Filter out stale left-trimmed handles BUG=chromium:620553 LOG=N R=jochen@chromium.org Review-Url: https://codereview.chromium.org/2078403002 Cr-Commit-Position: refs/heads/master@{#37108} --- deps/v8/src/heap/heap.cc | 30 ------------------- deps/v8/src/heap/heap.h | 3 -- deps/v8/src/heap/mark-compact.cc | 28 ++++++++++++++++- .../v8/test/mjsunit/regress/regress-620553.js | 17 +++++++++++ 4 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-620553.js diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 2b5ff9cd1aeaac..3e8e14493955b6 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -3166,10 +3166,6 @@ FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object, DCHECK(!lo_space()->Contains(object)); DCHECK(object->map() != fixed_cow_array_map()); - // Ensure that the no handle-scope has more than one pointer to the same - // backing-store. - SLOW_DCHECK(CountHandlesForObject(object) <= 1); - STATIC_ASSERT(FixedArrayBase::kMapOffset == 0); STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize); STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); @@ -5671,32 +5667,6 @@ void Heap::PrintHandles() { #endif -#ifdef ENABLE_SLOW_DCHECKS - -class CountHandleVisitor : public ObjectVisitor { - public: - explicit CountHandleVisitor(Object* object) : object_(object) {} - - void VisitPointers(Object** start, Object** end) override { - for (Object** p = start; p < end; p++) { - if (object_ == reinterpret_cast(*p)) count_++; - } - } - - int count() { return count_; } - - private: - Object* object_; - int count_ = 0; -}; - -int Heap::CountHandlesForObject(Object* object) { - CountHandleVisitor v(object); - isolate_->handle_scope_implementer()->Iterate(&v); - return v.count(); -} -#endif - class CheckHandleCountVisitor : public ObjectVisitor { public: CheckHandleCountVisitor() : handle_count_(0) {} diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index bbe1f05e4f2659..2d2029912cd717 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -1394,9 +1394,6 @@ class Heap { void ReportHeapStatistics(const char* title); void ReportCodeStatistics(const char* title); #endif -#ifdef ENABLE_SLOW_DCHECKS - int CountHandlesForObject(Object* object); -#endif private: class PretenuringScope; diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 9abcd1a4b334a6..e3c56b04ee275d 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1374,8 +1374,34 @@ class RootMarkingVisitor : public ObjectVisitor { void MarkObjectByPointer(Object** p) { if (!(*p)->IsHeapObject()) return; - // Replace flat cons strings in place. HeapObject* object = HeapObject::cast(*p); + + // We cannot avoid stale handles to left-trimmed objects, but can only make + // sure all handles still needed are updated. Filter out any stale pointers + // and clear the slot to allow post processing of handles (needed because + // the sweeper might actually free the underlying page). + if (object->IsFiller()) { +#ifdef DEBUG + // We need to find a FixedArrayBase map after walking the fillers. + Heap* heap = collector_->heap(); + HeapObject* current = object; + while (current->IsFiller()) { + Address next = reinterpret_cast
(current); + if (current->map() == heap->one_pointer_filler_map()) { + next += kPointerSize; + } else if (current->map() == heap->two_pointer_filler_map()) { + next += 2 * kPointerSize; + } else { + next += current->Size(); + } + current = reinterpret_cast(next); + } + DCHECK(current->IsFixedArrayBase()); +#endif // DEBUG + *p = nullptr; + return; + } + MarkBit mark_bit = Marking::MarkBitFrom(object); if (Marking::IsBlackOrGrey(mark_bit)) return; diff --git a/deps/v8/test/mjsunit/regress/regress-620553.js b/deps/v8/test/mjsunit/regress/regress-620553.js new file mode 100644 index 00000000000000..461b9bb189e559 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-620553.js @@ -0,0 +1,17 @@ +// Copyright 2016 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. + +// Flags: --expose-gc + +var o0 = []; +var o1 = []; +var cnt = 0; +o1.__defineGetter__(0, function() { + if (cnt++ > 2) return; + o0.shift(); + gc(); + o0.push(0); + o0.concat(o1); +}); +o1[0]; From 74f42352ad7c045fa0201b82b14ad20b62348661 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Wed, 22 Jun 2016 05:21:16 -0700 Subject: [PATCH 2/4] deps: cherry-pick 7a88ff3 from V8 upstream Original commit message: Filter out stale left-trimmed handles for scavenges The missing part from https://codereview.chromium.org/2078403002/ R=jochen@chromium.org BUG=chromium:621869 LOG=N Review-Url: https://codereview.chromium.org/2077353004 Cr-Commit-Position: refs/heads/master@{#37184} --- deps/v8/src/heap/heap-inl.h | 25 ++++++++++++++++++ deps/v8/src/heap/heap.h | 6 +++++ deps/v8/src/heap/mark-compact.cc | 26 +------------------ deps/v8/src/heap/scavenger.cc | 3 +++ deps/v8/src/objects-inl.h | 3 +-- deps/v8/src/objects.h | 2 +- .../v8/test/mjsunit/regress/regress-621869.js | 18 +++++++++++++ 7 files changed, 55 insertions(+), 28 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-621869.js diff --git a/deps/v8/src/heap/heap-inl.h b/deps/v8/src/heap/heap-inl.h index e31d3d6859b463..3d2e059fae8939 100644 --- a/deps/v8/src/heap/heap-inl.h +++ b/deps/v8/src/heap/heap-inl.h @@ -449,6 +449,31 @@ void Heap::CopyBlock(Address dst, Address src, int byte_size) { static_cast(byte_size / kPointerSize)); } +bool Heap::PurgeLeftTrimmedObject(Object** object) { + HeapObject* current = reinterpret_cast(*object); + const MapWord map_word = current->map_word(); + if (current->IsFiller() && !map_word.IsForwardingAddress()) { +#ifdef DEBUG + // We need to find a FixedArrayBase map after walking the fillers. + while (current->IsFiller()) { + Address next = reinterpret_cast
(current); + if (current->map() == one_pointer_filler_map()) { + next += kPointerSize; + } else if (current->map() == two_pointer_filler_map()) { + next += 2 * kPointerSize; + } else { + next += current->Size(); + } + current = reinterpret_cast(next); + } + DCHECK(current->IsFixedArrayBase()); +#endif // DEBUG + *object = nullptr; + return true; + } + return false; +} + template AllocationMemento* Heap::FindAllocationMemento(HeapObject* object) { // Check if there is potentially a memento behind the object. If diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 2d2029912cd717..2ce326a64e8416 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -602,6 +602,12 @@ class Heap { // stored on the map to facilitate fast dispatch for {StaticVisitorBase}. static int GetStaticVisitorIdForMap(Map* map); + // We cannot avoid stale handles to left-trimmed objects, but can only make + // sure all handles still needed are updated. Filter out a stale pointer + // and clear the slot to allow post processing of handles (needed because + // the sweeper might actually free the underlying page). + inline bool PurgeLeftTrimmedObject(Object** object); + // Notifies the heap that is ok to start marking or other activities that // should not happen during deserialization. void NotifyDeserializationComplete(); diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index e3c56b04ee275d..31b12f1d1b59b2 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1376,31 +1376,7 @@ class RootMarkingVisitor : public ObjectVisitor { HeapObject* object = HeapObject::cast(*p); - // We cannot avoid stale handles to left-trimmed objects, but can only make - // sure all handles still needed are updated. Filter out any stale pointers - // and clear the slot to allow post processing of handles (needed because - // the sweeper might actually free the underlying page). - if (object->IsFiller()) { -#ifdef DEBUG - // We need to find a FixedArrayBase map after walking the fillers. - Heap* heap = collector_->heap(); - HeapObject* current = object; - while (current->IsFiller()) { - Address next = reinterpret_cast
(current); - if (current->map() == heap->one_pointer_filler_map()) { - next += kPointerSize; - } else if (current->map() == heap->two_pointer_filler_map()) { - next += 2 * kPointerSize; - } else { - next += current->Size(); - } - current = reinterpret_cast(next); - } - DCHECK(current->IsFixedArrayBase()); -#endif // DEBUG - *p = nullptr; - return; - } + if (collector_->heap()->PurgeLeftTrimmedObject(p)) return; MarkBit mark_bit = Marking::MarkBitFrom(object); if (Marking::IsBlackOrGrey(mark_bit)) return; diff --git a/deps/v8/src/heap/scavenger.cc b/deps/v8/src/heap/scavenger.cc index 3f532ead6265f0..18735bd20179cc 100644 --- a/deps/v8/src/heap/scavenger.cc +++ b/deps/v8/src/heap/scavenger.cc @@ -462,6 +462,9 @@ void ScavengeVisitor::VisitPointers(Object** start, Object** end) { void ScavengeVisitor::ScavengePointer(Object** p) { Object* object = *p; if (!heap_->InNewSpace(object)) return; + + if (heap_->PurgeLeftTrimmedObject(p)) return; + Scavenger::ScavengeObject(reinterpret_cast(p), reinterpret_cast(object)); } diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index b75dd1c969a498..11f4d7498d7558 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -1261,8 +1261,7 @@ Map* MapWord::ToMap() { return reinterpret_cast(value_); } - -bool MapWord::IsForwardingAddress() { +bool MapWord::IsForwardingAddress() const { return HAS_SMI_TAG(reinterpret_cast(value_)); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index abced2d4bad50c..d1632c9deb2982 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -1476,7 +1476,7 @@ class MapWord BASE_EMBEDDED { // True if this map word is a forwarding address for a scavenge // collection. Only valid during a scavenge collection (specifically, // when all map words are heap object pointers, i.e. not during a full GC). - inline bool IsForwardingAddress(); + inline bool IsForwardingAddress() const; // Create a map word from a forwarding address. static inline MapWord FromForwardingAddress(HeapObject* object); diff --git a/deps/v8/test/mjsunit/regress/regress-621869.js b/deps/v8/test/mjsunit/regress/regress-621869.js new file mode 100644 index 00000000000000..db34064457cc30 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-621869.js @@ -0,0 +1,18 @@ +// Copyright 2016 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. + +// Flags: --expose-gc + +var o0 = []; +var o1 = []; +var cnt = 0; +var only_scavenge = true; +o1.__defineGetter__(0, function() { + if (cnt++ > 2) return; + o0.shift(); + gc(only_scavenge); + o0.push((64)); + o0.concat(o1); +}); +o1[0]; From e8225506225cdc72c5a2284fd91e376af065964f Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Wed, 29 Jun 2016 01:16:07 -0700 Subject: [PATCH 3/4] deps: cherry-pick a715957 from V8 upstream Original commit message: Iterate handles with special left-trim visitor BUG=chromium:620553 LOG=N R=hpayer@chromium.org Review-Url: https://codereview.chromium.org/2102243002 Cr-Commit-Position: refs/heads/master@{#37366} --- deps/v8/src/heap/heap-inl.h | 25 ------------------ deps/v8/src/heap/heap.cc | 45 ++++++++++++++++++++++++++++++++ deps/v8/src/heap/heap.h | 6 ----- deps/v8/src/heap/mark-compact.cc | 2 -- deps/v8/src/heap/scavenger.cc | 2 -- 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/deps/v8/src/heap/heap-inl.h b/deps/v8/src/heap/heap-inl.h index 3d2e059fae8939..e31d3d6859b463 100644 --- a/deps/v8/src/heap/heap-inl.h +++ b/deps/v8/src/heap/heap-inl.h @@ -449,31 +449,6 @@ void Heap::CopyBlock(Address dst, Address src, int byte_size) { static_cast(byte_size / kPointerSize)); } -bool Heap::PurgeLeftTrimmedObject(Object** object) { - HeapObject* current = reinterpret_cast(*object); - const MapWord map_word = current->map_word(); - if (current->IsFiller() && !map_word.IsForwardingAddress()) { -#ifdef DEBUG - // We need to find a FixedArrayBase map after walking the fillers. - while (current->IsFiller()) { - Address next = reinterpret_cast
(current); - if (current->map() == one_pointer_filler_map()) { - next += kPointerSize; - } else if (current->map() == two_pointer_filler_map()) { - next += 2 * kPointerSize; - } else { - next += current->Size(); - } - current = reinterpret_cast(next); - } - DCHECK(current->IsFixedArrayBase()); -#endif // DEBUG - *object = nullptr; - return true; - } - return false; -} - template AllocationMemento* Heap::FindAllocationMemento(HeapObject* object) { // Check if there is potentially a memento behind the object. If diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 3e8e14493955b6..eae9695caf09af 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -4800,6 +4800,49 @@ void Heap::IterateSmiRoots(ObjectVisitor* v) { v->Synchronize(VisitorSynchronization::kSmiRootList); } +// We cannot avoid stale handles to left-trimmed objects, but can only make +// sure all handles still needed are updated. Filter out a stale pointer +// and clear the slot to allow post processing of handles (needed because +// the sweeper might actually free the underlying page). +class FixStaleLeftTrimmedHandlesVisitor : public ObjectVisitor { + public: + explicit FixStaleLeftTrimmedHandlesVisitor(Heap* heap) : heap_(heap) { + USE(heap_); + } + + void VisitPointer(Object** p) override { FixHandle(p); } + + void VisitPointers(Object** start, Object** end) override { + for (Object** p = start; p < end; p++) FixHandle(p); + } + + private: + inline void FixHandle(Object** p) { + HeapObject* current = reinterpret_cast(*p); + if (!current->IsHeapObject()) return; + const MapWord map_word = current->map_word(); + if (!map_word.IsForwardingAddress() && current->IsFiller()) { +#ifdef DEBUG + // We need to find a FixedArrayBase map after walking the fillers. + while (current->IsFiller()) { + Address next = reinterpret_cast
(current); + if (current->map() == heap_->one_pointer_filler_map()) { + next += kPointerSize; + } else if (current->map() == heap_->two_pointer_filler_map()) { + next += 2 * kPointerSize; + } else { + next += current->Size(); + } + current = reinterpret_cast(next); + } + DCHECK(current->IsFixedArrayBase()); +#endif // DEBUG + *p = nullptr; + } + } + + Heap* heap_; +}; void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); @@ -4820,6 +4863,8 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { v->Synchronize(VisitorSynchronization::kCompilationCache); // Iterate over local handles in handle scopes. + FixStaleLeftTrimmedHandlesVisitor left_trim_visitor(this); + isolate_->handle_scope_implementer()->Iterate(&left_trim_visitor); isolate_->handle_scope_implementer()->Iterate(v); isolate_->IterateDeferredHandles(v); v->Synchronize(VisitorSynchronization::kHandleScope); diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 2ce326a64e8416..2d2029912cd717 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -602,12 +602,6 @@ class Heap { // stored on the map to facilitate fast dispatch for {StaticVisitorBase}. static int GetStaticVisitorIdForMap(Map* map); - // We cannot avoid stale handles to left-trimmed objects, but can only make - // sure all handles still needed are updated. Filter out a stale pointer - // and clear the slot to allow post processing of handles (needed because - // the sweeper might actually free the underlying page). - inline bool PurgeLeftTrimmedObject(Object** object); - // Notifies the heap that is ok to start marking or other activities that // should not happen during deserialization. void NotifyDeserializationComplete(); diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 31b12f1d1b59b2..16f93f13316bad 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1376,8 +1376,6 @@ class RootMarkingVisitor : public ObjectVisitor { HeapObject* object = HeapObject::cast(*p); - if (collector_->heap()->PurgeLeftTrimmedObject(p)) return; - MarkBit mark_bit = Marking::MarkBitFrom(object); if (Marking::IsBlackOrGrey(mark_bit)) return; diff --git a/deps/v8/src/heap/scavenger.cc b/deps/v8/src/heap/scavenger.cc index 18735bd20179cc..dce53554474a57 100644 --- a/deps/v8/src/heap/scavenger.cc +++ b/deps/v8/src/heap/scavenger.cc @@ -463,8 +463,6 @@ void ScavengeVisitor::ScavengePointer(Object** p) { Object* object = *p; if (!heap_->InNewSpace(object)) return; - if (heap_->PurgeLeftTrimmedObject(p)) return; - Scavenger::ScavengeObject(reinterpret_cast(p), reinterpret_cast(object)); } From bf0838144d3c2cd3ccd3c57db6190d010068e3dd Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Fri, 6 Jan 2017 19:04:02 -0500 Subject: [PATCH 4/4] deps: update patch level in V8 --- deps/v8/include/v8-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 35984a97ad2e8a..79f057037b4dc7 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 1 #define V8_BUILD_NUMBER 281 -#define V8_PATCH_LEVEL 90 +#define V8_PATCH_LEVEL 91 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.)