Skip to content

Commit

Permalink
[JSC] Use libpas' zeroed-allocation for zero-filling typed array allo…
Browse files Browse the repository at this point in the history
…cations

https://bugs.webkit.org/show_bug.cgi?id=259765
rdar://113315414

Reviewed by Mark Lam.

It turned out that large typed array can consume long time for zeroing its backing store.
But libpas already knows that this is zero-filled or not (for example, newly allocated pages are zeroed),
and libpas have try_allocate_zeroed APIs to return efficiently zero-filled memory.
This patch leverages this for TypedArray allocations.

* Source/JavaScriptCore/runtime/ArrayBuffer.cpp:
(JSC::ArrayBufferContents::tryAllocate):
* Source/JavaScriptCore/runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
* Source/WTF/wtf/FastMalloc.cpp:
(WTF::fastZeroedMalloc):
(WTF::tryFastZeroedMalloc):
* Source/WTF/wtf/Gigacage.cpp:
(Gigacage::tryZeroedMalloc):
(Gigacage::zeroedMalloc):
* Source/WTF/wtf/Gigacage.h:
* Source/bmalloc/bmalloc/bmalloc.h:
(bmalloc::api::tryZeroedMalloc):
(bmalloc::api::zeroedMalloc):

Canonical link: https://commits.webkit.org/266536@main
  • Loading branch information
Constellation committed Aug 3, 2023
1 parent dc06957 commit ad82b55
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 24 deletions.
9 changes: 5 additions & 4 deletions Source/JavaScriptCore/runtime/ArrayBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,16 @@ void ArrayBufferContents::tryAllocate(size_t numElements, unsigned elementByteSi
if (!allocationSize)
allocationSize = 1; // Make sure malloc actually allocates something, but not too much. We use null to mean that the buffer is detached.

void* data = Gigacage::tryMalloc(Gigacage::Primitive, allocationSize);
void* data = nullptr;
if (policy == InitializationPolicy::ZeroInitialize)
data = Gigacage::tryZeroedMalloc(Gigacage::Primitive, allocationSize);
else
data = Gigacage::tryMalloc(Gigacage::Primitive, allocationSize);
m_data = DataType(data, sizeInBytes.value());
if (!data) {
reset();
return;
}

if (policy == InitializationPolicy::ZeroInitialize)
memset(data, 0, allocationSize);

m_sizeInBytes = sizeInBytes.value();
RELEASE_ASSERT(m_sizeInBytes <= MAX_ARRAY_BUFFER_SIZE);
Expand Down
11 changes: 7 additions & 4 deletions Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,15 @@ JSArrayBufferView::ConstructionContext::ConstructionContext(VM& vm, Structure* s
if (size.hasOverflowed() || size > MAX_ARRAY_BUFFER_SIZE)
return;

m_vector = VectorType(Gigacage::tryMalloc(Gigacage::Primitive, size.value()), m_length);
void* memory = nullptr;
if (mode == ZeroFill)
memory = Gigacage::tryZeroedMalloc(Gigacage::Primitive, size.value());
else
memory = Gigacage::tryMalloc(Gigacage::Primitive, size.value());
m_vector = VectorType(memory, m_length);
if (!m_vector)
return;
if (mode == ZeroFill)
memset(vector(), 0, size);


vm.heap.reportExtraMemoryAllocated(size.value());

m_structure = structure;
Expand Down
51 changes: 35 additions & 16 deletions Source/WTF/wtf/FastMalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,6 @@ void fastSetMaxSingleAllocationSize(size_t size)

#endif // !defined(NDEBUG)

void* fastZeroedMalloc(size_t n)
{
void* result = fastMalloc(n);
memset(result, 0, n);
return result;
}

char* fastStrDup(const char* src)
{
size_t len = strlen(src) + 1;
Expand All @@ -142,15 +135,6 @@ void* fastMemDup(const void* mem, size_t bytes)
return result;
}

TryMallocReturnValue tryFastZeroedMalloc(size_t n)
{
void* result;
if (!tryFastMalloc(n).getValue(result))
return nullptr;
memset(result, 0, n);
return result;
}

} // namespace WTF

#if USE(SYSTEM_MALLOC)
Expand Down Expand Up @@ -244,6 +228,22 @@ void* fastMalloc(size_t n)
return result;
}

void* fastZeroedMalloc(size_t n)
{
void* result = fastMalloc(n);
memset(result, 0, n);
return result;
}

TryMallocReturnValue tryFastZeroedMalloc(size_t n)
{
void* result;
if (!tryFastMalloc(n).getValue(result))
return nullptr;
memset(result, 0, n);
return result;
}

TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size)
{
FAIL_IF_EXCEEDS_LIMIT(n_elements * element_size);
Expand Down Expand Up @@ -538,6 +538,25 @@ void* fastMalloc(size_t size)
return result;
}

void* fastZeroedMalloc(size_t size)
{
ASSERT_IS_WITHIN_LIMIT(size);
ASSERT(!forbidMallocUseScopeCount || disableMallocRestrictionScopeCount);
void* result = bmalloc::api::zeroedMalloc(size);
#if ENABLE(MALLOC_HEAP_BREAKDOWN) && TRACK_MALLOC_CALLSTACK
if (!AvoidRecordingScope::avoidRecordingCount())
MallocCallTracker::singleton().recordMalloc(result, size);
#endif
return result;
}

TryMallocReturnValue tryFastZeroedMalloc(size_t size)
{
FAIL_IF_EXCEEDS_LIMIT(size);
ASSERT(!forbidMallocUseScopeCount || disableMallocRestrictionScopeCount);
return bmalloc::api::tryZeroedMalloc(size);
}

void* fastCalloc(size_t numElements, size_t elementSize)
{
ASSERT_IS_WITHIN_LIMIT(numElements * elementSize);
Expand Down
19 changes: 19 additions & 0 deletions Source/WTF/wtf/Gigacage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ void* tryMalloc(Kind, size_t size)
return FastMalloc::tryMalloc(size);
}

void* tryZeroedMalloc(Kind, size_t size)
{
return FastMalloc::tryZeroedMalloc(size);
}

void* tryRealloc(Kind, void* pointer, size_t size)
{
return FastMalloc::tryRealloc(pointer, size);
Expand Down Expand Up @@ -96,6 +101,13 @@ void* tryMalloc(Kind kind, size_t size)
return result;
}

void* tryZeroedMalloc(Kind kind, size_t size)
{
void* result = bmalloc::api::tryZeroedMalloc(size, bmalloc::heapKind(kind));
WTF::compilerFence();
return result;
}

void* tryRealloc(Kind kind, void* pointer, size_t size)
{
void* result = bmalloc::api::tryRealloc(pointer, size, bmalloc::heapKind(kind));
Expand Down Expand Up @@ -149,6 +161,13 @@ void* malloc(Kind kind, size_t size)
return result;
}

void* zeroedMalloc(Kind kind, size_t size)
{
void* result = tryZeroedMalloc(kind, size);
RELEASE_ASSERT(result);
return result;
}

void* mallocArray(Kind kind, size_t numElements, size_t elementSize)
{
void* result = tryMallocArray(kind, numElements, elementSize);
Expand Down
3 changes: 3 additions & 0 deletions Source/WTF/wtf/Gigacage.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ inline bool isCaged(Kind, const void*) { return false; }
inline void* tryAlignedMalloc(Kind, size_t alignment, size_t size) { return tryFastAlignedMalloc(alignment, size); }
inline void alignedFree(Kind, void* p) { fastAlignedFree(p); }
WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t size);
WTF_EXPORT_PRIVATE void* tryZeroedMalloc(Kind, size_t);
WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t);
inline void free(Kind, void* p) { fastFree(p); }

Expand All @@ -101,6 +102,7 @@ namespace Gigacage {
WTF_EXPORT_PRIVATE void* tryAlignedMalloc(Kind, size_t alignment, size_t size);
WTF_EXPORT_PRIVATE void alignedFree(Kind, void*);
WTF_EXPORT_PRIVATE void* tryMalloc(Kind, size_t);
WTF_EXPORT_PRIVATE void* tryZeroedMalloc(Kind, size_t);
WTF_EXPORT_PRIVATE void* tryRealloc(Kind, void*, size_t);
WTF_EXPORT_PRIVATE void free(Kind, void*);

Expand All @@ -115,6 +117,7 @@ namespace Gigacage {
WTF_EXPORT_PRIVATE void* tryMallocArray(Kind, size_t numElements, size_t elementSize);

WTF_EXPORT_PRIVATE void* malloc(Kind, size_t);
WTF_EXPORT_PRIVATE void* zeroedMalloc(Kind, size_t);
WTF_EXPORT_PRIVATE void* mallocArray(Kind, size_t numElements, size_t elementSize);

} // namespace Gigacage
Expand Down
28 changes: 28 additions & 0 deletions Source/bmalloc/bmalloc/bmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,34 @@ BINLINE void* malloc(size_t size, HeapKind kind = HeapKind::Primary)
#endif
}

BINLINE void* tryZeroedMalloc(size_t size, HeapKind kind = HeapKind::Primary)
{
#if BUSE(LIBPAS)
if (!isGigacage(kind))
return bmalloc_try_allocate_zeroed_inline(size);
return bmalloc_try_allocate_auxiliary_zeroed_inline(&heapForKind(gigacageKind(kind)), size);
#else
auto* mem = Cache::tryAllocate(kind, size);
if (mem)
memset(mem, 0, size);
return mem;
#endif
}

// Crashes on failure.
BINLINE void* zeroedMalloc(size_t size, HeapKind kind = HeapKind::Primary)
{
#if BUSE(LIBPAS)
if (!isGigacage(kind))
return bmalloc_allocate_zeroed_inline(size);
return bmalloc_allocate_auxiliary_zeroed_inline(&heapForKind(gigacageKind(kind)), size);
#else
auto* mem = Cache::allocate(kind, size);
memset(mem, 0, size);
return mem;
#endif
}

BEXPORT void* mallocOutOfLine(size_t size, HeapKind kind = HeapKind::Primary);

// Returns null on failure.
Expand Down

0 comments on commit ad82b55

Please sign in to comment.