authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-08 21:48:57-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-09 17:29:01-04:00
logc5283eb49b50c0d8b0d590b90f43523bed96e80a
tree712e3f607a745ad72a35e6f79cf16d6d6d9088dc
parent13070448f5f1dba172946e6a1e1a5c885093cad8

InternPool: implement thread-safe allocated lists


4 files changed, 363 insertions(+), 206 deletions(-)

src/InternPool.zig+235-73
...@@ -14,25 +14,6 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_th...@@ -14,25 +14,6 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_th
14/// Cached shift amount to put a `tid` in the top bits of a 32-bit value.14/// Cached shift amount to put a `tid` in the top bits of a 32-bit value.
15tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31,15tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31,
1616
17/// Rather than allocating Decl objects with an Allocator, we instead allocate
18/// them with this SegmentedList. This provides four advantages:
19/// * Stable memory so that one thread can access a Decl object while another
20/// thread allocates additional Decl objects from this list.
21/// * It allows us to use u32 indexes to reference Decl objects rather than
22/// pointers, saving memory in Type, Value, and dependency sets.
23/// * Using integers to reference Decl objects rather than pointers makes
24/// serialization trivial.
25/// * It provides a unique integer to be used for anonymous symbol names, avoiding
26/// multi-threaded contention on an atomic counter.
27allocated_decls: std.SegmentedList(Module.Decl, 0) = .{},
28/// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.
29decls_free_list: std.ArrayListUnmanaged(DeclIndex) = .{},
30
31/// Same pattern as with `allocated_decls`.
32allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{},
33/// Same pattern as with `decls_free_list`.
34namespaces_free_list: std.ArrayListUnmanaged(NamespaceIndex) = .{},
35
36/// Some types such as enums, structs, and unions need to store mappings from field names17/// Some types such as enums, structs, and unions need to store mappings from field names
37/// to field index, or value to field index. In such cases, they will store the underlying18/// to field index, or value to field index. In such cases, they will store the underlying
38/// field names and values directly, relying on one of these maps, stored separately,19/// field names and values directly, relying on one of these maps, stored separately,
...@@ -354,10 +335,14 @@ const Local = struct {...@@ -354,10 +335,14 @@ const Local = struct {
354 /// atomic access.335 /// atomic access.
355 mutate: struct {336 mutate: struct {
356 arena: std.heap.ArenaAllocator.State,337 arena: std.heap.ArenaAllocator.State,
357 items: Mutate,338
358 extra: Mutate,339 items: ListMutate,
359 limbs: Mutate,340 extra: ListMutate,
360 strings: Mutate,341 limbs: ListMutate,
342 strings: ListMutate,
343
344 decls: BucketListMutate,
345 namespaces: BucketListMutate,
361 } align(std.atomic.cache_line),346 } align(std.atomic.cache_line),
362347
363 const Shared = struct {348 const Shared = struct {
...@@ -366,6 +351,9 @@ const Local = struct {...@@ -366,6 +351,9 @@ const Local = struct {
366 limbs: Limbs,351 limbs: Limbs,
367 strings: Strings,352 strings: Strings,
368353
354 decls: Decls,
355 namespaces: Namespaces,
356
369 pub fn getLimbs(shared: *const Local.Shared) Limbs {357 pub fn getLimbs(shared: *const Local.Shared) Limbs {
370 return switch (@sizeOf(Limb)) {358 return switch (@sizeOf(Limb)) {
371 @sizeOf(u32) => shared.extra,359 @sizeOf(u32) => shared.extra,
...@@ -383,14 +371,38 @@ const Local = struct {...@@ -383,14 +371,38 @@ const Local = struct {
383 };371 };
384 const Strings = List(struct { u8 });372 const Strings = List(struct { u8 });
385373
386 const Mutate = struct {374 const decls_bucket_width = 8;
375 const decls_bucket_mask = (1 << decls_bucket_width) - 1;
376 const decl_next_free_field = "src_namespace";
377 const Decls = List(struct { *[1 << decls_bucket_width]Module.Decl });
378
379 const namespaces_bucket_width = 8;
380 const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1;
381 const namespace_next_free_field = "decl_index";
382 const Namespaces = List(struct { *[1 << namespaces_bucket_width]Module.Namespace });
383
384 const ListMutate = struct {
387 len: u32,385 len: u32,
388386
389 const empty: Mutate = .{387 const empty: ListMutate = .{
390 .len = 0,388 .len = 0,
391 };389 };
392 };390 };
393391
392 const BucketListMutate = struct {
393 last_bucket_len: u32,
394 buckets_list: ListMutate,
395 free_list: u32,
396
397 const free_list_sentinel = std.math.maxInt(u32);
398
399 const empty: BucketListMutate = .{
400 .last_bucket_len = 0,
401 .buckets_list = ListMutate.empty,
402 .free_list = free_list_sentinel,
403 };
404 };
405
394 fn List(comptime Elem: type) type {406 fn List(comptime Elem: type) type {
395 assert(@typeInfo(Elem) == .Struct);407 assert(@typeInfo(Elem) == .Struct);
396 return struct {408 return struct {
...@@ -400,7 +412,7 @@ const Local = struct {...@@ -400,7 +412,7 @@ const Local = struct {
400 const Mutable = struct {412 const Mutable = struct {
401 gpa: std.mem.Allocator,413 gpa: std.mem.Allocator,
402 arena: *std.heap.ArenaAllocator.State,414 arena: *std.heap.ArenaAllocator.State,
403 mutate: *Mutate,415 mutate: *ListMutate,
404 list: *ListSelf,416 list: *ListSelf,
405417
406 const fields = std.enums.values(std.meta.FieldEnum(Elem));418 const fields = std.enums.values(std.meta.FieldEnum(Elem));
...@@ -664,6 +676,35 @@ const Local = struct {...@@ -664,6 +676,35 @@ const Local = struct {
664 .list = &local.shared.strings,676 .list = &local.shared.strings,
665 };677 };
666 }678 }
679
680 /// Rather than allocating Decl objects with an Allocator, we instead allocate
681 /// them with this BucketList. This provides four advantages:
682 /// * Stable memory so that one thread can access a Decl object while another
683 /// thread allocates additional Decl objects from this list.
684 /// * It allows us to use u32 indexes to reference Decl objects rather than
685 /// pointers, saving memory in Type, Value, and dependency sets.
686 /// * Using integers to reference Decl objects rather than pointers makes
687 /// serialization trivial.
688 /// * It provides a unique integer to be used for anonymous symbol names, avoiding
689 /// multi-threaded contention on an atomic counter.
690 pub fn getMutableDecls(local: *Local, gpa: std.mem.Allocator) Decls.Mutable {
691 return .{
692 .gpa = gpa,
693 .arena = &local.mutate.arena,
694 .mutate = &local.mutate.decls.buckets_list,
695 .list = &local.shared.decls,
696 };
697 }
698
699 /// Same pattern as with `getMutableDecls`.
700 pub fn getMutableNamespaces(local: *Local, gpa: std.mem.Allocator) Namespaces.Mutable {
701 return .{
702 .gpa = gpa,
703 .arena = &local.mutate.arena,
704 .mutate = &local.mutate.namespaces.buckets_list,
705 .list = &local.shared.namespaces,
706 };
707 }
667};708};
668709
669pub fn getLocal(ip: *InternPool, tid: Zcu.PerThread.Id) *Local {710pub fn getLocal(ip: *InternPool, tid: Zcu.PerThread.Id) *Local {
...@@ -810,6 +851,29 @@ pub const ComptimeAllocIndex = enum(u32) { _ };...@@ -810,6 +851,29 @@ pub const ComptimeAllocIndex = enum(u32) { _ };
810pub const DeclIndex = enum(u32) {851pub const DeclIndex = enum(u32) {
811 _,852 _,
812853
854 const Unwrapped = struct {
855 tid: Zcu.PerThread.Id,
856 bucket_index: u32,
857 index: u32,
858
859 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) DeclIndex {
860 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
861 assert(unwrapped.bucket_index <= ip.getIndexMask(u32) >> Local.decls_bucket_width);
862 assert(unwrapped.index <= Local.decls_bucket_mask);
863 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
864 unwrapped.bucket_index << Local.decls_bucket_width |
865 unwrapped.index);
866 }
867 };
868 fn unwrap(decl_index: DeclIndex, ip: *const InternPool) Unwrapped {
869 const index = @intFromEnum(decl_index) & ip.getIndexMask(u32);
870 return .{
871 .tid = @enumFromInt(@intFromEnum(decl_index) >> ip.tid_shift_32 & ip.getTidMask()),
872 .bucket_index = index >> Local.decls_bucket_width,
873 .index = index & Local.decls_bucket_mask,
874 };
875 }
876
813 pub fn toOptional(i: DeclIndex) OptionalDeclIndex {877 pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
814 return @enumFromInt(@intFromEnum(i));878 return @enumFromInt(@intFromEnum(i));
815 }879 }
...@@ -832,6 +896,29 @@ pub const OptionalDeclIndex = enum(u32) {...@@ -832,6 +896,29 @@ pub const OptionalDeclIndex = enum(u32) {
832pub const NamespaceIndex = enum(u32) {896pub const NamespaceIndex = enum(u32) {
833 _,897 _,
834898
899 const Unwrapped = struct {
900 tid: Zcu.PerThread.Id,
901 bucket_index: u32,
902 index: u32,
903
904 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) NamespaceIndex {
905 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
906 assert(unwrapped.bucket_index <= ip.getIndexMask(u32) >> Local.namespaces_bucket_width);
907 assert(unwrapped.index <= Local.namespaces_bucket_mask);
908 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
909 unwrapped.bucket_index << Local.namespaces_bucket_width |
910 unwrapped.index);
911 }
912 };
913 fn unwrap(namespace_index: NamespaceIndex, ip: *const InternPool) Unwrapped {
914 const index = @intFromEnum(namespace_index) & ip.getIndexMask(u32);
915 return .{
916 .tid = @enumFromInt(@intFromEnum(namespace_index) >> ip.tid_shift_32 & ip.getTidMask()),
917 .bucket_index = index >> Local.namespaces_bucket_width,
918 .index = index & Local.namespaces_bucket_mask,
919 };
920 }
921
835 pub fn toOptional(i: NamespaceIndex) OptionalNamespaceIndex {922 pub fn toOptional(i: NamespaceIndex) OptionalNamespaceIndex {
836 return @enumFromInt(@intFromEnum(i));923 return @enumFromInt(@intFromEnum(i));
837 }924 }
...@@ -5114,13 +5201,20 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5114,13 +5201,20 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5114 .extra = Local.Extra.empty,5201 .extra = Local.Extra.empty,
5115 .limbs = Local.Limbs.empty,5202 .limbs = Local.Limbs.empty,
5116 .strings = Local.Strings.empty,5203 .strings = Local.Strings.empty,
5204
5205 .decls = Local.Decls.empty,
5206 .namespaces = Local.Namespaces.empty,
5117 },5207 },
5118 .mutate = .{5208 .mutate = .{
5119 .arena = .{},5209 .arena = .{},
5120 .items = Local.Mutate.empty,5210
5121 .extra = Local.Mutate.empty,5211 .items = Local.ListMutate.empty,
5122 .limbs = Local.Mutate.empty,5212 .extra = Local.ListMutate.empty,
5123 .strings = Local.Mutate.empty,5213 .limbs = Local.ListMutate.empty,
5214 .strings = Local.ListMutate.empty,
5215
5216 .decls = Local.BucketListMutate.empty,
5217 .namespaces = Local.BucketListMutate.empty,
5124 },5218 },
5125 });5219 });
51265220
...@@ -5173,12 +5267,6 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5173,12 +5267,6 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5173}5267}
51745268
5175pub fn deinit(ip: *InternPool, gpa: Allocator) void {5269pub fn deinit(ip: *InternPool, gpa: Allocator) void {
5176 ip.decls_free_list.deinit(gpa);
5177 ip.allocated_decls.deinit(gpa);
5178
5179 ip.namespaces_free_list.deinit(gpa);
5180 ip.allocated_namespaces.deinit(gpa);
5181
5182 for (ip.maps.items) |*map| map.deinit(gpa);5270 for (ip.maps.items) |*map| map.deinit(gpa);
5183 ip.maps.deinit(gpa);5271 ip.maps.deinit(gpa);
51845272
...@@ -5198,7 +5286,23 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -5198,7 +5286,23 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
5198 ip.files.deinit(gpa);5286 ip.files.deinit(gpa);
51995287
5200 gpa.free(ip.shards);5288 gpa.free(ip.shards);
5201 for (ip.locals) |*local| local.mutate.arena.promote(gpa).deinit();5289 for (ip.locals) |*local| {
5290 const buckets_len = local.mutate.namespaces.buckets_list.len;
5291 if (buckets_len > 0) for (
5292 local.shared.namespaces.view().items(.@"0")[0..buckets_len],
5293 0..,
5294 ) |namespace_bucket, buckets_index| {
5295 for (namespace_bucket[0..if (buckets_index < buckets_len - 1)
5296 namespace_bucket.len
5297 else
5298 local.mutate.namespaces.last_bucket_len]) |*namespace|
5299 {
5300 namespace.decls.deinit(gpa);
5301 namespace.usingnamespace_set.deinit(gpa);
5302 }
5303 };
5304 local.mutate.arena.promote(gpa).deinit();
5305 }
5202 gpa.free(ip.locals);5306 gpa.free(ip.locals);
52035307
5204 ip.* = undefined;5308 ip.* = undefined;
...@@ -7849,7 +7953,7 @@ fn finishFuncInstance(...@@ -7849,7 +7953,7 @@ fn finishFuncInstance(
7849 section: OptionalNullTerminatedString,7953 section: OptionalNullTerminatedString,
7850) Allocator.Error!void {7954) Allocator.Error!void {
7851 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));7955 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
7852 const decl_index = try ip.createDecl(gpa, .{7956 const decl_index = try ip.createDecl(gpa, tid, .{
7853 .name = undefined,7957 .name = undefined,
7854 .src_namespace = fn_owner_decl.src_namespace,7958 .src_namespace = fn_owner_decl.src_namespace,
7855 .has_tv = true,7959 .has_tv = true,
...@@ -7864,7 +7968,7 @@ fn finishFuncInstance(...@@ -7864,7 +7968,7 @@ fn finishFuncInstance(
7864 .is_exported = fn_owner_decl.is_exported,7968 .is_exported = fn_owner_decl.is_exported,
7865 .kind = .anon,7969 .kind = .anon,
7866 });7970 });
7867 errdefer ip.destroyDecl(gpa, decl_index);7971 errdefer ip.destroyDecl(tid, decl_index);
78687972
7869 // Populate the owner_decl field which was left undefined until now.7973 // Populate the owner_decl field which was left undefined until now.
7870 extra.view().items(.@"0")[7974 extra.view().items(.@"0")[
...@@ -9078,15 +9182,17 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -9078,15 +9182,17 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
9078 var items_len: usize = 0;9182 var items_len: usize = 0;
9079 var extra_len: usize = 0;9183 var extra_len: usize = 0;
9080 var limbs_len: usize = 0;9184 var limbs_len: usize = 0;
9185 var decls_len: usize = 0;
9081 for (ip.locals) |*local| {9186 for (ip.locals) |*local| {
9082 items_len += local.mutate.items.len;9187 items_len += local.mutate.items.len;
9083 extra_len += local.mutate.extra.len;9188 extra_len += local.mutate.extra.len;
9084 limbs_len += local.mutate.limbs.len;9189 limbs_len += local.mutate.limbs.len;
9190 decls_len += local.mutate.decls.buckets_list.len;
9085 }9191 }
9086 const items_size = (1 + 4) * items_len;9192 const items_size = (1 + 4) * items_len;
9087 const extra_size = 4 * extra_len;9193 const extra_size = 4 * extra_len;
9088 const limbs_size = 8 * limbs_len;9194 const limbs_size = 8 * limbs_len;
9089 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);9195 const decls_size = @sizeOf(Module.Decl) * decls_len;
90909196
9091 // TODO: map overhead size is not taken into account9197 // TODO: map overhead size is not taken into account
9092 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + decls_size;9198 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + decls_size;
...@@ -9106,7 +9212,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -9106,7 +9212,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
9106 extra_size,9212 extra_size,
9107 limbs_len,9213 limbs_len,
9108 limbs_size,9214 limbs_size,
9109 ip.allocated_decls.len,9215 decls_len,
9110 decls_size,9216 decls_size,
9111 });9217 });
91129218
...@@ -9513,64 +9619,120 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)...@@ -9513,64 +9619,120 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
9513 try bw.flush();9619 try bw.flush();
9514}9620}
95159621
9516pub fn declPtr(ip: *InternPool, index: DeclIndex) *Module.Decl {9622pub fn declPtr(ip: *InternPool, decl_index: DeclIndex) *Module.Decl {
9517 return ip.allocated_decls.at(@intFromEnum(index));9623 return @constCast(ip.declPtrConst(decl_index));
9518}9624}
95199625
9520pub fn declPtrConst(ip: *const InternPool, index: DeclIndex) *const Module.Decl {9626pub fn declPtrConst(ip: *const InternPool, decl_index: DeclIndex) *const Module.Decl {
9521 return ip.allocated_decls.at(@intFromEnum(index));9627 const unwrapped_decl_index = decl_index.unwrap(ip);
9628 const decls = ip.getLocalShared(unwrapped_decl_index.tid).decls.acquire();
9629 const decls_bucket = decls.view().items(.@"0")[unwrapped_decl_index.bucket_index];
9630 return &decls_bucket[unwrapped_decl_index.index];
9522}9631}
95239632
9524pub fn namespacePtr(ip: *InternPool, index: NamespaceIndex) *Module.Namespace {9633pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Module.Namespace {
9525 return ip.allocated_namespaces.at(@intFromEnum(index));9634 const unwrapped_namespace_index = namespace_index.unwrap(ip);
9635 const namespaces = ip.getLocalShared(unwrapped_namespace_index.tid).namespaces.acquire();
9636 const namespaces_bucket = namespaces.view().items(.@"0")[unwrapped_namespace_index.bucket_index];
9637 return &namespaces_bucket[unwrapped_namespace_index.index];
9526}9638}
95279639
9528pub fn createDecl(9640pub fn createDecl(
9529 ip: *InternPool,9641 ip: *InternPool,
9530 gpa: Allocator,9642 gpa: Allocator,
9643 tid: Zcu.PerThread.Id,
9531 initialization: Module.Decl,9644 initialization: Module.Decl,
9532) Allocator.Error!DeclIndex {9645) Allocator.Error!DeclIndex {
9533 if (ip.decls_free_list.popOrNull()) |index| {9646 const local = ip.getLocal(tid);
9534 ip.allocated_decls.at(@intFromEnum(index)).* = initialization;9647 const free_list_next = local.mutate.decls.free_list;
9535 return index;9648 if (free_list_next != Local.BucketListMutate.free_list_sentinel) {
9536 }9649 const reused_decl_index: DeclIndex = @enumFromInt(free_list_next);
9537 const ptr = try ip.allocated_decls.addOne(gpa);9650 const reused_decl = ip.declPtr(reused_decl_index);
9538 ptr.* = initialization;9651 local.mutate.decls.free_list = @intFromEnum(@field(reused_decl, Local.decl_next_free_field));
9539 return @enumFromInt(ip.allocated_decls.len - 1);9652 reused_decl.* = initialization;
9653 return reused_decl_index;
9654 }
9655 const decls = local.getMutableDecls(gpa);
9656 if (local.mutate.decls.last_bucket_len == 0) {
9657 try decls.ensureUnusedCapacity(1);
9658 var arena = decls.arena.promote(decls.gpa);
9659 defer decls.arena.* = arena.state;
9660 decls.appendAssumeCapacity(.{try arena.allocator().create(
9661 [1 << Local.decls_bucket_width]Module.Decl,
9662 )});
9663 }
9664 const unwrapped_decl_index: DeclIndex.Unwrapped = .{
9665 .tid = tid,
9666 .bucket_index = decls.mutate.len - 1,
9667 .index = local.mutate.decls.last_bucket_len,
9668 };
9669 local.mutate.decls.last_bucket_len =
9670 (unwrapped_decl_index.index + 1) & Local.namespaces_bucket_mask;
9671 const decl_index = unwrapped_decl_index.wrap(ip);
9672 ip.declPtr(decl_index).* = initialization;
9673 return decl_index;
9540}9674}
95419675
9542pub fn destroyDecl(ip: *InternPool, gpa: Allocator, index: DeclIndex) void {9676pub fn destroyDecl(ip: *InternPool, tid: Zcu.PerThread.Id, decl_index: DeclIndex) void {
9543 ip.declPtr(index).* = undefined;9677 const local = ip.getLocal(tid);
9544 ip.decls_free_list.append(gpa, index) catch {9678 const decl = ip.declPtr(decl_index);
9545 // In order to keep `destroyDecl` a non-fallible function, we ignore memory9679 decl.* = undefined;
9546 // allocation failures here, instead leaking the Decl until garbage collection.9680 @field(decl, Local.decl_next_free_field) = @enumFromInt(local.mutate.decls.free_list);
9547 };9681 local.mutate.decls.free_list = @intFromEnum(decl_index);
9548}9682}
95499683
9550pub fn createNamespace(9684pub fn createNamespace(
9551 ip: *InternPool,9685 ip: *InternPool,
9552 gpa: Allocator,9686 gpa: Allocator,
9687 tid: Zcu.PerThread.Id,
9553 initialization: Module.Namespace,9688 initialization: Module.Namespace,
9554) Allocator.Error!NamespaceIndex {9689) Allocator.Error!NamespaceIndex {
9555 if (ip.namespaces_free_list.popOrNull()) |index| {9690 const local = ip.getLocal(tid);
9556 ip.allocated_namespaces.at(@intFromEnum(index)).* = initialization;9691 const free_list_next = local.mutate.namespaces.free_list;
9557 return index;9692 if (free_list_next != Local.BucketListMutate.free_list_sentinel) {
9558 }9693 const reused_namespace_index: NamespaceIndex = @enumFromInt(free_list_next);
9559 const ptr = try ip.allocated_namespaces.addOne(gpa);9694 const reused_namespace = ip.namespacePtr(reused_namespace_index);
9560 ptr.* = initialization;9695 local.mutate.namespaces.free_list =
9561 return @enumFromInt(ip.allocated_namespaces.len - 1);9696 @intFromEnum(@field(reused_namespace, Local.namespace_next_free_field));
9697 reused_namespace.* = initialization;
9698 return reused_namespace_index;
9699 }
9700 const namespaces = local.getMutableNamespaces(gpa);
9701 if (local.mutate.namespaces.last_bucket_len == 0) {
9702 try namespaces.ensureUnusedCapacity(1);
9703 var arena = namespaces.arena.promote(namespaces.gpa);
9704 defer namespaces.arena.* = arena.state;
9705 namespaces.appendAssumeCapacity(.{try arena.allocator().create(
9706 [1 << Local.namespaces_bucket_width]Module.Namespace,
9707 )});
9708 }
9709 const unwrapped_namespace_index: NamespaceIndex.Unwrapped = .{
9710 .tid = tid,
9711 .bucket_index = namespaces.mutate.len - 1,
9712 .index = local.mutate.namespaces.last_bucket_len,
9713 };
9714 local.mutate.namespaces.last_bucket_len =
9715 (unwrapped_namespace_index.index + 1) & Local.namespaces_bucket_mask;
9716 const namespace_index = unwrapped_namespace_index.wrap(ip);
9717 ip.namespacePtr(namespace_index).* = initialization;
9718 return namespace_index;
9562}9719}
95639720
9564pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex) void {9721pub fn destroyNamespace(
9565 ip.namespacePtr(index).* = .{9722 ip: *InternPool,
9723 tid: Zcu.PerThread.Id,
9724 namespace_index: NamespaceIndex,
9725) void {
9726 const local = ip.getLocal(tid);
9727 const namespace = ip.namespacePtr(namespace_index);
9728 namespace.* = .{
9566 .parent = undefined,9729 .parent = undefined,
9567 .file_scope = undefined,9730 .file_scope = undefined,
9568 .decl_index = undefined,9731 .decl_index = undefined,
9569 };9732 };
9570 ip.namespaces_free_list.append(gpa, index) catch {9733 @field(namespace, Local.namespace_next_free_field) =
9571 // In order to keep `destroyNamespace` a non-fallible function, we ignore memory9734 @enumFromInt(local.mutate.namespaces.free_list);
9572 // allocation failures here, instead leaking the Namespace until garbage collection.9735 local.mutate.namespaces.free_list = @intFromEnum(namespace_index);
9573 };
9574}9736}
95759737
9576const EmbeddedNulls = enum {9738const EmbeddedNulls = enum {
src/Sema.zig+26-26
...@@ -2830,7 +2830,7 @@ fn zirStructDecl(...@@ -2830,7 +2830,7 @@ fn zirStructDecl(
2830 inst,2830 inst,
2831 );2831 );
2832 mod.declPtr(new_decl_index).owns_tv = true;2832 mod.declPtr(new_decl_index).owns_tv = true;
2833 errdefer mod.abortAnonDecl(new_decl_index);2833 errdefer pt.abortAnonDecl(new_decl_index);
28342834
2835 if (pt.zcu.comp.debug_incremental) {2835 if (pt.zcu.comp.debug_incremental) {
2836 try ip.addDependency(2836 try ip.addDependency(
...@@ -2841,12 +2841,12 @@ fn zirStructDecl(...@@ -2841,12 +2841,12 @@ fn zirStructDecl(
2841 }2841 }
28422842
2843 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.2843 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
2844 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{2844 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{
2845 .parent = block.namespace.toOptional(),2845 .parent = block.namespace.toOptional(),
2846 .decl_index = new_decl_index,2846 .decl_index = new_decl_index,
2847 .file_scope = block.getFileScopeIndex(mod),2847 .file_scope = block.getFileScopeIndex(mod),
2848 })).toOptional() else .none;2848 })).toOptional() else .none;
2849 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);2849 errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns);
28502850
2851 if (new_namespace_index.unwrap()) |ns| {2851 if (new_namespace_index.unwrap()) |ns| {
2852 const decls = sema.code.bodySlice(extra_index, decls_len);2852 const decls = sema.code.bodySlice(extra_index, decls_len);
...@@ -2872,8 +2872,8 @@ fn createAnonymousDeclTypeNamed(...@@ -2872,8 +2872,8 @@ fn createAnonymousDeclTypeNamed(
2872 const ip = &zcu.intern_pool;2872 const ip = &zcu.intern_pool;
2873 const gpa = sema.gpa;2873 const gpa = sema.gpa;
2874 const namespace = block.namespace;2874 const namespace = block.namespace;
2875 const new_decl_index = try zcu.allocateNewDecl(namespace);2875 const new_decl_index = try pt.allocateNewDecl(namespace);
2876 errdefer zcu.destroyDecl(new_decl_index);2876 errdefer pt.destroyDecl(new_decl_index);
28772877
2878 switch (name_strategy) {2878 switch (name_strategy) {
2879 .anon => {}, // handled after switch2879 .anon => {}, // handled after switch
...@@ -3068,7 +3068,7 @@ fn zirEnumDecl(...@@ -3068,7 +3068,7 @@ fn zirEnumDecl(
3068 );3068 );
3069 const new_decl = mod.declPtr(new_decl_index);3069 const new_decl = mod.declPtr(new_decl_index);
3070 new_decl.owns_tv = true;3070 new_decl.owns_tv = true;
3071 errdefer if (!done) mod.abortAnonDecl(new_decl_index);3071 errdefer if (!done) pt.abortAnonDecl(new_decl_index);
30723072
3073 if (pt.zcu.comp.debug_incremental) {3073 if (pt.zcu.comp.debug_incremental) {
3074 try mod.intern_pool.addDependency(3074 try mod.intern_pool.addDependency(
...@@ -3079,12 +3079,12 @@ fn zirEnumDecl(...@@ -3079,12 +3079,12 @@ fn zirEnumDecl(
3079 }3079 }
30803080
3081 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.3081 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3082 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{3082 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{
3083 .parent = block.namespace.toOptional(),3083 .parent = block.namespace.toOptional(),
3084 .decl_index = new_decl_index,3084 .decl_index = new_decl_index,
3085 .file_scope = block.getFileScopeIndex(mod),3085 .file_scope = block.getFileScopeIndex(mod),
3086 })).toOptional() else .none;3086 })).toOptional() else .none;
3087 errdefer if (!done) if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);3087 errdefer if (!done) if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns);
30883088
3089 if (new_namespace_index.unwrap()) |ns| {3089 if (new_namespace_index.unwrap()) |ns| {
3090 try pt.scanNamespace(ns, decls, new_decl);3090 try pt.scanNamespace(ns, decls, new_decl);
...@@ -3335,7 +3335,7 @@ fn zirUnionDecl(...@@ -3335,7 +3335,7 @@ fn zirUnionDecl(
3335 inst,3335 inst,
3336 );3336 );
3337 mod.declPtr(new_decl_index).owns_tv = true;3337 mod.declPtr(new_decl_index).owns_tv = true;
3338 errdefer mod.abortAnonDecl(new_decl_index);3338 errdefer pt.abortAnonDecl(new_decl_index);
33393339
3340 if (pt.zcu.comp.debug_incremental) {3340 if (pt.zcu.comp.debug_incremental) {
3341 try mod.intern_pool.addDependency(3341 try mod.intern_pool.addDependency(
...@@ -3346,12 +3346,12 @@ fn zirUnionDecl(...@@ -3346,12 +3346,12 @@ fn zirUnionDecl(
3346 }3346 }
33473347
3348 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.3348 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3349 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{3349 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{
3350 .parent = block.namespace.toOptional(),3350 .parent = block.namespace.toOptional(),
3351 .decl_index = new_decl_index,3351 .decl_index = new_decl_index,
3352 .file_scope = block.getFileScopeIndex(mod),3352 .file_scope = block.getFileScopeIndex(mod),
3353 })).toOptional() else .none;3353 })).toOptional() else .none;
3354 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);3354 errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns);
33553355
3356 if (new_namespace_index.unwrap()) |ns| {3356 if (new_namespace_index.unwrap()) |ns| {
3357 const decls = sema.code.bodySlice(extra_index, decls_len);3357 const decls = sema.code.bodySlice(extra_index, decls_len);
...@@ -3425,7 +3425,7 @@ fn zirOpaqueDecl(...@@ -3425,7 +3425,7 @@ fn zirOpaqueDecl(
3425 inst,3425 inst,
3426 );3426 );
3427 mod.declPtr(new_decl_index).owns_tv = true;3427 mod.declPtr(new_decl_index).owns_tv = true;
3428 errdefer mod.abortAnonDecl(new_decl_index);3428 errdefer pt.abortAnonDecl(new_decl_index);
34293429
3430 if (pt.zcu.comp.debug_incremental) {3430 if (pt.zcu.comp.debug_incremental) {
3431 try ip.addDependency(3431 try ip.addDependency(
...@@ -3435,12 +3435,12 @@ fn zirOpaqueDecl(...@@ -3435,12 +3435,12 @@ fn zirOpaqueDecl(
3435 );3435 );
3436 }3436 }
34373437
3438 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try mod.createNamespace(.{3438 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try pt.createNamespace(.{
3439 .parent = block.namespace.toOptional(),3439 .parent = block.namespace.toOptional(),
3440 .decl_index = new_decl_index,3440 .decl_index = new_decl_index,
3441 .file_scope = block.getFileScopeIndex(mod),3441 .file_scope = block.getFileScopeIndex(mod),
3442 })).toOptional() else .none;3442 })).toOptional() else .none;
3443 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);3443 errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns);
34443444
3445 if (new_namespace_index.unwrap()) |ns| {3445 if (new_namespace_index.unwrap()) |ns| {
3446 const decls = sema.code.bodySlice(extra_index, decls_len);3446 const decls = sema.code.bodySlice(extra_index, decls_len);
...@@ -21716,7 +21716,7 @@ fn zirReify(...@@ -21716,7 +21716,7 @@ fn zirReify(
21716 inst,21716 inst,
21717 );21717 );
21718 mod.declPtr(new_decl_index).owns_tv = true;21718 mod.declPtr(new_decl_index).owns_tv = true;
21719 errdefer mod.abortAnonDecl(new_decl_index);21719 errdefer pt.abortAnonDecl(new_decl_index);
2172021720
21721 try pt.finalizeAnonDecl(new_decl_index);21721 try pt.finalizeAnonDecl(new_decl_index);
2172221722
...@@ -21916,7 +21916,7 @@ fn reifyEnum(...@@ -21916,7 +21916,7 @@ fn reifyEnum(
21916 inst,21916 inst,
21917 );21917 );
21918 mod.declPtr(new_decl_index).owns_tv = true;21918 mod.declPtr(new_decl_index).owns_tv = true;
21919 errdefer mod.abortAnonDecl(new_decl_index);21919 errdefer pt.abortAnonDecl(new_decl_index);
2192021920
21921 wip_ty.prepare(ip, new_decl_index, .none);21921 wip_ty.prepare(ip, new_decl_index, .none);
21922 wip_ty.setTagTy(ip, tag_ty.toIntern());21922 wip_ty.setTagTy(ip, tag_ty.toIntern());
...@@ -22063,7 +22063,7 @@ fn reifyUnion(...@@ -22063,7 +22063,7 @@ fn reifyUnion(
22063 inst,22063 inst,
22064 );22064 );
22065 mod.declPtr(new_decl_index).owns_tv = true;22065 mod.declPtr(new_decl_index).owns_tv = true;
22066 errdefer mod.abortAnonDecl(new_decl_index);22066 errdefer pt.abortAnonDecl(new_decl_index);
2206722067
22068 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);22068 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
22069 const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;22069 const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
...@@ -22322,7 +22322,7 @@ fn reifyStruct(...@@ -22322,7 +22322,7 @@ fn reifyStruct(
22322 inst,22322 inst,
22323 );22323 );
22324 mod.declPtr(new_decl_index).owns_tv = true;22324 mod.declPtr(new_decl_index).owns_tv = true;
22325 errdefer mod.abortAnonDecl(new_decl_index);22325 errdefer pt.abortAnonDecl(new_decl_index);
2232622326
22327 const struct_type = ip.loadStructType(wip_ty.index);22327 const struct_type = ip.loadStructType(wip_ty.index);
2232822328
...@@ -26497,8 +26497,8 @@ fn zirBuiltinExtern(...@@ -26497,8 +26497,8 @@ fn zirBuiltinExtern(
26497 }26497 }
26498 const ptr_info = ty.ptrInfo(mod);26498 const ptr_info = ty.ptrInfo(mod);
2649926499
26500 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace);26500 const new_decl_index = try pt.allocateNewDecl(sema.owner_decl.src_namespace);
26501 errdefer mod.destroyDecl(new_decl_index);26501 errdefer pt.destroyDecl(new_decl_index);
26502 const new_decl = mod.declPtr(new_decl_index);26502 const new_decl = mod.declPtr(new_decl_index);
26503 try mod.initNewAnonDecl(26503 try mod.initNewAnonDecl(
26504 new_decl_index,26504 new_decl_index,
...@@ -36733,8 +36733,8 @@ fn generateUnionTagTypeNumbered(...@@ -36733,8 +36733,8 @@ fn generateUnionTagTypeNumbered(
36733 const gpa = sema.gpa;36733 const gpa = sema.gpa;
36734 const ip = &mod.intern_pool;36734 const ip = &mod.intern_pool;
3673536735
36736 const new_decl_index = try mod.allocateNewDecl(block.namespace);36736 const new_decl_index = try pt.allocateNewDecl(block.namespace);
36737 errdefer mod.destroyDecl(new_decl_index);36737 errdefer pt.destroyDecl(new_decl_index);
36738 const fqn = try union_owner_decl.fullyQualifiedName(pt);36738 const fqn = try union_owner_decl.fullyQualifiedName(pt);
36739 const name = try ip.getOrPutStringFmt(36739 const name = try ip.getOrPutStringFmt(
36740 gpa,36740 gpa,
...@@ -36748,7 +36748,7 @@ fn generateUnionTagTypeNumbered(...@@ -36748,7 +36748,7 @@ fn generateUnionTagTypeNumbered(
36748 Value.@"unreachable",36748 Value.@"unreachable",
36749 name,36749 name,
36750 );36750 );
36751 errdefer mod.abortAnonDecl(new_decl_index);36751 errdefer pt.abortAnonDecl(new_decl_index);
3675236752
36753 const new_decl = mod.declPtr(new_decl_index);36753 const new_decl = mod.declPtr(new_decl_index);
36754 new_decl.owns_tv = true;36754 new_decl.owns_tv = true;
...@@ -36785,8 +36785,8 @@ fn generateUnionTagTypeSimple(...@@ -36785,8 +36785,8 @@ fn generateUnionTagTypeSimple(
3678536785
36786 const new_decl_index = new_decl_index: {36786 const new_decl_index = new_decl_index: {
36787 const fqn = try union_owner_decl.fullyQualifiedName(pt);36787 const fqn = try union_owner_decl.fullyQualifiedName(pt);
36788 const new_decl_index = try mod.allocateNewDecl(block.namespace);36788 const new_decl_index = try pt.allocateNewDecl(block.namespace);
36789 errdefer mod.destroyDecl(new_decl_index);36789 errdefer pt.destroyDecl(new_decl_index);
36790 const name = try ip.getOrPutStringFmt(36790 const name = try ip.getOrPutStringFmt(
36791 gpa,36791 gpa,
36792 pt.tid,36792 pt.tid,
...@@ -36802,7 +36802,7 @@ fn generateUnionTagTypeSimple(...@@ -36802,7 +36802,7 @@ fn generateUnionTagTypeSimple(
36802 mod.declPtr(new_decl_index).name_fully_qualified = true;36802 mod.declPtr(new_decl_index).name_fully_qualified = true;
36803 break :new_decl_index new_decl_index;36803 break :new_decl_index new_decl_index;
36804 };36804 };
36805 errdefer mod.abortAnonDecl(new_decl_index);36805 errdefer pt.abortAnonDecl(new_decl_index);
3680636806
36807 const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{36807 const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{
36808 .decl = new_decl_index,36808 .decl = new_decl_index,
src/Zcu.zig+2-103
...@@ -2410,6 +2410,7 @@ pub fn init(mod: *Module, thread_count: usize) !void {...@@ -2410,6 +2410,7 @@ pub fn init(mod: *Module, thread_count: usize) !void {
2410}2410}
24112411
2412pub fn deinit(zcu: *Zcu) void {2412pub fn deinit(zcu: *Zcu) void {
2413 const pt: Zcu.PerThread = .{ .tid = .main, .zcu = zcu };
2413 const gpa = zcu.gpa;2414 const gpa = zcu.gpa;
24142415
2415 if (zcu.llvm_object) |llvm_object| {2416 if (zcu.llvm_object) |llvm_object| {
...@@ -2422,7 +2423,7 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2422,7 +2423,7 @@ pub fn deinit(zcu: *Zcu) void {
2422 }2423 }
2423 for (0..zcu.import_table.entries.len) |file_index_usize| {2424 for (0..zcu.import_table.entries.len) |file_index_usize| {
2424 const file_index: File.Index = @enumFromInt(file_index_usize);2425 const file_index: File.Index = @enumFromInt(file_index_usize);
2425 zcu.destroyFile(file_index);2426 pt.destroyFile(file_index);
2426 }2427 }
2427 zcu.import_table.deinit(gpa);2428 zcu.import_table.deinit(gpa);
24282429
...@@ -2497,68 +2498,9 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2497,68 +2498,9 @@ pub fn deinit(zcu: *Zcu) void {
2497 zcu.all_references.deinit(gpa);2498 zcu.all_references.deinit(gpa);
2498 zcu.free_references.deinit(gpa);2499 zcu.free_references.deinit(gpa);
24992500
2500 {
2501 var it = zcu.intern_pool.allocated_namespaces.iterator(0);
2502 while (it.next()) |namespace| {
2503 namespace.decls.deinit(gpa);
2504 namespace.usingnamespace_set.deinit(gpa);
2505 }
2506 }
2507
2508 zcu.intern_pool.deinit(gpa);2501 zcu.intern_pool.deinit(gpa);
2509}2502}
25102503
2511pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
2512 const gpa = mod.gpa;
2513 const ip = &mod.intern_pool;
2514
2515 {
2516 _ = mod.test_functions.swapRemove(decl_index);
2517 if (mod.global_assembly.fetchSwapRemove(decl_index)) |kv| {
2518 gpa.free(kv.value);
2519 }
2520 }
2521
2522 ip.destroyDecl(gpa, decl_index);
2523
2524 if (mod.emit_h) |mod_emit_h| {
2525 const decl_emit_h = mod_emit_h.declPtr(decl_index);
2526 decl_emit_h.fwd_decl.deinit(gpa);
2527 decl_emit_h.* = undefined;
2528 }
2529}
2530
2531fn deinitFile(zcu: *Zcu, file_index: File.Index) void {
2532 const gpa = zcu.gpa;
2533 const file = zcu.fileByIndex(file_index);
2534 const is_builtin = file.mod.isBuiltin();
2535 log.debug("deinit File {s}", .{file.sub_file_path});
2536 if (is_builtin) {
2537 file.unloadTree(gpa);
2538 file.unloadZir(gpa);
2539 } else {
2540 gpa.free(file.sub_file_path);
2541 file.unload(gpa);
2542 }
2543 file.references.deinit(gpa);
2544 if (zcu.fileRootDecl(file_index).unwrap()) |root_decl| {
2545 zcu.destroyDecl(root_decl);
2546 }
2547 if (file.prev_zir) |prev_zir| {
2548 prev_zir.deinit(gpa);
2549 gpa.destroy(prev_zir);
2550 }
2551 file.* = undefined;
2552}
2553
2554pub fn destroyFile(zcu: *Zcu, file_index: File.Index) void {
2555 const gpa = zcu.gpa;
2556 const file = zcu.fileByIndex(file_index);
2557 const is_builtin = file.mod.isBuiltin();
2558 zcu.deinitFile(file_index);
2559 if (!is_builtin) gpa.destroy(file);
2560}
2561
2562pub fn declPtr(mod: *Module, index: Decl.Index) *Decl {2504pub fn declPtr(mod: *Module, index: Decl.Index) *Decl {
2563 return mod.intern_pool.declPtr(index);2505 return mod.intern_pool.declPtr(index);
2564}2506}
...@@ -3269,13 +3211,6 @@ fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8)...@@ -3269,13 +3211,6 @@ fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8)
3269 return bin;3211 return bin;
3270}3212}
32713213
3272/// Cancel the creation of an anon decl and delete any references to it.
3273/// If other decls depend on this decl, they must be aborted first.
3274pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
3275 assert(!mod.declIsRoot(decl_index));
3276 mod.destroyDecl(decl_index);
3277}
3278
3279/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of3214/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
3280/// this `AnalUnit` will cause them to be re-created (or not).3215/// this `AnalUnit` will cause them to be re-created (or not).
3281pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {3216pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
...@@ -3357,42 +3292,6 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -3357,42 +3292,6 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
3357 gop.value_ptr.* = @intCast(ref_idx);3292 gop.value_ptr.* = @intCast(ref_idx);
3358}3293}
33593294
3360pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index {
3361 return mod.intern_pool.createNamespace(mod.gpa, initialization);
3362}
3363
3364pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
3365 return mod.intern_pool.destroyNamespace(mod.gpa, index);
3366}
3367
3368pub fn allocateNewDecl(zcu: *Zcu, namespace: Namespace.Index) !Decl.Index {
3369 const gpa = zcu.gpa;
3370 const decl_index = try zcu.intern_pool.createDecl(gpa, .{
3371 .name = undefined,
3372 .src_namespace = namespace,
3373 .has_tv = false,
3374 .owns_tv = false,
3375 .val = undefined,
3376 .alignment = undefined,
3377 .@"linksection" = .none,
3378 .@"addrspace" = .generic,
3379 .analysis = .unreferenced,
3380 .zir_decl_index = .none,
3381 .is_pub = false,
3382 .is_exported = false,
3383 .kind = .anon,
3384 });
3385
3386 if (zcu.emit_h) |zcu_emit_h| {
3387 if (@intFromEnum(decl_index) >= zcu_emit_h.allocated_emit_h.len) {
3388 try zcu_emit_h.allocated_emit_h.append(gpa, .{});
3389 assert(@intFromEnum(decl_index) == zcu_emit_h.allocated_emit_h.len);
3390 }
3391 }
3392
3393 return decl_index;
3394}
3395
3396pub fn getErrorValue(3295pub fn getErrorValue(
3397 mod: *Module,3296 mod: *Module,
3398 name: InternPool.NullTerminatedString,3297 name: InternPool.NullTerminatedString,
src/Zcu/PerThread.zig+100-4
...@@ -5,6 +5,58 @@ tid: Id,...@@ -5,6 +5,58 @@ tid: Id,
55
6pub const Id = if (InternPool.single_threaded) enum { main } else enum(u8) { main, _ };6pub const Id = if (InternPool.single_threaded) enum { main } else enum(u8) { main, _ };
77
8pub fn destroyDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) void {
9 const zcu = pt.zcu;
10 const gpa = zcu.gpa;
11
12 {
13 _ = zcu.test_functions.swapRemove(decl_index);
14 if (zcu.global_assembly.fetchSwapRemove(decl_index)) |kv| {
15 gpa.free(kv.value);
16 }
17 }
18
19 pt.zcu.intern_pool.destroyDecl(pt.tid, decl_index);
20
21 if (zcu.emit_h) |zcu_emit_h| {
22 const decl_emit_h = zcu_emit_h.declPtr(decl_index);
23 decl_emit_h.fwd_decl.deinit(gpa);
24 decl_emit_h.* = undefined;
25 }
26}
27
28fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
29 const zcu = pt.zcu;
30 const gpa = zcu.gpa;
31 const file = zcu.fileByIndex(file_index);
32 const is_builtin = file.mod.isBuiltin();
33 log.debug("deinit File {s}", .{file.sub_file_path});
34 if (is_builtin) {
35 file.unloadTree(gpa);
36 file.unloadZir(gpa);
37 } else {
38 gpa.free(file.sub_file_path);
39 file.unload(gpa);
40 }
41 file.references.deinit(gpa);
42 if (zcu.fileRootDecl(file_index).unwrap()) |root_decl| {
43 pt.zcu.intern_pool.destroyDecl(pt.tid, root_decl);
44 }
45 if (file.prev_zir) |prev_zir| {
46 prev_zir.deinit(gpa);
47 gpa.destroy(prev_zir);
48 }
49 file.* = undefined;
50}
51
52pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
53 const gpa = pt.zcu.gpa;
54 const file = pt.zcu.fileByIndex(file_index);
55 const is_builtin = file.mod.isBuiltin();
56 pt.deinitFile(file_index);
57 if (!is_builtin) gpa.destroy(file);
58}
59
8pub fn astGenFile(60pub fn astGenFile(
9 pt: Zcu.PerThread,61 pt: Zcu.PerThread,
10 file: *Zcu.File,62 file: *Zcu.File,
...@@ -930,14 +982,14 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -930,14 +982,14 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
930 // Because these three things each reference each other, `undefined`982 // Because these three things each reference each other, `undefined`
931 // placeholders are used before being set after the struct type gains an983 // placeholders are used before being set after the struct type gains an
932 // InternPool index.984 // InternPool index.
933 const new_namespace_index = try zcu.createNamespace(.{985 const new_namespace_index = try pt.createNamespace(.{
934 .parent = .none,986 .parent = .none,
935 .decl_index = undefined,987 .decl_index = undefined,
936 .file_scope = file_index,988 .file_scope = file_index,
937 });989 });
938 errdefer zcu.destroyNamespace(new_namespace_index);990 errdefer pt.destroyNamespace(new_namespace_index);
939991
940 const new_decl_index = try zcu.allocateNewDecl(new_namespace_index);992 const new_decl_index = try pt.allocateNewDecl(new_namespace_index);
941 const new_decl = zcu.declPtr(new_decl_index);993 const new_decl = zcu.declPtr(new_decl_index);
942 errdefer @panic("TODO error handling");994 errdefer @panic("TODO error handling");
943995
...@@ -1380,6 +1432,13 @@ pub fn embedFile(...@@ -1380,6 +1432,13 @@ pub fn embedFile(
1380 return pt.newEmbedFile(cur_file.mod, sub_file_path, resolved_path, gop.value_ptr, src_loc);1432 return pt.newEmbedFile(cur_file.mod, sub_file_path, resolved_path, gop.value_ptr, src_loc);
1381}1433}
13821434
1435/// Cancel the creation of an anon decl and delete any references to it.
1436/// If other decls depend on this decl, they must be aborted first.
1437pub fn abortAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) void {
1438 assert(!pt.zcu.declIsRoot(decl_index));
1439 pt.destroyDecl(decl_index);
1440}
1441
1383/// Finalize the creation of an anon decl.1442/// Finalize the creation of an anon decl.
1384pub fn finalizeAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Allocator.Error!void {1443pub fn finalizeAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Allocator.Error!void {
1385 if (pt.zcu.declPtr(decl_index).typeOf(pt.zcu).isFnOrHasRuntimeBits(pt)) {1444 if (pt.zcu.declPtr(decl_index).typeOf(pt.zcu).isFnOrHasRuntimeBits(pt)) {
...@@ -1674,7 +1733,7 @@ const ScanDeclIter = struct {...@@ -1674,7 +1733,7 @@ const ScanDeclIter = struct {
1674 break :decl_index .{ was_exported, decl_index };1733 break :decl_index .{ was_exported, decl_index };
1675 } else decl_index: {1734 } else decl_index: {
1676 // Create and set up a new Decl.1735 // Create and set up a new Decl.
1677 const new_decl_index = try zcu.allocateNewDecl(namespace_index);1736 const new_decl_index = try pt.allocateNewDecl(namespace_index);
1678 const new_decl = zcu.declPtr(new_decl_index);1737 const new_decl = zcu.declPtr(new_decl_index);
1679 new_decl.kind = kind;1738 new_decl.kind = kind;
1680 new_decl.name = decl_name;1739 new_decl.name = decl_name;
...@@ -1981,6 +2040,43 @@ pub fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index, arena: All...@@ -1981,6 +2040,43 @@ pub fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index, arena: All
1981 };2040 };
1982}2041}
19832042
2043pub fn createNamespace(pt: Zcu.PerThread, initialization: Zcu.Namespace) !Zcu.Namespace.Index {
2044 return pt.zcu.intern_pool.createNamespace(pt.zcu.gpa, pt.tid, initialization);
2045}
2046
2047pub fn destroyNamespace(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) void {
2048 return pt.zcu.intern_pool.destroyNamespace(pt.tid, namespace_index);
2049}
2050
2051pub fn allocateNewDecl(pt: Zcu.PerThread, namespace: Zcu.Namespace.Index) !Zcu.Decl.Index {
2052 const zcu = pt.zcu;
2053 const gpa = zcu.gpa;
2054 const decl_index = try zcu.intern_pool.createDecl(gpa, pt.tid, .{
2055 .name = undefined,
2056 .src_namespace = namespace,
2057 .has_tv = false,
2058 .owns_tv = false,
2059 .val = undefined,
2060 .alignment = undefined,
2061 .@"linksection" = .none,
2062 .@"addrspace" = .generic,
2063 .analysis = .unreferenced,
2064 .zir_decl_index = .none,
2065 .is_pub = false,
2066 .is_exported = false,
2067 .kind = .anon,
2068 });
2069
2070 if (zcu.emit_h) |zcu_emit_h| {
2071 if (@intFromEnum(decl_index) >= zcu_emit_h.allocated_emit_h.len) {
2072 try zcu_emit_h.allocated_emit_h.append(gpa, .{});
2073 assert(@intFromEnum(decl_index) == zcu_emit_h.allocated_emit_h.len);
2074 }
2075 }
2076
2077 return decl_index;
2078}
2079
1984fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {2080fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
1985 switch (file.status) {2081 switch (file.status) {
1986 .success_zir, .retryable_failure => {},2082 .success_zir, .retryable_failure => {},