Index: src/heap.cc |
=================================================================== |
--- src/heap.cc (revision 7267) |
+++ src/heap.cc (working copy) |
@@ -50,119 +50,110 @@ |
#include "arm/regexp-macro-assembler-arm.h" |
#endif |
- |
namespace v8 { |
namespace internal { |
-String* Heap::hidden_symbol_; |
-Object* Heap::roots_[Heap::kRootListLength]; |
-Object* Heap::global_contexts_list_; |
- |
- |
-NewSpace Heap::new_space_; |
-OldSpace* Heap::old_pointer_space_ = NULL; |
-OldSpace* Heap::old_data_space_ = NULL; |
-OldSpace* Heap::code_space_ = NULL; |
-MapSpace* Heap::map_space_ = NULL; |
-CellSpace* Heap::cell_space_ = NULL; |
-LargeObjectSpace* Heap::lo_space_ = NULL; |
- |
static const intptr_t kMinimumPromotionLimit = 2 * MB; |
static const intptr_t kMinimumAllocationLimit = 8 * MB; |
-intptr_t Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit; |
-intptr_t Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit; |
-int Heap::old_gen_exhausted_ = false; |
+static Mutex* gc_initializer_mutex = OS::CreateMutex(); |
-int Heap::amount_of_external_allocated_memory_ = 0; |
-int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0; |
+Heap::Heap() |
+ : isolate_(NULL), |
// semispace_size_ should be a power of 2 and old_generation_size_ should be |
// a multiple of Page::kPageSize. |
#if defined(ANDROID) |
-static const int default_max_semispace_size_ = 2*MB; |
-intptr_t Heap::max_old_generation_size_ = 192*MB; |
-int Heap::initial_semispace_size_ = 128*KB; |
-intptr_t Heap::code_range_size_ = 0; |
-intptr_t Heap::max_executable_size_ = max_old_generation_size_; |
+ reserved_semispace_size_(2*MB), |
+ max_semispace_size_(2*MB), |
+ initial_semispace_size_(128*KB), |
+ max_old_generation_size_(192*MB), |
+ max_executable_size_(max_old_generation_size_), |
+ code_range_size_(0), |
#elif defined(V8_TARGET_ARCH_X64) |
-static const int default_max_semispace_size_ = 16*MB; |
-intptr_t Heap::max_old_generation_size_ = 1*GB; |
-int Heap::initial_semispace_size_ = 1*MB; |
-intptr_t Heap::code_range_size_ = 512*MB; |
-intptr_t Heap::max_executable_size_ = 256*MB; |
+ reserved_semispace_size_(16*MB), |
+ max_semispace_size_(16*MB), |
+ initial_semispace_size_(1*MB), |
+ max_old_generation_size_(1*GB), |
+ max_executable_size_(256*MB), |
+ code_range_size_(512*MB), |
#else |
-static const int default_max_semispace_size_ = 8*MB; |
-intptr_t Heap::max_old_generation_size_ = 512*MB; |
-int Heap::initial_semispace_size_ = 512*KB; |
-intptr_t Heap::code_range_size_ = 0; |
-intptr_t Heap::max_executable_size_ = 128*MB; |
+ reserved_semispace_size_(8*MB), |
+ max_semispace_size_(8*MB), |
+ initial_semispace_size_(512*KB), |
+ max_old_generation_size_(512*MB), |
+ max_executable_size_(128*MB), |
+ code_range_size_(0), |
#endif |
- |
-// Allow build-time customization of the max semispace size. Building |
-// V8 with snapshots and a non-default max semispace size is much |
-// easier if you can define it as part of the build environment. |
-#if defined(V8_MAX_SEMISPACE_SIZE) |
-int Heap::max_semispace_size_ = V8_MAX_SEMISPACE_SIZE; |
-#else |
-int Heap::max_semispace_size_ = default_max_semispace_size_; |
-#endif |
- |
-// The snapshot semispace size will be the default semispace size if |
-// snapshotting is used and will be the requested semispace size as |
-// set up by ConfigureHeap otherwise. |
-int Heap::reserved_semispace_size_ = Heap::max_semispace_size_; |
- |
-List<Heap::GCPrologueCallbackPair> Heap::gc_prologue_callbacks_; |
-List<Heap::GCEpilogueCallbackPair> Heap::gc_epilogue_callbacks_; |
- |
-GCCallback Heap::global_gc_prologue_callback_ = NULL; |
-GCCallback Heap::global_gc_epilogue_callback_ = NULL; |
-HeapObjectCallback Heap::gc_safe_size_of_old_object_ = NULL; |
- |
// Variables set based on semispace_size_ and old_generation_size_ in |
-// ConfigureHeap. |
- |
+// ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_) |
// Will be 4 * reserved_semispace_size_ to ensure that young |
// generation can be aligned to its size. |
-int Heap::survived_since_last_expansion_ = 0; |
-intptr_t Heap::external_allocation_limit_ = 0; |
- |
-Heap::HeapState Heap::gc_state_ = NOT_IN_GC; |
- |
-int Heap::mc_count_ = 0; |
-int Heap::ms_count_ = 0; |
-unsigned int Heap::gc_count_ = 0; |
- |
-GCTracer* Heap::tracer_ = NULL; |
- |
-int Heap::unflattened_strings_length_ = 0; |
- |
-int Heap::always_allocate_scope_depth_ = 0; |
-int Heap::linear_allocation_scope_depth_ = 0; |
-int Heap::contexts_disposed_ = 0; |
- |
-int Heap::young_survivors_after_last_gc_ = 0; |
-int Heap::high_survival_rate_period_length_ = 0; |
-double Heap::survival_rate_ = 0; |
-Heap::SurvivalRateTrend Heap::previous_survival_rate_trend_ = Heap::STABLE; |
-Heap::SurvivalRateTrend Heap::survival_rate_trend_ = Heap::STABLE; |
- |
+ survived_since_last_expansion_(0), |
+ always_allocate_scope_depth_(0), |
+ linear_allocation_scope_depth_(0), |
+ contexts_disposed_(0), |
+ new_space_(this), |
+ old_pointer_space_(NULL), |
+ old_data_space_(NULL), |
+ code_space_(NULL), |
+ map_space_(NULL), |
+ cell_space_(NULL), |
+ lo_space_(NULL), |
+ gc_state_(NOT_IN_GC), |
+ mc_count_(0), |
+ ms_count_(0), |
+ gc_count_(0), |
+ unflattened_strings_length_(0), |
#ifdef DEBUG |
-bool Heap::allocation_allowed_ = true; |
- |
-int Heap::allocation_timeout_ = 0; |
-bool Heap::disallow_allocation_failure_ = false; |
+ allocation_allowed_(true), |
+ allocation_timeout_(0), |
+ disallow_allocation_failure_(false), |
+ debug_utils_(NULL), |
#endif // DEBUG |
+ old_gen_promotion_limit_(kMinimumPromotionLimit), |
+ old_gen_allocation_limit_(kMinimumAllocationLimit), |
+ external_allocation_limit_(0), |
+ amount_of_external_allocated_memory_(0), |
+ amount_of_external_allocated_memory_at_last_global_gc_(0), |
+ old_gen_exhausted_(false), |
+ hidden_symbol_(NULL), |
+ global_gc_prologue_callback_(NULL), |
+ global_gc_epilogue_callback_(NULL), |
+ gc_safe_size_of_old_object_(NULL), |
+ tracer_(NULL), |
+ young_survivors_after_last_gc_(0), |
+ high_survival_rate_period_length_(0), |
+ survival_rate_(0), |
+ previous_survival_rate_trend_(Heap::STABLE), |
+ survival_rate_trend_(Heap::STABLE), |
+ max_gc_pause_(0), |
+ max_alive_after_gc_(0), |
+ min_in_mutator_(kMaxInt), |
+ alive_after_last_gc_(0), |
+ last_gc_end_timestamp_(0.0), |
+ page_watermark_invalidated_mark_(1 << Page::WATERMARK_INVALIDATED), |
+ number_idle_notifications_(0), |
+ last_idle_notification_gc_count_(0), |
+ last_idle_notification_gc_count_init_(false), |
+ configured_(false), |
+ is_safe_to_read_maps_(true) { |
+ // Allow build-time customization of the max semispace size. Building |
+ // V8 with snapshots and a non-default max semispace size is much |
+ // easier if you can define it as part of the build environment. |
+#if defined(V8_MAX_SEMISPACE_SIZE) |
+ max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; |
+#endif |
-intptr_t GCTracer::alive_after_last_gc_ = 0; |
-double GCTracer::last_gc_end_timestamp_ = 0.0; |
-int GCTracer::max_gc_pause_ = 0; |
-intptr_t GCTracer::max_alive_after_gc_ = 0; |
-int GCTracer::min_in_mutator_ = kMaxInt; |
+ memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); |
+ global_contexts_list_ = NULL; |
+ mark_compact_collector_.heap_ = this; |
+ external_string_table_.heap_ = this; |
+} |
+ |
intptr_t Heap::Capacity() { |
if (!HasBeenSetup()) return 0; |
@@ -190,7 +181,7 @@ |
intptr_t Heap::CommittedMemoryExecutable() { |
if (!HasBeenSetup()) return 0; |
- return MemoryAllocator::SizeExecutable(); |
+ return isolate()->memory_allocator()->SizeExecutable(); |
} |
@@ -217,8 +208,8 @@ |
int Heap::GcSafeSizeOfOldObject(HeapObject* object) { |
- ASSERT(!Heap::InNewSpace(object)); // Code only works for old objects. |
- ASSERT(!MarkCompactCollector::are_map_pointers_encoded()); |
+ ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects. |
+ ASSERT(!HEAP->mark_compact_collector()->are_map_pointers_encoded()); |
MapWord map_word = object->map_word(); |
map_word.ClearMark(); |
map_word.ClearOverflow(); |
@@ -227,8 +218,8 @@ |
int Heap::GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object) { |
- ASSERT(!Heap::InNewSpace(object)); // Code only works for old objects. |
- ASSERT(MarkCompactCollector::are_map_pointers_encoded()); |
+ ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects. |
+ ASSERT(HEAP->mark_compact_collector()->are_map_pointers_encoded()); |
uint32_t marker = Memory::uint32_at(object->address()); |
if (marker == MarkCompactCollector::kSingleFreeEncoding) { |
return kIntSize; |
@@ -236,7 +227,7 @@ |
return Memory::int_at(object->address() + kIntSize); |
} else { |
MapWord map_word = object->map_word(); |
- Address map_address = map_word.DecodeMapAddress(Heap::map_space()); |
+ Address map_address = map_word.DecodeMapAddress(HEAP->map_space()); |
Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_address)); |
return object->SizeFromMap(map); |
} |
@@ -246,19 +237,20 @@ |
GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
// Is global GC requested? |
if (space != NEW_SPACE || FLAG_gc_global) { |
- Counters::gc_compactor_caused_by_request.Increment(); |
+ isolate_->counters()->gc_compactor_caused_by_request()->Increment(); |
return MARK_COMPACTOR; |
} |
// Is enough data promoted to justify a global GC? |
if (OldGenerationPromotionLimitReached()) { |
- Counters::gc_compactor_caused_by_promoted_data.Increment(); |
+ isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); |
return MARK_COMPACTOR; |
} |
// Have allocation in OLD and LO failed? |
if (old_gen_exhausted_) { |
- Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment(); |
+ isolate_->counters()-> |
+ gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
return MARK_COMPACTOR; |
} |
@@ -271,8 +263,9 @@ |
// and does not count available bytes already in the old space or code |
// space. Undercounting is safe---we may get an unrequested full GC when |
// a scavenge would have succeeded. |
- if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) { |
- Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment(); |
+ if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { |
+ isolate_->counters()-> |
+ gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
return MARK_COMPACTOR; |
} |
@@ -317,8 +310,8 @@ |
if (!FLAG_trace_gc_verbose) return; |
PrintF("Memory allocator, used: %8" V8_PTR_PREFIX "d" |
", available: %8" V8_PTR_PREFIX "d\n", |
- MemoryAllocator::Size(), |
- MemoryAllocator::Available()); |
+ isolate_->memory_allocator()->Size(), |
+ isolate_->memory_allocator()->Available()); |
PrintF("New space, used: %8" V8_PTR_PREFIX "d" |
", available: %8" V8_PTR_PREFIX "d\n", |
Heap::new_space_.Size(), |
@@ -383,7 +376,7 @@ |
void Heap::GarbageCollectionPrologue() { |
- TranscendentalCache::Clear(); |
+ isolate_->transcendental_cache()->Clear(); |
ClearJSFunctionResultCaches(); |
gc_count_++; |
unflattened_strings_length_ = 0; |
@@ -424,21 +417,24 @@ |
Verify(); |
} |
- if (FLAG_print_global_handles) GlobalHandles::Print(); |
+ if (FLAG_print_global_handles) isolate_->global_handles()->Print(); |
if (FLAG_print_handles) PrintHandles(); |
if (FLAG_gc_verbose) Print(); |
if (FLAG_code_stats) ReportCodeStatistics("After GC"); |
#endif |
- Counters::alive_after_last_gc.Set(static_cast<int>(SizeOfObjects())); |
+ isolate_->counters()->alive_after_last_gc()->Set( |
+ static_cast<int>(SizeOfObjects())); |
- Counters::symbol_table_capacity.Set(symbol_table()->Capacity()); |
- Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); |
+ isolate_->counters()->symbol_table_capacity()->Set( |
+ symbol_table()->Capacity()); |
+ isolate_->counters()->number_of_symbols()->Set( |
+ symbol_table()->NumberOfElements()); |
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
ReportStatisticsAfterGC(); |
#endif |
#ifdef ENABLE_DEBUGGER_SUPPORT |
- Debug::AfterGarbageCollection(); |
+ isolate_->debug()->AfterGarbageCollection(); |
#endif |
} |
@@ -447,9 +443,9 @@ |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
// cause a full GC. |
- MarkCompactCollector::SetForceCompaction(force_compaction); |
+ mark_compact_collector_.SetForceCompaction(force_compaction); |
CollectGarbage(OLD_POINTER_SPACE); |
- MarkCompactCollector::SetForceCompaction(false); |
+ mark_compact_collector_.SetForceCompaction(false); |
} |
@@ -457,7 +453,7 @@ |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
// cause a full GC. |
- MarkCompactCollector::SetForceCompaction(true); |
+ mark_compact_collector()->SetForceCompaction(true); |
// Major GC would invoke weak handle callbacks on weakly reachable |
// handles, but won't collect weakly reachable objects until next |
@@ -473,13 +469,13 @@ |
break; |
} |
} |
- MarkCompactCollector::SetForceCompaction(false); |
+ mark_compact_collector()->SetForceCompaction(false); |
} |
bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
// The VM is in the GC state until exiting this function. |
- VMState state(GC); |
+ VMState state(isolate_, GC); |
#ifdef DEBUG |
// Reset the allocation timeout to the GC interval, but make sure to |
@@ -492,7 +488,7 @@ |
bool next_gc_likely_to_collect_more = false; |
- { GCTracer tracer; |
+ { GCTracer tracer(this); |
GarbageCollectionPrologue(); |
// The GC count was incremented in the prologue. Tell the tracer about |
// it. |
@@ -502,8 +498,8 @@ |
tracer.set_collector(collector); |
HistogramTimer* rate = (collector == SCAVENGER) |
- ? &Counters::gc_scavenger |
- : &Counters::gc_compactor; |
+ ? isolate_->counters()->gc_scavenger() |
+ : isolate_->counters()->gc_compactor(); |
rate->Start(); |
next_gc_likely_to_collect_more = |
PerformGarbageCollection(collector, &tracer); |
@@ -522,7 +518,7 @@ |
void Heap::PerformScavenge() { |
- GCTracer tracer; |
+ GCTracer tracer(this); |
PerformGarbageCollection(SCAVENGER, &tracer); |
} |
@@ -531,7 +527,6 @@ |
// Helper class for verifying the symbol table. |
class SymbolTableVerifier : public ObjectVisitor { |
public: |
- SymbolTableVerifier() { } |
void VisitPointers(Object** start, Object** end) { |
// Visit all HeapObject pointers in [start, end). |
for (Object** p = start; p < end; p++) { |
@@ -548,7 +543,7 @@ |
static void VerifySymbolTable() { |
#ifdef DEBUG |
SymbolTableVerifier verifier; |
- Heap::symbol_table()->IterateElements(&verifier); |
+ HEAP->symbol_table()->IterateElements(&verifier); |
#endif // DEBUG |
} |
@@ -633,7 +628,7 @@ |
void Heap::ClearJSFunctionResultCaches() { |
- if (Bootstrapper::IsActive()) return; |
+ if (isolate_->bootstrapper()->IsActive()) return; |
Object* context = global_contexts_list_; |
while (!context->IsUndefined()) { |
@@ -651,8 +646,9 @@ |
} |
+ |
void Heap::ClearNormalizedMapCaches() { |
- if (Bootstrapper::IsActive()) return; |
+ if (isolate_->bootstrapper()->IsActive()) return; |
Object* context = global_contexts_list_; |
while (!context->IsUndefined()) { |
@@ -709,7 +705,7 @@ |
bool next_gc_likely_to_collect_more = false; |
if (collector != SCAVENGER) { |
- PROFILE(CodeMovingGCEvent()); |
+ PROFILE(isolate_, CodeMovingGCEvent()); |
} |
VerifySymbolTable(); |
@@ -768,13 +764,13 @@ |
UpdateSurvivalRateTrend(start_new_space_size); |
} |
- Counters::objs_since_last_young.Set(0); |
+ isolate_->counters()->objs_since_last_young()->Set(0); |
if (collector == MARK_COMPACTOR) { |
DisableAssertNoAllocation allow_allocation; |
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
next_gc_likely_to_collect_more = |
- GlobalHandles::PostGarbageCollectionProcessing(); |
+ isolate_->global_handles()->PostGarbageCollectionProcessing(); |
} |
// Update relocatables. |
@@ -808,11 +804,11 @@ |
void Heap::MarkCompact(GCTracer* tracer) { |
gc_state_ = MARK_COMPACT; |
- LOG(ResourceEvent("markcompact", "begin")); |
+ LOG(isolate_, ResourceEvent("markcompact", "begin")); |
- MarkCompactCollector::Prepare(tracer); |
+ mark_compact_collector_.Prepare(tracer); |
- bool is_compacting = MarkCompactCollector::IsCompacting(); |
+ bool is_compacting = mark_compact_collector_.IsCompacting(); |
if (is_compacting) { |
mc_count_++; |
@@ -823,15 +819,17 @@ |
MarkCompactPrologue(is_compacting); |
- MarkCompactCollector::CollectGarbage(); |
+ is_safe_to_read_maps_ = false; |
+ mark_compact_collector_.CollectGarbage(); |
+ is_safe_to_read_maps_ = true; |
- LOG(ResourceEvent("markcompact", "end")); |
+ LOG(isolate_, ResourceEvent("markcompact", "end")); |
gc_state_ = NOT_IN_GC; |
Shrink(); |
- Counters::objs_since_last_full.Set(0); |
+ isolate_->counters()->objs_since_last_full()->Set(0); |
contexts_disposed_ = 0; |
} |
@@ -840,11 +838,11 @@ |
void Heap::MarkCompactPrologue(bool is_compacting) { |
// At any old GC clear the keyed lookup cache to enable collection of unused |
// maps. |
- KeyedLookupCache::Clear(); |
- ContextSlotCache::Clear(); |
- DescriptorLookupCache::Clear(); |
+ isolate_->keyed_lookup_cache()->Clear(); |
+ isolate_->context_slot_cache()->Clear(); |
+ isolate_->descriptor_lookup_cache()->Clear(); |
- CompilationCache::MarkCompactPrologue(); |
+ isolate_->compilation_cache()->MarkCompactPrologue(); |
CompletelyClearInstanceofCache(); |
@@ -868,6 +866,7 @@ |
// Helper class for copying HeapObjects |
class ScavengeVisitor: public ObjectVisitor { |
public: |
+ explicit ScavengeVisitor(Heap* heap) : heap_(heap) {} |
void VisitPointer(Object** p) { ScavengePointer(p); } |
@@ -879,48 +878,15 @@ |
private: |
void ScavengePointer(Object** p) { |
Object* object = *p; |
- if (!Heap::InNewSpace(object)) return; |
+ if (!heap_->InNewSpace(object)) return; |
Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
reinterpret_cast<HeapObject*>(object)); |
} |
-}; |
- |
-// A queue of objects promoted during scavenge. Each object is accompanied |
-// by it's size to avoid dereferencing a map pointer for scanning. |
-class PromotionQueue { |
- public: |
- void Initialize(Address start_address) { |
- front_ = rear_ = reinterpret_cast<intptr_t*>(start_address); |
- } |
- |
- bool is_empty() { return front_ <= rear_; } |
- |
- void insert(HeapObject* target, int size) { |
- *(--rear_) = reinterpret_cast<intptr_t>(target); |
- *(--rear_) = size; |
- // Assert no overflow into live objects. |
- ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top()); |
- } |
- |
- void remove(HeapObject** target, int* size) { |
- *target = reinterpret_cast<HeapObject*>(*(--front_)); |
- *size = static_cast<int>(*(--front_)); |
- // Assert no underflow. |
- ASSERT(front_ >= rear_); |
- } |
- |
- private: |
- // The front of the queue is higher in memory than the rear. |
- intptr_t* front_; |
- intptr_t* rear_; |
+ Heap* heap_; |
}; |
-// Shared state read by the scavenge collector and set by ScavengeObject. |
-static PromotionQueue promotion_queue; |
- |
- |
#ifdef DEBUG |
// Visitor class to verify pointers in code or data space do not point into |
// new space. |
@@ -929,7 +895,7 @@ |
void VisitPointers(Object** start, Object**end) { |
for (Object** current = start; current < end; current++) { |
if ((*current)->IsHeapObject()) { |
- ASSERT(!Heap::InNewSpace(HeapObject::cast(*current))); |
+ ASSERT(!HEAP->InNewSpace(HeapObject::cast(*current))); |
} |
} |
} |
@@ -940,12 +906,12 @@ |
// Verify that there are no pointers to new space in spaces where we |
// do not expect them. |
VerifyNonPointerSpacePointersVisitor v; |
- HeapObjectIterator code_it(Heap::code_space()); |
+ HeapObjectIterator code_it(HEAP->code_space()); |
for (HeapObject* object = code_it.next(); |
object != NULL; object = code_it.next()) |
object->Iterate(&v); |
- HeapObjectIterator data_it(Heap::old_data_space()); |
+ HeapObjectIterator data_it(HEAP->old_data_space()); |
for (HeapObject* object = data_it.next(); |
object != NULL; object = data_it.next()) |
object->Iterate(&v); |
@@ -971,7 +937,7 @@ |
gc_state_ = SCAVENGE; |
- Page::FlipMeaningOfInvalidatedWatermarkFlag(); |
+ Page::FlipMeaningOfInvalidatedWatermarkFlag(this); |
#ifdef DEBUG |
VerifyPageWatermarkValidity(old_pointer_space_, ALL_VALID); |
VerifyPageWatermarkValidity(map_space_, ALL_VALID); |
@@ -986,10 +952,10 @@ |
map_space_->FlushTopPageWatermark(); |
// Implements Cheney's copying algorithm |
- LOG(ResourceEvent("scavenge", "begin")); |
+ LOG(isolate_, ResourceEvent("scavenge", "begin")); |
// Clear descriptor cache. |
- DescriptorLookupCache::Clear(); |
+ isolate_->descriptor_lookup_cache()->Clear(); |
// Used for updating survived_since_last_expansion_ at function end. |
intptr_t survived_watermark = PromotedSpaceSize(); |
@@ -1019,16 +985,17 @@ |
// frees up its size in bytes from the top of the new space, and |
// objects are at least one pointer in size. |
Address new_space_front = new_space_.ToSpaceLow(); |
- promotion_queue.Initialize(new_space_.ToSpaceHigh()); |
+ promotion_queue_.Initialize(new_space_.ToSpaceHigh()); |
- ScavengeVisitor scavenge_visitor; |
+ is_safe_to_read_maps_ = false; |
+ ScavengeVisitor scavenge_visitor(this); |
// Copy roots. |
IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); |
// Copy objects reachable from the old generation. By definition, |
// there are no intergenerational pointers in code or data spaces. |
IterateDirtyRegions(old_pointer_space_, |
- &IteratePointersInDirtyRegion, |
+ &Heap::IteratePointersInDirtyRegion, |
&ScavengePointer, |
WATERMARK_CAN_BE_INVALID); |
@@ -1060,10 +1027,12 @@ |
&UpdateNewSpaceReferenceInExternalStringTableEntry); |
LiveObjectList::UpdateReferencesForScavengeGC(); |
- RuntimeProfiler::UpdateSamplesAfterScavenge(); |
+ isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); |
ASSERT(new_space_front == new_space_.top()); |
+ is_safe_to_read_maps_ = true; |
+ |
// Set age mark. |
new_space_.set_age_mark(new_space_.top()); |
@@ -1071,18 +1040,19 @@ |
IncrementYoungSurvivorsCounter(static_cast<int>( |
(PromotedSpaceSize() - survived_watermark) + new_space_.Size())); |
- LOG(ResourceEvent("scavenge", "end")); |
+ LOG(isolate_, ResourceEvent("scavenge", "end")); |
gc_state_ = NOT_IN_GC; |
} |
-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Object** p) { |
+String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, |
+ Object** p) { |
MapWord first_word = HeapObject::cast(*p)->map_word(); |
if (!first_word.IsForwardingAddress()) { |
// Unreachable external string can be finalized. |
- FinalizeExternalString(String::cast(*p)); |
+ heap->FinalizeExternalString(String::cast(*p)); |
return NULL; |
} |
@@ -1093,48 +1063,49 @@ |
void Heap::UpdateNewSpaceReferencesInExternalStringTable( |
ExternalStringTableUpdaterCallback updater_func) { |
- ExternalStringTable::Verify(); |
+ external_string_table_.Verify(); |
- if (ExternalStringTable::new_space_strings_.is_empty()) return; |
+ if (external_string_table_.new_space_strings_.is_empty()) return; |
- Object** start = &ExternalStringTable::new_space_strings_[0]; |
- Object** end = start + ExternalStringTable::new_space_strings_.length(); |
+ Object** start = &external_string_table_.new_space_strings_[0]; |
+ Object** end = start + external_string_table_.new_space_strings_.length(); |
Object** last = start; |
for (Object** p = start; p < end; ++p) { |
- ASSERT(Heap::InFromSpace(*p)); |
- String* target = updater_func(p); |
+ ASSERT(InFromSpace(*p)); |
+ String* target = updater_func(this, p); |
if (target == NULL) continue; |
ASSERT(target->IsExternalString()); |
- if (Heap::InNewSpace(target)) { |
+ if (InNewSpace(target)) { |
// String is still in new space. Update the table entry. |
*last = target; |
++last; |
} else { |
// String got promoted. Move it to the old string list. |
- ExternalStringTable::AddOldString(target); |
+ external_string_table_.AddOldString(target); |
} |
} |
ASSERT(last <= end); |
- ExternalStringTable::ShrinkNewStrings(static_cast<int>(last - start)); |
+ external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); |
} |
-static Object* ProcessFunctionWeakReferences(Object* function, |
+static Object* ProcessFunctionWeakReferences(Heap* heap, |
+ Object* function, |
WeakObjectRetainer* retainer) { |
- Object* head = Heap::undefined_value(); |
+ Object* head = heap->undefined_value(); |
JSFunction* tail = NULL; |
Object* candidate = function; |
- while (!candidate->IsUndefined()) { |
+ while (candidate != heap->undefined_value()) { |
// Check whether to keep the candidate in the list. |
JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate); |
Object* retain = retainer->RetainAs(candidate); |
if (retain != NULL) { |
- if (head->IsUndefined()) { |
+ if (head == heap->undefined_value()) { |
// First element in the list. |
head = candidate_function; |
} else { |
@@ -1151,7 +1122,7 @@ |
// Terminate the list if there is one or more elements. |
if (tail != NULL) { |
- tail->set_next_function_link(Heap::undefined_value()); |
+ tail->set_next_function_link(heap->undefined_value()); |
} |
return head; |
@@ -1162,18 +1133,19 @@ |
Object* head = undefined_value(); |
Context* tail = NULL; |
Object* candidate = global_contexts_list_; |
- while (!candidate->IsUndefined()) { |
+ while (candidate != undefined_value()) { |
// Check whether to keep the candidate in the list. |
Context* candidate_context = reinterpret_cast<Context*>(candidate); |
Object* retain = retainer->RetainAs(candidate); |
if (retain != NULL) { |
- if (head->IsUndefined()) { |
+ if (head == undefined_value()) { |
// First element in the list. |
head = candidate_context; |
} else { |
// Subsequent elements in the list. |
ASSERT(tail != NULL); |
- tail->set_unchecked(Context::NEXT_CONTEXT_LINK, |
+ tail->set_unchecked(this, |
+ Context::NEXT_CONTEXT_LINK, |
candidate_context, |
UPDATE_WRITE_BARRIER); |
} |
@@ -1183,9 +1155,11 @@ |
// Process the weak list of optimized functions for the context. |
Object* function_list_head = |
ProcessFunctionWeakReferences( |
+ this, |
candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), |
retainer); |
- candidate_context->set_unchecked(Context::OPTIMIZED_FUNCTIONS_LIST, |
+ candidate_context->set_unchecked(this, |
+ Context::OPTIMIZED_FUNCTIONS_LIST, |
function_list_head, |
UPDATE_WRITE_BARRIER); |
} |
@@ -1195,21 +1169,22 @@ |
// Terminate the list if there is one or more elements. |
if (tail != NULL) { |
- tail->set_unchecked(Context::NEXT_CONTEXT_LINK, |
+ tail->set_unchecked(this, |
+ Context::NEXT_CONTEXT_LINK, |
Heap::undefined_value(), |
UPDATE_WRITE_BARRIER); |
} |
// Update the head of the list of contexts. |
- Heap::global_contexts_list_ = head; |
+ global_contexts_list_ = head; |
} |
class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> { |
public: |
- static inline void VisitPointer(Object** p) { |
+ static inline void VisitPointer(Heap* heap, Object** p) { |
Object* object = *p; |
- if (!Heap::InNewSpace(object)) return; |
+ if (!heap->InNewSpace(object)) return; |
Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
reinterpret_cast<HeapObject*>(object)); |
} |
@@ -1230,10 +1205,10 @@ |
} |
// Promote and process all the to-be-promoted objects. |
- while (!promotion_queue.is_empty()) { |
+ while (!promotion_queue_.is_empty()) { |
HeapObject* target; |
int size; |
- promotion_queue.remove(&target, &size); |
+ promotion_queue_.remove(&target, &size); |
// Promoted object might be already partially visited |
// during dirty regions iteration. Thus we search specificly |
@@ -1303,7 +1278,7 @@ |
enum SizeRestriction { SMALL, UNKNOWN_SIZE }; |
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
- static void RecordCopiedObject(HeapObject* obj) { |
+ static void RecordCopiedObject(Heap* heap, HeapObject* obj) { |
bool should_record = false; |
#ifdef DEBUG |
should_record = FLAG_heap_stats; |
@@ -1312,10 +1287,10 @@ |
should_record = should_record || FLAG_log_gc; |
#endif |
if (should_record) { |
- if (Heap::new_space()->Contains(obj)) { |
- Heap::new_space()->RecordAllocation(obj); |
+ if (heap->new_space()->Contains(obj)) { |
+ heap->new_space()->RecordAllocation(obj); |
} else { |
- Heap::new_space()->RecordPromotion(obj); |
+ heap->new_space()->RecordPromotion(obj); |
} |
} |
} |
@@ -1324,24 +1299,27 @@ |
// Helper function used by CopyObject to copy a source object to an |
// allocated target object and update the forwarding pointer in the source |
// object. Returns the target object. |
- INLINE(static HeapObject* MigrateObject(HeapObject* source, |
+ INLINE(static HeapObject* MigrateObject(Heap* heap, |
+ HeapObject* source, |
HeapObject* target, |
int size)) { |
// Copy the content of source to target. |
- Heap::CopyBlock(target->address(), source->address(), size); |
+ heap->CopyBlock(target->address(), source->address(), size); |
// Set the forwarding address. |
source->set_map_word(MapWord::FromForwardingAddress(target)); |
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
// Update NewSpace stats if necessary. |
- RecordCopiedObject(target); |
+ RecordCopiedObject(heap, target); |
#endif |
- HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address())); |
+ HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address())); |
#if defined(ENABLE_LOGGING_AND_PROFILING) |
- if (Logger::is_logging() || CpuProfiler::is_profiling()) { |
+ Isolate* isolate = heap->isolate(); |
+ if (isolate->logger()->is_logging() || |
+ isolate->cpu_profiler()->is_profiling()) { |
if (target->IsSharedFunctionInfo()) { |
- PROFILE(SharedFunctionInfoMoveEvent( |
+ PROFILE(isolate, SharedFunctionInfoMoveEvent( |
source->address(), target->address())); |
} |
} |
@@ -1359,36 +1337,37 @@ |
(object_size <= Page::kMaxHeapObjectSize)); |
ASSERT(object->Size() == object_size); |
- if (Heap::ShouldBePromoted(object->address(), object_size)) { |
+ Heap* heap = map->heap(); |
+ if (heap->ShouldBePromoted(object->address(), object_size)) { |
MaybeObject* maybe_result; |
if ((size_restriction != SMALL) && |
(object_size > Page::kMaxHeapObjectSize)) { |
- maybe_result = Heap::lo_space()->AllocateRawFixedArray(object_size); |
+ maybe_result = heap->lo_space()->AllocateRawFixedArray(object_size); |
} else { |
if (object_contents == DATA_OBJECT) { |
- maybe_result = Heap::old_data_space()->AllocateRaw(object_size); |
+ maybe_result = heap->old_data_space()->AllocateRaw(object_size); |
} else { |
- maybe_result = Heap::old_pointer_space()->AllocateRaw(object_size); |
+ maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); |
} |
} |
Object* result = NULL; // Initialization to please compiler. |
if (maybe_result->ToObject(&result)) { |
HeapObject* target = HeapObject::cast(result); |
- *slot = MigrateObject(object, target, object_size); |
+ *slot = MigrateObject(heap, object , target, object_size); |
if (object_contents == POINTER_OBJECT) { |
- promotion_queue.insert(target, object_size); |
+ heap->promotion_queue()->insert(target, object_size); |
} |
- Heap::tracer()->increment_promoted_objects_size(object_size); |
+ heap->tracer()->increment_promoted_objects_size(object_size); |
return; |
} |
} |
Object* result = |
- Heap::new_space()->AllocateRaw(object_size)->ToObjectUnchecked(); |
- *slot = MigrateObject(object, HeapObject::cast(result), object_size); |
+ heap->new_space()->AllocateRaw(object_size)->ToObjectUnchecked(); |
+ *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size); |
return; |
} |
@@ -1439,13 +1418,14 @@ |
HeapObject* object) { |
ASSERT(IsShortcutCandidate(map->instance_type())); |
- if (ConsString::cast(object)->unchecked_second() == Heap::empty_string()) { |
+ if (ConsString::cast(object)->unchecked_second() == |
+ map->heap()->empty_string()) { |
HeapObject* first = |
HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
*slot = first; |
- if (!Heap::InNewSpace(first)) { |
+ if (!map->heap()->InNewSpace(first)) { |
object->set_map_word(MapWord::FromForwardingAddress(first)); |
return; |
} |
@@ -1496,7 +1476,7 @@ |
void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
- ASSERT(InFromSpace(object)); |
+ ASSERT(HEAP->InFromSpace(object)); |
MapWord first_word = object->map_word(); |
ASSERT(!first_word.IsForwardingAddress()); |
Map* map = first_word.ToMap(); |
@@ -1504,11 +1484,6 @@ |
} |
-void Heap::ScavengePointer(HeapObject** p) { |
- ScavengeObject(p, *p); |
-} |
- |
- |
MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, |
int instance_size) { |
Object* result; |
@@ -1520,9 +1495,8 @@ |
reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map()); |
reinterpret_cast<Map*>(result)->set_instance_type(instance_type); |
reinterpret_cast<Map*>(result)->set_instance_size(instance_size); |
- reinterpret_cast<Map*>(result)-> |
- set_visitor_id( |
- StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
+ reinterpret_cast<Map*>(result)->set_visitor_id( |
+ StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
reinterpret_cast<Map*>(result)->set_inobject_properties(0); |
reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); |
reinterpret_cast<Map*>(result)->set_unused_property_fields(0); |
@@ -1631,6 +1605,7 @@ |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_null_value(obj); |
+ Oddball::cast(obj)->set_kind(Oddball::kNull); |
// Allocate the empty descriptor array. |
{ MaybeObject* maybe_obj = AllocateEmptyFixedArray(); |
@@ -1822,7 +1797,7 @@ |
} |
set_message_object_map(Map::cast(obj)); |
- ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); |
+ ASSERT(!InNewSpace(empty_fixed_array())); |
return true; |
} |
@@ -1875,12 +1850,13 @@ |
MaybeObject* Heap::CreateOddball(const char* to_string, |
- Object* to_number) { |
+ Object* to_number, |
+ byte kind) { |
Object* result; |
{ MaybeObject* maybe_result = Allocate(oddball_map(), OLD_DATA_SPACE); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
- return Oddball::cast(result)->Initialize(to_string, to_number); |
+ return Oddball::cast(result)->Initialize(to_string, to_number, kind); |
} |
@@ -1892,7 +1868,7 @@ |
} |
set_neander_map(Map::cast(obj)); |
- { MaybeObject* maybe_obj = Heap::AllocateJSObjectFromMap(neander_map()); |
+ { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map()); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
Object* elements; |
@@ -1957,6 +1933,7 @@ |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_undefined_value(obj); |
+ Oddball::cast(obj)->set_kind(Oddball::kUndefined); |
ASSERT(!InNewSpace(undefined_value())); |
// Allocate initial symbol table. |
@@ -1976,39 +1953,50 @@ |
// Allocate the null_value |
{ MaybeObject* maybe_obj = |
- Oddball::cast(null_value())->Initialize("null", Smi::FromInt(0)); |
+ Oddball::cast(null_value())->Initialize("null", |
+ Smi::FromInt(0), |
+ Oddball::kNull); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
- { MaybeObject* maybe_obj = CreateOddball("true", Smi::FromInt(1)); |
+ { MaybeObject* maybe_obj = CreateOddball("true", |
+ Smi::FromInt(1), |
+ Oddball::kTrue); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_true_value(obj); |
- { MaybeObject* maybe_obj = CreateOddball("false", Smi::FromInt(0)); |
+ { MaybeObject* maybe_obj = CreateOddball("false", |
+ Smi::FromInt(0), |
+ Oddball::kFalse); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_false_value(obj); |
- { MaybeObject* maybe_obj = CreateOddball("hole", Smi::FromInt(-1)); |
+ { MaybeObject* maybe_obj = CreateOddball("hole", |
+ Smi::FromInt(-1), |
+ Oddball::kTheHole); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_the_hole_value(obj); |
{ MaybeObject* maybe_obj = CreateOddball("arguments_marker", |
- Smi::FromInt(-4)); |
+ Smi::FromInt(-4), |
+ Oddball::kArgumentMarker); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_arguments_marker(obj); |
- { MaybeObject* maybe_obj = |
- CreateOddball("no_interceptor_result_sentinel", Smi::FromInt(-2)); |
+ { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel", |
+ Smi::FromInt(-2), |
+ Oddball::kOther); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_no_interceptor_result_sentinel(obj); |
- { MaybeObject* maybe_obj = |
- CreateOddball("termination_exception", Smi::FromInt(-3)); |
+ { MaybeObject* maybe_obj = CreateOddball("termination_exception", |
+ Smi::FromInt(-3), |
+ Oddball::kOther); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_termination_exception(obj); |
@@ -2070,7 +2058,8 @@ |
{ MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
- { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(obj); |
+ { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this, |
+ obj); |
if (!maybe_obj->ToObject(&obj)) return false; |
} |
set_intrinsic_function_names(StringDictionary::cast(obj)); |
@@ -2090,20 +2079,20 @@ |
} |
set_natives_source_cache(FixedArray::cast(obj)); |
- // Handling of script id generation is in Factory::NewScript. |
+ // Handling of script id generation is in FACTORY->NewScript. |
set_last_script_id(undefined_value()); |
// Initialize keyed lookup cache. |
- KeyedLookupCache::Clear(); |
+ isolate_->keyed_lookup_cache()->Clear(); |
// Initialize context slot cache. |
- ContextSlotCache::Clear(); |
+ isolate_->context_slot_cache()->Clear(); |
// Initialize descriptor cache. |
- DescriptorLookupCache::Clear(); |
+ isolate_->descriptor_lookup_cache()->Clear(); |
// Initialize compilation cache. |
- CompilationCache::Clear(); |
+ isolate_->compilation_cache()->Clear(); |
return true; |
} |
@@ -2127,7 +2116,7 @@ |
// Flush the number to string cache. |
int len = number_string_cache()->length(); |
for (int i = 0; i < len; i++) { |
- number_string_cache()->set_undefined(i); |
+ number_string_cache()->set_undefined(this, i); |
} |
} |
@@ -2179,7 +2168,7 @@ |
MaybeObject* Heap::NumberToString(Object* number, |
bool check_number_string_cache) { |
- Counters::number_to_string_runtime.Increment(); |
+ isolate_->counters()->number_to_string_runtime()->Increment(); |
if (check_number_string_cache) { |
Object* cached = GetNumberStringCache(number); |
if (cached != undefined_value()) { |
@@ -2282,10 +2271,11 @@ |
SharedFunctionInfo* share = SharedFunctionInfo::cast(result); |
share->set_name(name); |
- Code* illegal = Builtins::builtin(Builtins::Illegal); |
+ Code* illegal = isolate_->builtins()->builtin(Builtins::Illegal); |
share->set_code(illegal); |
share->set_scope_info(SerializedScopeInfo::Empty()); |
- Code* construct_stub = Builtins::builtin(Builtins::JSConstructStubGeneric); |
+ Code* construct_stub = isolate_->builtins()->builtin( |
+ Builtins::JSConstructStubGeneric); |
share->set_construct_stub(construct_stub); |
share->set_expected_nof_properties(0); |
share->set_length(0); |
@@ -2343,20 +2333,21 @@ |
MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( |
+ Heap* heap, |
uint32_t c1, |
uint32_t c2) { |
String* symbol; |
// Numeric strings have a different hash algorithm not known by |
// LookupTwoCharsSymbolIfExists, so we skip this step for such strings. |
if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && |
- Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) { |
+ heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) { |
return symbol; |
// Now we know the length is 2, we might as well make use of that fact |
// when building the new string. |
} else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this |
ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this. |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateRawAsciiString(2); |
+ { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
char* dest = SeqAsciiString::cast(result)->GetChars(); |
@@ -2365,7 +2356,7 @@ |
return result; |
} else { |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateRawTwoByteString(2); |
+ { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
@@ -2395,7 +2386,7 @@ |
if (length == 2) { |
unsigned c1 = first->Get(0); |
unsigned c2 = second->Get(0); |
- return MakeOrFindTwoCharacterString(c1, c2); |
+ return MakeOrFindTwoCharacterString(this, c1, c2); |
} |
bool first_is_ascii = first->IsAsciiRepresentation(); |
@@ -2405,7 +2396,7 @@ |
// Make sure that an out of memory exception is thrown if the length |
// of the new cons string is too large. |
if (length > String::kMaxLength || length < 0) { |
- Top::context()->mark_out_of_memory(); |
+ isolate()->context()->mark_out_of_memory(); |
return Failure::OutOfMemoryException(); |
} |
@@ -2417,7 +2408,7 @@ |
is_ascii_data_in_two_byte_string = |
first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars(); |
if (is_ascii_data_in_two_byte_string) { |
- Counters::string_add_runtime_ext_to_ascii.Increment(); |
+ isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); |
} |
} |
@@ -2458,6 +2449,7 @@ |
char* dest = SeqAsciiString::cast(result)->GetChars(); |
String::WriteToFlat(first, dest, 0, first_length); |
String::WriteToFlat(second, dest + first_length, 0, second_length); |
+ isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); |
return result; |
} |
@@ -2499,15 +2491,14 @@ |
int length = end - start; |
if (length == 1) { |
- return Heap::LookupSingleCharacterStringFromCode( |
- buffer->Get(start)); |
+ return LookupSingleCharacterStringFromCode(buffer->Get(start)); |
} else if (length == 2) { |
// Optimization for 2-byte strings often used as keys in a decompression |
// dictionary. Check whether we already have the string in the symbol |
// table to prevent creation of many unneccesary strings. |
unsigned c1 = buffer->Get(start); |
unsigned c2 = buffer->Get(start + 1); |
- return MakeOrFindTwoCharacterString(c1, c2); |
+ return MakeOrFindTwoCharacterString(this, c1, c2); |
} |
// Make an attempt to flatten the buffer to reduce access time. |
@@ -2539,7 +2530,7 @@ |
ExternalAsciiString::Resource* resource) { |
size_t length = resource->length(); |
if (length > static_cast<size_t>(String::kMaxLength)) { |
- Top::context()->mark_out_of_memory(); |
+ isolate()->context()->mark_out_of_memory(); |
return Failure::OutOfMemoryException(); |
} |
@@ -2562,7 +2553,7 @@ |
ExternalTwoByteString::Resource* resource) { |
size_t length = resource->length(); |
if (length > static_cast<size_t>(String::kMaxLength)) { |
- Top::context()->mark_out_of_memory(); |
+ isolate()->context()->mark_out_of_memory(); |
return Failure::OutOfMemoryException(); |
} |
@@ -2572,7 +2563,7 @@ |
bool is_ascii = length <= kAsciiCheckLengthLimit && |
String::IsAscii(resource->data(), static_cast<int>(length)); |
Map* map = is_ascii ? |
- Heap::external_string_with_ascii_data_map() : Heap::external_string_map(); |
+ external_string_with_ascii_data_map() : external_string_map(); |
Object* result; |
{ MaybeObject* maybe_result = Allocate(map, NEW_SPACE); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
@@ -2589,8 +2580,8 @@ |
MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) { |
if (code <= String::kMaxAsciiCharCode) { |
- Object* value = Heap::single_character_string_cache()->get(code); |
- if (value != Heap::undefined_value()) return value; |
+ Object* value = single_character_string_cache()->get(code); |
+ if (value != undefined_value()) return value; |
char buffer[1]; |
buffer[0] = static_cast<char>(code); |
@@ -2598,12 +2589,12 @@ |
MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1)); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
- Heap::single_character_string_cache()->set(code, result); |
+ single_character_string_cache()->set(code, result); |
return result; |
} |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateRawTwoByteString(1); |
+ { MaybeObject* maybe_result = AllocateRawTwoByteString(1); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
String* answer = String::cast(result); |
@@ -2717,7 +2708,8 @@ |
// Initialize the object |
HeapObject::cast(result)->set_map(code_map()); |
Code* code = Code::cast(result); |
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); |
+ ASSERT(!isolate_->code_range()->exists() || |
+ isolate_->code_range()->contains(code->address())); |
code->set_instruction_size(desc.instr_size); |
code->set_relocation_info(ByteArray::cast(reloc_info)); |
code->set_flags(flags); |
@@ -2763,7 +2755,8 @@ |
CopyBlock(new_addr, old_addr, obj_size); |
// Relocate the copy. |
Code* new_code = Code::cast(result); |
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); |
+ ASSERT(!isolate_->code_range()->exists() || |
+ isolate_->code_range()->contains(code->address())); |
new_code->Relocate(new_addr - old_addr); |
return new_code; |
} |
@@ -2812,7 +2805,8 @@ |
memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length()); |
// Relocate the copy. |
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address())); |
+ ASSERT(!isolate_->code_range()->exists() || |
+ isolate_->code_range()->contains(code->address())); |
new_code->Relocate(new_addr - old_addr); |
#ifdef DEBUG |
@@ -2836,7 +2830,7 @@ |
} |
HeapObject::cast(result)->set_map(map); |
#ifdef ENABLE_LOGGING_AND_PROFILING |
- ProducerHeapProfile::RecordJSObjectAllocation(result); |
+ isolate_->producer_heap_profile()->RecordJSObjectAllocation(result); |
#endif |
return result; |
} |
@@ -2904,10 +2898,12 @@ |
JSFunction::cast(callee)->shared()->strict_mode(); |
if (strict_mode_callee) { |
boilerplate = |
- Top::context()->global_context()->strict_mode_arguments_boilerplate(); |
+ isolate()->context()->global_context()-> |
+ strict_mode_arguments_boilerplate(); |
arguments_object_size = kArgumentsObjectSizeStrict; |
} else { |
- boilerplate = Top::context()->global_context()->arguments_boilerplate(); |
+ boilerplate = |
+ isolate()->context()->global_context()->arguments_boilerplate(); |
arguments_object_size = kArgumentsObjectSize; |
} |
@@ -2974,8 +2970,7 @@ |
int instance_size = fun->shared()->CalculateInstanceSize(); |
int in_object_properties = fun->shared()->CalculateInObjectProperties(); |
Object* map_obj; |
- { MaybeObject* maybe_map_obj = |
- Heap::AllocateMap(JS_OBJECT_TYPE, instance_size); |
+ { MaybeObject* maybe_map_obj = AllocateMap(JS_OBJECT_TYPE, instance_size); |
if (!maybe_map_obj->ToObject(&map_obj)) return maybe_map_obj; |
} |
@@ -3171,7 +3166,7 @@ |
PropertyDetails d = |
PropertyDetails(details.attributes(), CALLBACKS, details.index()); |
Object* value = descs->GetCallbacksObject(i); |
- { MaybeObject* maybe_value = Heap::AllocateJSGlobalPropertyCell(value); |
+ { MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value); |
if (!maybe_value->ToObject(&value)) return maybe_value; |
} |
@@ -3197,7 +3192,7 @@ |
// Setup the global object as a normalized object. |
global->set_map(new_map); |
- global->map()->set_instance_descriptors(Heap::empty_descriptor_array()); |
+ global->map()->set_instance_descriptors(empty_descriptor_array()); |
global->set_properties(dictionary); |
// Make sure result is a global object with properties in dictionary. |
@@ -3236,7 +3231,7 @@ |
{ MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size); |
if (!maybe_clone->ToObject(&clone)) return maybe_clone; |
} |
- ASSERT(Heap::InNewSpace(clone)); |
+ ASSERT(InNewSpace(clone)); |
// Since we know the clone is allocated in new space, we can copy |
// the contents without worrying about updating the write barrier. |
CopyBlock(HeapObject::cast(clone)->address(), |
@@ -3266,7 +3261,7 @@ |
} |
// Return the new clone. |
#ifdef ENABLE_LOGGING_AND_PROFILING |
- ProducerHeapProfile::RecordJSObjectAllocation(clone); |
+ isolate_->producer_heap_profile()->RecordJSObjectAllocation(clone); |
#endif |
return clone; |
} |
@@ -3322,7 +3317,7 @@ |
// Count the number of characters in the UTF-8 string and check if |
// it is an ASCII string. |
Access<ScannerConstants::Utf8Decoder> |
- decoder(ScannerConstants::utf8_decoder()); |
+ decoder(isolate_->scanner_constants()->utf8_decoder()); |
decoder->Reset(string.start(), string.length()); |
int chars = 0; |
while (decoder->has_more()) { |
@@ -3375,12 +3370,24 @@ |
// Find the corresponding symbol map for strings. |
Map* map = string->map(); |
- if (map == ascii_string_map()) return ascii_symbol_map(); |
- if (map == string_map()) return symbol_map(); |
- if (map == cons_string_map()) return cons_symbol_map(); |
- if (map == cons_ascii_string_map()) return cons_ascii_symbol_map(); |
- if (map == external_string_map()) return external_symbol_map(); |
- if (map == external_ascii_string_map()) return external_ascii_symbol_map(); |
+ if (map == ascii_string_map()) { |
+ return ascii_symbol_map(); |
+ } |
+ if (map == string_map()) { |
+ return symbol_map(); |
+ } |
+ if (map == cons_string_map()) { |
+ return cons_symbol_map(); |
+ } |
+ if (map == cons_ascii_string_map()) { |
+ return cons_ascii_symbol_map(); |
+ } |
+ if (map == external_string_map()) { |
+ return external_symbol_map(); |
+ } |
+ if (map == external_ascii_string_map()) { |
+ return external_ascii_symbol_map(); |
+ } |
if (map == external_string_with_ascii_data_map()) { |
return external_symbol_with_ascii_data_map(); |
} |
@@ -3554,7 +3561,7 @@ |
{ MaybeObject* maybe_obj = AllocateRawFixedArray(len); |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
} |
- if (Heap::InNewSpace(obj)) { |
+ if (InNewSpace(obj)) { |
HeapObject* dst = HeapObject::cast(obj); |
dst->set_map(map); |
CopyBlock(dst->address() + kPointerSize, |
@@ -3586,7 +3593,7 @@ |
array->set_map(fixed_array_map()); |
array->set_length(length); |
// Initialize body. |
- ASSERT(!Heap::InNewSpace(undefined_value())); |
+ ASSERT(!InNewSpace(undefined_value())); |
MemsetPointer(array->data_start(), undefined_value(), length); |
return result; |
} |
@@ -3617,20 +3624,21 @@ |
MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller( |
+ Heap* heap, |
int length, |
PretenureFlag pretenure, |
Object* filler) { |
ASSERT(length >= 0); |
- ASSERT(Heap::empty_fixed_array()->IsFixedArray()); |
- if (length == 0) return Heap::empty_fixed_array(); |
+ ASSERT(heap->empty_fixed_array()->IsFixedArray()); |
+ if (length == 0) return heap->empty_fixed_array(); |
- ASSERT(!Heap::InNewSpace(filler)); |
+ ASSERT(!heap->InNewSpace(filler)); |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateRawFixedArray(length, pretenure); |
+ { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
- HeapObject::cast(result)->set_map(Heap::fixed_array_map()); |
+ HeapObject::cast(result)->set_map(heap->fixed_array_map()); |
FixedArray* array = FixedArray::cast(result); |
array->set_length(length); |
MemsetPointer(array->data_start(), filler, length); |
@@ -3639,13 +3647,19 @@ |
MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { |
- return AllocateFixedArrayWithFiller(length, pretenure, undefined_value()); |
+ return AllocateFixedArrayWithFiller(this, |
+ length, |
+ pretenure, |
+ undefined_value()); |
} |
MaybeObject* Heap::AllocateFixedArrayWithHoles(int length, |
PretenureFlag pretenure) { |
- return AllocateFixedArrayWithFiller(length, pretenure, the_hole_value()); |
+ return AllocateFixedArrayWithFiller(this, |
+ length, |
+ pretenure, |
+ the_hole_value()); |
} |
@@ -3665,7 +3679,7 @@ |
MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) { |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateFixedArray(length, pretenure); |
+ { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
reinterpret_cast<HeapObject*>(result)->set_map(hash_table_map()); |
@@ -3677,7 +3691,7 @@ |
MaybeObject* Heap::AllocateGlobalContext() { |
Object* result; |
{ MaybeObject* maybe_result = |
- Heap::AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS); |
+ AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
Context* context = reinterpret_cast<Context*>(result); |
@@ -3691,7 +3705,7 @@ |
MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { |
ASSERT(length >= Context::MIN_CONTEXT_SLOTS); |
Object* result; |
- { MaybeObject* maybe_result = Heap::AllocateFixedArray(length); |
+ { MaybeObject* maybe_result = AllocateFixedArray(length); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
Context* context = reinterpret_cast<Context*>(result); |
@@ -3712,12 +3726,12 @@ |
JSObject* extension, |
bool is_catch_context) { |
Object* result; |
- { MaybeObject* maybe_result = |
- Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS); |
+ { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
Context* context = reinterpret_cast<Context*>(result); |
- context->set_map(is_catch_context ? catch_context_map() : context_map()); |
+ context->set_map(is_catch_context ? catch_context_map() : |
+ context_map()); |
context->set_closure(previous->closure()); |
context->set_fcontext(previous->fcontext()); |
context->set_previous(previous); |
@@ -3733,7 +3747,8 @@ |
MaybeObject* Heap::AllocateStruct(InstanceType type) { |
Map* map; |
switch (type) { |
-#define MAKE_CASE(NAME, Name, name) case NAME##_TYPE: map = name##_map(); break; |
+#define MAKE_CASE(NAME, Name, name) \ |
+ case NAME##_TYPE: map = name##_map(); break; |
STRUCT_LIST(MAKE_CASE) |
#undef MAKE_CASE |
default: |
@@ -3744,7 +3759,7 @@ |
AllocationSpace space = |
(size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; |
Object* result; |
- { MaybeObject* maybe_result = Heap::Allocate(map, space); |
+ { MaybeObject* maybe_result = Allocate(map, space); |
if (!maybe_result->ToObject(&result)) return maybe_result; |
} |
Struct::cast(result)->InitializeBody(size); |
@@ -3758,9 +3773,12 @@ |
static const int kIdlesBeforeMarkCompact = 8; |
static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
static const unsigned int kGCsBetweenCleanup = 4; |
- static int number_idle_notifications = 0; |
- static unsigned int last_gc_count = gc_count_; |
+ if (!last_idle_notification_gc_count_init_) { |
+ last_idle_notification_gc_count_ = gc_count_; |
+ last_idle_notification_gc_count_init_ = true; |
+ } |
+ |
bool uncommit = true; |
bool finished = false; |
@@ -3768,56 +3786,56 @@ |
// 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_gc_count < kGCsBetweenCleanup) { |
- number_idle_notifications = |
- Min(number_idle_notifications + 1, kMaxIdleCount); |
+ if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) { |
+ number_idle_notifications_ = |
+ Min(number_idle_notifications_ + 1, kMaxIdleCount); |
} else { |
- number_idle_notifications = 0; |
- last_gc_count = gc_count_; |
+ number_idle_notifications_ = 0; |
+ last_idle_notification_gc_count_ = gc_count_; |
} |
- if (number_idle_notifications == kIdlesBeforeScavenge) { |
+ if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
if (contexts_disposed_ > 0) { |
- HistogramTimerScope scope(&Counters::gc_context); |
+ HistogramTimerScope scope(isolate_->counters()->gc_context()); |
CollectAllGarbage(false); |
} else { |
CollectGarbage(NEW_SPACE); |
} |
new_space_.Shrink(); |
- last_gc_count = gc_count_; |
- } else if (number_idle_notifications == kIdlesBeforeMarkSweep) { |
+ 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 |
// generated code for cached functions. |
- CompilationCache::Clear(); |
+ isolate_->compilation_cache()->Clear(); |
CollectAllGarbage(false); |
new_space_.Shrink(); |
- last_gc_count = gc_count_; |
+ last_idle_notification_gc_count_ = gc_count_; |
- } else if (number_idle_notifications == kIdlesBeforeMarkCompact) { |
+ } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
CollectAllGarbage(true); |
new_space_.Shrink(); |
- last_gc_count = gc_count_; |
+ 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; |
} else { |
- HistogramTimerScope scope(&Counters::gc_context); |
+ HistogramTimerScope scope(isolate_->counters()->gc_context()); |
CollectAllGarbage(false); |
- last_gc_count = gc_count_; |
+ last_idle_notification_gc_count_ = gc_count_; |
} |
// If this is the first idle notification, we reset the |
// notification count to avoid letting idle notifications for |
// context disposal garbage collections start a potentially too |
// aggressive idle GC cycle. |
- if (number_idle_notifications <= 1) { |
- number_idle_notifications = 0; |
+ if (number_idle_notifications_ <= 1) { |
+ number_idle_notifications_ = 0; |
uncommit = false; |
} |
- } else if (number_idle_notifications > kIdlesBeforeMarkCompact) { |
+ } 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. |
@@ -3827,7 +3845,7 @@ |
// Make sure that we have no pending context disposals and |
// conditionally uncommit from space. |
ASSERT(contexts_disposed_ == 0); |
- if (uncommit) Heap::UncommitFromSpace(); |
+ if (uncommit) UncommitFromSpace(); |
return finished; |
} |
@@ -3836,7 +3854,7 @@ |
void Heap::Print() { |
if (!HasBeenSetup()) return; |
- Top::PrintStack(); |
+ isolate()->PrintStack(); |
AllSpaces spaces; |
for (Space* space = spaces.next(); space != NULL; space = spaces.next()) |
space->Print(); |
@@ -3869,11 +3887,11 @@ |
PrintF("\n"); |
PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); |
- GlobalHandles::PrintStats(); |
+ isolate_->global_handles()->PrintStats(); |
PrintF("\n"); |
PrintF("Heap statistics : "); |
- MemoryAllocator::ReportStatistics(); |
+ isolate_->memory_allocator()->ReportStatistics(); |
PrintF("To space : "); |
new_space_.ReportStatistics(); |
PrintF("Old pointer space : "); |
@@ -3956,7 +3974,7 @@ |
Address start = page->ObjectAreaStart(); |
Address end = page->AllocationWatermark(); |
- Heap::IterateDirtyRegions(Page::kAllRegionsDirtyMarks, |
+ HEAP->IterateDirtyRegions(Page::kAllRegionsDirtyMarks, |
start, |
end, |
visit_dirty_region, |
@@ -3977,7 +3995,7 @@ |
// When we are not in GC the Heap::InNewSpace() predicate |
// checks that pointers which satisfy predicate point into |
// the active semispace. |
- Heap::InNewSpace(*slot); |
+ HEAP->InNewSpace(*slot); |
slot_address += kPointerSize; |
} |
} |
@@ -4098,7 +4116,8 @@ |
#endif // DEBUG |
-bool Heap::IteratePointersInDirtyRegion(Address start, |
+bool Heap::IteratePointersInDirtyRegion(Heap* heap, |
+ Address start, |
Address end, |
ObjectSlotCallback copy_object_func) { |
Address slot_address = start; |
@@ -4106,10 +4125,10 @@ |
while (slot_address < end) { |
Object** slot = reinterpret_cast<Object**>(slot_address); |
- if (Heap::InNewSpace(*slot)) { |
+ if (heap->InNewSpace(*slot)) { |
ASSERT((*slot)->IsHeapObject()); |
copy_object_func(reinterpret_cast<HeapObject**>(slot)); |
- if (Heap::InNewSpace(*slot)) { |
+ if (heap->InNewSpace(*slot)) { |
ASSERT((*slot)->IsHeapObject()); |
pointers_to_new_space_found = true; |
} |
@@ -4143,14 +4162,16 @@ |
Address map_address = start; |
bool pointers_to_new_space_found = false; |
+ Heap* heap = HEAP; |
while (map_address < end) { |
- ASSERT(!Heap::InNewSpace(Memory::Object_at(map_address))); |
+ ASSERT(!heap->InNewSpace(Memory::Object_at(map_address))); |
ASSERT(Memory::Object_at(map_address)->IsMap()); |
Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset; |
Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset; |
- if (Heap::IteratePointersInDirtyRegion(pointer_fields_start, |
+ if (Heap::IteratePointersInDirtyRegion(heap, |
+ pointer_fields_start, |
pointer_fields_end, |
copy_object_func)) { |
pointers_to_new_space_found = true; |
@@ -4164,6 +4185,7 @@ |
bool Heap::IteratePointersInDirtyMapsRegion( |
+ Heap* heap, |
Address start, |
Address end, |
ObjectSlotCallback copy_object_func) { |
@@ -4183,7 +4205,8 @@ |
Min(prev_map + Map::kPointerFieldsEndOffset, end); |
contains_pointers_to_new_space = |
- IteratePointersInDirtyRegion(pointer_fields_start, |
+ IteratePointersInDirtyRegion(heap, |
+ pointer_fields_start, |
pointer_fields_end, |
copy_object_func) |
|| contains_pointers_to_new_space; |
@@ -4205,7 +4228,8 @@ |
Min(end, map_aligned_end + Map::kPointerFieldsEndOffset); |
contains_pointers_to_new_space = |
- IteratePointersInDirtyRegion(pointer_fields_start, |
+ IteratePointersInDirtyRegion(heap, |
+ pointer_fields_start, |
pointer_fields_end, |
copy_object_func) |
|| contains_pointers_to_new_space; |
@@ -4225,10 +4249,10 @@ |
while (slot_address < end) { |
Object** slot = reinterpret_cast<Object**>(slot_address); |
- if (Heap::InFromSpace(*slot)) { |
+ if (InFromSpace(*slot)) { |
ASSERT((*slot)->IsHeapObject()); |
callback(reinterpret_cast<HeapObject**>(slot)); |
- if (Heap::InNewSpace(*slot)) { |
+ if (InNewSpace(*slot)) { |
ASSERT((*slot)->IsHeapObject()); |
marks |= page->GetRegionMaskForAddress(slot_address); |
} |
@@ -4267,7 +4291,7 @@ |
Address region_end = Min(second_region, area_end); |
if (marks & mask) { |
- if (visit_dirty_region(region_start, region_end, copy_object_func)) { |
+ if (visit_dirty_region(this, region_start, region_end, copy_object_func)) { |
newmarks |= mask; |
} |
} |
@@ -4279,7 +4303,10 @@ |
while (region_end <= area_end) { |
if (marks & mask) { |
- if (visit_dirty_region(region_start, region_end, copy_object_func)) { |
+ if (visit_dirty_region(this, |
+ region_start, |
+ region_end, |
+ copy_object_func)) { |
newmarks |= mask; |
} |
} |
@@ -4295,7 +4322,7 @@ |
// with region end. Check whether region covering last part of area is |
// dirty. |
if (marks & mask) { |
- if (visit_dirty_region(region_start, area_end, copy_object_func)) { |
+ if (visit_dirty_region(this, region_start, area_end, copy_object_func)) { |
newmarks |= mask; |
} |
} |
@@ -4361,7 +4388,7 @@ |
v->Synchronize("symbol_table"); |
if (mode != VISIT_ALL_IN_SCAVENGE) { |
// Scavenge collections have special processing for this. |
- ExternalStringTable::Iterate(v); |
+ external_string_table_.Iterate(v); |
} |
v->Synchronize("external_string_table"); |
} |
@@ -4374,42 +4401,42 @@ |
v->VisitPointer(BitCast<Object**>(&hidden_symbol_)); |
v->Synchronize("symbol"); |
- Bootstrapper::Iterate(v); |
+ isolate_->bootstrapper()->Iterate(v); |
v->Synchronize("bootstrapper"); |
- Top::Iterate(v); |
+ isolate_->Iterate(v); |
v->Synchronize("top"); |
Relocatable::Iterate(v); |
v->Synchronize("relocatable"); |
#ifdef ENABLE_DEBUGGER_SUPPORT |
- Debug::Iterate(v); |
+ isolate_->debug()->Iterate(v); |
#endif |
v->Synchronize("debug"); |
- CompilationCache::Iterate(v); |
+ isolate_->compilation_cache()->Iterate(v); |
v->Synchronize("compilationcache"); |
// Iterate over local handles in handle scopes. |
- HandleScopeImplementer::Iterate(v); |
+ isolate_->handle_scope_implementer()->Iterate(v); |
v->Synchronize("handlescope"); |
// Iterate over the builtin code objects and code stubs in the |
// heap. Note that it is not necessary to iterate over code objects |
// on scavenge collections. |
if (mode != VISIT_ALL_IN_SCAVENGE) { |
- Builtins::IterateBuiltins(v); |
+ isolate_->builtins()->IterateBuiltins(v); |
} |
v->Synchronize("builtins"); |
// Iterate over global handles. |
if (mode == VISIT_ONLY_STRONG) { |
- GlobalHandles::IterateStrongRoots(v); |
+ isolate_->global_handles()->IterateStrongRoots(v); |
} else { |
- GlobalHandles::IterateAllRoots(v); |
+ isolate_->global_handles()->IterateAllRoots(v); |
} |
v->Synchronize("globalhandles"); |
// Iterate over pointers being held by inactive threads. |
- ThreadManager::Iterate(v); |
+ isolate_->thread_manager()->Iterate(v); |
v->Synchronize("threadmanager"); |
// Iterate over the pointers the Serialization/Deserialization code is |
@@ -4428,10 +4455,6 @@ |
} |
-// Flag is set when the heap has been configured. The heap can be repeatedly |
-// configured through the API until it is setup. |
-static bool heap_configured = false; |
- |
// TODO(1236194): Since the heap size is configurable on the command line |
// and through the API, we should gracefully handle the case that the heap |
// size is not big enough to fit all the initial objects. |
@@ -4478,7 +4501,7 @@ |
// The old generation is paged. |
max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize); |
- heap_configured = true; |
+ configured_ = true; |
return true; |
} |
@@ -4506,11 +4529,13 @@ |
*stats->cell_space_size = cell_space_->Size(); |
*stats->cell_space_capacity = cell_space_->Capacity(); |
*stats->lo_space_size = lo_space_->Size(); |
- GlobalHandles::RecordStats(stats); |
- *stats->memory_allocator_size = MemoryAllocator::Size(); |
+ isolate_->global_handles()->RecordStats(stats); |
+ *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); |
*stats->memory_allocator_capacity = |
- MemoryAllocator::Size() + MemoryAllocator::Available(); |
+ isolate()->memory_allocator()->Size() + |
+ isolate()->memory_allocator()->Available(); |
*stats->os_error = OS::GetLastError(); |
+ isolate()->memory_allocator()->Available(); |
if (take_snapshot) { |
HeapIterator iterator(HeapIterator::kFilterFreeListNodes); |
for (HeapObject* obj = iterator.next(); |
@@ -4542,8 +4567,177 @@ |
- amount_of_external_allocated_memory_at_last_global_gc_; |
} |
+#ifdef DEBUG |
+// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. |
+static const int kMarkTag = 2; |
+ |
+ |
+class HeapDebugUtils { |
+ public: |
+ explicit HeapDebugUtils(Heap* heap) |
+ : search_for_any_global_(false), |
+ search_target_(NULL), |
+ found_target_(false), |
+ object_stack_(20), |
+ heap_(heap) { |
+ } |
+ |
+ class MarkObjectVisitor : public ObjectVisitor { |
+ public: |
+ explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { } |
+ |
+ void VisitPointers(Object** start, Object** end) { |
+ // Copy all HeapObject pointers in [start, end) |
+ for (Object** p = start; p < end; p++) { |
+ if ((*p)->IsHeapObject()) |
+ utils_->MarkObjectRecursively(p); |
+ } |
+ } |
+ |
+ HeapDebugUtils* utils_; |
+ }; |
+ |
+ void MarkObjectRecursively(Object** p) { |
+ if (!(*p)->IsHeapObject()) return; |
+ |
+ HeapObject* obj = HeapObject::cast(*p); |
+ |
+ Object* map = obj->map(); |
+ |
+ if (!map->IsHeapObject()) return; // visited before |
+ |
+ if (found_target_) return; // stop if target found |
+ object_stack_.Add(obj); |
+ if ((search_for_any_global_ && obj->IsJSGlobalObject()) || |
+ (!search_for_any_global_ && (obj == search_target_))) { |
+ found_target_ = true; |
+ return; |
+ } |
+ |
+ // not visited yet |
+ Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); |
+ |
+ Address map_addr = map_p->address(); |
+ |
+ obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag)); |
+ |
+ MarkObjectRecursively(&map); |
+ |
+ MarkObjectVisitor mark_visitor(this); |
+ |
+ obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), |
+ &mark_visitor); |
+ |
+ if (!found_target_) // don't pop if found the target |
+ object_stack_.RemoveLast(); |
+ } |
+ |
+ |
+ class UnmarkObjectVisitor : public ObjectVisitor { |
+ public: |
+ explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { } |
+ |
+ void VisitPointers(Object** start, Object** end) { |
+ // Copy all HeapObject pointers in [start, end) |
+ for (Object** p = start; p < end; p++) { |
+ if ((*p)->IsHeapObject()) |
+ utils_->UnmarkObjectRecursively(p); |
+ } |
+ } |
+ |
+ HeapDebugUtils* utils_; |
+ }; |
+ |
+ |
+ void UnmarkObjectRecursively(Object** p) { |
+ if (!(*p)->IsHeapObject()) return; |
+ |
+ HeapObject* obj = HeapObject::cast(*p); |
+ |
+ Object* map = obj->map(); |
+ |
+ if (map->IsHeapObject()) return; // unmarked already |
+ |
+ Address map_addr = reinterpret_cast<Address>(map); |
+ |
+ map_addr -= kMarkTag; |
+ |
+ ASSERT_TAG_ALIGNED(map_addr); |
+ |
+ HeapObject* map_p = HeapObject::FromAddress(map_addr); |
+ |
+ obj->set_map(reinterpret_cast<Map*>(map_p)); |
+ |
+ UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); |
+ |
+ UnmarkObjectVisitor unmark_visitor(this); |
+ |
+ obj->IterateBody(Map::cast(map_p)->instance_type(), |
+ obj->SizeFromMap(Map::cast(map_p)), |
+ &unmark_visitor); |
+ } |
+ |
+ |
+ void MarkRootObjectRecursively(Object** root) { |
+ if (search_for_any_global_) { |
+ ASSERT(search_target_ == NULL); |
+ } else { |
+ ASSERT(search_target_->IsHeapObject()); |
+ } |
+ found_target_ = false; |
+ object_stack_.Clear(); |
+ |
+ MarkObjectRecursively(root); |
+ UnmarkObjectRecursively(root); |
+ |
+ if (found_target_) { |
+ PrintF("=====================================\n"); |
+ PrintF("==== Path to object ====\n"); |
+ PrintF("=====================================\n\n"); |
+ |
+ ASSERT(!object_stack_.is_empty()); |
+ for (int i = 0; i < object_stack_.length(); i++) { |
+ if (i > 0) PrintF("\n |\n |\n V\n\n"); |
+ Object* obj = object_stack_[i]; |
+ obj->Print(); |
+ } |
+ PrintF("=====================================\n"); |
+ } |
+ } |
+ |
+ // Helper class for visiting HeapObjects recursively. |
+ class MarkRootVisitor: public ObjectVisitor { |
+ public: |
+ explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { } |
+ |
+ void VisitPointers(Object** start, Object** end) { |
+ // Visit all HeapObject pointers in [start, end) |
+ for (Object** p = start; p < end; p++) { |
+ if ((*p)->IsHeapObject()) |
+ utils_->MarkRootObjectRecursively(p); |
+ } |
+ } |
+ |
+ HeapDebugUtils* utils_; |
+ }; |
+ |
+ bool search_for_any_global_; |
+ Object* search_target_; |
+ bool found_target_; |
+ List<Object*> object_stack_; |
+ Heap* heap_; |
+ |
+ friend class Heap; |
+}; |
+ |
+#endif |
+ |
bool Heap::Setup(bool create_heap_objects) { |
+#ifdef DEBUG |
+ debug_utils_ = new HeapDebugUtils(this); |
+#endif |
+ |
// Initialize heap spaces and initial maps and objects. Whenever something |
// goes wrong, just return false. The caller should check the results and |
// call Heap::TearDown() to release allocated memory. |
@@ -4552,13 +4746,19 @@ |
// Configuration is based on the flags new-space-size (really the semispace |
// size) and old-space-size if set or the initial values of semispace_size_ |
// and old_generation_size_ otherwise. |
- if (!heap_configured) { |
+ if (!configured_) { |
if (!ConfigureHeapDefault()) return false; |
} |
- ScavengingVisitor::Initialize(); |
- NewSpaceScavenger::Initialize(); |
- MarkCompactCollector::Initialize(); |
+ gc_initializer_mutex->Lock(); |
+ static bool initialized_gc = false; |
+ if (!initialized_gc) { |
+ initialized_gc = true; |
+ ScavengingVisitor::Initialize(); |
+ NewSpaceScavenger::Initialize(); |
+ MarkCompactCollector::Initialize(); |
+ } |
+ gc_initializer_mutex->Unlock(); |
MarkMapPointersAsEncoded(false); |
@@ -4566,9 +4766,11 @@ |
// space. The chunk is double the size of the requested reserved |
// new space size to ensure that we can find a pair of semispaces that |
// are contiguous and aligned to their size. |
- if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false; |
+ if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize())) |
+ return false; |
void* chunk = |
- MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_); |
+ isolate_->memory_allocator()->ReserveInitialChunk( |
+ 4 * reserved_semispace_size_); |
if (chunk == NULL) return false; |
// Align the pair of semispaces to their size, which must be a power |
@@ -4581,13 +4783,19 @@ |
// Initialize old pointer space. |
old_pointer_space_ = |
- new OldSpace(max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE); |
+ new OldSpace(this, |
+ max_old_generation_size_, |
+ OLD_POINTER_SPACE, |
+ NOT_EXECUTABLE); |
if (old_pointer_space_ == NULL) return false; |
if (!old_pointer_space_->Setup(NULL, 0)) return false; |
// Initialize old data space. |
old_data_space_ = |
- new OldSpace(max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE); |
+ new OldSpace(this, |
+ max_old_generation_size_, |
+ OLD_DATA_SPACE, |
+ NOT_EXECUTABLE); |
if (old_data_space_ == NULL) return false; |
if (!old_data_space_->Setup(NULL, 0)) return false; |
@@ -4596,18 +4804,18 @@ |
// On 64-bit platform(s), we put all code objects in a 2 GB range of |
// virtual address space, so that they can call each other with near calls. |
if (code_range_size_ > 0) { |
- if (!CodeRange::Setup(code_range_size_)) { |
+ if (!isolate_->code_range()->Setup(code_range_size_)) { |
return false; |
} |
} |
code_space_ = |
- new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE); |
+ new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); |
if (code_space_ == NULL) return false; |
if (!code_space_->Setup(NULL, 0)) return false; |
// Initialize map space. |
- map_space_ = new MapSpace(FLAG_use_big_map_space |
+ map_space_ = new MapSpace(this, FLAG_use_big_map_space |
? max_old_generation_size_ |
: MapSpace::kMaxMapPageIndex * Page::kPageSize, |
FLAG_max_map_space_pages, |
@@ -4616,14 +4824,14 @@ |
if (!map_space_->Setup(NULL, 0)) return false; |
// Initialize global property cell space. |
- cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE); |
+ cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); |
if (cell_space_ == NULL) return false; |
if (!cell_space_->Setup(NULL, 0)) return false; |
// The large object code space may contain code or data. We set the memory |
// to be non-executable here for safety, but this means we need to enable it |
// explicitly when allocating large code objects. |
- lo_space_ = new LargeObjectSpace(LO_SPACE); |
+ lo_space_ = new LargeObjectSpace(this, LO_SPACE); |
if (lo_space_ == NULL) return false; |
if (!lo_space_->Setup()) return false; |
@@ -4638,12 +4846,12 @@ |
global_contexts_list_ = undefined_value(); |
} |
- LOG(IntPtrTEvent("heap-capacity", Capacity())); |
- LOG(IntPtrTEvent("heap-available", Available())); |
+ LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); |
+ LOG(isolate_, IntPtrTEvent("heap-available", Available())); |
#ifdef ENABLE_LOGGING_AND_PROFILING |
// This should be called only after initial objects have been created. |
- ProducerHeapProfile::Setup(); |
+ isolate_->producer_heap_profile()->Setup(); |
#endif |
return true; |
@@ -4651,6 +4859,8 @@ |
void Heap::SetStackLimits() { |
+ ASSERT(isolate_ != NULL); |
+ ASSERT(isolate_ == isolate()); |
// On 64 bit machines, pointers are generally out of range of Smis. We write |
// something that looks like an out of range Smi to the GC. |
@@ -4658,10 +4868,10 @@ |
// These are actually addresses, but the tag makes the GC ignore it. |
roots_[kStackLimitRootIndex] = |
reinterpret_cast<Object*>( |
- (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag); |
+ (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); |
roots_[kRealStackLimitRootIndex] = |
reinterpret_cast<Object*>( |
- (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag); |
+ (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); |
} |
@@ -4671,16 +4881,16 @@ |
PrintF("gc_count=%d ", gc_count_); |
PrintF("mark_sweep_count=%d ", ms_count_); |
PrintF("mark_compact_count=%d ", mc_count_); |
- PrintF("max_gc_pause=%d ", GCTracer::get_max_gc_pause()); |
- PrintF("min_in_mutator=%d ", GCTracer::get_min_in_mutator()); |
+ PrintF("max_gc_pause=%d ", get_max_gc_pause()); |
+ PrintF("min_in_mutator=%d ", get_min_in_mutator()); |
PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", |
- GCTracer::get_max_alive_after_gc()); |
+ get_max_alive_after_gc()); |
PrintF("\n\n"); |
} |
- GlobalHandles::TearDown(); |
+ isolate_->global_handles()->TearDown(); |
- ExternalStringTable::TearDown(); |
+ external_string_table_.TearDown(); |
new_space_.TearDown(); |
@@ -4720,7 +4930,12 @@ |
lo_space_ = NULL; |
} |
- MemoryAllocator::TearDown(); |
+ isolate_->memory_allocator()->TearDown(); |
+ |
+#ifdef DEBUG |
+ delete debug_utils_; |
+ debug_utils_ = NULL; |
+#endif |
} |
@@ -4809,7 +5024,7 @@ |
void Heap::PrintHandles() { |
PrintF("Handles:\n"); |
PrintHandleVisitor v; |
- HandleScopeImplementer::Iterate(&v); |
+ isolate_->handle_scope_implementer()->Iterate(&v); |
} |
#endif |
@@ -4818,19 +5033,19 @@ |
Space* AllSpaces::next() { |
switch (counter_++) { |
case NEW_SPACE: |
- return Heap::new_space(); |
+ return HEAP->new_space(); |
case OLD_POINTER_SPACE: |
- return Heap::old_pointer_space(); |
+ return HEAP->old_pointer_space(); |
case OLD_DATA_SPACE: |
- return Heap::old_data_space(); |
+ return HEAP->old_data_space(); |
case CODE_SPACE: |
- return Heap::code_space(); |
+ return HEAP->code_space(); |
case MAP_SPACE: |
- return Heap::map_space(); |
+ return HEAP->map_space(); |
case CELL_SPACE: |
- return Heap::cell_space(); |
+ return HEAP->cell_space(); |
case LO_SPACE: |
- return Heap::lo_space(); |
+ return HEAP->lo_space(); |
default: |
return NULL; |
} |
@@ -4840,15 +5055,15 @@ |
PagedSpace* PagedSpaces::next() { |
switch (counter_++) { |
case OLD_POINTER_SPACE: |
- return Heap::old_pointer_space(); |
+ return HEAP->old_pointer_space(); |
case OLD_DATA_SPACE: |
- return Heap::old_data_space(); |
+ return HEAP->old_data_space(); |
case CODE_SPACE: |
- return Heap::code_space(); |
+ return HEAP->code_space(); |
case MAP_SPACE: |
- return Heap::map_space(); |
+ return HEAP->map_space(); |
case CELL_SPACE: |
- return Heap::cell_space(); |
+ return HEAP->cell_space(); |
default: |
return NULL; |
} |
@@ -4859,11 +5074,11 @@ |
OldSpace* OldSpaces::next() { |
switch (counter_++) { |
case OLD_POINTER_SPACE: |
- return Heap::old_pointer_space(); |
+ return HEAP->old_pointer_space(); |
case OLD_DATA_SPACE: |
- return Heap::old_data_space(); |
+ return HEAP->old_data_space(); |
case CODE_SPACE: |
- return Heap::code_space(); |
+ return HEAP->code_space(); |
default: |
return NULL; |
} |
@@ -4918,25 +5133,25 @@ |
switch (current_space_) { |
case NEW_SPACE: |
- iterator_ = new SemiSpaceIterator(Heap::new_space(), size_func_); |
+ iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_); |
break; |
case OLD_POINTER_SPACE: |
- iterator_ = new HeapObjectIterator(Heap::old_pointer_space(), size_func_); |
+ iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_); |
break; |
case OLD_DATA_SPACE: |
- iterator_ = new HeapObjectIterator(Heap::old_data_space(), size_func_); |
+ iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_); |
break; |
case CODE_SPACE: |
- iterator_ = new HeapObjectIterator(Heap::code_space(), size_func_); |
+ iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_); |
break; |
case MAP_SPACE: |
- iterator_ = new HeapObjectIterator(Heap::map_space(), size_func_); |
+ iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_); |
break; |
case CELL_SPACE: |
- iterator_ = new HeapObjectIterator(Heap::cell_space(), size_func_); |
+ iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_); |
break; |
case LO_SPACE: |
- iterator_ = new LargeObjectIterator(Heap::lo_space(), size_func_); |
+ iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_); |
break; |
} |
@@ -4970,16 +5185,17 @@ |
private: |
void MarkFreeListNodes() { |
- Heap::old_pointer_space()->MarkFreeListNodes(); |
- Heap::old_data_space()->MarkFreeListNodes(); |
- MarkCodeSpaceFreeListNodes(); |
- Heap::map_space()->MarkFreeListNodes(); |
- Heap::cell_space()->MarkFreeListNodes(); |
+ Heap* heap = HEAP; |
+ heap->old_pointer_space()->MarkFreeListNodes(); |
+ heap->old_data_space()->MarkFreeListNodes(); |
+ MarkCodeSpaceFreeListNodes(heap); |
+ heap->map_space()->MarkFreeListNodes(); |
+ heap->cell_space()->MarkFreeListNodes(); |
} |
- void MarkCodeSpaceFreeListNodes() { |
+ void MarkCodeSpaceFreeListNodes(Heap* heap) { |
// For code space, using FreeListNode::IsFreeListNode is OK. |
- HeapObjectIterator iter(Heap::code_space()); |
+ HeapObjectIterator iter(heap->code_space()); |
for (HeapObject* obj = iter.next_object(); |
obj != NULL; |
obj = iter.next_object()) { |
@@ -5041,7 +5257,7 @@ |
obj->SetMark(); |
} |
UnmarkingVisitor visitor; |
- Heap::IterateRoots(&visitor, VISIT_ALL); |
+ HEAP->IterateRoots(&visitor, VISIT_ALL); |
while (visitor.can_process()) |
visitor.ProcessNext(); |
} |
@@ -5344,7 +5560,7 @@ |
} |
-GCTracer::GCTracer() |
+GCTracer::GCTracer(Heap* heap) |
: start_time_(0.0), |
start_size_(0), |
gc_count_(0), |
@@ -5353,14 +5569,16 @@ |
marked_count_(0), |
allocated_since_last_gc_(0), |
spent_in_mutator_(0), |
- promoted_objects_size_(0) { |
+ promoted_objects_size_(0), |
+ heap_(heap) { |
// These two fields reflect the state of the previous full collection. |
// Set them before they are changed by the collector. |
- previous_has_compacted_ = MarkCompactCollector::HasCompacted(); |
- previous_marked_count_ = MarkCompactCollector::previous_marked_count(); |
+ previous_has_compacted_ = heap_->mark_compact_collector_.HasCompacted(); |
+ previous_marked_count_ = |
+ heap_->mark_compact_collector_.previous_marked_count(); |
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
start_time_ = OS::TimeCurrentMillis(); |
- start_size_ = Heap::SizeOfObjects(); |
+ start_size_ = heap_->SizeOfObjects(); |
for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
scopes_[i] = 0; |
@@ -5368,10 +5586,11 @@ |
in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); |
- allocated_since_last_gc_ = Heap::SizeOfObjects() - alive_after_last_gc_; |
+ allocated_since_last_gc_ = |
+ heap_->SizeOfObjects() - heap_->alive_after_last_gc_; |
- if (last_gc_end_timestamp_ > 0) { |
- spent_in_mutator_ = Max(start_time_ - last_gc_end_timestamp_, 0.0); |
+ if (heap_->last_gc_end_timestamp_ > 0) { |
+ spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); |
} |
} |
@@ -5380,20 +5599,21 @@ |
// Printf ONE line iff flag is set. |
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
- bool first_gc = (last_gc_end_timestamp_ == 0); |
+ bool first_gc = (heap_->last_gc_end_timestamp_ == 0); |
- alive_after_last_gc_ = Heap::SizeOfObjects(); |
- last_gc_end_timestamp_ = OS::TimeCurrentMillis(); |
+ heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); |
+ heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis(); |
- int time = static_cast<int>(last_gc_end_timestamp_ - start_time_); |
+ int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_); |
// Update cumulative GC statistics if required. |
if (FLAG_print_cumulative_gc_stat) { |
- max_gc_pause_ = Max(max_gc_pause_, time); |
- max_alive_after_gc_ = Max(max_alive_after_gc_, alive_after_last_gc_); |
+ heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time); |
+ heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_, |
+ heap_->alive_after_last_gc_); |
if (!first_gc) { |
- min_in_mutator_ = Min(min_in_mutator_, |
- static_cast<int>(spent_in_mutator_)); |
+ heap_->min_in_mutator_ = Min(heap_->min_in_mutator_, |
+ static_cast<int>(spent_in_mutator_)); |
} |
} |
@@ -5418,7 +5638,8 @@ |
PrintF("s"); |
break; |
case MARK_COMPACTOR: |
- PrintF(MarkCompactCollector::HasCompacted() ? "mc" : "ms"); |
+ PrintF("%s", |
+ heap_->mark_compact_collector_.HasCompacted() ? "mc" : "ms"); |
break; |
default: |
UNREACHABLE(); |
@@ -5432,7 +5653,7 @@ |
PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); |
PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); |
- PrintF("total_size_after=%" V8_PTR_PREFIX "d ", Heap::SizeOfObjects()); |
+ PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); |
PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", |
in_free_list_or_wasted_before_gc_); |
PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); |
@@ -5444,7 +5665,7 @@ |
} |
#if defined(ENABLE_LOGGING_AND_PROFILING) |
- Heap::PrintShortHeapStatistics(); |
+ heap_->PrintShortHeapStatistics(); |
#endif |
} |
@@ -5454,8 +5675,8 @@ |
case SCAVENGER: |
return "Scavenge"; |
case MARK_COMPACTOR: |
- return MarkCompactCollector::HasCompacted() ? "Mark-compact" |
- : "Mark-sweep"; |
+ return heap_->mark_compact_collector_.HasCompacted() ? "Mark-compact" |
+ : "Mark-sweep"; |
} |
return "Unknown GC"; |
} |
@@ -5475,13 +5696,13 @@ |
if ((key.map == map) && key.name->Equals(name)) { |
return field_offsets_[index]; |
} |
- return -1; |
+ return kNotFound; |
} |
void KeyedLookupCache::Update(Map* map, String* name, int field_offset) { |
String* symbol; |
- if (Heap::LookupSymbolIfExists(name, &symbol)) { |
+ if (HEAP->LookupSymbolIfExists(name, &symbol)) { |
int index = Hash(map, symbol); |
Key& key = keys_[index]; |
key.map = map; |
@@ -5496,35 +5717,24 @@ |
} |
-KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength]; |
- |
- |
-int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength]; |
- |
- |
void DescriptorLookupCache::Clear() { |
for (int index = 0; index < kLength; index++) keys_[index].array = NULL; |
} |
-DescriptorLookupCache::Key |
-DescriptorLookupCache::keys_[DescriptorLookupCache::kLength]; |
- |
-int DescriptorLookupCache::results_[DescriptorLookupCache::kLength]; |
- |
- |
#ifdef DEBUG |
void Heap::GarbageCollectionGreedyCheck() { |
ASSERT(FLAG_gc_greedy); |
- if (Bootstrapper::IsActive()) return; |
+ if (isolate_->bootstrapper()->IsActive()) return; |
if (disallow_allocation_failure()) return; |
CollectGarbage(NEW_SPACE); |
} |
#endif |
-TranscendentalCache::TranscendentalCache(TranscendentalCache::Type t) |
- : type_(t) { |
+TranscendentalCache::SubCache::SubCache(Type t) |
+ : type_(t), |
+ isolate_(Isolate::Current()) { |
uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't |
uint32_t in1 = 0xffffffffu; // generated by the FPU. |
for (int i = 0; i < kCacheSize; i++) { |
@@ -5535,9 +5745,6 @@ |
} |
-TranscendentalCache* TranscendentalCache::caches_[kNumberOfCaches]; |
- |
- |
void TranscendentalCache::Clear() { |
for (int i = 0; i < kNumberOfCaches; i++) { |
if (caches_[i] != NULL) { |
@@ -5551,8 +5758,8 @@ |
void ExternalStringTable::CleanUp() { |
int last = 0; |
for (int i = 0; i < new_space_strings_.length(); ++i) { |
- if (new_space_strings_[i] == Heap::raw_unchecked_null_value()) continue; |
- if (Heap::InNewSpace(new_space_strings_[i])) { |
+ if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; |
+ if (heap_->InNewSpace(new_space_strings_[i])) { |
new_space_strings_[last++] = new_space_strings_[i]; |
} else { |
old_space_strings_.Add(new_space_strings_[i]); |
@@ -5561,8 +5768,8 @@ |
new_space_strings_.Rewind(last); |
last = 0; |
for (int i = 0; i < old_space_strings_.length(); ++i) { |
- if (old_space_strings_[i] == Heap::raw_unchecked_null_value()) continue; |
- ASSERT(!Heap::InNewSpace(old_space_strings_[i])); |
+ if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; |
+ ASSERT(!heap_->InNewSpace(old_space_strings_[i])); |
old_space_strings_[last++] = old_space_strings_[i]; |
} |
old_space_strings_.Rewind(last); |
@@ -5576,7 +5783,4 @@ |
} |
-List<Object*> ExternalStringTable::new_space_strings_; |
-List<Object*> ExternalStringTable::old_space_strings_; |
- |
} } // namespace v8::internal |