V8 Project
compilation-cache.cc
Go to the documentation of this file.
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/v8.h"
6 
7 #include "src/assembler.h"
9 #include "src/serialize.h"
10 
11 namespace v8 {
12 namespace internal {
13 
14 
15 // The number of generations for each sub cache.
16 // The number of ScriptGenerations is carefully chosen based on histograms.
17 // See issue 458: http://code.google.com/p/v8/issues/detail?id=458
18 static const int kScriptGenerations = 5;
19 static const int kEvalGlobalGenerations = 2;
20 static const int kEvalContextualGenerations = 2;
21 static const int kRegExpGenerations = 2;
22 
23 // Initial size of each compilation cache table allocated.
24 static const int kInitialCacheSize = 64;
25 
26 
28  : isolate_(isolate),
29  script_(isolate, kScriptGenerations),
30  eval_global_(isolate, kEvalGlobalGenerations),
31  eval_contextual_(isolate, kEvalContextualGenerations),
32  reg_exp_(isolate, kRegExpGenerations),
33  enabled_(true) {
36  for (int i = 0; i < kSubCacheCount; ++i) {
37  subcaches_[i] = subcaches[i];
38  }
39 }
40 
41 
43 
44 
46  DCHECK(generation < generations_);
48  if (tables_[generation]->IsUndefined()) {
50  tables_[generation] = *result;
51  } else {
52  CompilationCacheTable* table =
53  CompilationCacheTable::cast(tables_[generation]);
54  result = Handle<CompilationCacheTable>(table, isolate());
55  }
56  return result;
57 }
58 
59 
61  // Age the generations implicitly killing off the oldest.
62  for (int i = generations_ - 1; i > 0; i--) {
63  tables_[i] = tables_[i - 1];
64  }
65 
66  // Set the first generation as unborn.
67  tables_[0] = isolate()->heap()->undefined_value();
68 }
69 
70 
72  Object* undefined = isolate()->heap()->undefined_value();
73  for (int i = 0; i < generations_; i++) {
74  if (tables_[i] != undefined) {
75  reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v);
76  }
77  }
78 }
79 
80 
82  v->VisitPointers(&tables_[0], &tables_[generations_]);
83 }
84 
85 
87  MemsetPointer(tables_, isolate()->heap()->undefined_value(), generations_);
88 }
89 
90 
92  // Probe the script generation tables. Make sure not to leak handles
93  // into the caller's handle scope.
94  { HandleScope scope(isolate());
95  for (int generation = 0; generation < generations(); generation++) {
96  Handle<CompilationCacheTable> table = GetTable(generation);
97  table->Remove(*function_info);
98  }
99  }
100 }
101 
102 
104  int generations)
105  : CompilationSubCache(isolate, generations),
106  script_histogram_(NULL),
107  script_histogram_initialized_(false) { }
108 
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.
114  Handle<SharedFunctionInfo> function_info,
116  int line_offset,
117  int column_offset,
118  bool is_shared_cross_origin) {
119  Handle<Script> script =
120  Handle<Script>(Script::cast(function_info->script()), isolate());
121  // If the script name isn't set, the boilerplate script should have
122  // an undefined name to have the same origin.
123  if (name.is_null()) {
124  return script->name()->IsUndefined();
125  }
126  // Do the fast bailout checks first.
127  if (line_offset != script->line_offset()->value()) return false;
128  if (column_offset != script->column_offset()->value()) return false;
129  // Check that both names are strings. If not, no match.
130  if (!name->IsString() || !script->name()->IsString()) return false;
131  // Were both scripts tagged by the embedder as being shared cross-origin?
132  if (is_shared_cross_origin != script->is_shared_cross_origin()) return false;
133  // Compare the two name strings for equality.
135  Handle<String>(String::cast(script->name())));
136 }
137 
138 
139 // TODO(245): Need to allow identical code from different contexts to
140 // be cached in the same script generation. Currently the first use
141 // will be cached, but subsequent code from different source / line
142 // won't.
144  Handle<String> source,
146  int line_offset,
147  int column_offset,
148  bool is_shared_cross_origin,
149  Handle<Context> context) {
150  Object* result = NULL;
151  int generation;
152 
153  // Probe the script generation tables. Make sure not to leak handles
154  // into the caller's handle scope.
155  { HandleScope scope(isolate());
156  for (generation = 0; generation < generations(); generation++) {
157  Handle<CompilationCacheTable> table = GetTable(generation);
158  Handle<Object> probe = table->Lookup(source, context);
159  if (probe->IsSharedFunctionInfo()) {
160  Handle<SharedFunctionInfo> function_info =
162  // Break when we've found a suitable shared function info that
163  // matches the origin.
164  if (HasOrigin(function_info,
165  name,
166  line_offset,
167  column_offset,
168  is_shared_cross_origin)) {
169  result = *function_info;
170  break;
171  }
172  }
173  }
174  }
175 
178  "V8.ScriptCache",
179  0,
181  kScriptGenerations + 1);
183  }
184 
185  if (script_histogram_ != NULL) {
186  // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss.
188  }
189 
190  // Once outside the manacles of the handle scope, we need to recheck
191  // to see if we actually found a cached script. If so, we return a
192  // handle created in the caller's handle scope.
193  if (result != NULL) {
194  Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result),
195  isolate());
196  DCHECK(HasOrigin(shared,
197  name,
198  line_offset,
199  column_offset,
200  is_shared_cross_origin));
201  // If the script was found in a later generation, we promote it to
202  // the first generation to let it survive longer in the cache.
203  if (generation != 0) Put(source, context, shared);
204  isolate()->counters()->compilation_cache_hits()->Increment();
205  return shared;
206  } else {
207  isolate()->counters()->compilation_cache_misses()->Increment();
209  }
210 }
211 
212 
214  Handle<Context> context,
215  Handle<SharedFunctionInfo> function_info) {
216  HandleScope scope(isolate());
219  CompilationCacheTable::Put(table, source, context, function_info));
220 }
221 
222 
224  Handle<String> source,
225  Handle<Context> context,
226  StrictMode strict_mode,
227  int scope_position) {
228  HandleScope scope(isolate());
229  // Make sure not to leak the table into the surrounding handle
230  // scope. Otherwise, we risk keeping old tables around even after
231  // having cleared the cache.
232  Handle<Object> result = isolate()->factory()->undefined_value();
233  int generation;
234  for (generation = 0; generation < generations(); generation++) {
235  Handle<CompilationCacheTable> table = GetTable(generation);
236  result = table->LookupEval(source, context, strict_mode, scope_position);
237  if (result->IsSharedFunctionInfo()) break;
238  }
239  if (result->IsSharedFunctionInfo()) {
240  Handle<SharedFunctionInfo> function_info =
242  if (generation != 0) {
243  Put(source, context, function_info, scope_position);
244  }
245  isolate()->counters()->compilation_cache_hits()->Increment();
246  return scope.CloseAndEscape(function_info);
247  } else {
248  isolate()->counters()->compilation_cache_misses()->Increment();
250  }
251 }
252 
253 
255  Handle<Context> context,
256  Handle<SharedFunctionInfo> function_info,
257  int scope_position) {
258  HandleScope scope(isolate());
260  table = CompilationCacheTable::PutEval(table, source, context,
261  function_info, scope_position);
262  SetFirstTable(table);
263 }
264 
265 
267  Handle<String> source,
269  HandleScope scope(isolate());
270  // Make sure not to leak the table into the surrounding handle
271  // scope. Otherwise, we risk keeping old tables around even after
272  // having cleared the cache.
273  Handle<Object> result = isolate()->factory()->undefined_value();
274  int generation;
275  for (generation = 0; generation < generations(); generation++) {
276  Handle<CompilationCacheTable> table = GetTable(generation);
277  result = table->LookupRegExp(source, flags);
278  if (result->IsFixedArray()) break;
279  }
280  if (result->IsFixedArray()) {
282  if (generation != 0) {
283  Put(source, flags, data);
284  }
285  isolate()->counters()->compilation_cache_hits()->Increment();
286  return scope.CloseAndEscape(data);
287  } else {
288  isolate()->counters()->compilation_cache_misses()->Increment();
289  return MaybeHandle<FixedArray>();
290  }
291 }
292 
293 
296  Handle<FixedArray> data) {
297  HandleScope scope(isolate());
300 }
301 
302 
304  if (!IsEnabled()) return;
305 
306  eval_global_.Remove(function_info);
307  eval_contextual_.Remove(function_info);
308  script_.Remove(function_info);
309 }
310 
311 
313  Handle<String> source,
315  int line_offset,
316  int column_offset,
317  bool is_shared_cross_origin,
318  Handle<Context> context) {
320 
321  return script_.Lookup(source, name, line_offset, column_offset,
322  is_shared_cross_origin, context);
323 }
324 
325 
327  Handle<String> source,
328  Handle<Context> context,
329  StrictMode strict_mode,
330  int scope_position) {
332 
334  if (context->IsNativeContext()) {
335  result = eval_global_.Lookup(
336  source, context, strict_mode, scope_position);
337  } else {
338  DCHECK(scope_position != RelocInfo::kNoPosition);
339  result = eval_contextual_.Lookup(
340  source, context, strict_mode, scope_position);
341  }
342  return result;
343 }
344 
345 
348  if (!IsEnabled()) return MaybeHandle<FixedArray>();
349 
350  return reg_exp_.Lookup(source, flags);
351 }
352 
353 
355  Handle<Context> context,
356  Handle<SharedFunctionInfo> function_info) {
357  if (!IsEnabled()) return;
358 
359  script_.Put(source, context, function_info);
360 }
361 
362 
364  Handle<Context> context,
365  Handle<SharedFunctionInfo> function_info,
366  int scope_position) {
367  if (!IsEnabled()) return;
368 
369  HandleScope scope(isolate());
370  if (context->IsNativeContext()) {
371  eval_global_.Put(source, context, function_info, scope_position);
372  } else {
373  DCHECK(scope_position != RelocInfo::kNoPosition);
374  eval_contextual_.Put(source, context, function_info, scope_position);
375  }
376 }
377 
378 
379 
382  Handle<FixedArray> data) {
383  if (!IsEnabled()) {
384  return;
385  }
386 
387  reg_exp_.Put(source, flags, data);
388 }
389 
390 
392  for (int i = 0; i < kSubCacheCount; i++) {
393  subcaches_[i]->Clear();
394  }
395 }
396 
397 
399  for (int i = 0; i < kSubCacheCount; i++) {
400  subcaches_[i]->Iterate(v);
401  }
402 }
403 
404 
406  for (int i = 0; i < kSubCacheCount; i++) {
408  }
409 }
410 
411 
413  for (int i = 0; i < kSubCacheCount; i++) {
414  subcaches_[i]->Age();
415  }
416 }
417 
418 
420  enabled_ = true;
421 }
422 
423 
425  enabled_ = false;
426  Clear();
427 }
428 
429 
430 } } // namespace v8::internal
void Put(Handle< String > source, Handle< Context > context, Handle< SharedFunctionInfo > function_info, int scope_position)
MaybeHandle< SharedFunctionInfo > Lookup(Handle< String > source, Handle< Context > context, StrictMode strict_mode, int scope_position)
MaybeHandle< FixedArray > Lookup(Handle< String > source, JSRegExp::Flags flags)
void Put(Handle< String > source, JSRegExp::Flags flags, Handle< FixedArray > data)
Handle< SharedFunctionInfo > Lookup(Handle< String > source, Handle< Object > name, int line_offset, int column_offset, bool is_shared_cross_origin, Handle< Context > context)
void Put(Handle< String > source, Handle< Context > context, Handle< SharedFunctionInfo > function_info)
CompilationCacheScript(Isolate *isolate, int generations)
bool HasOrigin(Handle< SharedFunctionInfo > function_info, Handle< Object > name, int line_offset, int column_offset, bool is_shared_cross_origin)
static Handle< CompilationCacheTable > PutRegExp(Handle< CompilationCacheTable > cache, Handle< String > src, JSRegExp::Flags flags, Handle< FixedArray > value)
Definition: objects.cc:14811
static Handle< CompilationCacheTable > PutEval(Handle< CompilationCacheTable > cache, Handle< String > src, Handle< Context > context, Handle< SharedFunctionInfo > value, int scope_position)
Definition: objects.cc:14794
static Handle< CompilationCacheTable > Put(Handle< CompilationCacheTable > cache, Handle< String > src, Handle< Context > context, Handle< Object > value)
Definition: objects.cc:14777
void Iterate(ObjectVisitor *v)
CompilationCacheRegExp reg_exp_
void IterateFunctions(ObjectVisitor *v)
MaybeHandle< FixedArray > LookupRegExp(Handle< String > source, JSRegExp::Flags flags)
void PutEval(Handle< String > source, Handle< Context > context, Handle< SharedFunctionInfo > function_info, int scope_position)
MaybeHandle< SharedFunctionInfo > LookupScript(Handle< String > source, Handle< Object > name, int line_offset, int column_offset, bool is_shared_cross_origin, Handle< Context > context)
CompilationCacheEval eval_contextual_
MaybeHandle< SharedFunctionInfo > LookupEval(Handle< String > source, Handle< Context > context, StrictMode strict_mode, int scope_position)
void PutScript(Handle< String > source, Handle< Context > context, Handle< SharedFunctionInfo > function_info)
CompilationCacheScript script_
void Remove(Handle< SharedFunctionInfo > function_info)
void PutRegExp(Handle< String > source, JSRegExp::Flags flags, Handle< FixedArray > data)
CompilationSubCache * subcaches_[kSubCacheCount]
CompilationCacheEval eval_global_
Handle< CompilationCacheTable > GetTable(int generation)
void Remove(Handle< SharedFunctionInfo > function_info)
void IterateFunctions(ObjectVisitor *v)
Handle< CompilationCacheTable > GetFirstTable()
void SetFirstTable(Handle< CompilationCacheTable > value)
Handle< T > CloseAndEscape(Handle< T > handle_value)
Definition: handles-inl.h:119
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static Handle< T > null()
Definition: handles.h:123
static MUST_USE_RESULT Handle< CompilationCacheTable > New(Isolate *isolate, int at_least_space_for, MinimumCapacity capacity_option=USE_DEFAULT_MINIMUM_CAPACITY, PretenureFlag pretenure=NOT_TENURED)
Definition: objects.cc:13756
Counters * counters()
Definition: isolate.h:857
StatsTable * stats_table()
Definition: isolate.cc:2039
Factory * factory()
Definition: isolate.h:982
static const int kNoPosition
Definition: assembler.h:317
void * CreateHistogram(const char *name, int min, int max, size_t buckets)
Definition: counters.h:61
void AddHistogramSample(void *histogram, int sample)
Definition: counters.h:71
bool Equals(String *other)
Definition: objects-inl.h:3336
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
static bool IterateElements(Isolate *isolate, Handle< JSArray > receiver, ArrayConcatVisitor *visitor)
A helper function that visits elements of a JSArray in numerical order.
Definition: runtime.cc:4946
static const int kEvalContextualGenerations
void MemsetPointer(T **dest, U *value, int counter)
Definition: utils.h:1183
static const int kRegExpGenerations
static const int kScriptGenerations
static const int kInitialCacheSize
static const int kEvalGlobalGenerations
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20