diff options
| author | Luuk de Gram <luuk@degram.dev> | 2023-02-01 18:55:35 +0100 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2023-02-01 19:10:56 +0100 |
| commit | 46f54b23ae604c3f99f51ca719d9085530f6b59c (patch) | |
| tree | 66547a2f4b33e876afb0b29ea6799795959699fb /src/link | |
| parent | 1aa0f8aa2f382fb56639ea6833a62c4b8b031247 (diff) | |
| download | zig-46f54b23ae604c3f99f51ca719d9085530f6b59c.tar.gz zig-46f54b23ae604c3f99f51ca719d9085530f6b59c.zip | |
link: make Wasm atoms fully owned by the linker
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Dwarf.zig | 25 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 522 | ||||
| -rw-r--r-- | src/link/Wasm/Atom.zig | 44 | ||||
| -rw-r--r-- | src/link/Wasm/Object.zig | 15 |
4 files changed, 313 insertions, 293 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e90db2d0df..a3d0aa8a53 100644 --- a/src/link/Dwarf.zig +++ b/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, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ee4518796e..b06703ed61 100644 --- a/src/link/Wasm.zig +++ b/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; diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index 554f98b5ca..e719f8dfcc 100644 --- a/src/link/Wasm/Atom.zig +++ b/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); diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 8f49d68712..7d4f6a4e36 100644 --- a/src/link/Wasm/Object.zig +++ b/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 }); } } |
