Commit 9e240773 authored by Seth Brenith's avatar Seth Brenith Committed by V8 LUCI CQ

Reland "Refactor CompilationSubCache"

This is a reland of commit c8848cf4

This change was reverted due to a problem in a preceding change. This
relanded version differs in its implementations of the
CompilationCacheScript member functions Lookup, Put, and Age, because
the intent is to not change any behavior.

Original change's description:
> CompilationSubCache has some complexity regarding generations of tables
> which is only used by one subclass, CompilationCacheRegExp. This change
> adjusts the class hierarchy so that classes only contain the necessary
> member functions.
>
> Bug: v8:12808
> Change-Id: I4f4cf15bbf9b80c2de0c18aea82a0c238804759d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3629603
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
> Cr-Commit-Position: refs/heads/main@{#80506}

Bug: v8:12808
Change-Id: Ib0621b7de8da86a89752c66907f6a56adff9075d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3665936Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#80825}
parent d1f2ccf1
This diff is collapsed.
......@@ -18,69 +18,41 @@ class Handle;
class RootVisitor;
struct ScriptDetails;
// 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. Since the same source code string has
// different compiled code for scripts and evals, we use separate sub-caches
// for different compilation modes, to avoid retrieving the wrong result.
class CompilationSubCache {
// The compilation cache consists of several sub-caches: one each for evals and
// scripts, which use this class as a base class, and a separate generational
// sub-cache for RegExps. Since the same source code string has different
// compiled code for scripts and evals, we use separate sub-caches for different
// compilation modes, to avoid retrieving the wrong result.
class CompilationCacheEvalOrScript {
public:
CompilationSubCache(Isolate* isolate, int generations)
: isolate_(isolate), generations_(generations) {
DCHECK_LE(generations, kMaxGenerations);
}
static constexpr int kFirstGeneration = 0;
static constexpr int kMaxGenerations = 2;
explicit CompilationCacheEvalOrScript(Isolate* isolate) : isolate_(isolate) {}
// Get the compilation cache tables for a specific generation.
Handle<CompilationCacheTable> GetTable(int generation);
// Accessors for first generation.
Handle<CompilationCacheTable> GetFirstTable() {
return GetTable(kFirstGeneration);
}
void SetFirstTable(Handle<CompilationCacheTable> value) {
DCHECK_LT(kFirstGeneration, generations_);
tables_[kFirstGeneration] = *value;
}
// Age the sub-cache by evicting the oldest generation and creating a new
// young generation.
virtual void Age() = 0;
// Allocates the table if it didn't yet exist.
Handle<CompilationCacheTable> GetTable();
// GC support.
void Iterate(RootVisitor* v);
// Clear this sub-cache evicting all its content.
// Clears this sub-cache evicting all its content.
void Clear();
// Remove given shared function info from sub-cache.
// Removes given shared function info from sub-cache.
void Remove(Handle<SharedFunctionInfo> function_info);
// Number of generations in this sub-cache.
int generations() const { return generations_; }
protected:
Isolate* isolate() const { return isolate_; }
// Ageing occurs either by removing the oldest generation, or with
// custom logic implemented in CompilationCacheTable::Age.
static void AgeByGeneration(CompilationSubCache* c);
static void AgeCustom(CompilationSubCache* c);
private:
Isolate* const isolate_;
const int generations_;
Object tables_[kMaxGenerations]; // One for each generation.
Object table_;
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache);
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEvalOrScript);
};
// Sub-cache for scripts.
class CompilationCacheScript : public CompilationSubCache {
class CompilationCacheScript : public CompilationCacheEvalOrScript {
public:
explicit CompilationCacheScript(Isolate* isolate);
explicit CompilationCacheScript(Isolate* isolate)
: CompilationCacheEvalOrScript(isolate) {}
MaybeHandle<SharedFunctionInfo> Lookup(Handle<String> source,
const ScriptDetails& script_details,
......@@ -89,7 +61,7 @@ class CompilationCacheScript : public CompilationSubCache {
void Put(Handle<String> source, LanguageMode language_mode,
Handle<SharedFunctionInfo> function_info);
void Age() override;
void Age();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript);
......@@ -107,10 +79,10 @@ class CompilationCacheScript : public CompilationSubCache {
// More specifically these are the CompileString, DebugEvaluate and
// DebugEvaluateGlobal runtime functions.
// 4. The start position of the calling scope.
class CompilationCacheEval : public CompilationSubCache {
class CompilationCacheEval : public CompilationCacheEvalOrScript {
public:
explicit CompilationCacheEval(Isolate* isolate)
: CompilationSubCache(isolate, 1) {}
: CompilationCacheEvalOrScript(isolate) {}
InfoCellPair Lookup(Handle<String> source,
Handle<SharedFunctionInfo> outer_info,
......@@ -122,26 +94,45 @@ class CompilationCacheEval : public CompilationSubCache {
Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
int position);
void Age() override;
void Age();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
};
// Sub-cache for regular expressions.
class CompilationCacheRegExp : public CompilationSubCache {
class CompilationCacheRegExp {
public:
CompilationCacheRegExp(Isolate* isolate, int generations)
: CompilationSubCache(isolate, generations) {}
CompilationCacheRegExp(Isolate* isolate) : isolate_(isolate) {}
MaybeHandle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags);
void Put(Handle<String> source, JSRegExp::Flags flags,
Handle<FixedArray> data);
void Age() override;
// The number of generations for the RegExp sub cache.
static const int kGenerations = 2;
// Gets the compilation cache tables for a specific generation. Allocates the
// table if it does not yet exist.
Handle<CompilationCacheTable> GetTable(int generation);
// Ages the sub-cache by evicting the oldest generation and creating a new
// young generation.
void Age();
// GC support.
void Iterate(RootVisitor* v);
// Clears this sub-cache evicting all its content.
void Clear();
private:
Isolate* isolate() const { return isolate_; }
Isolate* const isolate_;
Object tables_[kGenerations]; // One for each generation.
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp);
};
......@@ -234,9 +225,6 @@ class V8_EXPORT_PRIVATE CompilationCache {
CompilationCacheEval eval_contextual_;
CompilationCacheRegExp reg_exp_;
static constexpr int kSubCacheCount = 4;
CompilationSubCache* subcaches_[kSubCacheCount];
// Current enable state of the compilation cache for scripts and eval.
bool enabled_script_and_eval_;
......
......@@ -17,9 +17,6 @@ const int kLiteralInitialLength = 2;
const int kLiteralContextOffset = 0;
const int kLiteralLiteralsOffset = 1;
// The initial placeholder insertion of the eval cache survives this many GCs.
const int kHashGenerations = 10;
int SearchLiteralsMapEntry(CompilationCacheTable cache,
InternalIndex cache_entry, Context native_context) {
DisallowGarbageCollection no_gc;
......@@ -360,36 +357,6 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
return cache;
}
void CompilationCacheTable::Age(Isolate* isolate) {
DisallowGarbageCollection no_gc;
for (InternalIndex entry : IterateEntries()) {
Object key = KeyAt(entry);
if (key.IsNumber()) {
// The ageing mechanism for the initial dummy entry in the eval cache.
// The 'key' is the hash represented as a Number. The 'value' is a smi
// counting down from kHashGenerations. On reaching zero, the entry is
// cleared.
// Note: The following static assert only establishes an explicit
// connection between initialization- and use-sites of the smi value
// field.
static_assert(kHashGenerations);
const int new_count = Smi::ToInt(PrimaryValueAt(entry)) - 1;
if (new_count == 0) {
RemoveEntry(entry);
} else {
DCHECK_GT(new_count, 0);
SetPrimaryValueAt(entry, Smi::FromInt(new_count), SKIP_WRITE_BARRIER);
}
} else if (key.IsFixedArray()) {
// The ageing mechanism for script and eval caches.
SharedFunctionInfo info = SharedFunctionInfo::cast(PrimaryValueAt(entry));
if (info.HasBytecodeArray() && info.GetBytecodeArray(isolate).IsOld()) {
RemoveEntry(entry);
}
}
}
}
void CompilationCacheTable::Remove(Object value) {
DisallowGarbageCollection no_gc;
for (InternalIndex entry : IterateEntries()) {
......
......@@ -124,7 +124,7 @@ class CompilationCacheTable
JSRegExp::Flags flags, Handle<FixedArray> value);
void Remove(Object value);
void Age(Isolate* isolate);
void RemoveEntry(InternalIndex entry);
inline Object PrimaryValueAt(InternalIndex entry);
inline void SetPrimaryValueAt(InternalIndex entry, Object value,
......@@ -134,11 +134,12 @@ class CompilationCacheTable
InternalIndex entry, Object value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// The initial placeholder insertion of the eval cache survives this many GCs.
static constexpr int kHashGenerations = 10;
DECL_CAST(CompilationCacheTable)
private:
void RemoveEntry(InternalIndex entry);
OBJECT_CONSTRUCTORS(CompilationCacheTable,
HashTable<CompilationCacheTable, CompilationCacheShape>);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment