| ... | @@ -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 | } |
| 573 | | 598 | |
| 574 | test "ArenaAllocator" { | 599 | test "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 | } |
| 585 | | 611 | |
| 586 | var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined; | 612 | var test_fixed_buffer_allocator_memory: [40000 * @sizeOf(usize)]u8 = undefined; |
| 587 | test "FixedBufferAllocator" { | 613 | test "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..]); |
| 589 | | 615 | |
| 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 | } |
| 594 | | 621 | |
| 595 | test "FixedBufferAllocator Reuse memory on realloc" { | 622 | test "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 | } |
| 631 | | 659 | |
| 632 | fn testAllocator(allocator: *mem.Allocator) !void { | 660 | fn 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 |
| 709 | | 737 | |
| 710 | allocator.free(slice); | 738 | allocator.free(slice); |
| 711 | } | 739 | } |
| | 740 | |
| | 741 | fn 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 | } |