• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Copyright 2012 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  #ifndef V8_CODEGEN_COMPILATION_CACHE_H_
6  #define V8_CODEGEN_COMPILATION_CACHE_H_
7  
8  #include "src/base/hashmap.h"
9  #include "src/objects/compilation-cache-table.h"
10  #include "src/utils/allocation.h"
11  
12  namespace v8 {
13  namespace internal {
14  
15  template <typename T>
16  class Handle;
17  
18  class RootVisitor;
19  
20  // The compilation cache consists of several generational sub-caches which uses
21  // this class as a base class. A sub-cache contains a compilation cache tables
22  // for each generation of the sub-cache. Since the same source code string has
23  // different compiled code for scripts and evals, we use separate sub-caches
24  // for different compilation modes, to avoid retrieving the wrong result.
25  class CompilationSubCache {
26   public:
CompilationSubCache(Isolate * isolate,int generations)27    CompilationSubCache(Isolate* isolate, int generations)
28        : isolate_(isolate), generations_(generations) {
29      DCHECK_LE(generations, kMaxGenerations);
30    }
31  
32    static constexpr int kFirstGeneration = 0;
33    static constexpr int kMaxGenerations = 2;
34  
35    // Get the compilation cache tables for a specific generation.
36    Handle<CompilationCacheTable> GetTable(int generation);
37  
38    // Accessors for first generation.
GetFirstTable()39    Handle<CompilationCacheTable> GetFirstTable() {
40      return GetTable(kFirstGeneration);
41    }
SetFirstTable(Handle<CompilationCacheTable> value)42    void SetFirstTable(Handle<CompilationCacheTable> value) {
43      DCHECK_LT(kFirstGeneration, generations_);
44      tables_[kFirstGeneration] = *value;
45    }
46  
47    // Age the sub-cache by evicting the oldest generation and creating a new
48    // young generation.
49    virtual void Age() = 0;
50  
51    // GC support.
52    void Iterate(RootVisitor* v);
53  
54    // Clear this sub-cache evicting all its content.
55    void Clear();
56  
57    // Remove given shared function info from sub-cache.
58    void Remove(Handle<SharedFunctionInfo> function_info);
59  
60    // Number of generations in this sub-cache.
generations()61    int generations() const { return generations_; }
62  
63   protected:
isolate()64    Isolate* isolate() const { return isolate_; }
65  
66    // Ageing occurs either by removing the oldest generation, or with
67    // custom logic implemented in CompilationCacheTable::Age.
68    static void AgeByGeneration(CompilationSubCache* c);
69    static void AgeCustom(CompilationSubCache* c);
70  
71   private:
72    Isolate* const isolate_;
73    const int generations_;
74    Object tables_[kMaxGenerations];  // One for each generation.
75  
76    DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache);
77  };
78  
79  // Sub-cache for scripts.
80  class CompilationCacheScript : public CompilationSubCache {
81   public:
82    explicit CompilationCacheScript(Isolate* isolate);
83  
84    MaybeHandle<SharedFunctionInfo> Lookup(Handle<String> source,
85                                           MaybeHandle<Object> name,
86                                           int line_offset, int column_offset,
87                                           ScriptOriginOptions resource_options,
88                                           Handle<Context> native_context,
89                                           LanguageMode language_mode);
90  
91    void Put(Handle<String> source, Handle<Context> context,
92             LanguageMode language_mode,
93             Handle<SharedFunctionInfo> function_info);
94  
95    void Age() override;
96  
97   private:
98    bool HasOrigin(Handle<SharedFunctionInfo> function_info,
99                   MaybeHandle<Object> name, int line_offset, int column_offset,
100                   ScriptOriginOptions resource_options);
101  
102    DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript);
103  };
104  
105  // Sub-cache for eval scripts. Two caches for eval are used. One for eval calls
106  // in native contexts and one for eval calls in other contexts. The cache
107  // considers the following pieces of information when checking for matching
108  // entries:
109  // 1. The source string.
110  // 2. The shared function info of the calling function.
111  // 3. Whether the source should be compiled as strict code or as sloppy code.
112  //    Note: Currently there are clients of CompileEval that always compile
113  //    sloppy code even if the calling function is a strict mode function.
114  //    More specifically these are the CompileString, DebugEvaluate and
115  //    DebugEvaluateGlobal runtime functions.
116  // 4. The start position of the calling scope.
117  class CompilationCacheEval : public CompilationSubCache {
118   public:
CompilationCacheEval(Isolate * isolate)119    explicit CompilationCacheEval(Isolate* isolate)
120        : CompilationSubCache(isolate, 1) {}
121  
122    InfoCellPair Lookup(Handle<String> source,
123                        Handle<SharedFunctionInfo> outer_info,
124                        Handle<Context> native_context,
125                        LanguageMode language_mode, int position);
126  
127    void Put(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
128             Handle<SharedFunctionInfo> function_info,
129             Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
130             int position);
131  
132    void Age() override;
133  
134   private:
135    DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
136  };
137  
138  // Sub-cache for regular expressions.
139  class CompilationCacheRegExp : public CompilationSubCache {
140   public:
CompilationCacheRegExp(Isolate * isolate,int generations)141    CompilationCacheRegExp(Isolate* isolate, int generations)
142        : CompilationSubCache(isolate, generations) {}
143  
144    MaybeHandle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags);
145  
146    void Put(Handle<String> source, JSRegExp::Flags flags,
147             Handle<FixedArray> data);
148  
149    void Age() override;
150  
151   private:
152    DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp);
153  };
154  
155  // Sub-cache for Code objects. All code inserted into this cache must
156  // be usable across different native contexts.
157  class CompilationCacheCode : public CompilationSubCache {
158   public:
CompilationCacheCode(Isolate * isolate)159    explicit CompilationCacheCode(Isolate* isolate)
160        : CompilationSubCache(isolate, kGenerations) {}
161  
162    MaybeHandle<Code> Lookup(Handle<SharedFunctionInfo> key);
163    void Put(Handle<SharedFunctionInfo> key, Handle<Code> value);
164  
165    void Age() override;
166  
167    // TODO(jgruber,v8:8888): For simplicity we use the generational
168    // approach here, but could consider something else (or more
169    // generations) in the future.
170    static constexpr int kGenerations = 2;
171  
172    static void TraceAgeing();
173    static void TraceInsertion(Handle<SharedFunctionInfo> key,
174                               Handle<Code> value);
175    static void TraceHit(Handle<SharedFunctionInfo> key, Handle<Code> value);
176  
177   private:
178    DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheCode);
179  };
180  
181  // The compilation cache keeps shared function infos for compiled
182  // scripts and evals. The shared function infos are looked up using
183  // the source string as the key. For regular expressions the
184  // compilation data is cached.
185  class V8_EXPORT_PRIVATE CompilationCache {
186   public:
187    // Finds the script shared function info for a source
188    // string. Returns an empty handle if the cache doesn't contain a
189    // script for the given source string with the right origin.
190    MaybeHandle<SharedFunctionInfo> LookupScript(
191        Handle<String> source, MaybeHandle<Object> name, int line_offset,
192        int column_offset, ScriptOriginOptions resource_options,
193        Handle<Context> native_context, LanguageMode language_mode);
194  
195    // Finds the shared function info for a source string for eval in a
196    // given context.  Returns an empty handle if the cache doesn't
197    // contain a script for the given source string.
198    InfoCellPair LookupEval(Handle<String> source,
199                            Handle<SharedFunctionInfo> outer_info,
200                            Handle<Context> context, LanguageMode language_mode,
201                            int position);
202  
203    // Returns the regexp data associated with the given regexp if it
204    // is in cache, otherwise an empty handle.
205    MaybeHandle<FixedArray> LookupRegExp(Handle<String> source,
206                                         JSRegExp::Flags flags);
207  
208    MaybeHandle<Code> LookupCode(Handle<SharedFunctionInfo> sfi);
209  
210    // Associate the (source, kind) pair to the shared function
211    // info. This may overwrite an existing mapping.
212    void PutScript(Handle<String> source, Handle<Context> native_context,
213                   LanguageMode language_mode,
214                   Handle<SharedFunctionInfo> function_info);
215  
216    // Associate the (source, context->closure()->shared(), kind) triple
217    // with the shared function info. This may overwrite an existing mapping.
218    void PutEval(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
219                 Handle<Context> context,
220                 Handle<SharedFunctionInfo> function_info,
221                 Handle<FeedbackCell> feedback_cell, int position);
222  
223    // Associate the (source, flags) pair to the given regexp data.
224    // This may overwrite an existing mapping.
225    void PutRegExp(Handle<String> source, JSRegExp::Flags flags,
226                   Handle<FixedArray> data);
227  
228    void PutCode(Handle<SharedFunctionInfo> shared, Handle<Code> code);
229  
230    // Clear the cache - also used to initialize the cache at startup.
231    void Clear();
232  
233    // Remove given shared function info from all caches.
234    void Remove(Handle<SharedFunctionInfo> function_info);
235  
236    // GC support.
237    void Iterate(RootVisitor* v);
238  
239    // Notify the cache that a mark-sweep garbage collection is about to
240    // take place. This is used to retire entries from the cache to
241    // avoid keeping them alive too long without using them.
242    void MarkCompactPrologue();
243  
244    // Enable/disable compilation cache. Used by debugger to disable compilation
245    // cache during debugging so that eval and new scripts are always compiled.
246    // TODO(bmeurer, chromium:992277): The RegExp cache cannot be enabled and/or
247    // disabled, since it doesn't affect debugging. However ideally the other
248    // caches should also be always on, even in the presence of the debugger,
249    // but at this point there are too many unclear invariants, and so I decided
250    // to just fix the pressing performance problem for RegExp individually first.
251    void EnableScriptAndEval();
252    void DisableScriptAndEval();
253  
254   private:
255    explicit CompilationCache(Isolate* isolate);
256    ~CompilationCache() = default;
257  
258    base::HashMap* EagerOptimizingSet();
259  
IsEnabledScriptAndEval()260    bool IsEnabledScriptAndEval() const {
261      return FLAG_compilation_cache && enabled_script_and_eval_;
262    }
263  
isolate()264    Isolate* isolate() const { return isolate_; }
265  
266    Isolate* isolate_;
267  
268    CompilationCacheScript script_;
269    CompilationCacheEval eval_global_;
270    CompilationCacheEval eval_contextual_;
271    CompilationCacheRegExp reg_exp_;
272    CompilationCacheCode code_;
273  
274    static constexpr int kSubCacheCount = 5;
275    CompilationSubCache* subcaches_[kSubCacheCount];
276  
277    // Current enable state of the compilation cache for scripts and eval.
278    bool enabled_script_and_eval_;
279  
280    friend class Isolate;
281  
282    DISALLOW_COPY_AND_ASSIGN(CompilationCache);
283  };
284  
285  }  // namespace internal
286  }  // namespace v8
287  
288  #endif  // V8_CODEGEN_COMPILATION_CACHE_H_
289