| ... | @@ -11,6 +11,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -11,6 +11,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 11 | pub const vtable: Allocator.VTable = .{ | 11 | pub const vtable: Allocator.VTable = .{ |
| 12 | .alloc = alloc, | 12 | .alloc = alloc, |
| 13 | .resize = resize, | 13 | .resize = resize, |
| | 14 | .remap = remap, |
| 14 | .free = free, | 15 | .free = free, |
| 15 | }; | 16 | }; |
| 16 | | 17 | |
| ... | @@ -39,14 +40,13 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -39,14 +40,13 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 39 | | 40 | |
| 40 | // TODO don't do the naive locking strategy | 41 | // TODO don't do the naive locking strategy |
| 41 | var lock: std.Thread.Mutex = .{}; | 42 | var lock: std.Thread.Mutex = .{}; |
| 42 | fn alloc(ctx: *anyopaque, len: usize, log2_align: u8, return_address: usize) ?[*]u8 { | 43 | fn alloc(ctx: *anyopaque, len: usize, alignment: mem.Alignment, return_address: usize) ?[*]u8 { |
| 43 | _ = ctx; | 44 | _ = ctx; |
| 44 | _ = return_address; | 45 | _ = return_address; |
| 45 | lock.lock(); | 46 | lock.lock(); |
| 46 | defer lock.unlock(); | 47 | defer lock.unlock(); |
| 47 | // Make room for the freelist next pointer. | 48 | // Make room for the freelist next pointer. |
| 48 | const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align)); | 49 | const actual_len = @max(len +| @sizeOf(usize), alignment.toByteUnits()); |
| 49 | const actual_len = @max(len +| @sizeOf(usize), alignment); | | |
| 50 | const slot_size = math.ceilPowerOfTwo(usize, actual_len) catch return null; | 50 | const slot_size = math.ceilPowerOfTwo(usize, actual_len) catch return null; |
| 51 | const class = math.log2(slot_size) - min_class; | 51 | const class = math.log2(slot_size) - min_class; |
| 52 | if (class < size_class_count) { | 52 | if (class < size_class_count) { |
| ... | @@ -82,7 +82,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -82,7 +82,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 82 | fn resize( | 82 | fn resize( |
| 83 | ctx: *anyopaque, | 83 | ctx: *anyopaque, |
| 84 | buf: []u8, | 84 | buf: []u8, |
| 85 | log2_buf_align: u8, | 85 | alignment: mem.Alignment, |
| 86 | new_len: usize, | 86 | new_len: usize, |
| 87 | return_address: usize, | 87 | return_address: usize, |
| 88 | ) bool { | 88 | ) bool { |
| ... | @@ -92,7 +92,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -92,7 +92,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 92 | defer lock.unlock(); | 92 | defer lock.unlock(); |
| 93 | // We don't want to move anything from one size class to another, but we | 93 | // We don't want to move anything from one size class to another, but we |
| 94 | // can recover bytes in between powers of two. | 94 | // can recover bytes in between powers of two. |
| 95 | const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align)); | 95 | const buf_align = alignment.toByteUnits(); |
| 96 | const old_actual_len = @max(buf.len + @sizeOf(usize), buf_align); | 96 | const old_actual_len = @max(buf.len + @sizeOf(usize), buf_align); |
| 97 | const new_actual_len = @max(new_len +| @sizeOf(usize), buf_align); | 97 | const new_actual_len = @max(new_len +| @sizeOf(usize), buf_align); |
| 98 | const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_actual_len); | 98 | const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_actual_len); |
| ... | @@ -109,17 +109,27 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -109,17 +109,27 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | | 111 | |
| | 112 | fn remap( |
| | 113 | context: *anyopaque, |
| | 114 | memory: []u8, |
| | 115 | alignment: mem.Alignment, |
| | 116 | new_len: usize, |
| | 117 | return_address: usize, |
| | 118 | ) ?[*]u8 { |
| | 119 | return if (resize(context, memory, alignment, new_len, return_address)) memory.ptr else null; |
| | 120 | } |
| | 121 | |
| 112 | fn free( | 122 | fn free( |
| 113 | ctx: *anyopaque, | 123 | ctx: *anyopaque, |
| 114 | buf: []u8, | 124 | buf: []u8, |
| 115 | log2_buf_align: u8, | 125 | alignment: mem.Alignment, |
| 116 | return_address: usize, | 126 | return_address: usize, |
| 117 | ) void { | 127 | ) void { |
| 118 | _ = ctx; | 128 | _ = ctx; |
| 119 | _ = return_address; | 129 | _ = return_address; |
| 120 | lock.lock(); | 130 | lock.lock(); |
| 121 | defer lock.unlock(); | 131 | defer lock.unlock(); |
| 122 | const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align)); | 132 | const buf_align = alignment.toByteUnits(); |
| 123 | const actual_len = @max(buf.len + @sizeOf(usize), buf_align); | 133 | const actual_len = @max(buf.len + @sizeOf(usize), buf_align); |
| 124 | const slot_size = math.ceilPowerOfTwoAssert(usize, actual_len); | 134 | const slot_size = math.ceilPowerOfTwoAssert(usize, actual_len); |
| 125 | const class = math.log2(slot_size) - min_class; | 135 | const class = math.log2(slot_size) - min_class; |
| ... | @@ -158,3 +168,11 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -158,3 +168,11 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 158 | } | 168 | } |
| 159 | }; | 169 | }; |
| 160 | } | 170 | } |
| | 171 | |
| | 172 | test SbrkAllocator { |
| | 173 | _ = SbrkAllocator(struct { |
| | 174 | fn sbrk(_: usize) usize { |
| | 175 | return 0; |
| | 176 | } |
| | 177 | }.sbrk); |
| | 178 | } |