| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compilation-cache.h" | 5 #include "src/compilation-cache.h" |
| 6 | 6 |
| 7 #include "src/counters.h" | 7 #include "src/counters.h" |
| 8 #include "src/factory.h" | 8 #include "src/factory.h" |
| 9 #include "src/globals.h" | 9 #include "src/globals.h" |
| 10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 | 15 |
| 16 // The number of generations for each sub cache. | 16 // The number of generations for each sub cache. |
| 17 static const int kRegExpGenerations = 2; | 17 static const int kRegExpGenerations = 2; |
| 18 | 18 |
| 19 // Initial size of each compilation cache table allocated. | 19 // Initial size of each compilation cache table allocated. |
| 20 static const int kInitialCacheSize = 64; | 20 static const int kInitialCacheSize = 64; |
| 21 | 21 |
| 22 | |
| 23 CompilationCache::CompilationCache(Isolate* isolate) | 22 CompilationCache::CompilationCache(Isolate* isolate) |
| 24 : isolate_(isolate), | 23 : isolate_(isolate), |
| 25 script_(isolate, 1), | 24 script_(isolate), |
| 26 eval_global_(isolate, 1), | 25 eval_global_(isolate), |
| 27 eval_contextual_(isolate, 1), | 26 eval_contextual_(isolate), |
| 28 reg_exp_(isolate, kRegExpGenerations), | 27 reg_exp_(isolate, kRegExpGenerations), |
| 29 enabled_(true) { | 28 enabled_(true) { |
| 30 CompilationSubCache* subcaches[kSubCacheCount] = | 29 CompilationSubCache* subcaches[kSubCacheCount] = |
| 31 {&script_, &eval_global_, &eval_contextual_, ®_exp_}; | 30 {&script_, &eval_global_, &eval_contextual_, ®_exp_}; |
| 32 for (int i = 0; i < kSubCacheCount; ++i) { | 31 for (int i = 0; i < kSubCacheCount; ++i) { |
| 33 subcaches_[i] = subcaches[i]; | 32 subcaches_[i] = subcaches[i]; |
| 34 } | 33 } |
| 35 } | 34 } |
| 36 | 35 |
| 37 | 36 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 // Probe the script generation tables. Make sure not to leak handles | 95 // Probe the script generation tables. Make sure not to leak handles |
| 97 // into the caller's handle scope. | 96 // into the caller's handle scope. |
| 98 { HandleScope scope(isolate()); | 97 { HandleScope scope(isolate()); |
| 99 for (int generation = 0; generation < generations(); generation++) { | 98 for (int generation = 0; generation < generations(); generation++) { |
| 100 Handle<CompilationCacheTable> table = GetTable(generation); | 99 Handle<CompilationCacheTable> table = GetTable(generation); |
| 101 table->Remove(*function_info); | 100 table->Remove(*function_info); |
| 102 } | 101 } |
| 103 } | 102 } |
| 104 } | 103 } |
| 105 | 104 |
| 106 | 105 CompilationCacheScript::CompilationCacheScript(Isolate* isolate) |
| 107 CompilationCacheScript::CompilationCacheScript(Isolate* isolate, | 106 : CompilationSubCache(isolate, 1) {} |
| 108 int generations) | |
| 109 : CompilationSubCache(isolate, generations) {} | |
| 110 | |
| 111 | 107 |
| 112 // We only re-use a cached function for some script source code if the | 108 // We only re-use a cached function for some script source code if the |
| 113 // script originates from the same place. This is to avoid issues | 109 // script originates from the same place. This is to avoid issues |
| 114 // when reporting errors, etc. | 110 // when reporting errors, etc. |
| 115 bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info, | 111 bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info, |
| 116 Handle<Object> name, int line_offset, | 112 Handle<Object> name, int line_offset, |
| 117 int column_offset, | 113 int column_offset, |
| 118 ScriptOriginOptions resource_options) { | 114 ScriptOriginOptions resource_options) { |
| 119 Handle<Script> script = | 115 Handle<Script> script = |
| 120 Handle<Script>(Script::cast(function_info->script()), isolate()); | 116 Handle<Script>(Script::cast(function_info->script()), isolate()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 134 // Compare the two name strings for equality. | 130 // Compare the two name strings for equality. |
| 135 return String::Equals(Handle<String>::cast(name), | 131 return String::Equals(Handle<String>::cast(name), |
| 136 Handle<String>(String::cast(script->name()))); | 132 Handle<String>(String::cast(script->name()))); |
| 137 } | 133 } |
| 138 | 134 |
| 139 | 135 |
| 140 // TODO(245): Need to allow identical code from different contexts to | 136 // TODO(245): Need to allow identical code from different contexts to |
| 141 // be cached in the same script generation. Currently the first use | 137 // be cached in the same script generation. Currently the first use |
| 142 // will be cached, but subsequent code from different source / line | 138 // will be cached, but subsequent code from different source / line |
| 143 // won't. | 139 // won't. |
| 144 Handle<SharedFunctionInfo> CompilationCacheScript::Lookup( | 140 InfoVectorPair CompilationCacheScript::Lookup( |
| 145 Handle<String> source, Handle<Object> name, int line_offset, | 141 Handle<String> source, Handle<Object> name, int line_offset, |
| 146 int column_offset, ScriptOriginOptions resource_options, | 142 int column_offset, ScriptOriginOptions resource_options, |
| 147 Handle<Context> context, LanguageMode language_mode) { | 143 Handle<Context> context, LanguageMode language_mode) { |
| 148 Object* result = NULL; | 144 InfoVectorPair result; |
| 149 int generation; | |
| 150 | 145 |
| 151 // Probe the script generation tables. Make sure not to leak handles | 146 // Probe the script generation tables. Make sure not to leak handles |
| 152 // into the caller's handle scope. | 147 // into the caller's handle scope. |
| 153 { HandleScope scope(isolate()); | 148 { HandleScope scope(isolate()); |
| 154 for (generation = 0; generation < generations(); generation++) { | 149 const int generation = 0; |
| 155 Handle<CompilationCacheTable> table = GetTable(generation); | 150 DCHECK(generations() == 1); |
| 156 Handle<Object> probe = table->Lookup(source, context, language_mode); | 151 Handle<CompilationCacheTable> table = GetTable(generation); |
| 157 if (probe->IsSharedFunctionInfo()) { | 152 InfoVectorPair probe = table->LookupScript(source, context, language_mode); |
| 158 Handle<SharedFunctionInfo> function_info = | 153 if (probe.has_shared()) { |
| 159 Handle<SharedFunctionInfo>::cast(probe); | 154 Handle<SharedFunctionInfo> function_info(probe.shared(), isolate()); |
| 160 // Break when we've found a suitable shared function info that | 155 Handle<Cell> vector_handle; |
| 161 // matches the origin. | 156 if (probe.has_vector()) { |
| 162 if (HasOrigin(function_info, name, line_offset, column_offset, | 157 vector_handle = Handle<Cell>(probe.vector(), isolate()); |
| 163 resource_options)) { | 158 } |
| 164 result = *function_info; | 159 // Break when we've found a suitable shared function info that |
| 165 break; | 160 // matches the origin. |
| 166 } | 161 if (HasOrigin(function_info, name, line_offset, column_offset, |
| 162 resource_options)) { |
| 163 result = InfoVectorPair(*function_info, |
| 164 probe.has_vector() ? *vector_handle : nullptr); |
| 167 } | 165 } |
| 168 } | 166 } |
| 169 } | 167 } |
| 170 | 168 |
| 171 // Once outside the manacles of the handle scope, we need to recheck | 169 // 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 | 170 // to see if we actually found a cached script. If so, we return a |
| 173 // handle created in the caller's handle scope. | 171 // handle created in the caller's handle scope. |
| 174 if (result != NULL) { | 172 if (result.has_shared()) { |
| 175 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result), | 173 Handle<SharedFunctionInfo> shared(result.shared(), isolate()); |
| 176 isolate()); | 174 // TODO(mvstanton): Make sure HasOrigin can't allocate, or it will |
| 175 // mess up our InfoVectorPair. |
| 177 DCHECK( | 176 DCHECK( |
| 178 HasOrigin(shared, name, line_offset, column_offset, resource_options)); | 177 HasOrigin(shared, name, line_offset, column_offset, resource_options)); |
| 179 // If the script was found in a later generation, we promote it to | |
| 180 // the first generation to let it survive longer in the cache. | |
| 181 if (generation != 0) Put(source, context, language_mode, shared); | |
| 182 isolate()->counters()->compilation_cache_hits()->Increment(); | 178 isolate()->counters()->compilation_cache_hits()->Increment(); |
| 183 return shared; | |
| 184 } else { | 179 } else { |
| 185 isolate()->counters()->compilation_cache_misses()->Increment(); | 180 isolate()->counters()->compilation_cache_misses()->Increment(); |
| 186 return Handle<SharedFunctionInfo>::null(); | |
| 187 } | 181 } |
| 182 return result; |
| 188 } | 183 } |
| 189 | 184 |
| 190 | 185 void CompilationCacheScript::Put(Handle<String> source, Handle<Context> context, |
| 191 void CompilationCacheScript::Put(Handle<String> source, | |
| 192 Handle<Context> context, | |
| 193 LanguageMode language_mode, | 186 LanguageMode language_mode, |
| 194 Handle<SharedFunctionInfo> function_info) { | 187 Handle<SharedFunctionInfo> function_info, |
| 188 Handle<Cell> literals) { |
| 195 HandleScope scope(isolate()); | 189 HandleScope scope(isolate()); |
| 196 Handle<CompilationCacheTable> table = GetFirstTable(); | 190 Handle<CompilationCacheTable> table = GetFirstTable(); |
| 197 SetFirstTable(CompilationCacheTable::Put(table, source, context, | 191 SetFirstTable(CompilationCacheTable::PutScript( |
| 198 language_mode, function_info)); | 192 table, source, context, language_mode, function_info, literals)); |
| 199 } | 193 } |
| 200 | 194 |
| 201 | 195 InfoVectorPair CompilationCacheEval::Lookup( |
| 202 MaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup( | |
| 203 Handle<String> source, Handle<SharedFunctionInfo> outer_info, | 196 Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
| 204 LanguageMode language_mode, int scope_position) { | 197 Handle<Context> native_context, LanguageMode language_mode, |
| 198 int scope_position) { |
| 205 HandleScope scope(isolate()); | 199 HandleScope scope(isolate()); |
| 206 // Make sure not to leak the table into the surrounding handle | 200 // Make sure not to leak the table into the surrounding handle |
| 207 // scope. Otherwise, we risk keeping old tables around even after | 201 // scope. Otherwise, we risk keeping old tables around even after |
| 208 // having cleared the cache. | 202 // having cleared the cache. |
| 209 Handle<Object> result = isolate()->factory()->undefined_value(); | 203 InfoVectorPair result; |
| 210 int generation; | 204 const int generation = 0; |
| 211 for (generation = 0; generation < generations(); generation++) { | 205 DCHECK(generations() == 1); |
| 212 Handle<CompilationCacheTable> table = GetTable(generation); | 206 Handle<CompilationCacheTable> table = GetTable(generation); |
| 213 result = | 207 result = table->LookupEval(source, outer_info, native_context, language_mode, |
| 214 table->LookupEval(source, outer_info, language_mode, scope_position); | 208 scope_position); |
| 215 if (result->IsSharedFunctionInfo()) break; | 209 if (result.has_shared()) { |
| 216 } | |
| 217 if (result->IsSharedFunctionInfo()) { | |
| 218 Handle<SharedFunctionInfo> function_info = | |
| 219 Handle<SharedFunctionInfo>::cast(result); | |
| 220 if (generation != 0) { | |
| 221 Put(source, outer_info, function_info, scope_position); | |
| 222 } | |
| 223 isolate()->counters()->compilation_cache_hits()->Increment(); | 210 isolate()->counters()->compilation_cache_hits()->Increment(); |
| 224 return scope.CloseAndEscape(function_info); | |
| 225 } else { | 211 } else { |
| 226 isolate()->counters()->compilation_cache_misses()->Increment(); | 212 isolate()->counters()->compilation_cache_misses()->Increment(); |
| 227 return MaybeHandle<SharedFunctionInfo>(); | |
| 228 } | 213 } |
| 214 return result; |
| 229 } | 215 } |
| 230 | 216 |
| 231 | |
| 232 void CompilationCacheEval::Put(Handle<String> source, | 217 void CompilationCacheEval::Put(Handle<String> source, |
| 233 Handle<SharedFunctionInfo> outer_info, | 218 Handle<SharedFunctionInfo> outer_info, |
| 234 Handle<SharedFunctionInfo> function_info, | 219 Handle<SharedFunctionInfo> function_info, |
| 235 int scope_position) { | 220 Handle<Context> native_context, |
| 221 Handle<Cell> literals, int scope_position) { |
| 236 HandleScope scope(isolate()); | 222 HandleScope scope(isolate()); |
| 237 Handle<CompilationCacheTable> table = GetFirstTable(); | 223 Handle<CompilationCacheTable> table = GetFirstTable(); |
| 238 table = CompilationCacheTable::PutEval(table, source, outer_info, | 224 table = |
| 239 function_info, scope_position); | 225 CompilationCacheTable::PutEval(table, source, outer_info, function_info, |
| 226 native_context, literals, scope_position); |
| 240 SetFirstTable(table); | 227 SetFirstTable(table); |
| 241 } | 228 } |
| 242 | 229 |
| 243 | 230 |
| 244 MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup( | 231 MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup( |
| 245 Handle<String> source, | 232 Handle<String> source, |
| 246 JSRegExp::Flags flags) { | 233 JSRegExp::Flags flags) { |
| 247 HandleScope scope(isolate()); | 234 HandleScope scope(isolate()); |
| 248 // Make sure not to leak the table into the surrounding handle | 235 // Make sure not to leak the table into the surrounding handle |
| 249 // scope. Otherwise, we risk keeping old tables around even after | 236 // scope. Otherwise, we risk keeping old tables around even after |
| (...skipping 29 matching lines...) Expand all Loading... |
| 279 | 266 |
| 280 | 267 |
| 281 void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) { | 268 void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) { |
| 282 if (!IsEnabled()) return; | 269 if (!IsEnabled()) return; |
| 283 | 270 |
| 284 eval_global_.Remove(function_info); | 271 eval_global_.Remove(function_info); |
| 285 eval_contextual_.Remove(function_info); | 272 eval_contextual_.Remove(function_info); |
| 286 script_.Remove(function_info); | 273 script_.Remove(function_info); |
| 287 } | 274 } |
| 288 | 275 |
| 289 | 276 InfoVectorPair CompilationCache::LookupScript( |
| 290 MaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript( | |
| 291 Handle<String> source, Handle<Object> name, int line_offset, | 277 Handle<String> source, Handle<Object> name, int line_offset, |
| 292 int column_offset, ScriptOriginOptions resource_options, | 278 int column_offset, ScriptOriginOptions resource_options, |
| 293 Handle<Context> context, LanguageMode language_mode) { | 279 Handle<Context> context, LanguageMode language_mode) { |
| 294 if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>(); | 280 InfoVectorPair empty_result; |
| 281 if (!IsEnabled()) return empty_result; |
| 295 | 282 |
| 296 return script_.Lookup(source, name, line_offset, column_offset, | 283 return script_.Lookup(source, name, line_offset, column_offset, |
| 297 resource_options, context, language_mode); | 284 resource_options, context, language_mode); |
| 298 } | 285 } |
| 299 | 286 |
| 300 | 287 InfoVectorPair CompilationCache::LookupEval( |
| 301 MaybeHandle<SharedFunctionInfo> CompilationCache::LookupEval( | |
| 302 Handle<String> source, Handle<SharedFunctionInfo> outer_info, | 288 Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
| 303 Handle<Context> context, LanguageMode language_mode, int scope_position) { | 289 Handle<Context> context, LanguageMode language_mode, int scope_position) { |
| 304 if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>(); | 290 InfoVectorPair result; |
| 291 if (!IsEnabled()) return result; |
| 305 | 292 |
| 306 MaybeHandle<SharedFunctionInfo> result; | |
| 307 if (context->IsNativeContext()) { | 293 if (context->IsNativeContext()) { |
| 308 result = | 294 result = eval_global_.Lookup(source, outer_info, context, language_mode, |
| 309 eval_global_.Lookup(source, outer_info, language_mode, scope_position); | 295 scope_position); |
| 310 } else { | 296 } else { |
| 311 DCHECK(scope_position != kNoSourcePosition); | 297 DCHECK(scope_position != kNoSourcePosition); |
| 312 result = eval_contextual_.Lookup(source, outer_info, language_mode, | 298 Handle<Context> native_context(context->native_context(), isolate()); |
| 313 scope_position); | 299 result = eval_contextual_.Lookup(source, outer_info, native_context, |
| 300 language_mode, scope_position); |
| 314 } | 301 } |
| 302 |
| 315 return result; | 303 return result; |
| 316 } | 304 } |
| 317 | 305 |
| 318 | 306 |
| 319 MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, | 307 MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, |
| 320 JSRegExp::Flags flags) { | 308 JSRegExp::Flags flags) { |
| 321 if (!IsEnabled()) return MaybeHandle<FixedArray>(); | 309 if (!IsEnabled()) return MaybeHandle<FixedArray>(); |
| 322 | 310 |
| 323 return reg_exp_.Lookup(source, flags); | 311 return reg_exp_.Lookup(source, flags); |
| 324 } | 312 } |
| 325 | 313 |
| 326 | 314 void CompilationCache::PutScript(Handle<String> source, Handle<Context> context, |
| 327 void CompilationCache::PutScript(Handle<String> source, | |
| 328 Handle<Context> context, | |
| 329 LanguageMode language_mode, | 315 LanguageMode language_mode, |
| 330 Handle<SharedFunctionInfo> function_info) { | 316 Handle<SharedFunctionInfo> function_info, |
| 317 Handle<Cell> literals) { |
| 331 if (!IsEnabled()) return; | 318 if (!IsEnabled()) return; |
| 332 | 319 |
| 333 script_.Put(source, context, language_mode, function_info); | 320 script_.Put(source, context, language_mode, function_info, literals); |
| 334 } | 321 } |
| 335 | 322 |
| 336 | |
| 337 void CompilationCache::PutEval(Handle<String> source, | 323 void CompilationCache::PutEval(Handle<String> source, |
| 338 Handle<SharedFunctionInfo> outer_info, | 324 Handle<SharedFunctionInfo> outer_info, |
| 339 Handle<Context> context, | 325 Handle<Context> context, |
| 340 Handle<SharedFunctionInfo> function_info, | 326 Handle<SharedFunctionInfo> function_info, |
| 341 int scope_position) { | 327 Handle<Cell> literals, int scope_position) { |
| 342 if (!IsEnabled()) return; | 328 if (!IsEnabled()) return; |
| 343 | 329 |
| 344 HandleScope scope(isolate()); | 330 HandleScope scope(isolate()); |
| 345 if (context->IsNativeContext()) { | 331 if (context->IsNativeContext()) { |
| 346 eval_global_.Put(source, outer_info, function_info, scope_position); | 332 eval_global_.Put(source, outer_info, function_info, context, literals, |
| 333 scope_position); |
| 347 } else { | 334 } else { |
| 348 DCHECK(scope_position != kNoSourcePosition); | 335 DCHECK(scope_position != kNoSourcePosition); |
| 349 eval_contextual_.Put(source, outer_info, function_info, scope_position); | 336 Handle<Context> native_context(context->native_context(), isolate()); |
| 337 eval_contextual_.Put(source, outer_info, function_info, native_context, |
| 338 literals, scope_position); |
| 350 } | 339 } |
| 351 } | 340 } |
| 352 | 341 |
| 353 | 342 |
| 354 | 343 |
| 355 void CompilationCache::PutRegExp(Handle<String> source, | 344 void CompilationCache::PutRegExp(Handle<String> source, |
| 356 JSRegExp::Flags flags, | 345 JSRegExp::Flags flags, |
| 357 Handle<FixedArray> data) { | 346 Handle<FixedArray> data) { |
| 358 if (!IsEnabled()) { | 347 if (!IsEnabled()) { |
| 359 return; | 348 return; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 | 386 |
| 398 | 387 |
| 399 void CompilationCache::Disable() { | 388 void CompilationCache::Disable() { |
| 400 enabled_ = false; | 389 enabled_ = false; |
| 401 Clear(); | 390 Clear(); |
| 402 } | 391 } |
| 403 | 392 |
| 404 | 393 |
| 405 } // namespace internal | 394 } // namespace internal |
| 406 } // namespace v8 | 395 } // namespace v8 |
| OLD | NEW |