summaryrefslogtreecommitdiff
path: root/src/allocators.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/allocators.zig')
-rw-r--r--src/allocators.zig113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/allocators.zig b/src/allocators.zig
new file mode 100644
index 00000000..7a8433e8
--- /dev/null
+++ b/src/allocators.zig
@@ -0,0 +1,113 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const config = @import("pardes_config");
+
+const Allocator = std.mem.Allocator;
+const debug_enabled = builtin.mode == .Debug;
+const reduced_target = config.platform == .web or builtin.os.tag == .freestanding;
+const KiB = 1024;
+const MiB = 1024 * KiB;
+
+const capacities = struct {
+ const pardes = if (reduced_target) 8 * MiB else 32 * MiB;
+ const frame = if (reduced_target) 4 * MiB else 16 * MiB;
+ const tree_sitter = if (reduced_target) 4 * MiB else 16 * MiB;
+ const image = if (reduced_target) 64 * KiB else 32 * MiB;
+ const pdf = if (reduced_target or !config.mupdf) 64 * KiB else 64 * MiB;
+};
+
+pub const Allocators = struct {
+ pardes: Allocator,
+ frame: Allocator,
+ lsp: Allocator,
+ tree_sitter: Allocator,
+ image: Allocator,
+ pdf: Allocator,
+};
+
+var pardes_fallback: std.heap.StackFallbackAllocator(capacities.pardes) = undefined;
+var frame_fallback: std.heap.StackFallbackAllocator(capacities.frame) = undefined;
+var tree_sitter_fallback: std.heap.StackFallbackAllocator(capacities.tree_sitter) = undefined;
+var image_fallback: std.heap.StackFallbackAllocator(capacities.image) = undefined;
+var pdf_fallback: std.heap.StackFallbackAllocator(capacities.pdf) = undefined;
+
+const Debug = std.heap.DebugAllocator(.{});
+var pardes_debug: Debug = .init;
+var frame_debug: Debug = .init;
+var lsp_debug: Debug = .init;
+var tree_sitter_debug: Debug = .init;
+var image_debug: Debug = .init;
+var pdf_debug: Debug = .init;
+
+/// Returns ordinary allocators backed by stdlib fixed-buffer fallbacks. LSP
+/// keeps the caller's allocator because its detached workers are concurrent.
+pub fn init(fallback: Allocator) Allocators {
+ pardes_fallback.fallback_allocator = fallback;
+ pardes_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ frame_fallback.fallback_allocator = fallback;
+ frame_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ tree_sitter_fallback.fallback_allocator = fallback;
+ tree_sitter_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ image_fallback.fallback_allocator = fallback;
+ image_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ pdf_fallback.fallback_allocator = fallback;
+ pdf_fallback.get_called = if (std.debug.runtime_safety) false else {};
+
+ const raw: Allocators = .{
+ .pardes = pardes_fallback.get(),
+ .frame = frame_fallback.get(),
+ .lsp = fallback,
+ .tree_sitter = tree_sitter_fallback.get(),
+ .image = image_fallback.get(),
+ .pdf = pdf_fallback.get(),
+ };
+ if (!debug_enabled) return raw;
+
+ pardes_debug = .{ .backing_allocator = raw.pardes };
+ frame_debug = .{ .backing_allocator = raw.frame };
+ lsp_debug = .{ .backing_allocator = raw.lsp };
+ tree_sitter_debug = .{ .backing_allocator = raw.tree_sitter };
+ image_debug = .{ .backing_allocator = raw.image };
+ pdf_debug = .{ .backing_allocator = raw.pdf };
+ return .{
+ .pardes = pardes_debug.allocator(),
+ .frame = frame_debug.allocator(),
+ .lsp = lsp_debug.allocator(),
+ .tree_sitter = tree_sitter_debug.allocator(),
+ .image = image_debug.allocator(),
+ .pdf = pdf_debug.allocator(),
+ };
+}
+
+pub fn deinit() void {
+ if (!debug_enabled) return;
+ var leaked = pardes_debug.deinit() == .leak;
+ leaked = (frame_debug.deinit() == .leak) or leaked;
+ leaked = (lsp_debug.deinit() == .leak) or leaked;
+ leaked = (tree_sitter_debug.deinit() == .leak) or leaked;
+ leaked = (image_debug.deinit() == .leak) or leaked;
+ leaked = (pdf_debug.deinit() == .leak) or leaked;
+ if (leaked) @panic("allocator leaks detected");
+}
+
+test "fixed allocators are separate, spill, and restart" {
+ var allocs = init(std.testing.allocator);
+ const core = try allocs.pardes.alloc(u8, 32);
+ const frame = try allocs.frame.alloc(u8, 32);
+ try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(core.ptr));
+ try std.testing.expect(frame_fallback.fixed_buffer_allocator.ownsPtr(frame.ptr));
+ try std.testing.expect(core.ptr != frame.ptr);
+
+ const spill = try allocs.pardes.alloc(u8, capacities.pardes + 1);
+ try std.testing.expect(!pardes_fallback.fixed_buffer_allocator.ownsPtr(spill.ptr));
+ allocs.pardes.free(spill);
+ allocs.frame.free(frame);
+ allocs.pardes.free(core);
+ deinit();
+
+ allocs = init(std.testing.allocator);
+ defer deinit();
+ const restarted = try allocs.pardes.alloc(u8, 32);
+ defer allocs.pardes.free(restarted);
+ try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(restarted.ptr));
+}