test/support/std/lang/alloc.rad 3.3 KiB raw
1
//! Arena allocation support for binary lowering fixtures.
2
3
/// Error returned when an arena cannot satisfy an allocation.
4
export union AllocError: Copy {
5
    /// The arena has insufficient storage.
6
    OutOfMemory,
7
}
8
9
/// Bump allocator backed by a byte slice.
10
export record Arena {
11
    /// Backing storage.
12
    data: *mut [u8],
13
    /// Current allocation offset in bytes.
14
    offset: u32,
15
}
16
17
/// Create an arena backed by `data`.
18
export fn new(data: *mut [u8]) -> Arena {
19
    return Arena { data, offset: 0 };
20
}
21
22
/// Reset the arena to its initial empty state.
23
export fn reset(arena: &mut Arena) {
24
    set arena.offset = 0;
25
}
26
27
/// Return the number of bytes committed in the arena.
28
export fn used(arena: &Arena) -> u32 {
29
    return arena.offset;
30
}
31
32
/// Allocate aligned storage without changing the arena after failure.
33
export unsafe fn alloc(arena: *unsafe mut Arena, size: u32, alignment: u32) -> *mut opaque throws (AllocError) {
34
    assert alignment > 0;
35
    assert size > 0;
36
    assert (alignment & (alignment - 1)) == 0;
37
38
    let capacity = arena.data.len;
39
    if arena.offset >= capacity {
40
        throw AllocError::OutOfMemory;
41
    }
42
    let address = &arena.data[0] as u64;
43
    let mask = (alignment - 1) as u64;
44
    let remainder = ((address & mask) + (arena.offset as u64 & mask)) & mask;
45
    let padding = ((alignment as u64 - remainder) & mask) as u32;
46
    let available = capacity - arena.offset;
47
    if padding > available or size > available - padding {
48
        throw AllocError::OutOfMemory;
49
    }
50
    let aligned = arena.offset + padding;
51
    let base: *mut u8 = &mut arena.data[aligned];
52
    set arena.offset = aligned + size;
53
    return base as *mut opaque;
54
}
55
56
/// Allocate raw storage that remains valid until the arena is reset.
57
export unsafe fn allocRaw(arena: &mut Arena, size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError) {
58
    let owner = try alloc(&mut *arena, size, alignment);
59
    let byte = owner as *mut u8;
60
    return &mut *byte as *unsafe mut opaque;
61
}
62
63
/// Allocate a raw slice that remains valid until the arena is reset.
64
export unsafe fn allocRawSlice(arena: &mut Arena, size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError) {
65
    if count == 0 {
66
        return &mut [];
67
    }
68
    if size <> 0 and count > 4294967295 / size {
69
        throw AllocError::OutOfMemory;
70
    }
71
    let raw = try allocRaw(arena, size * count, alignment);
72
    return @sliceOf(raw, count);
73
}
74
75
/// Raw storage provider for allocation sessions.
76
export trait Alloc {
77
    /// Reserve one uninitialized object.
78
    unsafe fn (&mut Alloc) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError);
79
    /// Reserve an uninitialized slice.
80
    unsafe fn (&mut Alloc) reserveSlice(itemSize: u32, itemAlignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError);
81
}
82
83
instance Alloc for Arena {
84
    /// Reserve one uninitialized object in the arena.
85
    unsafe fn (arena: &mut Arena) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError) {
86
        return try allocRaw(arena, size, alignment);
87
    }
88
89
    /// Reserve an uninitialized slice in the arena.
90
    unsafe fn (arena: &mut Arena) reserveSlice(size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError) {
91
        return try allocRawSlice(arena, size, alignment, count);
92
    }
93
}