diff options
Diffstat (limited to 'deps/v8/src/heap.cc')
-rw-r--r-- | deps/v8/src/heap.cc | 308 |
1 files changed, 223 insertions, 85 deletions
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 817a50f163..ae18fbe6b7 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -39,9 +39,11 @@ #include "natives.h" #include "scanner.h" #include "scopeinfo.h" +#include "snapshot.h" #include "v8threads.h" #if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP #include "regexp-macro-assembler.h" +#include "arm/regexp-macro-assembler-arm.h" #endif namespace v8 { @@ -74,28 +76,35 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0; // semispace_size_ should be a power of 2 and old_generation_size_ should be // a multiple of Page::kPageSize. #if defined(ANDROID) -int Heap::semispace_size_ = 512*KB; -int Heap::old_generation_size_ = 128*MB; +int Heap::max_semispace_size_ = 512*KB; +int Heap::max_old_generation_size_ = 128*MB; int Heap::initial_semispace_size_ = 128*KB; size_t Heap::code_range_size_ = 0; #elif defined(V8_TARGET_ARCH_X64) -int Heap::semispace_size_ = 16*MB; -int Heap::old_generation_size_ = 1*GB; +int Heap::max_semispace_size_ = 16*MB; +int Heap::max_old_generation_size_ = 1*GB; int Heap::initial_semispace_size_ = 1*MB; size_t Heap::code_range_size_ = 512*MB; #else -int Heap::semispace_size_ = 8*MB; -int Heap::old_generation_size_ = 512*MB; +int Heap::max_semispace_size_ = 8*MB; +int Heap::max_old_generation_size_ = 512*MB; int Heap::initial_semispace_size_ = 512*KB; size_t Heap::code_range_size_ = 0; #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_; + GCCallback Heap::global_gc_prologue_callback_ = NULL; GCCallback Heap::global_gc_epilogue_callback_ = NULL; // Variables set based on semispace_size_ and old_generation_size_ in // ConfigureHeap. -int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_. + +// Will be 4 * reserved_semispace_size_ to ensure that young +// generation can be aligned to its size. int Heap::survived_since_last_expansion_ = 0; int Heap::external_allocation_limit_ = 0; @@ -105,6 +114,7 @@ int Heap::mc_count_ = 0; int Heap::gc_count_ = 0; int Heap::always_allocate_scope_depth_ = 0; +int Heap::linear_allocation_scope_depth_ = 0; bool Heap::context_disposed_pending_ = false; #ifdef DEBUG @@ -127,6 +137,19 @@ int Heap::Capacity() { } +int Heap::CommittedMemory() { + if (!HasBeenSetup()) return 0; + + return new_space_.CommittedMemory() + + old_pointer_space_->CommittedMemory() + + old_data_space_->CommittedMemory() + + code_space_->CommittedMemory() + + map_space_->CommittedMemory() + + cell_space_->CommittedMemory() + + lo_space_->Size(); +} + + int Heap::Available() { if (!HasBeenSetup()) return 0; @@ -222,19 +245,34 @@ void Heap::ReportStatisticsBeforeGC() { void Heap::PrintShortHeapStatistics() { if (!FLAG_trace_gc_verbose) return; PrintF("Memory allocator, used: %8d, available: %8d\n", - MemoryAllocator::Size(), MemoryAllocator::Available()); + MemoryAllocator::Size(), + MemoryAllocator::Available()); PrintF("New space, used: %8d, available: %8d\n", - Heap::new_space_.Size(), new_space_.Available()); - PrintF("Old pointers, used: %8d, available: %8d\n", - old_pointer_space_->Size(), old_pointer_space_->Available()); - PrintF("Old data space, used: %8d, available: %8d\n", - old_data_space_->Size(), old_data_space_->Available()); - PrintF("Code space, used: %8d, available: %8d\n", - code_space_->Size(), code_space_->Available()); - PrintF("Map space, used: %8d, available: %8d\n", - map_space_->Size(), map_space_->Available()); + Heap::new_space_.Size(), + new_space_.Available()); + PrintF("Old pointers, used: %8d, available: %8d, waste: %8d\n", + old_pointer_space_->Size(), + old_pointer_space_->Available(), + old_pointer_space_->Waste()); + PrintF("Old data space, used: %8d, available: %8d, waste: %8d\n", + old_data_space_->Size(), + old_data_space_->Available(), + old_data_space_->Waste()); + PrintF("Code space, used: %8d, available: %8d, waste: %8d\n", + code_space_->Size(), + code_space_->Available(), + code_space_->Waste()); + PrintF("Map space, used: %8d, available: %8d, waste: %8d\n", + map_space_->Size(), + map_space_->Available(), + map_space_->Waste()); + PrintF("Cell space, used: %8d, available: %8d, waste: %8d\n", + cell_space_->Size(), + cell_space_->Available(), + cell_space_->Waste()); PrintF("Large object space, used: %8d, avaialble: %8d\n", - lo_space_->Size(), lo_space_->Available()); + lo_space_->Size(), + lo_space_->Available()); } #endif @@ -478,7 +516,13 @@ void Heap::PerformGarbageCollection(AllocationSpace space, Counters::objs_since_last_young.Set(0); - PostGarbageCollectionProcessing(); + if (collector == MARK_COMPACTOR) { + DisableAssertNoAllocation allow_allocation; + GlobalHandles::PostGarbageCollectionProcessing(); + } + + // Update relocatables. + Relocatable::PostGarbageCollectionProcessing(); if (collector == MARK_COMPACTOR) { // Register the amount of external allocated memory. @@ -494,17 +538,6 @@ void Heap::PerformGarbageCollection(AllocationSpace space, } -void Heap::PostGarbageCollectionProcessing() { - // Process weak handles post gc. - { - DisableAssertNoAllocation allow_allocation; - GlobalHandles::PostGarbageCollectionProcessing(); - } - // Update relocatables. - Relocatable::PostGarbageCollectionProcessing(); -} - - void Heap::MarkCompact(GCTracer* tracer) { gc_state_ = MARK_COMPACT; mc_count_++; @@ -1195,6 +1228,41 @@ bool Heap::CreateInitialMaps() { if (obj->IsFailure()) return false; set_pixel_array_map(Map::cast(obj)); + obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_byte_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_unsigned_byte_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_short_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_unsigned_short_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_int_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_unsigned_int_array_map(Map::cast(obj)); + + obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE, + ExternalArray::kAlignedSize); + if (obj->IsFailure()) return false; + set_external_float_array_map(Map::cast(obj)); + obj = AllocateMap(CODE_TYPE, Code::kHeaderSize); if (obj->IsFailure()) return false; set_code_map(Map::cast(obj)); @@ -1615,6 +1683,35 @@ Object* Heap::NumberToString(Object* number) { } +Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { + return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); +} + + +Heap::RootListIndex Heap::RootIndexForExternalArrayType( + ExternalArrayType array_type) { + switch (array_type) { + case kExternalByteArray: + return kExternalByteArrayMapRootIndex; + case kExternalUnsignedByteArray: + return kExternalUnsignedByteArrayMapRootIndex; + case kExternalShortArray: + return kExternalShortArrayMapRootIndex; + case kExternalUnsignedShortArray: + return kExternalUnsignedShortArrayMapRootIndex; + case kExternalIntArray: + return kExternalIntArrayMapRootIndex; + case kExternalUnsignedIntArray: + return kExternalUnsignedIntArrayMapRootIndex; + case kExternalFloatArray: + return kExternalFloatArrayMapRootIndex; + default: + UNREACHABLE(); + return kUndefinedValueRootIndex; + } +} + + Object* Heap::NewNumberFromDouble(double value, PretenureFlag pretenure) { return SmiOrNumberFromDouble(value, true /* number object must be new */, @@ -1713,10 +1810,10 @@ Object* Heap::AllocateConsString(String* first, String* second) { } Map* map; - if (length <= String::kMaxShortStringSize) { + if (length <= String::kMaxShortSize) { map = is_ascii ? short_cons_ascii_string_map() : short_cons_string_map(); - } else if (length <= String::kMaxMediumStringSize) { + } else if (length <= String::kMaxMediumSize) { map = is_ascii ? medium_cons_ascii_string_map() : medium_cons_string_map(); } else { @@ -1746,11 +1843,11 @@ Object* Heap::AllocateSlicedString(String* buffer, } Map* map; - if (length <= String::kMaxShortStringSize) { + if (length <= String::kMaxShortSize) { map = buffer->IsAsciiRepresentation() ? short_sliced_ascii_string_map() : short_sliced_string_map(); - } else if (length <= String::kMaxMediumStringSize) { + } else if (length <= String::kMaxMediumSize) { map = buffer->IsAsciiRepresentation() ? medium_sliced_ascii_string_map() : medium_sliced_string_map(); @@ -1815,9 +1912,9 @@ Object* Heap::AllocateExternalStringFromAscii( ExternalAsciiString::Resource* resource) { Map* map; int length = resource->length(); - if (length <= String::kMaxShortStringSize) { + if (length <= String::kMaxShortSize) { map = short_external_ascii_string_map(); - } else if (length <= String::kMaxMediumStringSize) { + } else if (length <= String::kMaxMediumSize) { map = medium_external_ascii_string_map(); } else { map = long_external_ascii_string_map(); @@ -1940,6 +2037,31 @@ Object* Heap::AllocatePixelArray(int length, } +Object* Heap::AllocateExternalArray(int length, + ExternalArrayType array_type, + void* external_pointer, + PretenureFlag pretenure) { + AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; + + // New space can't cope with forced allocation. + if (always_allocate()) space = OLD_DATA_SPACE; + + Object* result = AllocateRaw(ExternalArray::kAlignedSize, + space, + OLD_DATA_SPACE); + + if (result->IsFailure()) return result; + + reinterpret_cast<ExternalArray*>(result)->set_map( + MapForExternalArrayType(array_type)); + reinterpret_cast<ExternalArray*>(result)->set_length(length); + reinterpret_cast<ExternalArray*>(result)->set_external_pointer( + external_pointer); + + return result; +} + + Object* Heap::CreateCode(const CodeDesc& desc, ZoneScopeInfo* sinfo, Code::Flags flags, @@ -2021,7 +2143,9 @@ Object* Heap::Allocate(Map* map, AllocationSpace space) { TargetSpaceId(map->instance_type())); if (result->IsFailure()) return result; HeapObject::cast(result)->set_map(map); +#ifdef ENABLE_LOGGING_AND_PROFILING ProducerHeapProfile::RecordJSObjectAllocation(result); +#endif return result; } @@ -2134,7 +2258,7 @@ Object* Heap::AllocateInitialMap(JSFunction* fun) { // descriptors for these to the initial map as the object cannot be // constructed without having these properties. ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields); - if (fun->shared()->has_only_this_property_assignments() && + if (fun->shared()->has_only_simple_this_property_assignments() && fun->shared()->this_property_assignments_count() > 0) { int count = fun->shared()->this_property_assignments_count(); if (count > in_object_properties) { @@ -2343,7 +2467,9 @@ Object* Heap::CopyJSObject(JSObject* source) { JSObject::cast(clone)->set_properties(FixedArray::cast(prop)); } // Return the new clone. +#ifdef ENABLE_LOGGING_AND_PROFILING ProducerHeapProfile::RecordJSObjectAllocation(clone); +#endif return clone; } @@ -2533,18 +2659,18 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, Map* map; if (is_ascii) { - if (chars <= String::kMaxShortStringSize) { + if (chars <= String::kMaxShortSize) { map = short_ascii_symbol_map(); - } else if (chars <= String::kMaxMediumStringSize) { + } else if (chars <= String::kMaxMediumSize) { map = medium_ascii_symbol_map(); } else { map = long_ascii_symbol_map(); } size = SeqAsciiString::SizeFor(chars); } else { - if (chars <= String::kMaxShortStringSize) { + if (chars <= String::kMaxShortSize) { map = short_symbol_map(); - } else if (chars <= String::kMaxMediumStringSize) { + } else if (chars <= String::kMaxMediumSize) { map = medium_symbol_map(); } else { map = long_symbol_map(); @@ -2594,9 +2720,9 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { // Determine the map based on the string's length. Map* map; - if (length <= String::kMaxShortStringSize) { + if (length <= String::kMaxShortSize) { map = short_ascii_string_map(); - } else if (length <= String::kMaxMediumStringSize) { + } else if (length <= String::kMaxMediumSize) { map = medium_ascii_string_map(); } else { map = long_ascii_string_map(); @@ -2631,9 +2757,9 @@ Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) { // Determine the map based on the string's length. Map* map; - if (length <= String::kMaxShortStringSize) { + if (length <= String::kMaxShortSize) { map = short_string_map(); - } else if (length <= String::kMaxMediumStringSize) { + } else if (length <= String::kMaxMediumSize) { map = medium_string_map(); } else { map = long_string_map(); @@ -3118,60 +3244,53 @@ void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) { } -#ifdef DEBUG -#define SYNCHRONIZE_TAG(tag) v->Synchronize(tag) -#else -#define SYNCHRONIZE_TAG(tag) -#endif - void Heap::IterateRoots(ObjectVisitor* v) { IterateStrongRoots(v); v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); - SYNCHRONIZE_TAG("symbol_table"); + v->Synchronize("symbol_table"); } void Heap::IterateStrongRoots(ObjectVisitor* v) { v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); - SYNCHRONIZE_TAG("strong_root_list"); + v->Synchronize("strong_root_list"); v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_)); - SYNCHRONIZE_TAG("symbol"); + v->Synchronize("symbol"); Bootstrapper::Iterate(v); - SYNCHRONIZE_TAG("bootstrapper"); + v->Synchronize("bootstrapper"); Top::Iterate(v); - SYNCHRONIZE_TAG("top"); + v->Synchronize("top"); Relocatable::Iterate(v); - SYNCHRONIZE_TAG("relocatable"); + v->Synchronize("relocatable"); #ifdef ENABLE_DEBUGGER_SUPPORT Debug::Iterate(v); #endif - SYNCHRONIZE_TAG("debug"); + v->Synchronize("debug"); CompilationCache::Iterate(v); - SYNCHRONIZE_TAG("compilationcache"); + v->Synchronize("compilationcache"); // Iterate over local handles in handle scopes. HandleScopeImplementer::Iterate(v); - SYNCHRONIZE_TAG("handlescope"); + v->Synchronize("handlescope"); // Iterate over the builtin code objects and code stubs in the heap. Note // that it is not strictly necessary to iterate over code objects on // scavenge collections. We still do it here because this same function // is used by the mark-sweep collector and the deserializer. Builtins::IterateBuiltins(v); - SYNCHRONIZE_TAG("builtins"); + v->Synchronize("builtins"); // Iterate over global handles. GlobalHandles::IterateRoots(v); - SYNCHRONIZE_TAG("globalhandles"); + v->Synchronize("globalhandles"); // Iterate over pointers being held by inactive threads. ThreadManager::Iterate(v); - SYNCHRONIZE_TAG("threadmanager"); + v->Synchronize("threadmanager"); } -#undef SYNCHRONIZE_TAG // Flag is set when the heap has been configured. The heap can be repeatedly @@ -3181,21 +3300,37 @@ 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. -bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) { +bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { if (HasBeenSetup()) return false; - if (semispace_size > 0) semispace_size_ = semispace_size; - if (old_gen_size > 0) old_generation_size_ = old_gen_size; + if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; + + if (Snapshot::IsEnabled()) { + // If we are using a snapshot we always reserve the default amount + // of memory for each semispace because code in the snapshot has + // write-barrier code that relies on the size and alignment of new + // space. We therefore cannot use a larger max semispace size + // than the default reserved semispace size. + if (max_semispace_size_ > reserved_semispace_size_) { + max_semispace_size_ = reserved_semispace_size_; + } + } else { + // If we are not using snapshots we reserve space for the actual + // max semispace size. + reserved_semispace_size_ = max_semispace_size_; + } + + if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; // The new space size must be a power of two to support single-bit testing // for containment. - semispace_size_ = RoundUpToPowerOf2(semispace_size_); - initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_); - young_generation_size_ = 2 * semispace_size_; - external_allocation_limit_ = 10 * semispace_size_; + max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); + reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); + initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); + external_allocation_limit_ = 10 * max_semispace_size_; // The old generation is paged. - old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize); + max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize); heap_configured = true; return true; @@ -3203,7 +3338,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) { bool Heap::ConfigureHeapDefault() { - return ConfigureHeap(FLAG_new_space_size, FLAG_old_space_size); + return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size); } @@ -3239,30 +3374,31 @@ bool Heap::Setup(bool create_heap_objects) { } // Setup memory allocator and reserve a chunk of memory for new - // space. The chunk is double the size of the new space to ensure - // that we can find a pair of semispaces that are contiguous and - // aligned to their size. - if (!MemoryAllocator::Setup(MaxCapacity())) return false; + // 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())) return false; void* chunk = - MemoryAllocator::ReserveInitialChunk(2 * young_generation_size_); + MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_); if (chunk == NULL) return false; // Align the pair of semispaces to their size, which must be a power // of 2. - ASSERT(IsPowerOf2(young_generation_size_)); Address new_space_start = - RoundUp(reinterpret_cast<byte*>(chunk), young_generation_size_); - if (!new_space_.Setup(new_space_start, young_generation_size_)) return false; + RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_); + if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) { + return false; + } // Initialize old pointer space. old_pointer_space_ = - new OldSpace(old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE); + new OldSpace(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(old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE); + new OldSpace(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; @@ -3277,7 +3413,7 @@ bool Heap::Setup(bool create_heap_objects) { } code_space_ = - new OldSpace(old_generation_size_, CODE_SPACE, EXECUTABLE); + new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE); if (code_space_ == NULL) return false; if (!code_space_->Setup(NULL, 0)) return false; @@ -3287,7 +3423,7 @@ bool Heap::Setup(bool create_heap_objects) { if (!map_space_->Setup(NULL, 0)) return false; // Initialize global property cell space. - cell_space_ = new CellSpace(old_generation_size_, CELL_SPACE); + cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE); if (cell_space_ == NULL) return false; if (!cell_space_->Setup(NULL, 0)) return false; @@ -3310,8 +3446,10 @@ bool Heap::Setup(bool create_heap_objects) { LOG(IntEvent("heap-capacity", Capacity())); LOG(IntEvent("heap-available", Available())); +#ifdef ENABLE_LOGGING_AND_PROFILING // This should be called only after initial objects have been created. ProducerHeapProfile::Setup(); +#endif return true; } |