1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_COMPILATION_CACHE_H_ 29 #define V8_COMPILATION_CACHE_H_ 30 31 namespace v8 { 32 namespace internal { 33 34 // The compilation cache consists of several generational sub-caches which uses 35 // this class as a base class. A sub-cache contains a compilation cache tables 36 // for each generation of the sub-cache. Since the same source code string has 37 // different compiled code for scripts and evals, we use separate sub-caches 38 // for different compilation modes, to avoid retrieving the wrong result. 39 class CompilationSubCache { 40 public: 41 CompilationSubCache(Isolate* isolate, int generations) 42 : isolate_(isolate), 43 generations_(generations) { 44 tables_ = NewArray<Object*>(generations); 45 } 46 47 ~CompilationSubCache() { DeleteArray(tables_); } 48 49 // Index for the first generation in the cache. 50 static const int kFirstGeneration = 0; 51 52 // Get the compilation cache tables for a specific generation. 53 Handle<CompilationCacheTable> GetTable(int generation); 54 55 // Accessors for first generation. 56 Handle<CompilationCacheTable> GetFirstTable() { 57 return GetTable(kFirstGeneration); 58 } 59 void SetFirstTable(Handle<CompilationCacheTable> value) { 60 ASSERT(kFirstGeneration < generations_); 61 tables_[kFirstGeneration] = *value; 62 } 63 64 // Age the sub-cache by evicting the oldest generation and creating a new 65 // young generation. 66 void Age(); 67 68 // GC support. 69 void Iterate(ObjectVisitor* v); 70 void IterateFunctions(ObjectVisitor* v); 71 72 // Clear this sub-cache evicting all its content. 73 void Clear(); 74 75 // Remove given shared function info from sub-cache. 76 void Remove(Handle<SharedFunctionInfo> function_info); 77 78 // Number of generations in this sub-cache. 79 inline int generations() { return generations_; } 80 81 protected: 82 Isolate* isolate() { return isolate_; } 83 84 private: 85 Isolate* isolate_; 86 int generations_; // Number of generations. 87 Object** tables_; // Compilation cache tables - one for each generation. 88 89 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache); 90 }; 91 92 93 // Sub-cache for scripts. 94 class CompilationCacheScript : public CompilationSubCache { 95 public: 96 CompilationCacheScript(Isolate* isolate, int generations); 97 98 Handle<SharedFunctionInfo> Lookup(Handle<String> source, 99 Handle<Object> name, 100 int line_offset, 101 int column_offset, 102 bool is_shared_cross_origin, 103 Handle<Context> context); 104 void Put(Handle<String> source, 105 Handle<Context> context, 106 Handle<SharedFunctionInfo> function_info); 107 108 private: 109 MUST_USE_RESULT MaybeObject* TryTablePut( 110 Handle<String> source, 111 Handle<Context> context, 112 Handle<SharedFunctionInfo> function_info); 113 114 // Note: Returns a new hash table if operation results in expansion. 115 Handle<CompilationCacheTable> TablePut( 116 Handle<String> source, 117 Handle<Context> context, 118 Handle<SharedFunctionInfo> function_info); 119 120 bool HasOrigin(Handle<SharedFunctionInfo> function_info, 121 Handle<Object> name, 122 int line_offset, 123 int column_offset, 124 bool is_shared_cross_origin); 125 126 void* script_histogram_; 127 bool script_histogram_initialized_; 128 129 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript); 130 }; 131 132 133 // Sub-cache for eval scripts. Two caches for eval are used. One for eval calls 134 // in native contexts and one for eval calls in other contexts. The cache 135 // considers the following pieces of information when checking for matching 136 // entries: 137 // 1. The source string. 138 // 2. The shared function info of the calling function. 139 // 3. Whether the source should be compiled as strict code or as non-strict 140 // code. 141 // Note: Currently there are clients of CompileEval that always compile 142 // non-strict code even if the calling function is a strict mode function. 143 // More specifically these are the CompileString, DebugEvaluate and 144 // DebugEvaluateGlobal runtime functions. 145 // 4. The start position of the calling scope. 146 class CompilationCacheEval: public CompilationSubCache { 147 public: 148 CompilationCacheEval(Isolate* isolate, int generations) 149 : CompilationSubCache(isolate, generations) { } 150 151 Handle<SharedFunctionInfo> Lookup(Handle<String> source, 152 Handle<Context> context, 153 LanguageMode language_mode, 154 int scope_position); 155 156 void Put(Handle<String> source, 157 Handle<Context> context, 158 Handle<SharedFunctionInfo> function_info, 159 int scope_position); 160 161 private: 162 MUST_USE_RESULT MaybeObject* TryTablePut( 163 Handle<String> source, 164 Handle<Context> context, 165 Handle<SharedFunctionInfo> function_info, 166 int scope_position); 167 168 // Note: Returns a new hash table if operation results in expansion. 169 Handle<CompilationCacheTable> TablePut( 170 Handle<String> source, 171 Handle<Context> context, 172 Handle<SharedFunctionInfo> function_info, 173 int scope_position); 174 175 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval); 176 }; 177 178 179 // Sub-cache for regular expressions. 180 class CompilationCacheRegExp: public CompilationSubCache { 181 public: 182 CompilationCacheRegExp(Isolate* isolate, int generations) 183 : CompilationSubCache(isolate, generations) { } 184 185 Handle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags); 186 187 void Put(Handle<String> source, 188 JSRegExp::Flags flags, 189 Handle<FixedArray> data); 190 private: 191 MUST_USE_RESULT MaybeObject* TryTablePut(Handle<String> source, 192 JSRegExp::Flags flags, 193 Handle<FixedArray> data); 194 195 // Note: Returns a new hash table if operation results in expansion. 196 Handle<CompilationCacheTable> TablePut(Handle<String> source, 197 JSRegExp::Flags flags, 198 Handle<FixedArray> data); 199 200 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp); 201 }; 202 203 204 // The compilation cache keeps shared function infos for compiled 205 // scripts and evals. The shared function infos are looked up using 206 // the source string as the key. For regular expressions the 207 // compilation data is cached. 208 class CompilationCache { 209 public: 210 // Finds the script shared function info for a source 211 // string. Returns an empty handle if the cache doesn't contain a 212 // script for the given source string with the right origin. 213 Handle<SharedFunctionInfo> LookupScript(Handle<String> source, 214 Handle<Object> name, 215 int line_offset, 216 int column_offset, 217 bool is_shared_cross_origin, 218 Handle<Context> context); 219 220 // Finds the shared function info for a source string for eval in a 221 // given context. Returns an empty handle if the cache doesn't 222 // contain a script for the given source string. 223 Handle<SharedFunctionInfo> LookupEval(Handle<String> source, 224 Handle<Context> context, 225 bool is_global, 226 LanguageMode language_mode, 227 int scope_position); 228 229 // Returns the regexp data associated with the given regexp if it 230 // is in cache, otherwise an empty handle. 231 Handle<FixedArray> LookupRegExp(Handle<String> source, 232 JSRegExp::Flags flags); 233 234 // Associate the (source, kind) pair to the shared function 235 // info. This may overwrite an existing mapping. 236 void PutScript(Handle<String> source, 237 Handle<Context> context, 238 Handle<SharedFunctionInfo> function_info); 239 240 // Associate the (source, context->closure()->shared(), kind) triple 241 // with the shared function info. This may overwrite an existing mapping. 242 void PutEval(Handle<String> source, 243 Handle<Context> context, 244 bool is_global, 245 Handle<SharedFunctionInfo> function_info, 246 int scope_position); 247 248 // Associate the (source, flags) pair to the given regexp data. 249 // This may overwrite an existing mapping. 250 void PutRegExp(Handle<String> source, 251 JSRegExp::Flags flags, 252 Handle<FixedArray> data); 253 254 // Clear the cache - also used to initialize the cache at startup. 255 void Clear(); 256 257 // Remove given shared function info from all caches. 258 void Remove(Handle<SharedFunctionInfo> function_info); 259 260 // GC support. 261 void Iterate(ObjectVisitor* v); 262 void IterateFunctions(ObjectVisitor* v); 263 264 // Notify the cache that a mark-sweep garbage collection is about to 265 // take place. This is used to retire entries from the cache to 266 // avoid keeping them alive too long without using them. 267 void MarkCompactPrologue(); 268 269 // Enable/disable compilation cache. Used by debugger to disable compilation 270 // cache during debugging to make sure new scripts are always compiled. 271 void Enable(); 272 void Disable(); 273 274 private: 275 explicit CompilationCache(Isolate* isolate); 276 ~CompilationCache(); 277 278 HashMap* EagerOptimizingSet(); 279 280 // The number of sub caches covering the different types to cache. 281 static const int kSubCacheCount = 4; 282 283 bool IsEnabled() { return FLAG_compilation_cache && enabled_; } 284 285 Isolate* isolate() { return isolate_; } 286 287 Isolate* isolate_; 288 289 CompilationCacheScript script_; 290 CompilationCacheEval eval_global_; 291 CompilationCacheEval eval_contextual_; 292 CompilationCacheRegExp reg_exp_; 293 CompilationSubCache* subcaches_[kSubCacheCount]; 294 295 // Current enable state of the compilation cache. 296 bool enabled_; 297 298 friend class Isolate; 299 300 DISALLOW_COPY_AND_ASSIGN(CompilationCache); 301 }; 302 303 304 } } // namespace v8::internal 305 306 #endif // V8_COMPILATION_CACHE_H_ 307