13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/compilation-cache.h"
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/assembler.h"
8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/counters.h"
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/factory.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/objects-inl.h"
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The number of generations for each sub cache.
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kRegExpGenerations = 2;
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block// Initial size of each compilation cache table allocated.
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kInitialCacheSize = 64;
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2344f0eee88ff00398ff7f715fab053374d808c90dSteve BlockCompilationCache::CompilationCache(Isolate* isolate)
2444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
25958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      script_(isolate, 1),
26958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      eval_global_(isolate, 1),
27958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      eval_contextual_(isolate, 1),
2844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      reg_exp_(isolate, kRegExpGenerations),
293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      enabled_(true) {
3044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CompilationSubCache* subcaches[kSubCacheCount] =
3144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
3244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i = 0; i < kSubCacheCount; ++i) {
3344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    subcaches_[i] = subcaches[i];
346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
3544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
383fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochCompilationCache::~CompilationCache() {}
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(generation < generations_);
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<CompilationCacheTable> result;
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (tables_[generation]->IsUndefined()) {
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    result = CompilationCacheTable::New(isolate(), kInitialCacheSize);
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    tables_[generation] = *result;
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CompilationCacheTable* table =
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        CompilationCacheTable::cast(tables_[generation]);
5044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    result = Handle<CompilationCacheTable>(table, isolate());
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result;
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationSubCache::Age() {
57958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  // Don't directly age single-generation caches.
58958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if (generations_ == 1) {
59958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if (tables_[0] != isolate()->heap()->undefined_value()) {
60958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      CompilationCacheTable::cast(tables_[0])->Age();
61958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    }
62958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    return;
63958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  }
64958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Age the generations implicitly killing off the oldest.
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = generations_ - 1; i > 0; i--) {
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    tables_[i] = tables_[i - 1];
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set the first generation as unborn.
7144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  tables_[0] = isolate()->heap()->undefined_value();
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
75756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrickvoid CompilationSubCache::IterateFunctions(ObjectVisitor* v) {
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Object* undefined = isolate()->heap()->undefined_value();
77756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0; i < generations_; i++) {
78756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (tables_[i] != undefined) {
79756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v);
80756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    }
81756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
82756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
83756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
84756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationSubCache::Iterate(ObjectVisitor* v) {
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v->VisitPointers(&tables_[0], &tables_[generations_]);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationSubCache::Clear() {
9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  MemsetPointer(tables_, isolate()->heap()->undefined_value(), generations_);
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
95b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
96b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Probe the script generation tables. Make sure not to leak handles
97b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // into the caller's handle scope.
9844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  { HandleScope scope(isolate());
99b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    for (int generation = 0; generation < generations(); generation++) {
100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Handle<CompilationCacheTable> table = GetTable(generation);
101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      table->Remove(*function_info);
102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
10744f0eee88ff00398ff7f715fab053374d808c90dSteve BlockCompilationCacheScript::CompilationCacheScript(Isolate* isolate,
10844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                               int generations)
109958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    : CompilationSubCache(isolate, generations) {}
11044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
11144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We only re-use a cached function for some script source code if the
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// script originates from the same place. This is to avoid issues
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// when reporting errors, etc.
115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochbool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info,
116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       Handle<Object> name, int line_offset,
117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       int column_offset,
118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       ScriptOriginOptions resource_options) {
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Script> script =
12044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Handle<Script>(Script::cast(function_info->script()), isolate());
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the script name isn't set, the boilerplate script should have
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // an undefined name to have the same origin.
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (name.is_null()) {
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return script->name()->IsUndefined();
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do the fast bailout checks first.
127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (line_offset != script->line_offset()) return false;
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (column_offset != script->column_offset()) return false;
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that both names are strings. If not, no match.
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!name->IsString() || !script->name()->IsString()) return false;
131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Are the origin_options same?
132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (resource_options.Flags() != script->origin_options().Flags())
133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return false;
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compare the two name strings for equality.
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return String::Equals(Handle<String>::cast(name),
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        Handle<String>(String::cast(script->name())));
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// TODO(245): Need to allow identical code from different contexts to
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// be cached in the same script generation. Currently the first use
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// will be cached, but subsequent code from different source / line
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// won't.
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochHandle<SharedFunctionInfo> CompilationCacheScript::Lookup(
145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<String> source, Handle<Object> name, int line_offset,
146014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    int column_offset, ScriptOriginOptions resource_options,
147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Context> context, LanguageMode language_mode) {
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* result = NULL;
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int generation;
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the script generation tables. Make sure not to leak handles
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // into the caller's handle scope.
15344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  { HandleScope scope(isolate());
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (generation = 0; generation < generations(); generation++) {
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Handle<CompilationCacheTable> table = GetTable(generation);
156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<Object> probe = table->Lookup(source, context, language_mode);
1576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      if (probe->IsSharedFunctionInfo()) {
1586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        Handle<SharedFunctionInfo> function_info =
1596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block            Handle<SharedFunctionInfo>::cast(probe);
1606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        // Break when we've found a suitable shared function info that
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // matches the origin.
162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if (HasOrigin(function_info, name, line_offset, column_offset,
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                      resource_options)) {
1646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          result = *function_info;
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Once outside the manacles of the handle scope, we need to recheck
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to see if we actually found a cached script. If so, we return a
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // handle created in the caller's handle scope.
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result != NULL) {
17544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result),
17644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      isolate());
177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    DCHECK(
178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        HasOrigin(shared, name, line_offset, column_offset, resource_options));
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If the script was found in a later generation, we promote it to
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the first generation to let it survive longer in the cache.
181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (generation != 0) Put(source, context, language_mode, shared);
18244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_hits()->Increment();
1836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    return shared;
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
18544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_misses()->Increment();
1866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    return Handle<SharedFunctionInfo>::null();
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCacheScript::Put(Handle<String> source,
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                 Handle<Context> context,
193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                 LanguageMode language_mode,
1946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                 Handle<SharedFunctionInfo> function_info) {
19544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HandleScope scope(isolate());
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Handle<CompilationCacheTable> table = GetFirstTable();
197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  SetFirstTable(CompilationCacheTable::Put(table, source, context,
198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                           language_mode, function_info));
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup(
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<String> source, Handle<SharedFunctionInfo> outer_info,
204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    LanguageMode language_mode, int scope_position) {
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  HandleScope scope(isolate());
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure not to leak the table into the surrounding handle
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scope. Otherwise, we risk keeping old tables around even after
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // having cleared the cache.
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Handle<Object> result = isolate()->factory()->undefined_value();
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int generation;
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (generation = 0; generation < generations(); generation++) {
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<CompilationCacheTable> table = GetTable(generation);
213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    result =
214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        table->LookupEval(source, outer_info, language_mode, scope_position);
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (result->IsSharedFunctionInfo()) break;
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (result->IsSharedFunctionInfo()) {
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<SharedFunctionInfo> function_info =
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Handle<SharedFunctionInfo>::cast(result);
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (generation != 0) {
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      Put(source, outer_info, function_info, scope_position);
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
22344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_hits()->Increment();
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return scope.CloseAndEscape(function_info);
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
22644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_misses()->Increment();
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return MaybeHandle<SharedFunctionInfo>();
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCacheEval::Put(Handle<String> source,
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                               Handle<SharedFunctionInfo> outer_info,
2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                               Handle<SharedFunctionInfo> function_info,
2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                               int scope_position) {
23644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HandleScope scope(isolate());
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Handle<CompilationCacheTable> table = GetFirstTable();
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  table = CompilationCacheTable::PutEval(table, source, outer_info,
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                         function_info, scope_position);
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SetFirstTable(table);
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMaybeHandle<FixedArray> CompilationCacheRegExp::Lookup(
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<String> source,
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    JSRegExp::Flags flags) {
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  HandleScope scope(isolate());
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure not to leak the table into the surrounding handle
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scope. Otherwise, we risk keeping old tables around even after
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // having cleared the cache.
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Handle<Object> result = isolate()->factory()->undefined_value();
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int generation;
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (generation = 0; generation < generations(); generation++) {
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<CompilationCacheTable> table = GetTable(generation);
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    result = table->LookupRegExp(source, flags);
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (result->IsFixedArray()) break;
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result->IsFixedArray()) {
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<FixedArray> data = Handle<FixedArray>::cast(result);
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (generation != 0) {
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Put(source, flags, data);
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
26344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_hits()->Increment();
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return scope.CloseAndEscape(data);
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
26644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate()->counters()->compilation_cache_misses()->Increment();
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return MaybeHandle<FixedArray>();
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCacheRegExp::Put(Handle<String> source,
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 JSRegExp::Flags flags,
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Handle<FixedArray> data) {
27544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HandleScope scope(isolate());
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Handle<CompilationCacheTable> table = GetFirstTable();
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SetFirstTable(CompilationCacheTable::PutRegExp(table, source, flags, data));
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (!IsEnabled()) return;
283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
28444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  eval_global_.Remove(function_info);
28544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  eval_contextual_.Remove(function_info);
28644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  script_.Remove(function_info);
287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript(
291014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<String> source, Handle<Object> name, int line_offset,
292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    int column_offset, ScriptOriginOptions resource_options,
293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Context> context, LanguageMode language_mode) {
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>();
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return script_.Lookup(source, name, line_offset, column_offset,
297014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        resource_options, context, language_mode);
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMaybeHandle<SharedFunctionInfo> CompilationCache::LookupEval(
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<String> source, Handle<SharedFunctionInfo> outer_info,
303014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Context> context, LanguageMode language_mode, int scope_position) {
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>();
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  MaybeHandle<SharedFunctionInfo> result;
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (context->IsNativeContext()) {
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    result =
309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        eval_global_.Lookup(source, outer_info, language_mode, scope_position);
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(scope_position != RelocInfo::kNoPosition);
312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    result = eval_contextual_.Lookup(source, outer_info, language_mode,
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                     scope_position);
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result;
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                                       JSRegExp::Flags flags) {
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!IsEnabled()) return MaybeHandle<FixedArray>();
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
32344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return reg_exp_.Lookup(source, flags);
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::PutScript(Handle<String> source,
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                 Handle<Context> context,
329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                 LanguageMode language_mode,
3306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                 Handle<SharedFunctionInfo> function_info) {
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!IsEnabled()) return;
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  script_.Put(source, context, language_mode, function_info);
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::PutEval(Handle<String> source,
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                               Handle<SharedFunctionInfo> outer_info,
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               Handle<Context> context,
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                               Handle<SharedFunctionInfo> function_info,
3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                               int scope_position) {
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!IsEnabled()) return;
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
34444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HandleScope scope(isolate());
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (context->IsNativeContext()) {
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    eval_global_.Put(source, outer_info, function_info, scope_position);
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(scope_position != RelocInfo::kNoPosition);
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    eval_contextual_.Put(source, outer_info, function_info, scope_position);
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::PutRegExp(Handle<String> source,
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 JSRegExp::Flags flags,
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Handle<FixedArray> data) {
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!IsEnabled()) {
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  reg_exp_.Put(source, flags, data);
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::Clear() {
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kSubCacheCount; i++) {
36844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    subcaches_[i]->Clear();
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
37244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
373756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrickvoid CompilationCache::Iterate(ObjectVisitor* v) {
374756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0; i < kSubCacheCount; i++) {
37544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    subcaches_[i]->Iterate(v);
376756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
3777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
3787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
3797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
380756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrickvoid CompilationCache::IterateFunctions(ObjectVisitor* v) {
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kSubCacheCount; i++) {
38244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    subcaches_[i]->IterateFunctions(v);
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::MarkCompactPrologue() {
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kSubCacheCount; i++) {
38944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    subcaches_[i]->Age();
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::Enable() {
39544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  enabled_ = true;
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompilationCache::Disable() {
40044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  enabled_ = false;
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Clear();
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
406014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
407