| ... | ... | @@ -48,7 +48,7 @@ |
| 48 | 48 | //! |
| 49 | 49 | //! ## Basic Design: |
| 50 | 50 | //! |
| 51 | | //! Small allocations are divided into buckets. For a max page size of 4K: |
| 51 | //! Small allocations are divided into buckets: |
| 52 | 52 | //! |
| 53 | 53 | //! ``` |
| 54 | 54 | //! index obj_size |
| ... | ... | @@ -75,9 +75,6 @@ |
| 75 | 75 | //! BucketHeader, followed by "used bits", and two stack traces for each slot |
| 76 | 76 | //! (allocation trace and free trace). |
| 77 | 77 | //! |
| 78 | | //! The buckets array contains buckets for every size class below `page_size_max`. |
| 79 | | //! At runtime, only size classes below `pageSize()` will actually be used for allocations. |
| 80 | | //! |
| 81 | 78 | //! The "used bits" are 1 bit per slot representing whether the slot is used. |
| 82 | 79 | //! Allocations use the data to iterate to find a free slot. Frees assert that the |
| 83 | 80 | //! corresponding bit is 1 and set it to 0. |
| ... | ... | @@ -102,13 +99,11 @@ const math = std.math; |
| 102 | 99 | const assert = std.debug.assert; |
| 103 | 100 | const mem = std.mem; |
| 104 | 101 | const Allocator = std.mem.Allocator; |
| 105 | | const page_size_min = std.heap.page_size_min; |
| 106 | | const page_size_max = std.heap.page_size_max; |
| 107 | | const pageSize = std.heap.pageSize; |
| 102 | const page_size = std.mem.page_size; |
| 108 | 103 | const StackTrace = std.builtin.StackTrace; |
| 109 | 104 | |
| 110 | 105 | /// Integer type for pointing to slots in a small allocation |
| 111 | | const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size_max) + 1); |
| 106 | const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size) + 1); |
| 112 | 107 | |
| 113 | 108 | const default_test_stack_trace_frames: usize = if (builtin.is_test) 10 else 6; |
| 114 | 109 | const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) default_test_stack_trace_frames else 0; |
| ... | ... | @@ -162,9 +157,6 @@ pub const Config = struct { |
| 162 | 157 | |
| 163 | 158 | pub const Check = enum { ok, leak }; |
| 164 | 159 | |
| 165 | | var used_small_bucket_count_cache = std.atomic.Value(usize).init(0); |
| 166 | | var largest_used_bucket_object_size_cache = std.atomic.Value(usize).init(0); |
| 167 | | |
| 168 | 160 | /// Default initialization of this struct is deprecated; use `.init` instead. |
| 169 | 161 | pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 170 | 162 | return struct { |
| ... | ... | @@ -214,27 +206,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 214 | 206 | |
| 215 | 207 | pub const Error = mem.Allocator.Error; |
| 216 | 208 | |
| 217 | | const small_bucket_count = math.log2(page_size_max); |
| 209 | const small_bucket_count = math.log2(page_size); |
| 218 | 210 | const largest_bucket_object_size = 1 << (small_bucket_count - 1); |
| 219 | 211 | const LargestSizeClassInt = std.math.IntFittingRange(0, largest_bucket_object_size); |
| 220 | | fn used_small_bucket_count() usize { |
| 221 | | const cached = used_small_bucket_count_cache.load(.monotonic); |
| 222 | | if (cached != 0) { |
| 223 | | return cached; |
| 224 | | } |
| 225 | | const val = math.log2(pageSize()); |
| 226 | | used_small_bucket_count_cache.store(val, .monotonic); |
| 227 | | return val; |
| 228 | | } |
| 229 | | fn largest_used_bucket_object_size() usize { |
| 230 | | const cached = largest_used_bucket_object_size_cache.load(.monotonic); |
| 231 | | if (cached != 0) { |
| 232 | | return cached; |
| 233 | | } |
| 234 | | const val = @as(usize, 1) << @truncate(used_small_bucket_count() - 1); |
| 235 | | largest_used_bucket_object_size_cache.store(val, .monotonic); |
| 236 | | return val; |
| 237 | | } |
| 238 | 212 | |
| 239 | 213 | const bucketCompare = struct { |
| 240 | 214 | fn compare(a: *BucketHeader, b: *BucketHeader) std.math.Order { |
| ... | ... | @@ -287,7 +261,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 287 | 261 | // * stack_trace_addresses: [N]usize, // traces_per_slot for every allocation |
| 288 | 262 | |
| 289 | 263 | const BucketHeader = struct { |
| 290 | | page: [*]align(page_size_min) u8, |
| 264 | page: [*]align(page_size) u8, |
| 291 | 265 | alloc_cursor: SlotIndex, |
| 292 | 266 | used_count: SlotIndex, |
| 293 | 267 | |
| ... | ... | @@ -299,14 +273,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 299 | 273 | if (!config.safety) @compileError("requested size is only stored when safety is enabled"); |
| 300 | 274 | const start_ptr = @as([*]u8, @ptrCast(bucket)) + bucketRequestedSizesStart(size_class); |
| 301 | 275 | const sizes = @as([*]LargestSizeClassInt, @ptrCast(@alignCast(start_ptr))); |
| 302 | | const slot_count = @divExact(pageSize(), size_class); |
| 276 | const slot_count = @divExact(page_size, size_class); |
| 303 | 277 | return sizes[0..slot_count]; |
| 304 | 278 | } |
| 305 | 279 | |
| 306 | 280 | fn log2PtrAligns(bucket: *BucketHeader, size_class: usize) []u8 { |
| 307 | 281 | if (!config.safety) @compileError("requested size is only stored when safety is enabled"); |
| 308 | 282 | const aligns_ptr = @as([*]u8, @ptrCast(bucket)) + bucketAlignsStart(size_class); |
| 309 | | const slot_count = @divExact(pageSize(), size_class); |
| 283 | const slot_count = @divExact(page_size, size_class); |
| 310 | 284 | return aligns_ptr[0..slot_count]; |
| 311 | 285 | } |
| 312 | 286 | |
| ... | ... | @@ -338,7 +312,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 338 | 312 | /// Only valid for buckets within `empty_buckets`, and relies on the `alloc_cursor` |
| 339 | 313 | /// of empty buckets being set to `slot_count` when they are added to `empty_buckets` |
| 340 | 314 | fn emptyBucketSizeClass(bucket: *BucketHeader) usize { |
| 341 | | return @divExact(pageSize(), bucket.alloc_cursor); |
| 315 | return @divExact(page_size, bucket.alloc_cursor); |
| 342 | 316 | } |
| 343 | 317 | }; |
| 344 | 318 | |
| ... | ... | @@ -381,13 +355,13 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 381 | 355 | |
| 382 | 356 | fn bucketAlignsStart(size_class: usize) usize { |
| 383 | 357 | if (!config.safety) @compileError("requested sizes are not stored unless safety is enabled"); |
| 384 | | const slot_count = @divExact(pageSize(), size_class); |
| 358 | const slot_count = @divExact(page_size, size_class); |
| 385 | 359 | return bucketRequestedSizesStart(size_class) + (@sizeOf(LargestSizeClassInt) * slot_count); |
| 386 | 360 | } |
| 387 | 361 | |
| 388 | 362 | fn bucketStackFramesStart(size_class: usize) usize { |
| 389 | 363 | const unaligned_start = if (config.safety) blk: { |
| 390 | | const slot_count = @divExact(pageSize(), size_class); |
| 364 | const slot_count = @divExact(page_size, size_class); |
| 391 | 365 | break :blk bucketAlignsStart(size_class) + slot_count; |
| 392 | 366 | } else @sizeOf(BucketHeader) + usedBitsCount(size_class); |
| 393 | 367 | return mem.alignForward( |
| ... | ... | @@ -398,12 +372,12 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 398 | 372 | } |
| 399 | 373 | |
| 400 | 374 | fn bucketSize(size_class: usize) usize { |
| 401 | | const slot_count = @divExact(pageSize(), size_class); |
| 375 | const slot_count = @divExact(page_size, size_class); |
| 402 | 376 | return bucketStackFramesStart(size_class) + one_trace_size * traces_per_slot * slot_count; |
| 403 | 377 | } |
| 404 | 378 | |
| 405 | 379 | fn usedBitsCount(size_class: usize) usize { |
| 406 | | const slot_count = @divExact(pageSize(), size_class); |
| 380 | const slot_count = @divExact(page_size, size_class); |
| 407 | 381 | if (slot_count < 8) return 1; |
| 408 | 382 | return @divExact(slot_count, 8); |
| 409 | 383 | } |
| ... | ... | @@ -442,8 +416,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 442 | 416 | pub fn detectLeaks(self: *Self) bool { |
| 443 | 417 | var leaks = false; |
| 444 | 418 | |
| 445 | | for (0..used_small_bucket_count()) |bucket_i| { |
| 446 | | const buckets = &self.buckets[bucket_i]; |
| 419 | for (&self.buckets, 0..) |*buckets, bucket_i| { |
| 447 | 420 | if (buckets.root == null) continue; |
| 448 | 421 | const size_class = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(bucket_i)); |
| 449 | 422 | const used_bits_count = usedBitsCount(size_class); |
| ... | ... | @@ -491,7 +464,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 491 | 464 | var bucket = node.key; |
| 492 | 465 | if (config.never_unmap) { |
| 493 | 466 | // free page that was intentionally leaked by never_unmap |
| 494 | | self.backing_allocator.free(bucket.page[0..pageSize()]); |
| 467 | self.backing_allocator.free(bucket.page[0..page_size]); |
| 495 | 468 | } |
| 496 | 469 | // alloc_cursor was set to slot count when bucket added to empty_buckets |
| 497 | 470 | self.freeBucket(bucket, bucket.emptyBucketSizeClass()); |
| ... | ... | @@ -558,7 +531,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 558 | 531 | fn allocSlot(self: *Self, size_class: usize, trace_addr: usize) Error!Slot { |
| 559 | 532 | const bucket_index = math.log2(size_class); |
| 560 | 533 | var buckets = &self.buckets[bucket_index]; |
| 561 | | const slot_count = @divExact(pageSize(), size_class); |
| 534 | const slot_count = @divExact(page_size, size_class); |
| 562 | 535 | if (self.cur_buckets[bucket_index] == null or self.cur_buckets[bucket_index].?.alloc_cursor == slot_count) { |
| 563 | 536 | const new_bucket = try self.createBucket(size_class); |
| 564 | 537 | errdefer self.freeBucket(new_bucket, size_class); |
| ... | ... | @@ -591,7 +564,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 591 | 564 | addr: usize, |
| 592 | 565 | current_bucket: ?*BucketHeader, |
| 593 | 566 | ) ?*BucketHeader { |
| 594 | | const search_page: [*]align(page_size_min) u8 = @ptrFromInt(mem.alignBackward(usize, addr, pageSize())); |
| 567 | const search_page: [*]align(page_size) u8 = @ptrFromInt(mem.alignBackward(usize, addr, page_size)); |
| 595 | 568 | if (current_bucket != null and current_bucket.?.page == search_page) { |
| 596 | 569 | return current_bucket; |
| 597 | 570 | } |
| ... | ... | @@ -756,14 +729,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 756 | 729 | assert(old_mem.len != 0); |
| 757 | 730 | |
| 758 | 731 | const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align); |
| 759 | | if (aligned_size > largest_used_bucket_object_size()) { |
| 732 | if (aligned_size > largest_bucket_object_size) { |
| 760 | 733 | return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr); |
| 761 | 734 | } |
| 762 | 735 | const size_class_hint = math.ceilPowerOfTwoAssert(usize, aligned_size); |
| 763 | 736 | |
| 764 | 737 | var bucket_index = math.log2(size_class_hint); |
| 765 | 738 | var size_class: usize = size_class_hint; |
| 766 | | const bucket = while (bucket_index < used_small_bucket_count()) : (bucket_index += 1) { |
| 739 | const bucket = while (bucket_index < small_bucket_count) : (bucket_index += 1) { |
| 767 | 740 | if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| { |
| 768 | 741 | break bucket; |
| 769 | 742 | } |
| ... | ... | @@ -874,7 +847,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 874 | 847 | assert(old_mem.len != 0); |
| 875 | 848 | |
| 876 | 849 | const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align); |
| 877 | | if (aligned_size > largest_used_bucket_object_size()) { |
| 850 | if (aligned_size > largest_bucket_object_size) { |
| 878 | 851 | self.freeLarge(old_mem, log2_old_align, ret_addr); |
| 879 | 852 | return; |
| 880 | 853 | } |
| ... | ... | @@ -882,7 +855,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 882 | 855 | |
| 883 | 856 | var bucket_index = math.log2(size_class_hint); |
| 884 | 857 | var size_class: usize = size_class_hint; |
| 885 | | const bucket = while (bucket_index < used_small_bucket_count()) : (bucket_index += 1) { |
| 858 | const bucket = while (bucket_index < small_bucket_count) : (bucket_index += 1) { |
| 886 | 859 | if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| { |
| 887 | 860 | break bucket; |
| 888 | 861 | } |
| ... | ... | @@ -971,14 +944,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 971 | 944 | self.cur_buckets[bucket_index] = null; |
| 972 | 945 | } |
| 973 | 946 | if (!config.never_unmap) { |
| 974 | | self.backing_allocator.free(bucket.page[0..pageSize()]); |
| 947 | self.backing_allocator.free(bucket.page[0..page_size]); |
| 975 | 948 | } |
| 976 | 949 | if (!config.retain_metadata) { |
| 977 | 950 | self.freeBucket(bucket, size_class); |
| 978 | 951 | self.bucket_node_pool.destroy(node); |
| 979 | 952 | } else { |
| 980 | 953 | // move alloc_cursor to end so we can tell size_class later |
| 981 | | const slot_count = @divExact(pageSize(), size_class); |
| 954 | const slot_count = @divExact(page_size, size_class); |
| 982 | 955 | bucket.alloc_cursor = @as(SlotIndex, @truncate(slot_count)); |
| 983 | 956 | var empty_entry = self.empty_buckets.getEntryFor(node.key); |
| 984 | 957 | empty_entry.set(node); |
| ... | ... | @@ -1019,7 +992,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 1019 | 992 | ret_addr: usize, |
| 1020 | 993 | ) Allocator.Error![*]u8 { |
| 1021 | 994 | const new_aligned_size = @max(len, @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align))); |
| 1022 | | if (new_aligned_size > largest_used_bucket_object_size()) { |
| 995 | if (new_aligned_size > largest_bucket_object_size) { |
| 1023 | 996 | try self.large_allocations.ensureUnusedCapacity(self.backing_allocator, 1); |
| 1024 | 997 | const ptr = self.backing_allocator.rawAlloc(len, log2_ptr_align, ret_addr) orelse |
| 1025 | 998 | return error.OutOfMemory; |
| ... | ... | @@ -1062,7 +1035,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 1062 | 1035 | } |
| 1063 | 1036 | |
| 1064 | 1037 | fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader { |
| 1065 | | const page = try self.backing_allocator.alignedAlloc(u8, page_size_min, pageSize()); |
| 1038 | const page = try self.backing_allocator.alignedAlloc(u8, page_size, page_size); |
| 1066 | 1039 | errdefer self.backing_allocator.free(page); |
| 1067 | 1040 | |
| 1068 | 1041 | const bucket_size = bucketSize(size_class); |
| ... | ... | @@ -1206,17 +1179,17 @@ test "large object - grow" { |
| 1206 | 1179 | defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); |
| 1207 | 1180 | const allocator = gpa.allocator(); |
| 1208 | 1181 | |
| 1209 | | var slice1 = try allocator.alloc(u8, pageSize() * 2 - 20); |
| 1182 | var slice1 = try allocator.alloc(u8, page_size * 2 - 20); |
| 1210 | 1183 | defer allocator.free(slice1); |
| 1211 | 1184 | |
| 1212 | 1185 | const old = slice1; |
| 1213 | | slice1 = try allocator.realloc(slice1, pageSize() * 2 - 10); |
| 1186 | slice1 = try allocator.realloc(slice1, page_size * 2 - 10); |
| 1214 | 1187 | try std.testing.expect(slice1.ptr == old.ptr); |
| 1215 | 1188 | |
| 1216 | | slice1 = try allocator.realloc(slice1, pageSize() * 2); |
| 1189 | slice1 = try allocator.realloc(slice1, page_size * 2); |
| 1217 | 1190 | try std.testing.expect(slice1.ptr == old.ptr); |
| 1218 | 1191 | |
| 1219 | | slice1 = try allocator.realloc(slice1, pageSize() * 2 + 1); |
| 1192 | slice1 = try allocator.realloc(slice1, page_size * 2 + 1); |
| 1220 | 1193 | } |
| 1221 | 1194 | |
| 1222 | 1195 | test "realloc small object to large object" { |
| ... | ... | @@ -1230,7 +1203,7 @@ test "realloc small object to large object" { |
| 1230 | 1203 | slice[60] = 0x34; |
| 1231 | 1204 | |
| 1232 | 1205 | // This requires upgrading to a large object |
| 1233 | | const large_object_size = pageSize() * 2 + 50; |
| 1206 | const large_object_size = page_size * 2 + 50; |
| 1234 | 1207 | slice = try allocator.realloc(slice, large_object_size); |
| 1235 | 1208 | try std.testing.expect(slice[0] == 0x12); |
| 1236 | 1209 | try std.testing.expect(slice[60] == 0x34); |
| ... | ... | @@ -1241,22 +1214,22 @@ test "shrink large object to large object" { |
| 1241 | 1214 | defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); |
| 1242 | 1215 | const allocator = gpa.allocator(); |
| 1243 | 1216 | |
| 1244 | | var slice = try allocator.alloc(u8, pageSize() * 2 + 50); |
| 1217 | var slice = try allocator.alloc(u8, page_size * 2 + 50); |
| 1245 | 1218 | defer allocator.free(slice); |
| 1246 | 1219 | slice[0] = 0x12; |
| 1247 | 1220 | slice[60] = 0x34; |
| 1248 | 1221 | |
| 1249 | | if (!allocator.resize(slice, pageSize() * 2 + 1)) return; |
| 1250 | | slice = slice.ptr[0 .. pageSize() * 2 + 1]; |
| 1222 | if (!allocator.resize(slice, page_size * 2 + 1)) return; |
| 1223 | slice = slice.ptr[0 .. page_size * 2 + 1]; |
| 1251 | 1224 | try std.testing.expect(slice[0] == 0x12); |
| 1252 | 1225 | try std.testing.expect(slice[60] == 0x34); |
| 1253 | 1226 | |
| 1254 | | try std.testing.expect(allocator.resize(slice, pageSize() * 2 + 1)); |
| 1255 | | slice = slice[0 .. pageSize() * 2 + 1]; |
| 1227 | try std.testing.expect(allocator.resize(slice, page_size * 2 + 1)); |
| 1228 | slice = slice[0 .. page_size * 2 + 1]; |
| 1256 | 1229 | try std.testing.expect(slice[0] == 0x12); |
| 1257 | 1230 | try std.testing.expect(slice[60] == 0x34); |
| 1258 | 1231 | |
| 1259 | | slice = try allocator.realloc(slice, pageSize() * 2); |
| 1232 | slice = try allocator.realloc(slice, page_size * 2); |
| 1260 | 1233 | try std.testing.expect(slice[0] == 0x12); |
| 1261 | 1234 | try std.testing.expect(slice[60] == 0x34); |
| 1262 | 1235 | } |
| ... | ... | @@ -1272,13 +1245,13 @@ test "shrink large object to large object with larger alignment" { |
| 1272 | 1245 | var fba = std.heap.FixedBufferAllocator.init(&debug_buffer); |
| 1273 | 1246 | const debug_allocator = fba.allocator(); |
| 1274 | 1247 | |
| 1275 | | const alloc_size = pageSize() * 2 + 50; |
| 1248 | const alloc_size = page_size * 2 + 50; |
| 1276 | 1249 | var slice = try allocator.alignedAlloc(u8, 16, alloc_size); |
| 1277 | 1250 | defer allocator.free(slice); |
| 1278 | 1251 | |
| 1279 | 1252 | const big_alignment: usize = switch (builtin.os.tag) { |
| 1280 | | .windows => pageSize() * 32, // Windows aligns to 64K. |
| 1281 | | else => pageSize() * 2, |
| 1253 | .windows => page_size * 32, // Windows aligns to 64K. |
| 1254 | else => page_size * 2, |
| 1282 | 1255 | }; |
| 1283 | 1256 | // This loop allocates until we find a page that is not aligned to the big |
| 1284 | 1257 | // alignment. Then we shrink the allocation after the loop, but increase the |
| ... | ... | @@ -1304,7 +1277,7 @@ test "realloc large object to small object" { |
| 1304 | 1277 | defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); |
| 1305 | 1278 | const allocator = gpa.allocator(); |
| 1306 | 1279 | |
| 1307 | | var slice = try allocator.alloc(u8, pageSize() * 2 + 50); |
| 1280 | var slice = try allocator.alloc(u8, page_size * 2 + 50); |
| 1308 | 1281 | defer allocator.free(slice); |
| 1309 | 1282 | slice[0] = 0x12; |
| 1310 | 1283 | slice[16] = 0x34; |
| ... | ... | @@ -1346,18 +1319,18 @@ test "realloc large object to larger alignment" { |
| 1346 | 1319 | var fba = std.heap.FixedBufferAllocator.init(&debug_buffer); |
| 1347 | 1320 | const debug_allocator = fba.allocator(); |
| 1348 | 1321 | |
| 1349 | | var slice = try allocator.alignedAlloc(u8, 16, pageSize() * 2 + 50); |
| 1322 | var slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50); |
| 1350 | 1323 | defer allocator.free(slice); |
| 1351 | 1324 | |
| 1352 | 1325 | const big_alignment: usize = switch (builtin.os.tag) { |
| 1353 | | .windows => pageSize() * 32, // Windows aligns to 64K. |
| 1354 | | else => pageSize() * 2, |
| 1326 | .windows => page_size * 32, // Windows aligns to 64K. |
| 1327 | else => page_size * 2, |
| 1355 | 1328 | }; |
| 1356 | 1329 | // This loop allocates until we find a page that is not aligned to the big alignment. |
| 1357 | 1330 | var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator); |
| 1358 | 1331 | while (mem.isAligned(@intFromPtr(slice.ptr), big_alignment)) { |
| 1359 | 1332 | try stuff_to_free.append(slice); |
| 1360 | | slice = try allocator.alignedAlloc(u8, 16, pageSize() * 2 + 50); |
| 1333 | slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50); |
| 1361 | 1334 | } |
| 1362 | 1335 | while (stuff_to_free.popOrNull()) |item| { |
| 1363 | 1336 | allocator.free(item); |
| ... | ... | @@ -1365,15 +1338,15 @@ test "realloc large object to larger alignment" { |
| 1365 | 1338 | slice[0] = 0x12; |
| 1366 | 1339 | slice[16] = 0x34; |
| 1367 | 1340 | |
| 1368 | | slice = try allocator.reallocAdvanced(slice, 32, pageSize() * 2 + 100); |
| 1341 | slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100); |
| 1369 | 1342 | try std.testing.expect(slice[0] == 0x12); |
| 1370 | 1343 | try std.testing.expect(slice[16] == 0x34); |
| 1371 | 1344 | |
| 1372 | | slice = try allocator.reallocAdvanced(slice, 32, pageSize() * 2 + 25); |
| 1345 | slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25); |
| 1373 | 1346 | try std.testing.expect(slice[0] == 0x12); |
| 1374 | 1347 | try std.testing.expect(slice[16] == 0x34); |
| 1375 | 1348 | |
| 1376 | | slice = try allocator.reallocAdvanced(slice, big_alignment, pageSize() * 2 + 100); |
| 1349 | slice = try allocator.reallocAdvanced(slice, big_alignment, page_size * 2 + 100); |
| 1377 | 1350 | try std.testing.expect(slice[0] == 0x12); |
| 1378 | 1351 | try std.testing.expect(slice[16] == 0x34); |
| 1379 | 1352 | } |
| ... | ... | @@ -1389,7 +1362,7 @@ test "large object shrinks to small but allocation fails during shrink" { |
| 1389 | 1362 | defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); |
| 1390 | 1363 | const allocator = gpa.allocator(); |
| 1391 | 1364 | |
| 1392 | | var slice = try allocator.alloc(u8, pageSize() * 2 + 50); |
| 1365 | var slice = try allocator.alloc(u8, page_size * 2 + 50); |
| 1393 | 1366 | defer allocator.free(slice); |
| 1394 | 1367 | slice[0] = 0x12; |
| 1395 | 1368 | slice[3] = 0x34; |
| ... | ... | @@ -1460,7 +1433,7 @@ test "double frees" { |
| 1460 | 1433 | try std.testing.expect(GPA.searchBucket(&gpa.empty_buckets, @intFromPtr(small.ptr), null) != null); |
| 1461 | 1434 | |
| 1462 | 1435 | // detect a large allocation double free |
| 1463 | | const large = try allocator.alloc(u8, 2 * pageSize()); |
| 1436 | const large = try allocator.alloc(u8, 2 * page_size); |
| 1464 | 1437 | try std.testing.expect(gpa.large_allocations.contains(@intFromPtr(large.ptr))); |
| 1465 | 1438 | try std.testing.expectEqual(gpa.large_allocations.getEntry(@intFromPtr(large.ptr)).?.value_ptr.bytes, large); |
| 1466 | 1439 | allocator.free(large); |
| ... | ... | @@ -1469,7 +1442,7 @@ test "double frees" { |
| 1469 | 1442 | |
| 1470 | 1443 | const normal_small = try allocator.alloc(u8, size_class); |
| 1471 | 1444 | defer allocator.free(normal_small); |
| 1472 | | const normal_large = try allocator.alloc(u8, 2 * pageSize()); |
| 1445 | const normal_large = try allocator.alloc(u8, 2 * page_size); |
| 1473 | 1446 | defer allocator.free(normal_large); |
| 1474 | 1447 | |
| 1475 | 1448 | // check that flushing retained metadata doesn't disturb live allocations |
| ... | ... | @@ -1502,8 +1475,8 @@ test "bug 9995 fix, large allocs count requested size not backing size" { |
| 1502 | 1475 | var gpa = GeneralPurposeAllocator(.{ .enable_memory_limit = true }){}; |
| 1503 | 1476 | const allocator = gpa.allocator(); |
| 1504 | 1477 | |
| 1505 | | var buf = try allocator.alignedAlloc(u8, 1, pageSize() + 1); |
| 1506 | | try std.testing.expect(gpa.total_requested_bytes == pageSize() + 1); |
| 1478 | var buf = try allocator.alignedAlloc(u8, 1, page_size + 1); |
| 1479 | try std.testing.expect(gpa.total_requested_bytes == page_size + 1); |
| 1507 | 1480 | buf = try allocator.realloc(buf, 1); |
| 1508 | 1481 | try std.testing.expect(gpa.total_requested_bytes == 1); |
| 1509 | 1482 | buf = try allocator.realloc(buf, 2); |