1212#include " hermes/VM/GCBase.h"
1313
1414#include < cstdint>
15+ #include < deque>
16+ #include < memory>
17+ #include < vector>
1518
1619namespace hermes {
1720namespace vm {
@@ -55,6 +58,8 @@ class HadesGC final : public GCBase {
5558
5659 ~HadesGC ();
5760
61+ static uint32_t minAllocationSize ();
62+
5863 static constexpr uint32_t maxAllocationSize () {
5964 // The largest allocation allowable in Hades is the max size a single
6065 // segment supports.
@@ -64,9 +69,11 @@ class HadesGC final : public GCBase {
6469 // / \name GCBase overrides
6570 // / \{
6671
72+ void getHeapInfo (HeapInfo &info) override ;
6773 void getHeapInfoWithMallocSize (HeapInfo &info) override ;
6874 void getCrashManagerHeapInfo (CrashManager::HeapInformation &info) override ;
6975 void createSnapshot (llvm::raw_ostream &os) override ;
76+ void printStats (llvm::raw_ostream &os, bool trailingComma) override ;
7077
7178 // / \}
7279
@@ -89,7 +96,7 @@ class HadesGC final : public GCBase {
8996 // / \tparam hasFinalizer Indicates whether the object being allocated will
9097 // / have a finalizer.
9198 template <HasFinalizer hasFinalizer = HasFinalizer::No>
92- inline void *allocLongLived (uint32_t size );
99+ inline void *allocLongLived (uint32_t sz );
93100
94101 // / Force a garbage collection cycle.
95102 // / (Part of general GC API defined in GCBase.h).
@@ -141,6 +148,9 @@ class HadesGC final : public GCBase {
141148
142149 // / \}
143150
151+ // / \return true if the pointer lives in the young generation.
152+ bool inYoungGen (const void *p) const ;
153+
144154#ifndef NDEBUG
145155 // / \name Debug APIs
146156 // / \{
@@ -168,20 +178,150 @@ class HadesGC final : public GCBase {
168178 // / \}
169179#endif
170180
181+ class HeapSegment ;
182+ class CollectionSection ;
183+ class EvacAcceptor ;
184+ class MarkAcceptor ;
185+ class WeakRootAcceptor ;
186+
171187 private:
188+ const uint64_t maxHeapSize_;
189+
190+ // / Keeps the storage provider alive until after the GC is fully destructed.
191+ std::shared_ptr<StorageProvider> provider_;
192+
193+ // / youngGen is a bump-pointer space, so it can re-use AlignedHeapSegment.
194+ std::unique_ptr<HeapSegment> youngGen_;
195+ // / List of cells in YG that have finalizers. Iterate through this to clean
196+ // / them out.
197+ std::vector<GCCell *> youngGenFinalizables_;
198+
199+ // / oldGen_ is a free list space, so it needs a different segment
200+ // / representation.
201+ std::vector<std::unique_ptr<HeapSegment>> oldGen_;
202+
203+ // / weakPointers_ is a list of all the weak pointers in the system. They are
204+ // / invalidated if they point to an object that is dead, and do not count
205+ // / towards whether an object is live or dead.
206+ std::deque<WeakRefSlot> weakPointers_;
207+
208+ // / The main entrypoint for all allocations.
209+ // / \param sz The size of allocation requested. This might be rounded up to
210+ // / fit heap alignment requirements.
211+ // / \param longLived If true, allocate directly into OG, instead of YG.
212+ // / \param fixedSize If true, the allocation is of a cell type that always has
213+ // / the same size. The requirement enforced by Hades is that all fixed-size
214+ // / allocations must go into YG, unless \p longLived is also true.
215+ // / \param hasFinalizer If true, the cell about to be allocated into the
216+ // / requested space will have a finalizer that the GC will need to invoke.
217+ void *allocWork (
218+ uint32_t sz,
219+ bool longLived,
220+ bool fixedSize,
221+ HasFinalizer hasFinalizer);
222+
223+ // / Allocate into OG. Returns a pointer to the newly allocated space. That
224+ // / space must be filled immediately after this call completes.
225+ // / \return A non-null pointer to memory in the old gen that should have a
226+ // / constructor run in immediately.
227+ // / \post This function either successfully allocates, or reports OOM.
228+ GCCell *oldGenAlloc (uint32_t sz);
229+
230+ // / Searches the OG for a space to allocate memory into.
231+ // / \return A pointer to uninitialized memory that can be written into, null
232+ // / if no such space exists.
233+ // / NOTE: oldGenAlloc should be called instead, which will try to do
234+ // / collections until this function returns a non-null pointer.
235+ GCCell *oldGenSearch (uint32_t sz);
236+
237+ // / Frees the weak slot, so it can be re-used by future WeakRef allocations.
238+ void freeWeakSlot (WeakRefSlot *slot);
239+
240+ // / Perform a YG garbage collection. All live objects in YG will be evacuated
241+ // / to the OG.
242+ // / \post The YG is completely empty, and all bytes are available for new
243+ // / allocations.
244+ void youngGenCollection (bool allowOGBegin);
245+
246+ // / Perform an OG garbage collection. All live objects in OG will be left
247+ // / untouched, all unreachable objects will be placed into a free list that
248+ // / can be used by \c oldGenAlloc.
249+ void oldGenCollection ();
250+
251+ // / Find all pointers from OG into YG during a YG collection. This is done
252+ // / quickly through use of write barriers that detect the creation of OG-to-YG
253+ // / pointers.
254+ void scanDirtyCards (EvacAcceptor &acceptor);
255+
256+ // / Finalize all objects in YG that have finalizers.
257+ void finalizeYoungGenObjects ();
258+
259+ // / Update all of the weak references and invalidate the ones that point to
260+ // / dead objects.
261+ void updateWeakReferencesForYoungGen ();
262+
263+ // / Update all of the weak references, invalidate the ones that point to
264+ // / dead objects, and free the ones that were not marked at all.
265+ void updateWeakReferencesForOldGen ();
266+
267+ // / The WeakMap type in JS has special semantics for handling keys kept alive
268+ // / by only their values. In between marking and sweeping, this function is
269+ // / called to handle that special case.
270+ void completeWeakMapMarking (MarkAcceptor &acceptor);
271+
272+ // / Sets all weak references to unmarked in preparation for a collection.
273+ void resetWeakReferences ();
274+
275+ // / Return the total number of bytes that are in use by the JS heap.
276+ uint64_t allocatedBytes ();
277+
278+ // / Return the total number of bytes that are in use by the OG section of the
279+ // / JS heap.
280+ uint64_t oldGenAllocatedBytes ();
281+
282+ // / Accessor for the YG.
283+ HeapSegment &youngGen ();
284+ const HeapSegment &youngGen () const ;
285+
286+ // / Accessors for the segments of OG.
287+ std::vector<std::unique_ptr<HeapSegment>>::iterator oldGenBegin ();
288+ std::vector<std::unique_ptr<HeapSegment>>::const_iterator oldGenBegin () const ;
289+
290+ std::vector<std::unique_ptr<HeapSegment>>::iterator oldGenEnd ();
291+ std::vector<std::unique_ptr<HeapSegment>>::const_iterator oldGenEnd () const ;
292+
293+ // / Create a new OG segment and attach it to the end of the OG segment vector.
294+ // / \return a reference to the newly created segment.
295+ HeapSegment &createOldGenSegment ();
296+
297+ // / Searches the old gen for this pointer. This is O(number of OG segments).
298+ // / NOTE: In any non-debug case, \c inYoungGen should be used instead, because
299+ // / it is O(1).
300+ // / \return true if the pointer is in the old gen.
301+ bool inOldGen (const void *p) const ;
302+
303+ #ifdef HERMES_SLOW_DEBUG
304+ // / Checks the heap to make sure all cells are valid.
305+ void checkWellFormed ();
306+
307+ // / Verify that the card table used to find pointers from OG into YG has the
308+ // / correct cards dirtied, given the contents of the OG currently.
309+ void verifyCardTable ();
310+ void verifyCardTableBoundaries () const ;
311+ #endif
172312};
173313
174314// / \name Inline implementations
175315// / \{
176316
177317template <bool fixedSize, HasFinalizer hasFinalizer>
178318void *HadesGC::alloc (uint32_t sz) {
179- return nullptr ;
319+ return allocWork (sz, false , fixedSize, hasFinalizer) ;
180320}
181321
182322template <HasFinalizer hasFinalizer>
183- void *HadesGC::allocLongLived (uint32_t size ) {
184- return nullptr ;
323+ void *HadesGC::allocLongLived (uint32_t sz ) {
324+ return allocWork (sz, true , false , hasFinalizer) ;
185325}
186326
187327// / \}
0 commit comments