From: sgjesse@chromium.org Date: Mon, 22 Jun 2009 11:12:51 +0000 (+0000) Subject: Refactor the handling of generations in the compilation cache. X-Git-Tag: upstream/4.7.83~23851 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3ce873c351a54d2d699df9e2ed4692732184adca;p=platform%2Fupstream%2Fv8.git Refactor the handling of generations in the compilation cache. Add generations to the compilation cache for eval and regexp. The number of generations for these are set to two. BUG=none TEST=none Review URL: http://codereview.chromium.org/140056 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2233 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc index 421b676..fd706af 100644 --- a/src/compilation-cache.cc +++ b/src/compilation-cache.cc @@ -32,28 +32,123 @@ namespace v8 { namespace internal { -enum { - // The number of script generations tell how many GCs a script can - // survive in the compilation cache, before it will be flushed if it - // hasn't been used. - NUMBER_OF_SCRIPT_GENERATIONS = 5, - - // The compilation cache consists of tables - one for each entry - // kind plus extras for the script generations. - NUMBER_OF_TABLE_ENTRIES = - CompilationCache::LAST_ENTRY + NUMBER_OF_SCRIPT_GENERATIONS + +// The number of sub caches covering the different types to cache. +static const int kSubCacheCount = 4; + +// The number of generations for each sub cache. +static const int kScriptGenerations = 5; +static const int kEvalGlobalGenerations = 2; +static const int kEvalContextualGenerations = 2; +static const int kRegExpGenerations = 2; + +// Initial of each compilation cache table allocated. +static const int kInitialCacheSize = 64; + +// The compilation cache consists of several generational sub-caches which uses +// this class as a base class. A sub-cache contains a compilation cache tables +// for each generation of the sub-cache. As the same source code string has +// different compiled code for scripts and evals. Internally, we use separate +// sub-caches to avoid getting the wrong kind of result when looking up. +class CompilationSubCache { + public: + explicit CompilationSubCache(int generations): generations_(generations) { + tables_ = NewArray(generations); + } + + // Get the compilation cache tables for a specific generation. + Handle GetTable(int generation); + + // Age the sub-cache by evicting the oldest generation and creating a new + // young generation. + void Age(); + + // GC support. + void Iterate(ObjectVisitor* v); + + // Clear this sub-cache evicting all its content. + void Clear(); + + // Number of generations in this sub-cache. + inline int generations() { return generations_; } + + private: + int generations_; // Number of generations. + Object** tables_; // Compilation cache tables - one for each generation. + + DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache); }; +// Sub-cache for scripts. +class CompilationCacheScript : public CompilationSubCache { + public: + explicit CompilationCacheScript(int generations) + : CompilationSubCache(generations) { } + + Handle Lookup(Handle source, + Handle name, + int line_offset, + int column_offset); + void Put(Handle source, Handle boilerplate); + + private: + bool HasOrigin(Handle boilerplate, + Handle name, + int line_offset, + int column_offset); + + DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript); +}; + + +// Sub-cache for eval scripts. +class CompilationCacheEval: public CompilationSubCache { + public: + explicit CompilationCacheEval(int generations) + : CompilationSubCache(generations) { } + + Handle Lookup(Handle source, Handle context); + + void Put(Handle source, + Handle context, + Handle boilerplate); + + DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval); +}; + + +// Sub-cache for regular expressions. +class CompilationCacheRegExp: public CompilationSubCache { + public: + explicit CompilationCacheRegExp(int generations) + : CompilationSubCache(generations) { } + + Handle Lookup(Handle source, JSRegExp::Flags flags); + + void Put(Handle source, + JSRegExp::Flags flags, + Handle data); + + DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp); +}; + + +// Statically allocate all the sub-caches. +static CompilationCacheScript script(kScriptGenerations); +static CompilationCacheEval eval_global(kEvalGlobalGenerations); +static CompilationCacheEval eval_contextual(kEvalContextualGenerations); +static CompilationCacheRegExp reg_exp(kRegExpGenerations); +static CompilationSubCache* subcaches[kSubCacheCount] = + {&script, &eval_global, &eval_contextual, ®_exp}; + + // Current enable state of the compilation cache. static bool enabled = true; static inline bool IsEnabled() { return FLAG_compilation_cache && enabled; } -// Keep separate tables for the different entry kinds. -static Object* tables[NUMBER_OF_TABLE_ENTRIES] = { 0, }; - static Handle AllocateTable(int size) { CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size), @@ -61,54 +156,40 @@ static Handle AllocateTable(int size) { } -static Handle GetTable(int index) { - ASSERT(index >= 0 && index < NUMBER_OF_TABLE_ENTRIES); +Handle CompilationSubCache::GetTable(int generation) { + ASSERT(generation < generations_); Handle result; - if (tables[index]->IsUndefined()) { - static const int kInitialCacheSize = 64; + if (tables_[generation]->IsUndefined()) { result = AllocateTable(kInitialCacheSize); - tables[index] = *result; + tables_[generation] = *result; } else { - CompilationCacheTable* table = CompilationCacheTable::cast(tables[index]); + CompilationCacheTable* table = + CompilationCacheTable::cast(tables_[generation]); result = Handle(table); } return result; } -static Handle Lookup(Handle source, - Handle context, - CompilationCache::Entry entry) { - // Make sure not to leak the table into the surrounding handle - // scope. Otherwise, we risk keeping old tables around even after - // having cleared the cache. - Object* result; - { HandleScope scope; - Handle table = GetTable(entry); - result = table->LookupEval(*source, *context); - } - if (result->IsJSFunction()) { - return Handle(JSFunction::cast(result)); - } else { - return Handle::null(); +void CompilationSubCache::Age() { + // Age the generations implicitly killing off the oldest. + for (int i = generations_ - 1; i > 0; i--) { + tables_[i] = tables_[i - 1]; } + + // Set the first generation as unborn. + tables_[0] = Heap::undefined_value(); } -static Handle Lookup(Handle source, - JSRegExp::Flags flags) { - // Make sure not to leak the table into the surrounding handle - // scope. Otherwise, we risk keeping old tables around even after - // having cleared the cache. - Object* result; - { HandleScope scope; - Handle table = GetTable(CompilationCache::REGEXP); - result = table->LookupRegExp(*source, flags); - } - if (result->IsFixedArray()) { - return Handle(FixedArray::cast(result)); - } else { - return Handle::null(); +void CompilationSubCache::Iterate(ObjectVisitor* v) { + v->VisitPointers(&tables_[0], &tables_[generations_]); +} + + +void CompilationSubCache::Clear() { + for (int i = 0; i < generations_; i++) { + tables_[i] = Heap::undefined_value(); } } @@ -116,10 +197,10 @@ static Handle Lookup(Handle source, // We only re-use a cached function for some script source code if the // script originates from the same place. This is to avoid issues // when reporting errors, etc. -static bool HasOrigin(Handle boilerplate, - Handle name, - int line_offset, - int column_offset) { +bool CompilationCacheScript::HasOrigin(Handle boilerplate, + Handle name, + int line_offset, + int column_offset) { Handle