LCOV - code coverage report
Current view: top level - src - compilation-cache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 137 150 91.3 %
Date: 2017-04-26 Functions: 25 29 86.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             : 
      18             : // The number of generations for each sub cache.
      19             : static const int kRegExpGenerations = 2;
      20             : 
      21             : // Initial size of each compilation cache table allocated.
      22             : static const int kInitialCacheSize = 64;
      23             : 
      24       60782 : CompilationCache::CompilationCache(Isolate* isolate)
      25             :     : isolate_(isolate),
      26             :       script_(isolate),
      27             :       eval_global_(isolate),
      28             :       eval_contextual_(isolate),
      29             :       reg_exp_(isolate, kRegExpGenerations),
      30      121564 :       enabled_(true) {
      31             :   CompilationSubCache* subcaches[kSubCacheCount] =
      32       60782 :     {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
      33      303910 :   for (int i = 0; i < kSubCacheCount; ++i) {
      34      243128 :     subcaches_[i] = subcaches[i];
      35             :   }
      36       60782 : }
      37             : 
      38             : 
      39      118570 : CompilationCache::~CompilationCache() {}
      40             : 
      41             : 
      42    18547116 : Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
      43             :   DCHECK(generation < generations_);
      44             :   Handle<CompilationCacheTable> result;
      45    18547116 :   if (tables_[generation]->IsUndefined(isolate())) {
      46       65550 :     result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
      47      131100 :     tables_[generation] = *result;
      48             :   } else {
      49             :     CompilationCacheTable* table =
      50     9208008 :         CompilationCacheTable::cast(tables_[generation]);
      51             :     result = Handle<CompilationCacheTable>(table, isolate());
      52             :   }
      53     9273558 :   return result;
      54             : }
      55             : 
      56             : 
      57      436400 : void CompilationSubCache::Age() {
      58             :   // Don't directly age single-generation caches.
      59      218200 :   if (generations_ == 1) {
      60      327300 :     if (!tables_[0]->IsUndefined(isolate())) {
      61       19088 :       CompilationCacheTable::cast(tables_[0])->Age();
      62             :     }
      63      218200 :     return;
      64             :   }
      65             : 
      66             :   // Age the generations implicitly killing off the oldest.
      67      109100 :   for (int i = generations_ - 1; i > 0; i--) {
      68       54550 :     tables_[i] = tables_[i - 1];
      69             :   }
      70             : 
      71             :   // Set the first generation as unborn.
      72      109100 :   tables_[0] = isolate()->heap()->undefined_value();
      73             : }
      74             : 
      75             : 
      76      213384 : void CompilationSubCache::IterateFunctions(ObjectVisitor* v) {
      77      213384 :   Object* undefined = isolate()->heap()->undefined_value();
      78      480114 :   for (int i = 0; i < generations_; i++) {
      79      266730 :     if (tables_[i] != undefined) {
      80       18086 :       reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v);
      81             :     }
      82             :   }
      83      213384 : }
      84             : 
      85           0 : void CompilationSubCache::Iterate(RootVisitor* v) {
      86             :   v->VisitRootPointers(Root::kCompilationCache, &tables_[0],
      87      966340 :                        &tables_[generations_]);
      88           0 : }
      89             : 
      90             : 
      91     2699824 : void CompilationSubCache::Clear() {
      92     5399648 :   MemsetPointer(tables_, isolate()->heap()->undefined_value(), generations_);
      93           0 : }
      94             : 
      95             : 
      96           0 : void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
      97             :   // Probe the script generation tables. Make sure not to leak handles
      98             :   // into the caller's handle scope.
      99             :   { HandleScope scope(isolate());
     100           0 :     for (int generation = 0; generation < generations(); generation++) {
     101           0 :       Handle<CompilationCacheTable> table = GetTable(generation);
     102           0 :       table->Remove(*function_info);
     103             :     }
     104             :   }
     105           0 : }
     106             : 
     107           0 : CompilationCacheScript::CompilationCacheScript(Isolate* isolate)
     108           0 :     : CompilationSubCache(isolate, 1) {}
     109             : 
     110             : // We only re-use a cached function for some script source code if the
     111             : // script originates from the same place. This is to avoid issues
     112             : // when reporting errors, etc.
     113      141811 : bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info,
     114             :                                        Handle<Object> name, int line_offset,
     115             :                                        int column_offset,
     116             :                                        ScriptOriginOptions resource_options) {
     117             :   Handle<Script> script =
     118      200974 :       Handle<Script>(Script::cast(function_info->script()), isolate());
     119             :   // If the script name isn't set, the boilerplate script should have
     120             :   // an undefined name to have the same origin.
     121      141811 :   if (name.is_null()) {
     122       59163 :     return script->name()->IsUndefined(isolate());
     123             :   }
     124             :   // Do the fast bailout checks first.
     125       82648 :   if (line_offset != script->line_offset()) return false;
     126       82640 :   if (column_offset != script->column_offset()) return false;
     127             :   // Check that both names are strings. If not, no match.
     128      165280 :   if (!name->IsString() || !script->name()->IsString()) return false;
     129             :   // Are the origin_options same?
     130       82640 :   if (resource_options.Flags() != script->origin_options().Flags())
     131             :     return false;
     132             :   // Compare the two name strings for equality.
     133             :   return String::Equals(Handle<String>::cast(name),
     134       82634 :                         Handle<String>(String::cast(script->name())));
     135             : }
     136             : 
     137             : 
     138             : // TODO(245): Need to allow identical code from different contexts to
     139             : // be cached in the same script generation. Currently the first use
     140             : // will be cached, but subsequent code from different source / line
     141             : // won't.
     142      311147 : InfoVectorPair CompilationCacheScript::Lookup(
     143             :     Handle<String> source, Handle<Object> name, int line_offset,
     144             :     int column_offset, ScriptOriginOptions resource_options,
     145             :     Handle<Context> context, LanguageMode language_mode) {
     146             :   InfoVectorPair result;
     147             : 
     148             :   // Probe the script generation tables. Make sure not to leak handles
     149             :   // into the caller's handle scope.
     150      815178 :   { HandleScope scope(isolate());
     151             :     const int generation = 0;
     152             :     DCHECK(generations() == 1);
     153      311147 :     Handle<CompilationCacheTable> table = GetTable(generation);
     154      311147 :     InfoVectorPair probe = table->LookupScript(source, context, language_mode);
     155      311147 :     if (probe.has_shared()) {
     156             :       Handle<SharedFunctionInfo> function_info(probe.shared(), isolate());
     157             :       Handle<Cell> vector_handle;
     158      141811 :       if (probe.has_vector()) {
     159             :         vector_handle = Handle<Cell>(probe.vector(), isolate());
     160             :       }
     161             :       // Break when we've found a suitable shared function info that
     162             :       // matches the origin.
     163      141811 :       if (HasOrigin(function_info, name, line_offset, column_offset,
     164             :                     resource_options)) {
     165             :         result = InfoVectorPair(*function_info,
     166      141187 :                                 probe.has_vector() ? *vector_handle : nullptr);
     167             :       }
     168             :     }
     169             :   }
     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.
     174      311147 :   if (result.has_shared()) {
     175             : #ifdef DEBUG
     176             :     // Since HasOrigin can allocate, we need to protect the SharedFunctionInfo
     177             :     // and the FeedbackVector with handles during the call.
     178             :     Handle<SharedFunctionInfo> shared(result.shared(), isolate());
     179             :     Handle<Cell> vector_handle;
     180             :     if (result.has_vector()) {
     181             :       vector_handle = Handle<Cell>(result.vector(), isolate());
     182             :     }
     183             :     DCHECK(
     184             :         HasOrigin(shared, name, line_offset, column_offset, resource_options));
     185             :     result =
     186             :         InfoVectorPair(*shared, result.has_vector() ? *vector_handle : nullptr);
     187             : #endif
     188      141187 :     isolate()->counters()->compilation_cache_hits()->Increment();
     189             :   } else {
     190      169960 :     isolate()->counters()->compilation_cache_misses()->Increment();
     191             :   }
     192      311147 :   return result;
     193             : }
     194             : 
     195      168529 : void CompilationCacheScript::Put(Handle<String> source, Handle<Context> context,
     196             :                                  LanguageMode language_mode,
     197             :                                  Handle<SharedFunctionInfo> function_info,
     198             :                                  Handle<Cell> literals) {
     199      337058 :   HandleScope scope(isolate());
     200      337058 :   Handle<CompilationCacheTable> table = GetFirstTable();
     201             :   SetFirstTable(CompilationCacheTable::PutScript(
     202      168529 :       table, source, context, language_mode, function_info, literals));
     203      168529 : }
     204             : 
     205     5554356 : InfoVectorPair CompilationCacheEval::Lookup(
     206             :     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     207             :     Handle<Context> native_context, LanguageMode language_mode, int position) {
     208    11108712 :   HandleScope scope(isolate());
     209             :   // Make sure not to leak the table into the surrounding handle
     210             :   // scope. Otherwise, we risk keeping old tables around even after
     211             :   // having cleared the cache.
     212             :   InfoVectorPair result;
     213             :   const int generation = 0;
     214             :   DCHECK(generations() == 1);
     215     5554356 :   Handle<CompilationCacheTable> table = GetTable(generation);
     216             :   result = table->LookupEval(source, outer_info, native_context, language_mode,
     217     5554356 :                              position);
     218     5554356 :   if (result.has_shared()) {
     219     4302215 :     isolate()->counters()->compilation_cache_hits()->Increment();
     220             :   } else {
     221     1252141 :     isolate()->counters()->compilation_cache_misses()->Increment();
     222             :   }
     223    11108712 :   return result;
     224             : }
     225             : 
     226     1816841 : void CompilationCacheEval::Put(Handle<String> source,
     227             :                                Handle<SharedFunctionInfo> outer_info,
     228             :                                Handle<SharedFunctionInfo> function_info,
     229             :                                Handle<Context> native_context,
     230             :                                Handle<Cell> literals, int position) {
     231     3633682 :   HandleScope scope(isolate());
     232     1816841 :   Handle<CompilationCacheTable> table = GetFirstTable();
     233             :   table =
     234             :       CompilationCacheTable::PutEval(table, source, outer_info, function_info,
     235     1816841 :                                      native_context, literals, position);
     236             :   SetFirstTable(table);
     237     1816841 : }
     238             : 
     239             : 
     240      712898 : MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
     241             :     Handle<String> source,
     242             :     JSRegExp::Flags flags) {
     243     2851851 :   HandleScope scope(isolate());
     244             :   // Make sure not to leak the table into the surrounding handle
     245             :   // scope. Otherwise, we risk keeping old tables around even after
     246             :   // having cleared the cache.
     247             :   Handle<Object> result = isolate()->factory()->undefined_value();
     248             :   int generation;
     249     2852110 :   for (generation = 0; generation < generations(); generation++) {
     250     1069572 :     Handle<CompilationCacheTable> table = GetTable(generation);
     251     1069572 :     result = table->LookupRegExp(source, flags);
     252     1069572 :     if (result->IsFixedArray()) break;
     253             :   }
     254      712898 :   if (result->IsFixedArray()) {
     255      356415 :     Handle<FixedArray> data = Handle<FixedArray>::cast(result);
     256      356415 :     if (generation != 0) {
     257         191 :       Put(source, flags, data);
     258             :     }
     259      356415 :     isolate()->counters()->compilation_cache_hits()->Increment();
     260      356415 :     return scope.CloseAndEscape(data);
     261             :   } else {
     262      356483 :     isolate()->counters()->compilation_cache_misses()->Increment();
     263             :     return MaybeHandle<FixedArray>();
     264             :   }
     265             : }
     266             : 
     267             : 
     268      353113 : void CompilationCacheRegExp::Put(Handle<String> source,
     269             :                                  JSRegExp::Flags flags,
     270             :                                  Handle<FixedArray> data) {
     271      706226 :   HandleScope scope(isolate());
     272      706226 :   Handle<CompilationCacheTable> table = GetFirstTable();
     273      353113 :   SetFirstTable(CompilationCacheTable::PutRegExp(table, source, flags, data));
     274      353113 : }
     275             : 
     276             : 
     277        6966 : void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
     278       13932 :   if (!IsEnabled()) return;
     279             : 
     280           0 :   eval_global_.Remove(function_info);
     281           0 :   eval_contextual_.Remove(function_info);
     282           0 :   script_.Remove(function_info);
     283             : }
     284             : 
     285      344247 : InfoVectorPair CompilationCache::LookupScript(
     286             :     Handle<String> source, Handle<Object> name, int line_offset,
     287             :     int column_offset, ScriptOriginOptions resource_options,
     288             :     Handle<Context> context, LanguageMode language_mode) {
     289             :   InfoVectorPair empty_result;
     290      344247 :   if (!IsEnabled()) return empty_result;
     291             : 
     292             :   return script_.Lookup(source, name, line_offset, column_offset,
     293      311147 :                         resource_options, context, language_mode);
     294             : }
     295             : 
     296     5596538 : InfoVectorPair CompilationCache::LookupEval(
     297             :     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     298     3460743 :     Handle<Context> context, LanguageMode language_mode, int position) {
     299             :   InfoVectorPair result;
     300     5596538 :   if (!IsEnabled()) return result;
     301             : 
     302     5554356 :   if (context->IsNativeContext()) {
     303             :     result = eval_global_.Lookup(source, outer_info, context, language_mode,
     304     2093613 :                                  position);
     305             :   } else {
     306             :     DCHECK(position != kNoSourcePosition);
     307             :     Handle<Context> native_context(context->native_context(), isolate());
     308             :     result = eval_contextual_.Lookup(source, outer_info, native_context,
     309     3460743 :                                      language_mode, position);
     310             :   }
     311             : 
     312     5554356 :   return result;
     313             : }
     314             : 
     315             : 
     316      719988 : MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
     317             :                                                        JSRegExp::Flags flags) {
     318      719988 :   if (!IsEnabled()) return MaybeHandle<FixedArray>();
     319             : 
     320      712898 :   return reg_exp_.Lookup(source, flags);
     321             : }
     322             : 
     323      200924 : void CompilationCache::PutScript(Handle<String> source, Handle<Context> context,
     324             :                                  LanguageMode language_mode,
     325             :                                  Handle<SharedFunctionInfo> function_info,
     326             :                                  Handle<Cell> literals) {
     327      401848 :   if (!IsEnabled()) return;
     328             : 
     329      168529 :   script_.Put(source, context, language_mode, function_info, literals);
     330             : }
     331             : 
     332     1858849 : void CompilationCache::PutEval(Handle<String> source,
     333             :                                Handle<SharedFunctionInfo> outer_info,
     334             :                                Handle<Context> context,
     335             :                                Handle<SharedFunctionInfo> function_info,
     336     2809970 :                                Handle<Cell> literals, int position) {
     337     3717698 :   if (!IsEnabled()) return;
     338             : 
     339             :   HandleScope scope(isolate());
     340     1816841 :   if (context->IsNativeContext()) {
     341             :     eval_global_.Put(source, outer_info, function_info, context, literals,
     342      823712 :                      position);
     343             :   } else {
     344             :     DCHECK(position != kNoSourcePosition);
     345             :     Handle<Context> native_context(context->native_context(), isolate());
     346             :     eval_contextual_.Put(source, outer_info, function_info, native_context,
     347      993129 :                          literals, position);
     348             :   }
     349             : }
     350             : 
     351             : 
     352             : 
     353      360011 : void CompilationCache::PutRegExp(Handle<String> source,
     354             :                                  JSRegExp::Flags flags,
     355             :                                  Handle<FixedArray> data) {
     356      360011 :   if (!IsEnabled()) {
     357      360011 :     return;
     358             :   }
     359             : 
     360      352922 :   reg_exp_.Put(source, flags, data);
     361             : }
     362             : 
     363             : 
     364        7448 : void CompilationCache::Clear() {
     365     2707272 :   for (int i = 0; i < kSubCacheCount; i++) {
     366     2699824 :     subcaches_[i]->Clear();
     367             :   }
     368        7448 : }
     369             : 
     370      241585 : void CompilationCache::Iterate(RootVisitor* v) {
     371     1207925 :   for (int i = 0; i < kSubCacheCount; i++) {
     372      966340 :     subcaches_[i]->Iterate(v);
     373             :   }
     374      241585 : }
     375             : 
     376             : 
     377       53346 : void CompilationCache::IterateFunctions(ObjectVisitor* v) {
     378      266730 :   for (int i = 0; i < kSubCacheCount; i++) {
     379      213384 :     subcaches_[i]->IterateFunctions(v);
     380             :   }
     381       53346 : }
     382             : 
     383             : 
     384       54550 : void CompilationCache::MarkCompactPrologue() {
     385      272750 :   for (int i = 0; i < kSubCacheCount; i++) {
     386      218200 :     subcaches_[i]->Age();
     387             :   }
     388       54550 : }
     389             : 
     390             : 
     391        5243 : void CompilationCache::Enable() {
     392        5243 :   enabled_ = true;
     393        5243 : }
     394             : 
     395             : 
     396      667508 : void CompilationCache::Disable() {
     397      667508 :   enabled_ = false;
     398             :   Clear();
     399      667508 : }
     400             : 
     401             : 
     402             : }  // namespace internal
     403             : }  // namespace v8

Generated by: LCOV version 1.10