authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-22 12:49:13-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-04-22 12:49:13-04:00
log3010668390794ad095eb9c102c079487c28efac6
tree8b40e9cf2cea710f8771c458a09bf67ba458cd95
parenta3e9ae8f74050d8a28553defc92e1a61b09f34c8
parenta1083b019ccc2a22cbfcbe75477895b4a0de4f72
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #939 from tgschultz/large-alignment-directalloc

DirectAllocator alignments > os.page_size on posix

1 files changed, 59 insertions(+), 8 deletions(-)

std/heap.zig+59-8
...@@ -79,19 +79,38 @@ pub const DirectAllocator = struct {...@@ -79,19 +79,38 @@ pub const DirectAllocator = struct {
7979
80 switch (builtin.os) {80 switch (builtin.os) {
81 Os.linux, Os.macosx, Os.ios => {81 Os.linux, Os.macosx, Os.ios => {
82 assert(alignment <= os.page_size);
83 const p = os.posix;82 const p = os.posix;
84 const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE,83 const alloc_size = if(alignment <= os.page_size) n else n + alignment;
85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);84 const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE,
86 if (addr == p.MAP_FAILED) {85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
87 return error.OutOfMemory;86 if(addr == p.MAP_FAILED) return error.OutOfMemory;
88 }87
89 return @intToPtr(&u8, addr)[0..n];88 if(alloc_size == n) return @intToPtr(&u8, addr)[0..n];
89
90 var aligned_addr = addr & ~usize(alignment - 1);
91 aligned_addr += alignment;
92
93 //We can unmap the unused portions of our mmap, but we must only
94 // pass munmap bytes that exist outside our allocated pages or it
95 // will happily eat us too
96
97 //Since alignment > page_size, we are by definition on a page boundry
98 const unused_start = addr;
99 const unused_len = aligned_addr - 1 - unused_start;
100
101 var err = p.munmap(@intToPtr(&u8, unused_start), unused_len);
102 debug.assert(p.getErrno(err) == 0);
103
104 //It is impossible that there is an unoccupied page at the top of our
105 // mmap.
106
107 return @intToPtr(&u8, aligned_addr)[0..n];
90 },108 },
91 Os.windows => {109 Os.windows => {
92 const amt = n + alignment + @sizeOf(usize);110 const amt = n + alignment + @sizeOf(usize);
93 const heap_handle = self.heap_handle ?? blk: {111 const heap_handle = self.heap_handle ?? blk: {
94 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;112 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0)
113 ?? return error.OutOfMemory;
95 self.heap_handle = hh;114 self.heap_handle = hh;
96 break :blk hh;115 break :blk hh;
97 };116 };
...@@ -322,6 +341,7 @@ test "DirectAllocator" {...@@ -322,6 +341,7 @@ test "DirectAllocator" {
322341
323 const allocator = &direct_allocator.allocator;342 const allocator = &direct_allocator.allocator;
324 try testAllocator(allocator);343 try testAllocator(allocator);
344 try testAllocatorLargeAlignment(allocator);
325}345}
326346
327test "ArenaAllocator" {347test "ArenaAllocator" {
...@@ -332,6 +352,7 @@ test "ArenaAllocator" {...@@ -332,6 +352,7 @@ test "ArenaAllocator" {
332 defer arena_allocator.deinit();352 defer arena_allocator.deinit();
333353
334 try testAllocator(&arena_allocator.allocator);354 try testAllocator(&arena_allocator.allocator);
355 try testAllocatorLargeAlignment(&arena_allocator.allocator);
335}356}
336357
337var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;358var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
...@@ -339,6 +360,7 @@ test "FixedBufferAllocator" {...@@ -339,6 +360,7 @@ test "FixedBufferAllocator" {
339 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);360 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
340361
341 try testAllocator(&fixed_buffer_allocator.allocator);362 try testAllocator(&fixed_buffer_allocator.allocator);
363 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
342}364}
343365
344fn testAllocator(allocator: &mem.Allocator) !void {366fn testAllocator(allocator: &mem.Allocator) !void {
...@@ -360,3 +382,32 @@ fn testAllocator(allocator: &mem.Allocator) !void {...@@ -360,3 +382,32 @@ fn testAllocator(allocator: &mem.Allocator) !void {
360382
361 allocator.free(slice);383 allocator.free(slice);
362}384}
385
386fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {
387 //Maybe a platform's page_size is actually the same as or
388 // very near usize?
389 if(os.page_size << 2 > @maxValue(usize)) return;
390
391 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
392 const large_align = u29(os.page_size << 2);
393
394 var align_mask: usize = undefined;
395 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
396
397 var slice = try allocator.allocFn(allocator, 500, large_align);
398 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
399
400 slice = try allocator.reallocFn(allocator, slice, 100, large_align);
401 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
402
403 slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
404 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
405
406 slice = try allocator.reallocFn(allocator, slice, 10, large_align);
407 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
408
409 slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
410 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
411
412 allocator.free(slice);
413}