/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/codegen/compilation-cache.cc
365 строк
13 KB
Michaël Zasso
deps: update V8 to 14.2.231.9
23 окт 2025, 08:36
Не верифицирован
23 окт 2025, 08:36
c2843b7
Код
Авторство
О чём код?
// Copyright 2011 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/codegen/compilation-cache.h" #include "src/common/globals.h" #include "src/heap/factory.h" #include "src/logging/counters.h" #include "src/logging/log.h" #include "src/objects/compilation-cache-table-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" #include "src/objects/slots.h" #include "src/objects/visitors.h" #include "src/utils/ostreams.h" namespace v8 { namespace internal { // Initial size of each compilation cache table allocated. static const int kInitialCacheSize = 64; CompilationCache::CompilationCache(Isolate* isolate) : isolate_(isolate), script_(isolate), eval_global_(isolate), eval_contextual_(isolate), reg_exp_(isolate), enabled_script_and_eval_(true) {} Handle<CompilationCacheTable> CompilationCacheEvalOrScript::GetTable() { if (IsUndefined(table_, isolate())) { return CompilationCacheTable::New(isolate(), kInitialCacheSize); } return handle(Cast<CompilationCacheTable>(table_), isolate()); } DirectHandle<CompilationCacheTable> CompilationCacheRegExp::GetTable( int generation) { DCHECK_LT(generation, kGenerations); DirectHandle<CompilationCacheTable> result; if (IsUndefined(tables_[generation], isolate())) { result = CompilationCacheTable::New(isolate(), kInitialCacheSize); tables_[generation] = *result; } else { Tagged<CompilationCacheTable> table = Cast<CompilationCacheTable>(tables_[generation]); result = DirectHandle<CompilationCacheTable>(table, isolate()); } return result; } void CompilationCacheRegExp::Age() { static_assert(kGenerations > 1); // Age the generations implicitly killing off the oldest. for (int i = kGenerations - 1; i > 0; i--) { tables_[i] = tables_[i - 1]; } // Set the first generation as unborn. tables_[0] = ReadOnlyRoots(isolate()).undefined_value(); } void CompilationCacheScript::Age() { DisallowGarbageCollection no_gc; if (IsUndefined(table_, isolate())) return; Tagged<CompilationCacheTable> table = Cast<CompilationCacheTable>(table_); for (InternalIndex entry : table->IterateEntries()) { Tagged<Object> key; if (!table->ToKey(isolate(), entry, &key)) continue; DCHECK(IsWeakFixedArray(key)); Tagged<Object> value = table->PrimaryValueAt(entry); if (!IsUndefined(value, isolate())) { Tagged<SharedFunctionInfo> info = Cast<SharedFunctionInfo>(value); // Clear entries after Bytecode was flushed from SFI. if (!info->HasBytecodeArray()) { table->SetPrimaryValueAt(entry, ReadOnlyRoots(isolate()).undefined_value(), SKIP_WRITE_BARRIER); } } } } void CompilationCacheEval::Age() { DisallowGarbageCollection no_gc; if (IsUndefined(table_, isolate())) return; Tagged<CompilationCacheTable> table = Cast<CompilationCacheTable>(table_); for (InternalIndex entry : table->IterateEntries()) { Tagged<Object> key; if (!table->ToKey(isolate(), entry, &key)) continue; DCHECK(IsFixedArray(key)); // The ageing mechanism for eval caches. Tagged<SharedFunctionInfo> info = Cast<SharedFunctionInfo>(table->PrimaryValueAt(entry)); // Clear entries after Bytecode was flushed from SFI. if (!info->HasBytecodeArray()) { table->RemoveEntry(entry); } } } void CompilationCacheEvalOrScript::Iterate(RootVisitor* v) { v->VisitRootPointer(Root::kCompilationCache, nullptr, FullObjectSlot(&table_)); } void CompilationCacheRegExp::Iterate(RootVisitor* v) { v->VisitRootPointers(Root::kCompilationCache, nullptr, FullObjectSlot(&tables_[0]), FullObjectSlot(&tables_[kGenerations])); } void CompilationCacheEvalOrScript::Clear() { table_ = ReadOnlyRoots(isolate()).undefined_value(); } void CompilationCacheRegExp::Clear() { MemsetPointer(FullObjectSlot(tables_), ReadOnlyRoots(isolate()).undefined_value(), kGenerations); } void CompilationCacheEvalOrScript::Remove( DirectHandle<SharedFunctionInfo> function_info) { if (IsUndefined(table_, isolate())) return; Cast<CompilationCacheTable>(table_)->Remove(*function_info); } CompilationCacheScript::LookupResult CompilationCacheScript::Lookup( Handle<String> source, const ScriptDetails& script_details) { DirectHandle<CompilationCacheTable> table = GetTable(); LookupResult result = CompilationCacheTable::LookupScript( table, source, script_details, isolate()); DirectHandle<Script> script; if (result.script().ToHandle(&script)) { DirectHandle<SharedFunctionInfo> sfi; if (result.toplevel_sfi().ToHandle(&sfi)) { isolate()->counters()->compilation_cache_hits()->Increment(); LOG(isolate(), CompilationCacheEvent("hit", "script", *sfi)); } else { isolate()->counters()->compilation_cache_partial_hits()->Increment(); } } else { isolate()->counters()->compilation_cache_misses()->Increment(); } return result; } void CompilationCacheScript::Put( Handle<String> source, DirectHandle<SharedFunctionInfo> function_info) { Handle<CompilationCacheTable> table = GetTable(); table_ = *CompilationCacheTable::PutScript(table, source, kNullMaybeHandle, function_info, isolate()); } void CompilationCacheEval::UpdateEval( DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<JSFunction> js_function, LanguageMode language_mode, int position) { DirectHandle<CompilationCacheTable> table = GetTable(); CompilationCacheTable::UpdateEval(table, source, outer_info, js_function, language_mode, position); } InfoCellPair CompilationCacheEval::Lookup( DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<NativeContext> native_context, LanguageMode language_mode, int position) { InfoCellPair result; DirectHandle<CompilationCacheTable> table = GetTable(); result = CompilationCacheTable::LookupEval( table, source, outer_info, native_context, language_mode, position); if (result.has_shared()) { isolate()->counters()->compilation_cache_hits()->Increment(); } else { isolate()->counters()->compilation_cache_misses()->Increment(); } return result; } void CompilationCacheEval::Put(DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<JSFunction> js_function, int position) { DirectHandle<CompilationCacheTable> table = GetTable(); table_ = *CompilationCacheTable::PutEval(table, source, outer_info, js_function, position); } MaybeDirectHandle<RegExpData> CompilationCacheRegExp::Lookup( DirectHandle<String> source, JSRegExp::Flags flags) { HandleScope scope(isolate()); // 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. DirectHandle<Object> result = isolate()->factory()->undefined_value(); int generation; for (generation = 0; generation < kGenerations; generation++) { DirectHandle<CompilationCacheTable> table = GetTable(generation); result = table->LookupRegExp(source, flags); if (IsRegExpDataWrapper(*result)) break; } if (IsRegExpDataWrapper(*result)) { Handle<RegExpData> data(Cast<RegExpDataWrapper>(result)->data(isolate()), isolate()); if (generation != 0) { Put(source, flags, data); } isolate()->counters()->compilation_cache_hits()->Increment(); return scope.CloseAndEscape(data); } else { isolate()->counters()->compilation_cache_misses()->Increment(); return MaybeDirectHandle<RegExpData>(); } } void CompilationCacheRegExp::Put(DirectHandle<String> source, JSRegExp::Flags flags, DirectHandle<RegExpData> data) { HandleScope scope(isolate()); DirectHandle<CompilationCacheTable> table = GetTable(0); tables_[0] = *CompilationCacheTable::PutRegExp(isolate(), table, source, flags, data); } void CompilationCache::Remove(DirectHandle<SharedFunctionInfo> function_info) { if (!IsEnabledScriptAndEval()) return; eval_global_.Remove(function_info); eval_contextual_.Remove(function_info); script_.Remove(function_info); } CompilationCacheScript::LookupResult CompilationCache::LookupScript( Handle<String> source, const ScriptDetails& script_details, LanguageMode language_mode) { if (!IsEnabledScript(language_mode)) return {}; return script_.Lookup(source, script_details); } void CompilationCache::UpdateEval(DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<JSFunction> js_function, LanguageMode language_mode, int position) { if (IsNativeContext(js_function->context())) { eval_global_.UpdateEval(source, outer_info, js_function, language_mode, position); } else { DCHECK_NE(position, kNoSourcePosition); eval_contextual_.UpdateEval(source, outer_info, js_function, language_mode, position); } } InfoCellPair CompilationCache::LookupEval( DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<Context> context, LanguageMode language_mode, int position) { InfoCellPair result; if (!IsEnabledScriptAndEval()) return result; const char* cache_type; DirectHandle<NativeContext> maybe_native_context; if (TryCast<NativeContext>(context, &maybe_native_context)) { result = eval_global_.Lookup(source, outer_info, maybe_native_context, language_mode, position); cache_type = "eval-global"; } else { DCHECK_NE(position, kNoSourcePosition); DirectHandle<NativeContext> native_context(context->native_context(), isolate()); result = eval_contextual_.Lookup(source, outer_info, native_context, language_mode, position); cache_type = "eval-contextual"; } if (result.has_shared()) { LOG(isolate(), CompilationCacheEvent("hit", cache_type, result.shared())); } return result; } MaybeDirectHandle<RegExpData> CompilationCache::LookupRegExp( DirectHandle<String> source, JSRegExp::Flags flags) { return reg_exp_.Lookup(source, flags); } void CompilationCache::PutScript( Handle<String> source, LanguageMode language_mode, DirectHandle<SharedFunctionInfo> function_info) { if (!IsEnabledScript(language_mode)) return; LOG(isolate(), CompilationCacheEvent("put", "script", *function_info)); script_.Put(source, function_info); } void CompilationCache::PutEval(DirectHandle<String> source, DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<JSFunction> js_function, int position) { if (!IsEnabledScriptAndEval()) return; const char* cache_type; if (IsNativeContext(js_function->context())) { eval_global_.Put(source, outer_info, js_function, position); cache_type = "eval-global"; } else { DCHECK_NE(position, kNoSourcePosition); eval_contextual_.Put(source, outer_info, js_function, position); cache_type = "eval-contextual"; } LOG(isolate(), CompilationCacheEvent("put", cache_type, js_function->shared())); } void CompilationCache::PutRegExp(DirectHandle<String> source, JSRegExp::Flags flags, DirectHandle<RegExpData> data) { reg_exp_.Put(source, flags, data); } void CompilationCache::Clear() { script_.Clear(); eval_global_.Clear(); eval_contextual_.Clear(); reg_exp_.Clear(); } void CompilationCache::Iterate(RootVisitor* v) { script_.Iterate(v); eval_global_.Iterate(v); eval_contextual_.Iterate(v); reg_exp_.Iterate(v); } void CompilationCache::MarkCompactPrologue() { // Drop SFI entries with flushed bytecode. script_.Age(); eval_global_.Age(); eval_contextual_.Age(); // Drop entries in oldest generation. reg_exp_.Age(); } void CompilationCache::EnableScriptAndEval() { enabled_script_and_eval_ = true; } void CompilationCache::DisableScriptAndEval() { enabled_script_and_eval_ = false; Clear(); } } // namespace internal } // namespace v8