| OLD | NEW | 
|     1 // Copyright 2012 the V8 project authors. All rights reserved. |     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 |     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 #ifndef V8_HEAP_MARK_COMPACT_H_ |     5 #ifndef V8_HEAP_MARK_COMPACT_H_ | 
|     6 #define V8_HEAP_MARK_COMPACT_H_ |     6 #define V8_HEAP_MARK_COMPACT_H_ | 
|     7  |     7  | 
|     8 #include "src/base/bits.h" |     8 #include "src/base/bits.h" | 
|     9 #include "src/heap/spaces.h" |     9 #include "src/heap/spaces.h" | 
|    10  |    10  | 
|    11 namespace v8 { |    11 namespace v8 { | 
|    12 namespace internal { |    12 namespace internal { | 
|    13  |    13  | 
|    14 // Callback function, returns whether an object is alive. The heap size |    14 // Callback function, returns whether an object is alive. The heap size | 
|    15 // of the object is returned in size. It optionally updates the offset |    15 // of the object is returned in size. It optionally updates the offset | 
|    16 // to the first live object in the page (only used for old and map objects). |    16 // to the first live object in the page (only used for old and map objects). | 
|    17 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset); |    17 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset); | 
|    18  |    18  | 
|    19 // Callback function to mark an object in a given heap. |    19 // Callback function to mark an object in a given heap. | 
|    20 typedef void (*MarkObjectFunction)(Heap* heap, HeapObject* object); |    20 typedef void (*MarkObjectFunction)(Heap* heap, HeapObject* object); | 
|    21  |    21  | 
|    22 // Forward declarations. |    22 // Forward declarations. | 
|    23 class CodeFlusher; |    23 class CodeFlusher; | 
|    24 class MarkCompactCollector; |    24 class MarkCompactCollector; | 
|    25 class MarkingVisitor; |    25 class MarkingVisitor; | 
|    26 class RootMarkingVisitor; |    26 class RootMarkingVisitor; | 
 |    27 class SlotsBuffer; | 
 |    28 class SlotsBufferAllocator; | 
|    27  |    29  | 
|    28  |    30  | 
|    29 class Marking : public AllStatic { |    31 class Marking : public AllStatic { | 
|    30  public: |    32  public: | 
|    31   INLINE(static MarkBit MarkBitFrom(Address addr)) { |    33   INLINE(static MarkBit MarkBitFrom(Address addr)) { | 
|    32     MemoryChunk* p = MemoryChunk::FromAddress(addr); |    34     MemoryChunk* p = MemoryChunk::FromAddress(addr); | 
|    33     return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(addr)); |    35     return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(addr)); | 
|    34   } |    36   } | 
|    35  |    37  | 
|    36   INLINE(static MarkBit MarkBitFrom(HeapObject* obj)) { |    38   INLINE(static MarkBit MarkBitFrom(HeapObject* obj)) { | 
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   251   int top_; |   253   int top_; | 
|   252   int bottom_; |   254   int bottom_; | 
|   253   int mask_; |   255   int mask_; | 
|   254   bool overflowed_; |   256   bool overflowed_; | 
|   255   bool in_use_; |   257   bool in_use_; | 
|   256  |   258  | 
|   257   DISALLOW_COPY_AND_ASSIGN(MarkingDeque); |   259   DISALLOW_COPY_AND_ASSIGN(MarkingDeque); | 
|   258 }; |   260 }; | 
|   259  |   261  | 
|   260  |   262  | 
|   261 class SlotsBufferAllocator { |  | 
|   262  public: |  | 
|   263   SlotsBuffer* AllocateBuffer(SlotsBuffer* next_buffer); |  | 
|   264   void DeallocateBuffer(SlotsBuffer* buffer); |  | 
|   265  |  | 
|   266   void DeallocateChain(SlotsBuffer** buffer_address); |  | 
|   267 }; |  | 
|   268  |  | 
|   269  |  | 
|   270 // SlotsBuffer records a sequence of slots that has to be updated |  | 
|   271 // after live objects were relocated from evacuation candidates. |  | 
|   272 // All slots are either untyped or typed: |  | 
|   273 //    - Untyped slots are expected to contain a tagged object pointer. |  | 
|   274 //      They are recorded by an address. |  | 
|   275 //    - Typed slots are expected to contain an encoded pointer to a heap |  | 
|   276 //      object where the way of encoding depends on the type of the slot. |  | 
|   277 //      They are recorded as a pair (SlotType, slot address). |  | 
|   278 // We assume that zero-page is never mapped this allows us to distinguish |  | 
|   279 // untyped slots from typed slots during iteration by a simple comparison: |  | 
|   280 // if element of slots buffer is less than NUMBER_OF_SLOT_TYPES then it |  | 
|   281 // is the first element of typed slot's pair. |  | 
|   282 class SlotsBuffer { |  | 
|   283  public: |  | 
|   284   typedef Object** ObjectSlot; |  | 
|   285  |  | 
|   286   explicit SlotsBuffer(SlotsBuffer* next_buffer) |  | 
|   287       : idx_(0), chain_length_(1), next_(next_buffer) { |  | 
|   288     if (next_ != NULL) { |  | 
|   289       chain_length_ = next_->chain_length_ + 1; |  | 
|   290     } |  | 
|   291   } |  | 
|   292  |  | 
|   293   ~SlotsBuffer() {} |  | 
|   294  |  | 
|   295   void Add(ObjectSlot slot) { |  | 
|   296     DCHECK(0 <= idx_ && idx_ < kNumberOfElements); |  | 
|   297 #ifdef DEBUG |  | 
|   298     if (slot >= reinterpret_cast<ObjectSlot>(NUMBER_OF_SLOT_TYPES)) { |  | 
|   299       DCHECK_NOT_NULL(*slot); |  | 
|   300     } |  | 
|   301 #endif |  | 
|   302     slots_[idx_++] = slot; |  | 
|   303   } |  | 
|   304  |  | 
|   305   // Should be used for testing only. |  | 
|   306   ObjectSlot Get(intptr_t i) { |  | 
|   307     DCHECK(i >= 0 && i < kNumberOfElements); |  | 
|   308     return slots_[i]; |  | 
|   309   } |  | 
|   310  |  | 
|   311   enum SlotType { |  | 
|   312     EMBEDDED_OBJECT_SLOT, |  | 
|   313     OBJECT_SLOT, |  | 
|   314     RELOCATED_CODE_OBJECT, |  | 
|   315     CELL_TARGET_SLOT, |  | 
|   316     CODE_TARGET_SLOT, |  | 
|   317     CODE_ENTRY_SLOT, |  | 
|   318     DEBUG_TARGET_SLOT, |  | 
|   319     NUMBER_OF_SLOT_TYPES |  | 
|   320   }; |  | 
|   321  |  | 
|   322   static const char* SlotTypeToString(SlotType type) { |  | 
|   323     switch (type) { |  | 
|   324       case EMBEDDED_OBJECT_SLOT: |  | 
|   325         return "EMBEDDED_OBJECT_SLOT"; |  | 
|   326       case OBJECT_SLOT: |  | 
|   327         return "OBJECT_SLOT"; |  | 
|   328       case RELOCATED_CODE_OBJECT: |  | 
|   329         return "RELOCATED_CODE_OBJECT"; |  | 
|   330       case CELL_TARGET_SLOT: |  | 
|   331         return "CELL_TARGET_SLOT"; |  | 
|   332       case CODE_TARGET_SLOT: |  | 
|   333         return "CODE_TARGET_SLOT"; |  | 
|   334       case CODE_ENTRY_SLOT: |  | 
|   335         return "CODE_ENTRY_SLOT"; |  | 
|   336       case DEBUG_TARGET_SLOT: |  | 
|   337         return "DEBUG_TARGET_SLOT"; |  | 
|   338       case NUMBER_OF_SLOT_TYPES: |  | 
|   339         return "NUMBER_OF_SLOT_TYPES"; |  | 
|   340     } |  | 
|   341     return "UNKNOWN SlotType"; |  | 
|   342   } |  | 
|   343  |  | 
|   344   void UpdateSlots(Heap* heap); |  | 
|   345  |  | 
|   346   void UpdateSlotsWithFilter(Heap* heap); |  | 
|   347  |  | 
|   348   SlotsBuffer* next() { return next_; } |  | 
|   349  |  | 
|   350   static int SizeOfChain(SlotsBuffer* buffer) { |  | 
|   351     if (buffer == NULL) return 0; |  | 
|   352     return static_cast<int>(buffer->idx_ + |  | 
|   353                             (buffer->chain_length_ - 1) * kNumberOfElements); |  | 
|   354   } |  | 
|   355  |  | 
|   356   inline bool IsFull() { return idx_ == kNumberOfElements; } |  | 
|   357  |  | 
|   358   inline bool HasSpaceForTypedSlot() { return idx_ < kNumberOfElements - 1; } |  | 
|   359  |  | 
|   360   static void UpdateSlotsRecordedIn(Heap* heap, SlotsBuffer* buffer) { |  | 
|   361     while (buffer != NULL) { |  | 
|   362         buffer->UpdateSlots(heap); |  | 
|   363       buffer = buffer->next(); |  | 
|   364     } |  | 
|   365   } |  | 
|   366  |  | 
|   367   enum AdditionMode { FAIL_ON_OVERFLOW, IGNORE_OVERFLOW }; |  | 
|   368  |  | 
|   369   static bool ChainLengthThresholdReached(SlotsBuffer* buffer) { |  | 
|   370     return buffer != NULL && buffer->chain_length_ >= kChainLengthThreshold; |  | 
|   371   } |  | 
|   372  |  | 
|   373   INLINE(static bool AddToSynchronized(SlotsBufferAllocator* allocator, |  | 
|   374                                        SlotsBuffer** buffer_address, |  | 
|   375                                        base::Mutex* buffer_mutex, |  | 
|   376                                        ObjectSlot slot, AdditionMode mode)) { |  | 
|   377     base::LockGuard<base::Mutex> lock_guard(buffer_mutex); |  | 
|   378     return AddTo(allocator, buffer_address, slot, mode); |  | 
|   379   } |  | 
|   380  |  | 
|   381   INLINE(static bool AddTo(SlotsBufferAllocator* allocator, |  | 
|   382                            SlotsBuffer** buffer_address, ObjectSlot slot, |  | 
|   383                            AdditionMode mode)) { |  | 
|   384     SlotsBuffer* buffer = *buffer_address; |  | 
|   385     if (buffer == NULL || buffer->IsFull()) { |  | 
|   386       if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) { |  | 
|   387         allocator->DeallocateChain(buffer_address); |  | 
|   388         return false; |  | 
|   389       } |  | 
|   390       buffer = allocator->AllocateBuffer(buffer); |  | 
|   391       *buffer_address = buffer; |  | 
|   392     } |  | 
|   393     buffer->Add(slot); |  | 
|   394     return true; |  | 
|   395   } |  | 
|   396  |  | 
|   397   static bool IsTypedSlot(ObjectSlot slot); |  | 
|   398  |  | 
|   399   static bool AddToSynchronized(SlotsBufferAllocator* allocator, |  | 
|   400                                 SlotsBuffer** buffer_address, |  | 
|   401                                 base::Mutex* buffer_mutex, SlotType type, |  | 
|   402                                 Address addr, AdditionMode mode); |  | 
|   403  |  | 
|   404   static bool AddTo(SlotsBufferAllocator* allocator, |  | 
|   405                     SlotsBuffer** buffer_address, SlotType type, Address addr, |  | 
|   406                     AdditionMode mode); |  | 
|   407  |  | 
|   408   // Eliminates all stale entries from the slots buffer, i.e., slots that |  | 
|   409   // are not part of live objects anymore. This method must be called after |  | 
|   410   // marking, when the whole transitive closure is known and must be called |  | 
|   411   // before sweeping when mark bits are still intact. |  | 
|   412   static void RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer); |  | 
|   413  |  | 
|   414   // Eliminate all slots that are within the given address range. |  | 
|   415   static void RemoveObjectSlots(Heap* heap, SlotsBuffer* buffer, |  | 
|   416                                 Address start_slot, Address end_slot); |  | 
|   417  |  | 
|   418   // Ensures that there are no invalid slots in the chain of slots buffers. |  | 
|   419   static void VerifySlots(Heap* heap, SlotsBuffer* buffer); |  | 
|   420  |  | 
|   421   static const int kNumberOfElements = 1021; |  | 
|   422  |  | 
|   423  private: |  | 
|   424   static const int kChainLengthThreshold = 15; |  | 
|   425  |  | 
|   426   intptr_t idx_; |  | 
|   427   intptr_t chain_length_; |  | 
|   428   SlotsBuffer* next_; |  | 
|   429   ObjectSlot slots_[kNumberOfElements]; |  | 
|   430 }; |  | 
|   431  |  | 
|   432  |  | 
|   433 // CodeFlusher collects candidates for code flushing during marking and |   263 // CodeFlusher collects candidates for code flushing during marking and | 
|   434 // processes those candidates after marking has completed in order to |   264 // processes those candidates after marking has completed in order to | 
|   435 // reset those functions referencing code objects that would otherwise |   265 // reset those functions referencing code objects that would otherwise | 
|   436 // be unreachable. Code objects can be referenced in three ways: |   266 // be unreachable. Code objects can be referenced in three ways: | 
|   437 //    - SharedFunctionInfo references unoptimized code. |   267 //    - SharedFunctionInfo references unoptimized code. | 
|   438 //    - JSFunction references either unoptimized or optimized code. |   268 //    - JSFunction references either unoptimized or optimized code. | 
|   439 //    - OptimizedCodeMap references optimized code. |   269 //    - OptimizedCodeMap references optimized code. | 
|   440 // We are not allowed to flush unoptimized code for functions that got |   270 // We are not allowed to flush unoptimized code for functions that got | 
|   441 // optimized or inlined into optimized code, because we might bailout |   271 // optimized or inlined into optimized code, because we might bailout | 
|   442 // into the unoptimized code again during deoptimization. |   272 // into the unoptimized code again during deoptimization. | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   582   } |   412   } | 
|   583  |   413  | 
|   584   INLINE(static bool IsOnEvacuationCandidate(Object* obj)) { |   414   INLINE(static bool IsOnEvacuationCandidate(Object* obj)) { | 
|   585     return Page::FromAddress(reinterpret_cast<Address>(obj)) |   415     return Page::FromAddress(reinterpret_cast<Address>(obj)) | 
|   586         ->IsEvacuationCandidate(); |   416         ->IsEvacuationCandidate(); | 
|   587   } |   417   } | 
|   588  |   418  | 
|   589   void RecordRelocSlot(RelocInfo* rinfo, Object* target); |   419   void RecordRelocSlot(RelocInfo* rinfo, Object* target); | 
|   590   void RecordCodeEntrySlot(HeapObject* object, Address slot, Code* target); |   420   void RecordCodeEntrySlot(HeapObject* object, Address slot, Code* target); | 
|   591   void RecordCodeTargetPatch(Address pc, Code* target); |   421   void RecordCodeTargetPatch(Address pc, Code* target); | 
 |   422   void RecordSlot(HeapObject* object, Object** slot, Object* target); | 
 |   423   void ForceRecordSlot(HeapObject* object, Object** slot, Object* target); | 
|   592  |   424  | 
|   593   INLINE(void RecordSlot( |   425   void UpdateSlots(SlotsBuffer* buffer); | 
|   594       HeapObject* object, Object** slot, Object* target, |   426   void UpdateSlotsRecordedIn(SlotsBuffer* buffer); | 
|   595       SlotsBuffer::AdditionMode mode = SlotsBuffer::FAIL_ON_OVERFLOW)); |  | 
|   596  |   427  | 
|   597   void MigrateObject(HeapObject* dst, HeapObject* src, int size, |   428   void MigrateObject(HeapObject* dst, HeapObject* src, int size, | 
|   598                      AllocationSpace to_old_space); |   429                      AllocationSpace to_old_space); | 
|   599  |   430  | 
|   600   void MigrateObjectTagged(HeapObject* dst, HeapObject* src, int size); |   431   void MigrateObjectTagged(HeapObject* dst, HeapObject* src, int size); | 
|   601   void MigrateObjectMixed(HeapObject* dst, HeapObject* src, int size); |   432   void MigrateObjectMixed(HeapObject* dst, HeapObject* src, int size); | 
|   602   void MigrateObjectRaw(HeapObject* dst, HeapObject* src, int size); |   433   void MigrateObjectRaw(HeapObject* dst, HeapObject* src, int size); | 
|   603  |   434  | 
|   604   bool TryPromoteObject(HeapObject* object, int object_size); |   435   bool TryPromoteObject(HeapObject* object, int object_size); | 
|   605  |   436  | 
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   720   bool parallel_compaction_in_progress_; |   551   bool parallel_compaction_in_progress_; | 
|   721  |   552  | 
|   722   // Synchronize sweeper threads. |   553   // Synchronize sweeper threads. | 
|   723   base::Semaphore pending_sweeper_jobs_semaphore_; |   554   base::Semaphore pending_sweeper_jobs_semaphore_; | 
|   724  |   555  | 
|   725   // Synchronize compaction threads. |   556   // Synchronize compaction threads. | 
|   726   base::Semaphore pending_compaction_jobs_semaphore_; |   557   base::Semaphore pending_compaction_jobs_semaphore_; | 
|   727  |   558  | 
|   728   bool evacuation_; |   559   bool evacuation_; | 
|   729  |   560  | 
|   730   SlotsBufferAllocator slots_buffer_allocator_; |   561   SlotsBufferAllocator* slots_buffer_allocator_; | 
|   731  |   562  | 
|   732   SlotsBuffer* migration_slots_buffer_; |   563   SlotsBuffer* migration_slots_buffer_; | 
|   733  |   564  | 
|   734   base::Mutex migration_slots_buffer_mutex_; |   565   base::Mutex migration_slots_buffer_mutex_; | 
|   735  |   566  | 
|   736   // Finishes GC, performs heap verification if enabled. |   567   // Finishes GC, performs heap verification if enabled. | 
|   737   void Finish(); |   568   void Finish(); | 
|   738  |   569  | 
|   739   // ----------------------------------------------------------------------- |   570   // ----------------------------------------------------------------------- | 
|   740   // Phase 1: Marking live objects. |   571   // Phase 1: Marking live objects. | 
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   992  private: |   823  private: | 
|   993   MarkCompactCollector* collector_; |   824   MarkCompactCollector* collector_; | 
|   994 }; |   825 }; | 
|   995  |   826  | 
|   996  |   827  | 
|   997 const char* AllocationSpaceName(AllocationSpace space); |   828 const char* AllocationSpaceName(AllocationSpace space); | 
|   998 } |   829 } | 
|   999 }  // namespace v8::internal |   830 }  // namespace v8::internal | 
|  1000  |   831  | 
|  1001 #endif  // V8_HEAP_MARK_COMPACT_H_ |   832 #endif  // V8_HEAP_MARK_COMPACT_H_ | 
| OLD | NEW |