scavenger.h 9.89 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_HEAP_SCAVENGER_H_
#define V8_HEAP_SCAVENGER_H_

8
#include "src/base/platform/condition-variable.h"
9
#include "src/heap/local-allocator.h"
10
#include "src/heap/objects-visiting.h"
11
#include "src/heap/slot-set.h"
12
#include "src/heap/worklist.h"
13 14 15 16

namespace v8 {
namespace internal {

17
class OneshotBarrier;
18 19
class RootScavengeVisitor;
class Scavenger;
20

21 22 23 24 25 26
enum class CopyAndForwardResult {
  SUCCESS_YOUNG_GENERATION,
  SUCCESS_OLD_GENERATION,
  FAILURE
};

27 28
using ObjectAndSize = std::pair<HeapObject, int>;
using SurvivingNewLargeObjectsMap =
29
    std::unordered_map<HeapObject, Map, Object::Hasher>;
30
using SurvivingNewLargeObjectMapEntry = std::pair<HeapObject, Map>;
31

32 33 34 35
constexpr int kEphemeronTableListSegmentSize = 128;
using EphemeronTableList =
    Worklist<EphemeronHashTable, kEphemeronTableListSegmentSize>;

36 37 38
class ScavengerCollector {
 public:
  static const int kMaxScavengerTasks = 8;
39
  static const int kMaxWaitTimeMs = 2;
40 41 42 43 44 45

  explicit ScavengerCollector(Heap* heap);

  void CollectGarbage();

 private:
46 47 48
  void MergeSurvivingNewLargeObjects(
      const SurvivingNewLargeObjectsMap& objects);

49 50
  int NumberOfScavengeTasks();

51 52
  void ProcessWeakReferences(EphemeronTableList* ephemeron_table_list);
  void ClearYoungEphemerons(EphemeronTableList* ephemeron_table_list);
53
  void ClearOldEphemerons();
54 55
  void HandleSurvivingNewLargeObjects();

56 57
  void SweepArrayBufferExtensions();

58 59 60
  void IterateStackAndScavenge(RootScavengeVisitor* root_scavenge_visitor,
                               Scavenger** scavengers, int num_scavenge_tasks,
                               int main_thread_id);
61 62 63
  Isolate* const isolate_;
  Heap* const heap_;
  base::Semaphore parallel_scavenge_semaphore_;
64 65 66
  SurvivingNewLargeObjectsMap surviving_new_large_objects_;

  friend class Scavenger;
67 68
};

69
class Scavenger {
70
 public:
71
  struct PromotionListEntry {
72
    HeapObject heap_object;
73
    Map map;
74 75 76 77 78 79 80 81 82 83
    int size;
  };

  class PromotionList {
   public:
    class View {
     public:
      View(PromotionList* promotion_list, int task_id)
          : promotion_list_(promotion_list), task_id_(task_id) {}

84 85
      inline void PushRegularObject(HeapObject object, int size);
      inline void PushLargeObject(HeapObject object, Map map, int size);
86 87 88 89 90 91 92 93 94 95 96
      inline bool IsEmpty();
      inline size_t LocalPushSegmentSize();
      inline bool Pop(struct PromotionListEntry* entry);
      inline bool IsGlobalPoolEmpty();
      inline bool ShouldEagerlyProcessPromotionList();

     private:
      PromotionList* promotion_list_;
      int task_id_;
    };

97 98 99 100
    explicit PromotionList(int num_tasks)
        : regular_object_promotion_list_(num_tasks),
          large_object_promotion_list_(num_tasks) {}

101 102
    inline void PushRegularObject(int task_id, HeapObject object, int size);
    inline void PushLargeObject(int task_id, HeapObject object, Map map,
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
                                int size);
    inline bool IsEmpty();
    inline size_t LocalPushSegmentSize(int task_id);
    inline bool Pop(int task_id, struct PromotionListEntry* entry);
    inline bool IsGlobalPoolEmpty();
    inline bool ShouldEagerlyProcessPromotionList(int task_id);

   private:
    static const int kRegularObjectPromotionListSegmentSize = 256;
    static const int kLargeObjectPromotionListSegmentSize = 4;

    using RegularObjectPromotionList =
        Worklist<ObjectAndSize, kRegularObjectPromotionListSegmentSize>;
    using LargeObjectPromotionList =
        Worklist<PromotionListEntry, kLargeObjectPromotionListSegmentSize>;

    RegularObjectPromotionList regular_object_promotion_list_;
    LargeObjectPromotionList large_object_promotion_list_;
  };

123 124 125
  static const int kCopiedListSegmentSize = 256;

  using CopiedList = Worklist<ObjectAndSize, kCopiedListSegmentSize>;
126
  Scavenger(ScavengerCollector* collector, Heap* heap, bool is_logging,
127 128
            Worklist<MemoryChunk*, 64>* empty_chunks, CopiedList* copied_list,
            PromotionList* promotion_list,
129
            EphemeronTableList* ephemeron_table_list, int task_id);
130

131 132 133
  // Entry point for scavenging an old generation page. For scavenging single
  // objects see RootScavengingVisitor and ScavengeVisitor below.
  void ScavengePage(MemoryChunk* page);
134 135 136

  // Processes remaining work (=objects) after single objects have been
  // manually scavenged using ScavengeObject or CheckAndScavengeObject.
137
  void Process(OneshotBarrier* barrier = nullptr);
138

139 140 141
  // Finalize the Scavenger. Needs to be called from the main thread.
  void Finalize();

142 143
  void AddEphemeronHashTable(EphemeronHashTable table);

144 145 146
  size_t bytes_copied() const { return copied_size_; }
  size_t bytes_promoted() const { return promoted_size_; }

147
 private:
148 149 150
  // Number of objects to process before interrupting for potentially waking
  // up other tasks.
  static const int kInterruptThreshold = 128;
151 152
  static const int kInitialLocalPretenuringFeedbackCapacity = 256;

153 154
  inline Heap* heap() { return heap_; }

155
  inline void PageMemoryFence(MaybeObject object);
156

157 158
  void AddPageToSweeperIfNecessary(MemoryChunk* page);

159
  // Potentially scavenges an object referenced from |slot| if it is
160
  // indeed a HeapObject and resides in from space.
161 162
  template <typename TSlot>
  inline SlotCallbackResult CheckAndScavengeObject(Heap* heap, TSlot slot);
163 164 165

  // Scavenges an object |object| referenced from slot |p|. |object| is required
  // to be in from space.
166 167
  template <typename THeapObjectSlot>
  inline SlotCallbackResult ScavengeObject(THeapObjectSlot p,
168
                                           HeapObject object);
169

170
  // Copies |source| to |target| and sets the forwarding pointer in |source|.
171
  V8_INLINE bool MigrateObject(Map map, HeapObject source, HeapObject target,
172
                               int size);
173

174 175
  V8_INLINE SlotCallbackResult
  RememberedSetEntryNeeded(CopyAndForwardResult result);
176

177
  template <typename THeapObjectSlot>
178 179 180
  V8_INLINE CopyAndForwardResult
  SemiSpaceCopyObject(Map map, THeapObjectSlot slot, HeapObject object,
                      int object_size, ObjectFields object_fields);
181

182 183
  template <typename THeapObjectSlot>
  V8_INLINE CopyAndForwardResult PromoteObject(Map map, THeapObjectSlot slot,
184
                                               HeapObject object,
185 186
                                               int object_size,
                                               ObjectFields object_fields);
187

188 189
  template <typename THeapObjectSlot>
  V8_INLINE SlotCallbackResult EvacuateObject(THeapObjectSlot slot, Map map,
190
                                              HeapObject source);
191

192 193
  V8_INLINE bool HandleLargeObject(Map map, HeapObject object, int object_size,
                                   ObjectFields object_fields);
194

195
  // Different cases for object evacuation.
196
  template <typename THeapObjectSlot>
197 198 199
  V8_INLINE SlotCallbackResult
  EvacuateObjectDefault(Map map, THeapObjectSlot slot, HeapObject object,
                        int object_size, ObjectFields object_fields);
200

201 202
  template <typename THeapObjectSlot>
  inline SlotCallbackResult EvacuateThinString(Map map, THeapObjectSlot slot,
203
                                               ThinString object,
204 205
                                               int object_size);

206
  template <typename THeapObjectSlot>
207
  inline SlotCallbackResult EvacuateShortcutCandidate(Map map,
208
                                                      THeapObjectSlot slot,
209
                                                      ConsString object,
210
                                                      int object_size);
211

212
  void IterateAndScavengePromotedObject(HeapObject target, Map map, int size);
213
  void RememberPromotedEphemeron(EphemeronHashTable table, int index);
214

215
  ScavengerCollector* const collector_;
216
  Heap* const heap_;
217
  Worklist<MemoryChunk*, 64>::View empty_chunks_;
218
  PromotionList::View promotion_list_;
219
  CopiedList::View copied_list_;
220
  EphemeronTableList::View ephemeron_table_list_;
221
  Heap::PretenuringFeedbackMap local_pretenuring_feedback_;
222 223
  size_t copied_size_;
  size_t promoted_size_;
224
  EvacuationAllocator allocator_;
225
  SurvivingNewLargeObjectsMap surviving_new_large_objects_;
226 227

  EphemeronRememberedSet ephemeron_remembered_set_;
228 229 230
  const bool is_logging_;
  const bool is_incremental_marking_;
  const bool is_compacting_;
231 232

  friend class IterateAndScavengePromotedObjectsVisitor;
233 234
  friend class RootScavengeVisitor;
  friend class ScavengeVisitor;
235 236 237 238
};

// Helper class for turning the scavenger into an object visitor that is also
// filtering out non-HeapObjects and objects which do not reside in new space.
239
class RootScavengeVisitor final : public RootVisitor {
240
 public:
241
  explicit RootScavengeVisitor(Scavenger* scavenger);
242

243 244 245 246
  void VisitRootPointer(Root root, const char* description,
                        FullObjectSlot p) final;
  void VisitRootPointers(Root root, const char* description,
                         FullObjectSlot start, FullObjectSlot end) final;
247

248
 private:
249
  void ScavengePointer(FullObjectSlot p);
250

251
  Scavenger* const scavenger_;
252 253
};

254
class ScavengeVisitor final : public NewSpaceVisitor<ScavengeVisitor> {
255
 public:
256
  explicit ScavengeVisitor(Scavenger* scavenger);
257

258
  V8_INLINE void VisitPointers(HeapObject host, ObjectSlot start,
259
                               ObjectSlot end) final;
260

261
  V8_INLINE void VisitPointers(HeapObject host, MaybeObjectSlot start,
262
                               MaybeObjectSlot end) final;
263

264
  V8_INLINE void VisitCodeTarget(Code host, RelocInfo* rinfo) final;
265
  V8_INLINE void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final;
266
  V8_INLINE int VisitEphemeronHashTable(Map map, EphemeronHashTable object);
267
  V8_INLINE int VisitJSArrayBuffer(Map map, JSArrayBuffer object);
268

269
 private:
270
  template <typename TSlot>
271
  V8_INLINE void VisitHeapObjectImpl(TSlot slot, HeapObject heap_object);
272

273
  template <typename TSlot>
274
  V8_INLINE void VisitPointersImpl(HeapObject host, TSlot start, TSlot end);
275

276
  Scavenger* const scavenger_;
277 278 279 280 281 282
};

}  // namespace internal
}  // namespace v8

#endif  // V8_HEAP_SCAVENGER_H_