| ... | ... | @@ -265,7 +265,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 265 | 265 | |
| 266 | 266 | /// Bucket: In memory, in order: |
| 267 | 267 | /// * BucketHeader |
| 268 | | /// * bucket_used_bits: [N]u8, // 1 bit for every slot; 1 byte for every 8 slots |
| 268 | /// * bucket_used_bits: [N]usize, // 1 bit for every slot |
| 269 | 269 | /// -- below only exists when config.safety is true -- |
| 270 | 270 | /// * requested_sizes: [N]LargestSizeClassInt // 1 int for every slot |
| 271 | 271 | /// * log2_ptr_aligns: [N]u8 // 1 byte for every slot |
| ... | ... | @@ -282,10 +282,10 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 282 | 282 | return @ptrFromInt(unaligned & ~(@as(usize, @alignOf(BucketHeader)) - 1)); |
| 283 | 283 | } |
| 284 | 284 | |
| 285 | | // TODO use usize instead of u8 |
| 286 | | fn usedBits(bucket: *BucketHeader, index: usize) *u8 { |
| 287 | | // TODO avoid ptr to int |
| 288 | | return @ptrFromInt(@intFromPtr(bucket) + @sizeOf(BucketHeader) + index); |
| 285 | fn usedBits(bucket: *BucketHeader, index: usize) *usize { |
| 286 | const ptr: [*]u8 = @ptrCast(bucket); |
| 287 | const bits: [*]usize = @alignCast(@ptrCast(ptr + @sizeOf(BucketHeader))); |
| 288 | return &bits[index]; |
| 289 | 289 | } |
| 290 | 290 | |
| 291 | 291 | fn requestedSizes(bucket: *BucketHeader, slot_count: usize) []LargestSizeClassInt { |
| ... | ... | @@ -360,7 +360,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 360 | 360 | if (!config.safety) @compileError("requested sizes are not stored unless safety is enabled"); |
| 361 | 361 | return mem.alignForward( |
| 362 | 362 | usize, |
| 363 | | @sizeOf(BucketHeader) + usedBitsCount(slot_count), |
| 363 | @sizeOf(BucketHeader) + usedBitsSize(slot_count), |
| 364 | 364 | @alignOf(LargestSizeClassInt), |
| 365 | 365 | ); |
| 366 | 366 | } |
| ... | ... | @@ -374,7 +374,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 374 | 374 | const unaligned_start = if (config.safety) |
| 375 | 375 | bucketAlignsStart(slot_count) + slot_count |
| 376 | 376 | else |
| 377 | | @sizeOf(BucketHeader) + usedBitsCount(slot_count); |
| 377 | @sizeOf(BucketHeader) + usedBitsSize(slot_count); |
| 378 | 378 | return mem.alignForward(usize, unaligned_start, @alignOf(usize)); |
| 379 | 379 | } |
| 380 | 380 | |
| ... | ... | @@ -404,8 +404,11 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | 406 | fn usedBitsCount(slot_count: usize) usize { |
| 407 | | assert(slot_count >= 8); |
| 408 | | return (slot_count + 7) / 8; |
| 407 | return (slot_count + (@bitSizeOf(usize) - 1)) / @bitSizeOf(usize); |
| 408 | } |
| 409 | |
| 410 | fn usedBitsSize(slot_count: usize) usize { |
| 411 | return usedBitsCount(slot_count) * @sizeOf(usize); |
| 409 | 412 | } |
| 410 | 413 | |
| 411 | 414 | fn detectLeaksInBucket(bucket: *BucketHeader, size_class_index: usize, used_bits_count: usize) bool { |
| ... | ... | @@ -413,13 +416,13 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 413 | 416 | const slot_count = slot_counts[size_class_index]; |
| 414 | 417 | var leaks = false; |
| 415 | 418 | for (0..used_bits_count) |used_bits_byte| { |
| 416 | | const used_byte = bucket.usedBits(used_bits_byte).*; |
| 417 | | if (used_byte != 0) { |
| 418 | | for (0..8) |bit_index_usize| { |
| 419 | | const bit_index: u3 = @intCast(bit_index_usize); |
| 420 | | const is_used = @as(u1, @truncate(used_byte >> bit_index)) != 0; |
| 419 | const used_int = bucket.usedBits(used_bits_byte).*; |
| 420 | if (used_int != 0) { |
| 421 | for (0..@bitSizeOf(usize)) |bit_index_usize| { |
| 422 | const bit_index: Log2USize = @intCast(bit_index_usize); |
| 423 | const is_used = @as(u1, @truncate(used_int >> bit_index)) != 0; |
| 421 | 424 | if (is_used) { |
| 422 | | const slot_index: SlotIndex = @intCast(used_bits_byte * 8 + bit_index); |
| 425 | const slot_index: SlotIndex = @intCast(used_bits_byte * @bitSizeOf(usize) + bit_index); |
| 423 | 426 | const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); |
| 424 | 427 | const page_addr = @intFromPtr(bucket) & ~(page_size - 1); |
| 425 | 428 | const addr = page_addr + slot_index * size_class; |
| ... | ... | @@ -740,9 +743,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 740 | 743 | if (slot_index < slot_count) { |
| 741 | 744 | @branchHint(.likely); |
| 742 | 745 | bucket.allocated_count = slot_index + 1; |
| 743 | | const used_bits_byte = bucket.usedBits(slot_index / 8); |
| 744 | | const used_bit_index: u3 = @intCast(slot_index % 8); |
| 745 | | used_bits_byte.* |= (@as(u8, 1) << used_bit_index); |
| 746 | const used_bits_byte = bucket.usedBits(slot_index / @bitSizeOf(usize)); |
| 747 | const used_bit_index: Log2USize = @intCast(slot_index % @bitSizeOf(usize)); |
| 748 | used_bits_byte.* |= (@as(usize, 1) << used_bit_index); |
| 746 | 749 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); |
| 747 | 750 | if (config.stack_trace_frames > 0) { |
| 748 | 751 | bucket.captureStackTrace(ret_addr, slot_count, slot_index, .alloc); |
| ... | ... | @@ -771,7 +774,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 771 | 774 | self.buckets[size_class_index] = bucket; |
| 772 | 775 | |
| 773 | 776 | if (!config.backing_allocator_zeroes) { |
| 774 | | @memset(@as([*]u8, @as(*[1]u8, bucket.usedBits(0)))[0..usedBitsCount(slot_count)], 0); |
| 777 | @memset(@as([*]usize, @as(*[1]usize, bucket.usedBits(0)))[0..usedBitsCount(slot_count)], 0); |
| 775 | 778 | if (config.safety) @memset(bucket.requestedSizes(slot_count), 0); |
| 776 | 779 | } |
| 777 | 780 | |
| ... | ... | @@ -858,8 +861,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 858 | 861 | const page_offset = freed_addr - page_addr; |
| 859 | 862 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); |
| 860 | 863 | const slot_index: SlotIndex = @intCast(page_offset / size_class); |
| 861 | | const used_byte_index = slot_index / 8; |
| 862 | | const used_bit_index: u3 = @intCast(slot_index % 8); |
| 864 | const used_byte_index = slot_index / @bitSizeOf(usize); |
| 865 | const used_bit_index: Log2USize = @intCast(slot_index % @bitSizeOf(usize)); |
| 863 | 866 | const used_byte = bucket.usedBits(used_byte_index); |
| 864 | 867 | const is_used = @as(u1, @truncate(used_byte.* >> used_bit_index)) != 0; |
| 865 | 868 | if (!is_used) { |
| ... | ... | @@ -916,7 +919,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 916 | 919 | bucket.captureStackTrace(return_address, slot_count, slot_index, .free); |
| 917 | 920 | } |
| 918 | 921 | |
| 919 | | used_byte.* &= ~(@as(u8, 1) << used_bit_index); |
| 922 | used_byte.* &= ~(@as(usize, 1) << used_bit_index); |
| 920 | 923 | if (config.safety) { |
| 921 | 924 | bucket.requestedSizes(slot_count)[slot_index] = 0; |
| 922 | 925 | } |
| ... | ... | @@ -953,8 +956,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 953 | 956 | const page_offset = memory_addr - page_addr; |
| 954 | 957 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); |
| 955 | 958 | const slot_index: SlotIndex = @intCast(page_offset / size_class); |
| 956 | | const used_byte_index = slot_index / 8; |
| 957 | | const used_bit_index: u3 = @intCast(slot_index % 8); |
| 959 | const used_byte_index = slot_index / @bitSizeOf(usize); |
| 960 | const used_bit_index: Log2USize = @intCast(slot_index % @bitSizeOf(usize)); |
| 958 | 961 | const used_byte = bucket.usedBits(used_byte_index); |
| 959 | 962 | const is_used = @as(u1, @truncate(used_byte.* >> used_bit_index)) != 0; |
| 960 | 963 | if (!is_used) { |