| Index: src/heap.cc
|
| ===================================================================
|
| --- src/heap.cc (revision 9457)
|
| +++ src/heap.cc (working copy)
|
| @@ -92,6 +92,7 @@
|
| sweep_generation_(0),
|
| always_allocate_scope_depth_(0),
|
| linear_allocation_scope_depth_(0),
|
| + visualizer_(NULL),
|
| contexts_disposed_(0),
|
| scan_on_scavenge_pages_(0),
|
| new_space_(this),
|
| @@ -359,7 +360,10 @@
|
| }
|
|
|
|
|
| -void Heap::GarbageCollectionPrologue() {
|
| +void Heap::GarbageCollectionPrologue(GarbageCollector collector) {
|
| + VisualizerTimeStamp(collector == SCAVENGER ?
|
| + HeapVisualizer::kScavenging :
|
| + HeapVisualizer::kMarking);
|
| isolate_->transcendental_cache()->Clear();
|
| ClearJSFunctionResultCaches();
|
| gc_count_++;
|
| @@ -383,6 +387,7 @@
|
| store_buffer()->GCPrologue();
|
| }
|
|
|
| +
|
| intptr_t Heap::SizeOfObjects() {
|
| intptr_t total = 0;
|
| AllSpaces spaces;
|
| @@ -422,6 +427,10 @@
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| isolate_->debug()->AfterGarbageCollection();
|
| #endif // ENABLE_DEBUGGER_SUPPORT
|
| + VisualizerTimeStamp(HeapVisualizer::kRunning);
|
| + for (HeapVisualizer* vis = visualizer(); vis != NULL; vis = vis->next()) {
|
| + UpdateHeapVisualizer(vis, new_space());
|
| + }
|
| }
|
|
|
|
|
| @@ -491,7 +500,7 @@
|
| bool next_gc_likely_to_collect_more = false;
|
|
|
| { GCTracer tracer(this);
|
| - GarbageCollectionPrologue();
|
| + GarbageCollectionPrologue(collector);
|
| // The GC count was incremented in the prologue. Tell the tracer about
|
| // it.
|
| tracer.set_gc_count(gc_count_);
|
| @@ -6393,6 +6402,248 @@
|
| }
|
|
|
|
|
| +static void HandleRange(uintptr_t* allocated_bytes,
|
| + int pixel_size_log_2,
|
| + uintptr_t page_address,
|
| + uintptr_t object_start,
|
| + uintptr_t object_size) {
|
| + uintptr_t pixel_size = 1 << pixel_size_log_2;
|
| + int start_pixel = (object_start - page_address) >> pixel_size_log_2;
|
| + int end_pixel =
|
| + (object_start + object_size - page_address) >> pixel_size_log_2;
|
| + if (start_pixel != end_pixel) {
|
| + int on_first_page = pixel_size - (object_start & (pixel_size - 1));
|
| + allocated_bytes[start_pixel++] += on_first_page;
|
| + object_size -= on_first_page;
|
| + object_start += on_first_page;
|
| + while (start_pixel != end_pixel) {
|
| + allocated_bytes[start_pixel++] += pixel_size;
|
| + object_size -= pixel_size;
|
| + object_start += pixel_size;
|
| + }
|
| + }
|
| + allocated_bytes[start_pixel] += object_size;
|
| +}
|
| +
|
| +
|
| +void Heap::UpdateHeapVisualizer(HeapVisualizer* visualizer, NewSpace* space) {
|
| + SemiSpace* semi_space = space->active_space();
|
| +
|
| + Address top = space->top();
|
| + NewSpacePage* top_page = NewSpacePage::FromLimit(top);
|
| + bool allocated = true;
|
| + for (NewSpacePage* page = semi_space->first_page();
|
| + !page->is_anchor();
|
| + page = page->next_page()) {
|
| + uintptr_t page_address = reinterpret_cast<uintptr_t>(page->address());
|
| + uintptr_t address = reinterpret_cast<uintptr_t>(page->ObjectAreaStart());
|
| + uintptr_t end = reinterpret_cast<uintptr_t>(page->ObjectAreaEnd());
|
| + int overhead_size = address - page_address;
|
| + visualizer->Name(HeapVisualizer::kHeapOverheadPseudoSpaceIdentity,
|
| + page_address,
|
| + overhead_size);
|
| + visualizer->ConstantAllocation(page_address, overhead_size, 0);
|
| + Address age_mark = space->to_space_age_mark();
|
| + if (page->ObjectAreaStart() <= age_mark &&
|
| + page->ObjectAreaEnd() > age_mark) {
|
| + visualizer->Name(HeapVisualizer::kSurvivingNewSpacePseudoSpaceIdentity,
|
| + address,
|
| + age_mark - page->ObjectAreaStart());
|
| + visualizer->Name(space->identity(),
|
| + reinterpret_cast<uintptr_t>(age_mark),
|
| + page->ObjectAreaEnd() - age_mark);
|
| + } else {
|
| + bool below_mark = page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK);
|
| + int space_id = below_mark ?
|
| + HeapVisualizer::kSurvivingNewSpacePseudoSpaceIdentity :
|
| + space->identity();
|
| + visualizer->Name(space_id, address, end - address);
|
| + }
|
| + if (page == top_page) {
|
| + int allocated_size = reinterpret_cast<uintptr_t>(top) - address;
|
| + allocated = false;
|
| + if (allocated_size != 0) {
|
| + uintptr_t size =
|
| + Max(allocated_size, 1 << visualizer->pixel_size_log_2());
|
| + visualizer->ConstantAllocation(address, size, 0);
|
| + }
|
| + }
|
| + if (allocated) {
|
| + visualizer->ConstantAllocation(address, end - address, 0);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +static void UpdateAllocation(HeapVisualizer* visualizer, Page* page) {
|
| + int pixel_size_log_2 = visualizer->pixel_size_log_2();
|
| + uint32_t page_address = reinterpret_cast<uintptr_t>(page->address());
|
| + uint32_t address = reinterpret_cast<uintptr_t>(page->ObjectAreaStart());
|
| + uintptr_t end = reinterpret_cast<uintptr_t>(page->ObjectAreaEnd());
|
| + int overhead_size = address - page_address;
|
| + visualizer->Name(HeapVisualizer::kHeapOverheadPseudoSpaceIdentity,
|
| + page_address,
|
| + overhead_size);
|
| + visualizer->ConstantAllocation(page_address, overhead_size, 0);
|
| +
|
| + visualizer->Name(page->owner()->identity(), address, end - address);
|
| + if (page->WasSwept()) {
|
| + uintptr_t pixel_size = 1 << pixel_size_log_2;
|
| + int pixels = ((end - address) >> pixel_size_log_2) + 1;
|
| + uintptr_t* allocated_bytes = new uintptr_t[pixels];
|
| + for (int i = 0; i < pixels; i++) {
|
| + allocated_bytes[i] = 0;
|
| + }
|
| + if (page->WasSweptPrecisely()) {
|
| + HeapObjectIterator iterator(page, NULL);
|
| + for (HeapObject* object = iterator.Next();
|
| + object != NULL; object = iterator.Next()) {
|
| + HandleRange(allocated_bytes,
|
| + pixel_size_log_2,
|
| + address,
|
| + reinterpret_cast<intptr_t>(object->address()),
|
| + object->Size());
|
| + }
|
| + } else {
|
| + FreeList* free_list =
|
| + reinterpret_cast<PagedSpace*>(page->owner())->free_list();
|
| + if (free_list->IsVeryLong()) {
|
| + // Make checker board pattern to indicate fragmentation.
|
| + for (int i = 0; i < pixels; i += 8) {
|
| + allocated_bytes[i] = pixel_size;
|
| + allocated_bytes[i + 1] = pixel_size;
|
| + allocated_bytes[i + 4] = pixel_size;
|
| + allocated_bytes[i + 5] = pixel_size;
|
| + }
|
| + } else {
|
| + FreeListNode* node;
|
| + for (int i = 0; i < FreeList::kNumberOfChains; i++) {
|
| + for (node = free_list->get_chain(i);
|
| + node != NULL;
|
| + node = node->next()) {
|
| + if (node->address() >= page->ObjectAreaStart() &&
|
| + node->address() < page->ObjectAreaEnd()) {
|
| + HandleRange(allocated_bytes,
|
| + pixel_size_log_2,
|
| + address,
|
| + reinterpret_cast<intptr_t>(node->address()),
|
| + node->Size());
|
| + }
|
| + }
|
| + }
|
| + }
|
| + for (int i = 0; i < pixels; i++) {
|
| + allocated_bytes[i] = pixel_size - allocated_bytes[i];
|
| + }
|
| + }
|
| + unsigned char* freeness = new unsigned char[pixels];
|
| + for (int i = 0; i < pixels; i++) {
|
| + if (allocated_bytes[i] == pixel_size) {
|
| + freeness[i] = 0;
|
| + } else {
|
| + freeness[i] = 255 - (allocated_bytes[i] >> (8 - pixel_size_log_2));
|
| + }
|
| + }
|
| + visualizer->Allocate(address, pixels, freeness);
|
| + delete[] allocated_bytes;
|
| + delete[] freeness;
|
| + }
|
| +}
|
| +
|
| +
|
| +void Heap::UpdateVisualizers(Page* page) {
|
| + for (HeapVisualizer* vis = visualizer(); vis != NULL; vis = vis->next()) {
|
| + UpdateAllocation(vis, page);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Heap::VisualizeCrankshaft() {
|
| + VisualizerTimeStamp(HeapVisualizer::kCrankshafting);
|
| +}
|
| +
|
| +
|
| +static void VisualizeAllocationTop(PagedSpace* space) {
|
| + space->SetTop(space->top(), space->limit());
|
| +}
|
| +
|
| +
|
| +void Heap::VisualizeCrankshaftDone() {
|
| + VisualizeAllocationTop(old_data_space());
|
| + VisualizeAllocationTop(old_pointer_space());
|
| + VisualizeAllocationTop(map_space());
|
| + VisualizeAllocationTop(cell_space());
|
| + VisualizeAllocationTop(code_space());
|
| + new_space()->VisualizeTop();
|
| + VisualizerTimeStamp(HeapVisualizer::kRunning);
|
| +}
|
| +
|
| +
|
| +void Heap::VisualizerTimeStamp(HeapVisualizer::ProfileState state) {
|
| + uint32_t secs, usecs;
|
| + OS::GetUserTime(&secs, &usecs);
|
| + for (HeapVisualizer* vis = visualizer(); vis != NULL; vis = vis->next()) {
|
| + if (vis->secs_zero() == 0) {
|
| + vis->set_time_zero(secs, usecs);
|
| + }
|
| + if (usecs < vis->usecs_zero()) {
|
| + usecs += 1000000;
|
| + secs -= 1;
|
| + }
|
| + vis->TimeStamp(state, secs - vis->secs_zero(), usecs - vis->usecs_zero());
|
| + vis->Flush();
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| +void Heap::UpdateHeapVisualizer(HeapVisualizer* visualizer, PagedSpace* space) {
|
| + // Update the other visualizers (not the new one) with the latest allocation
|
| + // events.
|
| + space->SetTop(space->top(), space->limit());
|
| +
|
| + PageIterator pages(space);
|
| + while (pages.has_next()) {
|
| + Page* page = pages.next();
|
| + UpdateAllocation(visualizer, page);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Heap::UpdateHeapVisualizer(
|
| + HeapVisualizer* visualizer, LargeObjectSpace* space) {
|
| + LargeObjectIterator it(space);
|
| + for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
|
| + MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
|
| + int space_id = OLD_DATA_SPACE;
|
| + if (object->IsCode()) space_id = CODE_SPACE;
|
| + if (object->IsFixedArray()) space_id = OLD_POINTER_SPACE;
|
| + visualizer->Name(HeapVisualizer::kHeapOverheadPseudoSpaceIdentity,
|
| + reinterpret_cast<uint32_t>(chunk->address()),
|
| + object->address() - chunk->address());
|
| + visualizer->Name(space_id,
|
| + reinterpret_cast<intptr_t>(object->address()),
|
| + object->Size());
|
| + visualizer->ConstantAllocation(
|
| + reinterpret_cast<uint32_t>(chunk->address()),
|
| + object->address() - chunk->address() + object->Size(),
|
| + 0);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Heap::UpdateVisualizer(HeapVisualizer* visualizer) {
|
| + UpdateHeapVisualizer(visualizer, old_data_space());
|
| + UpdateHeapVisualizer(visualizer, old_pointer_space());
|
| + UpdateHeapVisualizer(visualizer, map_space());
|
| + UpdateHeapVisualizer(visualizer, cell_space());
|
| + UpdateHeapVisualizer(visualizer, code_space());
|
| + UpdateHeapVisualizer(visualizer, lo_space());
|
| + UpdateHeapVisualizer(visualizer, new_space());
|
| + visualizer->Flush();
|
| +}
|
| +
|
| +
|
| void TranscendentalCache::Clear() {
|
| for (int i = 0; i < kNumberOfCaches; i++) {
|
| if (caches_[i] != NULL) {
|
| @@ -6473,6 +6724,13 @@
|
| isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
|
| for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
|
| next = chunk->next_chunk();
|
| + for (HeapVisualizer* vis = isolate_->heap()->visualizer();
|
| + vis != NULL;
|
| + vis = vis->next()) {
|
| + vis->ConstantAllocation(reinterpret_cast<uintptr_t>(chunk->address()),
|
| + chunk->size(),
|
| + 255);
|
| + }
|
| isolate_->memory_allocator()->Free(chunk);
|
| }
|
| chunks_queued_for_free_ = NULL;
|
|
|