LCOV - code coverage report
Current view: top level - src - compilation-cache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 131 137 95.6 %
Date: 2019-04-19 Functions: 24 27 88.9 %

          Line data    Source code
       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             : 
       5             : #include "src/compilation-cache.h"
       6             : 
       7             : #include "src/counters.h"
       8             : #include "src/globals.h"
       9             : #include "src/heap/factory.h"
      10             : #include "src/log.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/compilation-cache-inl.h"
      13             : #include "src/objects/slots.h"
      14             : #include "src/visitors.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : // The number of generations for each sub cache.
      20             : static const int kRegExpGenerations = 2;
      21             : 
      22             : // Initial size of each compilation cache table allocated.
      23             : static const int kInitialCacheSize = 64;
      24             : 
      25       62442 : CompilationCache::CompilationCache(Isolate* isolate)
      26             :     : isolate_(isolate),
      27             :       script_(isolate),
      28             :       eval_global_(isolate),
      29             :       eval_contextual_(isolate),
      30             :       reg_exp_(isolate, kRegExpGenerations),
      31      124884 :       enabled_(true) {
      32             :   CompilationSubCache* subcaches[kSubCacheCount] =
      33       62442 :     {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
      34      561978 :   for (int i = 0; i < kSubCacheCount; ++i) {
      35      249768 :     subcaches_[i] = subcaches[i];
      36             :   }
      37       62442 : }
      38             : 
      39     6134987 : Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
      40             :   DCHECK(generation < generations_);
      41             :   Handle<CompilationCacheTable> result;
      42    12269974 :   if (tables_[generation]->IsUndefined(isolate())) {
      43       62643 :     result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
      44      125286 :     tables_[generation] = *result;
      45             :   } else {
      46             :     CompilationCacheTable table =
      47             :         CompilationCacheTable::cast(tables_[generation]);
      48             :     result = Handle<CompilationCacheTable>(table, isolate());
      49             :   }
      50     6134987 :   return result;
      51             : }
      52             : 
      53      384676 : void CompilationSubCache::Age() {
      54             :   // Don't directly age single-generation caches.
      55      384676 :   if (generations_ == 1) {
      56      577014 :     if (!tables_[0]->IsUndefined(isolate())) {
      57       62272 :       CompilationCacheTable::cast(tables_[0])->Age();
      58             :     }
      59             :     return;
      60             :   }
      61             : 
      62             :   // Age the generations implicitly killing off the oldest.
      63      192338 :   for (int i = generations_ - 1; i > 0; i--) {
      64       96169 :     tables_[i] = tables_[i - 1];
      65             :   }
      66             : 
      67             :   // Set the first generation as unborn.
      68      192338 :   tables_[0] = ReadOnlyRoots(isolate()).undefined_value();
      69             : }
      70             : 
      71           0 : void CompilationSubCache::Iterate(RootVisitor* v) {
      72     2204312 :   v->VisitRootPointers(Root::kCompilationCache, nullptr,
      73             :                        FullObjectSlot(&tables_[0]),
      74     2204312 :                        FullObjectSlot(&tables_[generations_]));
      75           0 : }
      76             : 
      77           0 : void CompilationSubCache::Clear() {
      78       44224 :   MemsetPointer(reinterpret_cast<Address*>(tables_),
      79             :                 ReadOnlyRoots(isolate()).undefined_value()->ptr(),
      80       22112 :                 generations_);
      81           0 : }
      82             : 
      83         804 : void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
      84             :   // Probe the script generation tables. Make sure not to leak handles
      85             :   // into the caller's handle scope.
      86             :   { HandleScope scope(isolate());
      87        2412 :     for (int generation = 0; generation < generations(); generation++) {
      88         804 :       Handle<CompilationCacheTable> table = GetTable(generation);
      89        1608 :       table->Remove(*function_info);
      90             :     }
      91             :   }
      92         804 : }
      93             : 
      94           0 : CompilationCacheScript::CompilationCacheScript(Isolate* isolate)
      95           0 :     : CompilationSubCache(isolate, 1) {}
      96             : 
      97             : // We only re-use a cached function for some script source code if the
      98             : // script originates from the same place. This is to avoid issues
      99             : // when reporting errors, etc.
     100      131505 : bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info,
     101             :                                        MaybeHandle<Object> maybe_name,
     102             :                                        int line_offset, int column_offset,
     103             :                                        ScriptOriginOptions resource_options) {
     104             :   Handle<Script> script =
     105      263010 :       Handle<Script>(Script::cast(function_info->script()), isolate());
     106             :   // If the script name isn't set, the boilerplate script should have
     107             :   // an undefined name to have the same origin.
     108             :   Handle<Object> name;
     109      131505 :   if (!maybe_name.ToHandle(&name)) {
     110             :     return script->name()->IsUndefined(isolate());
     111             :   }
     112             :   // Do the fast bailout checks first.
     113       63983 :   if (line_offset != script->line_offset()) return false;
     114       63977 :   if (column_offset != script->column_offset()) return false;
     115             :   // Check that both names are strings. If not, no match.
     116      127954 :   if (!name->IsString() || !script->name()->IsString()) return false;
     117             :   // Are the origin_options same?
     118       63977 :   if (resource_options.Flags() != script->origin_options().Flags())
     119             :     return false;
     120             :   // Compare the two name strings for equality.
     121       63967 :   return String::Equals(
     122             :       isolate(), Handle<String>::cast(name),
     123       63967 :       Handle<String>(String::cast(script->name()), isolate()));
     124             : }
     125             : 
     126             : // TODO(245): Need to allow identical code from different contexts to
     127             : // be cached in the same script generation. Currently the first use
     128             : // will be cached, but subsequent code from different source / line
     129             : // won't.
     130      272078 : MaybeHandle<SharedFunctionInfo> CompilationCacheScript::Lookup(
     131             :     Handle<String> source, MaybeHandle<Object> name, int line_offset,
     132             :     int column_offset, ScriptOriginOptions resource_options,
     133             :     Handle<Context> native_context, LanguageMode language_mode) {
     134             :   MaybeHandle<SharedFunctionInfo> result;
     135             : 
     136             :   // Probe the script generation tables. Make sure not to leak handles
     137             :   // into the caller's handle scope.
     138             :   { HandleScope scope(isolate());
     139             :     const int generation = 0;
     140             :     DCHECK_EQ(generations(), 1);
     141      272078 :     Handle<CompilationCacheTable> table = GetTable(generation);
     142             :     MaybeHandle<SharedFunctionInfo> probe = CompilationCacheTable::LookupScript(
     143      272078 :         table, source, native_context, language_mode);
     144             :     Handle<SharedFunctionInfo> function_info;
     145      272078 :     if (probe.ToHandle(&function_info)) {
     146             :       // Break when we've found a suitable shared function info that
     147             :       // matches the origin.
     148      131505 :       if (HasOrigin(function_info, name, line_offset, column_offset,
     149             :                     resource_options)) {
     150      131025 :         result = scope.CloseAndEscape(function_info);
     151             :       }
     152             :     }
     153             :   }
     154             : 
     155             :   // Once outside the manacles of the handle scope, we need to recheck
     156             :   // to see if we actually found a cached script. If so, we return a
     157             :   // handle created in the caller's handle scope.
     158             :   Handle<SharedFunctionInfo> function_info;
     159      272078 :   if (result.ToHandle(&function_info)) {
     160             : #ifdef DEBUG
     161             :     // Since HasOrigin can allocate, we need to protect the SharedFunctionInfo
     162             :     // with handles during the call.
     163             :     DCHECK(HasOrigin(function_info, name, line_offset, column_offset,
     164             :                      resource_options));
     165             : #endif
     166      131025 :     isolate()->counters()->compilation_cache_hits()->Increment();
     167      131025 :     LOG(isolate(), CompilationCacheEvent("hit", "script", *function_info));
     168             :   } else {
     169      141053 :     isolate()->counters()->compilation_cache_misses()->Increment();
     170             :   }
     171      272078 :   return result;
     172             : }
     173             : 
     174      138860 : void CompilationCacheScript::Put(Handle<String> source,
     175             :                                  Handle<Context> native_context,
     176             :                                  LanguageMode language_mode,
     177             :                                  Handle<SharedFunctionInfo> function_info) {
     178             :   HandleScope scope(isolate());
     179      277720 :   Handle<CompilationCacheTable> table = GetFirstTable();
     180      138860 :   SetFirstTable(CompilationCacheTable::PutScript(table, source, native_context,
     181             :                                                  language_mode, function_info));
     182      138860 : }
     183             : 
     184     3526571 : InfoCellPair CompilationCacheEval::Lookup(Handle<String> source,
     185             :                                           Handle<SharedFunctionInfo> outer_info,
     186             :                                           Handle<Context> native_context,
     187             :                                           LanguageMode language_mode,
     188             :                                           int position) {
     189             :   HandleScope scope(isolate());
     190             :   // Make sure not to leak the table into the surrounding handle
     191             :   // scope. Otherwise, we risk keeping old tables around even after
     192             :   // having cleared the cache.
     193             :   InfoCellPair result;
     194             :   const int generation = 0;
     195             :   DCHECK_EQ(generations(), 1);
     196     3526571 :   Handle<CompilationCacheTable> table = GetTable(generation);
     197             :   result = CompilationCacheTable::LookupEval(
     198     3526571 :       table, source, outer_info, native_context, language_mode, position);
     199     3526571 :   if (result.has_shared()) {
     200     2593390 :     isolate()->counters()->compilation_cache_hits()->Increment();
     201             :   } else {
     202      933181 :     isolate()->counters()->compilation_cache_misses()->Increment();
     203             :   }
     204     3526571 :   return result;
     205             : }
     206             : 
     207     1188860 : void CompilationCacheEval::Put(Handle<String> source,
     208             :                                Handle<SharedFunctionInfo> outer_info,
     209             :                                Handle<SharedFunctionInfo> function_info,
     210             :                                Handle<Context> native_context,
     211             :                                Handle<FeedbackCell> feedback_cell,
     212             :                                int position) {
     213             :   HandleScope scope(isolate());
     214     1188860 :   Handle<CompilationCacheTable> table = GetFirstTable();
     215             :   table =
     216             :       CompilationCacheTable::PutEval(table, source, outer_info, function_info,
     217     1188860 :                                      native_context, feedback_cell, position);
     218             :   SetFirstTable(table);
     219     1188860 : }
     220             : 
     221      459168 : MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
     222             :     Handle<String> source,
     223             :     JSRegExp::Flags flags) {
     224             :   HandleScope scope(isolate());
     225             :   // Make sure not to leak the table into the surrounding handle
     226             :   // scope. Otherwise, we risk keeping old tables around even after
     227             :   // having cleared the cache.
     228             :   Handle<Object> result = isolate()->factory()->undefined_value();
     229             :   int generation;
     230     1517092 :   for (generation = 0; generation < generations(); generation++) {
     231      734904 :     Handle<CompilationCacheTable> table = GetTable(generation);
     232      734904 :     result = table->LookupRegExp(source, flags);
     233      734904 :     if (result->IsFixedArray()) break;
     234             :   }
     235      459168 :   if (result->IsFixedArray()) {
     236      205942 :     Handle<FixedArray> data = Handle<FixedArray>::cast(result);
     237      205942 :     if (generation != 0) {
     238       22510 :       Put(source, flags, data);
     239             :     }
     240      205942 :     isolate()->counters()->compilation_cache_hits()->Increment();
     241      205942 :     return scope.CloseAndEscape(data);
     242             :   } else {
     243      253226 :     isolate()->counters()->compilation_cache_misses()->Increment();
     244      253226 :     return MaybeHandle<FixedArray>();
     245             :   }
     246             : }
     247             : 
     248      272910 : void CompilationCacheRegExp::Put(Handle<String> source,
     249             :                                  JSRegExp::Flags flags,
     250             :                                  Handle<FixedArray> data) {
     251             :   HandleScope scope(isolate());
     252      545820 :   Handle<CompilationCacheTable> table = GetFirstTable();
     253      272910 :   SetFirstTable(
     254             :       CompilationCacheTable::PutRegExp(isolate(), table, source, flags, data));
     255      272910 : }
     256             : 
     257        1819 : void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
     258        1819 :   if (!IsEnabled()) return;
     259             : 
     260         268 :   eval_global_.Remove(function_info);
     261         268 :   eval_contextual_.Remove(function_info);
     262         268 :   script_.Remove(function_info);
     263             : }
     264             : 
     265      285296 : MaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript(
     266             :     Handle<String> source, MaybeHandle<Object> name, int line_offset,
     267             :     int column_offset, ScriptOriginOptions resource_options,
     268             :     Handle<Context> native_context, LanguageMode language_mode) {
     269      285296 :   if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>();
     270             : 
     271             :   return script_.Lookup(source, name, line_offset, column_offset,
     272      272078 :                         resource_options, native_context, language_mode);
     273             : }
     274             : 
     275     3556334 : InfoCellPair CompilationCache::LookupEval(Handle<String> source,
     276             :                                           Handle<SharedFunctionInfo> outer_info,
     277             :                                           Handle<Context> context,
     278             :                                           LanguageMode language_mode,
     279             :                                           int position) {
     280             :   InfoCellPair result;
     281     3556334 :   if (!IsEnabled()) return result;
     282             : 
     283             :   const char* cache_type;
     284             : 
     285     3526571 :   if (context->IsNativeContext()) {
     286             :     result = eval_global_.Lookup(source, outer_info, context, language_mode,
     287     1271307 :                                  position);
     288             :     cache_type = "eval-global";
     289             : 
     290             :   } else {
     291             :     DCHECK_NE(position, kNoSourcePosition);
     292             :     Handle<Context> native_context(context->native_context(), isolate());
     293             :     result = eval_contextual_.Lookup(source, outer_info, native_context,
     294     2255264 :                                      language_mode, position);
     295             :     cache_type = "eval-contextual";
     296             :   }
     297             : 
     298     3526571 :   if (result.has_shared()) {
     299     2593390 :     LOG(isolate(), CompilationCacheEvent("hit", cache_type, result.shared()));
     300             :   }
     301             : 
     302             :   return result;
     303             : }
     304             : 
     305      460435 : MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
     306             :                                                        JSRegExp::Flags flags) {
     307      460435 :   if (!IsEnabled()) return MaybeHandle<FixedArray>();
     308             : 
     309      459168 :   return reg_exp_.Lookup(source, flags);
     310             : }
     311             : 
     312      151988 : void CompilationCache::PutScript(Handle<String> source,
     313             :                                  Handle<Context> native_context,
     314             :                                  LanguageMode language_mode,
     315             :                                  Handle<SharedFunctionInfo> function_info) {
     316      151988 :   if (!IsEnabled()) return;
     317      138911 :   LOG(isolate(), CompilationCacheEvent("put", "script", *function_info));
     318             : 
     319      138860 :   script_.Put(source, native_context, language_mode, function_info);
     320             : }
     321             : 
     322     1218479 : void CompilationCache::PutEval(Handle<String> source,
     323             :                                Handle<SharedFunctionInfo> outer_info,
     324             :                                Handle<Context> context,
     325             :                                Handle<SharedFunctionInfo> function_info,
     326             :                                Handle<FeedbackCell> feedback_cell,
     327             :                                int position) {
     328     1218479 :   if (!IsEnabled()) return;
     329             : 
     330             :   const char* cache_type;
     331             :   HandleScope scope(isolate());
     332     1188860 :   if (context->IsNativeContext()) {
     333      535230 :     eval_global_.Put(source, outer_info, function_info, context, feedback_cell,
     334      535230 :                      position);
     335             :     cache_type = "eval-global";
     336             :   } else {
     337             :     DCHECK_NE(position, kNoSourcePosition);
     338             :     Handle<Context> native_context(context->native_context(), isolate());
     339      653630 :     eval_contextual_.Put(source, outer_info, function_info, native_context,
     340      653630 :                          feedback_cell, position);
     341             :     cache_type = "eval-contextual";
     342             :   }
     343     1188860 :   LOG(isolate(), CompilationCacheEvent("put", cache_type, *function_info));
     344             : }
     345             : 
     346      251662 : void CompilationCache::PutRegExp(Handle<String> source,
     347             :                                  JSRegExp::Flags flags,
     348             :                                  Handle<FixedArray> data) {
     349      251662 :   if (!IsEnabled()) return;
     350             : 
     351      250400 :   reg_exp_.Put(source, flags, data);
     352             : }
     353             : 
     354        1476 : void CompilationCache::Clear() {
     355       49752 :   for (int i = 0; i < kSubCacheCount; i++) {
     356       22112 :     subcaches_[i]->Clear();
     357             :   }
     358        1476 : }
     359             : 
     360      275539 : void CompilationCache::Iterate(RootVisitor* v) {
     361     2479851 :   for (int i = 0; i < kSubCacheCount; i++) {
     362     1102156 :     subcaches_[i]->Iterate(v);
     363             :   }
     364      275539 : }
     365             : 
     366       96169 : void CompilationCache::MarkCompactPrologue() {
     367      865521 :   for (int i = 0; i < kSubCacheCount; i++) {
     368      384676 :     subcaches_[i]->Age();
     369             :   }
     370       96169 : }
     371             : 
     372        3932 : void CompilationCache::Enable() {
     373        3932 :   enabled_ = true;
     374        3932 : }
     375             : 
     376        4052 : void CompilationCache::Disable() {
     377        4052 :   enabled_ = false;
     378             :   Clear();
     379        4052 : }
     380             : 
     381             : }  // namespace internal
     382      122036 : }  // namespace v8

Generated by: LCOV version 1.10