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
signature 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 {...@@ -139,7 +139,11 @@ pub const DirectAllocator = struct {
139 return shrink(allocator, old_mem, old_align, new_size, new_align);139 return shrink(allocator, old_mem, old_align, new_size, new_align);
140 }140 }
141 const result = try alloc(allocator, new_size, new_align);141 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 }
143 _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len);147 _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len);
144 return result;148 return result;
145 },149 },
...@@ -152,9 +156,8 @@ pub const DirectAllocator = struct {...@@ -152,9 +156,8 @@ pub const DirectAllocator = struct {
152 const root_addr = @intToPtr(*align(1) usize, old_record_addr).*;156 const root_addr = @intToPtr(*align(1) usize, old_record_addr).*;
153 const old_ptr = @intToPtr(*c_void, root_addr);157 const old_ptr = @intToPtr(*c_void, root_addr);
154 158
155 if(new_size == 0)159 if(new_size == 0) {
156 {160 if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
157 if(os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
158 return old_mem[0..0];161 return old_mem[0..0];
159 }162 }
160 163
...@@ -167,8 +170,17 @@ pub const DirectAllocator = struct {...@@ -167,8 +170,17 @@ pub const DirectAllocator = struct {
167 ) orelse return error.OutOfMemory;170 ) orelse return error.OutOfMemory;
168 const offset = old_adjusted_addr - root_addr;171 const offset = old_adjusted_addr - root_addr;
169 const new_root_addr = @ptrToInt(new_ptr);172 const new_root_addr = @ptrToInt(new_ptr);
170 const new_adjusted_addr = new_root_addr + offset;173 const adjusted_addr = new_root_addr + offset;
171 assert(new_adjusted_addr % new_align == 0);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 }
172 const new_record_addr = new_adjusted_addr + new_size;184 const new_record_addr = new_adjusted_addr + new_size;
173 @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr;185 @intToPtr(*align(1) usize, new_record_addr).* = new_root_addr;
174 return @intToPtr([*]u8, new_adjusted_addr)[0..new_size];186 return @intToPtr([*]u8, new_adjusted_addr)[0..new_size];
...@@ -258,7 +270,11 @@ pub const ArenaAllocator = struct {...@@ -258,7 +270,11 @@ pub const ArenaAllocator = struct {
258 return error.OutOfMemory;270 return error.OutOfMemory;
259 } else {271 } else {
260 const result = try alloc(allocator, new_size, new_align);272 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 }
262 return result;278 return result;
263 }279 }
264 }280 }
...@@ -316,7 +332,11 @@ pub const FixedBufferAllocator = struct {...@@ -316,7 +332,11 @@ pub const FixedBufferAllocator = struct {
316 return error.OutOfMemory;332 return error.OutOfMemory;
317 } else {333 } else {
318 const result = try alloc(allocator, new_size, new_align);334 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 }
320 return result;340 return result;
321 }341 }
322 }342 }
...@@ -459,7 +479,11 @@ pub const ThreadSafeFixedBufferAllocator = blk: {...@@ -459,7 +479,11 @@ pub const ThreadSafeFixedBufferAllocator = blk: {
459 return error.OutOfMemory;479 return error.OutOfMemory;
460 } else {480 } else {
461 const result = try alloc(allocator, new_size, new_align);481 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 }
463 return result;487 return result;
464 }488 }
465 }489 }
...@@ -569,6 +593,7 @@ test "DirectAllocator" {...@@ -569,6 +593,7 @@ test "DirectAllocator" {
569 try testAllocator(allocator);593 try testAllocator(allocator);
570 try testAllocatorAligned(allocator, 16);594 try testAllocatorAligned(allocator, 16);
571 try testAllocatorLargeAlignment(allocator);595 try testAllocatorLargeAlignment(allocator);
596 try testAllocatorAlignedShrink(allocator);
572}597}
573598
574test "ArenaAllocator" {599test "ArenaAllocator" {
...@@ -581,15 +606,17 @@ test "ArenaAllocator" {...@@ -581,15 +606,17 @@ test "ArenaAllocator" {
581 try testAllocator(&arena_allocator.allocator);606 try testAllocator(&arena_allocator.allocator);
582 try testAllocatorAligned(&arena_allocator.allocator, 16);607 try testAllocatorAligned(&arena_allocator.allocator, 16);
583 try testAllocatorLargeAlignment(&arena_allocator.allocator);608 try testAllocatorLargeAlignment(&arena_allocator.allocator);
609 try testAllocatorAlignedShrink(&arena_allocator.allocator);
584}610}
585611
586var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;612var test_fixed_buffer_allocator_memory: [40000 * @sizeOf(usize)]u8 = undefined;
587test "FixedBufferAllocator" {613test "FixedBufferAllocator" {
588 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);614 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
589615
590 try testAllocator(&fixed_buffer_allocator.allocator);616 try testAllocator(&fixed_buffer_allocator.allocator);
591 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);617 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
592 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);618 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
619 try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator);
593}620}
594621
595test "FixedBufferAllocator Reuse memory on realloc" {622test "FixedBufferAllocator Reuse memory on realloc" {
...@@ -627,6 +654,7 @@ test "ThreadSafeFixedBufferAllocator" {...@@ -627,6 +654,7 @@ test "ThreadSafeFixedBufferAllocator" {
627 try testAllocator(&fixed_buffer_allocator.allocator);654 try testAllocator(&fixed_buffer_allocator.allocator);
628 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);655 try testAllocatorAligned(&fixed_buffer_allocator.allocator, 16);
629 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);656 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
657 try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator);
630}658}
631659
632fn testAllocator(allocator: *mem.Allocator) !void {660fn testAllocator(allocator: *mem.Allocator) !void {
...@@ -709,3 +737,28 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo...@@ -709,3 +737,28 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo
709737
710 allocator.free(slice);738 allocator.free(slice);
711}739}
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}