authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-04-27 01:11:41-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-04-27 01:11:57-04:00
log15dafd16e65a8cd8ea434f0b4783f08875254cd4
tree3d375de60cb43e1a353994cc101f4efb3bfc023e
parent2b592d7e3cf328deb1b8ffa7ea88389d785837ff

sema: add `prev` to ValueArena to allow freeing previous arenas when new ones are created during re-analysis

In semaDecl, it was possible for a new ArenaAllocators state to replace an existing one that hadn't been freed yet. Instead of the ref_count (which was made redundant by adding the allocator parameter to `release`), I now store a pointer to the previous arena, if one exists. This allows a recursive deinit to happen when the last arena created is destroyed.

2 files changed, 31 insertions(+), 25 deletions(-)

src/Module.zig+25-19
......@@ -415,23 +415,15 @@ const ValueArena = struct {
415415 state: std.heap.ArenaAllocator.State,
416416 state_acquired: ?*std.heap.ArenaAllocator.State = null,
417417
418 /// If non-zero, then an ArenaAllocator has been promoted from `state`,
419 /// and `state_acquired` points to its state field.
420 ref_count: usize = 0,
418 /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance
419 prev: ?*ValueArena = null,
421420
422421 /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator
423422 /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion,
424 /// and must live until the matching call to release()
423 /// and must live until the matching call to release().
425424 pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator {
426 defer self.ref_count += 1;
427
428425 if (self.state_acquired) |state_acquired| {
429 const arena_allocator = @fieldParentPtr(
430 std.heap.ArenaAllocator,
431 "state",
432 state_acquired,
433 );
434 return arena_allocator.allocator();
426 return @fieldParentPtr(std.heap.ArenaAllocator, "state", state_acquired).allocator();
435427 }
436428
437429 out_arena_allocator.* = self.state.promote(child_allocator);
......@@ -439,13 +431,24 @@ const ValueArena = struct {
439431 return out_arena_allocator.allocator();
440432 }
441433
442 pub fn release(self: *ValueArena) void {
443 self.ref_count -= 1;
444 if (self.ref_count == 0) {
434 /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`.
435 pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void {
436 if (@fieldParentPtr(std.heap.ArenaAllocator, "state", self.state_acquired.?) == arena_allocator) {
445437 self.state = self.state_acquired.?.*;
446438 self.state_acquired = null;
447439 }
448440 }
441
442 pub fn deinit(self: ValueArena, child_allocator: Allocator) void {
443 assert(self.state_acquired == null);
444
445 const prev = self.prev;
446 self.state.promote(child_allocator).deinit();
447
448 if (prev) |p| {
449 p.deinit(child_allocator);
450 }
451 }
449452};
450453
451454pub const Decl = struct {
......@@ -652,8 +655,7 @@ pub const Decl = struct {
652655 }).?.* = .none;
653656 }
654657 }
655 assert(value_arena.ref_count == 0);
656 value_arena.state.promote(gpa).deinit();
658 value_arena.deinit(gpa);
657659 decl.value_arena = null;
658660 decl.has_tv = false;
659661 decl.owns_tv = false;
......@@ -4575,7 +4577,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
45754577 // We need the memory for the Type to go into the arena for the Decl
45764578 var decl_arena = std.heap.ArenaAllocator.init(gpa);
45774579 const decl_arena_allocator = decl_arena.allocator();
4578
45794580 const decl_value_arena = blk: {
45804581 errdefer decl_arena.deinit();
45814582 const s = try decl_arena_allocator.create(ValueArena);
......@@ -4583,6 +4584,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
45834584 break :blk s;
45844585 };
45854586 defer {
4587 if (decl.value_arena) |value_arena| {
4588 assert(value_arena.state_acquired == null);
4589 decl_value_arena.prev = value_arena;
4590 }
4591
45864592 decl_value_arena.state = decl_arena.state;
45874593 decl.value_arena = decl_value_arena;
45884594 }
......@@ -5534,7 +5540,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
55345540 // Use the Decl's arena for captured values.
55355541 var decl_arena: std.heap.ArenaAllocator = undefined;
55365542 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
5537 defer decl.value_arena.?.release();
5543 defer decl.value_arena.?.release(&decl_arena);
55385544
55395545 var sema: Sema = .{
55405546 .mod = mod,
src/Sema.zig+6-6
......@@ -2858,7 +2858,7 @@ fn zirEnumDecl(
28582858
28592859 var decl_arena: std.heap.ArenaAllocator = undefined;
28602860 const decl_arena_allocator = new_decl.value_arena.?.acquire(gpa, &decl_arena);
2861 defer new_decl.value_arena.?.release();
2861 defer new_decl.value_arena.?.release(&decl_arena);
28622862
28632863 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
28642864
......@@ -27004,7 +27004,7 @@ const ComptimePtrMutationKit = struct {
2700427004
2700527005 fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {
2700627006 const decl = mod.declPtr(self.decl_ref_mut.decl_index);
27007 decl.value_arena.?.release();
27007 decl.value_arena.?.release(&self.decl_arena);
2700827008 self.decl_arena = undefined;
2700927009 }
2701027010};
......@@ -30655,7 +30655,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3065530655 const decl = sema.mod.declPtr(struct_obj.owner_decl);
3065630656 var decl_arena: std.heap.ArenaAllocator = undefined;
3065730657 const decl_arena_allocator = decl.value_arena.?.acquire(sema.mod.gpa, &decl_arena);
30658 defer decl.value_arena.?.release();
30658 defer decl.value_arena.?.release(&decl_arena);
3065930659 break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count());
3066030660 };
3066130661
......@@ -30701,7 +30701,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3070130701 const decl = mod.declPtr(decl_index);
3070230702 var decl_arena: std.heap.ArenaAllocator = undefined;
3070330703 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
30704 defer decl.value_arena.?.release();
30704 defer decl.value_arena.?.release(&decl_arena);
3070530705
3070630706 const zir = struct_obj.namespace.file_scope.zir;
3070730707 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
......@@ -31395,7 +31395,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3139531395 const decl = mod.declPtr(decl_index);
3139631396 var decl_arena: std.heap.ArenaAllocator = undefined;
3139731397 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
31398 defer decl.value_arena.?.release();
31398 defer decl.value_arena.?.release(&decl_arena);
3139931399
3140031400 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3140131401 defer analysis_arena.deinit();
......@@ -31735,7 +31735,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3173531735 const decl = mod.declPtr(decl_index);
3173631736 var decl_arena: std.heap.ArenaAllocator = undefined;
3173731737 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
31738 defer decl.value_arena.?.release();
31738 defer decl.value_arena.?.release(&decl_arena);
3173931739
3174031740 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3174131741 defer analysis_arena.deinit();