| Index: src/incremental-marking.cc
 | 
| ===================================================================
 | 
| --- src/incremental-marking.cc	(revision 12562)
 | 
| +++ src/incremental-marking.cc	(working copy)
 | 
| @@ -192,6 +192,41 @@
 | 
|                       void>::Visit(map, object);
 | 
|    }
 | 
|  
 | 
| +  static const int kScanningChunk = 32 * 1024;
 | 
| +
 | 
| +  static int VisitHugeArray(FixedArray* array) {
 | 
| +    Heap* heap = array->GetHeap();
 | 
| +    MemoryChunk* chunk = MemoryChunk::FromAddress(array->address());
 | 
| +    Object** start = array->data_start();
 | 
| +    int length = array->length();
 | 
| +
 | 
| +    if (chunk->owner()->identity() != LO_SPACE) {
 | 
| +      VisitPointers(heap, start, start + length);
 | 
| +      return length;
 | 
| +    }
 | 
| +
 | 
| +    int from =
 | 
| +        chunk->IsPartiallyScanned() ? chunk->PartiallyScannedProgress() : 0;
 | 
| +    int to = Min(from + kScanningChunk, length);
 | 
| +
 | 
| +    VisitPointers(heap, start + from, start + to);
 | 
| +
 | 
| +    if (to == length) {
 | 
| +      // If it went from black to grey while it was waiting for the next bit to
 | 
| +      // be scanned then we have to start the scan again.
 | 
| +      MarkBit mark_bit = Marking::MarkBitFrom(array);
 | 
| +      if (!Marking::IsBlack(mark_bit)) {
 | 
| +        ASSERT(Marking::IsGrey(mark_bit));
 | 
| +        chunk->SetPartiallyScannedProgress(0);
 | 
| +      } else {
 | 
| +        chunk->SetCompletelyScanned();
 | 
| +      }
 | 
| +    } else {
 | 
| +      chunk->SetPartiallyScannedProgress(to);
 | 
| +    }
 | 
| +    return to - from;
 | 
| +  }
 | 
| +
 | 
|    static inline void VisitJSFunction(Map* map, HeapObject* object) {
 | 
|      Heap* heap = map->GetHeap();
 | 
|      // Iterate over all fields in the body but take care in dealing with
 | 
| @@ -621,7 +656,8 @@
 | 
|  #ifdef DEBUG
 | 
|          MarkBit mark_bit = Marking::MarkBitFrom(obj);
 | 
|          ASSERT(Marking::IsGrey(mark_bit) ||
 | 
| -               (obj->IsFiller() && Marking::IsWhite(mark_bit)));
 | 
| +               (obj->IsFiller() && Marking::IsWhite(mark_bit)) ||
 | 
| +               MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned());
 | 
|  #endif
 | 
|      }
 | 
|    }
 | 
| @@ -633,6 +669,19 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void IncrementalMarking::FillMarkingDequeFromLargePostponedArrays() {
 | 
| +  ASSERT(marking_deque_.IsEmpty());
 | 
| +  LargeObjectIterator it(heap_->lo_space());
 | 
| +  for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
 | 
| +    if (!obj->IsFixedArray()) continue;
 | 
| +    MemoryChunk* p = MemoryChunk::FromAddress(obj->address());
 | 
| +    if (p->IsPartiallyScanned()) {
 | 
| +      marking_deque_.PushGrey(obj);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void IncrementalMarking::Hurry() {
 | 
|    if (state() == MARKING) {
 | 
|      double start = 0.0;
 | 
| @@ -644,36 +693,57 @@
 | 
|      // was stopped.
 | 
|      Map* filler_map = heap_->one_pointer_filler_map();
 | 
|      Map* native_context_map = heap_->native_context_map();
 | 
| -    while (!marking_deque_.IsEmpty()) {
 | 
| -      HeapObject* obj = marking_deque_.Pop();
 | 
| +    do {
 | 
| +      while (!marking_deque_.IsEmpty()) {
 | 
| +        HeapObject* obj = marking_deque_.Pop();
 | 
|  
 | 
| -      // Explicitly skip one word fillers. Incremental markbit patterns are
 | 
| -      // correct only for objects that occupy at least two words.
 | 
| -      Map* map = obj->map();
 | 
| -      if (map == filler_map) {
 | 
| -        continue;
 | 
| -      } else if (map == native_context_map) {
 | 
| -        // Native contexts have weak fields.
 | 
| -        IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj);
 | 
| -      } else {
 | 
| -        MarkBit map_mark_bit = Marking::MarkBitFrom(map);
 | 
| -        if (Marking::IsWhite(map_mark_bit)) {
 | 
| -          WhiteToGreyAndPush(map, map_mark_bit);
 | 
| +        // Explicitly skip one word fillers. Incremental markbit patterns are
 | 
| +        // correct only for objects that occupy at least two words.
 | 
| +        Map* map = obj->map();
 | 
| +        if (map == filler_map) {
 | 
| +          continue;
 | 
| +        } else if (map == native_context_map) {
 | 
| +          // Native contexts have weak fields.
 | 
| +          IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj);
 | 
| +          ASSERT(!Marking::IsBlack(Marking::MarkBitFrom(obj)));
 | 
| +          MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
 | 
| +        } else if (map->instance_type() == FIXED_ARRAY_TYPE &&
 | 
| +          FixedArray::cast(obj)->length() >
 | 
| +                IncrementalMarkingMarkingVisitor::kScanningChunk) {
 | 
| +          MarkBit map_mark_bit = Marking::MarkBitFrom(map);
 | 
| +          if (Marking::IsWhite(map_mark_bit)) {
 | 
| +            WhiteToGreyAndPush(map, map_mark_bit);
 | 
| +          }
 | 
| +          MarkBit mark_bit = Marking::MarkBitFrom(obj);
 | 
| +          if (!Marking::IsBlack(mark_bit)) {
 | 
| +            MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
 | 
| +          } else {
 | 
| +            ASSERT(
 | 
| +                MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned());
 | 
| +          }
 | 
| +          IncrementalMarkingMarkingVisitor::VisitHugeArray(
 | 
| +                FixedArray::cast(obj));
 | 
| +         } else {
 | 
| +          MarkBit map_mark_bit = Marking::MarkBitFrom(map);
 | 
| +          if (Marking::IsWhite(map_mark_bit)) {
 | 
| +            WhiteToGreyAndPush(map, map_mark_bit);
 | 
| +          }
 | 
| +          IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
 | 
| +          ASSERT(!Marking::IsBlack(Marking::MarkBitFrom(obj)));
 | 
| +          MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
 | 
|          }
 | 
| -        IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
 | 
| +
 | 
| +        MarkBit mark_bit = Marking::MarkBitFrom(obj);
 | 
| +        Marking::MarkBlack(mark_bit);
 | 
|        }
 | 
| -
 | 
| -      MarkBit mark_bit = Marking::MarkBitFrom(obj);
 | 
| -      ASSERT(!Marking::IsBlack(mark_bit));
 | 
| -      Marking::MarkBlack(mark_bit);
 | 
| -      MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
 | 
| -    }
 | 
| -    state_ = COMPLETE;
 | 
| -    if (FLAG_trace_incremental_marking) {
 | 
| -      double end = OS::TimeCurrentMillis();
 | 
| -      PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n",
 | 
| -             static_cast<int>(end - start));
 | 
| -    }
 | 
| +      state_ = COMPLETE;
 | 
| +      if (FLAG_trace_incremental_marking) {
 | 
| +        double end = OS::TimeCurrentMillis();
 | 
| +        PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n",
 | 
| +               static_cast<int>(end - start));
 | 
| +      }
 | 
| +      FillMarkingDequeFromLargePostponedArrays();
 | 
| +    } while (!marking_deque_.IsEmpty());
 | 
|    }
 | 
|  
 | 
|    if (FLAG_cleanup_code_caches_at_gc) {
 | 
| @@ -794,42 +864,70 @@
 | 
|    } else if (state_ == MARKING) {
 | 
|      Map* filler_map = heap_->one_pointer_filler_map();
 | 
|      Map* native_context_map = heap_->native_context_map();
 | 
| -    while (!marking_deque_.IsEmpty() && bytes_to_process > 0) {
 | 
| -      HeapObject* obj = marking_deque_.Pop();
 | 
| +    while (true) {
 | 
| +      while (!marking_deque_.IsEmpty() && bytes_to_process > 0) {
 | 
| +        HeapObject* obj = marking_deque_.Pop();
 | 
|  
 | 
| -      // Explicitly skip one word fillers. Incremental markbit patterns are
 | 
| -      // correct only for objects that occupy at least two words.
 | 
| -      Map* map = obj->map();
 | 
| -      if (map == filler_map) continue;
 | 
| +        // Explicitly skip one word fillers. Incremental markbit patterns are
 | 
| +        // correct only for objects that occupy at least two words.
 | 
| +        Map* map = obj->map();
 | 
| +        if (map == filler_map) continue;
 | 
|  
 | 
| -      int size = obj->SizeFromMap(map);
 | 
| -      bytes_to_process -= size;
 | 
| -      MarkBit map_mark_bit = Marking::MarkBitFrom(map);
 | 
| -      if (Marking::IsWhite(map_mark_bit)) {
 | 
| -        WhiteToGreyAndPush(map, map_mark_bit);
 | 
| -      }
 | 
| +        int size = obj->SizeFromMap(map);
 | 
| +        MarkBit map_mark_bit = Marking::MarkBitFrom(map);
 | 
| +        if (Marking::IsWhite(map_mark_bit)) {
 | 
| +          WhiteToGreyAndPush(map, map_mark_bit);
 | 
| +        }
 | 
|  
 | 
| -      // TODO(gc) switch to static visitor instead of normal visitor.
 | 
| -      if (map == native_context_map) {
 | 
| -        // Native contexts have weak fields.
 | 
| -        Context* ctx = Context::cast(obj);
 | 
| +        // TODO(gc) switch to static visitor instead of normal visitor.
 | 
| +        if (map == native_context_map) {
 | 
| +          // Native contexts have weak fields.
 | 
| +          Context* ctx = Context::cast(obj);
 | 
|  
 | 
| -        // We will mark cache black with a separate pass
 | 
| -        // when we finish marking.
 | 
| -        MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache());
 | 
| +          // We will mark cache black with a separate pass
 | 
| +          // when we finish marking.
 | 
| +          MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache());
 | 
|  
 | 
| -        IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx);
 | 
| -      } else {
 | 
| -        IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
 | 
| +          IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx);
 | 
| +          bytes_to_process -= size;
 | 
| +          SLOW_ASSERT(Marking::IsGrey(Marking::MarkBitFrom(obj)));
 | 
| +          MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size);
 | 
| +        } else if (map->instance_type() == FIXED_ARRAY_TYPE &&
 | 
| +          FixedArray::cast(obj)->length() >
 | 
| +              IncrementalMarkingMarkingVisitor::kScanningChunk) {
 | 
| +          SLOW_ASSERT(
 | 
| +              Marking::IsGrey(Marking::MarkBitFrom(obj)) ||
 | 
| +              MemoryChunk::FromAddress(obj->address())->IsPartiallyScanned());
 | 
| +          bytes_to_process -=
 | 
| +              IncrementalMarkingMarkingVisitor::VisitHugeArray(
 | 
| +                  FixedArray::cast(obj));
 | 
| +          MarkBit obj_mark_bit = Marking::MarkBitFrom(obj);
 | 
| +          if (!Marking::IsBlack(obj_mark_bit)) {
 | 
| +            MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size);
 | 
| +          }
 | 
| +         } else {
 | 
| +          IncrementalMarkingMarkingVisitor::IterateBody(map, obj);
 | 
| +          bytes_to_process -= size;
 | 
| +          SLOW_ASSERT(
 | 
| +              Marking::IsGrey(Marking::MarkBitFrom(obj)) ||
 | 
| +              (obj->IsFiller() && Marking::IsWhite(Marking::MarkBitFrom(obj))));
 | 
| +          MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size);
 | 
| +        }
 | 
| +
 | 
| +        MarkBit obj_mark_bit = Marking::MarkBitFrom(obj);
 | 
| +        Marking::MarkBlack(obj_mark_bit);
 | 
|        }
 | 
| -
 | 
| -      MarkBit obj_mark_bit = Marking::MarkBitFrom(obj);
 | 
| -      SLOW_ASSERT(Marking::IsGrey(obj_mark_bit) ||
 | 
| -                  (obj->IsFiller() && Marking::IsWhite(obj_mark_bit)));
 | 
| -      Marking::MarkBlack(obj_mark_bit);
 | 
| -      MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size);
 | 
| +      if (marking_deque_.IsEmpty()) {
 | 
| +        FillMarkingDequeFromLargePostponedArrays();
 | 
| +        if (marking_deque_.IsEmpty()) {
 | 
| +          MarkingComplete(action);
 | 
| +          break;
 | 
| +         }
 | 
| +       } else {
 | 
| +        ASSERT(bytes_to_process <= 0);
 | 
| +        break;
 | 
| +       }
 | 
|      }
 | 
| -    if (marking_deque_.IsEmpty()) MarkingComplete(action);
 | 
|    }
 | 
|  
 | 
|    allocated_ = 0;
 | 
| 
 |