Commit 46f54b23ae

Luuk de Gram <luuk@degram.dev>
2023-02-01 18:55:35
link: make Wasm atoms fully owned by the linker
1 parent 1aa0f8a
Changed files (10)
src/arch/wasm/CodeGen.zig
@@ -1269,10 +1269,10 @@ fn genFunc(func: *CodeGen) InnerError!void {
 
     var emit: Emit = .{
         .mir = mir,
-        .bin_file = &func.bin_file.base,
+        .bin_file = func.bin_file,
         .code = func.code,
         .locals = func.locals.items,
-        .decl = func.decl,
+        .decl_index = func.decl_index,
         .dbg_output = func.debug_output,
         .prev_di_line = 0,
         .prev_di_column = 0,
@@ -2115,21 +2115,20 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
     const fn_info = fn_ty.fnInfo();
     const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target);
 
-    const callee: ?*Decl = blk: {
+    const callee: ?Decl.Index = blk: {
         const func_val = func.air.value(pl_op.operand) orelse break :blk null;
         const module = func.bin_file.base.options.module.?;
 
         if (func_val.castTag(.function)) |function| {
-            const decl = module.declPtr(function.data.owner_decl);
-            try decl.link.wasm.ensureInitialized(func.bin_file);
-            break :blk decl;
+            _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl);
+            break :blk function.data.owner_decl;
         } else if (func_val.castTag(.extern_fn)) |extern_fn| {
             const ext_decl = module.declPtr(extern_fn.data.owner_decl);
             const ext_info = ext_decl.ty.fnInfo();
             var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);
             defer func_type.deinit(func.gpa);
-            const atom = &ext_decl.link.wasm;
-            try atom.ensureInitialized(func.bin_file);
+            const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl);
+            const atom = func.bin_file.getAtomPtr(atom_index);
             ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);
             try func.bin_file.addOrUpdateImport(
                 mem.sliceTo(ext_decl.name, 0),
@@ -2137,11 +2136,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
                 ext_decl.getExternFn().?.lib_name,
                 ext_decl.fn_link.wasm.type_index,
             );
-            break :blk ext_decl;
+            break :blk extern_fn.data.owner_decl;
         } else if (func_val.castTag(.decl_ref)) |decl_ref| {
-            const decl = module.declPtr(decl_ref.data);
-            try decl.link.wasm.ensureInitialized(func.bin_file);
-            break :blk decl;
+            _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data);
+            break :blk decl_ref.data;
         }
         return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()});
     };
@@ -2162,7 +2160,8 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
     }
 
     if (callee) |direct| {
-        try func.addLabel(.call, direct.link.wasm.sym_index);
+        const atom_index = func.bin_file.decls.get(direct).?;
+        try func.addLabel(.call, func.bin_file.getAtom(atom_index).sym_index);
     } else {
         // in this case we call a function pointer
         // so load its value onto the stack
@@ -2758,9 +2757,10 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
     }
 
     module.markDeclAlive(decl);
-    try decl.link.wasm.ensureInitialized(func.bin_file);
+    const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index);
+    const atom = func.bin_file.getAtom(atom_index);
 
-    const target_sym_index = decl.link.wasm.sym_index;
+    const target_sym_index = atom.sym_index;
     if (decl.ty.zigTypeTag() == .Fn) {
         try func.bin_file.addTableFunction(target_sym_index);
         return WValue{ .function_index = target_sym_index };
src/arch/wasm/Emit.zig
@@ -11,8 +11,8 @@ const leb128 = std.leb;
 
 /// Contains our list of instructions
 mir: Mir,
-/// Reference to the file handler
-bin_file: *link.File,
+/// Reference to the Wasm module linker
+bin_file: *link.File.Wasm,
 /// Possible error message. When set, the value is allocated and
 /// must be freed manually.
 error_msg: ?*Module.ErrorMsg = null,
@@ -21,7 +21,7 @@ code: *std.ArrayList(u8),
 /// List of allocated locals.
 locals: []const u8,
 /// The declaration that code is being generated for.
-decl: *Module.Decl,
+decl_index: Module.Decl.Index,
 
 // Debug information
 /// Holds the debug information for this emission
@@ -252,8 +252,8 @@ fn offset(self: Emit) u32 {
 fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
     @setCold(true);
     std.debug.assert(emit.error_msg == null);
-    // TODO: Determine the source location.
-    emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.allocator, emit.decl.srcLoc(), format, args);
+    const mod = emit.bin_file.base.options.module.?;
+    emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(), format, args);
     return error.EmitFail;
 }
 
@@ -304,8 +304,9 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
     const global_offset = emit.offset();
     try emit.code.appendSlice(&buf);
 
-    // globals can have index 0 as it represents the stack pointer
-    try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
+    const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
+    const atom = emit.bin_file.getAtomPtr(atom_index);
+    try atom.relocs.append(emit.bin_file.base.allocator, .{
         .index = label,
         .offset = global_offset,
         .relocation_type = .R_WASM_GLOBAL_INDEX_LEB,
@@ -361,7 +362,9 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
     try emit.code.appendSlice(&buf);
 
     if (label != 0) {
-        try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
+        const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
+        const atom = emit.bin_file.getAtomPtr(atom_index);
+        try atom.relocs.append(emit.bin_file.base.allocator, .{
             .offset = call_offset,
             .index = label,
             .relocation_type = .R_WASM_FUNCTION_INDEX_LEB,
@@ -387,7 +390,9 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
     try emit.code.appendSlice(&buf);
 
     if (symbol_index != 0) {
-        try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
+        const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
+        const atom = emit.bin_file.getAtomPtr(atom_index);
+        try atom.relocs.append(emit.bin_file.base.allocator, .{
             .offset = index_offset,
             .index = symbol_index,
             .relocation_type = .R_WASM_TABLE_INDEX_SLEB,
@@ -399,7 +404,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
     const extra_index = emit.mir.instructions.items(.data)[inst].payload;
     const mem = emit.mir.extraData(Mir.Memory, extra_index).data;
     const mem_offset = emit.offset() + 1;
-    const is_wasm32 = emit.bin_file.options.target.cpu.arch == .wasm32;
+    const is_wasm32 = emit.bin_file.base.options.target.cpu.arch == .wasm32;
     if (is_wasm32) {
         try emit.code.append(std.wasm.opcode(.i32_const));
         var buf: [5]u8 = undefined;
@@ -413,7 +418,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
     }
 
     if (mem.pointer != 0) {
-        try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
+        const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
+        const atom = emit.bin_file.getAtomPtr(atom_index);
+        try atom.relocs.append(emit.bin_file.base.allocator, .{
             .offset = mem_offset,
             .index = mem.pointer,
             .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64,
src/link/Wasm/Atom.zig
@@ -29,14 +29,17 @@ file: ?u16,
 
 /// Next atom in relation to this atom.
 /// When null, this atom is the last atom
-next: ?*Atom,
+next: ?Atom.Index,
 /// Previous atom in relation to this atom.
 /// is null when this atom is the first in its order
-prev: ?*Atom,
+prev: ?Atom.Index,
 
 /// Contains atoms local to a decl, all managed by this `Atom`.
 /// When the parent atom is being freed, it will also do so for all local atoms.
-locals: std.ArrayListUnmanaged(Atom) = .{},
+locals: std.ArrayListUnmanaged(Atom.Index) = .{},
+
+/// Alias to an unsigned 32-bit integer
+pub const Index = u32;
 
 /// Represents a default empty wasm `Atom`
 pub const empty: Atom = .{
@@ -50,14 +53,12 @@ pub const empty: Atom = .{
 };
 
 /// Frees all resources owned by this `Atom`.
-pub fn deinit(atom: *Atom, gpa: Allocator) void {
+pub fn deinit(atom: *Atom, wasm: *Wasm) void {
+    const gpa = wasm.base.allocator;
     atom.relocs.deinit(gpa);
     atom.code.deinit(gpa);
-
-    for (atom.locals.items) |*local| {
-        local.deinit(gpa);
-    }
     atom.locals.deinit(gpa);
+    atom.* = undefined;
 }
 
 /// Sets the length of relocations and code to '0',
@@ -78,24 +79,11 @@ pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptio
     });
 }
 
-/// Returns the first `Atom` from a given atom
-pub fn getFirst(atom: *Atom) *Atom {
-    var tmp = atom;
-    while (tmp.prev) |prev| tmp = prev;
-    return tmp;
-}
-
 /// Returns the location of the symbol that represents this `Atom`
 pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
     return .{ .file = atom.file, .index = atom.sym_index };
 }
 
-pub fn ensureInitialized(atom: *Atom, wasm_bin: *Wasm) !void {
-    if (atom.getSymbolIndex() != null) return; // already initialized
-    atom.sym_index = try wasm_bin.allocateSymbol();
-    try wasm_bin.symbol_atom.putNoClobber(wasm_bin.base.allocator, atom.symbolLoc(), atom);
-}
-
 pub fn getSymbolIndex(atom: Atom) ?u32 {
     if (atom.sym_index == 0) return null;
     return atom.sym_index;
@@ -198,20 +186,28 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
             if (symbol.isUndefined()) {
                 return 0;
             }
-            const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
+            const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse {
+                // this can only occur during incremental-compilation when a relocation
+                // still points to a freed decl. It is fine to emit the value 0 here
+                // as no actual code will point towards it.
+                return 0;
+            };
+            const target_atom = wasm_bin.getAtom(target_atom_index);
             const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));
             return @intCast(u32, va + relocation.addend);
         },
         .R_WASM_EVENT_INDEX_LEB => return symbol.index,
         .R_WASM_SECTION_OFFSET_I32 => {
-            const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
+            const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?;
+            const target_atom = wasm_bin.getAtom(target_atom_index);
             const rel_value = @intCast(i32, target_atom.offset) + relocation.addend;
             return @intCast(u32, rel_value);
         },
         .R_WASM_FUNCTION_OFFSET_I32 => {
-            const target_atom = wasm_bin.symbol_atom.get(target_loc) orelse {
+            const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse {
                 return @bitCast(u32, @as(i32, -1));
             };
+            const target_atom = wasm_bin.getAtom(target_atom_index);
             const offset: u32 = 11 + Wasm.getULEB128Size(target_atom.size); // Header (11 bytes fixed-size) + body size (leb-encoded)
             const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
             return @intCast(u32, rel_value);
src/link/Wasm/Object.zig
@@ -901,14 +901,9 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
             continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
         };
 
-        const atom = try gpa.create(Atom);
+        const atom_index = @intCast(Atom.Index, wasm_bin.managed_atoms.items.len);
+        const atom = try wasm_bin.managed_atoms.addOne(gpa);
         atom.* = Atom.empty;
-        errdefer {
-            atom.deinit(gpa);
-            gpa.destroy(atom);
-        }
-
-        try wasm_bin.managed_atoms.append(gpa, atom);
         atom.file = object_index;
         atom.size = relocatable_data.size;
         atom.alignment = relocatable_data.getAlignment(object);
@@ -938,12 +933,12 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
             .index = relocatable_data.getIndex(),
         })) |symbols| {
             atom.sym_index = symbols.pop();
-            try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
+            try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);
 
             // symbols referencing the same atom will be added as alias
             // or as 'parent' when they are global.
             while (symbols.popOrNull()) |idx| {
-                try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom);
+                try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom_index);
                 const alias_symbol = object.symtable[idx];
                 if (alias_symbol.isGlobal()) {
                     atom.sym_index = idx;
@@ -956,7 +951,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
             segment.alignment = std.math.max(segment.alignment, atom.alignment);
         }
 
-        try wasm_bin.appendAtomAtIndex(final_index, atom);
+        try wasm_bin.appendAtomAtIndex(final_index, atom_index);
         log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
     }
 }
src/link/Dwarf.zig
@@ -1099,7 +1099,7 @@ pub fn commitDeclState(
                             },
                             .wasm => {
                                 const wasm_file = self.bin_file.cast(File.Wasm).?;
-                                const debug_line = wasm_file.debug_line_atom.?.code;
+                                const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
                                 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
                             },
                             else => unreachable,
@@ -1177,7 +1177,7 @@ pub fn commitDeclState(
 
                 .wasm => {
                     const wasm_file = self.bin_file.cast(File.Wasm).?;
-                    const atom = wasm_file.debug_line_atom.?;
+                    const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?);
                     const debug_line = &atom.code;
                     const segment_size = debug_line.items.len;
                     if (needed_size != segment_size) {
@@ -1345,7 +1345,8 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
                     },
                     .wasm => {
                         const wasm_file = self.bin_file.cast(File.Wasm).?;
-                        const debug_info = &wasm_file.debug_info_atom.?.code;
+                        const debug_info_index = wasm_file.debug_info_atom.?;
+                        const debug_info = &wasm_file.getAtomPtr(debug_info_index).code;
                         try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
                     },
                     else => unreachable,
@@ -1441,7 +1442,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
             const info_atom = wasm_file.debug_info_atom.?;
-            const debug_info = &info_atom.code;
+            const debug_info = &wasm_file.getAtomPtr(info_atom).code;
             const segment_size = debug_info.items.len;
             if (needed_size != segment_size) {
                 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
@@ -1504,8 +1505,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
             const offset = atom.off + self.getRelocDbgLineOff();
-            const atom_ = wasm_file.debug_line_atom.?;
-            mem.copy(u8, atom_.code.items[offset..], &data);
+            const line_atom_index = wasm_file.debug_line_atom.?;
+            mem.copy(u8, wasm_file.getAtomPtr(line_atom_index).code.items[offset..], &data);
         },
         else => unreachable,
     }
@@ -1722,7 +1723,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
         },
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
-            const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;
+            const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
             try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
             mem.copy(u8, debug_abbrev.items, &abbrev_buf);
         },
@@ -1835,7 +1836,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
         },
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
-            const debug_info = &wasm_file.debug_info_atom.?.code;
+            const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
             try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
         },
         else => unreachable,
@@ -2156,7 +2157,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
         },
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
-            const debug_ranges = &wasm_file.debug_ranges_atom.?.code;
+            const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;
             try debug_ranges.resize(wasm_file.base.allocator, needed_size);
             mem.copy(u8, debug_ranges.items, di_buf.items);
         },
@@ -2330,7 +2331,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
             },
             .wasm => {
                 const wasm_file = self.bin_file.cast(File.Wasm).?;
-                const debug_line = &wasm_file.debug_line_atom.?.code;
+                const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
                 mem.copy(u8, buffer, debug_line.items[first_fn.off..]);
                 try debug_line.resize(self.allocator, debug_line.items.len + delta);
                 mem.copy(u8, debug_line.items[first_fn.off + delta ..], buffer);
@@ -2381,7 +2382,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
         },
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
-            const debug_line = wasm_file.debug_line_atom.?.code;
+            const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
             writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
         },
         else => unreachable,
@@ -2526,7 +2527,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
                 },
                 .wasm => {
                     const wasm_file = self.bin_file.cast(File.Wasm).?;
-                    const debug_info = wasm_file.debug_info_atom.?.code;
+                    const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
                     mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf);
                 },
                 else => unreachable,
src/link/Wasm.zig
@@ -9,7 +9,7 @@ const fs = std.fs;
 const leb = std.leb;
 const log = std.log.scoped(.link);
 
-const Atom = @import("Wasm/Atom.zig");
+pub const Atom = @import("Wasm/Atom.zig");
 const Dwarf = @import("Dwarf.zig");
 const Module = @import("../Module.zig");
 const Compilation = @import("../Compilation.zig");
@@ -31,10 +31,7 @@ const Object = @import("Wasm/Object.zig");
 const Archive = @import("Wasm/Archive.zig");
 const types = @import("Wasm/types.zig");
 
-pub const base_tag = link.File.Tag.wasm;
-
-/// deprecated: Use `@import("Wasm/Atom.zig");`
-pub const DeclBlock = Atom;
+pub const base_tag: link.File.Tag = .wasm;
 
 base: link.File,
 /// Output name of the file
@@ -47,18 +44,16 @@ llvm_object: ?*LlvmObject = null,
 /// TODO: Allow setting this through a flag?
 host_name: []const u8 = "env",
 /// List of all `Decl` that are currently alive.
-/// This is ment for bookkeeping so we can safely cleanup all codegen memory
-/// when calling `deinit`
-decls: std.AutoHashMapUnmanaged(Module.Decl.Index, void) = .{},
+/// Each index maps to the corresponding `Atom.Index`.
+decls: std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index) = .{},
 /// List of all symbols generated by Zig code.
 symbols: std.ArrayListUnmanaged(Symbol) = .{},
 /// List of symbol indexes which are free to be used.
 symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
 /// Maps atoms to their segment index
-atoms: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
-/// Atoms managed and created by the linker. This contains atoms
-/// from object files, and not Atoms generated by a Decl.
-managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
+atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
+/// List of all atoms.
+managed_atoms: std.ArrayListUnmanaged(Atom) = .{},
 /// Represents the index into `segments` where the 'code' section
 /// lives.
 code_section_index: ?u32 = null,
@@ -148,7 +143,7 @@ undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{},
 /// Maps a symbol's location to an atom. This can be used to find meta
 /// data of a symbol, such as its size, or its offset to perform a relocation.
 /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
-symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{},
+symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{},
 /// Maps a symbol's location to its export name, which may differ from the decl's name
 /// which does the exporting.
 /// Note: The value represents the offset into the string table, rather than the actual string.
@@ -165,14 +160,14 @@ error_table_symbol: ?u32 = null,
 // unit contains Zig code. The lifetime of these atoms are extended
 // until the end of the compiler's lifetime. Meaning they're not freed
 // during `flush()` in incremental-mode.
-debug_info_atom: ?*Atom = null,
-debug_line_atom: ?*Atom = null,
-debug_loc_atom: ?*Atom = null,
-debug_ranges_atom: ?*Atom = null,
-debug_abbrev_atom: ?*Atom = null,
-debug_str_atom: ?*Atom = null,
-debug_pubnames_atom: ?*Atom = null,
-debug_pubtypes_atom: ?*Atom = null,
+debug_info_atom: ?Atom.Index = null,
+debug_line_atom: ?Atom.Index = null,
+debug_loc_atom: ?Atom.Index = null,
+debug_ranges_atom: ?Atom.Index = null,
+debug_abbrev_atom: ?Atom.Index = null,
+debug_str_atom: ?Atom.Index = null,
+debug_pubnames_atom: ?Atom.Index = null,
+debug_pubtypes_atom: ?Atom.Index = null,
 
 pub const Segment = struct {
     alignment: u32,
@@ -430,10 +425,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
         // at the end during `initializeCallCtorsFunction`.
     }
 
-    if (!options.strip and options.module != null) {
-        wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
-        try wasm_bin.initDebugSections();
-    }
+    // if (!options.strip and options.module != null) {
+    //     wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
+    //     try wasm_bin.initDebugSections();
+    // }
 
     return wasm_bin;
 }
@@ -474,6 +469,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol
     try wasm.globals.put(wasm.base.allocator, name_offset, loc);
     return loc;
 }
+
 /// Initializes symbols and atoms for the debug sections
 /// Initialization is only done when compiling Zig code.
 /// When Zig is invoked as a linker instead, the atoms
@@ -516,6 +512,36 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
     return true;
 }
 
+/// For a given `Module.Decl.Index` returns its corresponding `Atom.Index`.
+/// When the index was not found, a new `Atom` will be created, and its index will be returned.
+/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
+pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: Module.Decl.Index) !Atom.Index {
+    const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
+    if (!gop.found_existing) {
+        gop.value_ptr.* = try wasm.createAtom();
+    }
+    return gop.value_ptr.*;
+}
+
+/// Creates a new empty `Atom` and returns its `Atom.Index`
+fn createAtom(wasm: *Wasm) !Atom.Index {
+    const index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
+    const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
+    atom.* = Atom.empty;
+    atom.sym_index = try wasm.allocateSymbol();
+    try wasm.symbol_atom.putNoClobber(wasm.base.allocator, .{ .file = null, .index = atom.sym_index }, index);
+
+    return index;
+}
+
+pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {
+    return wasm.managed_atoms.items[index];
+}
+
+pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
+    return &wasm.managed_atoms.items[index];
+}
+
 /// Parses an archive file and will then parse each object file
 /// that was found in the archive file.
 /// Returns false when the file is not an archive file.
@@ -857,15 +883,16 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
         try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
         _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.
 
-        const atom = try wasm.base.allocator.create(Atom);
-        errdefer wasm.base.allocator.destroy(atom);
-        try wasm.managed_atoms.append(wasm.base.allocator, atom);
+        // TODO: Can we use `createAtom` here while also re-using the symbol
+        // from `createSyntheticSymbol`.
+        const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
+        const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
         atom.* = Atom.empty;
         atom.sym_index = loc.index;
         atom.alignment = 1;
 
-        try wasm.parseAtom(atom, .{ .data = .synthetic });
-        try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
+        try wasm.parseAtom(atom_index, .{ .data = .synthetic });
+        try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
     }
 
     if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {
@@ -873,15 +900,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
         try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
         _ = wasm.resolved_symbols.swapRemove(loc);
 
-        const atom = try wasm.base.allocator.create(Atom);
-        errdefer wasm.base.allocator.destroy(atom);
-        try wasm.managed_atoms.append(wasm.base.allocator, atom);
+        const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
+        const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
         atom.* = Atom.empty;
         atom.sym_index = loc.index;
         atom.alignment = 1;
 
-        try wasm.parseAtom(atom, .{ .data = .synthetic });
-        try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
+        try wasm.parseAtom(atom_index, .{ .data = .synthetic });
+        try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
     }
 }
 
@@ -920,16 +946,6 @@ pub fn deinit(wasm: *Wasm) void {
         if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
     }
 
-    if (wasm.base.options.module) |mod| {
-        var decl_it = wasm.decls.keyIterator();
-        while (decl_it.next()) |decl_index_ptr| {
-            const decl = mod.declPtr(decl_index_ptr.*);
-            decl.link.wasm.deinit(gpa);
-        }
-    } else {
-        assert(wasm.decls.count() == 0);
-    }
-
     for (wasm.func_types.items) |*func_type| {
         func_type.deinit(gpa);
     }
@@ -954,9 +970,8 @@ pub fn deinit(wasm: *Wasm) void {
     wasm.symbol_atom.deinit(gpa);
     wasm.export_names.deinit(gpa);
     wasm.atoms.deinit(gpa);
-    for (wasm.managed_atoms.items) |managed_atom| {
-        managed_atom.deinit(gpa);
-        gpa.destroy(managed_atom);
+    for (wasm.managed_atoms.items) |*managed_atom| {
+        managed_atom.deinit(wasm);
     }
     wasm.managed_atoms.deinit(gpa);
     wasm.segments.deinit(gpa);
@@ -1014,18 +1029,24 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
 
     const decl_index = func.owner_decl;
     const decl = mod.declPtr(decl_index);
-    const atom = &decl.link.wasm;
-    try atom.ensureInitialized(wasm);
-    const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
-    if (gop.found_existing) {
-        atom.clear();
-    } else gop.value_ptr.* = {};
+    const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
+    const atom = wasm.getAtomPtr(atom_index);
+    atom.clear();
 
-    var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
-    defer if (decl_state) |*ds| ds.deinit();
+    // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
+    // defer if (decl_state) |*ds| ds.deinit();
 
     var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
     defer code_writer.deinit();
+    // const result = try codegen.generateFunction(
+    //     &wasm.base,
+    //     decl.srcLoc(),
+    //     func,
+    //     air,
+    //     liveness,
+    //     &code_writer,
+    //     if (decl_state) |*ds| .{ .dwarf = ds } else .none,
+    // );
     const result = try codegen.generateFunction(
         &wasm.base,
         decl.srcLoc(),
@@ -1033,7 +1054,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
         air,
         liveness,
         &code_writer,
-        if (decl_state) |*ds| .{ .dwarf = ds } else .none,
+        .none,
     );
 
     const code = switch (result) {
@@ -1045,19 +1066,19 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
         },
     };
 
-    if (wasm.dwarf) |*dwarf| {
-        try dwarf.commitDeclState(
-            mod,
-            decl_index,
-            // Actual value will be written after relocation.
-            // For Wasm, this is the offset relative to the code section
-            // which isn't known until flush().
-            0,
-            code.len,
-            &decl_state.?,
-        );
-    }
-    return wasm.finishUpdateDecl(decl, code);
+    // if (wasm.dwarf) |*dwarf| {
+    //     try dwarf.commitDeclState(
+    //         mod,
+    //         decl_index,
+    //         // Actual value will be written after relocation.
+    //         // For Wasm, this is the offset relative to the code section
+    //         // which isn't known until flush().
+    //         0,
+    //         code.len,
+    //         &decl_state.?,
+    //     );
+    // }
+    return wasm.finishUpdateDecl(decl_index, code);
 }
 
 // Generate code for the Decl, storing it in memory to be later written to
@@ -1080,17 +1101,14 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
         return;
     }
 
-    const atom = &decl.link.wasm;
-    try atom.ensureInitialized(wasm);
-    const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
-    if (gop.found_existing) {
-        atom.clear();
-    } else gop.value_ptr.* = {};
+    const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
+    const atom = wasm.getAtomPtr(atom_index);
+    atom.clear();
 
     if (decl.isExtern()) {
         const variable = decl.getVariable().?;
         const name = mem.sliceTo(decl.name, 0);
-        return wasm.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);
+        return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null);
     }
     const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
 
@@ -1103,7 +1121,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
         .{ .ty = decl.ty, .val = val },
         &code_writer,
         .none,
-        .{ .parent_atom_index = decl.link.wasm.sym_index },
+        .{ .parent_atom_index = atom.sym_index },
     );
 
     const code = switch (res) {
@@ -1115,7 +1133,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
         },
     };
 
-    return wasm.finishUpdateDecl(decl, code);
+    return wasm.finishUpdateDecl(decl_index, code);
 }
 
 pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void {
@@ -1133,9 +1151,11 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I
     }
 }
 
-fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void {
+fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8) !void {
     const mod = wasm.base.options.module.?;
-    const atom: *Atom = &decl.link.wasm;
+    const decl = mod.declPtr(decl_index);
+    const atom_index = wasm.decls.get(decl_index).?;
+    const atom = wasm.getAtomPtr(atom_index);
     const symbol = &wasm.symbols.items[atom.sym_index];
     const full_name = try decl.getFullyQualifiedName(mod);
     defer wasm.base.allocator.free(full_name);
@@ -1201,48 +1221,51 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
     const decl = mod.declPtr(decl_index);
 
     // Create and initialize a new local symbol and atom
-    const local_index = decl.link.wasm.locals.items.len;
+    const atom_index = try wasm.createAtom();
+    const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
+    const parent_atom = wasm.getAtomPtr(parent_atom_index);
+    const local_index = parent_atom.locals.items.len;
+    try parent_atom.locals.append(wasm.base.allocator, atom_index);
     const fqdn = try decl.getFullyQualifiedName(mod);
     defer wasm.base.allocator.free(fqdn);
     const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });
     defer wasm.base.allocator.free(name);
-
-    const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator);
-    atom.* = Atom.empty;
-    try atom.ensureInitialized(wasm);
-    atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
-    wasm.symbols.items[atom.sym_index] = .{
-        .name = try wasm.string_table.put(wasm.base.allocator, name),
-        .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
-        .tag = .data,
-        .index = undefined,
-    };
-
-    try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
-
     var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
     defer value_bytes.deinit();
 
-    const result = try codegen.generateSymbol(
-        &wasm.base,
-        decl.srcLoc(),
-        tv,
-        &value_bytes,
-        .none,
-        .{
-            .parent_atom_index = atom.sym_index,
-            .addend = null,
-        },
-    );
-    const code = switch (result) {
-        .ok => value_bytes.items,
-        .fail => |em| {
-            decl.analysis = .codegen_failure;
-            try mod.failed_decls.put(mod.gpa, decl_index, em);
-            return error.AnalysisFail;
-        },
+    const code = code: {
+        const atom = wasm.getAtomPtr(atom_index);
+        atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
+        wasm.symbols.items[atom.sym_index] = .{
+            .name = try wasm.string_table.put(wasm.base.allocator, name),
+            .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
+            .tag = .data,
+            .index = undefined,
+        };
+        try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
+
+        const result = try codegen.generateSymbol(
+            &wasm.base,
+            decl.srcLoc(),
+            tv,
+            &value_bytes,
+            .none,
+            .{
+                .parent_atom_index = atom.sym_index,
+                .addend = null,
+            },
+        );
+        break :code switch (result) {
+            .ok => value_bytes.items,
+            .fail => |em| {
+                decl.analysis = .codegen_failure;
+                try mod.failed_decls.put(mod.gpa, decl_index, em);
+                return error.AnalysisFail;
+            },
+        };
     };
 
+    const atom = wasm.getAtomPtr(atom_index);
     atom.size = @intCast(u32, code.len);
     try atom.code.appendSlice(wasm.base.allocator, code);
     return atom.sym_index;
@@ -1290,10 +1313,13 @@ pub fn getDeclVAddr(
 ) !u64 {
     const mod = wasm.base.options.module.?;
     const decl = mod.declPtr(decl_index);
-    try decl.link.wasm.ensureInitialized(wasm);
-    const target_symbol_index = decl.link.wasm.sym_index;
+
+    const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
+    const target_symbol_index = wasm.getAtom(target_atom_index).sym_index;
+
     assert(reloc_info.parent_atom_index != 0);
-    const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
+    const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
+    const atom = wasm.getAtomPtr(atom_index);
     const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
     if (decl.ty.zigTypeTag() == .Fn) {
         assert(reloc_info.addend == 0); // addend not allowed for function relocations
@@ -1321,9 +1347,10 @@ pub fn getDeclVAddr(
     return target_symbol_index;
 }
 
-pub fn deleteExport(wasm: *Wasm, exp: Export) void {
+pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
     if (wasm.llvm_object) |_| return;
-    const sym_index = exp.sym_index orelse return;
+    const atom_index = wasm.decls.get(decl_index) orelse return;
+    const sym_index = wasm.getAtom(atom_index).sym_index;
     const loc: SymbolLoc = .{ .file = null, .index = sym_index };
     const symbol = loc.getSymbol(wasm);
     const symbol_name = wasm.string_table.get(symbol.name);
@@ -1349,7 +1376,8 @@ pub fn updateDeclExports(
     }
 
     const decl = mod.declPtr(decl_index);
-    if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized
+    const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
+    const atom = wasm.getAtom(atom_index);
 
     for (exports) |exp| {
         if (exp.options.section) |section| {
@@ -1364,7 +1392,7 @@ pub fn updateDeclExports(
 
         const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name);
         if (wasm.globals.getPtr(export_name)) |existing_loc| {
-            if (existing_loc.index == decl.link.wasm.sym_index) continue;
+            if (existing_loc.index == atom.sym_index) continue;
             const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
 
             const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;
@@ -1385,15 +1413,16 @@ pub fn updateDeclExports(
             } else if (exp_is_weak) {
                 continue; // to-be-exported symbol is weak, so we keep the existing symbol
             } else {
-                existing_loc.index = decl.link.wasm.sym_index;
+                // TODO: Revisit this, why was this needed?
+                existing_loc.index = atom.sym_index;
                 existing_loc.file = null;
-                exp.link.wasm.sym_index = existing_loc.index;
+                // exp.link.wasm.sym_index = existing_loc.index;
             }
         }
 
-        const exported_decl = mod.declPtr(exp.exported_decl);
-        const sym_index = exported_decl.link.wasm.sym_index;
-        const sym_loc = exported_decl.link.wasm.symbolLoc();
+        const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl);
+        const exported_atom = wasm.getAtom(exported_atom_index);
+        const sym_loc = exported_atom.symbolLoc();
         const symbol = sym_loc.getSymbol(wasm);
         switch (exp.options.linkage) {
             .Internal => {
@@ -1429,7 +1458,6 @@ pub fn updateDeclExports(
         // if the symbol was previously undefined, remove it as an import
         _ = wasm.imports.remove(sym_loc);
         _ = wasm.undefs.swapRemove(exp.options.name);
-        exp.link.wasm.sym_index = sym_index;
     }
 }
 
@@ -1439,11 +1467,13 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
     }
     const mod = wasm.base.options.module.?;
     const decl = mod.declPtr(decl_index);
-    const atom = &decl.link.wasm;
+    const atom_index = wasm.decls.get(decl_index).?;
+    const atom = wasm.getAtomPtr(atom_index);
     wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};
     _ = wasm.decls.remove(decl_index);
     wasm.symbols.items[atom.sym_index].tag = .dead;
-    for (atom.locals.items) |local_atom| {
+    for (atom.locals.items) |local_atom_index| {
+        const local_atom = wasm.getAtom(local_atom_index);
         const local_symbol = &wasm.symbols.items[local_atom.sym_index];
         local_symbol.tag = .dead; // also for any local symbol
         wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {};
@@ -1461,7 +1491,16 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
     //     dwarf.freeDecl(decl_index);
     // }
 
-    atom.deinit(wasm.base.allocator);
+    if (atom.next) |next_atom_index| {
+        const next_atom = wasm.getAtomPtr(next_atom_index);
+        next_atom.prev = atom.prev;
+        atom.next = null;
+    }
+    if (atom.prev) |prev_index| {
+        const prev_atom = wasm.getAtomPtr(prev_index);
+        prev_atom.next = atom.next;
+        atom.prev = null;
+    }
 }
 
 /// Appends a new entry to the indirect function table
@@ -1583,7 +1622,8 @@ const Kind = union(enum) {
 };
 
 /// Parses an Atom and inserts its metadata into the corresponding sections.
-fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
+fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
+    const atom = wasm.getAtomPtr(atom_index);
     const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
     const final_index: u32 = switch (kind) {
         .function => |fn_data| result: {
@@ -1658,18 +1698,20 @@ fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
     const segment: *Segment = &wasm.segments.items[final_index];
     segment.alignment = std.math.max(segment.alignment, atom.alignment);
 
-    try wasm.appendAtomAtIndex(final_index, atom);
+    try wasm.appendAtomAtIndex(final_index, atom_index);
 }
 
 /// From a given index, append the given `Atom` at the back of the linked list.
 /// Simply inserts it into the map of atoms when it doesn't exist yet.
-pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom: *Atom) !void {
-    if (wasm.atoms.getPtr(index)) |last| {
-        last.*.next = atom;
-        atom.prev = last.*;
-        last.* = atom;
+pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
+    const atom = wasm.getAtomPtr(atom_index);
+    if (wasm.atoms.getPtr(index)) |last_index_ptr| {
+        const last = wasm.getAtomPtr(last_index_ptr.*);
+        last.*.next = atom_index;
+        atom.prev = last_index_ptr.*;
+        last_index_ptr.* = atom_index;
     } else {
-        try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom);
+        try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index);
     }
 }
 
@@ -1679,16 +1721,17 @@ fn allocateDebugAtoms(wasm: *Wasm) !void {
     if (wasm.dwarf == null) return;
 
     const allocAtom = struct {
-        fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void {
+        fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void {
             const index = maybe_index.* orelse idx: {
                 const index = @intCast(u32, bin.segments.items.len);
                 try bin.appendDummySegment();
                 maybe_index.* = index;
                 break :idx index;
             };
+            const atom = bin.getAtomPtr(atom_index);
             atom.size = @intCast(u32, atom.code.items.len);
             bin.symbols.items[atom.sym_index].index = index;
-            try bin.appendAtomAtIndex(index, atom);
+            try bin.appendAtomAtIndex(index, atom_index);
         }
     }.f;
 
@@ -1710,15 +1753,16 @@ fn allocateAtoms(wasm: *Wasm) !void {
     var it = wasm.atoms.iterator();
     while (it.next()) |entry| {
         const segment = &wasm.segments.items[entry.key_ptr.*];
-        var atom: *Atom = entry.value_ptr.*.getFirst();
+        var atom_index = entry.value_ptr.*;
         var offset: u32 = 0;
         while (true) {
+            const atom = wasm.getAtomPtr(atom_index);
             const symbol_loc = atom.symbolLoc();
             if (wasm.code_section_index) |index| {
                 if (index == entry.key_ptr.*) {
                     if (!wasm.resolved_symbols.contains(symbol_loc)) {
                         // only allocate resolved function body's.
-                        atom = atom.next orelse break;
+                        atom_index = atom.prev orelse break;
                         continue;
                     }
                 }
@@ -1732,8 +1776,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
                 atom.size,
             });
             offset += atom.size;
-            try wasm.symbol_atom.put(wasm.base.allocator, symbol_loc, atom); // Update atom pointers
-            atom = atom.next orelse break;
+            atom_index = atom.prev orelse break;
         }
         segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
     }
@@ -1867,8 +1910,8 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
     symbol.index = func_index;
 
     // create the atom that will be output into the final binary
-    const atom = try wasm.base.allocator.create(Atom);
-    errdefer wasm.base.allocator.destroy(atom);
+    const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
+    const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
     atom.* = .{
         .size = @intCast(u32, function_body.items.len),
         .offset = 0,
@@ -1879,13 +1922,13 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
         .prev = null,
         .code = function_body.moveToUnmanaged(),
     };
-    try wasm.managed_atoms.append(wasm.base.allocator, atom);
-    try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom);
-    try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
+    try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
+    try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
 
     // `allocateAtoms` has already been called, set the atom's offset manually.
     // This is fine to do manually as we insert the atom at the very end.
-    atom.offset = atom.prev.?.offset + atom.prev.?.size;
+    const prev_atom = wasm.getAtom(atom.prev.?);
+    atom.offset = prev_atom.offset + prev_atom.size;
 }
 
 fn setupImports(wasm: *Wasm) !void {
@@ -2088,7 +2131,8 @@ fn setupExports(wasm: *Wasm) !void {
             break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
         };
         const exp: types.Export = if (symbol.tag == .data) exp: {
-            const atom = wasm.symbol_atom.get(sym_loc).?;
+            const atom_index = wasm.symbol_atom.get(sym_loc).?;
+            const atom = wasm.getAtom(atom_index);
             const va = atom.getVA(wasm, symbol);
             const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);
             try wasm.wasm_globals.append(wasm.base.allocator, .{
@@ -2193,7 +2237,8 @@ fn setupMemory(wasm: *Wasm) !void {
         const segment_index = wasm.data_segments.get(".synthetic").?;
         const segment = &wasm.segments.items[segment_index];
         segment.offset = 0; // for simplicity we store the entire VA into atom's offset.
-        const atom = wasm.symbol_atom.get(loc).?;
+        const atom_index = wasm.symbol_atom.get(loc).?;
+        const atom = wasm.getAtomPtr(atom_index);
         atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment));
     }
 
@@ -2226,7 +2271,8 @@ fn setupMemory(wasm: *Wasm) !void {
         const segment_index = wasm.data_segments.get(".synthetic").?;
         const segment = &wasm.segments.items[segment_index];
         segment.offset = 0;
-        const atom = wasm.symbol_atom.get(loc).?;
+        const atom_index = wasm.symbol_atom.get(loc).?;
+        const atom = wasm.getAtomPtr(atom_index);
         atom.offset = @intCast(u32, memory_ptr);
     }
 
@@ -2352,15 +2398,14 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
     // and then return said symbol's index. The final table will be populated
     // during `flush` when we know all possible error names.
 
-    // As sym_index '0' is reserved, we use it for our stack pointer symbol
-    const symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
-        const index = @intCast(u32, wasm.symbols.items.len);
-        _ = try wasm.symbols.addOne(wasm.base.allocator);
-        break :blk index;
-    };
+    const atom_index = try wasm.createAtom();
+    const atom = wasm.getAtomPtr(atom_index);
+    const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
+    atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
+    const sym_index = atom.sym_index;
 
     const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table");
-    const symbol = &wasm.symbols.items[symbol_index];
+    const symbol = &wasm.symbols.items[sym_index];
     symbol.* = .{
         .name = sym_name,
         .tag = .data,
@@ -2369,20 +2414,11 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
     };
     symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
 
-    const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
+    try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
 
-    const atom = try wasm.base.allocator.create(Atom);
-    atom.* = Atom.empty;
-    atom.sym_index = symbol_index;
-    atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
-    try wasm.managed_atoms.append(wasm.base.allocator, atom);
-    const loc = atom.symbolLoc();
-    try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});
-    try wasm.symbol_atom.put(wasm.base.allocator, loc, atom);
-
-    log.debug("Error name table was created with symbol index: ({d})", .{symbol_index});
-    wasm.error_table_symbol = symbol_index;
-    return symbol_index;
+    log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
+    wasm.error_table_symbol = sym_index;
+    return sym_index;
 }
 
 /// Populates the error name table, when `error_table_symbol` is not null.
@@ -2391,22 +2427,17 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
 /// The table is what is being pointed to within the runtime bodies that are generated.
 fn populateErrorNameTable(wasm: *Wasm) !void {
     const symbol_index = wasm.error_table_symbol orelse return;
-    const atom: *Atom = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
+    const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
+    const atom = wasm.getAtomPtr(atom_index);
+
     // Rather than creating a symbol for each individual error name,
     // we create a symbol for the entire region of error names. We then calculate
     // the pointers into the list using addends which are appended to the relocation.
-    const names_atom = try wasm.base.allocator.create(Atom);
-    names_atom.* = Atom.empty;
-    try wasm.managed_atoms.append(wasm.base.allocator, names_atom);
-    const names_symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
-        const index = @intCast(u32, wasm.symbols.items.len);
-        _ = try wasm.symbols.addOne(wasm.base.allocator);
-        break :blk index;
-    };
-    names_atom.sym_index = names_symbol_index;
+    const names_atom_index = try wasm.createAtom();
+    const names_atom = wasm.getAtomPtr(names_atom_index);
     names_atom.alignment = 1;
     const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
-    const names_symbol = &wasm.symbols.items[names_symbol_index];
+    const names_symbol = &wasm.symbols.items[names_atom.sym_index];
     names_symbol.* = .{
         .name = sym_name,
         .tag = .data,
@@ -2430,7 +2461,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
         try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1);
         // create relocation to the error name
         try atom.relocs.append(wasm.base.allocator, .{
-            .index = names_symbol_index,
+            .index = names_atom.sym_index,
             .relocation_type = .R_WASM_MEMORY_ADDR_I32,
             .offset = offset,
             .addend = @intCast(i32, addend),
@@ -2449,61 +2480,53 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
 
     const name_loc = names_atom.symbolLoc();
     try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});
-    try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom);
+    try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index);
 
     // link the atoms with the rest of the binary so they can be allocated
     // and relocations will be performed.
-    try wasm.parseAtom(atom, .{ .data = .read_only });
-    try wasm.parseAtom(names_atom, .{ .data = .read_only });
+    try wasm.parseAtom(atom_index, .{ .data = .read_only });
+    try wasm.parseAtom(names_atom_index, .{ .data = .read_only });
 }
 
 /// From a given index variable, creates a new debug section.
 /// This initializes the index, appends a new segment,
 /// and finally, creates a managed `Atom`.
-pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !*Atom {
+pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
     const new_index = @intCast(u32, wasm.segments.items.len);
     index.* = new_index;
     try wasm.appendDummySegment();
 
-    const sym_index = wasm.symbols_free_list.popOrNull() orelse idx: {
-        const tmp_index = @intCast(u32, wasm.symbols.items.len);
-        _ = try wasm.symbols.addOne(wasm.base.allocator);
-        break :idx tmp_index;
-    };
-    wasm.symbols.items[sym_index] = .{
+    const atom_index = try wasm.createAtom();
+    const atom = wasm.getAtomPtr(atom_index);
+    wasm.symbols.items[atom.sym_index] = .{
         .tag = .section,
         .name = try wasm.string_table.put(wasm.base.allocator, name),
         .index = 0,
         .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
     };
 
-    const atom = try wasm.base.allocator.create(Atom);
-    atom.* = Atom.empty;
     atom.alignment = 1; // debug sections are always 1-byte-aligned
-    atom.sym_index = sym_index;
-    try wasm.managed_atoms.append(wasm.base.allocator, atom);
-    try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom);
-    return atom;
+    return atom_index;
 }
 
 fn resetState(wasm: *Wasm) void {
     for (wasm.segment_info.values()) |segment_info| {
         wasm.base.allocator.free(segment_info.name);
     }
-    if (wasm.base.options.module) |mod| {
-        var decl_it = wasm.decls.keyIterator();
-        while (decl_it.next()) |decl_index_ptr| {
-            const decl = mod.declPtr(decl_index_ptr.*);
-            const atom = &decl.link.wasm;
-            atom.next = null;
-            atom.prev = null;
-
-            for (atom.locals.items) |*local_atom| {
-                local_atom.next = null;
-                local_atom.prev = null;
-            }
+
+    var atom_it = wasm.decls.valueIterator();
+    while (atom_it.next()) |atom_index| {
+        const atom = wasm.getAtomPtr(atom_index.*);
+        atom.next = null;
+        atom.prev = null;
+
+        for (atom.locals.items) |local_atom_index| {
+            const local_atom = wasm.getAtomPtr(local_atom_index);
+            local_atom.next = null;
+            local_atom.prev = null;
         }
     }
+
     wasm.functions.clearRetainingCapacity();
     wasm.exports.clearRetainingCapacity();
     wasm.segments.clearRetainingCapacity();
@@ -2800,28 +2823,29 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
     try wasm.setupStart();
     try wasm.setupImports();
     if (wasm.base.options.module) |mod| {
-        var decl_it = wasm.decls.keyIterator();
-        while (decl_it.next()) |decl_index_ptr| {
-            const decl = mod.declPtr(decl_index_ptr.*);
+        var decl_it = wasm.decls.iterator();
+        while (decl_it.next()) |entry| {
+            const decl = mod.declPtr(entry.key_ptr.*);
             if (decl.isExtern()) continue;
-            const atom = &decl.*.link.wasm;
+            const atom_index = entry.value_ptr.*;
             if (decl.ty.zigTypeTag() == .Fn) {
-                try wasm.parseAtom(atom, .{ .function = decl.fn_link.wasm });
+                try wasm.parseAtom(atom_index, .{ .function = decl.fn_link.wasm });
             } else if (decl.getVariable()) |variable| {
                 if (!variable.is_mutable) {
-                    try wasm.parseAtom(atom, .{ .data = .read_only });
+                    try wasm.parseAtom(atom_index, .{ .data = .read_only });
                 } else if (variable.init.isUndefDeep()) {
-                    try wasm.parseAtom(atom, .{ .data = .uninitialized });
+                    try wasm.parseAtom(atom_index, .{ .data = .uninitialized });
                 } else {
-                    try wasm.parseAtom(atom, .{ .data = .initialized });
+                    try wasm.parseAtom(atom_index, .{ .data = .initialized });
                 }
             } else {
-                try wasm.parseAtom(atom, .{ .data = .read_only });
+                try wasm.parseAtom(atom_index, .{ .data = .read_only });
             }
 
             // also parse atoms for a decl's locals
-            for (atom.locals.items) |*local_atom| {
-                try wasm.parseAtom(local_atom, .{ .data = .read_only });
+            const atom = wasm.getAtomPtr(atom_index);
+            for (atom.locals.items) |local_atom_index| {
+                try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
             }
         }
 
@@ -3066,20 +3090,22 @@ fn writeToFile(
     var code_section_size: u32 = 0;
     if (wasm.code_section_index) |code_index| {
         const header_offset = try reserveVecSectionHeader(&binary_bytes);
-        var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
+        var atom_index = wasm.atoms.get(code_index).?;
 
         // The code section must be sorted in line with the function order.
         var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
         defer sorted_atoms.deinit();
 
         while (true) {
+            var atom = wasm.getAtomPtr(atom_index);
             if (wasm.resolved_symbols.contains(atom.symbolLoc())) {
                 if (!is_obj) {
                     atom.resolveRelocs(wasm);
                 }
                 sorted_atoms.appendAssumeCapacity(atom);
             }
-            atom = atom.next orelse break;
+            // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
+            atom_index = atom.prev orelse break;
         }
 
         const atom_sort_fn = struct {
@@ -3119,11 +3145,11 @@ fn writeToFile(
             // do not output 'bss' section unless we import memory and therefore
             // want to guarantee the data is zero initialized
             if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
-            const atom_index = entry.value_ptr.*;
-            const segment = wasm.segments.items[atom_index];
+            const segment_index = entry.value_ptr.*;
+            const segment = wasm.segments.items[segment_index];
             if (segment.size == 0) continue; // do not emit empty segments
             segment_count += 1;
-            var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst();
+            var atom_index = wasm.atoms.get(segment_index).?;
 
             // flag and index to memory section (currently, there can only be 1 memory section in wasm)
             try leb.writeULEB128(binary_writer, @as(u32, 0));
@@ -3134,6 +3160,7 @@ fn writeToFile(
             // fill in the offset table and the data segments
             var current_offset: u32 = 0;
             while (true) {
+                const atom = wasm.getAtomPtr(atom_index);
                 if (!is_obj) {
                     atom.resolveRelocs(wasm);
                 }
@@ -3149,8 +3176,8 @@ fn writeToFile(
                 try binary_writer.writeAll(atom.code.items);
 
                 current_offset += atom.size;
-                if (atom.next) |next| {
-                    atom = next;
+                if (atom.prev) |prev| {
+                    atom_index = prev;
                 } else {
                     // also pad with zeroes when last atom to ensure
                     // segments are aligned.
@@ -3192,15 +3219,15 @@ fn writeToFile(
     }
 
     if (!wasm.base.options.strip) {
-        if (wasm.dwarf) |*dwarf| {
-            const mod = wasm.base.options.module.?;
-            try dwarf.writeDbgAbbrev();
-            // for debug info and ranges, the address is always 0,
-            // as locations are always offsets relative to 'code' section.
-            try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
-            try dwarf.writeDbgAranges(0, code_section_size);
-            try dwarf.writeDbgLineHeader();
-        }
+        // if (wasm.dwarf) |*dwarf| {
+        //     const mod = wasm.base.options.module.?;
+        //     try dwarf.writeDbgAbbrev();
+        //     // for debug info and ranges, the address is always 0,
+        //     // as locations are always offsets relative to 'code' section.
+        //     try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
+        //     try dwarf.writeDbgAranges(0, code_section_size);
+        //     try dwarf.writeDbgLineHeader();
+        // }
 
         var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);
         defer debug_bytes.deinit();
@@ -3223,11 +3250,11 @@ fn writeToFile(
 
         for (debug_sections) |item| {
             if (item.index) |index| {
-                var atom = wasm.atoms.get(index).?.getFirst();
+                var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
                 while (true) {
                     atom.resolveRelocs(wasm);
                     try debug_bytes.appendSlice(atom.code.items);
-                    atom = atom.next orelse break;
+                    atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
                 }
                 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
                 debug_bytes.clearRetainingCapacity();
@@ -3959,7 +3986,8 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
 
                 if (symbol.isDefined()) {
                     try leb.writeULEB128(writer, symbol.index);
-                    const atom = wasm.symbol_atom.get(sym_loc).?;
+                    const atom_index = wasm.symbol_atom.get(sym_loc).?;
+                    const atom = wasm.getAtom(atom_index);
                     try leb.writeULEB128(writer, @as(u32, atom.offset));
                     try leb.writeULEB128(writer, @as(u32, atom.size));
                 }
@@ -4037,7 +4065,7 @@ fn emitCodeRelocations(
     const reloc_start = binary_bytes.items.len;
 
     var count: u32 = 0;
-    var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
+    var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(code_index).?);
     // for each atom, we calculate the uleb size and append that
     var size_offset: u32 = 5; // account for code section size leb128
     while (true) {
@@ -4055,7 +4083,7 @@ fn emitCodeRelocations(
             }
             log.debug("Emit relocation: {}", .{relocation});
         }
-        atom = atom.next orelse break;
+        atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
     }
     if (count == 0) return;
     var buf: [5]u8 = undefined;
@@ -4086,7 +4114,7 @@ fn emitDataRelocations(
     // for each atom, we calculate the uleb size and append that
     var size_offset: u32 = 5; // account for code section size leb128
     for (wasm.data_segments.values()) |segment_index| {
-        var atom: *Atom = wasm.atoms.get(segment_index).?.getFirst();
+        var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(segment_index).?);
         while (true) {
             size_offset += getULEB128Size(atom.size);
             for (atom.relocs.items) |relocation| {
@@ -4105,7 +4133,7 @@ fn emitDataRelocations(
                 }
                 log.debug("Emit relocation: {}", .{relocation});
             }
-            atom = atom.next orelse break;
+            atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
         }
     }
     if (count == 0) return;
src/link.zig
@@ -267,7 +267,7 @@ pub const File = struct {
         macho: void,
         plan9: void,
         c: void,
-        wasm: Wasm.DeclBlock,
+        wasm: void,
         spirv: void,
         nvptx: void,
     };
@@ -289,7 +289,7 @@ pub const File = struct {
         macho: void,
         plan9: void,
         c: void,
-        wasm: Wasm.Export,
+        wasm: void,
         spirv: void,
         nvptx: void,
     };
src/Module.zig
@@ -5266,7 +5266,7 @@ pub fn clearDecl(
                 .macho => .{ .macho = {} },
                 .plan9 => .{ .plan9 = {} },
                 .c => .{ .c = {} },
-                .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
+                .wasm => .{ .wasm = {} },
                 .spirv => .{ .spirv = {} },
                 .nvptx => .{ .nvptx = {} },
             };
@@ -5374,7 +5374,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
             try macho.deleteDeclExport(decl_index, exp.options.name);
         }
         if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
-            wasm.deleteExport(exp.link.wasm);
+            wasm.deleteDeclExport(decl_index);
         }
         if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
             coff.deleteDeclExport(decl_index, exp.options.name);
@@ -5686,7 +5686,7 @@ pub fn allocateNewDecl(
             .macho => .{ .macho = {} },
             .plan9 => .{ .plan9 = {} },
             .c => .{ .c = {} },
-            .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
+            .wasm => .{ .wasm = {} },
             .spirv => .{ .spirv = {} },
             .nvptx => .{ .nvptx = {} },
         },
src/Sema.zig
@@ -5570,7 +5570,7 @@ pub fn analyzeExport(
             .macho => .{ .macho = {} },
             .plan9 => .{ .plan9 = {} },
             .c => .{ .c = {} },
-            .wasm => .{ .wasm = .{} },
+            .wasm => .{ .wasm = {} },
             .spirv => .{ .spirv = {} },
             .nvptx => .{ .nvptx = {} },
         },
test/link/wasm/export-data/build.zig
@@ -23,8 +23,8 @@ pub fn build(b: *Builder) void {
     check_lib.checkNext("type i32");
     check_lib.checkNext("mutable false");
     check_lib.checkNext("i32.const {bar_address}");
-    check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 0 } });
-    check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 4 } });
+    check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 4 } });
+    check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 0 } });
 
     check_lib.checkStart("Section export");
     check_lib.checkNext("entries 3");