hidden_string_(NULL),
gc_safe_size_of_old_object_(NULL),
total_regexp_code_generated_(0),
- tracer_(NULL),
+ tracer_(this),
high_survival_rate_period_length_(0),
promoted_objects_size_(0),
promotion_rate_(0),
max_alive_after_gc_(0),
min_in_mutator_(kMaxInt),
alive_after_last_gc_(0),
- last_gc_end_timestamp_(0.0),
+ last_gc_end_timestamp_(base::OS::TimeCurrentMillis()),
marking_time_(0.0),
sweeping_time_(0.0),
mark_compact_collector_(this),
bool next_gc_likely_to_collect_more = false;
- { GCTracer tracer(this, collector, gc_reason, collector_reason);
+ { tracer()->start(collector, gc_reason, collector_reason);
ASSERT(AllowHeapAllocation::IsAllowed());
DisallowHeapAllocation no_allocation_during_gc;
GarbageCollectionPrologue();
(collector == SCAVENGER) ? isolate_->counters()->gc_scavenger()
: isolate_->counters()->gc_compactor());
next_gc_likely_to_collect_more =
- PerformGarbageCollection(collector, &tracer, gc_callback_flags);
+ PerformGarbageCollection(collector, gc_callback_flags);
}
GarbageCollectionEpilogue();
+ tracer()->stop();
}
// Start incremental marking for the next cycle. The heap snapshot
bool Heap::PerformGarbageCollection(
GarbageCollector collector,
- GCTracer* tracer,
const v8::GCCallbackFlags gc_callback_flags) {
int freed_global_handles = 0;
{ GCCallbacksScope scope(this);
if (scope.CheckReenter()) {
AllowHeapAllocation allow_allocation;
- GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
+ GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags);
if (collector == MARK_COMPACTOR) {
// Perform mark-sweep with optional compaction.
- MarkCompact(tracer);
+ MarkCompact();
sweep_generation_++;
// Temporarily set the limit for case when PostGarbageCollectionProcessing
// allocates and triggers GC. The real limit is set at after
OldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), 0);
old_gen_exhausted_ = false;
} else {
- tracer_ = tracer;
Scavenge();
- tracer_ = NULL;
}
UpdateSurvivalStatistics(start_new_space_size);
gc_post_processing_depth_++;
{ AllowHeapAllocation allow_allocation;
- GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
+ GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL);
freed_global_handles =
isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
}
{ GCCallbacksScope scope(this);
if (scope.CheckReenter()) {
AllowHeapAllocation allow_allocation;
- GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
+ GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
}
-void Heap::MarkCompact(GCTracer* tracer) {
+void Heap::MarkCompact() {
gc_state_ = MARK_COMPACT;
LOG(isolate_, ResourceEvent("markcompact", "begin"));
uint64_t size_of_objects_before_gc = SizeOfObjects();
- mark_compact_collector_.Prepare(tracer);
+ mark_compact_collector_.Prepare();
ms_count_++;
double marking_time) {
double duration = end_time - start_time;
alive_after_last_gc_ = SizeOfObjects();
- bool first_gc = (last_gc_end_timestamp_ == 0);
last_gc_end_timestamp_ = end_time;
if (FLAG_print_cumulative_gc_stat) {
total_gc_time_ms_ += duration;
max_gc_pause_ = Max(max_gc_pause_, duration);
max_alive_after_gc_ = Max(max_alive_after_gc_, alive_after_last_gc_);
- if (!first_gc)
- min_in_mutator_ = Min(min_in_mutator_, spent_in_mutator);
+ min_in_mutator_ = Min(min_in_mutator_, spent_in_mutator);
} else if (FLAG_trace_gc_verbose) {
total_gc_time_ms_ += duration;
}
}
-GCTracer::GCTracer(Heap* heap,
- GarbageCollector collector,
- const char* gc_reason,
- const char* collector_reason)
+GCTracer::GCTracer(Heap* heap)
: start_time_(0.0),
end_time_(0.0),
start_object_size_(0),
end_object_size_(0),
start_memory_size_(0),
end_memory_size_(0),
- collector_(collector),
+ in_free_list_or_wasted_before_gc_(0),
allocated_since_last_gc_(0),
spent_in_mutator_(0),
+ steps_count_(0),
+ steps_took_(0.0),
+ longest_step_(0.0),
+ steps_count_since_last_gc_(0),
+ steps_took_since_last_gc_(0.0),
heap_(heap),
- gc_reason_(gc_reason),
- collector_reason_(collector_reason) {
+ gc_reason_(NULL),
+ collector_reason_(NULL) {
+ for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
+ scopes_[i] = 0;
+ }
+}
+
+
+void GCTracer::start(GarbageCollector collector,
+ const char* gc_reason,
+ const char* collector_reason) {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
+ collector_ = collector;
+ gc_reason_ = gc_reason;
+ collector_reason_ = collector_reason;
+
start_time_ = base::OS::TimeCurrentMillis();
start_object_size_ = heap_->SizeOfObjects();
start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
scopes_[i] = 0;
}
- in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(heap);
+ in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(heap_);
allocated_since_last_gc_ =
heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
- if (heap_->last_gc_end_timestamp_ > 0) {
- spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
- }
+ spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
steps_count_ = heap_->incremental_marking()->steps_count();
steps_took_ = heap_->incremental_marking()->steps_took();
}
-GCTracer::~GCTracer() {
+void GCTracer::stop() {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
end_time_ = base::OS::TimeCurrentMillis();
V(intl_impl_object_string, "v8::intl_object")
// Forward declarations.
-class GCTracer;
class HeapStats;
class Isolate;
class WeakObjectRetainer;
};
+// GCTracer collects and prints ONE line after each garbage collector
+// invocation IFF --trace_gc is used.
+
+class GCTracer BASE_EMBEDDED {
+ public:
+ class Scope BASE_EMBEDDED {
+ public:
+ enum ScopeId {
+ EXTERNAL,
+ MC_MARK,
+ MC_SWEEP,
+ MC_SWEEP_NEWSPACE,
+ MC_SWEEP_OLDSPACE,
+ MC_SWEEP_CODE,
+ MC_SWEEP_CELL,
+ MC_SWEEP_MAP,
+ MC_EVACUATE_PAGES,
+ MC_UPDATE_NEW_TO_NEW_POINTERS,
+ MC_UPDATE_ROOT_TO_NEW_POINTERS,
+ MC_UPDATE_OLD_TO_NEW_POINTERS,
+ MC_UPDATE_POINTERS_TO_EVACUATED,
+ MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
+ MC_UPDATE_MISC_POINTERS,
+ MC_WEAKCOLLECTION_PROCESS,
+ MC_WEAKCOLLECTION_CLEAR,
+ MC_FLUSH_CODE,
+ NUMBER_OF_SCOPES
+ };
+
+ Scope(GCTracer* tracer, ScopeId scope)
+ : tracer_(tracer),
+ scope_(scope) {
+ start_time_ = base::OS::TimeCurrentMillis();
+ }
+
+ ~Scope() {
+ ASSERT(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
+ tracer_->scopes_[scope_] += base::OS::TimeCurrentMillis() - start_time_;
+ }
+
+ private:
+ GCTracer* tracer_;
+ ScopeId scope_;
+ double start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(Scope);
+ };
+
+ explicit GCTracer(Heap* heap);
+
+ // Start collecting data.
+ void start(GarbageCollector collector,
+ const char* gc_reason,
+ const char* collector_reason);
+
+ // Stop collecting data and print results.
+ void stop();
+
+ private:
+ // Returns a string matching the collector.
+ const char* CollectorString() const;
+
+ // Print one detailed trace line in name=value format.
+ void PrintNVP() const;
+
+ // Print one trace line.
+ void Print() const;
+
+ // Timestamp set in the constructor.
+ double start_time_;
+
+ // Timestamp set in the destructor.
+ double end_time_;
+
+ // Size of objects in heap set in constructor.
+ intptr_t start_object_size_;
+
+ // Size of objects in heap set in destructor.
+ intptr_t end_object_size_;
+
+ // Size of memory allocated from OS set in constructor.
+ intptr_t start_memory_size_;
+
+ // Size of memory allocated from OS set in destructor.
+ intptr_t end_memory_size_;
+
+ // Type of collector.
+ GarbageCollector collector_;
+
+ // Amounts of time spent in different scopes during GC.
+ double scopes_[Scope::NUMBER_OF_SCOPES];
+
+ // Total amount of space either wasted or contained in one of free lists
+ // before the current GC.
+ intptr_t in_free_list_or_wasted_before_gc_;
+
+ // Difference between space used in the heap at the beginning of the current
+ // collection and the end of the previous collection.
+ intptr_t allocated_since_last_gc_;
+
+ // Amount of time spent in mutator that is time elapsed between end of the
+ // previous collection and the beginning of the current one.
+ double spent_in_mutator_;
+
+ // Incremental marking steps counters.
+ int steps_count_;
+ double steps_took_;
+ double longest_step_;
+ int steps_count_since_last_gc_;
+ double steps_took_since_last_gc_;
+
+ Heap* heap_;
+
+ const char* gc_reason_;
+ const char* collector_reason_;
+
+ DISALLOW_COPY_AND_ASSIGN(GCTracer);
+};
+
+
class Heap {
public:
// Configure heap size in MB before setup. Return false if the heap has been
void ClearNormalizedMapCaches();
- GCTracer* tracer() { return tracer_; }
+ GCTracer* tracer() { return &tracer_; }
// Returns the size of objects residing in non new spaces.
intptr_t PromotedSpaceSizeOfObjects();
// collect more garbage.
bool PerformGarbageCollection(
GarbageCollector collector,
- GCTracer* tracer,
const GCCallbackFlags gc_callback_flags = kNoGCCallbackFlags);
inline void UpdateOldSpaceLimits();
StoreBufferEvent event);
// Performs a major collection in the whole heap.
- void MarkCompact(GCTracer* tracer);
+ void MarkCompact();
// Code to be run before and after mark-compact.
void MarkCompactPrologue();
// Total RegExp code ever generated
double total_regexp_code_generated_;
- GCTracer* tracer_;
+ GCTracer tracer_;
// Creates and installs the full-sized number string cache.
int FullSizeNumberStringCacheLength();
};
-// GCTracer collects and prints ONE line after each garbage collector
-// invocation IFF --trace_gc is used.
-
-class GCTracer BASE_EMBEDDED {
- public:
- class Scope BASE_EMBEDDED {
- public:
- enum ScopeId {
- EXTERNAL,
- MC_MARK,
- MC_SWEEP,
- MC_SWEEP_NEWSPACE,
- MC_SWEEP_OLDSPACE,
- MC_SWEEP_CODE,
- MC_SWEEP_CELL,
- MC_SWEEP_MAP,
- MC_EVACUATE_PAGES,
- MC_UPDATE_NEW_TO_NEW_POINTERS,
- MC_UPDATE_ROOT_TO_NEW_POINTERS,
- MC_UPDATE_OLD_TO_NEW_POINTERS,
- MC_UPDATE_POINTERS_TO_EVACUATED,
- MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
- MC_UPDATE_MISC_POINTERS,
- MC_WEAKCOLLECTION_PROCESS,
- MC_WEAKCOLLECTION_CLEAR,
- MC_FLUSH_CODE,
- NUMBER_OF_SCOPES
- };
-
- Scope(GCTracer* tracer, ScopeId scope)
- : tracer_(tracer),
- scope_(scope) {
- start_time_ = base::OS::TimeCurrentMillis();
- }
-
- ~Scope() {
- ASSERT(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
- tracer_->scopes_[scope_] += base::OS::TimeCurrentMillis() - start_time_;
- }
-
- private:
- GCTracer* tracer_;
- ScopeId scope_;
- double start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(Scope);
- };
-
- explicit GCTracer(Heap* heap,
- GarbageCollector collector,
- const char* gc_reason,
- const char* collector_reason);
- ~GCTracer();
-
- private:
- // Returns a string matching the collector.
- const char* CollectorString() const;
-
- // Print one detailed trace line in name=value format.
- void PrintNVP() const;
-
- // Print one trace line.
- void Print() const;
-
- // Timestamp set in the constructor.
- double start_time_;
-
- // Timestamp set in the destructor.
- double end_time_;
-
- // Size of objects in heap set in constructor.
- intptr_t start_object_size_;
-
- // Size of objects in heap set in destructor.
- intptr_t end_object_size_;
-
- // Size of memory allocated from OS set in constructor.
- intptr_t start_memory_size_;
-
- // Size of memory allocated from OS set in destructor.
- intptr_t end_memory_size_;
-
- // Type of collector.
- GarbageCollector collector_;
-
- // Amounts of time spent in different scopes during GC.
- double scopes_[Scope::NUMBER_OF_SCOPES];
-
- // Total amount of space either wasted or contained in one of free lists
- // before the current GC.
- intptr_t in_free_list_or_wasted_before_gc_;
-
- // Difference between space used in the heap at the beginning of the current
- // collection and the end of the previous collection.
- intptr_t allocated_since_last_gc_;
-
- // Amount of time spent in mutator that is time elapsed between end of the
- // previous collection and the beginning of the current one.
- double spent_in_mutator_;
-
- // Incremental marking steps counters.
- int steps_count_;
- double steps_took_;
- double longest_step_;
- int steps_count_since_last_gc_;
- double steps_took_since_last_gc_;
-
- Heap* heap_;
-
- const char* gc_reason_;
- const char* collector_reason_;
-
- DISALLOW_COPY_AND_ASSIGN(GCTracer);
-};
-
-
class RegExpResultsCache {
public:
enum ResultsCacheType { REGEXP_MULTIPLE_INDICES, STRING_SPLIT_SUBSTRINGS };
sweeping_in_progress_(false),
pending_sweeper_jobs_semaphore_(0),
sequential_sweeping_(false),
- tracer_(NULL),
migration_slots_buffer_(NULL),
heap_(heap),
code_flusher_(NULL),
ASSERT(marking_parity_ == ODD_MARKING_PARITY);
marking_parity_ = EVEN_MARKING_PARITY;
}
-
- tracer_ = NULL;
}
}
-void MarkCompactCollector::Prepare(GCTracer* tracer) {
+void MarkCompactCollector::Prepare() {
was_marked_incrementally_ = heap()->incremental_marking()->IsMarking();
- // Rather than passing the tracer around we stash it in a static member
- // variable.
- tracer_ = tracer;
-
#ifdef DEBUG
ASSERT(state_ == IDLE);
state_ = PREPARE_GC;
void MarkCompactCollector::MarkLiveObjects() {
- GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_MARK);
+ GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_MARK);
// The recursive GC marker detects when it is nearing stack overflow,
// and switches to a different marking system. JS interrupts interfere
// with the C stack limit check.
void MarkCompactCollector::ProcessWeakCollections() {
- GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_WEAKCOLLECTION_PROCESS);
+ GCTracer::Scope gc_scope(heap()->tracer(),
+ GCTracer::Scope::MC_WEAKCOLLECTION_PROCESS);
Object* weak_collection_obj = heap()->encountered_weak_collections();
while (weak_collection_obj != Smi::FromInt(0)) {
JSWeakCollection* weak_collection =
void MarkCompactCollector::ClearWeakCollections() {
- GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_WEAKCOLLECTION_CLEAR);
+ GCTracer::Scope gc_scope(heap()->tracer(),
+ GCTracer::Scope::MC_WEAKCOLLECTION_CLEAR);
Object* weak_collection_obj = heap()->encountered_weak_collections();
while (weak_collection_obj != Smi::FromInt(0)) {
JSWeakCollection* weak_collection =
Heap::RelocationLock relocation_lock(heap());
bool code_slots_filtering_required;
- { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE);
+ { GCTracer::Scope gc_scope(heap()->tracer(),
+ GCTracer::Scope::MC_SWEEP_NEWSPACE);
code_slots_filtering_required = MarkInvalidatedCode();
EvacuateNewSpace();
}
- { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_EVACUATE_PAGES);
+ { GCTracer::Scope gc_scope(heap()->tracer(),
+ GCTracer::Scope::MC_EVACUATE_PAGES);
EvacuatePages();
}
// Second pass: find pointers to new space and update them.
PointersUpdatingVisitor updating_visitor(heap());
- { GCTracer::Scope gc_scope(tracer_,
+ { GCTracer::Scope gc_scope(heap()->tracer(),
GCTracer::Scope::MC_UPDATE_NEW_TO_NEW_POINTERS);
// Update pointers in to space.
SemiSpaceIterator to_it(heap()->new_space()->bottom(),
}
}
- { GCTracer::Scope gc_scope(tracer_,
+ { GCTracer::Scope gc_scope(heap()->tracer(),
GCTracer::Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS);
// Update roots.
heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
}
- { GCTracer::Scope gc_scope(tracer_,
+ { GCTracer::Scope gc_scope(heap()->tracer(),
GCTracer::Scope::MC_UPDATE_OLD_TO_NEW_POINTERS);
StoreBufferRebuildScope scope(heap_,
heap_->store_buffer(),
&UpdatePointer);
}
- { GCTracer::Scope gc_scope(tracer_,
+ { GCTracer::Scope gc_scope(heap()->tracer(),
GCTracer::Scope::MC_UPDATE_POINTERS_TO_EVACUATED);
SlotsBuffer::UpdateSlotsRecordedIn(heap_,
migration_slots_buffer_,
int npages = evacuation_candidates_.length();
{ GCTracer::Scope gc_scope(
- tracer_, GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED);
+ heap()->tracer(), GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED);
for (int i = 0; i < npages; i++) {
Page* p = evacuation_candidates_[i];
ASSERT(p->IsEvacuationCandidate() ||
}
}
- GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_UPDATE_MISC_POINTERS);
+ GCTracer::Scope gc_scope(heap()->tracer(),
+ GCTracer::Scope::MC_UPDATE_MISC_POINTERS);
// Update pointers from cells.
HeapObjectIterator cell_iterator(heap_->cell_space());
void MarkCompactCollector::SweepSpaces() {
- GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP);
+ GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_SWEEP);
#ifdef DEBUG
state_ = SWEEP_SPACES;
#endif
// the map space last because freeing non-live maps overwrites them and
// the other spaces rely on possibly non-live maps to get the sizes for
// non-live objects.
- { GCTracer::Scope sweep_scope(tracer_, GCTracer::Scope::MC_SWEEP_OLDSPACE);
+ { GCTracer::Scope sweep_scope(heap()->tracer(),
+ GCTracer::Scope::MC_SWEEP_OLDSPACE);
{ SequentialSweepingScope scope(this);
SweepSpace(heap()->old_pointer_space(), how_to_sweep);
SweepSpace(heap()->old_data_space(), how_to_sweep);
}
RemoveDeadInvalidatedCode();
- { GCTracer::Scope sweep_scope(tracer_, GCTracer::Scope::MC_SWEEP_CODE);
+ { GCTracer::Scope sweep_scope(heap()->tracer(),
+ GCTracer::Scope::MC_SWEEP_CODE);
SweepSpace(heap()->code_space(), PRECISE);
}
- { GCTracer::Scope sweep_scope(tracer_, GCTracer::Scope::MC_SWEEP_CELL);
+ { GCTracer::Scope sweep_scope(heap()->tracer(),
+ GCTracer::Scope::MC_SWEEP_CELL);
SweepSpace(heap()->cell_space(), PRECISE);
SweepSpace(heap()->property_cell_space(), PRECISE);
}
// ClearNonLiveTransitions depends on precise sweeping of map space to
// detect whether unmarked map became dead in this collection or in one
// of the previous ones.
- { GCTracer::Scope sweep_scope(tracer_, GCTracer::Scope::MC_SWEEP_MAP);
+ { GCTracer::Scope sweep_scope(heap()->tracer(),
+ GCTracer::Scope::MC_SWEEP_MAP);
SweepSpace(heap()->map_space(), PRECISE);
}
// Forward declarations.
class CodeFlusher;
-class GCTracer;
class MarkCompactCollector;
class MarkingVisitor;
class RootMarkingVisitor;
// Prepares for GC by resetting relocation info in old and map spaces and
// choosing spaces to compact.
- void Prepare(GCTracer* tracer);
+ void Prepare();
// Performs a global garbage collection.
void CollectGarbage();
void AbortCompaction();
- // During a full GC, there is a stack-allocated GCTracer that is used for
- // bookkeeping information. Return a pointer to that tracer.
- GCTracer* tracer() { return tracer_; }
-
#ifdef DEBUG
// Checks whether performing mark-compact collection.
bool in_use() { return state_ > PREPARE_GC; }
bool sequential_sweeping_;
- // A pointer to the current stack-allocated GC tracer object during a full
- // collection (NULL before and after).
- GCTracer* tracer_;
-
SlotsBufferAllocator slots_buffer_allocator_;
SlotsBuffer* migration_slots_buffer_;