Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of allocating different sizes of storage in StorageProvider #1504

Open
wants to merge 2 commits into
base: static_h
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
436 changes: 228 additions & 208 deletions include/hermes/VM/AlignedHeapSegment.h

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion include/hermes/VM/CardTableNC.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace vm {

/// The card table optimizes young gen collections by restricting the amount of
/// heap belonging to the old gen that must be scanned. The card table expects
/// to be constructed inside an AlignedHeapSegment's storage, at some position
/// to be constructed inside an FixedSizeHeapSegment's storage, at some position
/// before the allocation region, and covers the extent of that storage's
/// memory.
///
Expand Down
2 changes: 1 addition & 1 deletion include/hermes/VM/GCBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ enum XorPtrKeyID {
/// Return the maximum amount of bytes holdable by this heap.
/// gcheapsize_t max() const;
/// Return the total amount of bytes of storage this GC will require.
/// This will be a multiple of AlignedHeapSegment::storageSize().
/// This will be a multiple of FixedSizeHeapSegment::storageSize().
/// gcheapsize_t storageFootprint() const;
///
class GCBase {
Expand Down
50 changes: 25 additions & 25 deletions include/hermes/VM/HadesGC.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class HadesGC final : public GCBase {
static constexpr uint32_t maxAllocationSizeImpl() {
// The largest allocation allowable in Hades is the max size a single
// segment supports.
return AlignedHeapSegment::maxSize();
return FixedSizeHeapSegment::maxSize();
}

static constexpr uint32_t minAllocationSizeImpl() {
Expand Down Expand Up @@ -297,7 +297,7 @@ class HadesGC final : public GCBase {

/// \return true if the pointer lives in the young generation.
bool inYoungGen(const void *p) const override {
return youngGen_.lowLim() == AlignedHeapSegment::storageStart(p);
return youngGen_.lowLim() == FixedSizeHeapSegment::storageStart(p);
}
bool inYoungGen(CompressedPointer p) const {
return p.getSegmentStart() == youngGenCP_;
Expand Down Expand Up @@ -361,34 +361,34 @@ class HadesGC final : public GCBase {
/// Call \p callback on every non-freelist cell allocated in this segment.
template <typename CallbackFunction>
static void forAllObjsInSegment(
AlignedHeapSegment &seg,
FixedSizeHeapSegment &seg,
CallbackFunction callback);
/// Only call the callback on cells without forwarding pointers.
template <typename CallbackFunction>
static void forCompactedObjsInSegment(
AlignedHeapSegment &seg,
FixedSizeHeapSegment &seg,
CallbackFunction callback,
PointerBase &base);

class OldGen final {
public:
explicit OldGen(HadesGC &gc);

std::deque<AlignedHeapSegment>::iterator begin();
std::deque<AlignedHeapSegment>::iterator end();
std::deque<AlignedHeapSegment>::const_iterator begin() const;
std::deque<AlignedHeapSegment>::const_iterator end() const;
std::deque<FixedSizeHeapSegment>::iterator begin();
std::deque<FixedSizeHeapSegment>::iterator end();
std::deque<FixedSizeHeapSegment>::const_iterator begin() const;
std::deque<FixedSizeHeapSegment>::const_iterator end() const;

size_t numSegments() const;

AlignedHeapSegment &operator[](size_t i);
FixedSizeHeapSegment &operator[](size_t i);

/// Take ownership of the given segment.
void addSegment(AlignedHeapSegment seg);
void addSegment(FixedSizeHeapSegment seg);

/// Remove the last segment from the OG.
/// \return the segment that was removed.
AlignedHeapSegment popSegment();
FixedSizeHeapSegment popSegment();

/// Indicate that OG should target having a size of \p targetSizeBytes.
void setTargetSizeBytes(size_t targetSizeBytes);
Expand Down Expand Up @@ -507,7 +507,7 @@ class HadesGC final : public GCBase {
static constexpr size_t kMinSizeForLargeBlock = 1
<< kLogMinSizeForLargeBlock;
static constexpr size_t kNumLargeFreelistBuckets =
llvh::detail::ConstantLog2<AlignedHeapSegment::maxSize()>::value -
llvh::detail::ConstantLog2<FixedSizeHeapSegment::maxSize()>::value -
kLogMinSizeForLargeBlock + 1;
static constexpr size_t kNumFreelistBuckets =
kNumSmallFreelistBuckets + kNumLargeFreelistBuckets;
Expand Down Expand Up @@ -578,7 +578,7 @@ class HadesGC final : public GCBase {

/// Use a std::deque instead of a std::vector so that references into it
/// remain valid across a push_back.
std::deque<AlignedHeapSegment> segments_;
std::deque<FixedSizeHeapSegment> segments_;

/// See \c targetSizeBytes() above.
ExponentialMovingAverage targetSizeBytes_{0, 0};
Expand Down Expand Up @@ -660,9 +660,9 @@ class HadesGC final : public GCBase {
/// Keeps the storage provider alive until after the GC is fully destructed.
std::shared_ptr<StorageProvider> provider_;

/// youngGen is a bump-pointer space, so it can re-use AlignedHeapSegment.
/// youngGen is a bump-pointer space, so it can re-use FixedSizeHeapSegment.
/// Protected by gcMutex_.
AlignedHeapSegment youngGen_;
FixedSizeHeapSegment youngGen_;
AssignableCompressedPointer youngGenCP_;

/// List of cells in YG that have finalizers. Iterate through this to clean
Expand All @@ -672,7 +672,7 @@ class HadesGC final : public GCBase {

/// Since YG collection times are the primary driver of pause times, it is
/// useful to have a knob to reduce the effective size of the YG. This number
/// is the fraction of AlignedHeapSegment::maxSize() that we should use for
/// is the fraction of FixedSizeHeapSegment::maxSize() that we should use for
/// the YG.. Note that we only set the YG size using this at the end of the
/// first real YG, since doing it for direct promotions would waste OG memory
/// without a pause time benefit.
Expand Down Expand Up @@ -772,7 +772,7 @@ class HadesGC final : public GCBase {
/// \return true if the pointer lives in the segment that is being marked or
/// evacuated for compaction.
bool contains(const void *p) const {
return start == AlignedHeapSegment::storageStart(p);
return start == FixedSizeHeapSegment::storageStart(p);
}
bool contains(CompressedPointer p) const {
return p.getSegmentStart() == startCP;
Expand All @@ -781,7 +781,7 @@ class HadesGC final : public GCBase {
/// \return true if the pointer lives in the segment that is currently being
/// evacuated for compaction.
bool evacContains(const void *p) const {
return evacStart == AlignedHeapSegment::storageStart(p);
return evacStart == FixedSizeHeapSegment::storageStart(p);
}
bool evacContains(CompressedPointer p) const {
return p.getSegmentStart() == evacStartCP;
Expand Down Expand Up @@ -829,7 +829,7 @@ class HadesGC final : public GCBase {
/// The segment being compacted. This should be removed from the OG right
/// after it is identified, and freed entirely once the compaction is
/// complete.
std::shared_ptr<AlignedHeapSegment> segment;
std::shared_ptr<FixedSizeHeapSegment> segment;
} compactee_;

/// The number of compactions this GC has performed.
Expand Down Expand Up @@ -964,7 +964,7 @@ class HadesGC final : public GCBase {
template <bool CompactionEnabled>
void scanDirtyCardsForSegment(
EvacAcceptor<CompactionEnabled> &acceptor,
AlignedHeapSegment &segment);
FixedSizeHeapSegment &segment);

/// Find all pointers from OG into the YG/compactee during a YG collection.
/// This is done quickly through use of write barriers that detect the
Expand Down Expand Up @@ -1011,19 +1011,19 @@ class HadesGC final : public GCBase {
uint64_t heapFootprint() const;

/// Accessor for the YG.
AlignedHeapSegment &youngGen() {
FixedSizeHeapSegment &youngGen() {
return youngGen_;
}
const AlignedHeapSegment &youngGen() const {
const FixedSizeHeapSegment &youngGen() const {
return youngGen_;
}

/// Create a new segment (to be used by either YG or OG).
llvh::ErrorOr<AlignedHeapSegment> createSegment();
llvh::ErrorOr<FixedSizeHeapSegment> createSegment();

/// Set a given segment as the YG segment.
/// \return the previous YG segment.
AlignedHeapSegment setYoungGen(AlignedHeapSegment seg);
FixedSizeHeapSegment setYoungGen(FixedSizeHeapSegment seg);

/// Get/set the current number of external bytes used by the YG.
size_t getYoungGenExternalBytes() const;
Expand All @@ -1048,7 +1048,7 @@ class HadesGC final : public GCBase {
/// \param extraName append this to the name of the segment. Must be
/// non-empty.
void addSegmentExtentToCrashManager(
const AlignedHeapSegment &seg,
const FixedSizeHeapSegment &seg,
const std::string &extraName);

/// Deletes a segment from the CrashManager's custom data.
Expand Down
8 changes: 4 additions & 4 deletions include/hermes/VM/HeapRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class HeapRuntime {
public:
~HeapRuntime() {
runtime_->~RT();
sp_->deleteStorage(runtime_);
sp_->deleteStorage(runtime_, kHeapRuntimeStorageSize);
}

/// Allocate a segment and create an aliased shared_ptr that points to the
Expand All @@ -36,16 +36,16 @@ class HeapRuntime {

private:
HeapRuntime(std::shared_ptr<StorageProvider> sp) : sp_{std::move(sp)} {
auto ptrOrError = sp_->newStorage("hermes-rt");
auto ptrOrError = sp_->newStorage(kHeapRuntimeStorageSize, "hermes-rt");
if (!ptrOrError)
hermes_fatal("Cannot initialize Runtime storage.", ptrOrError.getError());
static_assert(
sizeof(RT) < AlignedHeapSegment::storageSize(), "Segments too small.");
static_assert(sizeof(RT) < kHeapRuntimeStorageSize, "Segments too small.");
runtime_ = static_cast<RT *>(*ptrOrError);
}

std::shared_ptr<StorageProvider> sp_;
RT *runtime_;
static constexpr size_t kHeapRuntimeStorageSize = FixedSizeHeapSegment::kSize;
};
} // namespace vm
} // namespace hermes
Expand Down
4 changes: 2 additions & 2 deletions include/hermes/VM/LimitedStorageProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ class LimitedStorageProvider final : public StorageProvider {
: delegate_(std::move(provider)), limit_(limit) {}

protected:
llvh::ErrorOr<void *> newStorageImpl(const char *name) override;
llvh::ErrorOr<void *> newStorageImpl(size_t sz, const char *name) override;

void deleteStorageImpl(void *storage) override;
void deleteStorageImpl(void *storage, size_t sz) override;
};

} // namespace vm
Expand Down
29 changes: 15 additions & 14 deletions include/hermes/VM/StorageProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,17 @@ class StorageProvider {

/// @}

/// Create a new segment memory space.
llvh::ErrorOr<void *> newStorage() {
return newStorage(nullptr);
}
/// Create a new segment memory space and give this memory the name \p name.
/// \return A pointer to a block of memory that has
/// AlignedHeapSegment::storageSize() bytes, and is aligned on
/// AlignedHeapSegment::storageSize().
llvh::ErrorOr<void *> newStorage(const char *name);
/// \return A pointer to a block of memory that has \p sz bytes, and is
/// aligned on AlignedHeapSegment::kSegmentUnitSize. Note that \p sz must
/// be non-zero and equals to a multiple of
/// AlignedHeapSegment::kSegmentUnitSize.
llvh::ErrorOr<void *> newStorage(size_t sz, const char *name = nullptr);

/// Delete the given segment's memory space, and make it available for re-use.
/// \post Nothing in the range [storage, storage +
/// AlignedHeapSegment::storageSize()) is valid memory to be read or written.
void deleteStorage(void *storage);
/// Note that \p sz must be the same as used to allocating \p storage.
/// \post Nothing in the range [storage, storage + sz) is valid memory to be
/// read or written.
void deleteStorage(void *storage, size_t sz);

/// The number of storages this provider has allocated in its lifetime.
size_t numSucceededAllocs() const;
Expand All @@ -67,8 +64,12 @@ class StorageProvider {
size_t numLiveAllocs() const;

protected:
virtual llvh::ErrorOr<void *> newStorageImpl(const char *name) = 0;
virtual void deleteStorageImpl(void *storage) = 0;
/// \pre \p sz is non-zero and equals to a multiple of
/// AlignedHeapSegment::kSegmentUnitSize.
virtual llvh::ErrorOr<void *> newStorageImpl(size_t sz, const char *name) = 0;
/// \pre \p sz is non-zero and equals to a multiple of
/// AlignedHeapSegment::kSegmentUnitSize.
virtual void deleteStorageImpl(void *storage, size_t sz) = 0;

private:
size_t numSucceededAllocs_{0};
Expand Down
16 changes: 9 additions & 7 deletions lib/VM/LimitedStorageProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@
namespace hermes {
namespace vm {

llvh::ErrorOr<void *> LimitedStorageProvider::newStorageImpl(const char *name) {
if (limit_ < AlignedHeapSegment::storageSize()) {
llvh::ErrorOr<void *> LimitedStorageProvider::newStorageImpl(
size_t sz,
const char *name) {
if (limit_ < FixedSizeHeapSegment::storageSize()) {
return make_error_code(OOMError::TestVMLimitReached);
}
limit_ -= AlignedHeapSegment::storageSize();
return delegate_->newStorage(name);
limit_ -= sz;
return delegate_->newStorage(sz, name);
}

void LimitedStorageProvider::deleteStorageImpl(void *storage) {
void LimitedStorageProvider::deleteStorageImpl(void *storage, size_t sz) {
if (!storage) {
return;
}
delegate_->deleteStorage(storage);
limit_ += AlignedHeapSegment::storageSize();
delegate_->deleteStorage(storage, sz);
limit_ += sz;
}

} // namespace vm
Expand Down
11 changes: 6 additions & 5 deletions lib/VM/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ std::shared_ptr<Runtime> Runtime::create(const RuntimeConfig &runtimeConfig) {
uint64_t maxHeapSize = runtimeConfig.getGCConfig().getMaxHeapSize();
// Allow some extra segments for the runtime, and as a buffer for the GC.
uint64_t providerSize = std::min<uint64_t>(
1ULL << 32, maxHeapSize + AlignedHeapSegment::storageSize() * 4);
1ULL << 32, maxHeapSize + FixedSizeHeapSegment::storageSize() * 4);
std::shared_ptr<StorageProvider> sp =
StorageProvider::contiguousVAProvider(providerSize);
auto rt = HeapRuntime<Runtime>::create(sp);
Expand Down Expand Up @@ -248,12 +248,13 @@ RuntimeBase::RuntimeBase() {

void RuntimeBase::registerHeapSegment(unsigned idx, void *lowLim) {
#if defined(HERMESVM_COMPRESSED_POINTERS) && !defined(HERMESVM_CONTIGUOUS_HEAP)
char *bias =
reinterpret_cast<char *>(lowLim) - (idx << AlignedHeapSegment::kLogSize);
char *bias = reinterpret_cast<char *>(lowLim) -
(idx << FixedSizeHeapSegment::kLogSize);
segmentMap[idx] = bias;
#endif
assert(lowLim == AlignedHeapSegment::storageStart(lowLim) && "Precondition");
AlignedHeapSegment::setSegmentIndexFromStart(lowLim, idx);
assert(
lowLim == FixedSizeHeapSegment::storageStart(lowLim) && "Precondition");
FixedSizeHeapSegment::setSegmentIndexFromStart(lowLim, idx);
}

Runtime::Runtime(
Expand Down
Loading
Loading