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       60744 : CompilationCache::CompilationCache(Isolate* isolate)
      25             :     : isolate_(isolate),
      26             :       script_(isolate),
      27             :       eval_global_(isolate),
      28             :       eval_contextual_(isolate),
      29             :       reg_exp_(isolate, kRegExpGenerations),
      30      121488 :       enabled_(true) {
      31             :   CompilationSubCache* subcaches[kSubCacheCount] =
      32       60744 :     {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
      33      303720 :   for (int i = 0; i < kSubCacheCount; ++i) {
      34      242976 :     subcaches_[i] = subcaches[i];
      35             :   }
      36       60744 : }
      37             : 
      38             : 
      39      118518 : CompilationCache::~CompilationCache() {}
      40             : 
      41             : 
      42    18547328 : Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
      43             :   DCHECK(generation < generations_);
      44             :   Handle<CompilationCacheTable> result;
      45    18547328 :   if (tables_[generation]->IsUndefined(isolate())) {
      46       65502 :     result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
      47      131004 :     tables_[generation] = *result;
      48             :   } else {
      49             :     CompilationCacheTable* table =
      50     9208162 :         CompilationCacheTable::cast(tables_[generation]);
      51             :     result = Handle<CompilationCacheTable>(table, isolate());
      52             :   }
      53     9273664 :   return result;
      54             : }
      55             : 
      56             : 
      57      435944 : void CompilationSubCache::Age() {
      58             :   // Don't directly age single-generation caches.
      59      217972 :   if (generations_ == 1) {
      60      326958 :     if (!tables_[0]->IsUndefined(isolate())) {
      61       19083 :       CompilationCacheTable::cast(tables_[0])->Age();
      62             :     }
      63      217972 :     return;
      64             :   }
      65             : 
      66             :   // Age the generations implicitly killing off the oldest.
      67      108986 :   for (int i = generations_ - 1; i > 0; i--) {
      68       54493 :     tables_[i] = tables_[i - 1];
      69             :   }
      70             : 
      71             :   // Set the first generation as unborn.
      72      108986 :   tables_[0] = isolate()->heap()->undefined_value();
      73             : }
      74             : 
      75             : 
      76      213176 : void CompilationSubCache::IterateFunctions(ObjectVisitor* v) {
      77      213176 :   Object* undefined = isolate()->heap()->undefined_value();
      78      479646 :   for (int i = 0; i < generations_; i++) {
      79      266470 :     if (tables_[i] != undefined) {
      80       18090 :       reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v);
      81             :     }
      82             :   }
      83      213176 : }
      84             : 
      85           0 : void CompilationSubCache::Iterate(RootVisitor* v) {
      86             :   v->VisitRootPointers(Root::kCompilationCache, &tables_[0],
      87      963932 :                        &tables_[generations_]);
      88           0 : }
      89             : 
      90             : 
      91     2698368 : void CompilationSubCache::Clear() {
      92     5396736 :   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      141713 : 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      200876 :       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      141713 :   if (name.is_null()) {
     122       59163 :     return script->name()->IsUndefined(isolate());
     123             :   }
     124             :   // Do the fast bailout checks first.
     125       82550 :   if (line_offset != script->line_offset()) return false;
     126       82542 :   if (column_offset != script->column_offset()) return false;
     127             :   // Check that both names are strings. If not, no match.
     128      165084 :   if (!name->IsString() || !script->name()->IsString()) return false;
     129             :   // Are the origin_options same?
     130       82542 :   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       82536 :                         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      310823 : 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      814400 :   { HandleScope scope(isolate());
     151             :     const int generation = 0;
     152             :     DCHECK(generations() == 1);
     153      310823 :     Handle<CompilationCacheTable> table = GetTable(generation);
     154      310823 :     InfoVectorPair probe = table->LookupScript(source, context, language_mode);
     155      310823 :     if (probe.has_shared()) {
     156             :       Handle<SharedFunctionInfo> function_info(probe.shared(), isolate());
     157             :       Handle<Cell> vector_handle;
     158      141713 :       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      141713 :       if (HasOrigin(function_info, name, line_offset, column_offset,
     164             :                     resource_options)) {
     165             :         result = InfoVectorPair(*function_info,
     166      141089 :                                 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      310823 :   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      141089 :     isolate()->counters()->compilation_cache_hits()->Increment();
     189             :   } else {
     190      169734 :     isolate()->counters()->compilation_cache_misses()->Increment();
     191             :   }
     192      310823 :   return result;
     193             : }
     194             : 
     195      168303 : void CompilationCacheScript::Put(Handle<String> source, Handle<Context> context,
     196             :                                  LanguageMode language_mode,
     197             :                                  Handle<SharedFunctionInfo> function_info,
     198             :                                  Handle<Cell> literals) {
     199      336606 :   HandleScope scope(isolate());
     200      336606 :   Handle<CompilationCacheTable> table = GetFirstTable();
     201             :   SetFirstTable(CompilationCacheTable::PutScript(
     202      168303 :       table, source, context, language_mode, function_info, literals));
     203      168303 : }
     204             : 
     205     5554379 : InfoVectorPair CompilationCacheEval::Lookup(
     206             :     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     207             :     Handle<Context> native_context, LanguageMode language_mode, int position) {
     208    11108758 :   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     5554379 :   Handle<CompilationCacheTable> table = GetTable(generation);
     216             :   result = table->LookupEval(source, outer_info, native_context, language_mode,
     217     5554379 :                              position);
     218     5554379 :   if (result.has_shared()) {
     219     4302212 :     isolate()->counters()->compilation_cache_hits()->Increment();
     220             :   } else {
     221     1252167 :     isolate()->counters()->compilation_cache_misses()->Increment();
     222             :   }
     223    11108758 :   return result;
     224             : }
     225             : 
     226     1817488 : 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     3634976 :   HandleScope scope(isolate());
     232     1817488 :   Handle<CompilationCacheTable> table = GetFirstTable();
     233             :   table =
     234             :       CompilationCacheTable::PutEval(table, source, outer_info, function_info,
     235     1817488 :                                      native_context, literals, position);
     236             :   SetFirstTable(table);
     237     1817488 : }
     238             : 
     239             : 
     240      712892 : MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
     241             :     Handle<String> source,
     242             :     JSRegExp::Flags flags) {
     243     2851826 :   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     2852084 :   for (generation = 0; generation < generations(); generation++) {
     250     1069562 :     Handle<CompilationCacheTable> table = GetTable(generation);
     251     1069562 :     result = table->LookupRegExp(source, flags);
     252     1069562 :     if (result->IsFixedArray()) break;
     253             :   }
     254      712892 :   if (result->IsFixedArray()) {
     255      356412 :     Handle<FixedArray> data = Handle<FixedArray>::cast(result);
     256      356412 :     if (generation != 0) {
     257         190 :       Put(source, flags, data);
     258             :     }
     259      356412 :     isolate()->counters()->compilation_cache_hits()->Increment();
     260      356412 :     return scope.CloseAndEscape(data);
     261             :   } else {
     262      356480 :     isolate()->counters()->compilation_cache_misses()->Increment();
     263             :     return MaybeHandle<FixedArray>();
     264             :   }
     265             : }
     266             : 
     267             : 
     268      353109 : void CompilationCacheRegExp::Put(Handle<String> source,
     269             :                                  JSRegExp::Flags flags,
     270             :                                  Handle<FixedArray> data) {
     271      706218 :   HandleScope scope(isolate());
     272      706218 :   Handle<CompilationCacheTable> table = GetFirstTable();
     273      353109 :   SetFirstTable(CompilationCacheTable::PutRegExp(table, source, flags, data));
     274      353109 : }
     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      343887 : 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      343887 :   if (!IsEnabled()) return empty_result;
     291             : 
     292             :   return script_.Lookup(source, name, line_offset, column_offset,
     293      310823 :                         resource_options, context, language_mode);
     294             : }
     295             : 
     296     5596561 : 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     5596561 :   if (!IsEnabled()) return result;
     301             : 
     302     5554379 :   if (context->IsNativeContext()) {
     303             :     result = eval_global_.Lookup(source, outer_info, context, language_mode,
     304     2093636 :                                  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     5554379 :   return result;
     313             : }
     314             : 
     315             : 
     316      719976 : MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
     317             :                                                        JSRegExp::Flags flags) {
     318      719976 :   if (!IsEnabled()) return MaybeHandle<FixedArray>();
     319             : 
     320      712892 :   return reg_exp_.Lookup(source, flags);
     321             : }
     322             : 
     323      200660 : void CompilationCache::PutScript(Handle<String> source, Handle<Context> context,
     324             :                                  LanguageMode language_mode,
     325             :                                  Handle<SharedFunctionInfo> function_info,
     326             :                                  Handle<Cell> literals) {
     327      401320 :   if (!IsEnabled()) return;
     328             : 
     329      168303 :   script_.Put(source, context, language_mode, function_info, literals);
     330             : }
     331             : 
     332     1859496 : void CompilationCache::PutEval(Handle<String> source,
     333             :                                Handle<SharedFunctionInfo> outer_info,
     334             :                                Handle<Context> context,
     335             :                                Handle<SharedFunctionInfo> function_info,
     336     2811181 :                                Handle<Cell> literals, int position) {
     337     3718992 :   if (!IsEnabled()) return;
     338             : 
     339             :   HandleScope scope(isolate());
     340     1817488 :   if (context->IsNativeContext()) {
     341             :     eval_global_.Put(source, outer_info, function_info, context, literals,
     342      823795 :                      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      993693 :                          literals, position);
     348             :   }
     349             : }
     350             : 
     351             : 
     352             : 
     353      360002 : void CompilationCache::PutRegExp(Handle<String> source,
     354             :                                  JSRegExp::Flags flags,
     355             :                                  Handle<FixedArray> data) {
     356      360002 :   if (!IsEnabled()) {
     357      360002 :     return;
     358             :   }
     359             : 
     360      352919 :   reg_exp_.Put(source, flags, data);
     361             : }
     362             : 
     363             : 
     364        7438 : void CompilationCache::Clear() {
     365     2705806 :   for (int i = 0; i < kSubCacheCount; i++) {
     366     2698368 :     subcaches_[i]->Clear();
     367             :   }
     368        7438 : }
     369             : 
     370      240983 : void CompilationCache::Iterate(RootVisitor* v) {
     371     1204915 :   for (int i = 0; i < kSubCacheCount; i++) {
     372      963932 :     subcaches_[i]->Iterate(v);
     373             :   }
     374      240983 : }
     375             : 
     376             : 
     377       53294 : void CompilationCache::IterateFunctions(ObjectVisitor* v) {
     378      266470 :   for (int i = 0; i < kSubCacheCount; i++) {
     379      213176 :     subcaches_[i]->IterateFunctions(v);
     380             :   }
     381       53294 : }
     382             : 
     383             : 
     384       54493 : void CompilationCache::MarkCompactPrologue() {
     385      272465 :   for (int i = 0; i < kSubCacheCount; i++) {
     386      217972 :     subcaches_[i]->Age();
     387             :   }
     388       54493 : }
     389             : 
     390             : 
     391        5237 : void CompilationCache::Enable() {
     392        5237 :   enabled_ = true;
     393        5237 : }
     394             : 
     395             : 
     396      667154 : void CompilationCache::Disable() {
     397      667154 :   enabled_ = false;
     398             :   Clear();
     399      667154 : }
     400             : 
     401             : 
     402             : }  // namespace internal
     403             : }  // namespace v8

Generated by: LCOV version 1.10