scavenger.h 9.54 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 18
class OneshotBarrier;

19 20 21 22 23 24
enum class CopyAndForwardResult {
  SUCCESS_YOUNG_GENERATION,
  SUCCESS_OLD_GENERATION,
  FAILURE
};

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

30 31 32 33
constexpr int kEphemeronTableListSegmentSize = 128;
using EphemeronTableList =
    Worklist<EphemeronHashTable, kEphemeronTableListSegmentSize>;

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

  explicit ScavengerCollector(Heap* heap);

  void CollectGarbage();

 private:
44 45 46
  void MergeSurvivingNewLargeObjects(
      const SurvivingNewLargeObjectsMap& objects);

47 48
  int NumberOfScavengeTasks();

49 50
  void ProcessWeakReferences(EphemeronTableList* ephemeron_table_list);
  void ClearYoungEphemerons(EphemeronTableList* ephemeron_table_list);
51
  void ClearOldEphemerons();
52 53
  void HandleSurvivingNewLargeObjects();

54 55 56
  Isolate* const isolate_;
  Heap* const heap_;
  base::Semaphore parallel_scavenge_semaphore_;
57 58 59
  SurvivingNewLargeObjectsMap surviving_new_large_objects_;

  friend class Scavenger;
60 61
};

62
class Scavenger {
63
 public:
64
  struct PromotionListEntry {
65
    HeapObject heap_object;
66
    Map map;
67 68 69 70 71 72 73 74 75 76
    int size;
  };

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

77 78
      inline void PushRegularObject(HeapObject object, int size);
      inline void PushLargeObject(HeapObject object, Map map, int size);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
      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_;
    };

    explicit PromotionList(int num_tasks)
        : regular_object_promotion_list_(num_tasks),
          large_object_promotion_list_(num_tasks) {}

94 95
    inline void PushRegularObject(int task_id, HeapObject object, int size);
    inline void PushLargeObject(int task_id, HeapObject object, Map map,
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
                                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_;
  };

116 117 118
  static const int kCopiedListSegmentSize = 256;

  using CopiedList = Worklist<ObjectAndSize, kCopiedListSegmentSize>;
119
  Scavenger(ScavengerCollector* collector, Heap* heap, bool is_logging,
120 121
            Worklist<MemoryChunk*, 64>* empty_chunks, CopiedList* copied_list,
            PromotionList* promotion_list,
122
            EphemeronTableList* ephemeron_table_list, int task_id);
123

124 125 126
  // Entry point for scavenging an old generation page. For scavenging single
  // objects see RootScavengingVisitor and ScavengeVisitor below.
  void ScavengePage(MemoryChunk* page);
127 128 129

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

132 133 134
  // Finalize the Scavenger. Needs to be called from the main thread.
  void Finalize();

135 136
  void AddEphemeronHashTable(EphemeronHashTable table);

137 138 139
  size_t bytes_copied() const { return copied_size_; }
  size_t bytes_promoted() const { return promoted_size_; }

140
 private:
141 142 143
  // Number of objects to process before interrupting for potentially waking
  // up other tasks.
  static const int kInterruptThreshold = 128;
144 145
  static const int kInitialLocalPretenuringFeedbackCapacity = 256;

146 147
  inline Heap* heap() { return heap_; }

148
  inline void PageMemoryFence(MaybeObject object);
149

150 151
  void AddPageToSweeperIfNecessary(MemoryChunk* page);

152
  // Potentially scavenges an object referenced from |slot| if it is
153
  // indeed a HeapObject and resides in from space.
154 155
  template <typename TSlot>
  inline SlotCallbackResult CheckAndScavengeObject(Heap* heap, TSlot slot);
156 157 158

  // Scavenges an object |object| referenced from slot |p|. |object| is required
  // to be in from space.
159 160
  template <typename THeapObjectSlot>
  inline SlotCallbackResult ScavengeObject(THeapObjectSlot p,
161
                                           HeapObject object);
162

163
  // Copies |source| to |target| and sets the forwarding pointer in |source|.
164
  V8_INLINE bool MigrateObject(Map map, HeapObject source, HeapObject target,
165
                               int size);
166

167 168
  V8_INLINE SlotCallbackResult
  RememberedSetEntryNeeded(CopyAndForwardResult result);
169

170
  template <typename THeapObjectSlot>
171 172 173
  V8_INLINE CopyAndForwardResult
  SemiSpaceCopyObject(Map map, THeapObjectSlot slot, HeapObject object,
                      int object_size, ObjectFields object_fields);
174

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

181 182
  template <typename THeapObjectSlot>
  V8_INLINE SlotCallbackResult EvacuateObject(THeapObjectSlot slot, Map map,
183
                                              HeapObject source);
184

185 186
  V8_INLINE bool HandleLargeObject(Map map, HeapObject object, int object_size,
                                   ObjectFields object_fields);
187

188
  // Different cases for object evacuation.
189
  template <typename THeapObjectSlot>
190 191 192
  V8_INLINE SlotCallbackResult
  EvacuateObjectDefault(Map map, THeapObjectSlot slot, HeapObject object,
                        int object_size, ObjectFields object_fields);
193

194 195
  template <typename THeapObjectSlot>
  inline SlotCallbackResult EvacuateThinString(Map map, THeapObjectSlot slot,
196
                                               ThinString object,
197 198
                                               int object_size);

199
  template <typename THeapObjectSlot>
200
  inline SlotCallbackResult EvacuateShortcutCandidate(Map map,
201
                                                      THeapObjectSlot slot,
202
                                                      ConsString object,
203
                                                      int object_size);
204

205
  void IterateAndScavengePromotedObject(HeapObject target, Map map, int size);
206
  void RememberPromotedEphemeron(EphemeronHashTable table, int index);
207

208
  ScavengerCollector* const collector_;
209
  Heap* const heap_;
210
  Worklist<MemoryChunk*, 64>::View empty_chunks_;
211
  PromotionList::View promotion_list_;
212
  CopiedList::View copied_list_;
213
  EphemeronTableList::View ephemeron_table_list_;
214
  Heap::PretenuringFeedbackMap local_pretenuring_feedback_;
215 216
  size_t copied_size_;
  size_t promoted_size_;
217
  LocalAllocator allocator_;
218
  SurvivingNewLargeObjectsMap surviving_new_large_objects_;
219 220

  EphemeronRememberedSet ephemeron_remembered_set_;
221 222 223
  const bool is_logging_;
  const bool is_incremental_marking_;
  const bool is_compacting_;
224 225

  friend class IterateAndScavengePromotedObjectsVisitor;
226 227
  friend class RootScavengeVisitor;
  friend class ScavengeVisitor;
228 229 230 231
};

// 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.
232
class RootScavengeVisitor final : public RootVisitor {
233
 public:
234
  explicit RootScavengeVisitor(Scavenger* scavenger);
235

236 237 238 239
  void VisitRootPointer(Root root, const char* description,
                        FullObjectSlot p) final;
  void VisitRootPointers(Root root, const char* description,
                         FullObjectSlot start, FullObjectSlot end) final;
240

241
 private:
242
  void ScavengePointer(FullObjectSlot p);
243

244
  Scavenger* const scavenger_;
245 246
};

247
class ScavengeVisitor final : public NewSpaceVisitor<ScavengeVisitor> {
248
 public:
249
  explicit ScavengeVisitor(Scavenger* scavenger);
250

251
  V8_INLINE void VisitPointers(HeapObject host, ObjectSlot start,
252
                               ObjectSlot end) final;
253

254
  V8_INLINE void VisitPointers(HeapObject host, MaybeObjectSlot start,
255
                               MaybeObjectSlot end) final;
256

257
  V8_INLINE void VisitCodeTarget(Code host, RelocInfo* rinfo) final;
258
  V8_INLINE void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final;
259
  V8_INLINE int VisitEphemeronHashTable(Map map, EphemeronHashTable object);
260

261
 private:
262
  template <typename TSlot>
263
  V8_INLINE void VisitHeapObjectImpl(TSlot slot, HeapObject heap_object);
264

265
  template <typename TSlot>
266
  V8_INLINE void VisitPointersImpl(HeapObject host, TSlot start, TSlot end);
267

268
  Scavenger* const scavenger_;
269 270 271 272 273 274
};

}  // namespace internal
}  // namespace v8

#endif  // V8_HEAP_SCAVENGER_H_