mirror of
https://github.com/oven-sh/bun
synced 2026-02-14 12:51:54 +00:00
Ensure we aren't using multiple allocators with the same list by storing a pointer to the allocator in debug mode only. This check is stricter than the bare minimum necessary to prevent illegal behavior, so CI may reveal certain uses that fail the checks but don't cause IB. Most of these cases should probably be updated to comply with the new requirements—we want these types' invariants to be clear. (For internal tracking: fixes ENG-14987)
142 lines
4.8 KiB
Zig
142 lines
4.8 KiB
Zig
const vm_size_t = usize;
|
|
|
|
pub const enabled = Environment.allow_assert and Environment.isMac;
|
|
|
|
fn heapLabel(comptime T: type) [:0]const u8 {
|
|
const base_name = if (@hasDecl(T, "heap_label"))
|
|
T.heap_label
|
|
else
|
|
bun.meta.typeBaseName(@typeName(T));
|
|
return base_name;
|
|
}
|
|
|
|
pub fn allocator(comptime T: type) std.mem.Allocator {
|
|
return namedAllocator(comptime heapLabel(T));
|
|
}
|
|
pub fn namedAllocator(comptime name: [:0]const u8) std.mem.Allocator {
|
|
return getZone("Bun__" ++ name).allocator();
|
|
}
|
|
|
|
pub fn getZoneT(comptime T: type) *Zone {
|
|
return getZone(comptime heapLabel(T));
|
|
}
|
|
|
|
pub fn getZone(comptime name: [:0]const u8) *Zone {
|
|
comptime bun.assert(enabled);
|
|
|
|
const static = struct {
|
|
pub var zone: *Zone = undefined;
|
|
pub fn initOnce() void {
|
|
zone = Zone.init(name);
|
|
}
|
|
|
|
pub var once = std.once(initOnce);
|
|
};
|
|
|
|
static.once.call();
|
|
return static.zone;
|
|
}
|
|
|
|
pub const Zone = opaque {
|
|
pub fn init(comptime name: [:0]const u8) *Zone {
|
|
const zone = malloc_create_zone(0, 0);
|
|
|
|
malloc_set_zone_name(zone, name.ptr);
|
|
|
|
return zone;
|
|
}
|
|
|
|
fn alignedAlloc(zone: *Zone, len: usize, alignment: std.mem.Alignment) ?[*]u8 {
|
|
// The posix_memalign only accepts alignment values that are a
|
|
// multiple of the pointer size
|
|
const eff_alignment = @max(alignment.toByteUnits(), @sizeOf(usize));
|
|
const ptr = malloc_zone_memalign(zone, eff_alignment, len);
|
|
return @as(?[*]u8, @ptrCast(ptr));
|
|
}
|
|
|
|
fn alignedAllocSize(ptr: [*]u8) usize {
|
|
return std.c.malloc_size(ptr);
|
|
}
|
|
|
|
fn rawAlloc(zone: *anyopaque, len: usize, alignment: std.mem.Alignment, _: usize) ?[*]u8 {
|
|
return alignedAlloc(@ptrCast(zone), len, alignment);
|
|
}
|
|
|
|
fn resize(_: *anyopaque, buf: []u8, _: std.mem.Alignment, new_len: usize, _: usize) bool {
|
|
if (new_len <= buf.len) {
|
|
return true;
|
|
}
|
|
|
|
const full_len = alignedAllocSize(buf.ptr);
|
|
if (new_len <= full_len) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
fn rawFree(zone: *anyopaque, buf: []u8, _: std.mem.Alignment, _: usize) void {
|
|
malloc_zone_free(@ptrCast(zone), @ptrCast(buf.ptr));
|
|
}
|
|
|
|
pub const vtable = std.mem.Allocator.VTable{
|
|
.alloc = &rawAlloc,
|
|
.resize = &resize,
|
|
.remap = &std.mem.Allocator.noRemap,
|
|
.free = &rawFree,
|
|
};
|
|
|
|
pub fn allocator(zone: *Zone) std.mem.Allocator {
|
|
return .{
|
|
.vtable = &vtable,
|
|
.ptr = zone,
|
|
};
|
|
}
|
|
|
|
/// Create a single-item pointer with initialized data.
|
|
pub inline fn create(zone: *Zone, comptime T: type, data: T) *T {
|
|
const alignment: std.mem.Alignment = .fromByteUnits(@alignOf(T));
|
|
const ptr: *T = @alignCast(@ptrCast(
|
|
rawAlloc(zone, @sizeOf(T), alignment, @returnAddress()) orelse bun.outOfMemory(),
|
|
));
|
|
ptr.* = data;
|
|
return ptr;
|
|
}
|
|
|
|
/// Free a single-item pointer
|
|
pub inline fn destroy(zone: *Zone, comptime T: type, ptr: *T) void {
|
|
malloc_zone_free(zone, @ptrCast(ptr));
|
|
}
|
|
|
|
pub fn isInstance(allocator_: std.mem.Allocator) bool {
|
|
return allocator_.vtable == &vtable;
|
|
}
|
|
|
|
pub extern fn malloc_default_zone() *Zone;
|
|
pub extern fn malloc_create_zone(start_size: vm_size_t, flags: c_uint) *Zone;
|
|
pub extern fn malloc_destroy_zone(zone: *Zone) void;
|
|
pub extern fn malloc_zone_malloc(zone: *Zone, size: usize) ?*anyopaque;
|
|
pub extern fn malloc_zone_calloc(zone: *Zone, num_items: usize, size: usize) ?*anyopaque;
|
|
pub extern fn malloc_zone_valloc(zone: *Zone, size: usize) ?*anyopaque;
|
|
pub extern fn malloc_zone_free(zone: *Zone, ptr: ?*anyopaque) void;
|
|
pub extern fn malloc_zone_realloc(zone: *Zone, ptr: ?*anyopaque, size: usize) ?*anyopaque;
|
|
pub extern fn malloc_zone_from_ptr(ptr: ?*const anyopaque) *Zone;
|
|
pub extern fn malloc_zone_memalign(zone: *Zone, alignment: usize, size: usize) ?*anyopaque;
|
|
pub extern fn malloc_zone_batch_malloc(zone: *Zone, size: usize, results: [*]?*anyopaque, num_requested: c_uint) c_uint;
|
|
pub extern fn malloc_zone_batch_free(zone: *Zone, to_be_freed: [*]?*anyopaque, num: c_uint) void;
|
|
pub extern fn malloc_default_purgeable_zone() *Zone;
|
|
pub extern fn malloc_make_purgeable(ptr: ?*anyopaque) void;
|
|
pub extern fn malloc_make_nonpurgeable(ptr: ?*anyopaque) c_int;
|
|
pub extern fn malloc_zone_register(zone: *Zone) void;
|
|
pub extern fn malloc_zone_unregister(zone: *Zone) void;
|
|
pub extern fn malloc_set_zone_name(zone: *Zone, name: ?[*:0]const u8) void;
|
|
pub extern fn malloc_get_zone_name(zone: *Zone) ?[*:0]const u8;
|
|
pub extern fn malloc_zone_pressure_relief(zone: *Zone, goal: usize) usize;
|
|
};
|
|
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const bun = @import("bun");
|
|
const Environment = bun.Environment;
|