| author | |
| committer | |
| log | 15dafd16e65a8cd8ea434f0b4783f08875254cd4 |
| tree | 3d375de60cb43e1a353994cc101f4efb3bfc023e |
| parent | 2b592d7e3cf328deb1b8ffa7ea88389d785837ff |
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 | 415 | state: std.heap.ArenaAllocator.State, |
| 416 | 416 | state_acquired: ?*std.heap.ArenaAllocator.State = null, |
| 417 | 417 | |
| 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, | |
| 421 | 420 | |
| 422 | 421 | /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator |
| 423 | 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 | 424 | pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator { |
| 426 | defer self.ref_count += 1; | |
| 427 | ||
| 428 | 425 | 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(); | |
| 435 | 427 | } |
| 436 | 428 | |
| 437 | 429 | out_arena_allocator.* = self.state.promote(child_allocator); |
| ... | ... | @@ -439,13 +431,24 @@ const ValueArena = struct { |
| 439 | 431 | return out_arena_allocator.allocator(); |
| 440 | 432 | } |
| 441 | 433 | |
| 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) { | |
| 445 | 437 | self.state = self.state_acquired.?.*; |
| 446 | 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 | }; |
| 450 | 453 | |
| 451 | 454 | pub const Decl = struct { |
| ... | ... | @@ -652,8 +655,7 @@ pub const Decl = struct { |
| 652 | 655 | }).?.* = .none; |
| 653 | 656 | } |
| 654 | 657 | } |
| 655 | assert(value_arena.ref_count == 0); | |
| 656 | value_arena.state.promote(gpa).deinit(); | |
| 658 | value_arena.deinit(gpa); | |
| 657 | 659 | decl.value_arena = null; |
| 658 | 660 | decl.has_tv = false; |
| 659 | 661 | decl.owns_tv = false; |
| ... | ... | @@ -4575,7 +4577,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4575 | 4577 | // We need the memory for the Type to go into the arena for the Decl |
| 4576 | 4578 | var decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 4577 | 4579 | const decl_arena_allocator = decl_arena.allocator(); |
| 4578 | ||
| 4579 | 4580 | const decl_value_arena = blk: { |
| 4580 | 4581 | errdefer decl_arena.deinit(); |
| 4581 | 4582 | const s = try decl_arena_allocator.create(ValueArena); |
| ... | ... | @@ -4583,6 +4584,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4583 | 4584 | break :blk s; |
| 4584 | 4585 | }; |
| 4585 | 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 | 4592 | decl_value_arena.state = decl_arena.state; |
| 4587 | 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 | 5540 | // Use the Decl's arena for captured values. |
| 5535 | 5541 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 5536 | 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); | |
| 5538 | 5544 | |
| 5539 | 5545 | var sema: Sema = .{ |
| 5540 | 5546 | .mod = mod, |
src/Sema.zig+6-6| ... | ... | @@ -2858,7 +2858,7 @@ fn zirEnumDecl( |
| 2858 | 2858 | |
| 2859 | 2859 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 2860 | 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); | |
| 2862 | 2862 | |
| 2863 | 2863 | extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); |
| 2864 | 2864 | |
| ... | ... | @@ -27004,7 +27004,7 @@ const ComptimePtrMutationKit = struct { |
| 27004 | 27004 | |
| 27005 | 27005 | fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { |
| 27006 | 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 | 27008 | self.decl_arena = undefined; |
| 27009 | 27009 | } |
| 27010 | 27010 | }; |
| ... | ... | @@ -30655,7 +30655,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30655 | 30655 | const decl = sema.mod.declPtr(struct_obj.owner_decl); |
| 30656 | 30656 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 30657 | 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 | 30659 | break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); |
| 30660 | 30660 | }; |
| 30661 | 30661 | |
| ... | ... | @@ -30701,7 +30701,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 30701 | 30701 | const decl = mod.declPtr(decl_index); |
| 30702 | 30702 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 30703 | 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); | |
| 30705 | 30705 | |
| 30706 | 30706 | const zir = struct_obj.namespace.file_scope.zir; |
| 30707 | 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 | 31395 | const decl = mod.declPtr(decl_index); |
| 31396 | 31396 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 31397 | 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); | |
| 31399 | 31399 | |
| 31400 | 31400 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31401 | 31401 | defer analysis_arena.deinit(); |
| ... | ... | @@ -31735,7 +31735,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 31735 | 31735 | const decl = mod.declPtr(decl_index); |
| 31736 | 31736 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 31737 | 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); | |
| 31739 | 31739 | |
| 31740 | 31740 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31741 | 31741 | defer analysis_arena.deinit(); |