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 {...@@ -415,23 +415,15 @@ const ValueArena = struct {
415 state: std.heap.ArenaAllocator.State,415 state: std.heap.ArenaAllocator.State,
416 state_acquired: ?*std.heap.ArenaAllocator.State = null,416 state_acquired: ?*std.heap.ArenaAllocator.State = null,
417417
418 /// If non-zero, then an ArenaAllocator has been promoted from `state`,418 /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance
419 /// and `state_acquired` points to its state field.419 prev: ?*ValueArena = null,
420 ref_count: usize = 0,
421420
422 /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator421 /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator
423 /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion,422 /// 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().
425 pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator {424 pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator {
426 defer self.ref_count += 1;
427
428 if (self.state_acquired) |state_acquired| {425 if (self.state_acquired) |state_acquired| {
429 const arena_allocator = @fieldParentPtr(426 return @fieldParentPtr(std.heap.ArenaAllocator, "state", state_acquired).allocator();
430 std.heap.ArenaAllocator,
431 "state",
432 state_acquired,
433 );
434 return arena_allocator.allocator();
435 }427 }
436428
437 out_arena_allocator.* = self.state.promote(child_allocator);429 out_arena_allocator.* = self.state.promote(child_allocator);
...@@ -439,13 +431,24 @@ const ValueArena = struct {...@@ -439,13 +431,24 @@ const ValueArena = struct {
439 return out_arena_allocator.allocator();431 return out_arena_allocator.allocator();
440 }432 }
441433
442 pub fn release(self: *ValueArena) void {434 /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`.
443 self.ref_count -= 1;435 pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void {
444 if (self.ref_count == 0) {436 if (@fieldParentPtr(std.heap.ArenaAllocator, "state", self.state_acquired.?) == arena_allocator) {
445 self.state = self.state_acquired.?.*;437 self.state = self.state_acquired.?.*;
446 self.state_acquired = null;438 self.state_acquired = null;
447 }439 }
448 }440 }
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 }
449};452};
450453
451pub const Decl = struct {454pub const Decl = struct {
...@@ -652,8 +655,7 @@ pub const Decl = struct {...@@ -652,8 +655,7 @@ pub const Decl = struct {
652 }).?.* = .none;655 }).?.* = .none;
653 }656 }
654 }657 }
655 assert(value_arena.ref_count == 0);658 value_arena.deinit(gpa);
656 value_arena.state.promote(gpa).deinit();
657 decl.value_arena = null;659 decl.value_arena = null;
658 decl.has_tv = false;660 decl.has_tv = false;
659 decl.owns_tv = false;661 decl.owns_tv = false;
...@@ -4575,7 +4577,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4575,7 +4577,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4575 // We need the memory for the Type to go into the arena for the Decl4577 // We need the memory for the Type to go into the arena for the Decl
4576 var decl_arena = std.heap.ArenaAllocator.init(gpa);4578 var decl_arena = std.heap.ArenaAllocator.init(gpa);
4577 const decl_arena_allocator = decl_arena.allocator();4579 const decl_arena_allocator = decl_arena.allocator();
4578
4579 const decl_value_arena = blk: {4580 const decl_value_arena = blk: {
4580 errdefer decl_arena.deinit();4581 errdefer decl_arena.deinit();
4581 const s = try decl_arena_allocator.create(ValueArena);4582 const s = try decl_arena_allocator.create(ValueArena);
...@@ -4583,6 +4584,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4583,6 +4584,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4583 break :blk s;4584 break :blk s;
4584 };4585 };
4585 defer {4586 defer {
4587 if (decl.value_arena) |value_arena| {
4588 assert(value_arena.state_acquired == null);
4589 decl_value_arena.prev = value_arena;
4590 }
4591
4586 decl_value_arena.state = decl_arena.state;4592 decl_value_arena.state = decl_arena.state;
4587 decl.value_arena = decl_value_arena;4593 decl.value_arena = decl_value_arena;
4588 }4594 }
...@@ -5534,7 +5540,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {...@@ -5534,7 +5540,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
5534 // Use the Decl's arena for captured values.5540 // Use the Decl's arena for captured values.
5535 var decl_arena: std.heap.ArenaAllocator = undefined;5541 var decl_arena: std.heap.ArenaAllocator = undefined;
5536 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);5542 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
5539 var sema: Sema = .{5545 var sema: Sema = .{
5540 .mod = mod,5546 .mod = mod,
src/Sema.zig+6-6
...@@ -2858,7 +2858,7 @@ fn zirEnumDecl(...@@ -2858,7 +2858,7 @@ fn zirEnumDecl(
28582858
2859 var decl_arena: std.heap.ArenaAllocator = undefined;2859 var decl_arena: std.heap.ArenaAllocator = undefined;
2860 const decl_arena_allocator = new_decl.value_arena.?.acquire(gpa, &decl_arena);2860 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
2863 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);2863 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
28642864
...@@ -27004,7 +27004,7 @@ const ComptimePtrMutationKit = struct {...@@ -27004,7 +27004,7 @@ const ComptimePtrMutationKit = struct {
2700427004
27005 fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {27005 fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {
27006 const decl = mod.declPtr(self.decl_ref_mut.decl_index);27006 const decl = mod.declPtr(self.decl_ref_mut.decl_index);
27007 decl.value_arena.?.release();27007 decl.value_arena.?.release(&self.decl_arena);
27008 self.decl_arena = undefined;27008 self.decl_arena = undefined;
27009 }27009 }
27010};27010};
...@@ -30655,7 +30655,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -30655,7 +30655,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
30655 const decl = sema.mod.declPtr(struct_obj.owner_decl);30655 const decl = sema.mod.declPtr(struct_obj.owner_decl);
30656 var decl_arena: std.heap.ArenaAllocator = undefined;30656 var decl_arena: std.heap.ArenaAllocator = undefined;
30657 const decl_arena_allocator = decl.value_arena.?.acquire(sema.mod.gpa, &decl_arena);30657 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);
30659 break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count());30659 break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count());
30660 };30660 };
3066130661
...@@ -30701,7 +30701,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -30701,7 +30701,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
30701 const decl = mod.declPtr(decl_index);30701 const decl = mod.declPtr(decl_index);
30702 var decl_arena: std.heap.ArenaAllocator = undefined;30702 var decl_arena: std.heap.ArenaAllocator = undefined;
30703 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);30703 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
30706 const zir = struct_obj.namespace.file_scope.zir;30706 const zir = struct_obj.namespace.file_scope.zir;
30707 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;30707 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...@@ -31395,7 +31395,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
31395 const decl = mod.declPtr(decl_index);31395 const decl = mod.declPtr(decl_index);
31396 var decl_arena: std.heap.ArenaAllocator = undefined;31396 var decl_arena: std.heap.ArenaAllocator = undefined;
31397 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);31397 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
31400 var analysis_arena = std.heap.ArenaAllocator.init(gpa);31400 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
31401 defer analysis_arena.deinit();31401 defer analysis_arena.deinit();
...@@ -31735,7 +31735,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -31735,7 +31735,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
31735 const decl = mod.declPtr(decl_index);31735 const decl = mod.declPtr(decl_index);
31736 var decl_arena: std.heap.ArenaAllocator = undefined;31736 var decl_arena: std.heap.ArenaAllocator = undefined;
31737 const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);31737 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
31740 var analysis_arena = std.heap.ArenaAllocator.init(gpa);31740 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
31741 defer analysis_arena.deinit();31741 defer analysis_arena.deinit();