| Index: src/heap.cc
|
| ===================================================================
|
| --- src/heap.cc (revision 6904)
|
| +++ src/heap.cc (working copy)
|
| @@ -3300,8 +3300,8 @@
|
| }
|
|
|
|
|
| -MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string,
|
| - PretenureFlag pretenure) {
|
| +MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
|
| + PretenureFlag pretenure) {
|
| // V8 only supports characters in the Basic Multilingual Plane.
|
| const uc32 kMaxSupportedChar = 0xFFFF;
|
| // Count the number of characters in the UTF-8 string and check if
|
| @@ -3310,17 +3310,11 @@
|
| decoder(isolate_->scanner_constants()->utf8_decoder());
|
| decoder->Reset(string.start(), string.length());
|
| int chars = 0;
|
| - bool is_ascii = true;
|
| while (decoder->has_more()) {
|
| - uc32 r = decoder->GetNext();
|
| - if (r > String::kMaxAsciiCharCode) is_ascii = false;
|
| + decoder->GetNext();
|
| chars++;
|
| }
|
|
|
| - // If the string is ascii, we do not need to convert the characters
|
| - // since UTF8 is backwards compatible with ascii.
|
| - if (is_ascii) return AllocateStringFromAscii(string, pretenure);
|
| -
|
| Object* result;
|
| { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
|
| if (!maybe_result->ToObject(&result)) return maybe_result;
|
| @@ -3770,6 +3764,9 @@
|
| static const int kIdlesBeforeScavenge = 4;
|
| static const int kIdlesBeforeMarkSweep = 7;
|
| static const int kIdlesBeforeMarkCompact = 8;
|
| + static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
|
| + static const int kGCsBetweenCleanup = 4;
|
| +
|
| if (!last_idle_notification_gc_count_init_) {
|
| last_idle_notification_gc_count_ = gc_count_;
|
| last_idle_notification_gc_count_init_ = true;
|
| @@ -3778,8 +3775,13 @@
|
| bool uncommit = true;
|
| bool finished = false;
|
|
|
| - if (last_idle_notification_gc_count_ == gc_count_) {
|
| - number_idle_notifications_++;
|
| + // Reset the number of idle notifications received when a number of
|
| + // GCs have taken place. This allows another round of cleanup based
|
| + // on idle notifications if enough work has been carried out to
|
| + // provoke a number of garbage collections.
|
| + if (gc_count_ < last_idle_notification_gc_count_ + kGCsBetweenCleanup) {
|
| + number_idle_notifications_ =
|
| + Min(number_idle_notifications_ + 1, kMaxIdleCount);
|
| } else {
|
| number_idle_notifications_ = 0;
|
| last_idle_notification_gc_count_ = gc_count_;
|
| @@ -3794,7 +3796,6 @@
|
| }
|
| new_space_.Shrink();
|
| last_idle_notification_gc_count_ = gc_count_;
|
| -
|
| } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
|
| // Before doing the mark-sweep collections we clear the
|
| // compilation cache to avoid hanging on to source code and
|
| @@ -3811,7 +3812,6 @@
|
| last_idle_notification_gc_count_ = gc_count_;
|
| number_idle_notifications_ = 0;
|
| finished = true;
|
| -
|
| } else if (contexts_disposed_ > 0) {
|
| if (FLAG_expose_gc) {
|
| contexts_disposed_ = 0;
|
| @@ -3828,6 +3828,11 @@
|
| number_idle_notifications_ = 0;
|
| uncommit = false;
|
| }
|
| + } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
|
| + // If we have received more than kIdlesBeforeMarkCompact idle
|
| + // notifications we do not perform any cleanup because we don't
|
| + // expect to gain much by doing so.
|
| + finished = true;
|
| }
|
|
|
| // Make sure that we have no pending context disposals and
|
| @@ -4495,7 +4500,7 @@
|
| *stats->os_error = OS::GetLastError();
|
| isolate()->memory_allocator()->Available();
|
| if (take_snapshot) {
|
| - HeapIterator iterator(HeapIterator::kPreciseFiltering);
|
| + HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
|
| for (HeapObject* obj = iterator.next();
|
| obj != NULL;
|
| obj = iterator.next()) {
|
| @@ -5119,13 +5124,20 @@
|
| }
|
|
|
|
|
| -class FreeListNodesFilter {
|
| +class HeapObjectsFilter {
|
| public:
|
| + virtual ~HeapObjectsFilter() {}
|
| + virtual bool SkipObject(HeapObject* object) = 0;
|
| +};
|
| +
|
| +
|
| +class FreeListNodesFilter : public HeapObjectsFilter {
|
| + public:
|
| FreeListNodesFilter() {
|
| MarkFreeListNodes();
|
| }
|
|
|
| - inline bool IsFreeListNode(HeapObject* object) {
|
| + bool SkipObject(HeapObject* object) {
|
| if (object->IsMarked()) {
|
| object->ClearMark();
|
| return true;
|
| @@ -5158,6 +5170,65 @@
|
| };
|
|
|
|
|
| +class UnreachableObjectsFilter : public HeapObjectsFilter {
|
| + public:
|
| + UnreachableObjectsFilter() {
|
| + MarkUnreachableObjects();
|
| + }
|
| +
|
| + bool SkipObject(HeapObject* object) {
|
| + if (object->IsMarked()) {
|
| + object->ClearMark();
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + class UnmarkingVisitor : public ObjectVisitor {
|
| + public:
|
| + UnmarkingVisitor() : list_(10) {}
|
| +
|
| + void VisitPointers(Object** start, Object** end) {
|
| + for (Object** p = start; p < end; p++) {
|
| + if (!(*p)->IsHeapObject()) continue;
|
| + HeapObject* obj = HeapObject::cast(*p);
|
| + if (obj->IsMarked()) {
|
| + obj->ClearMark();
|
| + list_.Add(obj);
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool can_process() { return !list_.is_empty(); }
|
| +
|
| + void ProcessNext() {
|
| + HeapObject* obj = list_.RemoveLast();
|
| + obj->Iterate(this);
|
| + }
|
| +
|
| + private:
|
| + List<HeapObject*> list_;
|
| + };
|
| +
|
| + void MarkUnreachableObjects() {
|
| + HeapIterator iterator;
|
| + for (HeapObject* obj = iterator.next();
|
| + obj != NULL;
|
| + obj = iterator.next()) {
|
| + obj->SetMark();
|
| + }
|
| + UnmarkingVisitor visitor;
|
| + HEAP->IterateRoots(&visitor, VISIT_ONLY_STRONG);
|
| + while (visitor.can_process())
|
| + visitor.ProcessNext();
|
| + }
|
| +
|
| + AssertNoAllocation no_alloc;
|
| +};
|
| +
|
| +
|
| HeapIterator::HeapIterator()
|
| : filtering_(HeapIterator::kNoFiltering),
|
| filter_(NULL) {
|
| @@ -5165,7 +5236,7 @@
|
| }
|
|
|
|
|
| -HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering)
|
| +HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
|
| : filtering_(filtering),
|
| filter_(NULL) {
|
| Init();
|
| @@ -5179,12 +5250,17 @@
|
|
|
| void HeapIterator::Init() {
|
| // Start the iteration.
|
| - if (filtering_ == kPreciseFiltering) {
|
| - filter_ = new FreeListNodesFilter;
|
| - space_iterator_ =
|
| - new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
|
| - } else {
|
| - space_iterator_ = new SpaceIterator;
|
| + space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator :
|
| + new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
|
| + switch (filtering_) {
|
| + case kFilterFreeListNodes:
|
| + filter_ = new FreeListNodesFilter;
|
| + break;
|
| + case kFilterUnreachable:
|
| + filter_ = new UnreachableObjectsFilter;
|
| + break;
|
| + default:
|
| + break;
|
| }
|
| object_iterator_ = space_iterator_->next();
|
| }
|
| @@ -5192,9 +5268,9 @@
|
|
|
| void HeapIterator::Shutdown() {
|
| #ifdef DEBUG
|
| - // Assert that in precise mode we have iterated through all
|
| + // Assert that in filtering mode we have iterated through all
|
| // objects. Otherwise, heap will be left in an inconsistent state.
|
| - if (filtering_ == kPreciseFiltering) {
|
| + if (filtering_ != kNoFiltering) {
|
| ASSERT(object_iterator_ == NULL);
|
| }
|
| #endif
|
| @@ -5211,7 +5287,7 @@
|
| if (filter_ == NULL) return NextObject();
|
|
|
| HeapObject* obj = NextObject();
|
| - while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject();
|
| + while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
|
| return obj;
|
| }
|
|
|
|
|