LCOV - code coverage report
Current view: top level - src - compilation-cache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 128 141 90.8 %
Date: 2017-10-20 Functions: 23 27 85.2 %

          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/factory.h"
       9             : #include "src/globals.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects/compilation-cache-inl.h"
      12             : #include "src/visitors.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : // The number of generations for each sub cache.
      18             : static const int kRegExpGenerations = 2;
      19             : 
      20             : // Initial size of each compilation cache table allocated.
      21             : static const int kInitialCacheSize = 64;
      22             : 
      23       54999 : CompilationCache::CompilationCache(Isolate* isolate)
      24             :     : isolate_(isolate),
      25             :       script_(isolate),
      26             :       eval_global_(isolate),
      27             :       eval_contextual_(isolate),
      28             :       reg_exp_(isolate, kRegExpGenerations),
      29      109998 :       enabled_(true) {
      30             :   CompilationSubCache* subcaches[kSubCacheCount] =
      31       54999 :     {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
      32      274995 :   for (int i = 0; i < kSubCacheCount; ++i) {
      33      219996 :     subcaches_[i] = subcaches[i];
      34             :   }
      35       54999 : }
      36             : 
      37      106730 : CompilationCache::~CompilationCache() {}
      38             : 
      39    12504953 : Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
      40             :   DCHECK(generation < generations_);
      41             :   Handle<CompilationCacheTable> result;
      42    12504953 :   if (tables_[generation]->IsUndefined(isolate())) {
      43       58980 :     result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
      44      117960 :     tables_[generation] = *result;
      45             :   } else {
      46             :     CompilationCacheTable* table =
      47     6193497 :         CompilationCacheTable::cast(tables_[generation]);
      48             :     result = Handle<CompilationCacheTable>(table, isolate());
      49             :   }
      50     6252477 :   return result;
      51             : }
      52             : 
      53      589168 : void CompilationSubCache::Age() {
      54             :   // Don't directly age single-generation caches.
      55      294584 :   if (generations_ == 1) {
      56      441876 :     if (!tables_[0]->IsUndefined(isolate())) {
      57       37857 :       CompilationCacheTable::cast(tables_[0])->Age();
      58             :     }
      59      294584 :     return;
      60             :   }
      61             : 
      62             :   // Age the generations implicitly killing off the oldest.
      63      147292 :   for (int i = generations_ - 1; i > 0; i--) {
      64       73646 :     tables_[i] = tables_[i - 1];
      65             :   }
      66             : 
      67             :   // Set the first generation as unborn.
      68      147292 :   tables_[0] = isolate()->heap()->undefined_value();
      69             : }
      70             : 
      71           0 : void CompilationSubCache::Iterate(RootVisitor* v) {
      72             :   v->VisitRootPointers(Root::kCompilationCache, &tables_[0],
      73      929692 :                        &tables_[generations_]);
      74           0 : }
      75             : 
      76     1336408 : void CompilationSubCache::Clear() {
      77     2672816 :   MemsetPointer(tables_, isolate()->heap()->undefined_value(), generations_);
      78           0 : }
      79             : 
      80           0 : void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
      81             :   // Probe the script generation tables. Make sure not to leak handles
      82             :   // into the caller's handle scope.
      83             :   { HandleScope scope(isolate());
      84           0 :     for (int generation = 0; generation < generations(); generation++) {
      85           0 :       Handle<CompilationCacheTable> table = GetTable(generation);
      86           0 :       table->Remove(*function_info);
      87             :     }
      88             :   }
      89           0 : }
      90             : 
      91           0 : CompilationCacheScript::CompilationCacheScript(Isolate* isolate)
      92           0 :     : CompilationSubCache(isolate, 1) {}
      93             : 
      94             : // We only re-use a cached function for some script source code if the
      95             : // script originates from the same place. This is to avoid issues
      96             : // when reporting errors, etc.
      97       92034 : bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info,
      98             :                                        MaybeHandle<Object> maybe_name,
      99             :                                        int line_offset, int column_offset,
     100             :                                        ScriptOriginOptions resource_options) {
     101             :   Handle<Script> script =
     102      140527 :       Handle<Script>(Script::cast(function_info->script()), isolate());
     103             :   // If the script name isn't set, the boilerplate script should have
     104             :   // an undefined name to have the same origin.
     105             :   Handle<Object> name;
     106       92034 :   if (!maybe_name.ToHandle(&name)) {
     107       48493 :     return script->name()->IsUndefined(isolate());
     108             :   }
     109             :   // Do the fast bailout checks first.
     110       43541 :   if (line_offset != script->line_offset()) return false;
     111       43535 :   if (column_offset != script->column_offset()) return false;
     112             :   // Check that both names are strings. If not, no match.
     113       87070 :   if (!name->IsString() || !script->name()->IsString()) return false;
     114             :   // Are the origin_options same?
     115       43535 :   if (resource_options.Flags() != script->origin_options().Flags())
     116             :     return false;
     117             :   // Compare the two name strings for equality.
     118             :   return String::Equals(Handle<String>::cast(name),
     119       43530 :                         Handle<String>(String::cast(script->name())));
     120             : }
     121             : 
     122             : // TODO(245): Need to allow identical code from different contexts to
     123             : // be cached in the same script generation. Currently the first use
     124             : // will be cached, but subsequent code from different source / line
     125             : // won't.
     126      211326 : InfoVectorPair CompilationCacheScript::Lookup(
     127             :     Handle<String> source, MaybeHandle<Object> name, int line_offset,
     128             :     int column_offset, ScriptOriginOptions resource_options,
     129             :     Handle<Context> context, LanguageMode language_mode) {
     130             :   InfoVectorPair result;
     131             : 
     132             :   // Probe the script generation tables. Make sure not to leak handles
     133             :   // into the caller's handle scope.
     134      554213 :   { HandleScope scope(isolate());
     135             :     const int generation = 0;
     136             :     DCHECK_EQ(generations(), 1);
     137      211326 :     Handle<CompilationCacheTable> table = GetTable(generation);
     138      211326 :     InfoVectorPair probe = table->LookupScript(source, context, language_mode);
     139      211326 :     if (probe.has_shared()) {
     140             :       Handle<SharedFunctionInfo> function_info(probe.shared(), isolate());
     141             :       Handle<Cell> vector_handle;
     142       92034 :       if (probe.has_vector()) {
     143             :         vector_handle = Handle<Cell>(probe.vector(), isolate());
     144             :       }
     145             :       // Break when we've found a suitable shared function info that
     146             :       // matches the origin.
     147       92034 :       if (HasOrigin(function_info, name, line_offset, column_offset,
     148             :                     resource_options)) {
     149             :         result = InfoVectorPair(*function_info,
     150       91473 :                                 probe.has_vector() ? *vector_handle : nullptr);
     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      211326 :   if (result.has_shared()) {
     159             : #ifdef DEBUG
     160             :     // Since HasOrigin can allocate, we need to protect the SharedFunctionInfo
     161             :     // and the FeedbackVector with handles during the call.
     162             :     Handle<SharedFunctionInfo> shared(result.shared(), isolate());
     163             :     Handle<Cell> vector_handle;
     164             :     if (result.has_vector()) {
     165             :       vector_handle = Handle<Cell>(result.vector(), isolate());
     166             :     }
     167             :     DCHECK(
     168             :         HasOrigin(shared, name, line_offset, column_offset, resource_options));
     169             :     result =
     170             :         InfoVectorPair(*shared, result.has_vector() ? *vector_handle : nullptr);
     171             : #endif
     172       91473 :     isolate()->counters()->compilation_cache_hits()->Increment();
     173             :   } else {
     174      119853 :     isolate()->counters()->compilation_cache_misses()->Increment();
     175             :   }
     176      211326 :   return result;
     177             : }
     178             : 
     179      118424 : void CompilationCacheScript::Put(Handle<String> source, Handle<Context> context,
     180             :                                  LanguageMode language_mode,
     181             :                                  Handle<SharedFunctionInfo> function_info,
     182             :                                  Handle<Cell> literals) {
     183      236848 :   HandleScope scope(isolate());
     184      236848 :   Handle<CompilationCacheTable> table = GetFirstTable();
     185             :   SetFirstTable(CompilationCacheTable::PutScript(
     186      118424 :       table, source, context, language_mode, function_info, literals));
     187      118424 : }
     188             : 
     189     3620221 : InfoVectorPair CompilationCacheEval::Lookup(
     190             :     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     191             :     Handle<Context> native_context, LanguageMode language_mode, int position) {
     192     7240442 :   HandleScope scope(isolate());
     193             :   // Make sure not to leak the table into the surrounding handle
     194             :   // scope. Otherwise, we risk keeping old tables around even after
     195             :   // having cleared the cache.
     196             :   InfoVectorPair result;
     197             :   const int generation = 0;
     198             :   DCHECK_EQ(generations(), 1);
     199     3620221 :   Handle<CompilationCacheTable> table = GetTable(generation);
     200             :   result = table->LookupEval(source, outer_info, native_context, language_mode,
     201     3620221 :                              position);
     202     3620221 :   if (result.has_shared()) {
     203     2676093 :     isolate()->counters()->compilation_cache_hits()->Increment();
     204             :   } else {
     205      944128 :     isolate()->counters()->compilation_cache_misses()->Increment();
     206             :   }
     207     7240442 :   return result;
     208             : }
     209             : 
     210     1201484 : void CompilationCacheEval::Put(Handle<String> source,
     211             :                                Handle<SharedFunctionInfo> outer_info,
     212             :                                Handle<SharedFunctionInfo> function_info,
     213             :                                Handle<Context> native_context,
     214             :                                Handle<Cell> literals, int position) {
     215     2402968 :   HandleScope scope(isolate());
     216     1201484 :   Handle<CompilationCacheTable> table = GetFirstTable();
     217             :   table =
     218             :       CompilationCacheTable::PutEval(table, source, outer_info, function_info,
     219     1201484 :                                      native_context, literals, position);
     220             :   SetFirstTable(table);
     221     1201484 : }
     222             : 
     223      512735 : MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
     224             :     Handle<String> source,
     225             :     JSRegExp::Flags flags) {
     226     2641542 :   HandleScope scope(isolate());
     227             :   // Make sure not to leak the table into the surrounding handle
     228             :   // scope. Otherwise, we risk keeping old tables around even after
     229             :   // having cleared the cache.
     230             :   Handle<Object> result = isolate()->factory()->undefined_value();
     231             :   int generation;
     232     2206674 :   for (generation = 0; generation < generations(); generation++) {
     233      808106 :     Handle<CompilationCacheTable> table = GetTable(generation);
     234      808106 :     result = table->LookupRegExp(source, flags);
     235      808106 :     if (result->IsFixedArray()) break;
     236             :   }
     237      512735 :   if (result->IsFixedArray()) {
     238      217504 :     Handle<FixedArray> data = Handle<FixedArray>::cast(result);
     239      217504 :     if (generation != 0) {
     240         140 :       Put(source, flags, data);
     241             :     }
     242      217504 :     isolate()->counters()->compilation_cache_hits()->Increment();
     243      217504 :     return scope.CloseAndEscape(data);
     244             :   } else {
     245      295231 :     isolate()->counters()->compilation_cache_misses()->Increment();
     246      295231 :     return MaybeHandle<FixedArray>();
     247             :   }
     248             : }
     249             : 
     250      292916 : void CompilationCacheRegExp::Put(Handle<String> source,
     251             :                                  JSRegExp::Flags flags,
     252             :                                  Handle<FixedArray> data) {
     253      585832 :   HandleScope scope(isolate());
     254      585832 :   Handle<CompilationCacheTable> table = GetFirstTable();
     255      292916 :   SetFirstTable(CompilationCacheTable::PutRegExp(table, source, flags, data));
     256      292916 : }
     257             : 
     258        3576 : void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
     259        7152 :   if (!IsEnabled()) return;
     260             : 
     261           0 :   eval_global_.Remove(function_info);
     262           0 :   eval_contextual_.Remove(function_info);
     263           0 :   script_.Remove(function_info);
     264             : }
     265             : 
     266      233598 : InfoVectorPair CompilationCache::LookupScript(
     267             :     Handle<String> source, MaybeHandle<Object> name, int line_offset,
     268             :     int column_offset, ScriptOriginOptions resource_options,
     269             :     Handle<Context> context, LanguageMode language_mode) {
     270             :   InfoVectorPair empty_result;
     271      233598 :   if (!IsEnabled()) return empty_result;
     272             : 
     273             :   return script_.Lookup(source, name, line_offset, column_offset,
     274      211326 :                         resource_options, context, language_mode);
     275             : }
     276             : 
     277     3647841 : InfoVectorPair CompilationCache::LookupEval(
     278             :     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     279     2228059 :     Handle<Context> context, LanguageMode language_mode, int position) {
     280             :   InfoVectorPair result;
     281     3647841 :   if (!IsEnabled()) return result;
     282             : 
     283     3620221 :   if (context->IsNativeContext()) {
     284             :     result = eval_global_.Lookup(source, outer_info, context, language_mode,
     285     1392162 :                                  position);
     286             :   } else {
     287             :     DCHECK_NE(position, kNoSourcePosition);
     288             :     Handle<Context> native_context(context->native_context(), isolate());
     289             :     result = eval_contextual_.Lookup(source, outer_info, native_context,
     290     2228059 :                                      language_mode, position);
     291             :   }
     292             : 
     293     3620221 :   return result;
     294             : }
     295             : 
     296      518367 : MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
     297             :                                                        JSRegExp::Flags flags) {
     298      518367 :   if (!IsEnabled()) return MaybeHandle<FixedArray>();
     299             : 
     300      512735 :   return reg_exp_.Lookup(source, flags);
     301             : }
     302             : 
     303      140626 : void CompilationCache::PutScript(Handle<String> source, Handle<Context> context,
     304             :                                  LanguageMode language_mode,
     305             :                                  Handle<SharedFunctionInfo> function_info,
     306             :                                  Handle<Cell> literals) {
     307      281252 :   if (!IsEnabled()) return;
     308             : 
     309      118424 :   script_.Put(source, context, language_mode, function_info, literals);
     310             : }
     311             : 
     312     1228997 : void CompilationCache::PutEval(Handle<String> source,
     313             :                                Handle<SharedFunctionInfo> outer_info,
     314             :                                Handle<Context> context,
     315             :                                Handle<SharedFunctionInfo> function_info,
     316     1852323 :                                Handle<Cell> literals, int position) {
     317     2457994 :   if (!IsEnabled()) return;
     318             : 
     319             :   HandleScope scope(isolate());
     320     1201484 :   if (context->IsNativeContext()) {
     321             :     eval_global_.Put(source, outer_info, function_info, context, literals,
     322      550645 :                      position);
     323             :   } else {
     324             :     DCHECK_NE(position, kNoSourcePosition);
     325             :     Handle<Context> native_context(context->native_context(), isolate());
     326             :     eval_contextual_.Put(source, outer_info, function_info, native_context,
     327      650839 :                          literals, position);
     328             :   }
     329             : }
     330             : 
     331      298407 : void CompilationCache::PutRegExp(Handle<String> source,
     332             :                                  JSRegExp::Flags flags,
     333             :                                  Handle<FixedArray> data) {
     334      298407 :   if (!IsEnabled()) {
     335      298407 :     return;
     336             :   }
     337             : 
     338      292776 :   reg_exp_.Put(source, flags, data);
     339             : }
     340             : 
     341        6769 : void CompilationCache::Clear() {
     342     1343177 :   for (int i = 0; i < kSubCacheCount; i++) {
     343     1336408 :     subcaches_[i]->Clear();
     344             :   }
     345        6769 : }
     346             : 
     347      232423 : void CompilationCache::Iterate(RootVisitor* v) {
     348     1162115 :   for (int i = 0; i < kSubCacheCount; i++) {
     349      929692 :     subcaches_[i]->Iterate(v);
     350             :   }
     351      232423 : }
     352             : 
     353       73646 : void CompilationCache::MarkCompactPrologue() {
     354      368230 :   for (int i = 0; i < kSubCacheCount; i++) {
     355      294584 :     subcaches_[i]->Age();
     356             :   }
     357       73646 : }
     358             : 
     359        3820 : void CompilationCache::Enable() {
     360        3820 :   enabled_ = true;
     361        3820 : }
     362             : 
     363      327333 : void CompilationCache::Disable() {
     364      327333 :   enabled_ = false;
     365             :   Clear();
     366      327333 : }
     367             : 
     368             : }  // namespace internal
     369             : }  // namespace v8

Generated by: LCOV version 1.10