mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK: Adopt mimalloc v2 as main allocator
Use mimalloc for Ladybird-owned allocations without overriding malloc(). Route kmalloc(), kcalloc(), krealloc(), and kfree() through mimalloc, and put the embedded Rust crates on the same allocator via a shared shim in AK/kmalloc.cpp. This also lets us drop kfree_sized(), since it no longer used its size argument. StringData, Utf16StringData, JS object storage, Rust error strings, and the CoreAudio playback helpers can all free their AK-backed storage with plain kfree(). Sanitizer builds still use the system allocator. LeakSanitizer does not reliably trace references stored in mimalloc-managed AK containers, so static caches and other long-lived roots can look leaked. Pass the old size into the Rust realloc shim so aligned fallback reallocations can move posix_memalign-backed blocks safely. Static builds still need a little linker help. macOS app binaries need the Rust allocator entry points forced in from liblagom-ak.a, while static ELF links can pull in identical allocator shim definitions from multiple Rust staticlibs. Keep the Apple -u flags and allow those duplicate shim symbols for LibJS and LibRegex links on Linux and BSD.
This commit is contained in:
committed by
Andreas Kling
parent
648ececa62
commit
b23aa38546
Notes:
github-actions[bot]
2026-04-08 07:58:49 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/b23aa385467 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8752 Reviewed-by: https://github.com/trflynn89
@@ -50,7 +50,7 @@ public:
|
||||
Bitmap& operator=(Bitmap&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
kfree_sized(m_data, size_in_bytes());
|
||||
kfree(m_data);
|
||||
m_data = exchange(other.m_data, nullptr);
|
||||
m_size = exchange(other.m_size, 0);
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
~Bitmap()
|
||||
{
|
||||
if (m_is_owning) {
|
||||
kfree_sized(m_data, size_in_bytes());
|
||||
kfree(m_data);
|
||||
}
|
||||
m_data = nullptr;
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
__builtin_memcpy(m_data, previous_data, previous_size_bytes);
|
||||
if ((previous_size % 8) != 0)
|
||||
set_range(previous_size, 8 - previous_size % 8, default_value);
|
||||
kfree_sized(previous_data, previous_size_bytes);
|
||||
kfree(previous_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
munmap((void*)chunk, m_chunk_size);
|
||||
#endif
|
||||
} else {
|
||||
kfree_sized((void*)chunk, m_chunk_size);
|
||||
kfree((void*)chunk);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
{
|
||||
if (this != &other) {
|
||||
if (!m_inline)
|
||||
kfree_sized(m_outline_buffer, m_outline_capacity);
|
||||
kfree(m_outline_buffer);
|
||||
move_from(move(other));
|
||||
}
|
||||
return *this;
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
void clear()
|
||||
{
|
||||
if (!m_inline) {
|
||||
kfree_sized(m_outline_buffer, m_outline_capacity);
|
||||
kfree(m_outline_buffer);
|
||||
m_inline = true;
|
||||
}
|
||||
m_size = 0;
|
||||
@@ -353,10 +353,9 @@ private:
|
||||
{
|
||||
// m_inline_buffer and m_outline_buffer are part of a union, so save the pointer
|
||||
auto* outline_buffer = m_outline_buffer;
|
||||
auto outline_capacity = m_outline_capacity;
|
||||
if (!may_discard_existing_data)
|
||||
__builtin_memcpy(m_inline_buffer, outline_buffer, size);
|
||||
kfree_sized(outline_buffer, outline_capacity);
|
||||
kfree(outline_buffer);
|
||||
m_inline = true;
|
||||
}
|
||||
|
||||
@@ -377,7 +376,7 @@ private:
|
||||
__builtin_memcpy(new_buffer, data(), m_size);
|
||||
} else if (m_outline_buffer) {
|
||||
__builtin_memcpy(new_buffer, m_outline_buffer, min(new_capacity, m_outline_capacity));
|
||||
kfree_sized(m_outline_buffer, m_outline_capacity);
|
||||
kfree(m_outline_buffer);
|
||||
}
|
||||
|
||||
m_outline_buffer = new_buffer;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
kfree_sized(ptr, allocation_size_for_stringimpl(static_cast<ByteStringImpl*>(ptr)->m_length));
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
static ByteStringImpl& the_empty_stringimpl();
|
||||
|
||||
@@ -77,12 +77,22 @@ target_link_libraries(AK PRIVATE FastFloat::fast_float)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
target_link_libraries(AK PRIVATE fmt::fmt)
|
||||
|
||||
set(MIMALLOC_VISIBILITY PRIVATE)
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
set(MIMALLOC_VISIBILITY PUBLIC)
|
||||
endif()
|
||||
target_link_libraries(AK ${MIMALLOC_VISIBILITY} mimalloc)
|
||||
|
||||
# FIXME: Make this generic for all imported shared library dependencies and apply globally
|
||||
if (BUILD_SHARED_LIBS AND NOT CMAKE_SKIP_INSTALL_RULES AND NOT "${VCPKG_INSTALLED_DIR}" STREQUAL "")
|
||||
install(IMPORTED_RUNTIME_ARTIFACTS simdutf::simdutf
|
||||
LIBRARY COMPONENT Lagom_Runtime NAMELINK_COMPONENT Lagom_Development
|
||||
FRAMEWORK COMPONENT Lagom_Runtime
|
||||
)
|
||||
install(IMPORTED_RUNTIME_ARTIFACTS mimalloc
|
||||
LIBRARY COMPONENT Lagom_Runtime NAMELINK_COMPONENT Lagom_Development
|
||||
FRAMEWORK COMPONENT Lagom_Runtime
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
@@ -108,6 +118,14 @@ elseif (APPLE)
|
||||
set(ASSERTION_HANDLER_VISIBILITY INTERFACE)
|
||||
endif()
|
||||
target_link_options(AK ${ASSERTION_HANDLER_VISIBILITY} LINKER:-U,_ak_assertion_handler)
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
target_link_options(AK INTERFACE
|
||||
LINKER:-u,_ladybird_rust_alloc
|
||||
LINKER:-u,_ladybird_rust_alloc_zeroed
|
||||
LINKER:-u,_ladybird_rust_dealloc
|
||||
LINKER:-u,_ladybird_rust_realloc
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Manually install AK headers
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
return;
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_elements[i].~T();
|
||||
kfree_sized(m_elements, storage_allocation_size(m_size));
|
||||
kfree(m_elements);
|
||||
m_elements = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
kfree_sized(m_buckets, size_in_bytes(capacity()));
|
||||
kfree(m_buckets);
|
||||
}
|
||||
|
||||
HashTable(HashTable const& other)
|
||||
@@ -622,7 +622,6 @@ private:
|
||||
VERIFY(new_capacity >= size());
|
||||
|
||||
auto* old_buckets = m_buckets;
|
||||
auto old_buckets_size = size_in_bytes(capacity());
|
||||
Iterator old_iter = begin();
|
||||
|
||||
auto* new_buckets = kcalloc(1, size_in_bytes(new_capacity));
|
||||
@@ -644,7 +643,7 @@ private:
|
||||
it->~T();
|
||||
}
|
||||
|
||||
kfree_sized(old_buckets, old_buckets_size);
|
||||
kfree(old_buckets);
|
||||
return {};
|
||||
}
|
||||
void rehash(size_t new_capacity)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/kmalloc.h>
|
||||
|
||||
namespace AK::Detail {
|
||||
|
||||
@@ -26,7 +27,7 @@ public:
|
||||
VERIFY(byte_count);
|
||||
|
||||
auto capacity = allocation_size_for_string_data(byte_count);
|
||||
void* slot = malloc(capacity);
|
||||
void* slot = kmalloc(capacity);
|
||||
if (!slot)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
@@ -52,7 +53,7 @@ public:
|
||||
VERIFY(byte_count > MAX_SHORT_STRING_BYTE_COUNT);
|
||||
|
||||
auto capacity = sizeof(StringData) + sizeof(StringData::SubstringData);
|
||||
void* slot = malloc(capacity);
|
||||
void* slot = kmalloc(capacity);
|
||||
if (!slot)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
@@ -66,7 +67,7 @@ public:
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
~StringData()
|
||||
|
||||
@@ -20,11 +20,9 @@ namespace AK::Detail {
|
||||
|
||||
NonnullRefPtr<Utf16StringData> Utf16StringData::create_uninitialized(StorageType storage_type, size_t code_unit_length)
|
||||
{
|
||||
auto allocation_size = storage_type == Utf16StringData::StorageType::ASCII
|
||||
? sizeof(Utf16StringData) + (sizeof(char) * code_unit_length)
|
||||
: sizeof(Utf16StringData) + (sizeof(char16_t) * code_unit_length);
|
||||
auto allocation_size = allocation_size_for_string_data(storage_type == Utf16StringData::StorageType::ASCII, code_unit_length);
|
||||
|
||||
void* slot = malloc(allocation_size);
|
||||
void* slot = kmalloc(allocation_size);
|
||||
VERIFY(slot);
|
||||
|
||||
return adopt_ref(*new (slot) Utf16StringData(storage_type, code_unit_length));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Types.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/kmalloc.h>
|
||||
|
||||
namespace AK::Detail {
|
||||
|
||||
@@ -52,7 +53,7 @@ public:
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE bool operator==(Utf16StringData const& other) const
|
||||
@@ -130,6 +131,13 @@ private:
|
||||
template<typename ViewType>
|
||||
static NonnullRefPtr<Utf16StringData> create_from_code_point_iterable(ViewType const&);
|
||||
|
||||
[[nodiscard]] static constexpr size_t allocation_size_for_string_data(bool has_ascii_storage, size_t code_unit_length)
|
||||
{
|
||||
return has_ascii_storage
|
||||
? sizeof(Utf16StringData) + (sizeof(char) * code_unit_length)
|
||||
: sizeof(Utf16StringData) + (sizeof(char16_t) * code_unit_length);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t calculate_code_point_length() const;
|
||||
|
||||
// We store whether this string has ASCII or UTF-16 storage by setting the most significant bit of m_length_in_code_units
|
||||
|
||||
@@ -481,7 +481,7 @@ public:
|
||||
{
|
||||
clear_with_capacity();
|
||||
if (m_metadata.outline_buffer) {
|
||||
kfree_sized(m_metadata.outline_buffer, m_capacity * sizeof(StorageType));
|
||||
kfree(m_metadata.outline_buffer);
|
||||
m_metadata.outline_buffer = nullptr;
|
||||
}
|
||||
reset_capacity();
|
||||
@@ -862,7 +862,7 @@ public:
|
||||
}
|
||||
}
|
||||
if (m_metadata.outline_buffer)
|
||||
kfree_sized(m_metadata.outline_buffer, m_capacity * sizeof(StorageType));
|
||||
kfree(m_metadata.outline_buffer);
|
||||
m_metadata.outline_buffer = new_buffer;
|
||||
m_capacity = new_capacity;
|
||||
update_metadata(); // We have *some* space, we just allocated it.
|
||||
|
||||
158
AK/kmalloc.cpp
158
AK/kmalloc.cpp
@@ -68,4 +68,162 @@ nothrow_t const nothrow;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# include <cstddef>
|
||||
# include <cstring>
|
||||
|
||||
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
// LeakSanitizer does not reliably trace references stored in mimalloc-managed
|
||||
// AK containers, so sanitizer builds fall back to the system allocator.
|
||||
# define AK_USE_SYSTEM_ALLOCATOR_INSTRUMENTED 1
|
||||
# else
|
||||
# include <mimalloc.h>
|
||||
# endif
|
||||
|
||||
static bool allocation_needs_explicit_alignment(size_t alignment)
|
||||
{
|
||||
return alignment > alignof(std::max_align_t);
|
||||
}
|
||||
|
||||
# ifdef AK_USE_SYSTEM_ALLOCATOR_INSTRUMENTED
|
||||
|
||||
static void* aligned_alloc_with_system_allocator(size_t size, size_t alignment, bool zeroed)
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
auto actual_size = size == 0 ? static_cast<size_t>(1) : size;
|
||||
if (auto result = posix_memalign(&ptr, alignment, actual_size); result != 0)
|
||||
return nullptr;
|
||||
if (zeroed)
|
||||
__builtin_memset(ptr, 0, actual_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* ak_kcalloc(size_t count, size_t size)
|
||||
{
|
||||
return calloc(count, size);
|
||||
}
|
||||
|
||||
void* ak_kmalloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void* ak_krealloc(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
size_t ak_kmalloc_good_size(size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
void ak_kfree(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void* ladybird_rust_alloc(size_t size, size_t alignment);
|
||||
void* ladybird_rust_alloc_zeroed(size_t size, size_t alignment);
|
||||
void ladybird_rust_dealloc(void* ptr, size_t alignment);
|
||||
void* ladybird_rust_realloc(void* ptr, size_t old_size, size_t new_size, size_t alignment);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_alloc(size_t size, size_t alignment)
|
||||
{
|
||||
if (allocation_needs_explicit_alignment(alignment))
|
||||
return aligned_alloc_with_system_allocator(size, alignment, false);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_alloc_zeroed(size_t size, size_t alignment)
|
||||
{
|
||||
if (allocation_needs_explicit_alignment(alignment))
|
||||
return aligned_alloc_with_system_allocator(size, alignment, true);
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
extern "C" void ladybird_rust_dealloc(void* ptr, size_t)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_realloc(void* ptr, size_t old_size, size_t new_size, size_t alignment)
|
||||
{
|
||||
if (!allocation_needs_explicit_alignment(alignment))
|
||||
return realloc(ptr, new_size);
|
||||
|
||||
auto* new_ptr = aligned_alloc_with_system_allocator(new_size, alignment, false);
|
||||
if (!new_ptr)
|
||||
return nullptr;
|
||||
if (ptr)
|
||||
__builtin_memcpy(new_ptr, ptr, old_size < new_size ? old_size : new_size);
|
||||
free(ptr);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
void* ak_kcalloc(size_t count, size_t size)
|
||||
{
|
||||
return mi_calloc(count, size);
|
||||
}
|
||||
|
||||
void* ak_kmalloc(size_t size)
|
||||
{
|
||||
return mi_malloc(size);
|
||||
}
|
||||
|
||||
void* ak_krealloc(void* ptr, size_t size)
|
||||
{
|
||||
return mi_realloc(ptr, size);
|
||||
}
|
||||
|
||||
size_t ak_kmalloc_good_size(size_t size)
|
||||
{
|
||||
return mi_good_size(size);
|
||||
}
|
||||
|
||||
void ak_kfree(void* ptr)
|
||||
{
|
||||
mi_free(ptr);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void* ladybird_rust_alloc(size_t size, size_t alignment);
|
||||
void* ladybird_rust_alloc_zeroed(size_t size, size_t alignment);
|
||||
void ladybird_rust_dealloc(void* ptr, size_t alignment);
|
||||
void* ladybird_rust_realloc(void* ptr, size_t old_size, size_t new_size, size_t alignment);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_alloc(size_t size, size_t alignment)
|
||||
{
|
||||
if (allocation_needs_explicit_alignment(alignment))
|
||||
return mi_malloc_aligned(size, alignment);
|
||||
return mi_malloc(size);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_alloc_zeroed(size_t size, size_t alignment)
|
||||
{
|
||||
if (allocation_needs_explicit_alignment(alignment))
|
||||
return mi_zalloc_aligned(size, alignment);
|
||||
return mi_zalloc(size);
|
||||
}
|
||||
|
||||
extern "C" void ladybird_rust_dealloc(void* ptr, size_t)
|
||||
{
|
||||
mi_free(ptr);
|
||||
}
|
||||
|
||||
extern "C" void* ladybird_rust_realloc(void* ptr, size_t, size_t new_size, size_t alignment)
|
||||
{
|
||||
if (allocation_needs_explicit_alignment(alignment))
|
||||
return mi_realloc_aligned(ptr, new_size, alignment);
|
||||
return mi_realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
46
AK/kmalloc.h
46
AK/kmalloc.h
@@ -12,25 +12,43 @@
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define kcalloc calloc
|
||||
#define kmalloc malloc
|
||||
#define kmalloc_good_size malloc_good_size
|
||||
#if defined(AK_OS_SERENITY)
|
||||
# define kcalloc calloc
|
||||
# define kfree free
|
||||
# define kmalloc malloc
|
||||
# define krealloc realloc
|
||||
# define kmalloc_good_size malloc_good_size
|
||||
#else
|
||||
[[nodiscard]] void* ak_kcalloc(size_t count, size_t size);
|
||||
void ak_kfree(void* ptr);
|
||||
[[nodiscard]] void* ak_kmalloc(size_t size);
|
||||
[[nodiscard]] void* ak_krealloc(void* ptr, size_t size);
|
||||
[[nodiscard]] size_t ak_kmalloc_good_size(size_t size);
|
||||
|
||||
inline void kfree_sized(void* ptr, size_t)
|
||||
[[nodiscard]] inline void* kcalloc(size_t count, size_t size)
|
||||
{
|
||||
free(ptr);
|
||||
return ak_kcalloc(count, size);
|
||||
}
|
||||
|
||||
#ifndef AK_OS_SERENITY
|
||||
# include <AK/Types.h>
|
||||
|
||||
# ifndef AK_OS_MACOS
|
||||
extern "C" {
|
||||
inline size_t malloc_good_size(size_t size) { return size; }
|
||||
inline void kfree(void* ptr)
|
||||
{
|
||||
ak_kfree(ptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline void* kmalloc(size_t size)
|
||||
{
|
||||
return ak_kmalloc(size);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline void* krealloc(void* ptr, size_t size)
|
||||
{
|
||||
return ak_krealloc(ptr, size);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline size_t kmalloc_good_size(size_t size)
|
||||
{
|
||||
return ak_kmalloc_good_size(size);
|
||||
}
|
||||
# else
|
||||
# include <malloc/malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
@@ -137,6 +137,8 @@ if (WIN32)
|
||||
find_package(mman REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(mimalloc CONFIG REQUIRED)
|
||||
|
||||
include(rust_crate)
|
||||
include(targets)
|
||||
|
||||
|
||||
@@ -32,4 +32,4 @@ ref_option = "deny"
|
||||
elidable_lifetime_names = "deny"
|
||||
unnested_or_patterns = "deny"
|
||||
borrow_as_ptr = "deny"
|
||||
explicit_iter_loop = "deny"
|
||||
explicit_iter_loop = "deny"
|
||||
|
||||
@@ -108,8 +108,8 @@ Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, IntSize size, BackingS
|
||||
VERIFY(!size_would_overflow(format, size));
|
||||
VERIFY(m_data);
|
||||
VERIFY(backing_store.size_in_bytes == size_in_bytes());
|
||||
m_destruction_callback = [data = m_data, size_in_bytes = this->size_in_bytes()] {
|
||||
kfree_sized(data, size_in_bytes);
|
||||
m_destruction_callback = [data = m_data] {
|
||||
kfree(data);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +292,12 @@ target_link_libraries(LibJS PUBLIC JSClangPlugin)
|
||||
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libjs_rust FFI_HEADER RustFFI.h)
|
||||
target_link_libraries(LibJS PRIVATE libjs_rust)
|
||||
if ((LINUX OR BSD) AND NOT BUILD_SHARED_LIBS)
|
||||
# Rust staticlibs each carry the same allocator shim symbols. LibJS can
|
||||
# pull in multiple crates' copies in static ELF links, but they all
|
||||
# forward to the same ladybird_rust_* entry points in AK/kmalloc.cpp.
|
||||
target_link_options(LibJS INTERFACE LINKER:--allow-multiple-definition)
|
||||
endif()
|
||||
|
||||
# The Rust library and LibJS have a circular dependency (C++ calls Rust
|
||||
# entry points, Rust calls C++ callbacks). For static builds, merge the
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/kmalloc.h>
|
||||
#include <LibJS/Bytecode/PropertyAccess.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Accessor.h>
|
||||
@@ -43,7 +44,8 @@ static constexpr u32 HEAP_STORAGE_HEADER_SIZE = sizeof(Value);
|
||||
static Value* allocate_heap_named_storage(u32 capacity)
|
||||
{
|
||||
VERIFY(capacity > Object::INLINE_NAMED_PROPERTY_CAPACITY);
|
||||
auto* raw = static_cast<u8*>(malloc(HEAP_STORAGE_HEADER_SIZE + capacity * sizeof(Value)));
|
||||
auto allocation_size = HEAP_STORAGE_HEADER_SIZE + capacity * sizeof(Value);
|
||||
auto* raw = static_cast<u8*>(kmalloc(allocation_size));
|
||||
VERIFY(raw);
|
||||
*reinterpret_cast<u32*>(raw) = capacity;
|
||||
return reinterpret_cast<Value*>(raw + HEAP_STORAGE_HEADER_SIZE);
|
||||
@@ -51,7 +53,8 @@ static Value* allocate_heap_named_storage(u32 capacity)
|
||||
|
||||
static void free_heap_named_storage(Value* storage)
|
||||
{
|
||||
free(reinterpret_cast<u8*>(storage) - HEAP_STORAGE_HEADER_SIZE);
|
||||
auto* raw = reinterpret_cast<u8*>(storage) - HEAP_STORAGE_HEADER_SIZE;
|
||||
kfree(raw);
|
||||
}
|
||||
|
||||
static u32 heap_named_storage_capacity(Value* storage)
|
||||
@@ -73,7 +76,7 @@ void Object::ensure_named_storage_capacity(u32 needed)
|
||||
new_storage[i] = Value();
|
||||
m_named_properties = new_storage;
|
||||
} else {
|
||||
auto* raw = static_cast<u8*>(realloc(
|
||||
auto* raw = static_cast<u8*>(krealloc(
|
||||
reinterpret_cast<u8*>(m_named_properties) - HEAP_STORAGE_HEADER_SIZE,
|
||||
HEAP_STORAGE_HEADER_SIZE + new_capacity * sizeof(Value)));
|
||||
VERIFY(raw);
|
||||
@@ -1703,7 +1706,9 @@ u32 Object::indexed_elements_capacity() const
|
||||
static Value* allocate_indexed_elements(u32 capacity)
|
||||
{
|
||||
// Layout: [u32 capacity] [u32 padding] [Value 0] [Value 1] ...
|
||||
auto* raw = static_cast<u8*>(malloc(sizeof(u64) + capacity * sizeof(Value)));
|
||||
auto allocation_size = sizeof(u64) + capacity * sizeof(Value);
|
||||
auto* raw = static_cast<u8*>(kmalloc(allocation_size));
|
||||
VERIFY(raw);
|
||||
*reinterpret_cast<u32*>(raw) = capacity;
|
||||
*reinterpret_cast<u32*>(raw + sizeof(u32)) = 0; // padding
|
||||
auto* elements = reinterpret_cast<Value*>(raw + sizeof(u64));
|
||||
@@ -1717,7 +1722,7 @@ static void deallocate_indexed_elements(Value* elements)
|
||||
if (!elements)
|
||||
return;
|
||||
auto* raw = reinterpret_cast<u8*>(elements) - sizeof(u64);
|
||||
free(raw);
|
||||
kfree(raw);
|
||||
}
|
||||
|
||||
void Object::free_indexed_elements()
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
//! - `bytecode/` — Bytecode generator, instruction types, and FFI
|
||||
//! - `scope_collector.rs` — Scope analysis
|
||||
|
||||
#[path = "../../../RustAllocator.rs"]
|
||||
mod rust_allocator;
|
||||
|
||||
/// Compile-time conversion of an ASCII string literal to `&'static [u16]`.
|
||||
///
|
||||
/// Produces a static `[u16; N]` array, so comparisons like
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/kmalloc.h>
|
||||
#include <LibGC/DeferGC.h>
|
||||
#include <LibJS/Bytecode/ClassBlueprint.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
@@ -1005,7 +1006,7 @@ extern "C" void* rust_compile_regex(
|
||||
auto parsed_pattern = JS::parse_regex_pattern(pattern, is_unicode, is_unicode_sets);
|
||||
if (parsed_pattern.is_error()) {
|
||||
auto msg = MUST(String::formatted("RegExp compile error: {}", parsed_pattern.release_error().error));
|
||||
auto* buf = static_cast<char*>(malloc(msg.byte_count() + 1));
|
||||
auto* buf = static_cast<char*>(kmalloc(msg.byte_count() + 1));
|
||||
memcpy(buf, msg.bytes().data(), msg.byte_count());
|
||||
buf[msg.byte_count()] = '\0';
|
||||
*error_out = buf;
|
||||
@@ -1050,7 +1051,7 @@ extern "C" void* rust_compile_regex(
|
||||
auto compiled = regex::ECMAScriptRegex::compile(pattern_str.bytes_as_string_view(), compile_flags);
|
||||
if (compiled.is_error()) {
|
||||
auto msg = MUST(String::formatted("RegExp compile error: {}", compiled.release_error()));
|
||||
auto* buf = static_cast<char*>(malloc(msg.byte_count() + 1));
|
||||
auto* buf = static_cast<char*>(kmalloc(msg.byte_count() + 1));
|
||||
memcpy(buf, msg.bytes().data(), msg.byte_count());
|
||||
buf[msg.byte_count()] = '\0';
|
||||
*error_out = buf;
|
||||
@@ -1067,7 +1068,7 @@ extern "C" void rust_free_compiled_regex(void* ptr)
|
||||
|
||||
extern "C" void rust_free_error_string(char const* str)
|
||||
{
|
||||
free(const_cast<char*>(str));
|
||||
kfree(const_cast<char*>(str));
|
||||
}
|
||||
|
||||
extern "C" size_t rust_number_to_utf16(double value, uint16_t* buffer, size_t buffer_len)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <AK/SourceLocation.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/kmalloc.h>
|
||||
#include <LibCore/ThreadedPromise.h>
|
||||
#include <LibMedia/Audio/PlaybackStreamAudioUnit.h>
|
||||
#include <LibThreading/Mutex.h>
|
||||
@@ -78,7 +79,7 @@ class CoreAudioPropertyValue {
|
||||
public:
|
||||
static ErrorOr<CoreAudioPropertyValue<T>> create(u32 size)
|
||||
{
|
||||
auto ptr = reinterpret_cast<T*>(malloc(size));
|
||||
auto ptr = reinterpret_cast<T*>(kmalloc(size));
|
||||
if (ptr == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
return CoreAudioPropertyValue<T>(ptr, size);
|
||||
@@ -96,7 +97,7 @@ public:
|
||||
}
|
||||
~CoreAudioPropertyValue()
|
||||
{
|
||||
free(m_ptr);
|
||||
kfree(m_ptr);
|
||||
}
|
||||
|
||||
u32 size() const { return m_size; }
|
||||
@@ -471,8 +472,8 @@ ErrorOr<ChannelMap> audio_channel_layout_to_channel_map(AudioChannelLayout const
|
||||
&explicit_layout_size));
|
||||
VERIFY(explicit_layout_size >= sizeof(AudioChannelLayout));
|
||||
|
||||
auto* explicit_layout = reinterpret_cast<AudioChannelLayout*>(malloc(explicit_layout_size));
|
||||
ScopeGuard free_explicit_layout { [&] { free(explicit_layout); } };
|
||||
auto* explicit_layout = reinterpret_cast<AudioChannelLayout*>(kmalloc(explicit_layout_size));
|
||||
ScopeGuard free_explicit_layout { [&] { kfree(explicit_layout); } };
|
||||
|
||||
AU_TRY(AudioFormatGetProperty(
|
||||
kAudioFormatProperty_ChannelLayoutForTag,
|
||||
|
||||
@@ -8,3 +8,6 @@ target_link_libraries(LibRegex PRIVATE LibUnicode)
|
||||
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libregex_rust FFI_HEADER RustFFI.h)
|
||||
target_link_libraries(LibRegex PRIVATE libregex_rust)
|
||||
if ((LINUX OR BSD) AND NOT BUILD_SHARED_LIBS)
|
||||
target_link_options(LibRegex INTERFACE LINKER:--allow-multiple-definition)
|
||||
endif()
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#[path = "../../../RustAllocator.rs"]
|
||||
mod rust_allocator;
|
||||
|
||||
pub mod ast;
|
||||
pub mod bytecode;
|
||||
pub mod compiler;
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#[path = "../../../RustAllocator.rs"]
|
||||
mod rust_allocator;
|
||||
|
||||
pub mod calendar;
|
||||
|
||||
42
Libraries/RustAllocator.rs
Normal file
42
Libraries/RustAllocator.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
use std::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
unsafe extern "C" {
|
||||
fn ladybird_rust_alloc(size: usize, alignment: usize) -> *mut u8;
|
||||
fn ladybird_rust_alloc_zeroed(size: usize, alignment: usize) -> *mut u8;
|
||||
fn ladybird_rust_dealloc(ptr: *mut u8, alignment: usize);
|
||||
fn ladybird_rust_realloc(
|
||||
ptr: *mut u8,
|
||||
old_size: usize,
|
||||
new_size: usize,
|
||||
alignment: usize,
|
||||
) -> *mut u8;
|
||||
}
|
||||
|
||||
struct LadybirdAllocator;
|
||||
|
||||
#[global_allocator]
|
||||
static LADYBIRD_ALLOCATOR: LadybirdAllocator = LadybirdAllocator;
|
||||
|
||||
unsafe impl GlobalAlloc for LadybirdAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
unsafe { ladybird_rust_alloc(layout.size(), layout.align()) }
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
unsafe { ladybird_rust_alloc_zeroed(layout.size(), layout.align()) }
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
unsafe { ladybird_rust_dealloc(ptr, layout.align()) }
|
||||
}
|
||||
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
unsafe { ladybird_rust_realloc(ptr, layout.size(), new_size, layout.align()) }
|
||||
}
|
||||
}
|
||||
@@ -653,6 +653,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mimalloc",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/mimalloc.git",
|
||||
"tag": "v2.2.7"
|
||||
}
|
||||
],
|
||||
"config-opts": [
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_PREFIX_PATH=/app",
|
||||
"-DCMAKE_INSTALL_LIBDIR=lib",
|
||||
"-DMI_BUILD_OBJECT=OFF",
|
||||
"-DMI_BUILD_TESTS=OFF",
|
||||
"-DMI_BUILD_STATIC=OFF",
|
||||
"-DMI_BUILD_SHARED=ON",
|
||||
"-DMI_INSTALL_TOPLEVEL=ON",
|
||||
"-DMI_OVERRIDE=OFF",
|
||||
"-DMI_USE_CXX=ON"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Ladybird",
|
||||
"buildsystem": "cmake-ninja",
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
"name": "mman",
|
||||
"platform": "windows"
|
||||
},
|
||||
"mimalloc",
|
||||
"openssl",
|
||||
{
|
||||
"name": "pthread",
|
||||
@@ -309,6 +310,10 @@
|
||||
"name": "libxml2",
|
||||
"version": "2.13.8#1"
|
||||
},
|
||||
{
|
||||
"name": "mimalloc",
|
||||
"version": "2.2.7"
|
||||
},
|
||||
{
|
||||
"name": "mman",
|
||||
"version": "git-f5ff813#5"
|
||||
|
||||
Reference in New Issue
Block a user