| ... | @@ -4,11 +4,10 @@ | ... | @@ -4,11 +4,10 @@ |
| 4 | | 4 | |
| 5 | locals: []Local = &.{}, | 5 | locals: []Local = &.{}, |
| 6 | shards: []Shard = &.{}, | 6 | shards: []Shard = &.{}, |
| 7 | tid_width: std.math.Log2Int(u32) = 0, | 7 | tid_width: if (single_threaded) u0 else std.math.Log2Int(u32) = 0, |
| 8 | tid_shift_31: std.math.Log2Int(u32) = 31, | 8 | tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31, |
| 9 | tid_shift_32: std.math.Log2Int(u32) = 31, | 9 | tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31, |
| 10 | | 10 | |
| 11 | //items: std.MultiArrayList(Item) = .{}, | | |
| 12 | extra: std.ArrayListUnmanaged(u32) = .{}, | 11 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| 13 | /// On 32-bit systems, this array is ignored and extra is used for everything. | 12 | /// On 32-bit systems, this array is ignored and extra is used for everything. |
| 14 | /// On 64-bit systems, this array is used for big integers and associated metadata. | 13 | /// On 64-bit systems, this array is used for big integers and associated metadata. |
| ... | @@ -92,6 +91,14 @@ free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{}, | ... | @@ -92,6 +91,14 @@ free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{}, |
| 92 | /// Value is the `Decl` of the struct that represents this `File`. | 91 | /// Value is the `Decl` of the struct that represents this `File`. |
| 93 | files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{}, | 92 | files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{}, |
| 94 | | 93 | |
| | 94 | /// Whether a multi-threaded intern pool is useful. |
| | 95 | /// Currently `false` until the intern pool is actually accessed |
| | 96 | /// from multiple threads to reduce the cost of this data structure. |
| | 97 | const want_multi_threaded = false; |
| | 98 | |
| | 99 | /// Whether a single-threaded intern pool impl is in use. |
| | 100 | pub const single_threaded = builtin.single_threaded or !want_multi_threaded; |
| | 101 | |
| 95 | pub const FileIndex = enum(u32) { | 102 | pub const FileIndex = enum(u32) { |
| 96 | _, | 103 | _, |
| 97 | }; | 104 | }; |
| ... | @@ -497,19 +504,23 @@ const Local = struct { | ... | @@ -497,19 +504,23 @@ const Local = struct { |
| 497 | var new_list: ListSelf = .{ .bytes = @ptrCast(buf[bytes_offset..].ptr) }; | 504 | var new_list: ListSelf = .{ .bytes = @ptrCast(buf[bytes_offset..].ptr) }; |
| 498 | new_list.header().* = .{ .capacity = capacity }; | 505 | new_list.header().* = .{ .capacity = capacity }; |
| 499 | const len = mutable.lenPtr().*; | 506 | const len = mutable.lenPtr().*; |
| 500 | const old_slice = mutable.list.view().slice(); | 507 | // this cold, quickly predictable, condition enables |
| 501 | const new_slice = new_list.view().slice(); | 508 | // the `MultiArrayList` optimization in `view` |
| 502 | inline for (fields) |field| { | 509 | if (len > 0) { |
| 503 | @memcpy(new_slice.items(field)[0..len], old_slice.items(field)[0..len]); | 510 | const old_slice = mutable.list.view().slice(); |
| | 511 | const new_slice = new_list.view().slice(); |
| | 512 | inline for (fields) |field| @memcpy(new_slice.items(field)[0..len], old_slice.items(field)[0..len]); |
| 504 | } | 513 | } |
| 505 | mutable.list.release(new_list); | 514 | mutable.list.release(new_list); |
| 506 | } | 515 | } |
| 507 | | 516 | |
| 508 | fn view(mutable: Mutable) View { | 517 | fn view(mutable: Mutable) View { |
| | 518 | const capacity = mutable.capacityPtr().*; |
| | 519 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` |
| 509 | return .{ | 520 | return .{ |
| 510 | .bytes = mutable.list.bytes, | 521 | .bytes = mutable.list.bytes, |
| 511 | .len = mutable.lenPtr().*, | 522 | .len = mutable.lenPtr().*, |
| 512 | .capacity = mutable.capacityPtr().*, | 523 | .capacity = capacity, |
| 513 | }; | 524 | }; |
| 514 | } | 525 | } |
| 515 | | 526 | |
| ... | @@ -550,6 +561,7 @@ const Local = struct { | ... | @@ -550,6 +561,7 @@ const Local = struct { |
| 550 | | 561 | |
| 551 | fn view(list: ListSelf) View { | 562 | fn view(list: ListSelf) View { |
| 552 | const capacity = list.header().capacity; | 563 | const capacity = list.header().capacity; |
| | 564 | assert(capacity > 0); // optimizes `MultiArrayList.Slice.items` |
| 553 | return .{ | 565 | return .{ |
| 554 | .bytes = list.bytes, | 566 | .bytes = list.bytes, |
| 555 | .len = capacity, | 567 | .len = capacity, |
| ... | @@ -665,13 +677,8 @@ const Shard = struct { | ... | @@ -665,13 +677,8 @@ const Shard = struct { |
| 665 | } | 677 | } |
| 666 | }; | 678 | }; |
| 667 | | 679 | |
| 668 | fn getShard(ip: *InternPool, tid: Zcu.PerThread.Id) *Shard { | | |
| 669 | return &ip.shards[@intFromEnum(tid)]; | | |
| 670 | } | | |
| 671 | | | |
| 672 | fn getTidMask(ip: *const InternPool) u32 { | 680 | fn getTidMask(ip: *const InternPool) u32 { |
| 673 | assert(std.math.isPowerOfTwo(ip.shards.len)); | 681 | return (@as(u32, 1) << ip.tid_width) - 1; |
| 674 | return @intCast(ip.shards.len - 1); | | |
| 675 | } | 682 | } |
| 676 | | 683 | |
| 677 | fn getIndexMask(ip: *const InternPool, comptime BackingInt: type) u32 { | 684 | fn getIndexMask(ip: *const InternPool, comptime BackingInt: type) u32 { |
| ... | @@ -809,7 +816,7 @@ pub const String = enum(u32) { | ... | @@ -809,7 +816,7 @@ pub const String = enum(u32) { |
| 809 | }; | 816 | }; |
| 810 | } | 817 | } |
| 811 | | 818 | |
| 812 | fn toOverlongSlice(string: String, ip: *const InternPool) []const u8 { | 819 | noinline fn toOverlongSlice(string: String, ip: *const InternPool) []const u8 { |
| 813 | const unwrapped = string.unwrap(ip); | 820 | const unwrapped = string.unwrap(ip); |
| 814 | return ip.getLocalShared(unwrapped.tid).strings.acquire().view().items(.@"0")[unwrapped.index..]; | 821 | return ip.getLocalShared(unwrapped.tid).strings.acquire().view().items(.@"0")[unwrapped.index..]; |
| 815 | } | 822 | } |
| ... | @@ -3230,19 +3237,35 @@ pub const Index = enum(u32) { | ... | @@ -3230,19 +3237,35 @@ pub const Index = enum(u32) { |
| 3230 | } | 3237 | } |
| 3231 | }; | 3238 | }; |
| 3232 | | 3239 | |
| 3233 | pub fn getItem(index: Index, ip: *const InternPool) Item { | 3240 | pub inline fn getItem(index: Index, ip: *const InternPool) Item { |
| 3234 | const unwrapped = index.unwrap(ip); | 3241 | const item_ptr = index.itemPtr(ip); |
| 3235 | return ip.getLocalShared(unwrapped.tid).items.acquire().view().get(unwrapped.index); | 3242 | const tag = @atomicLoad(Tag, item_ptr.tag_ptr, .acquire); |
| | 3243 | return .{ .tag = tag, .data = item_ptr.data_ptr.* }; |
| 3236 | } | 3244 | } |
| 3237 | | 3245 | |
| 3238 | pub fn getTag(index: Index, ip: *const InternPool) Tag { | 3246 | pub inline fn getTag(index: Index, ip: *const InternPool) Tag { |
| 3239 | const unwrapped = index.unwrap(ip); | 3247 | const item_ptr = index.itemPtr(ip); |
| 3240 | return ip.getLocalShared(unwrapped.tid).items.acquire().view().items(.tag)[unwrapped.index]; | 3248 | return @atomicLoad(Tag, item_ptr.tag_ptr, .acquire); |
| 3241 | } | 3249 | } |
| 3242 | | 3250 | |
| 3243 | pub fn getData(index: Index, ip: *const InternPool) u32 { | 3251 | pub inline fn getData(index: Index, ip: *const InternPool) u32 { |
| 3244 | const unwrapped = index.unwrap(ip); | 3252 | return index.getItem(ip).data; |
| 3245 | return ip.getLocalShared(unwrapped.tid).items.acquire().view().items(.data)[unwrapped.index]; | 3253 | } |
| | 3254 | |
| | 3255 | const ItemPtr = struct { |
| | 3256 | tag_ptr: *Tag, |
| | 3257 | data_ptr: *u32, |
| | 3258 | }; |
| | 3259 | fn itemPtr(index: Index, ip: *const InternPool) ItemPtr { |
| | 3260 | const unwrapped: Unwrapped = if (single_threaded) .{ |
| | 3261 | .tid = .main, |
| | 3262 | .index = @intFromEnum(index), |
| | 3263 | } else index.unwrap(ip); |
| | 3264 | const slice = ip.getLocalShared(unwrapped.tid).items.acquire().view().slice(); |
| | 3265 | return .{ |
| | 3266 | .tag_ptr = &slice.items(.tag)[unwrapped.index], |
| | 3267 | .data_ptr = &slice.items(.data)[unwrapped.index], |
| | 3268 | }; |
| 3246 | } | 3269 | } |
| 3247 | | 3270 | |
| 3248 | const Unwrapped = struct { | 3271 | const Unwrapped = struct { |
| ... | @@ -4905,11 +4928,12 @@ pub const MemoizedCall = struct { | ... | @@ -4905,11 +4928,12 @@ pub const MemoizedCall = struct { |
| 4905 | result: Index, | 4928 | result: Index, |
| 4906 | }; | 4929 | }; |
| 4907 | | 4930 | |
| 4908 | pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void { | 4931 | pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void { |
| 4909 | errdefer ip.deinit(gpa); | 4932 | errdefer ip.deinit(gpa); |
| 4910 | assert(ip.locals.len == 0 and ip.shards.len == 0); | 4933 | assert(ip.locals.len == 0 and ip.shards.len == 0); |
| 4911 | | 4934 | |
| 4912 | ip.locals = try gpa.alloc(Local, total_threads); | 4935 | const used_threads = if (single_threaded) 1 else available_threads; |
| | 4936 | ip.locals = try gpa.alloc(Local, used_threads); |
| 4913 | @memset(ip.locals, .{ | 4937 | @memset(ip.locals, .{ |
| 4914 | .shared = .{ | 4938 | .shared = .{ |
| 4915 | .items = Local.List(Item).empty, | 4939 | .items = Local.List(Item).empty, |
| ... | @@ -4922,9 +4946,9 @@ pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void { | ... | @@ -4922,9 +4946,9 @@ pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void { |
| 4922 | }, | 4946 | }, |
| 4923 | }); | 4947 | }); |
| 4924 | | 4948 | |
| 4925 | ip.tid_width = @intCast(std.math.log2_int_ceil(usize, total_threads)); | 4949 | ip.tid_width = @intCast(std.math.log2_int_ceil(usize, used_threads)); |
| 4926 | ip.tid_shift_31 = 31 - ip.tid_width; | 4950 | ip.tid_shift_31 = if (single_threaded) 0 else 31 - ip.tid_width; |
| 4927 | ip.tid_shift_32 = ip.tid_shift_31 +| 1; | 4951 | ip.tid_shift_32 = if (single_threaded) 0 else ip.tid_shift_31 +| 1; |
| 4928 | ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.tid_width); | 4952 | ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.tid_width); |
| 4929 | @memset(ip.shards, .{ | 4953 | @memset(ip.shards, .{ |
| 4930 | .shared = .{ | 4954 | .shared = .{ |
| ... | @@ -7063,7 +7087,7 @@ pub fn getExternFunc( | ... | @@ -7063,7 +7087,7 @@ pub fn getExternFunc( |
| 7063 | .tag = .extern_func, | 7087 | .tag = .extern_func, |
| 7064 | .data = extra_index, | 7088 | .data = extra_index, |
| 7065 | }); | 7089 | }); |
| 7066 | errdefer ip.items.lenPtr().* -= 1; | 7090 | errdefer items.lenPtr().* -= 1; |
| 7067 | return gop.put(); | 7091 | return gop.put(); |
| 7068 | } | 7092 | } |
| 7069 | | 7093 | |
| ... | @@ -10146,12 +10170,9 @@ pub fn iesFuncIndex(ip: *const InternPool, ies_index: Index) Index { | ... | @@ -10146,12 +10170,9 @@ pub fn iesFuncIndex(ip: *const InternPool, ies_index: Index) Index { |
| 10146 | /// error set function. The returned pointer is invalidated when anything is | 10170 | /// error set function. The returned pointer is invalidated when anything is |
| 10147 | /// added to `ip`. | 10171 | /// added to `ip`. |
| 10148 | pub fn iesResolved(ip: *const InternPool, ies_index: Index) *Index { | 10172 | pub fn iesResolved(ip: *const InternPool, ies_index: Index) *Index { |
| 10149 | assert(ies_index != .none); | 10173 | const ies_item = ies_index.getItem(ip); |
| 10150 | const tags = ip.items.items(.tag); | 10174 | assert(ies_item.tag == .type_inferred_error_set); |
| 10151 | const datas = ip.items.items(.data); | 10175 | return funcIesResolved(ip, ies_item.data); |
| 10152 | assert(tags[@intFromEnum(ies_index)] == .type_inferred_error_set); | | |
| 10153 | const func_index = datas[@intFromEnum(ies_index)]; | | |
| 10154 | return funcIesResolved(ip, func_index); | | |
| 10155 | } | 10176 | } |
| 10156 | | 10177 | |
| 10157 | /// Returns a mutable pointer to the resolved error set type of an inferred | 10178 | /// Returns a mutable pointer to the resolved error set type of an inferred |