OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 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 "execution.h" | 31 #include "execution.h" |
31 #include "heap-profiler.h" | 32 #include "heap-profiler.h" |
32 #include "global-handles.h" | 33 #include "global-handles.h" |
33 #include "ic-inl.h" | 34 #include "ic-inl.h" |
34 #include "mark-compact.h" | 35 #include "mark-compact.h" |
35 #include "objects-visiting.h" | 36 #include "objects-visiting.h" |
36 #include "stub-cache.h" | 37 #include "stub-cache.h" |
37 | 38 |
38 namespace v8 { | 39 namespace v8 { |
39 namespace internal { | 40 namespace internal { |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 return HeapObject::cast(first); | 246 return HeapObject::cast(first); |
246 } | 247 } |
247 | 248 |
248 | 249 |
249 class StaticMarkingVisitor : public StaticVisitorBase { | 250 class StaticMarkingVisitor : public StaticVisitorBase { |
250 public: | 251 public: |
251 static inline void IterateBody(Map* map, HeapObject* obj) { | 252 static inline void IterateBody(Map* map, HeapObject* obj) { |
252 table_.GetVisitor(map)(map, obj); | 253 table_.GetVisitor(map)(map, obj); |
253 } | 254 } |
254 | 255 |
| 256 static void EnableCodeFlushing(bool enabled) { |
| 257 if (enabled) { |
| 258 table_.Register(kVisitJSFunction, &VisitJSFunction); |
| 259 } else { |
| 260 table_.Register(kVisitJSFunction, |
| 261 &JSObjectVisitor::VisitSpecialized<JSFunction::kSize>); |
| 262 } |
| 263 } |
| 264 |
255 static void Initialize() { | 265 static void Initialize() { |
256 table_.Register(kVisitShortcutCandidate, | 266 table_.Register(kVisitShortcutCandidate, |
257 &FixedBodyVisitor<StaticMarkingVisitor, | 267 &FixedBodyVisitor<StaticMarkingVisitor, |
258 ConsString::BodyDescriptor, | 268 ConsString::BodyDescriptor, |
259 void>::Visit); | 269 void>::Visit); |
260 | 270 |
261 table_.Register(kVisitConsString, | 271 table_.Register(kVisitConsString, |
262 &FixedBodyVisitor<StaticMarkingVisitor, | 272 &FixedBodyVisitor<StaticMarkingVisitor, |
263 ConsString::BodyDescriptor, | 273 ConsString::BodyDescriptor, |
264 void>::Visit); | 274 void>::Visit); |
(...skipping 17 matching lines...) Expand all Loading... |
282 &FixedBodyVisitor<StaticMarkingVisitor, | 292 &FixedBodyVisitor<StaticMarkingVisitor, |
283 Oddball::BodyDescriptor, | 293 Oddball::BodyDescriptor, |
284 void>::Visit); | 294 void>::Visit); |
285 table_.Register(kVisitMap, | 295 table_.Register(kVisitMap, |
286 &FixedBodyVisitor<StaticMarkingVisitor, | 296 &FixedBodyVisitor<StaticMarkingVisitor, |
287 Map::BodyDescriptor, | 297 Map::BodyDescriptor, |
288 void>::Visit); | 298 void>::Visit); |
289 | 299 |
290 table_.Register(kVisitCode, &VisitCode); | 300 table_.Register(kVisitCode, &VisitCode); |
291 | 301 |
| 302 table_.Register(kVisitJSFunction, &VisitJSFunction); |
| 303 |
292 table_.Register(kVisitPropertyCell, | 304 table_.Register(kVisitPropertyCell, |
293 &FixedBodyVisitor<StaticMarkingVisitor, | 305 &FixedBodyVisitor<StaticMarkingVisitor, |
294 JSGlobalPropertyCell::BodyDescriptor, | 306 JSGlobalPropertyCell::BodyDescriptor, |
295 void>::Visit); | 307 void>::Visit); |
296 | 308 |
297 table_.RegisterSpecializations<DataObjectVisitor, | 309 table_.RegisterSpecializations<DataObjectVisitor, |
298 kVisitDataObject, | 310 kVisitDataObject, |
299 kVisitDataObjectGeneric>(); | 311 kVisitDataObjectGeneric>(); |
300 | 312 |
301 table_.RegisterSpecializations<JSObjectVisitor, | 313 table_.RegisterSpecializations<JSObjectVisitor, |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 void> JSObjectVisitor; | 410 void> JSObjectVisitor; |
399 | 411 |
400 typedef FlexibleBodyVisitor<StaticMarkingVisitor, | 412 typedef FlexibleBodyVisitor<StaticMarkingVisitor, |
401 StructBodyDescriptor, | 413 StructBodyDescriptor, |
402 void> StructObjectVisitor; | 414 void> StructObjectVisitor; |
403 | 415 |
404 static void VisitCode(Map* map, HeapObject* object) { | 416 static void VisitCode(Map* map, HeapObject* object) { |
405 reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(); | 417 reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(); |
406 } | 418 } |
407 | 419 |
| 420 // Code flushing support. |
| 421 |
| 422 // How many collections newly compiled code object will survive before being |
| 423 // flushed. |
| 424 static const int kCodeAgeThreshold = 5; |
| 425 |
| 426 inline static bool HasSourceCode(SharedFunctionInfo* info) { |
| 427 Object* undefined = Heap::raw_unchecked_undefined_value(); |
| 428 return (info->script() != undefined) && |
| 429 (reinterpret_cast<Script*>(info->script())->source() != undefined); |
| 430 } |
| 431 |
| 432 |
| 433 inline static bool IsCompiled(JSFunction* function) { |
| 434 return |
| 435 function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile); |
| 436 } |
| 437 |
| 438 |
| 439 inline static bool IsCompiled(SharedFunctionInfo* function) { |
| 440 return |
| 441 function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile); |
| 442 } |
| 443 |
| 444 |
| 445 static void FlushCodeForFunction(JSFunction* function) { |
| 446 SharedFunctionInfo* shared_info = function->unchecked_shared(); |
| 447 |
| 448 if (shared_info->IsMarked()) return; |
| 449 |
| 450 // Special handling if the function and shared info objects |
| 451 // have different code objects. |
| 452 if (function->unchecked_code() != shared_info->unchecked_code()) { |
| 453 // If the shared function has been flushed but the function has not, |
| 454 // we flush the function if possible. |
| 455 if (!IsCompiled(shared_info) && |
| 456 IsCompiled(function) && |
| 457 !function->unchecked_code()->IsMarked()) { |
| 458 function->set_code(shared_info->unchecked_code()); |
| 459 } |
| 460 return; |
| 461 } |
| 462 |
| 463 // Code is either on stack or in compilation cache. |
| 464 if (shared_info->unchecked_code()->IsMarked()) { |
| 465 shared_info->set_code_age(0); |
| 466 return; |
| 467 } |
| 468 |
| 469 // The function must be compiled and have the source code available, |
| 470 // to be able to recompile it in case we need the function again. |
| 471 if (!(shared_info->is_compiled() && HasSourceCode(shared_info))) return; |
| 472 |
| 473 // We never flush code for Api functions. |
| 474 Object* function_data = shared_info->function_data(); |
| 475 if (function_data->IsHeapObject() && |
| 476 (SafeMap(function_data)->instance_type() == |
| 477 FUNCTION_TEMPLATE_INFO_TYPE)) { |
| 478 return; |
| 479 } |
| 480 |
| 481 // Only flush code for functions. |
| 482 if (shared_info->code()->kind() != Code::FUNCTION) return; |
| 483 |
| 484 // Function must be lazy compilable. |
| 485 if (!shared_info->allows_lazy_compilation()) return; |
| 486 |
| 487 // If this is a full script wrapped in a function we do no flush the code. |
| 488 if (shared_info->is_toplevel()) return; |
| 489 |
| 490 // Age this shared function info. |
| 491 if (shared_info->code_age() < kCodeAgeThreshold) { |
| 492 shared_info->set_code_age(shared_info->code_age() + 1); |
| 493 return; |
| 494 } |
| 495 |
| 496 // Compute the lazy compilable version of the code. |
| 497 Code* code = Builtins::builtin(Builtins::LazyCompile); |
| 498 shared_info->set_code(code); |
| 499 function->set_code(code); |
| 500 } |
| 501 |
| 502 |
| 503 static inline Map* SafeMap(Object* obj) { |
| 504 MapWord map_word = HeapObject::cast(obj)->map_word(); |
| 505 map_word.ClearMark(); |
| 506 map_word.ClearOverflow(); |
| 507 return map_word.ToMap(); |
| 508 } |
| 509 |
| 510 |
| 511 static inline bool IsJSBuiltinsObject(Object* obj) { |
| 512 return obj->IsHeapObject() && |
| 513 (SafeMap(obj)->instance_type() == JS_BUILTINS_OBJECT_TYPE); |
| 514 } |
| 515 |
| 516 |
| 517 static inline bool IsValidNotBuiltinContext(Object* ctx) { |
| 518 if (!ctx->IsHeapObject()) return false; |
| 519 |
| 520 Map* map = SafeMap(ctx); |
| 521 if(!(map == Heap::raw_unchecked_context_map() || |
| 522 map == Heap::raw_unchecked_catch_context_map() || |
| 523 map == Heap::raw_unchecked_global_context_map())) { |
| 524 return false; |
| 525 } |
| 526 |
| 527 Context* context = reinterpret_cast<Context*>(ctx); |
| 528 |
| 529 if(IsJSBuiltinsObject(context->global())) { |
| 530 return false; |
| 531 } |
| 532 |
| 533 return true; |
| 534 } |
| 535 |
| 536 |
| 537 static void VisitJSFunction(Map* map, HeapObject* object) { |
| 538 JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); |
| 539 |
| 540 // The function must have a valid context and not be a builtin. |
| 541 if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { |
| 542 FlushCodeForFunction(jsfunction); |
| 543 } |
| 544 |
| 545 JSObjectVisitor::VisitSpecialized<JSFunction::kSize>(map, object); |
| 546 } |
| 547 |
408 typedef void (*Callback)(Map* map, HeapObject* object); | 548 typedef void (*Callback)(Map* map, HeapObject* object); |
409 | 549 |
410 static VisitorDispatchTable<Callback> table_; | 550 static VisitorDispatchTable<Callback> table_; |
411 }; | 551 }; |
412 | 552 |
413 | 553 |
414 VisitorDispatchTable<StaticMarkingVisitor::Callback> | 554 VisitorDispatchTable<StaticMarkingVisitor::Callback> |
415 StaticMarkingVisitor::table_; | 555 StaticMarkingVisitor::table_; |
416 | 556 |
417 | 557 |
(...skipping 10 matching lines...) Expand all Loading... |
428 void VisitCodeTarget(RelocInfo* rinfo) { | 568 void VisitCodeTarget(RelocInfo* rinfo) { |
429 StaticMarkingVisitor::VisitCodeTarget(rinfo); | 569 StaticMarkingVisitor::VisitCodeTarget(rinfo); |
430 } | 570 } |
431 | 571 |
432 void VisitDebugTarget(RelocInfo* rinfo) { | 572 void VisitDebugTarget(RelocInfo* rinfo) { |
433 StaticMarkingVisitor::VisitDebugTarget(rinfo); | 573 StaticMarkingVisitor::VisitDebugTarget(rinfo); |
434 } | 574 } |
435 }; | 575 }; |
436 | 576 |
437 | 577 |
| 578 class CodeMarkingVisitor : public ThreadVisitor { |
| 579 public: |
| 580 void VisitThread(ThreadLocalTop* top) { |
| 581 for (StackFrameIterator it(top); !it.done(); it.Advance()) { |
| 582 MarkCompactCollector::MarkObject(it.frame()->unchecked_code()); |
| 583 } |
| 584 } |
| 585 }; |
| 586 |
| 587 |
| 588 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { |
| 589 public: |
| 590 void VisitPointers(Object** start, Object** end) { |
| 591 for (Object** p = start; p < end; p++) VisitPointer(p); |
| 592 } |
| 593 |
| 594 void VisitPointer(Object** slot) { |
| 595 Object* obj = *slot; |
| 596 if (obj->IsHeapObject()) { |
| 597 MarkCompactCollector::MarkObject(HeapObject::cast(obj)); |
| 598 } |
| 599 } |
| 600 }; |
| 601 |
| 602 |
| 603 void MarkCompactCollector::PrepareForCodeFlushing() { |
| 604 if (!FLAG_flush_code) { |
| 605 StaticMarkingVisitor::EnableCodeFlushing(false); |
| 606 return; |
| 607 } |
| 608 |
| 609 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 610 if (Debug::IsLoaded() || Debug::has_break_points()) { |
| 611 StaticMarkingVisitor::EnableCodeFlushing(false); |
| 612 return; |
| 613 } |
| 614 #endif |
| 615 StaticMarkingVisitor::EnableCodeFlushing(true); |
| 616 |
| 617 // Make sure we are not referencing the code from the stack. |
| 618 for (StackFrameIterator it; !it.done(); it.Advance()) { |
| 619 MarkCompactCollector::MarkObject(it.frame()->unchecked_code()); |
| 620 } |
| 621 |
| 622 // Iterate the archived stacks in all threads to check if |
| 623 // the code is referenced. |
| 624 CodeMarkingVisitor code_marking_visitor; |
| 625 ThreadManager::IterateArchivedThreads(&code_marking_visitor); |
| 626 |
| 627 SharedFunctionInfoMarkingVisitor visitor; |
| 628 CompilationCache::IterateFunctions(&visitor); |
| 629 |
| 630 MarkCompactCollector::ProcessMarkingStack(); |
| 631 } |
| 632 |
| 633 |
438 // Visitor class for marking heap roots. | 634 // Visitor class for marking heap roots. |
439 class RootMarkingVisitor : public ObjectVisitor { | 635 class RootMarkingVisitor : public ObjectVisitor { |
440 public: | 636 public: |
441 void VisitPointer(Object** p) { | 637 void VisitPointer(Object** p) { |
442 MarkObjectByPointer(p); | 638 MarkObjectByPointer(p); |
443 } | 639 } |
444 | 640 |
445 void VisitPointers(Object** start, Object** end) { | 641 void VisitPointers(Object** start, Object** end) { |
446 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); | 642 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); |
447 } | 643 } |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 ASSERT(state_ == PREPARE_GC); | 982 ASSERT(state_ == PREPARE_GC); |
787 state_ = MARK_LIVE_OBJECTS; | 983 state_ = MARK_LIVE_OBJECTS; |
788 #endif | 984 #endif |
789 // The to space contains live objects, the from space is used as a marking | 985 // The to space contains live objects, the from space is used as a marking |
790 // stack. | 986 // stack. |
791 marking_stack.Initialize(Heap::new_space()->FromSpaceLow(), | 987 marking_stack.Initialize(Heap::new_space()->FromSpaceLow(), |
792 Heap::new_space()->FromSpaceHigh()); | 988 Heap::new_space()->FromSpaceHigh()); |
793 | 989 |
794 ASSERT(!marking_stack.overflowed()); | 990 ASSERT(!marking_stack.overflowed()); |
795 | 991 |
| 992 PrepareForCodeFlushing(); |
| 993 |
796 RootMarkingVisitor root_visitor; | 994 RootMarkingVisitor root_visitor; |
797 MarkRoots(&root_visitor); | 995 MarkRoots(&root_visitor); |
798 | 996 |
799 // The objects reachable from the roots are marked, yet unreachable | 997 // The objects reachable from the roots are marked, yet unreachable |
800 // objects are unmarked. Mark objects reachable from object groups | 998 // objects are unmarked. Mark objects reachable from object groups |
801 // containing at least one marked object, and continue until no new | 999 // containing at least one marked object, and continue until no new |
802 // objects are reachable from the object groups. | 1000 // objects are reachable from the object groups. |
803 ProcessObjectGroups(); | 1001 ProcessObjectGroups(); |
804 | 1002 |
805 // The objects reachable from the roots or object groups are marked, | 1003 // The objects reachable from the roots or object groups are marked, |
(...skipping 1635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2441 } | 2639 } |
2442 | 2640 |
2443 | 2641 |
2444 void MarkCompactCollector::Initialize() { | 2642 void MarkCompactCollector::Initialize() { |
2445 StaticPointersToNewGenUpdatingVisitor::Initialize(); | 2643 StaticPointersToNewGenUpdatingVisitor::Initialize(); |
2446 StaticMarkingVisitor::Initialize(); | 2644 StaticMarkingVisitor::Initialize(); |
2447 } | 2645 } |
2448 | 2646 |
2449 | 2647 |
2450 } } // namespace v8::internal | 2648 } } // namespace v8::internal |
OLD | NEW |