authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-06-15 16:18:41-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-07 22:59:52-04:00
logcda716ecc43929fd1c2c9679335b8b22f1b67d1a
tree43161efad1af25784f1ac0933a3a4a94352ef6d6
parentca02266157ee72e41068672c8ca6f928fcbf6fdf

InternPool: implement thread-safe hash map


4 files changed, 452 insertions(+), 195 deletions(-)

lib/std/Thread/Pool.zig+4
...@@ -291,3 +291,7 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {...@@ -291,3 +291,7 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {
291 return;291 return;
292 }292 }
293}293}
294
295pub fn getIdCount(pool: *Pool) usize {
296 return 1 + pool.threads.len;
297}
src/Compilation.zig+2-2
...@@ -1397,7 +1397,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1397,7 +1397,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1397 .error_limit = error_limit,1397 .error_limit = error_limit,
1398 .llvm_object = null,1398 .llvm_object = null,
1399 };1399 };
1400 try zcu.init();1400 try zcu.init(options.thread_pool.getIdCount());
1401 break :blk zcu;1401 break :blk zcu;
1402 } else blk: {1402 } else blk: {
1403 if (options.emit_h != null) return error.NoZigModuleForCHeader;1403 if (options.emit_h != null) return error.NoZigModuleForCHeader;
...@@ -2156,7 +2156,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2156,7 +2156,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2156 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {2156 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {
2157 std.debug.print("generic instances for '{s}:0x{x}':\n", .{2157 std.debug.print("generic instances for '{s}:0x{x}':\n", .{
2158 comp.root_name,2158 comp.root_name,
2159 @as(usize, @intFromPtr(zcu)),2159 @intFromPtr(zcu),
2160 });2160 });
2161 zcu.intern_pool.dumpGenericInstances(gpa);2161 zcu.intern_pool.dumpGenericInstances(gpa);
2162 }2162 }
src/InternPool.zig+444-191
...@@ -2,9 +2,10 @@...@@ -2,9 +2,10 @@
2//! This data structure is self-contained, with the following exceptions:2//! This data structure is self-contained, with the following exceptions:
3//! * Module.Namespace has a pointer to Module.File3//! * Module.Namespace has a pointer to Module.File
44
5/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are5local: []Local = &.{},
6/// constructed lazily.6shard_shift: std.math.Log2Int(usize) = 0,
7map: std.AutoArrayHashMapUnmanaged(void, void) = .{},7shards: []Shard = &.{},
8
8items: std.MultiArrayList(Item) = .{},9items: std.MultiArrayList(Item) = .{},
9extra: std.ArrayListUnmanaged(u32) = .{},10extra: std.ArrayListUnmanaged(u32) = .{},
10/// On 32-bit systems, this array is ignored and extra is used for everything.11/// On 32-bit systems, this array is ignored and extra is used for everything.
...@@ -351,6 +352,115 @@ pub const DepEntry = extern struct {...@@ -351,6 +352,115 @@ pub const DepEntry = extern struct {
351 };352 };
352};353};
353354
355const Local = struct {
356 aligned: void align(std.atomic.cache_line) = {},
357
358 /// node: Garbage.Node,
359 /// header: List.Header,
360 /// data: [capacity]u32,
361 /// tag: [capacity]Tag,
362 items: List,
363
364 /// node: Garbage.Node,
365 /// header: List.Header,
366 /// extra: [capacity]u32,
367 extra: List,
368
369 garbage: Garbage,
370
371 const List = struct {
372 entries: [*]u32,
373
374 const empty: List = .{
375 .entries = @constCast(&[_]u32{ 0, 0 })[Header.fields_len..].ptr,
376 };
377
378 fn acquire(list: *const List) List {
379 return .{ .entries = @atomicLoad([*]u32, &list.entries, .acquire) };
380 }
381 fn release(list: *List, new_list: List) void {
382 @atomicStore([*]u32, &list.entries, new_list.entries, .release);
383 }
384
385 const Header = extern struct {
386 len: u32,
387 capacity: u32,
388
389 const fields_len = @typeInfo(Header).Struct.fields.len;
390 };
391 fn header(list: List) *Header {
392 return @ptrCast(list.entries - Header.fields_len);
393 }
394 };
395
396 const Garbage = std.SinglyLinkedList(struct { buf_len: usize });
397 const garbage_align = @max(@alignOf(Garbage.Node), @alignOf(u32));
398
399 fn freeGarbage(garbage: *const Garbage.Node, gpa: Allocator) void {
400 gpa.free(@as([*]align(Local.garbage_align) const u8, @ptrCast(garbage))[0..garbage.data.buf_len]);
401 }
402};
403
404const Shard = struct {
405 aligned: void align(std.atomic.cache_line) = {},
406
407 mutate_mutex: std.Thread.Mutex.Recursive,
408
409 /// node: Local.Garbage.Node,
410 /// header: Map.Header,
411 /// entries: [capacity]Map.Entry,
412 map: Map,
413
414 const Map = struct {
415 entries: [*]u32,
416
417 const empty: Map = .{
418 .entries = @constCast(&[_]u32{ 0, 1, @intFromEnum(Index.none), 0 })[Header.fields_len..].ptr,
419 };
420
421 fn acquire(map: *const Map) Map {
422 return .{ .entries = @atomicLoad([*]u32, &map.entries, .acquire) };
423 }
424 fn release(map: *Map, new_map: Map) void {
425 @atomicStore([*]u32, &map.entries, new_map.entries, .release);
426 }
427
428 const Header = extern struct {
429 len: u32,
430 capacity: u32,
431
432 const fields_len: u32 = @typeInfo(Header).Struct.fields.len;
433
434 fn mask(head: *const Header) u32 {
435 assert(std.math.isPowerOfTwo(head.capacity));
436 assert(std.math.isPowerOfTwo(Entry.fields_len));
437 return (head.capacity - 1) * Entry.fields_len;
438 }
439 };
440 fn header(map: Map) *Header {
441 return @ptrCast(map.entries - Header.fields_len);
442 }
443
444 const Entry = extern struct {
445 index: Index,
446 hash: u32,
447
448 const fields_len: u32 = @typeInfo(Entry).Struct.fields.len;
449
450 fn acquire(entry: *const Entry) Index {
451 return @atomicLoad(Index, &entry.index, .acquire);
452 }
453 fn release(entry: *Entry, index: Index) void {
454 @atomicStore(Index, &entry.index, index, .release);
455 }
456 };
457 fn at(map: Map, index: usize) *Entry {
458 assert(index % Entry.fields_len == 0);
459 return @ptrCast(&map.entries[index]);
460 }
461 };
462};
463
354const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);464const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
355465
356const builtin = @import("builtin");466const builtin = @import("builtin");
...@@ -369,20 +479,6 @@ const Zcu = @import("Zcu.zig");...@@ -369,20 +479,6 @@ const Zcu = @import("Zcu.zig");
369const Module = Zcu;479const Module = Zcu;
370const Zir = std.zig.Zir;480const Zir = std.zig.Zir;
371481
372const KeyAdapter = struct {
373 intern_pool: *const InternPool,
374
375 pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
376 _ = b_void;
377 if (ctx.intern_pool.items.items(.tag)[b_map_index] == .removed) return false;
378 return ctx.intern_pool.indexToKey(@enumFromInt(b_map_index)).eql(a, ctx.intern_pool);
379 }
380
381 pub fn hash(ctx: @This(), a: Key) u32 {
382 return a.hash32(ctx.intern_pool);
383 }
384};
385
386/// An index into `maps` which might be `none`.482/// An index into `maps` which might be `none`.
387pub const OptionalMapIndex = enum(u32) {483pub const OptionalMapIndex = enum(u32) {
388 none = std.math.maxInt(u32),484 none = std.math.maxInt(u32),
...@@ -4535,17 +4631,27 @@ pub const MemoizedCall = struct {...@@ -4535,17 +4631,27 @@ pub const MemoizedCall = struct {
4535 result: Index,4631 result: Index,
4536};4632};
45374633
4538pub fn init(ip: *InternPool, gpa: Allocator) !void {4634pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void {
4635 errdefer ip.deinit(gpa);
4539 assert(ip.items.len == 0);4636 assert(ip.items.len == 0);
45404637
4638 ip.local = try gpa.alloc(Local, total_threads);
4639 @memset(ip.local, .{
4640 .items = Local.List.empty,
4641 .extra = Local.List.empty,
4642 .garbage = .{},
4643 });
4644
4645 ip.shard_shift = @intCast(std.math.log2_int_ceil(usize, total_threads));
4646 ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.shard_shift);
4647 @memset(ip.shards, .{
4648 .mutate_mutex = std.Thread.Mutex.Recursive.init,
4649 .map = Shard.Map.empty,
4650 });
4651
4541 // Reserve string index 0 for an empty string.4652 // Reserve string index 0 for an empty string.
4542 assert((try ip.getOrPutString(gpa, .main, "", .no_embedded_nulls)) == .empty);4653 assert((try ip.getOrPutString(gpa, .main, "", .no_embedded_nulls)) == .empty);
45434654
4544 // So that we can use `catch unreachable` below.
4545 try ip.items.ensureUnusedCapacity(gpa, static_keys.len);
4546 try ip.map.ensureUnusedCapacity(gpa, static_keys.len);
4547 try ip.extra.ensureUnusedCapacity(gpa, static_keys.len);
4548
4549 // This inserts all the statically-known values into the intern pool in the4655 // This inserts all the statically-known values into the intern pool in the
4550 // order expected.4656 // order expected.
4551 for (&static_keys, 0..) |key, key_index| switch (@as(Index, @enumFromInt(key_index))) {4657 for (&static_keys, 0..) |key, key_index| switch (@as(Index, @enumFromInt(key_index))) {
...@@ -4574,12 +4680,9 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void {...@@ -4574,12 +4680,9 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void {
4574 assert(ip.indexToKey(ip.typeOf(cc_inline)).int_type.bits ==4680 assert(ip.indexToKey(ip.typeOf(cc_inline)).int_type.bits ==
4575 @typeInfo(@typeInfo(std.builtin.CallingConvention).Enum.tag_type).Int.bits);4681 @typeInfo(@typeInfo(std.builtin.CallingConvention).Enum.tag_type).Int.bits);
4576 }4682 }
4577
4578 assert(ip.items.len == static_keys.len);
4579}4683}
45804684
4581pub fn deinit(ip: *InternPool, gpa: Allocator) void {4685pub fn deinit(ip: *InternPool, gpa: Allocator) void {
4582 ip.map.deinit(gpa);
4583 ip.items.deinit(gpa);4686 ip.items.deinit(gpa);
4584 ip.extra.deinit(gpa);4687 ip.extra.deinit(gpa);
4585 ip.limbs.deinit(gpa);4688 ip.limbs.deinit(gpa);
...@@ -4611,6 +4714,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -4611,6 +4714,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
46114714
4612 ip.files.deinit(gpa);4715 ip.files.deinit(gpa);
46134716
4717 gpa.free(ip.shards);
4718 for (ip.local) |*local| {
4719 var next = local.garbage.first;
4720 while (next) |cur| {
4721 next = cur.next;
4722 Local.freeGarbage(cur, gpa);
4723 }
4724 }
4725 gpa.free(ip.local);
4726
4614 ip.* = undefined;4727 ip.* = undefined;
4615}4728}
46164729
...@@ -5239,10 +5352,133 @@ fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key...@@ -5239,10 +5352,133 @@ fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key
5239 } };5352 } };
5240}5353}
52415354
5355const GetOrPutKey = union(enum) {
5356 existing: Index,
5357 new: struct {
5358 shard: *Shard,
5359 map_index: u32,
5360 },
5361
5362 fn set(gop: *GetOrPutKey, index: Index) Index {
5363 switch (gop.*) {
5364 .existing => unreachable,
5365 .new => |info| {
5366 info.shard.map.at(info.map_index).release(index);
5367 info.shard.map.header().len += 1;
5368 info.shard.mutate_mutex.unlock();
5369 },
5370 }
5371 gop.* = .{ .existing = index };
5372 return index;
5373 }
5374
5375 fn assign(gop: *GetOrPutKey, new_gop: GetOrPutKey) void {
5376 gop.deinit();
5377 gop.* = new_gop;
5378 }
5379
5380 fn deinit(gop: *GetOrPutKey) void {
5381 switch (gop.*) {
5382 .existing => {},
5383 .new => |info| info.shard.mutate_mutex.unlock(),
5384 }
5385 gop.* = undefined;
5386 }
5387};
5388fn getOrPutKey(
5389 ip: *InternPool,
5390 gpa: Allocator,
5391 tid: Zcu.PerThread.Id,
5392 key: Key,
5393) Allocator.Error!GetOrPutKey {
5394 const full_hash = key.hash64(ip);
5395 const hash: u32 = @truncate(full_hash >> 32);
5396 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
5397 var map = shard.map.acquire();
5398 var map_mask = map.header().mask();
5399 var map_index = hash;
5400 while (true) : (map_index += Shard.Map.Entry.fields_len) {
5401 map_index &= map_mask;
5402 const entry = map.at(map_index);
5403 const index = entry.acquire();
5404 if (index == .none) break;
5405 if (entry.hash == hash and ip.indexToKey(index).eql(key, ip))
5406 return .{ .existing = index };
5407 }
5408 shard.mutate_mutex.lock();
5409 errdefer shard.mutate_mutex.unlock();
5410 if (map.entries != shard.map.entries) {
5411 map = shard.map;
5412 map_mask = map.header().mask();
5413 map_index = hash;
5414 }
5415 while (true) : (map_index += Shard.Map.Entry.fields_len) {
5416 map_index &= map_mask;
5417 const entry = map.at(map_index);
5418 const index = entry.index;
5419 if (index == .none) break;
5420 if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) {
5421 defer shard.mutate_mutex.unlock();
5422 return .{ .existing = index };
5423 }
5424 }
5425 const map_header = map.header().*;
5426 if (map_header.len >= map_header.capacity * 3 / 5) {
5427 const new_map_capacity = map_header.capacity * 2;
5428 const new_map_buf = try gpa.alignedAlloc(
5429 u8,
5430 Local.garbage_align,
5431 @sizeOf(Local.Garbage.Node) + (Shard.Map.Header.fields_len +
5432 new_map_capacity * Shard.Map.Entry.fields_len) * @sizeOf(u32),
5433 );
5434 const new_node: *Local.Garbage.Node = @ptrCast(new_map_buf.ptr);
5435 new_node.* = .{ .data = .{ .buf_len = new_map_buf.len } };
5436 ip.local[@intFromEnum(tid)].garbage.prepend(new_node);
5437 const new_map_entries = std.mem.bytesAsSlice(
5438 u32,
5439 new_map_buf[@sizeOf(Local.Garbage.Node)..],
5440 )[Shard.Map.Header.fields_len..];
5441 const new_map: Shard.Map = .{ .entries = new_map_entries.ptr };
5442 new_map.header().* = .{
5443 .len = map_header.len,
5444 .capacity = new_map_capacity,
5445 };
5446 @memset(new_map_entries, @intFromEnum(Index.none));
5447 const new_map_mask = new_map.header().mask();
5448 map_index = 0;
5449 while (map_index < map_header.capacity * 2) : (map_index += Shard.Map.Entry.fields_len) {
5450 const entry = map.at(map_index);
5451 const index = entry.index;
5452 if (index == .none) continue;
5453 const item_hash = entry.hash;
5454 var new_map_index = item_hash;
5455 while (true) : (new_map_index += Shard.Map.Entry.fields_len) {
5456 new_map_index &= new_map_mask;
5457 const new_entry = new_map.at(new_map_index);
5458 if (new_entry.index != .none) continue;
5459 new_entry.* = .{
5460 .index = index,
5461 .hash = item_hash,
5462 };
5463 break;
5464 }
5465 }
5466 map = new_map;
5467 map_index = hash;
5468 while (true) : (map_index += Shard.Map.Entry.fields_len) {
5469 map_index &= new_map_mask;
5470 if (map.at(map_index).index == .none) break;
5471 }
5472 shard.map.release(new_map);
5473 }
5474 map.at(map_index).hash = hash;
5475 return .{ .new = .{ .shard = shard, .map_index = map_index } };
5476}
5477
5242pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {5478pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {
5243 const adapter: KeyAdapter = .{ .intern_pool = ip };5479 var gop = try ip.getOrPutKey(gpa, tid, key);
5244 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);5480 defer gop.deinit();
5245 if (gop.found_existing) return @enumFromInt(gop.index);5481 if (gop == .existing) return gop.existing;
5246 try ip.items.ensureUnusedCapacity(gpa, 1);5482 try ip.items.ensureUnusedCapacity(gpa, 1);
5247 switch (key) {5483 switch (key) {
5248 .int_type => |int_type| {5484 .int_type => |int_type| {
...@@ -5260,18 +5496,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5260,18 +5496,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5260 assert(ptr_type.sentinel == .none or ip.typeOf(ptr_type.sentinel) == ptr_type.child);5496 assert(ptr_type.sentinel == .none or ip.typeOf(ptr_type.sentinel) == ptr_type.child);
52615497
5262 if (ptr_type.flags.size == .Slice) {5498 if (ptr_type.flags.size == .Slice) {
5263 _ = ip.map.pop();
5264 var new_key = key;5499 var new_key = key;
5265 new_key.ptr_type.flags.size = .Many;5500 new_key.ptr_type.flags.size = .Many;
5266 const ptr_type_index = try ip.get(gpa, tid, new_key);5501 const ptr_type_index = try ip.get(gpa, tid, new_key);
5267 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);5502 gop.assign(try ip.getOrPutKey(gpa, tid, key));
52685503
5269 try ip.items.ensureUnusedCapacity(gpa, 1);5504 try ip.items.ensureUnusedCapacity(gpa, 1);
5270 ip.items.appendAssumeCapacity(.{5505 ip.items.appendAssumeCapacity(.{
5271 .tag = .type_slice,5506 .tag = .type_slice,
5272 .data = @intFromEnum(ptr_type_index),5507 .data = @intFromEnum(ptr_type_index),
5273 });5508 });
5274 return @enumFromInt(ip.items.len - 1);5509 return gop.set(@enumFromInt(ip.items.len - 1));
5275 }5510 }
52765511
5277 var ptr_type_adjusted = ptr_type;5512 var ptr_type_adjusted = ptr_type;
...@@ -5295,7 +5530,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5295,7 +5530,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5295 .child = array_type.child,5530 .child = array_type.child,
5296 }),5531 }),
5297 });5532 });
5298 return @enumFromInt(ip.items.len - 1);5533 return gop.set(@enumFromInt(ip.items.len - 1));
5299 }5534 }
5300 }5535 }
53015536
...@@ -5442,11 +5677,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5442,11 +5677,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5442 },5677 },
5443 .anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {5678 .anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {
5444 if (ptr.ty != anon_decl.orig_ty) {5679 if (ptr.ty != anon_decl.orig_ty) {
5445 _ = ip.map.pop();
5446 var new_key = key;5680 var new_key = key;
5447 new_key.ptr.base_addr.anon_decl.orig_ty = ptr.ty;5681 new_key.ptr.base_addr.anon_decl.orig_ty = ptr.ty;
5448 const new_gop = try ip.map.getOrPutAdapted(gpa, new_key, adapter);5682 gop.assign(try ip.getOrPutKey(gpa, tid, new_key));
5449 if (new_gop.found_existing) return @enumFromInt(new_gop.index);5683 if (gop == .existing) return gop.existing;
5450 }5684 }
5451 break :item .{5685 break :item .{
5452 .tag = .ptr_anon_decl,5686 .tag = .ptr_anon_decl,
...@@ -5486,7 +5720,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5486,7 +5720,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5486 .tag = .ptr_int,5720 .tag = .ptr_int,
5487 .data = try ip.addExtra(gpa, PtrInt.init(ptr.ty, ptr.byte_offset)),5721 .data = try ip.addExtra(gpa, PtrInt.init(ptr.ty, ptr.byte_offset)),
5488 },5722 },
5489 .arr_elem, .field => |base_index| item: {5723 .arr_elem, .field => |base_index| {
5490 const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;5724 const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
5491 switch (ptr.base_addr) {5725 switch (ptr.base_addr) {
5492 .arr_elem => assert(base_ptr_type.flags.size == .Many),5726 .arr_elem => assert(base_ptr_type.flags.size == .Many),
...@@ -5516,21 +5750,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5516,21 +5750,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5516 },5750 },
5517 else => unreachable,5751 else => unreachable,
5518 }5752 }
5519 _ = ip.map.pop();
5520 const index_index = try ip.get(gpa, tid, .{ .int = .{5753 const index_index = try ip.get(gpa, tid, .{ .int = .{
5521 .ty = .usize_type,5754 .ty = .usize_type,
5522 .storage = .{ .u64 = base_index.index },5755 .storage = .{ .u64 = base_index.index },
5523 } });5756 } });
5524 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);5757 gop.assign(try ip.getOrPutKey(gpa, tid, key));
5525 try ip.items.ensureUnusedCapacity(gpa, 1);5758 try ip.items.ensureUnusedCapacity(gpa, 1);
5526 break :item .{5759 ip.items.appendAssumeCapacity(.{
5527 .tag = switch (ptr.base_addr) {5760 .tag = switch (ptr.base_addr) {
5528 .arr_elem => .ptr_elem,5761 .arr_elem => .ptr_elem,
5529 .field => .ptr_field,5762 .field => .ptr_field,
5530 else => unreachable,5763 else => unreachable,
5531 },5764 },
5532 .data = try ip.addExtra(gpa, PtrBaseIndex.init(ptr.ty, base_index.base, index_index, ptr.byte_offset)),5765 .data = try ip.addExtra(gpa, PtrBaseIndex.init(ptr.ty, base_index.base, index_index, ptr.byte_offset)),
5533 };5766 });
5767 return gop.set(@enumFromInt(ip.items.len - 1));
5534 },5768 },
5535 });5769 });
5536 },5770 },
...@@ -5566,7 +5800,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5566,7 +5800,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5566 .lazy_ty = lazy_ty,5800 .lazy_ty = lazy_ty,
5567 }),5801 }),
5568 });5802 });
5569 return @enumFromInt(ip.items.len - 1);5803 return gop.set(@enumFromInt(ip.items.len - 1));
5570 },5804 },
5571 }5805 }
5572 switch (int.ty) {5806 switch (int.ty) {
...@@ -5707,7 +5941,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5707,7 +5941,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5707 .value = casted,5941 .value = casted,
5708 }),5942 }),
5709 });5943 });
5710 return @enumFromInt(ip.items.len - 1);5944 return gop.set(@enumFromInt(ip.items.len - 1));
5711 } else |_| {}5945 } else |_| {}
57125946
5713 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;5947 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
...@@ -5722,7 +5956,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5722,7 +5956,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5722 .value = casted,5956 .value = casted,
5723 }),5957 }),
5724 });5958 });
5725 return @enumFromInt(ip.items.len - 1);5959 return gop.set(@enumFromInt(ip.items.len - 1));
5726 }5960 }
57275961
5728 var buf: [2]Limb = undefined;5962 var buf: [2]Limb = undefined;
...@@ -5881,7 +6115,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5881,7 +6115,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5881 .tag = .only_possible_value,6115 .tag = .only_possible_value,
5882 .data = @intFromEnum(aggregate.ty),6116 .data = @intFromEnum(aggregate.ty),
5883 });6117 });
5884 return @enumFromInt(ip.items.len - 1);6118 return gop.set(@enumFromInt(ip.items.len - 1));
5885 }6119 }
58866120
5887 switch (ty_key) {6121 switch (ty_key) {
...@@ -5914,7 +6148,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5914,7 +6148,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5914 .tag = .only_possible_value,6148 .tag = .only_possible_value,
5915 .data = @intFromEnum(aggregate.ty),6149 .data = @intFromEnum(aggregate.ty),
5916 });6150 });
5917 return @enumFromInt(ip.items.len - 1);6151 return gop.set(@enumFromInt(ip.items.len - 1));
5918 },6152 },
5919 else => {},6153 else => {},
5920 }6154 }
...@@ -5929,12 +6163,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5929,12 +6163,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5929 }6163 }
5930 const elem = switch (aggregate.storage) {6164 const elem = switch (aggregate.storage) {
5931 .bytes => |bytes| elem: {6165 .bytes => |bytes| elem: {
5932 _ = ip.map.pop();
5933 const elem = try ip.get(gpa, tid, .{ .int = .{6166 const elem = try ip.get(gpa, tid, .{ .int = .{
5934 .ty = .u8_type,6167 .ty = .u8_type,
5935 .storage = .{ .u64 = bytes.at(0, ip) },6168 .storage = .{ .u64 = bytes.at(0, ip) },
5936 } });6169 } });
5937 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);6170 gop.assign(try ip.getOrPutKey(gpa, tid, key));
5938 try ip.items.ensureUnusedCapacity(gpa, 1);6171 try ip.items.ensureUnusedCapacity(gpa, 1);
5939 break :elem elem;6172 break :elem elem;
5940 },6173 },
...@@ -5953,7 +6186,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5953,7 +6186,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5953 .elem_val = elem,6186 .elem_val = elem,
5954 }),6187 }),
5955 });6188 });
5956 return @enumFromInt(ip.items.len - 1);6189 return gop.set(@enumFromInt(ip.items.len - 1));
5957 }6190 }
59586191
5959 if (child == .u8_type) bytes: {6192 if (child == .u8_type) bytes: {
...@@ -5997,7 +6230,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -5997,7 +6230,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
5997 .bytes = string,6230 .bytes = string,
5998 }),6231 }),
5999 });6232 });
6000 return @enumFromInt(ip.items.len - 1);6233 return gop.set(@enumFromInt(ip.items.len - 1));
6001 }6234 }
60026235
6003 try ip.extra.ensureUnusedCapacity(6236 try ip.extra.ensureUnusedCapacity(
...@@ -6038,7 +6271,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -6038,7 +6271,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
6038 ip.extra.appendSliceAssumeCapacity(@ptrCast(memoized_call.arg_values));6271 ip.extra.appendSliceAssumeCapacity(@ptrCast(memoized_call.arg_values));
6039 },6272 },
6040 }6273 }
6041 return @enumFromInt(ip.items.len - 1);6274 return gop.set(@enumFromInt(ip.items.len - 1));
6042}6275}
60436276
6044pub const UnionTypeInit = struct {6277pub const UnionTypeInit = struct {
...@@ -6076,11 +6309,10 @@ pub const UnionTypeInit = struct {...@@ -6076,11 +6309,10 @@ pub const UnionTypeInit = struct {
6076pub fn getUnionType(6309pub fn getUnionType(
6077 ip: *InternPool,6310 ip: *InternPool,
6078 gpa: Allocator,6311 gpa: Allocator,
6079 _: Zcu.PerThread.Id,6312 tid: Zcu.PerThread.Id,
6080 ini: UnionTypeInit,6313 ini: UnionTypeInit,
6081) Allocator.Error!WipNamespaceType.Result {6314) Allocator.Error!WipNamespaceType.Result {
6082 const adapter: KeyAdapter = .{ .intern_pool = ip };6315 var gop = try ip.getOrPutKey(gpa, tid, .{ .union_type = switch (ini.key) {
6083 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .union_type = switch (ini.key) {
6084 .declared => |d| .{ .declared = .{6316 .declared => |d| .{ .declared = .{
6085 .zir_index = d.zir_index,6317 .zir_index = d.zir_index,
6086 .captures = .{ .external = d.captures },6318 .captures = .{ .external = d.captures },
...@@ -6089,9 +6321,9 @@ pub fn getUnionType(...@@ -6089,9 +6321,9 @@ pub fn getUnionType(
6089 .zir_index = r.zir_index,6321 .zir_index = r.zir_index,
6090 .type_hash = r.type_hash,6322 .type_hash = r.type_hash,
6091 } },6323 } },
6092 } }, adapter);6324 } });
6093 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };6325 defer gop.deinit();
6094 errdefer _ = ip.map.pop();6326 if (gop == .existing) return .{ .existing = gop.existing };
60956327
6096 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;6328 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
6097 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);6329 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
...@@ -6167,7 +6399,7 @@ pub fn getUnionType(...@@ -6167,7 +6399,7 @@ pub fn getUnionType(
6167 }6399 }
61686400
6169 return .{ .wip = .{6401 return .{ .wip = .{
6170 .index = @enumFromInt(ip.items.len - 1),6402 .index = gop.set(@enumFromInt(ip.items.len - 1)),
6171 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "decl").?,6403 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "decl").?,
6172 .namespace_extra_index = if (ini.has_namespace)6404 .namespace_extra_index = if (ini.has_namespace)
6173 extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?6405 extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?
...@@ -6225,11 +6457,10 @@ pub const StructTypeInit = struct {...@@ -6225,11 +6457,10 @@ pub const StructTypeInit = struct {
6225pub fn getStructType(6457pub fn getStructType(
6226 ip: *InternPool,6458 ip: *InternPool,
6227 gpa: Allocator,6459 gpa: Allocator,
6228 _: Zcu.PerThread.Id,6460 tid: Zcu.PerThread.Id,
6229 ini: StructTypeInit,6461 ini: StructTypeInit,
6230) Allocator.Error!WipNamespaceType.Result {6462) Allocator.Error!WipNamespaceType.Result {
6231 const adapter: KeyAdapter = .{ .intern_pool = ip };6463 var gop = try ip.getOrPutKey(gpa, tid, .{ .struct_type = switch (ini.key) {
6232 const key: Key = .{ .struct_type = switch (ini.key) {
6233 .declared => |d| .{ .declared = .{6464 .declared => |d| .{ .declared = .{
6234 .zir_index = d.zir_index,6465 .zir_index = d.zir_index,
6235 .captures = .{ .external = d.captures },6466 .captures = .{ .external = d.captures },
...@@ -6238,10 +6469,9 @@ pub fn getStructType(...@@ -6238,10 +6469,9 @@ pub fn getStructType(
6238 .zir_index = r.zir_index,6469 .zir_index = r.zir_index,
6239 .type_hash = r.type_hash,6470 .type_hash = r.type_hash,
6240 } },6471 } },
6241 } };6472 } });
6242 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);6473 defer gop.deinit();
6243 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };6474 if (gop == .existing) return .{ .existing = gop.existing };
6244 errdefer _ = ip.map.pop();
62456475
6246 const names_map = try ip.addMap(gpa, ini.fields_len);6476 const names_map = try ip.addMap(gpa, ini.fields_len);
6247 errdefer _ = ip.maps.pop();6477 errdefer _ = ip.maps.pop();
...@@ -6298,7 +6528,7 @@ pub fn getStructType(...@@ -6298,7 +6528,7 @@ pub fn getStructType(
6298 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);6528 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
6299 }6529 }
6300 return .{ .wip = .{6530 return .{ .wip = .{
6301 .index = @enumFromInt(ip.items.len - 1),6531 .index = gop.set(@enumFromInt(ip.items.len - 1)),
6302 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "decl").?,6532 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "decl").?,
6303 .namespace_extra_index = if (ini.has_namespace)6533 .namespace_extra_index = if (ini.has_namespace)
6304 extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?6534 extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?
...@@ -6387,7 +6617,7 @@ pub fn getStructType(...@@ -6387,7 +6617,7 @@ pub fn getStructType(
6387 }6617 }
6388 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);6618 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);
6389 return .{ .wip = .{6619 return .{ .wip = .{
6390 .index = @enumFromInt(ip.items.len - 1),6620 .index = gop.set(@enumFromInt(ip.items.len - 1)),
6391 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "decl").?,6621 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "decl").?,
6392 .namespace_extra_index = namespace_extra_index,6622 .namespace_extra_index = namespace_extra_index,
6393 } };6623 } };
...@@ -6404,7 +6634,7 @@ pub const AnonStructTypeInit = struct {...@@ -6404,7 +6634,7 @@ pub const AnonStructTypeInit = struct {
6404pub fn getAnonStructType(6634pub fn getAnonStructType(
6405 ip: *InternPool,6635 ip: *InternPool,
6406 gpa: Allocator,6636 gpa: Allocator,
6407 _: Zcu.PerThread.Id,6637 tid: Zcu.PerThread.Id,
6408 ini: AnonStructTypeInit,6638 ini: AnonStructTypeInit,
6409) Allocator.Error!Index {6639) Allocator.Error!Index {
6410 assert(ini.types.len == ini.values.len);6640 assert(ini.types.len == ini.values.len);
...@@ -6424,25 +6654,26 @@ pub fn getAnonStructType(...@@ -6424,25 +6654,26 @@ pub fn getAnonStructType(
6424 });6654 });
6425 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.types));6655 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.types));
6426 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));6656 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
6657 errdefer ip.extra.items.len = prev_extra_len;
64276658
6428 const adapter: KeyAdapter = .{ .intern_pool = ip };6659 var gop = try ip.getOrPutKey(gpa, tid, .{
6429 const key: Key = .{
6430 .anon_struct_type = if (ini.names.len == 0) extraTypeTupleAnon(ip, extra_index) else k: {6660 .anon_struct_type = if (ini.names.len == 0) extraTypeTupleAnon(ip, extra_index) else k: {
6431 assert(ini.names.len == ini.types.len);6661 assert(ini.names.len == ini.types.len);
6432 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));6662 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6433 break :k extraTypeStructAnon(ip, extra_index);6663 break :k extraTypeStructAnon(ip, extra_index);
6434 },6664 },
6435 };6665 });
6436 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);6666 defer gop.deinit();
6437 if (gop.found_existing) {6667 if (gop == .existing) {
6438 ip.extra.items.len = prev_extra_len;6668 ip.extra.items.len = prev_extra_len;
6439 return @enumFromInt(gop.index);6669 return gop.existing;
6440 }6670 }
6671
6441 ip.items.appendAssumeCapacity(.{6672 ip.items.appendAssumeCapacity(.{
6442 .tag = if (ini.names.len == 0) .type_tuple_anon else .type_struct_anon,6673 .tag = if (ini.names.len == 0) .type_tuple_anon else .type_struct_anon,
6443 .data = extra_index,6674 .data = extra_index,
6444 });6675 });
6445 return @enumFromInt(ip.items.len - 1);6676 return gop.set(@enumFromInt(ip.items.len - 1));
6446}6677}
64476678
6448/// This is equivalent to `Key.FuncType` but adjusted to have a slice for `param_types`.6679/// This is equivalent to `Key.FuncType` but adjusted to have a slice for `param_types`.
...@@ -6463,7 +6694,7 @@ pub const GetFuncTypeKey = struct {...@@ -6463,7 +6694,7 @@ pub const GetFuncTypeKey = struct {
6463pub fn getFuncType(6694pub fn getFuncType(
6464 ip: *InternPool,6695 ip: *InternPool,
6465 gpa: Allocator,6696 gpa: Allocator,
6466 _: Zcu.PerThread.Id,6697 tid: Zcu.PerThread.Id,
6467 key: GetFuncTypeKey,6698 key: GetFuncTypeKey,
6468) Allocator.Error!Index {6699) Allocator.Error!Index {
6469 // Validate input parameters.6700 // Validate input parameters.
...@@ -6501,33 +6732,33 @@ pub fn getFuncType(...@@ -6501,33 +6732,33 @@ pub fn getFuncType(
6501 if (key.comptime_bits != 0) ip.extra.appendAssumeCapacity(key.comptime_bits);6732 if (key.comptime_bits != 0) ip.extra.appendAssumeCapacity(key.comptime_bits);
6502 if (key.noalias_bits != 0) ip.extra.appendAssumeCapacity(key.noalias_bits);6733 if (key.noalias_bits != 0) ip.extra.appendAssumeCapacity(key.noalias_bits);
6503 ip.extra.appendSliceAssumeCapacity(@ptrCast(key.param_types));6734 ip.extra.appendSliceAssumeCapacity(@ptrCast(key.param_types));
6735 errdefer ip.extra.items.len = prev_extra_len;
65046736
6505 const adapter: KeyAdapter = .{ .intern_pool = ip };6737 var gop = try ip.getOrPutKey(gpa, tid, .{
6506 const gop = try ip.map.getOrPutAdapted(gpa, Key{
6507 .func_type = extraFuncType(ip, func_type_extra_index),6738 .func_type = extraFuncType(ip, func_type_extra_index),
6508 }, adapter);6739 });
6509 if (gop.found_existing) {6740 defer gop.deinit();
6741 if (gop == .existing) {
6510 ip.extra.items.len = prev_extra_len;6742 ip.extra.items.len = prev_extra_len;
6511 return @enumFromInt(gop.index);6743 return gop.existing;
6512 }6744 }
65136745
6514 ip.items.appendAssumeCapacity(.{6746 ip.items.appendAssumeCapacity(.{
6515 .tag = .type_function,6747 .tag = .type_function,
6516 .data = func_type_extra_index,6748 .data = func_type_extra_index,
6517 });6749 });
6518 return @enumFromInt(ip.items.len - 1);6750 return gop.set(@enumFromInt(ip.items.len - 1));
6519}6751}
65206752
6521pub fn getExternFunc(6753pub fn getExternFunc(
6522 ip: *InternPool,6754 ip: *InternPool,
6523 gpa: Allocator,6755 gpa: Allocator,
6524 _: Zcu.PerThread.Id,6756 tid: Zcu.PerThread.Id,
6525 key: Key.ExternFunc,6757 key: Key.ExternFunc,
6526) Allocator.Error!Index {6758) Allocator.Error!Index {
6527 const adapter: KeyAdapter = .{ .intern_pool = ip };6759 var gop = try ip.getOrPutKey(gpa, tid, .{ .extern_func = key });
6528 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .extern_func = key }, adapter);6760 defer gop.deinit();
6529 if (gop.found_existing) return @enumFromInt(gop.index);6761 if (gop == .existing) return gop.existing;
6530 errdefer _ = ip.map.pop();
6531 const prev_extra_len = ip.extra.items.len;6762 const prev_extra_len = ip.extra.items.len;
6532 const extra_index = try ip.addExtra(gpa, @as(Tag.ExternFunc, key));6763 const extra_index = try ip.addExtra(gpa, @as(Tag.ExternFunc, key));
6533 errdefer ip.extra.items.len = prev_extra_len;6764 errdefer ip.extra.items.len = prev_extra_len;
...@@ -6536,7 +6767,7 @@ pub fn getExternFunc(...@@ -6536,7 +6767,7 @@ pub fn getExternFunc(
6536 .data = extra_index,6767 .data = extra_index,
6537 });6768 });
6538 errdefer ip.items.len -= 1;6769 errdefer ip.items.len -= 1;
6539 return @enumFromInt(ip.items.len - 1);6770 return gop.set(@enumFromInt(ip.items.len - 1));
6540}6771}
65416772
6542pub const GetFuncDeclKey = struct {6773pub const GetFuncDeclKey = struct {
...@@ -6554,7 +6785,7 @@ pub const GetFuncDeclKey = struct {...@@ -6554,7 +6785,7 @@ pub const GetFuncDeclKey = struct {
6554pub fn getFuncDecl(6785pub fn getFuncDecl(
6555 ip: *InternPool,6786 ip: *InternPool,
6556 gpa: Allocator,6787 gpa: Allocator,
6557 _: Zcu.PerThread.Id,6788 tid: Zcu.PerThread.Id,
6558 key: GetFuncDeclKey,6789 key: GetFuncDeclKey,
6559) Allocator.Error!Index {6790) Allocator.Error!Index {
6560 // The strategy here is to add the function type unconditionally, then to6791 // The strategy here is to add the function type unconditionally, then to
...@@ -6564,7 +6795,6 @@ pub fn getFuncDecl(...@@ -6564,7 +6795,6 @@ pub fn getFuncDecl(
65646795
6565 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len);6796 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len);
6566 try ip.items.ensureUnusedCapacity(gpa, 1);6797 try ip.items.ensureUnusedCapacity(gpa, 1);
6567 try ip.map.ensureUnusedCapacity(gpa, 1);
65686798
6569 const func_decl_extra_index = ip.addExtraAssumeCapacity(Tag.FuncDecl{6799 const func_decl_extra_index = ip.addExtraAssumeCapacity(Tag.FuncDecl{
6570 .analysis = .{6800 .analysis = .{
...@@ -6583,22 +6813,22 @@ pub fn getFuncDecl(...@@ -6583,22 +6813,22 @@ pub fn getFuncDecl(
6583 .lbrace_column = key.lbrace_column,6813 .lbrace_column = key.lbrace_column,
6584 .rbrace_column = key.rbrace_column,6814 .rbrace_column = key.rbrace_column,
6585 });6815 });
6816 errdefer ip.extra.items.len = prev_extra_len;
65866817
6587 const adapter: KeyAdapter = .{ .intern_pool = ip };6818 var gop = try ip.getOrPutKey(gpa, tid, .{
6588 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
6589 .func = extraFuncDecl(ip, func_decl_extra_index),6819 .func = extraFuncDecl(ip, func_decl_extra_index),
6590 }, adapter);6820 });
65916821 defer gop.deinit();
6592 if (gop.found_existing) {6822 if (gop == .existing) {
6593 ip.extra.items.len = prev_extra_len;6823 ip.extra.items.len = prev_extra_len;
6594 return @enumFromInt(gop.index);6824 return gop.existing;
6595 }6825 }
65966826
6597 ip.items.appendAssumeCapacity(.{6827 ip.items.appendAssumeCapacity(.{
6598 .tag = .func_decl,6828 .tag = .func_decl,
6599 .data = func_decl_extra_index,6829 .data = func_decl_extra_index,
6600 });6830 });
6601 return @enumFromInt(ip.items.len - 1);6831 return gop.set(@enumFromInt(ip.items.len - 1));
6602}6832}
66036833
6604pub const GetFuncDeclIesKey = struct {6834pub const GetFuncDeclIesKey = struct {
...@@ -6626,7 +6856,7 @@ pub const GetFuncDeclIesKey = struct {...@@ -6626,7 +6856,7 @@ pub const GetFuncDeclIesKey = struct {
6626pub fn getFuncDeclIes(6856pub fn getFuncDeclIes(
6627 ip: *InternPool,6857 ip: *InternPool,
6628 gpa: Allocator,6858 gpa: Allocator,
6629 _: Zcu.PerThread.Id,6859 tid: Zcu.PerThread.Id,
6630 key: GetFuncDeclIesKey,6860 key: GetFuncDeclIesKey,
6631) Allocator.Error!Index {6861) Allocator.Error!Index {
6632 // Validate input parameters.6862 // Validate input parameters.
...@@ -6639,7 +6869,6 @@ pub fn getFuncDeclIes(...@@ -6639,7 +6869,6 @@ pub fn getFuncDeclIes(
6639 const prev_extra_len = ip.extra.items.len;6869 const prev_extra_len = ip.extra.items.len;
6640 const params_len: u32 = @intCast(key.param_types.len);6870 const params_len: u32 = @intCast(key.param_types.len);
66416871
6642 try ip.map.ensureUnusedCapacity(gpa, 4);
6643 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len +6872 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncDecl).Struct.fields.len +
6644 1 + // inferred_error_set6873 1 + // inferred_error_set
6645 @typeInfo(Tag.ErrorUnionType).Struct.fields.len +6874 @typeInfo(Tag.ErrorUnionType).Struct.fields.len +
...@@ -6704,40 +6933,51 @@ pub fn getFuncDeclIes(...@@ -6704,40 +6933,51 @@ pub fn getFuncDeclIes(
6704 if (key.comptime_bits != 0) ip.extra.appendAssumeCapacity(key.comptime_bits);6933 if (key.comptime_bits != 0) ip.extra.appendAssumeCapacity(key.comptime_bits);
6705 if (key.noalias_bits != 0) ip.extra.appendAssumeCapacity(key.noalias_bits);6934 if (key.noalias_bits != 0) ip.extra.appendAssumeCapacity(key.noalias_bits);
6706 ip.extra.appendSliceAssumeCapacity(@ptrCast(key.param_types));6935 ip.extra.appendSliceAssumeCapacity(@ptrCast(key.param_types));
6936 errdefer {
6937 ip.items.len -= 4;
6938 ip.extra.items.len = prev_extra_len;
6939 }
67076940
6708 ip.items.appendAssumeCapacity(.{6941 ip.items.appendAssumeCapacity(.{
6709 .tag = .type_function,6942 .tag = .type_function,
6710 .data = func_type_extra_index,6943 .data = func_type_extra_index,
6711 });6944 });
67126945
6713 const adapter: KeyAdapter = .{ .intern_pool = ip };6946 var gop = try ip.getOrPutKey(gpa, tid, .{
6714 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
6715 .func = extraFuncDecl(ip, func_decl_extra_index),6947 .func = extraFuncDecl(ip, func_decl_extra_index),
6716 }, adapter);6948 });
6717 if (!gop.found_existing) {6949 defer gop.deinit();
6718 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{6950 if (gop == .existing) {
6719 .error_set_type = @enumFromInt(ip.items.len - 2),6951 // An existing function type was found; undo the additions to our two arrays.
6720 .payload_type = key.bare_return_type,6952 ip.items.len -= 4;
6721 } }, adapter).found_existing);6953 ip.extra.items.len = prev_extra_len;
6722 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{6954 return gop.existing;
6723 .inferred_error_set_type = @enumFromInt(ip.items.len - 4),6955 }
6724 }, adapter).found_existing);6956
6725 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{6957 var eu_gop = try ip.getOrPutKey(gpa, tid, .{ .error_union_type = .{
6726 .func_type = extraFuncType(ip, func_type_extra_index),6958 .error_set_type = @enumFromInt(ip.items.len - 2),
6727 }, adapter).found_existing);6959 .payload_type = key.bare_return_type,
6728 return @enumFromInt(ip.items.len - 4);6960 } });
6729 }6961 defer eu_gop.deinit();
67306962 var ies_gop = try ip.getOrPutKey(gpa, tid, .{
6731 // An existing function type was found; undo the additions to our two arrays.6963 .inferred_error_set_type = @enumFromInt(ip.items.len - 4),
6732 ip.items.len -= 4;6964 });
6733 ip.extra.items.len = prev_extra_len;6965 defer ies_gop.deinit();
6734 return @enumFromInt(gop.index);6966 var ty_gop = try ip.getOrPutKey(gpa, tid, .{
6967 .func_type = extraFuncType(ip, func_type_extra_index),
6968 });
6969 defer ty_gop.deinit();
6970 const index = gop.set(@enumFromInt(ip.items.len - 4));
6971 _ = eu_gop.set(@enumFromInt(@intFromEnum(index) + 1));
6972 _ = ies_gop.set(@enumFromInt(@intFromEnum(index) + 2));
6973 _ = ty_gop.set(@enumFromInt(@intFromEnum(index) + 3));
6974 return index;
6735}6975}
67366976
6737pub fn getErrorSetType(6977pub fn getErrorSetType(
6738 ip: *InternPool,6978 ip: *InternPool,
6739 gpa: Allocator,6979 gpa: Allocator,
6740 _: Zcu.PerThread.Id,6980 tid: Zcu.PerThread.Id,
6741 names: []const NullTerminatedString,6981 names: []const NullTerminatedString,
6742) Allocator.Error!Index {6982) Allocator.Error!Index {
6743 assert(std.sort.isSorted(NullTerminatedString, names, {}, NullTerminatedString.indexLessThan));6983 assert(std.sort.isSorted(NullTerminatedString, names, {}, NullTerminatedString.indexLessThan));
...@@ -6757,16 +6997,15 @@ pub fn getErrorSetType(...@@ -6757,16 +6997,15 @@ pub fn getErrorSetType(
6757 .names_map = predicted_names_map,6997 .names_map = predicted_names_map,
6758 });6998 });
6759 ip.extra.appendSliceAssumeCapacity(@ptrCast(names));6999 ip.extra.appendSliceAssumeCapacity(@ptrCast(names));
7000 errdefer ip.extra.items.len = prev_extra_len;
67607001
6761 const adapter: KeyAdapter = .{ .intern_pool = ip };7002 var gop = try ip.getOrPutKey(gpa, tid, .{
6762 const gop = try ip.map.getOrPutAdapted(gpa, Key{
6763 .error_set_type = extraErrorSet(ip, error_set_extra_index),7003 .error_set_type = extraErrorSet(ip, error_set_extra_index),
6764 }, adapter);7004 });
6765 errdefer _ = ip.map.pop();7005 defer gop.deinit();
67667006 if (gop == .existing) {
6767 if (gop.found_existing) {
6768 ip.extra.items.len = prev_extra_len;7007 ip.extra.items.len = prev_extra_len;
6769 return @enumFromInt(gop.index);7008 return gop.existing;
6770 }7009 }
67717010
6772 try ip.items.append(gpa, .{7011 try ip.items.append(gpa, .{
...@@ -6781,7 +7020,7 @@ pub fn getErrorSetType(...@@ -6781,7 +7020,7 @@ pub fn getErrorSetType(
67817020
6782 addStringsToMap(ip, names_map, names);7021 addStringsToMap(ip, names_map, names);
67837022
6784 return @enumFromInt(ip.items.len - 1);7023 return gop.set(@enumFromInt(ip.items.len - 1));
6785}7024}
67867025
6787pub const GetFuncInstanceKey = struct {7026pub const GetFuncInstanceKey = struct {
...@@ -6845,14 +7084,13 @@ pub fn getFuncInstance(...@@ -6845,14 +7084,13 @@ pub fn getFuncInstance(
6845 });7084 });
6846 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));7085 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
68477086
6848 const gop = try ip.map.getOrPutAdapted(gpa, Key{7087 var gop = try ip.getOrPutKey(gpa, tid, .{
6849 .func = extraFuncInstance(ip, func_extra_index),7088 .func = extraFuncInstance(ip, func_extra_index),
6850 }, KeyAdapter{ .intern_pool = ip });7089 });
6851 errdefer _ = ip.map.pop();7090 defer gop.deinit();
68527091 if (gop == .existing) {
6853 if (gop.found_existing) {
6854 ip.extra.items.len = prev_extra_len;7092 ip.extra.items.len = prev_extra_len;
6855 return @enumFromInt(gop.index);7093 return gop.existing;
6856 }7094 }
68577095
6858 const func_index: Index = @enumFromInt(ip.items.len);7096 const func_index: Index = @enumFromInt(ip.items.len);
...@@ -6863,7 +7101,7 @@ pub fn getFuncInstance(...@@ -6863,7 +7101,7 @@ pub fn getFuncInstance(
6863 });7101 });
6864 errdefer ip.items.len -= 1;7102 errdefer ip.items.len -= 1;
68657103
6866 return finishFuncInstance(7104 return gop.set(try finishFuncInstance(
6867 ip,7105 ip,
6868 gpa,7106 gpa,
6869 tid,7107 tid,
...@@ -6872,7 +7110,7 @@ pub fn getFuncInstance(...@@ -6872,7 +7110,7 @@ pub fn getFuncInstance(
6872 func_extra_index,7110 func_extra_index,
6873 arg.alignment,7111 arg.alignment,
6874 arg.section,7112 arg.section,
6875 );7113 ));
6876}7114}
68777115
6878/// This function exists separately than `getFuncInstance` because it needs to7116/// This function exists separately than `getFuncInstance` because it needs to
...@@ -6897,7 +7135,6 @@ pub fn getFuncInstanceIes(...@@ -6897,7 +7135,6 @@ pub fn getFuncInstanceIes(
6897 const prev_extra_len = ip.extra.items.len;7135 const prev_extra_len = ip.extra.items.len;
6898 const params_len: u32 = @intCast(arg.param_types.len);7136 const params_len: u32 = @intCast(arg.param_types.len);
68997137
6900 try ip.map.ensureUnusedCapacity(gpa, 4);
6901 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncInstance).Struct.fields.len +7138 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncInstance).Struct.fields.len +
6902 1 + // inferred_error_set7139 1 + // inferred_error_set
6903 arg.comptime_args.len +7140 arg.comptime_args.len +
...@@ -6970,30 +7207,37 @@ pub fn getFuncInstanceIes(...@@ -6970,30 +7207,37 @@ pub fn getFuncInstanceIes(
6970 .tag = .type_function,7207 .tag = .type_function,
6971 .data = func_type_extra_index,7208 .data = func_type_extra_index,
6972 });7209 });
7210 errdefer {
7211 ip.items.len -= 4;
7212 ip.extra.items.len = prev_extra_len;
7213 }
69737214
6974 const adapter: KeyAdapter = .{ .intern_pool = ip };7215 var gop = try ip.getOrPutKey(gpa, tid, .{
6975 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
6976 .func = extraFuncInstance(ip, func_extra_index),7216 .func = extraFuncInstance(ip, func_extra_index),
6977 }, adapter);7217 });
6978 if (gop.found_existing) {7218 defer gop.deinit();
7219 if (gop == .existing) {
6979 // Hot path: undo the additions to our two arrays.7220 // Hot path: undo the additions to our two arrays.
6980 ip.items.len -= 4;7221 ip.items.len -= 4;
6981 ip.extra.items.len = prev_extra_len;7222 ip.extra.items.len = prev_extra_len;
6982 return @enumFromInt(gop.index);7223 return gop.existing;
6983 }7224 }
69847225
6985 // Synchronize the map with items.7226 // Synchronize the map with items.
6986 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{7227 var eu_gop = try ip.getOrPutKey(gpa, tid, .{ .error_union_type = .{
6987 .error_set_type = error_set_type,7228 .error_set_type = error_set_type,
6988 .payload_type = arg.bare_return_type,7229 .payload_type = arg.bare_return_type,
6989 } }, adapter).found_existing);7230 } });
6990 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{7231 defer eu_gop.deinit();
7232 var ies_gop = try ip.getOrPutKey(gpa, tid, .{
6991 .inferred_error_set_type = func_index,7233 .inferred_error_set_type = func_index,
6992 }, adapter).found_existing);7234 });
6993 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{7235 defer ies_gop.deinit();
7236 var ty_gop = try ip.getOrPutKey(gpa, tid, .{
6994 .func_type = extraFuncType(ip, func_type_extra_index),7237 .func_type = extraFuncType(ip, func_type_extra_index),
6995 }, adapter).found_existing);7238 });
6996 return finishFuncInstance(7239 defer ty_gop.deinit();
7240 const index = gop.set(try finishFuncInstance(
6997 ip,7241 ip,
6998 gpa,7242 gpa,
6999 tid,7243 tid,
...@@ -7002,7 +7246,11 @@ pub fn getFuncInstanceIes(...@@ -7002,7 +7246,11 @@ pub fn getFuncInstanceIes(
7002 func_extra_index,7246 func_extra_index,
7003 arg.alignment,7247 arg.alignment,
7004 arg.section,7248 arg.section,
7005 );7249 ));
7250 _ = eu_gop.set(@enumFromInt(@intFromEnum(index) + 1));
7251 _ = ies_gop.set(@enumFromInt(@intFromEnum(index) + 2));
7252 _ = ty_gop.set(@enumFromInt(@intFromEnum(index) + 3));
7253 return index;
7006}7254}
70077255
7008fn finishFuncInstance(7256fn finishFuncInstance(
...@@ -7135,11 +7383,10 @@ pub const WipEnumType = struct {...@@ -7135,11 +7383,10 @@ pub const WipEnumType = struct {
7135pub fn getEnumType(7383pub fn getEnumType(
7136 ip: *InternPool,7384 ip: *InternPool,
7137 gpa: Allocator,7385 gpa: Allocator,
7138 _: Zcu.PerThread.Id,7386 tid: Zcu.PerThread.Id,
7139 ini: EnumTypeInit,7387 ini: EnumTypeInit,
7140) Allocator.Error!WipEnumType.Result {7388) Allocator.Error!WipEnumType.Result {
7141 const adapter: KeyAdapter = .{ .intern_pool = ip };7389 var gop = try ip.getOrPutKey(gpa, tid, .{ .enum_type = switch (ini.key) {
7142 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .enum_type = switch (ini.key) {
7143 .declared => |d| .{ .declared = .{7390 .declared => |d| .{ .declared = .{
7144 .zir_index = d.zir_index,7391 .zir_index = d.zir_index,
7145 .captures = .{ .external = d.captures },7392 .captures = .{ .external = d.captures },
...@@ -7148,10 +7395,9 @@ pub fn getEnumType(...@@ -7148,10 +7395,9 @@ pub fn getEnumType(
7148 .zir_index = r.zir_index,7395 .zir_index = r.zir_index,
7149 .type_hash = r.type_hash,7396 .type_hash = r.type_hash,
7150 } },7397 } },
7151 } }, adapter);7398 } });
7152 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };7399 defer gop.deinit();
7153 assert(gop.index == ip.items.len);7400 if (gop == .existing) return .{ .existing = gop.existing };
7154 errdefer _ = ip.map.pop();
71557401
7156 try ip.items.ensureUnusedCapacity(gpa, 1);7402 try ip.items.ensureUnusedCapacity(gpa, 1);
71577403
...@@ -7196,7 +7442,7 @@ pub fn getEnumType(...@@ -7196,7 +7442,7 @@ pub fn getEnumType(
7196 const names_start = ip.extra.items.len;7442 const names_start = ip.extra.items.len;
7197 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);7443 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
7198 return .{ .wip = .{7444 return .{ .wip = .{
7199 .index = @enumFromInt(gop.index),7445 .index = gop.set(@enumFromInt(ip.items.len - 1)),
7200 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,7446 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
7201 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,7447 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
7202 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,7448 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
...@@ -7260,7 +7506,7 @@ pub fn getEnumType(...@@ -7260,7 +7506,7 @@ pub fn getEnumType(
7260 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);7506 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
7261 }7507 }
7262 return .{ .wip = .{7508 return .{ .wip = .{
7263 .index = @enumFromInt(gop.index),7509 .index = gop.set(@enumFromInt(ip.items.len - 1)),
7264 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,7510 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
7265 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,7511 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
7266 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,7512 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
...@@ -7288,14 +7534,13 @@ const GeneratedTagEnumTypeInit = struct {...@@ -7288,14 +7534,13 @@ const GeneratedTagEnumTypeInit = struct {
7288pub fn getGeneratedTagEnumType(7534pub fn getGeneratedTagEnumType(
7289 ip: *InternPool,7535 ip: *InternPool,
7290 gpa: Allocator,7536 gpa: Allocator,
7291 _: Zcu.PerThread.Id,7537 tid: Zcu.PerThread.Id,
7292 ini: GeneratedTagEnumTypeInit,7538 ini: GeneratedTagEnumTypeInit,
7293) Allocator.Error!Index {7539) Allocator.Error!Index {
7294 assert(ip.isUnion(ini.owner_union_ty));7540 assert(ip.isUnion(ini.owner_union_ty));
7295 assert(ip.isIntegerType(ini.tag_ty));7541 assert(ip.isIntegerType(ini.tag_ty));
7296 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);7542 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
72977543
7298 try ip.map.ensureUnusedCapacity(gpa, 1);
7299 try ip.items.ensureUnusedCapacity(gpa, 1);7544 try ip.items.ensureUnusedCapacity(gpa, 1);
73007545
7301 const names_map = try ip.addMap(gpa, ini.names.len);7546 const names_map = try ip.addMap(gpa, ini.names.len);
...@@ -7304,6 +7549,7 @@ pub fn getGeneratedTagEnumType(...@@ -7304,6 +7549,7 @@ pub fn getGeneratedTagEnumType(
73047549
7305 const fields_len: u32 = @intCast(ini.names.len);7550 const fields_len: u32 = @intCast(ini.names.len);
73067551
7552 const prev_extra_len = ip.extra.items.len;
7307 switch (ini.tag_mode) {7553 switch (ini.tag_mode) {
7308 .auto => {7554 .auto => {
7309 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +7555 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
...@@ -7360,17 +7606,17 @@ pub fn getGeneratedTagEnumType(...@@ -7360,17 +7606,17 @@ pub fn getGeneratedTagEnumType(
7360 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));7606 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
7361 },7607 },
7362 }7608 }
7363 // Same as above7609 errdefer ip.extra.items.len = prev_extra_len;
7364 errdefer @compileError("error path leaks values_map and extra data");7610 errdefer switch (ini.tag_mode) {
7611 .auto => {},
7612 .explicit, .nonexhaustive => _ = if (ini.values.len != 0) ip.maps.pop(),
7613 };
73657614
7366 // Capacity for this was ensured earlier7615 var gop = try ip.getOrPutKey(gpa, tid, .{ .enum_type = .{
7367 const adapter: KeyAdapter = .{ .intern_pool = ip };
7368 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ .enum_type = .{
7369 .generated_tag = .{ .union_type = ini.owner_union_ty },7616 .generated_tag = .{ .union_type = ini.owner_union_ty },
7370 } }, adapter);7617 } });
7371 assert(!gop.found_existing);7618 defer gop.deinit();
7372 assert(gop.index == ip.items.len - 1);7619 return gop.set(@enumFromInt(ip.items.len - 1));
7373 return @enumFromInt(gop.index);
7374}7620}
73757621
7376pub const OpaqueTypeInit = struct {7622pub const OpaqueTypeInit = struct {
...@@ -7390,11 +7636,10 @@ pub const OpaqueTypeInit = struct {...@@ -7390,11 +7636,10 @@ pub const OpaqueTypeInit = struct {
7390pub fn getOpaqueType(7636pub fn getOpaqueType(
7391 ip: *InternPool,7637 ip: *InternPool,
7392 gpa: Allocator,7638 gpa: Allocator,
7393 _: Zcu.PerThread.Id,7639 tid: Zcu.PerThread.Id,
7394 ini: OpaqueTypeInit,7640 ini: OpaqueTypeInit,
7395) Allocator.Error!WipNamespaceType.Result {7641) Allocator.Error!WipNamespaceType.Result {
7396 const adapter: KeyAdapter = .{ .intern_pool = ip };7642 var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = switch (ini.key) {
7397 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
7398 .declared => |d| .{ .declared = .{7643 .declared => |d| .{ .declared = .{
7399 .zir_index = d.zir_index,7644 .zir_index = d.zir_index,
7400 .captures = .{ .external = d.captures },7645 .captures = .{ .external = d.captures },
...@@ -7403,9 +7648,9 @@ pub fn getOpaqueType(...@@ -7403,9 +7648,9 @@ pub fn getOpaqueType(
7403 .zir_index = r.zir_index,7648 .zir_index = r.zir_index,
7404 .type_hash = 0,7649 .type_hash = 0,
7405 } },7650 } },
7406 } }, adapter);7651 } });
7407 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };7652 defer gop.deinit();
7408 errdefer _ = ip.map.pop();7653 if (gop == .existing) return .{ .existing = gop.existing };
7409 try ip.items.ensureUnusedCapacity(gpa, 1);7654 try ip.items.ensureUnusedCapacity(gpa, 1);
7410 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeOpaque).Struct.fields.len + switch (ini.key) {7655 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeOpaque).Struct.fields.len + switch (ini.key) {
7411 .declared => |d| d.captures.len,7656 .declared => |d| d.captures.len,
...@@ -7431,7 +7676,7 @@ pub fn getOpaqueType(...@@ -7431,7 +7676,7 @@ pub fn getOpaqueType(
7431 .reified => {},7676 .reified => {},
7432 }7677 }
7433 return .{ .wip = .{7678 return .{ .wip = .{
7434 .index = @enumFromInt(gop.index),7679 .index = gop.set(@enumFromInt(ip.items.len - 1)),
7435 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "decl").?,7680 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "decl").?,
7436 .namespace_extra_index = if (ini.has_namespace)7681 .namespace_extra_index = if (ini.has_namespace)
7437 extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?7682 extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?
...@@ -7441,9 +7686,19 @@ pub fn getOpaqueType(...@@ -7441,9 +7686,19 @@ pub fn getOpaqueType(
7441}7686}
74427687
7443pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {7688pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
7444 const adapter: KeyAdapter = .{ .intern_pool = ip };7689 const full_hash = key.hash64(ip);
7445 const index = ip.map.getIndexAdapted(key, adapter) orelse return null;7690 const hash: u32 = @truncate(full_hash >> 32);
7446 return @enumFromInt(index);7691 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
7692 const map = shard.map.acquire();
7693 const map_mask = map.header().mask();
7694 var map_index = hash;
7695 while (true) : (map_index += Shard.Map.Entry.fields_len) {
7696 map_index &= map_mask;
7697 const entry = map.at(map_index);
7698 const index = entry.acquire();
7699 if (index == .none) return null;
7700 if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) return index;
7701 }
7447}7702}
74487703
7449pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {7704pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {
...@@ -7506,7 +7761,6 @@ pub fn remove(ip: *InternPool, index: Index) void {...@@ -7506,7 +7761,6 @@ pub fn remove(ip: *InternPool, index: Index) void {
7506 if (@intFromEnum(index) == ip.items.len - 1) {7761 if (@intFromEnum(index) == ip.items.len - 1) {
7507 // Happy case - we can just drop the item without affecting any other indices.7762 // Happy case - we can just drop the item without affecting any other indices.
7508 ip.items.len -= 1;7763 ip.items.len -= 1;
7509 _ = ip.map.pop();
7510 } else {7764 } else {
7511 // We must preserve the item so that indices following it remain valid.7765 // We must preserve the item so that indices following it remain valid.
7512 // Thus, we will rewrite the tag to `removed`, leaking the item until7766 // Thus, we will rewrite the tag to `removed`, leaking the item until
...@@ -8133,35 +8387,34 @@ fn getCoercedFuncInstance(...@@ -8133,35 +8387,34 @@ fn getCoercedFuncInstance(
8133fn getCoercedFunc(8387fn getCoercedFunc(
8134 ip: *InternPool,8388 ip: *InternPool,
8135 gpa: Allocator,8389 gpa: Allocator,
8136 _: Zcu.PerThread.Id,8390 tid: Zcu.PerThread.Id,
8137 func: Index,8391 func: Index,
8138 ty: Index,8392 ty: Index,
8139) Allocator.Error!Index {8393) Allocator.Error!Index {
8140 const prev_extra_len = ip.extra.items.len;8394 const prev_extra_len = ip.extra.items.len;
8141 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncCoerced).Struct.fields.len);8395 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncCoerced).Struct.fields.len);
8142 try ip.items.ensureUnusedCapacity(gpa, 1);8396 try ip.items.ensureUnusedCapacity(gpa, 1);
8143 try ip.map.ensureUnusedCapacity(gpa, 1);
81448397
8145 const extra_index = ip.addExtraAssumeCapacity(Tag.FuncCoerced{8398 const extra_index = ip.addExtraAssumeCapacity(Tag.FuncCoerced{
8146 .ty = ty,8399 .ty = ty,
8147 .func = func,8400 .func = func,
8148 });8401 });
8402 errdefer ip.extra.items.len = prev_extra_len;
81498403
8150 const adapter: KeyAdapter = .{ .intern_pool = ip };8404 var gop = try ip.getOrPutKey(gpa, tid, .{
8151 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
8152 .func = extraFuncCoerced(ip, extra_index),8405 .func = extraFuncCoerced(ip, extra_index),
8153 }, adapter);8406 });
81548407 defer gop.deinit();
8155 if (gop.found_existing) {8408 if (gop == .existing) {
8156 ip.extra.items.len = prev_extra_len;8409 ip.extra.items.len = prev_extra_len;
8157 return @enumFromInt(gop.index);8410 return gop.existing;
8158 }8411 }
81598412
8160 ip.items.appendAssumeCapacity(.{8413 ip.items.appendAssumeCapacity(.{
8161 .tag = .func_coerced,8414 .tag = .func_coerced,
8162 .data = extra_index,8415 .data = extra_index,
8163 });8416 });
8164 return @enumFromInt(ip.items.len - 1);8417 return gop.set(@enumFromInt(ip.items.len - 1));
8165}8418}
81668419
8167/// Asserts `val` has an integer type.8420/// Asserts `val` has an integer type.
src/Zcu.zig+2-2
...@@ -2394,9 +2394,9 @@ pub const CompileError = error{...@@ -2394,9 +2394,9 @@ pub const CompileError = error{
2394 ComptimeBreak,2394 ComptimeBreak,
2395};2395};
23962396
2397pub fn init(mod: *Module) !void {2397pub fn init(mod: *Module, thread_count: usize) !void {
2398 const gpa = mod.gpa;2398 const gpa = mod.gpa;
2399 try mod.intern_pool.init(gpa);2399 try mod.intern_pool.init(gpa, thread_count);
2400 try mod.global_error_set.put(gpa, .empty, {});2400 try mod.global_error_set.put(gpa, .empty, {});
2401}2401}
24022402