5 #include "src/compilation-cache.h" 7 #include "src/counters.h" 8 #include "src/globals.h" 9 #include "src/heap/factory.h" 10 #include "src/objects-inl.h" 11 #include "src/objects/compilation-cache-inl.h" 12 #include "src/objects/slots.h" 13 #include "src/visitors.h" 19 static const int kRegExpGenerations = 2;
22 static const int kInitialCacheSize = 64;
24 CompilationCache::CompilationCache(Isolate* isolate)
27 eval_global_(isolate),
28 eval_contextual_(isolate),
29 reg_exp_(isolate, kRegExpGenerations),
31 CompilationSubCache* subcaches[kSubCacheCount] =
32 {&script_, &eval_global_, &eval_contextual_, ®_exp_};
33 for (
int i = 0;
i < kSubCacheCount; ++
i) {
34 subcaches_[
i] = subcaches[
i];
38 Handle<CompilationCacheTable> CompilationSubCache::GetTable(
int generation) {
39 DCHECK(generation < generations_);
40 Handle<CompilationCacheTable> result;
41 if (tables_[generation]->IsUndefined(isolate())) {
42 result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
43 tables_[generation] = *result;
45 CompilationCacheTable table =
46 CompilationCacheTable::cast(tables_[generation]);
47 result = Handle<CompilationCacheTable>(table, isolate());
52 void CompilationSubCache::Age() {
54 if (generations_ == 1) {
55 if (!tables_[0]->IsUndefined(isolate())) {
56 CompilationCacheTable::cast(tables_[0])->Age();
62 for (
int i = generations_ - 1;
i > 0;
i--) {
63 tables_[
i] = tables_[
i - 1];
67 tables_[0] = ReadOnlyRoots(isolate()).undefined_value();
70 void CompilationSubCache::Iterate(RootVisitor* v) {
71 v->VisitRootPointers(Root::kCompilationCache,
nullptr,
72 ObjectSlot(&tables_[0]),
73 ObjectSlot(&tables_[generations_]));
76 void CompilationSubCache::Clear() {
77 MemsetPointer(tables_, ReadOnlyRoots(isolate()).undefined_value(),
81 void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
84 { HandleScope scope(isolate());
85 for (
int generation = 0; generation < generations(); generation++) {
86 Handle<CompilationCacheTable> table = GetTable(generation);
87 table->Remove(*function_info);
92 CompilationCacheScript::CompilationCacheScript(Isolate* isolate)
93 : CompilationSubCache(isolate, 1) {}
98 bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info,
99 MaybeHandle<Object> maybe_name,
100 int line_offset,
int column_offset,
101 ScriptOriginOptions resource_options) {
102 Handle<Script> script =
103 Handle<Script>(Script::cast(function_info->script()), isolate());
107 if (!maybe_name.ToHandle(&name)) {
108 return script->name()->IsUndefined(isolate());
111 if (line_offset != script->line_offset())
return false;
112 if (column_offset != script->column_offset())
return false;
114 if (!name->IsString() || !script->name()->IsString())
return false;
116 if (resource_options.Flags() != script->origin_options().Flags())
119 return String::Equals(
120 isolate(), Handle<String>::cast(name),
121 Handle<String>(String::cast(script->name()), isolate()));
128 MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup(
129 Handle<String> source, MaybeHandle<Object> name,
int line_offset,
130 int column_offset, ScriptOriginOptions resource_options,
131 Handle<Context> native_context, LanguageMode language_mode) {
132 MaybeHandle<SharedFunctionInfo> result;
136 { HandleScope scope(isolate());
137 const int generation = 0;
138 DCHECK_EQ(generations(), 1);
139 Handle<CompilationCacheTable> table = GetTable(generation);
140 MaybeHandle<SharedFunctionInfo> probe = CompilationCacheTable::LookupScript(
141 table, source, native_context, language_mode);
142 Handle<SharedFunctionInfo> function_info;
143 if (probe.ToHandle(&function_info)) {
146 if (HasOrigin(function_info, name, line_offset, column_offset,
148 result = scope.CloseAndEscape(function_info);
156 Handle<SharedFunctionInfo> function_info;
157 if (result.ToHandle(&function_info)) {
161 DCHECK(HasOrigin(function_info, name, line_offset, column_offset,
164 isolate()->counters()->compilation_cache_hits()->Increment();
165 LOG(isolate(), CompilationCacheEvent(
"hit",
"script", *function_info));
167 isolate()->counters()->compilation_cache_misses()->Increment();
172 void CompilationCacheScript::Put(Handle<String> source,
173 Handle<Context> native_context,
174 LanguageMode language_mode,
175 Handle<SharedFunctionInfo> function_info) {
176 HandleScope scope(isolate());
177 Handle<CompilationCacheTable> table = GetFirstTable();
178 SetFirstTable(CompilationCacheTable::PutScript(table, source, native_context,
179 language_mode, function_info));
182 InfoCellPair CompilationCacheEval::Lookup(Handle<String> source,
183 Handle<SharedFunctionInfo> outer_info,
184 Handle<Context> native_context,
185 LanguageMode language_mode,
187 HandleScope scope(isolate());
192 const int generation = 0;
193 DCHECK_EQ(generations(), 1);
194 Handle<CompilationCacheTable> table = GetTable(generation);
195 result = CompilationCacheTable::LookupEval(
196 table, source, outer_info, native_context, language_mode, position);
197 if (result.has_shared()) {
198 isolate()->counters()->compilation_cache_hits()->Increment();
200 isolate()->counters()->compilation_cache_misses()->Increment();
205 void CompilationCacheEval::Put(Handle<String> source,
206 Handle<SharedFunctionInfo> outer_info,
207 Handle<SharedFunctionInfo> function_info,
208 Handle<Context> native_context,
209 Handle<FeedbackCell> feedback_cell,
211 HandleScope scope(isolate());
212 Handle<CompilationCacheTable> table = GetFirstTable();
214 CompilationCacheTable::PutEval(table, source, outer_info, function_info,
215 native_context, feedback_cell, position);
216 SetFirstTable(table);
219 MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
220 Handle<String> source,
221 JSRegExp::Flags flags) {
222 HandleScope scope(isolate());
226 Handle<Object> result = isolate()->factory()->undefined_value();
228 for (generation = 0; generation < generations(); generation++) {
229 Handle<CompilationCacheTable> table = GetTable(generation);
230 result = table->LookupRegExp(source, flags);
231 if (result->IsFixedArray())
break;
233 if (result->IsFixedArray()) {
234 Handle<FixedArray> data = Handle<FixedArray>::cast(result);
235 if (generation != 0) {
236 Put(source, flags, data);
238 isolate()->counters()->compilation_cache_hits()->Increment();
239 return scope.CloseAndEscape(data);
241 isolate()->counters()->compilation_cache_misses()->Increment();
242 return MaybeHandle<FixedArray>();
246 void CompilationCacheRegExp::Put(Handle<String> source,
247 JSRegExp::Flags flags,
248 Handle<FixedArray> data) {
249 HandleScope scope(isolate());
250 Handle<CompilationCacheTable> table = GetFirstTable();
252 CompilationCacheTable::PutRegExp(isolate(), table, source, flags, data));
255 void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
256 if (!IsEnabled())
return;
258 eval_global_.Remove(function_info);
259 eval_contextual_.Remove(function_info);
260 script_.Remove(function_info);
263 MaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript(
264 Handle<String> source, MaybeHandle<Object> name,
int line_offset,
265 int column_offset, ScriptOriginOptions resource_options,
266 Handle<Context> native_context, LanguageMode language_mode) {
267 if (!IsEnabled())
return MaybeHandle<SharedFunctionInfo>();
269 return script_.Lookup(source, name, line_offset, column_offset,
270 resource_options, native_context, language_mode);
273 InfoCellPair CompilationCache::LookupEval(Handle<String> source,
274 Handle<SharedFunctionInfo> outer_info,
275 Handle<Context> context,
276 LanguageMode language_mode,
279 if (!IsEnabled())
return result;
281 const char* cache_type;
283 if (context->IsNativeContext()) {
284 result = eval_global_.Lookup(source, outer_info, context, language_mode,
286 cache_type =
"eval-global";
289 DCHECK_NE(position, kNoSourcePosition);
290 Handle<Context> native_context(context->native_context(), isolate());
291 result = eval_contextual_.Lookup(source, outer_info, native_context,
292 language_mode, position);
293 cache_type =
"eval-contextual";
296 if (result.has_shared()) {
297 LOG(isolate(), CompilationCacheEvent(
"hit", cache_type, result.shared()));
303 MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
304 JSRegExp::Flags flags) {
305 if (!IsEnabled())
return MaybeHandle<FixedArray>();
307 return reg_exp_.Lookup(source, flags);
310 void CompilationCache::PutScript(Handle<String> source,
311 Handle<Context> native_context,
312 LanguageMode language_mode,
313 Handle<SharedFunctionInfo> function_info) {
314 if (!IsEnabled())
return;
315 LOG(isolate(), CompilationCacheEvent(
"put",
"script", *function_info));
317 script_.Put(source, native_context, language_mode, function_info);
320 void CompilationCache::PutEval(Handle<String> source,
321 Handle<SharedFunctionInfo> outer_info,
322 Handle<Context> context,
323 Handle<SharedFunctionInfo> function_info,
324 Handle<FeedbackCell> feedback_cell,
326 if (!IsEnabled())
return;
328 const char* cache_type;
329 HandleScope scope(isolate());
330 if (context->IsNativeContext()) {
331 eval_global_.Put(source, outer_info, function_info, context, feedback_cell,
333 cache_type =
"eval-global";
335 DCHECK_NE(position, kNoSourcePosition);
336 Handle<Context> native_context(context->native_context(), isolate());
337 eval_contextual_.Put(source, outer_info, function_info, native_context,
338 feedback_cell, position);
339 cache_type =
"eval-contextual";
341 LOG(isolate(), CompilationCacheEvent(
"put", cache_type, *function_info));
344 void CompilationCache::PutRegExp(Handle<String> source,
345 JSRegExp::Flags flags,
346 Handle<FixedArray> data) {
347 if (!IsEnabled())
return;
349 reg_exp_.Put(source, flags, data);
352 void CompilationCache::Clear() {
353 for (
int i = 0;
i < kSubCacheCount;
i++) {
354 subcaches_[
i]->Clear();
358 void CompilationCache::Iterate(RootVisitor* v) {
359 for (
int i = 0;
i < kSubCacheCount;
i++) {
360 subcaches_[
i]->Iterate(v);
364 void CompilationCache::MarkCompactPrologue() {
365 for (
int i = 0;
i < kSubCacheCount;
i++) {
366 subcaches_[
i]->Age();
370 void CompilationCache::Enable() {
374 void CompilationCache::Disable() {