From a49c8a19ee1df6516342e6e847cdf68417f0b43e Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Wed, 25 Jan 2012 14:27:58 +0000 Subject: [PATCH] Flush number string cache on GC (bug 1605). Also start with a small number string cache and only grow it if needed, which will be useful for saving boot time memory use. Review URL: https://chromiumcodereview.appspot.com/9235029 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10502 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/heap.cc | 60 ++++++++++++++++++++++++++++++---------- src/heap.h | 10 +++++-- test/cctest/test-mark-compact.cc | 2 +- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/heap.cc b/src/heap.cc index 3b5dc82..7e5880f 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -902,8 +902,7 @@ void Heap::MarkCompactPrologue() { CompletelyClearInstanceofCache(); - // TODO(1605) select heuristic for flushing NumberString cache with - // FlushNumberStringCache + FlushNumberStringCache(); if (FLAG_cleanup_code_caches_at_gc) { polymorphic_code_cache()->set_cache(undefined_value()); } @@ -2512,7 +2511,10 @@ bool Heap::CreateInitialObjects() { } set_intrinsic_function_names(StringDictionary::cast(obj)); - if (InitializeNumberStringCache()->IsFailure()) return false; + { MaybeObject* maybe_obj = AllocateInitialNumberStringCache(); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_number_string_cache(FixedArray::cast(obj)); // Allocate cache for single character ASCII strings. { MaybeObject* maybe_obj = @@ -2622,20 +2624,44 @@ void StringSplitCache::Clear(FixedArray* cache) { } -MaybeObject* Heap::InitializeNumberStringCache() { - // Compute the size of the number string cache based on the max heap size. - // max_semispace_size_ == 512 KB => number_string_cache_size = 32. - // max_semispace_size_ == 8 MB => number_string_cache_size = 16KB. - int number_string_cache_size = max_semispace_size_ / 512; - number_string_cache_size = Max(32, Min(16*KB, number_string_cache_size)); - Object* obj; +MaybeObject* Heap::AllocateInitialNumberStringCache() { MaybeObject* maybe_obj = - AllocateFixedArray(number_string_cache_size * 2, TENURED); - if (maybe_obj->ToObject(&obj)) set_number_string_cache(FixedArray::cast(obj)); + AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED); return maybe_obj; } +int Heap::FullSizeNumberStringCacheLength() { + // Compute the size of the number string cache based on the max newspace size. + // The number string cache has a minimum size based on twice the initial cache + // size to ensure that it is bigger after being made 'full size'. + int number_string_cache_size = max_semispace_size_ / 512; + number_string_cache_size = Max(kInitialNumberStringCacheSize * 2, + Min(0x4000, number_string_cache_size)); + // There is a string and a number per entry so the length is twice the number + // of entries. + return number_string_cache_size * 2; +} + + +void Heap::AllocateFullSizeNumberStringCache() { + // The idea is to have a small number string cache in the snapshot to keep + // boot-time memory usage down. If we expand the number string cache already + // while creating the snapshot then that didn't work out. + ASSERT(!Serializer::enabled()); + MaybeObject* maybe_obj = + AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED); + Object* new_cache; + if (maybe_obj->ToObject(&new_cache)) { + // We don't bother to repopulate the cache with entries from the old cache. + // It will be repopulated soon enough with new strings. + set_number_string_cache(FixedArray::cast(new_cache)); + } + // If allocation fails then we just return without doing anything. It is only + // a cache, so best effort is OK here. +} + + void Heap::FlushNumberStringCache() { // Flush the number to string cache. int len = number_string_cache()->length(); @@ -2681,11 +2707,17 @@ void Heap::SetNumberStringCache(Object* number, String* string) { int mask = (number_string_cache()->length() >> 1) - 1; if (number->IsSmi()) { hash = smi_get_hash(Smi::cast(number)) & mask; - number_string_cache()->set(hash * 2, Smi::cast(number)); } else { hash = double_get_hash(number->Number()) & mask; - number_string_cache()->set(hash * 2, number); } + if (number_string_cache()->get(hash * 2) != undefined_value() && + number_string_cache()->length() != FullSizeNumberStringCacheLength()) { + // The first time we have a hash collision, we move to the full sized + // number string cache. + AllocateFullSizeNumberStringCache(); + return; + } + number_string_cache()->set(hash * 2, number); number_string_cache()->set(hash * 2 + 1, string); } diff --git a/src/heap.h b/src/heap.h index c8ac927..e894622 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1798,8 +1798,13 @@ class Heap { GCTracer* tracer_; - // Initializes the number to string cache based on the max semispace size. - MUST_USE_RESULT MaybeObject* InitializeNumberStringCache(); + // Allocates a small number to string cache. + MUST_USE_RESULT MaybeObject* AllocateInitialNumberStringCache(); + // Creates and installs the full-sized number string cache. + void AllocateFullSizeNumberStringCache(); + // Get the length of the number to string cache based on the max semispace + // size. + int FullSizeNumberStringCacheLength(); // Flush the number to string cache. void FlushNumberStringCache(); @@ -1896,6 +1901,7 @@ class Heap { static const int kInitialSymbolTableSize = 2048; static const int kInitialEvalCacheSize = 64; + static const int kInitialNumberStringCacheSize = 256; // Maximum GC pause. int max_gc_pause_; diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc index 614b1fd..9de069d 100644 --- a/test/cctest/test-mark-compact.cc +++ b/test/cctest/test-mark-compact.cc @@ -540,7 +540,7 @@ TEST(BootUpMemoryUse) { } } else { if (v8::internal::Snapshot::IsEnabled()) { - CHECK_LE(booted_memory - initial_memory, 6500 * 1024); // 6365. + CHECK_LE(booted_memory - initial_memory, 6500 * 1024); // 6356. } else { CHECK_LE(booted_memory - initial_memory, 6654 * 1024); // 6424 } -- 2.7.4