1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
const std = @import("std");
const builtin = @import("builtin");
const limits = @import("limits.zig");
const Allocator = std.mem.Allocator;
const debug_enabled = builtin.mode == .Debug;
pub const Allocators = struct {
pardes: Allocator,
frame: Allocator,
lsp: Allocator,
tree_sitter: Allocator,
image: Allocator,
pdf: Allocator,
};
/// The static reservations, one per profile tier. See `limits.arena` for why
/// each number is what it is, and why the board's are 4 KiB and zero.
var pardes_fallback: std.heap.StackFallbackAllocator(limits.arena.pardes) = undefined;
var frame_fallback: std.heap.StackFallbackAllocator(limits.arena.frame) = undefined;
var tree_sitter_fallback: std.heap.StackFallbackAllocator(limits.arena.tree_sitter) = undefined;
var image_fallback: std.heap.StackFallbackAllocator(limits.arena.image) = undefined;
var pdf_fallback: std.heap.StackFallbackAllocator(limits.arena.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, limits.arena.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));
}
|