| ... | ... | @@ -79,19 +79,38 @@ pub const DirectAllocator = struct { |
| 79 | 79 | |
| 80 | 80 | switch (builtin.os) { |
| 81 | 81 | Os.linux, Os.macosx, Os.ios => { |
| 82 | | assert(alignment <= os.page_size); |
| 83 | 82 | const p = os.posix; |
| 84 | | const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE, |
| 85 | | p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0); |
| 86 | | if (addr == p.MAP_FAILED) { |
| 87 | | return error.OutOfMemory; |
| 88 | | } |
| 89 | | return @intToPtr(&u8, addr)[0..n]; |
| 83 | const alloc_size = if(alignment <= os.page_size) n else n + alignment; |
| 84 | const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE, |
| 85 | p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0); |
| 86 | if(addr == p.MAP_FAILED) return error.OutOfMemory; |
| 87 | |
| 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 | 109 | Os.windows => { |
| 92 | 110 | const amt = n + alignment + @sizeOf(usize); |
| 93 | 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 | 114 | self.heap_handle = hh; |
| 96 | 115 | break :blk hh; |
| 97 | 116 | }; |
| ... | ... | @@ -322,6 +341,7 @@ test "DirectAllocator" { |
| 322 | 341 | |
| 323 | 342 | const allocator = &direct_allocator.allocator; |
| 324 | 343 | try testAllocator(allocator); |
| 344 | try testAllocatorLargeAlignment(allocator); |
| 325 | 345 | } |
| 326 | 346 | |
| 327 | 347 | test "ArenaAllocator" { |
| ... | ... | @@ -332,6 +352,7 @@ test "ArenaAllocator" { |
| 332 | 352 | defer arena_allocator.deinit(); |
| 333 | 353 | |
| 334 | 354 | try testAllocator(&arena_allocator.allocator); |
| 355 | try testAllocatorLargeAlignment(&arena_allocator.allocator); |
| 335 | 356 | } |
| 336 | 357 | |
| 337 | 358 | var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined; |
| ... | ... | @@ -339,6 +360,7 @@ test "FixedBufferAllocator" { |
| 339 | 360 | var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); |
| 340 | 361 | |
| 341 | 362 | try testAllocator(&fixed_buffer_allocator.allocator); |
| 363 | try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator); |
| 342 | 364 | } |
| 343 | 365 | |
| 344 | 366 | fn testAllocator(allocator: &mem.Allocator) !void { |
| ... | ... | @@ -360,3 +382,32 @@ fn testAllocator(allocator: &mem.Allocator) !void { |
| 360 | 382 | |
| 361 | 383 | allocator.free(slice); |
| 362 | 384 | } |
| 385 | |
| 386 | fn 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 | } |