aboutsummaryrefslogtreecommitdiff
path: root/src/memory_allocator.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-23 02:29:07 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-23 02:29:07 -0700
commit8c6700792666b1d7a128095cd5cff392df68375c (patch)
tree2d094df1202fdf44587389e3e6f20967d6487dca /src/memory_allocator.zig
parente012efa1243d09fb1de282ac0a1fa6c8b07538a5 (diff)
downloadbun-8c6700792666b1d7a128095cd5cff392df68375c.tar.gz
bun-8c6700792666b1d7a128095cd5cff392df68375c.tar.zst
bun-8c6700792666b1d7a128095cd5cff392df68375c.zip
Use mimalloc for a 10% boost
Former-commit-id: 044e11d720bc6742dc53b30b4e88e8be7e76c419
Diffstat (limited to 'src/memory_allocator.zig')
-rw-r--r--src/memory_allocator.zig129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/memory_allocator.zig b/src/memory_allocator.zig
new file mode 100644
index 000000000..3f5a7897c
--- /dev/null
+++ b/src/memory_allocator.zig
@@ -0,0 +1,129 @@
+const mem = @import("std").mem;
+const builtin = @import("std").builtin;
+const std = @import("std");
+
+const mimalloc = @import("./allocators/mimalloc.zig");
+const Allocator = mem.Allocator;
+const assert = std.debug.assert;
+
+const CAllocator = struct {
+ comptime {
+ if (!builtin.link_libc) {
+ @compileError("C allocator is only available when linking against libc");
+ }
+ }
+ pub const supports_malloc_size = true;
+ pub const malloc_size = mimalloc.mi_malloc_size;
+ pub const supports_posix_memalign = true;
+
+ fn getHeader(ptr: [*]u8) *[*]u8 {
+ return @intToPtr(*[*]u8, @ptrToInt(ptr) - @sizeOf(usize));
+ }
+
+ fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 {
+ if (supports_posix_memalign) {
+ // The posix_memalign only accepts alignment values that are a
+ // multiple of the pointer size
+ const eff_alignment = std.math.max(alignment, @sizeOf(usize));
+
+ var aligned_ptr: ?*c_void = undefined;
+ if (mimalloc.mi_posix_memalign(&aligned_ptr, eff_alignment, len) != 0)
+ return null;
+
+ return @ptrCast([*]u8, aligned_ptr);
+ }
+
+ // Thin wrapper around regular malloc, overallocate to account for
+ // alignment padding and store the orignal malloc()'ed pointer before
+ // the aligned address.
+ var unaligned_ptr = @ptrCast([*]u8, mimalloc.mi_malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null);
+ const unaligned_addr = @ptrToInt(unaligned_ptr);
+ const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment);
+ var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
+ getHeader(aligned_ptr).* = unaligned_ptr;
+
+ return aligned_ptr;
+ }
+
+ fn alignedFree(ptr: [*]u8) void {
+ if (supports_posix_memalign) {
+ return mimalloc.mi_free(ptr);
+ }
+
+ const unaligned_ptr = getHeader(ptr).*;
+ mimalloc.mi_free(unaligned_ptr);
+ }
+
+ fn alignedAllocSize(ptr: [*]u8) usize {
+ if (supports_posix_memalign) {
+ return malloc_size(ptr);
+ }
+
+ const unaligned_ptr = getHeader(ptr).*;
+ const delta = @ptrToInt(ptr) - @ptrToInt(unaligned_ptr);
+ return malloc_size(unaligned_ptr) - delta;
+ }
+
+ fn alloc(
+ allocator: *Allocator,
+ len: usize,
+ alignment: u29,
+ len_align: u29,
+ return_address: usize,
+ ) error{OutOfMemory}![]u8 {
+ _ = allocator;
+ _ = return_address;
+ assert(len > 0);
+ assert(std.math.isPowerOfTwo(alignment));
+
+ var ptr = alignedAlloc(len, alignment) orelse return error.OutOfMemory;
+ if (len_align == 0) {
+ return ptr[0..len];
+ }
+ const full_len = init: {
+ if (supports_malloc_size) {
+ const s = alignedAllocSize(ptr);
+ assert(s >= len);
+ break :init s;
+ }
+ break :init len;
+ };
+ return ptr[0..mem.alignBackwardAnyAlign(full_len, len_align)];
+ }
+
+ fn resize(
+ allocator: *Allocator,
+ buf: []u8,
+ buf_align: u29,
+ new_len: usize,
+ len_align: u29,
+ return_address: usize,
+ ) Allocator.Error!usize {
+ _ = allocator;
+ _ = buf_align;
+ _ = return_address;
+ if (new_len == 0) {
+ alignedFree(buf.ptr);
+ return 0;
+ }
+ if (new_len <= buf.len) {
+ return mem.alignAllocLen(buf.len, new_len, len_align);
+ }
+ if (supports_malloc_size) {
+ const full_len = alignedAllocSize(buf.ptr);
+ if (new_len <= full_len) {
+ return mem.alignAllocLen(full_len, new_len, len_align);
+ }
+ }
+ return error.OutOfMemory;
+ }
+};
+
+/// Supports the full Allocator interface, including alignment, and exploiting
+/// `malloc_usable_size` if available. For an allocator that directly calls
+/// `malloc`/`free`, see `raw_c_allocator`.
+pub const c_allocator = &c_allocator_state;
+var c_allocator_state = Allocator{
+ .allocFn = CAllocator.alloc,
+ .resizeFn = CAllocator.resize,
+};