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:
Andreas Kling
2026-04-03 17:06:58 +02:00
committed by Andreas Kling
parent 648ececa62
commit b23aa38546
Notes: github-actions[bot] 2026-04-08 07:58:49 +00:00
27 changed files with 349 additions and 53 deletions

View File

@@ -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);
}
}

View File

@@ -87,7 +87,7 @@ public:
munmap((void*)chunk, m_chunk_size);
#endif
} else {
kfree_sized((void*)chunk, m_chunk_size);
kfree((void*)chunk);
}
});
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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()

View File

@@ -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));

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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;

View File

@@ -137,6 +137,8 @@ if (WIN32)
find_package(mman REQUIRED)
endif()
find_package(mimalloc CONFIG REQUIRED)
include(rust_crate)
include(targets)

View File

@@ -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"

View File

@@ -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);
};
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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()

View File

@@ -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;

View File

@@ -4,4 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#[path = "../../../RustAllocator.rs"]
mod rust_allocator;
pub mod calendar;

View 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()) }
}
}

View File

@@ -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",

View File

@@ -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"