authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-24 23:44:28-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-04-24 23:44:28-04:00
log56e07622c692f70eb10836b86c5fda02c53e2394
tree7b394c4517a2a332b4f3274dbebc1ba9d674653e
parent8ef7f6febb7132d7a1ee44199fd22006f326de5c
parent8ce130de3cf38e09cfbcbd1b22da34ae5b27a040
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2312 from squeek502/heap-shrink-large-align

fix heap allocators when shrinking an object but growing its alignment

1 files changed, 63 insertions(+), 10 deletions(-)

std/heap.zig+63-10
......@@ -139,7 +139,11 @@ pub const DirectAllocator = struct {
139139 return shrink(allocator, old_mem, old_align, new_size, new_align);
140140 }
141141 const result = try alloc(allocator, new_size, new_align);
142 mem.copy(u8, result, old_mem);
142 if (result.len >= old_mem.len) {
143 mem.copy(u8, result, old_mem);
144 } else {
145 @memcpy(result.ptr, old_mem.ptr, new_size);
146 }
143147 _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len);
144148 return result;
145149 },
......@@ -152,9 +156,8 @@ pub const DirectAllocator = struct {
152156 const root_addr = @intToPtr(*align(1) usize, old_record_addr).*;
153157 const old_ptr = @intToPtr(*c_void, root_addr);
154158
155 if(new_size == 0)
156 {
157 if(os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
159 if(new_size == 0) {
160 if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
158161 return old_mem[0..0];
159162 }
160163
......@@ -167,8 +170,17 @@ pub const DirectAllocator = struct {
167170 ) orelse return error.OutOfMemory;
168171 const offset = old_adjusted_addr - root_addr;
169172 const new_root_addr = @ptrToInt(new_ptr);
170 const new_adjusted_addr = new_root_addr + offset;
171 assert(new_adjusted_addr % new_align == 0);
173 const adjusted_addr = new_root_addr + offset;
174 const new_adjusted_addr = mem.alignForward(new_root_addr, new_align);
175 // If HeapReAlloc didn't happen to move the memory to the new alignment
176 // then we need to copy it
177 if (new_adjusted_addr != adjusted_addr) {
178 @memcpy(
179 @intToPtr([*]u8, new_adjusted_addr),
180 @intToPtr([*]u8, adjusted_addr),
181 std.math.min(old_mem.len, new_size),
182 );
183 }
172184 const new_record_addr = new_adjusted_addr + new_size;
173185 @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr;
174186 return @intToPtr([*]u8, new_adjusted_addr)[0..new_size];
......@@ -258,7 +270,11 @@ pub const ArenaAllocator = struct {
258270 return error.OutOfMemory;
259271 } else {
260272 const result = try alloc(allocator, new_size, new_align);
261 mem.copy(u8, result, old_mem);
273 if (result.len >= old_mem.len) {
274 mem.copy(u8, result, old_mem);
275 } else {
276 @memcpy(result.ptr, old_mem.ptr, new_size);
277 }
262278 return result;
263279 }
264280 }
......@@ -316,7 +332,11 @@ pub const FixedBufferAllocator = struct {
316332 return error.OutOfMemory;
317333 } else {
318334 const result = try alloc(allocator, new_size, new_align);
319 mem.copy(u8, result, old_mem);
335 if (result.len >= old_mem.len) {
336 mem.copy(u8, result, old_mem);
337 } else {
338 @memcpy(result.ptr, old_mem.ptr, new_size);
339 }
320340 return result;
321341 }
322342 }
......@@ -459,7 +479,11 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
459479 return error.OutOfMemory;
460480 } else {
461481 const result = try alloc(allocator, new_size, new_align);
462 mem.copy(u8, result, old_mem);
482 if (result.len >= old_mem.len) {
483 mem.copy(u8, result, old_mem);
484 } else {
485 @memcpy(result.ptr, old_mem.ptr, new_size);
486 }
463487 return result;
464488 }
465489 }
......@@ -569,6 +593,7 @@ test "DirectAllocator" {
569593 try testAllocator(allocator);
570594 try testAllocatorAligned(allocator, 16);
571595 try testAllocatorLargeAlignment(allocator);
596 try testAllocatorAlignedShrink(allocator);
572597}
573598
574599test "ArenaAllocator" {
......@@ -581,15 +606,17 @@ test "ArenaAllocator" {
581606 try testAllocator(&arena_allocator.allocator);
582607 try testAllocatorAligned(&arena_allocator.allocator, 16);
583608 try testAllocatorLargeAlignment(&arena_allocator.allocator);
609 try testAllocatorAlignedShrink(&arena_allocator.allocator);
584610}
585611
586var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
612var test_fixed_buffer_allocator_memory: [40000 * @sizeOf(usize)]u8 = undefined;
587613test "FixedBufferAllocator" {
588614 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
589615
590616 try testAllocator(&fixed_buffer_allocator.allocator);
591617 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
592618 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
619 try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator);
593620}
594621
595622test "FixedBufferAllocator Reuse memory on realloc" {
......@@ -627,6 +654,7 @@ test "ThreadSafeFixedBufferAllocator" {
627654 try testAllocator(&fixed_buffer_allocator.allocator);
628655 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
629656 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
657 try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator);
630658}
631659
632660fn testAllocator(allocator: *mem.Allocator) !void {
......@@ -709,3 +737,28 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo
709737
710738 allocator.free(slice);
711739}
740
741fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!void {
742 var debug_buffer: [1000]u8 = undefined;
743 const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator;
744
745 const alloc_size = os.page_size * 2 + 50;
746 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);
747 defer allocator.free(slice);
748
749 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);
750 while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), os.page_size * 2)) {
751 try stuff_to_free.append(slice);
752 slice = try allocator.alignedAlloc(u8, 16, alloc_size);
753 }
754 while (stuff_to_free.popOrNull()) |item| {
755 allocator.free(item);
756 }
757 slice[0] = 0x12;
758 slice[60] = 0x34;
759
760 // realloc to a smaller size but with a larger alignment
761 slice = try allocator.alignedRealloc(slice, os.page_size * 2, alloc_size / 2);
762 testing.expect(slice[0] == 0x12);
763 testing.expect(slice[60] == 0x34);
764}