v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
compilation-cache.cc
Go to the documentation of this file.
1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8#include "src/heap/factory.h"
10#include "src/logging/log.h"
13#include "src/objects/objects.h"
14#include "src/objects/slots.h"
16#include "src/utils/ostreams.h"
17
18namespace v8 {
19namespace internal {
20
21// Initial size of each compilation cache table allocated.
22static const int kInitialCacheSize = 64;
23
25 : isolate_(isolate),
26 script_(isolate),
27 eval_global_(isolate),
28 eval_contextual_(isolate),
29 reg_exp_(isolate),
30 enabled_script_and_eval_(true) {}
31
33 if (IsUndefined(table_, isolate())) {
34 return CompilationCacheTable::New(isolate(), kInitialCacheSize);
35 }
37}
38
40 int generation) {
41 DCHECK_LT(generation, kGenerations);
43 if (IsUndefined(tables_[generation], isolate())) {
44 result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
45 tables_[generation] = *result;
46 } else {
50 }
51 return result;
52}
53
55 static_assert(kGenerations > 1);
56
57 // Age the generations implicitly killing off the oldest.
58 for (int i = kGenerations - 1; i > 0; i--) {
59 tables_[i] = tables_[i - 1];
60 }
61
62 // Set the first generation as unborn.
63 tables_[0] = ReadOnlyRoots(isolate()).undefined_value();
64}
65
68 if (IsUndefined(table_, isolate())) return;
70
71 for (InternalIndex entry : table->IterateEntries()) {
73 if (!table->ToKey(isolate(), entry, &key)) continue;
74 DCHECK(IsWeakFixedArray(key));
75
76 Tagged<Object> value = table->PrimaryValueAt(entry);
77 if (!IsUndefined(value, isolate())) {
79 // Clear entries after Bytecode was flushed from SFI.
80 if (!info->HasBytecodeArray()) {
81 table->SetPrimaryValueAt(entry,
82 ReadOnlyRoots(isolate()).undefined_value(),
84 }
85 }
86 }
87}
88
91 if (IsUndefined(table_, isolate())) return;
93
94 for (InternalIndex entry : table->IterateEntries()) {
96 if (!table->ToKey(isolate(), entry, &key)) continue;
97
98 if (IsNumber(key, isolate())) {
99 // The ageing mechanism for the initial dummy entry in the eval cache.
100 // The 'key' is the hash represented as a Number. The 'value' is a smi
101 // counting down from kHashGenerations. On reaching zero, the entry is
102 // cleared.
103 // Note: The following static assert only establishes an explicit
104 // connection between initialization- and use-sites of the smi value
105 // field.
107 const int new_count = Smi::ToInt(table->PrimaryValueAt(entry)) - 1;
108 if (new_count == 0) {
109 table->RemoveEntry(entry);
110 } else {
111 DCHECK_GT(new_count, 0);
112 table->SetPrimaryValueAt(entry, Smi::FromInt(new_count),
114 }
115 } else {
116 DCHECK(IsFixedArray(key));
117 // The ageing mechanism for eval caches.
119 Cast<SharedFunctionInfo>(table->PrimaryValueAt(entry));
120 // Clear entries after Bytecode was flushed from SFI.
121 if (!info->HasBytecodeArray()) {
122 table->RemoveEntry(entry);
123 }
124 }
125 }
126}
127
129 v->VisitRootPointer(Root::kCompilationCache, nullptr,
131}
132
134 v->VisitRootPointers(Root::kCompilationCache, nullptr,
137}
138
140 table_ = ReadOnlyRoots(isolate()).undefined_value();
141}
142
144 MemsetPointer(reinterpret_cast<Address*>(tables_),
145 ReadOnlyRoots(isolate()).undefined_value().ptr(), kGenerations);
146}
147
149 DirectHandle<SharedFunctionInfo> function_info) {
150 if (IsUndefined(table_, isolate())) return;
151 Cast<CompilationCacheTable>(table_)->Remove(*function_info);
152}
153
155 Handle<String> source, const ScriptDetails& script_details) {
157 LookupResult::RawObjects raw_result_for_escaping_handle_scope;
158
159 // Probe the script table. Make sure not to leak handles
160 // into the caller's handle scope.
161 {
162 HandleScope scope(isolate());
165 table, source, script_details, isolate());
166 raw_result_for_escaping_handle_scope = probe.GetRawObjects();
167 }
168 result = LookupResult::FromRawObjects(raw_result_for_escaping_handle_scope,
169 isolate());
170
171 // Once outside the manacles of the handle scope, we need to recheck
172 // to see if we actually found a cached script. If so, we return a
173 // handle created in the caller's handle scope.
175 if (result.script().ToHandle(&script)) {
177 if (result.toplevel_sfi().ToHandle(&sfi)) {
178 isolate()->counters()->compilation_cache_hits()->Increment();
179 LOG(isolate(), CompilationCacheEvent("hit", "script", *sfi));
180 } else {
181 isolate()->counters()->compilation_cache_partial_hits()->Increment();
182 }
183 } else {
184 isolate()->counters()->compilation_cache_misses()->Increment();
185 }
186 return result;
187}
188
196
200 int position) {
201 HandleScope scope(isolate());
202 // Make sure not to leak the table into the surrounding handle
203 // scope. Otherwise, we risk keeping old tables around even after
204 // having cleared the cache.
208 table, source, outer_info, native_context, language_mode, position);
209 if (result.has_shared()) {
210 isolate()->counters()->compilation_cache_hits()->Increment();
211 } else {
212 isolate()->counters()->compilation_cache_misses()->Increment();
213 }
214 return result;
215}
216
221 DirectHandle<FeedbackCell> feedback_cell,
222 int position) {
223 HandleScope scope(isolate());
225 table_ =
226 *CompilationCacheTable::PutEval(table, source, outer_info, function_info,
227 native_context, feedback_cell, position);
228}
229
231 DirectHandle<String> source, JSRegExp::Flags flags) {
232 HandleScope scope(isolate());
233 // Make sure not to leak the table into the surrounding handle
234 // scope. Otherwise, we risk keeping old tables around even after
235 // having cleared the cache.
236 DirectHandle<Object> result = isolate()->factory()->undefined_value();
237 int generation;
238 for (generation = 0; generation < kGenerations; generation++) {
240 result = table->LookupRegExp(source, flags);
241 if (IsRegExpDataWrapper(*result)) break;
242 }
243 if (IsRegExpDataWrapper(*result)) {
245 isolate());
246 if (generation != 0) {
247 Put(source, flags, data);
248 }
249 isolate()->counters()->compilation_cache_hits()->Increment();
250 return scope.CloseAndEscape(data);
251 } else {
252 isolate()->counters()->compilation_cache_misses()->Increment();
254 }
255}
256
258 JSRegExp::Flags flags,
260 HandleScope scope(isolate());
262 tables_[0] =
263 *CompilationCacheTable::PutRegExp(isolate(), table, source, flags, data);
264}
265
267 if (!IsEnabledScriptAndEval()) return;
268
269 eval_global_.Remove(function_info);
270 eval_contextual_.Remove(function_info);
271 script_.Remove(function_info);
272}
273
275 Handle<String> source, const ScriptDetails& script_details,
276 LanguageMode language_mode) {
277 if (!IsEnabledScript(language_mode)) return {};
278 return script_.Lookup(source, script_details);
279}
280
283 DirectHandle<Context> context, LanguageMode language_mode, int position) {
285 if (!IsEnabledScriptAndEval()) return result;
286
287 const char* cache_type;
288
289 DirectHandle<NativeContext> maybe_native_context;
290 if (TryCast<NativeContext>(context, &maybe_native_context)) {
291 result = eval_global_.Lookup(source, outer_info, maybe_native_context,
292 language_mode, position);
293 cache_type = "eval-global";
294
295 } else {
297 DirectHandle<NativeContext> native_context(context->native_context(),
298 isolate());
299 result = eval_contextual_.Lookup(source, outer_info, native_context,
300 language_mode, position);
301 cache_type = "eval-contextual";
302 }
303
304 if (result.has_shared()) {
305 LOG(isolate(), CompilationCacheEvent("hit", cache_type, result.shared()));
306 }
307
308 return result;
309}
310
312 DirectHandle<String> source, JSRegExp::Flags flags) {
313 return reg_exp_.Lookup(source, flags);
314}
315
317 Handle<String> source, LanguageMode language_mode,
318 DirectHandle<SharedFunctionInfo> function_info) {
319 if (!IsEnabledScript(language_mode)) return;
320 LOG(isolate(), CompilationCacheEvent("put", "script", *function_info));
321
322 script_.Put(source, function_info);
323}
324
327 DirectHandle<Context> context,
329 DirectHandle<FeedbackCell> feedback_cell,
330 int position) {
331 if (!IsEnabledScriptAndEval()) return;
332
333 const char* cache_type;
334 HandleScope scope(isolate());
335 DirectHandle<NativeContext> maybe_native_context;
336 if (TryCast<NativeContext>(context, &maybe_native_context)) {
337 eval_global_.Put(source, outer_info, function_info, maybe_native_context,
338 feedback_cell, position);
339 cache_type = "eval-global";
340 } else {
342 DirectHandle<NativeContext> native_context(context->native_context(),
343 isolate());
344 eval_contextual_.Put(source, outer_info, function_info, native_context,
345 feedback_cell, position);
346 cache_type = "eval-contextual";
347 }
348 LOG(isolate(), CompilationCacheEvent("put", cache_type, *function_info));
349}
350
352 JSRegExp::Flags flags,
354 reg_exp_.Put(source, flags, data);
355}
356
363
370
372 // Drop SFI entries with flushed bytecode.
373 script_.Age();
376
377 // Drop entries in oldest generation.
378 reg_exp_.Age();
379}
380
384
389
390} // namespace internal
391} // namespace v8
Isolate * isolate_
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Handle< CompilationCacheTable > GetTable()
void Remove(DirectHandle< SharedFunctionInfo > function_info)
void Put(DirectHandle< String > source, DirectHandle< SharedFunctionInfo > outer_info, DirectHandle< SharedFunctionInfo > function_info, DirectHandle< NativeContext > native_context, DirectHandle< FeedbackCell > feedback_cell, int position)
InfoCellPair Lookup(DirectHandle< String > source, DirectHandle< SharedFunctionInfo > outer_info, DirectHandle< NativeContext > native_context, LanguageMode language_mode, int position)
void Put(DirectHandle< String > source, JSRegExp::Flags flags, DirectHandle< RegExpData > data)
DirectHandle< CompilationCacheTable > GetTable(int generation)
Tagged< Object > tables_[kGenerations]
MaybeDirectHandle< RegExpData > Lookup(DirectHandle< String > source, JSRegExp::Flags flags)
std::pair< Tagged< Script >, Tagged< SharedFunctionInfo > > RawObjects
static CompilationCacheScriptLookupResult FromRawObjects(RawObjects raw, Isolate *isolate)
LookupResult Lookup(Handle< String > source, const ScriptDetails &script_details)
void Put(Handle< String > source, DirectHandle< SharedFunctionInfo > function_info)
static InfoCellPair LookupEval(DirectHandle< CompilationCacheTable > table, DirectHandle< String > src, DirectHandle< SharedFunctionInfo > shared, DirectHandle< NativeContext > native_context, LanguageMode language_mode, int position)
static NEVER_READ_ONLY_SPACE CompilationCacheScriptLookupResult LookupScript(DirectHandle< CompilationCacheTable > table, Handle< String > src, const ScriptDetails &script_details, Isolate *isolate)
static DirectHandle< CompilationCacheTable > PutRegExp(Isolate *isolate, DirectHandle< CompilationCacheTable > cache, DirectHandle< String > src, JSRegExp::Flags flags, DirectHandle< RegExpData > value)
static DirectHandle< CompilationCacheTable > PutEval(DirectHandle< CompilationCacheTable > cache, DirectHandle< String > src, DirectHandle< SharedFunctionInfo > outer_info, DirectHandle< SharedFunctionInfo > value, DirectHandle< NativeContext > native_context, DirectHandle< FeedbackCell > feedback_cell, int position)
static DirectHandle< CompilationCacheTable > PutScript(Handle< CompilationCacheTable > cache, Handle< String > src, MaybeHandle< FixedArray > maybe_wrapped_arguments, DirectHandle< SharedFunctionInfo > value, Isolate *isolate)
bool IsEnabledScript(LanguageMode language_mode)
CompilationCacheRegExp reg_exp_
void PutRegExp(DirectHandle< String > source, JSRegExp::Flags flags, DirectHandle< RegExpData > data)
CompilationCacheScript::LookupResult LookupScript(Handle< String > source, const ScriptDetails &script_details, LanguageMode language_mode)
CompilationCacheEval eval_contextual_
void PutScript(Handle< String > source, LanguageMode language_mode, DirectHandle< SharedFunctionInfo > function_info)
MaybeDirectHandle< RegExpData > LookupRegExp(DirectHandle< String > source, JSRegExp::Flags flags)
CompilationCache(const CompilationCache &)=delete
InfoCellPair LookupEval(DirectHandle< String > source, DirectHandle< SharedFunctionInfo > outer_info, DirectHandle< Context > context, LanguageMode language_mode, int position)
void Remove(DirectHandle< SharedFunctionInfo > function_info)
void PutEval(DirectHandle< String > source, DirectHandle< SharedFunctionInfo > outer_info, DirectHandle< Context > context, DirectHandle< SharedFunctionInfo > function_info, DirectHandle< FeedbackCell > feedback_cell, int position)
HandleType< T > CloseAndEscape(HandleType< T > handle_value)
Counters * counters()
Definition isolate.h:1180
v8::internal::Factory * factory()
Definition isolate.h:1527
virtual void VisitRootPointers(Root root, const char *description, FullObjectSlot start, FullObjectSlot end)=0
virtual void VisitRootPointer(Root root, const char *description, FullObjectSlot p)
Definition visitors.h:75
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
Handle< Script > script_
ZoneVector< RpoNumber > & result
int position
Definition liveedit.cc:290
#define LOG(isolate, Call)
Definition log.h:78
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
bool TryCast(Tagged< From > value, Tagged< To > *out)
Definition casting.h:77
constexpr NullMaybeHandleType kNullMaybeHandle
@ SKIP_WRITE_BARRIER
Definition objects.h:52
constexpr int kNoSourcePosition
Definition globals.h:850
bool IsNumber(Tagged< Object > obj)
static const int kInitialCacheSize
void MemsetPointer(FullObjectSlot start, Tagged< Object > value, size_t counter)
Definition slots-inl.h:507
kInterpreterTrampolineOffset script
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_GT(v1, v2)
Definition logging.h:487