| OLD | NEW |
| 1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "compilation-cache.h" | 30 #include "compilation-cache.h" |
| 31 #include "serialize.h" | 31 #include "serialize.h" |
| 32 | 32 |
| 33 namespace v8 { | 33 namespace v8 { |
| 34 namespace internal { | 34 namespace internal { |
| 35 | 35 |
| 36 // The number of sub caches covering the different types to cache. | |
| 37 static const int kSubCacheCount = 4; | |
| 38 | 36 |
| 39 // The number of generations for each sub cache. | 37 // The number of generations for each sub cache. |
| 40 // The number of ScriptGenerations is carefully chosen based on histograms. | 38 // The number of ScriptGenerations is carefully chosen based on histograms. |
| 41 // See issue 458: http://code.google.com/p/v8/issues/detail?id=458 | 39 // See issue 458: http://code.google.com/p/v8/issues/detail?id=458 |
| 42 static const int kScriptGenerations = 5; | 40 static const int kScriptGenerations = 5; |
| 43 static const int kEvalGlobalGenerations = 2; | 41 static const int kEvalGlobalGenerations = 2; |
| 44 static const int kEvalContextualGenerations = 2; | 42 static const int kEvalContextualGenerations = 2; |
| 45 static const int kRegExpGenerations = 2; | 43 static const int kRegExpGenerations = 2; |
| 46 | 44 |
| 47 // Initial size of each compilation cache table allocated. | 45 // Initial size of each compilation cache table allocated. |
| 48 static const int kInitialCacheSize = 64; | 46 static const int kInitialCacheSize = 64; |
| 49 | 47 |
| 50 // Index for the first generation in the cache. | |
| 51 static const int kFirstGeneration = 0; | |
| 52 | 48 |
| 53 // The compilation cache consists of several generational sub-caches which uses | 49 CompilationCache::CompilationCache() |
| 54 // this class as a base class. A sub-cache contains a compilation cache tables | 50 : script_(kScriptGenerations), |
| 55 // for each generation of the sub-cache. Since the same source code string has | 51 eval_global_(kEvalGlobalGenerations), |
| 56 // different compiled code for scripts and evals, we use separate sub-caches | 52 eval_contextual_(kEvalContextualGenerations), |
| 57 // for different compilation modes, to avoid retrieving the wrong result. | 53 reg_exp_(kRegExpGenerations), |
| 58 class CompilationSubCache { | 54 enabled_(true) { |
| 59 public: | 55 CompilationSubCache* subcaches[kSubCacheCount] = |
| 60 explicit CompilationSubCache(int generations): generations_(generations) { | 56 {&script_, &eval_global_, &eval_contextual_, ®_exp_}; |
| 61 tables_ = NewArray<Object*>(generations); | 57 for (int i = 0; i < kSubCacheCount; ++i) { |
| 58 subcaches_[i] = subcaches[i]; |
| 62 } | 59 } |
| 63 | |
| 64 ~CompilationSubCache() { DeleteArray(tables_); } | |
| 65 | |
| 66 // Get the compilation cache tables for a specific generation. | |
| 67 Handle<CompilationCacheTable> GetTable(int generation); | |
| 68 | |
| 69 // Accessors for first generation. | |
| 70 Handle<CompilationCacheTable> GetFirstTable() { | |
| 71 return GetTable(kFirstGeneration); | |
| 72 } | |
| 73 void SetFirstTable(Handle<CompilationCacheTable> value) { | |
| 74 ASSERT(kFirstGeneration < generations_); | |
| 75 tables_[kFirstGeneration] = *value; | |
| 76 } | |
| 77 | |
| 78 // Age the sub-cache by evicting the oldest generation and creating a new | |
| 79 // young generation. | |
| 80 void Age(); | |
| 81 | |
| 82 bool HasFunction(SharedFunctionInfo* function_info); | |
| 83 | |
| 84 // GC support. | |
| 85 void Iterate(ObjectVisitor* v); | |
| 86 | |
| 87 // Clear this sub-cache evicting all its content. | |
| 88 void Clear(); | |
| 89 | |
| 90 // Number of generations in this sub-cache. | |
| 91 inline int generations() { return generations_; } | |
| 92 | |
| 93 private: | |
| 94 int generations_; // Number of generations. | |
| 95 Object** tables_; // Compilation cache tables - one for each generation. | |
| 96 | |
| 97 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache); | |
| 98 }; | |
| 99 | |
| 100 | |
| 101 // Sub-cache for scripts. | |
| 102 class CompilationCacheScript : public CompilationSubCache { | |
| 103 public: | |
| 104 explicit CompilationCacheScript(int generations) | |
| 105 : CompilationSubCache(generations) { } | |
| 106 | |
| 107 Handle<SharedFunctionInfo> Lookup(Handle<String> source, | |
| 108 Handle<Object> name, | |
| 109 int line_offset, | |
| 110 int column_offset); | |
| 111 void Put(Handle<String> source, Handle<SharedFunctionInfo> function_info); | |
| 112 | |
| 113 private: | |
| 114 // Note: Returns a new hash table if operation results in expansion. | |
| 115 Handle<CompilationCacheTable> TablePut( | |
| 116 Handle<String> source, Handle<SharedFunctionInfo> function_info); | |
| 117 | |
| 118 bool HasOrigin(Handle<SharedFunctionInfo> function_info, | |
| 119 Handle<Object> name, | |
| 120 int line_offset, | |
| 121 int column_offset); | |
| 122 | |
| 123 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript); | |
| 124 }; | |
| 125 | |
| 126 | |
| 127 // Sub-cache for eval scripts. | |
| 128 class CompilationCacheEval: public CompilationSubCache { | |
| 129 public: | |
| 130 explicit CompilationCacheEval(int generations) | |
| 131 : CompilationSubCache(generations) { } | |
| 132 | |
| 133 Handle<SharedFunctionInfo> Lookup(Handle<String> source, | |
| 134 Handle<Context> context); | |
| 135 | |
| 136 void Put(Handle<String> source, | |
| 137 Handle<Context> context, | |
| 138 Handle<SharedFunctionInfo> function_info); | |
| 139 | |
| 140 private: | |
| 141 // Note: Returns a new hash table if operation results in expansion. | |
| 142 Handle<CompilationCacheTable> TablePut( | |
| 143 Handle<String> source, | |
| 144 Handle<Context> context, | |
| 145 Handle<SharedFunctionInfo> function_info); | |
| 146 | |
| 147 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval); | |
| 148 }; | |
| 149 | |
| 150 | |
| 151 // Sub-cache for regular expressions. | |
| 152 class CompilationCacheRegExp: public CompilationSubCache { | |
| 153 public: | |
| 154 explicit CompilationCacheRegExp(int generations) | |
| 155 : CompilationSubCache(generations) { } | |
| 156 | |
| 157 Handle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags); | |
| 158 | |
| 159 void Put(Handle<String> source, | |
| 160 JSRegExp::Flags flags, | |
| 161 Handle<FixedArray> data); | |
| 162 private: | |
| 163 // Note: Returns a new hash table if operation results in expansion. | |
| 164 Handle<CompilationCacheTable> TablePut(Handle<String> source, | |
| 165 JSRegExp::Flags flags, | |
| 166 Handle<FixedArray> data); | |
| 167 | |
| 168 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp); | |
| 169 }; | |
| 170 | |
| 171 | |
| 172 // Statically allocate all the sub-caches. | |
| 173 static CompilationCacheScript script(kScriptGenerations); | |
| 174 static CompilationCacheEval eval_global(kEvalGlobalGenerations); | |
| 175 static CompilationCacheEval eval_contextual(kEvalContextualGenerations); | |
| 176 static CompilationCacheRegExp reg_exp(kRegExpGenerations); | |
| 177 static CompilationSubCache* subcaches[kSubCacheCount] = | |
| 178 {&script, &eval_global, &eval_contextual, ®_exp}; | |
| 179 | |
| 180 | |
| 181 // Current enable state of the compilation cache. | |
| 182 static bool enabled = true; | |
| 183 static inline bool IsEnabled() { | |
| 184 return FLAG_compilation_cache && enabled; | |
| 185 } | 60 } |
| 186 | 61 |
| 187 | 62 |
| 188 static Handle<CompilationCacheTable> AllocateTable(int size) { | 63 static Handle<CompilationCacheTable> AllocateTable(int size) { |
| 189 CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size), | 64 CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size), |
| 190 CompilationCacheTable); | 65 CompilationCacheTable); |
| 191 } | 66 } |
| 192 | 67 |
| 193 | 68 |
| 194 Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) { | 69 Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 // Break when we've found a suitable shared function info that | 171 // Break when we've found a suitable shared function info that |
| 297 // matches the origin. | 172 // matches the origin. |
| 298 if (HasOrigin(function_info, name, line_offset, column_offset)) { | 173 if (HasOrigin(function_info, name, line_offset, column_offset)) { |
| 299 result = *function_info; | 174 result = *function_info; |
| 300 break; | 175 break; |
| 301 } | 176 } |
| 302 } | 177 } |
| 303 } | 178 } |
| 304 } | 179 } |
| 305 | 180 |
| 181 // TODO(isolates): make it per isolate |
| 306 static void* script_histogram = StatsTable::CreateHistogram( | 182 static void* script_histogram = StatsTable::CreateHistogram( |
| 307 "V8.ScriptCache", | 183 "V8.ScriptCache", |
| 308 0, | 184 0, |
| 309 kScriptGenerations, | 185 kScriptGenerations, |
| 310 kScriptGenerations + 1); | 186 kScriptGenerations + 1); |
| 311 | 187 |
| 312 if (script_histogram != NULL) { | 188 if (script_histogram != NULL) { |
| 313 // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss. | 189 // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss. |
| 314 StatsTable::AddHistogramSample(script_histogram, generation); | 190 StatsTable::AddHistogramSample(script_histogram, generation); |
| 315 } | 191 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 | 321 |
| 446 | 322 |
| 447 Handle<SharedFunctionInfo> CompilationCache::LookupScript(Handle<String> source, | 323 Handle<SharedFunctionInfo> CompilationCache::LookupScript(Handle<String> source, |
| 448 Handle<Object> name, | 324 Handle<Object> name, |
| 449 int line_offset, | 325 int line_offset, |
| 450 int column_offset) { | 326 int column_offset) { |
| 451 if (!IsEnabled()) { | 327 if (!IsEnabled()) { |
| 452 return Handle<SharedFunctionInfo>::null(); | 328 return Handle<SharedFunctionInfo>::null(); |
| 453 } | 329 } |
| 454 | 330 |
| 455 return script.Lookup(source, name, line_offset, column_offset); | 331 return script_.Lookup(source, name, line_offset, column_offset); |
| 456 } | 332 } |
| 457 | 333 |
| 458 | 334 |
| 459 Handle<SharedFunctionInfo> CompilationCache::LookupEval(Handle<String> source, | 335 Handle<SharedFunctionInfo> CompilationCache::LookupEval(Handle<String> source, |
| 460 Handle<Context> context, | 336 Handle<Context> context, |
| 461 bool is_global) { | 337 bool is_global) { |
| 462 if (!IsEnabled()) { | 338 if (!IsEnabled()) { |
| 463 return Handle<SharedFunctionInfo>::null(); | 339 return Handle<SharedFunctionInfo>::null(); |
| 464 } | 340 } |
| 465 | 341 |
| 466 Handle<SharedFunctionInfo> result; | 342 Handle<SharedFunctionInfo> result; |
| 467 if (is_global) { | 343 if (is_global) { |
| 468 result = eval_global.Lookup(source, context); | 344 result = eval_global_.Lookup(source, context); |
| 469 } else { | 345 } else { |
| 470 result = eval_contextual.Lookup(source, context); | 346 result = eval_contextual_.Lookup(source, context); |
| 471 } | 347 } |
| 472 return result; | 348 return result; |
| 473 } | 349 } |
| 474 | 350 |
| 475 | 351 |
| 476 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, | 352 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, |
| 477 JSRegExp::Flags flags) { | 353 JSRegExp::Flags flags) { |
| 478 if (!IsEnabled()) { | 354 if (!IsEnabled()) { |
| 479 return Handle<FixedArray>::null(); | 355 return Handle<FixedArray>::null(); |
| 480 } | 356 } |
| 481 | 357 |
| 482 return reg_exp.Lookup(source, flags); | 358 return reg_exp_.Lookup(source, flags); |
| 483 } | 359 } |
| 484 | 360 |
| 485 | 361 |
| 486 void CompilationCache::PutScript(Handle<String> source, | 362 void CompilationCache::PutScript(Handle<String> source, |
| 487 Handle<SharedFunctionInfo> function_info) { | 363 Handle<SharedFunctionInfo> function_info) { |
| 488 if (!IsEnabled()) { | 364 if (!IsEnabled()) { |
| 489 return; | 365 return; |
| 490 } | 366 } |
| 491 | 367 |
| 492 script.Put(source, function_info); | 368 script_.Put(source, function_info); |
| 493 } | 369 } |
| 494 | 370 |
| 495 | 371 |
| 496 void CompilationCache::PutEval(Handle<String> source, | 372 void CompilationCache::PutEval(Handle<String> source, |
| 497 Handle<Context> context, | 373 Handle<Context> context, |
| 498 bool is_global, | 374 bool is_global, |
| 499 Handle<SharedFunctionInfo> function_info) { | 375 Handle<SharedFunctionInfo> function_info) { |
| 500 if (!IsEnabled()) { | 376 if (!IsEnabled()) { |
| 501 return; | 377 return; |
| 502 } | 378 } |
| 503 | 379 |
| 504 HandleScope scope; | 380 HandleScope scope; |
| 505 if (is_global) { | 381 if (is_global) { |
| 506 eval_global.Put(source, context, function_info); | 382 eval_global_.Put(source, context, function_info); |
| 507 } else { | 383 } else { |
| 508 eval_contextual.Put(source, context, function_info); | 384 eval_contextual_.Put(source, context, function_info); |
| 509 } | 385 } |
| 510 } | 386 } |
| 511 | 387 |
| 512 | 388 |
| 513 | 389 |
| 514 void CompilationCache::PutRegExp(Handle<String> source, | 390 void CompilationCache::PutRegExp(Handle<String> source, |
| 515 JSRegExp::Flags flags, | 391 JSRegExp::Flags flags, |
| 516 Handle<FixedArray> data) { | 392 Handle<FixedArray> data) { |
| 517 if (!IsEnabled()) { | 393 if (!IsEnabled()) { |
| 518 return; | 394 return; |
| 519 } | 395 } |
| 520 | 396 |
| 521 reg_exp.Put(source, flags, data); | 397 reg_exp_.Put(source, flags, data); |
| 522 } | 398 } |
| 523 | 399 |
| 524 | 400 |
| 525 void CompilationCache::Clear() { | 401 void CompilationCache::Clear() { |
| 526 for (int i = 0; i < kSubCacheCount; i++) { | 402 for (int i = 0; i < kSubCacheCount; i++) { |
| 527 subcaches[i]->Clear(); | 403 subcaches_[i]->Clear(); |
| 528 } | 404 } |
| 529 } | 405 } |
| 530 | 406 |
| 531 | 407 |
| 532 bool CompilationCache::HasFunction(SharedFunctionInfo* function_info) { | 408 bool CompilationCache::HasFunction(SharedFunctionInfo* function_info) { |
| 533 return script.HasFunction(function_info); | 409 return script_.HasFunction(function_info); |
| 534 } | 410 } |
| 535 | 411 |
| 536 | 412 |
| 537 void CompilationCache::Iterate(ObjectVisitor* v) { | 413 void CompilationCache::Iterate(ObjectVisitor* v) { |
| 538 for (int i = 0; i < kSubCacheCount; i++) { | 414 for (int i = 0; i < kSubCacheCount; i++) { |
| 539 subcaches[i]->Iterate(v); | 415 subcaches_[i]->Iterate(v); |
| 540 } | 416 } |
| 541 } | 417 } |
| 542 | 418 |
| 543 | 419 |
| 544 void CompilationCache::MarkCompactPrologue() { | 420 void CompilationCache::MarkCompactPrologue() { |
| 545 for (int i = 0; i < kSubCacheCount; i++) { | 421 for (int i = 0; i < kSubCacheCount; i++) { |
| 546 subcaches[i]->Age(); | 422 subcaches_[i]->Age(); |
| 547 } | 423 } |
| 548 } | 424 } |
| 549 | 425 |
| 550 | 426 |
| 551 void CompilationCache::Enable() { | 427 void CompilationCache::Enable() { |
| 552 enabled = true; | 428 enabled_ = true; |
| 553 } | 429 } |
| 554 | 430 |
| 555 | 431 |
| 556 void CompilationCache::Disable() { | 432 void CompilationCache::Disable() { |
| 557 enabled = false; | 433 enabled_ = false; |
| 558 Clear(); | 434 Clear(); |
| 559 } | 435 } |
| 560 | 436 |
| 561 | 437 |
| 562 } } // namespace v8::internal | 438 } } // namespace v8::internal |
| OLD | NEW |