diff options
| author | Luuk de Gram <luuk@degram.dev> | 2024-01-14 15:36:28 +0100 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2024-02-29 15:23:02 +0100 |
| commit | e54177e852e5674ff14a850586b7517697e52297 (patch) | |
| tree | d1745f35884d814236bb2f98d5d65d55f079f540 /src/link | |
| parent | ba0e84a411074fe661b7df14edb2595267edcd30 (diff) | |
| download | zig-e54177e852e5674ff14a850586b7517697e52297.tar.gz zig-e54177e852e5674ff14a850586b7517697e52297.zip | |
wasm: move incremental Dwarf info into ZigObject
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Dwarf.zig | 166 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 1213 | ||||
| -rw-r--r-- | src/link/Wasm/ZigObject.zig | 115 |
3 files changed, 329 insertions, 1165 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index a9a6942299..a28926c1c0 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1297,9 +1297,9 @@ pub fn commitDeclState( } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; - writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // 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, } @@ -1390,26 +1390,26 @@ pub fn commitDeclState( }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - 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) { - log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); - if (needed_size > segment_size) { - log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size}); - try debug_line.resize(self.allocator, needed_size); - @memset(debug_line.items[segment_size..], 0); - } - debug_line.items.len = needed_size; - } - writeDbgLineNopsBuffered( - debug_line.items, - src_fn.off, - prev_padding_size, - dbg_line_buffer.items, - next_padding_size, - ); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // 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) { + // log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); + // if (needed_size > segment_size) { + // log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size}); + // try debug_line.resize(self.allocator, needed_size); + // @memset(debug_line.items[segment_size..], 0); + // } + // debug_line.items.len = needed_size; + // } + // writeDbgLineNopsBuffered( + // debug_line.items, + // src_fn.off, + // prev_padding_size, + // dbg_line_buffer.items, + // next_padding_size, + // ); }, else => unreachable, } @@ -1553,10 +1553,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - 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); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // 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, } @@ -1594,7 +1594,6 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons // This logic is nearly identical to the logic above in `updateDecl` for // `SrcFn` and the line number programs. If you are editing this logic, you // probably need to edit that logic too. - const gpa = self.allocator; const atom = self.getAtom(.di_atom, atom_index); const last_decl_index = self.di_atom_last_index.?; @@ -1665,31 +1664,31 @@ 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 = &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}); - if (needed_size > segment_size) { - log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size}); - try debug_info.resize(self.allocator, needed_size); - @memset(debug_info.items[segment_size..], 0); - } - debug_info.items.len = needed_size; - } - log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{ - debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size, - }); - try writeDbgInfoNopsToArrayList( - gpa, - debug_info, - atom.off, - prev_padding_size, - dbg_info_buf, - next_padding_size, - trailing_zero, - ); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const info_atom = wasm_file.debug_info_atom.?; + // 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}); + // if (needed_size > segment_size) { + // log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size}); + // try debug_info.resize(self.allocator, needed_size); + // @memset(debug_info.items[segment_size..], 0); + // } + // debug_info.items.len = needed_size; + // } + // log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{ + // debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size, + // }); + // try writeDbgInfoNopsToArrayList( + // gpa, + // debug_info, + // atom.off, + // prev_padding_size, + // dbg_info_buf, + // next_padding_size, + // trailing_zero, + // ); }, else => unreachable, } @@ -1735,10 +1734,10 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const offset = atom.off + self.getRelocDbgLineOff(); - const line_atom_index = wasm_file.debug_line_atom.?; - wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data; + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const offset = atom.off + self.getRelocDbgLineOff(); + // const line_atom_index = wasm_file.debug_line_atom.?; + // wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data; }, else => unreachable, } @@ -1803,7 +1802,6 @@ pub fn freeDecl(self: *Dwarf, decl_index: InternPool.DeclIndex) void { } pub fn writeDbgAbbrev(self: *Dwarf) !void { - const gpa = self.allocator; // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. // zig fmt: off @@ -1960,10 +1958,10 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code; - try debug_abbrev.resize(gpa, needed_size); - debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf; + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code; + // try debug_abbrev.resize(gpa, needed_size); + // debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf; }, else => unreachable, } @@ -2055,9 +2053,9 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64) } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - 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); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // 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, } @@ -2318,7 +2316,6 @@ fn writeDbgInfoNopsToArrayList( pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { const comp = self.bin_file.comp; - const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; const target_endian = target.cpu.arch.endian(); const ptr_width_bytes = self.ptrWidthBytes(); @@ -2391,10 +2388,10 @@ 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.getAtomPtr(wasm_file.debug_ranges_atom.?).code; - try debug_ranges.resize(gpa, needed_size); - @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code; + // try debug_ranges.resize(gpa, needed_size); + // @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items); }, else => unreachable, } @@ -2548,14 +2545,15 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; - { - const src = debug_line.items[first_fn.off..]; - @memcpy(buffer[0..src.len], src); - } - try debug_line.resize(self.allocator, debug_line.items.len + delta); - @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer); + _ = &buffer; + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; + // { + // const src = debug_line.items[first_fn.off..]; + // @memcpy(buffer[0..src.len], src); + // } + // try debug_line.resize(self.allocator, debug_line.items.len + delta); + // @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer); }, else => unreachable, } @@ -2604,9 +2602,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; - writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // 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, } @@ -2754,9 +2752,9 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { } }, .wasm => { - const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; - debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf; + // const wasm_file = self.bin_file.cast(File.Wasm).?; + // const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; + // debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf; }, else => unreachable, } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ecb0ed7115..cdc019c4fc 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -37,12 +37,22 @@ pub const Relocation = types.Relocation; pub const base_tag: link.File.Tag = .wasm; base: link.File, +/// Symbol name of the entry function to export entry_name: ?[]const u8, +/// When true, will allow undefined symbols import_symbols: bool, +/// List of *global* symbol names to export to the host environment. export_symbol_names: []const []const u8, +/// When defined, sets the start of the data section. global_base: ?u64, +/// When defined, sets the initial memory size of the memory. initial_memory: ?u64, +/// When defined, sets the maximum memory size of the memory. max_memory: ?u64, +/// When true, will import the function table from the host environment. +import_table: bool, +/// When true, will export the function table to the host environment. +export_table: bool, /// Output name of the file name: []const u8, /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. @@ -52,16 +62,8 @@ llvm_object: ?*LlvmObject = null, /// to support existing code. /// TODO: Allow setting this through a flag? host_name: []const u8 = "env", -/// List of all `Decl` that are currently alive. -/// Each index maps to the corresponding `Atom.Index`. -decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, -/// Mapping between an `Atom` and its type index representing the Wasm -/// type of the function signature. -atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .{}, /// 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) = .{}, +synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .{}, /// Maps atoms to their segment index atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// List of all atoms. @@ -107,8 +109,6 @@ data_segments: std.StringArrayHashMapUnmanaged(u32) = .{}, segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{}, /// Deduplicated string table for strings used by symbols, imports and exports. string_table: StringTable = .{}, -/// Debug information for wasm -dwarf: ?Dwarf = null, // Output sections /// Output type section @@ -170,36 +170,10 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{}, /// Note: The value represents the offset into the string table, rather than the actual string. export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, -/// Represents the symbol index of the error name table -/// When this is `null`, no code references an error using runtime `@errorName`. -/// During initializion, a symbol with corresponding atom will be created that is -/// used to perform relocations to the pointer of this table. -/// The actual table is populated during `flush`. -error_table_symbol: ?u32 = null, - -// Debug section atoms. These are only set when the current compilation -// 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.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, - /// List of atom indexes of functions that are generated by the backend, /// rather than by the linker. synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, -/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. -anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, - -import_table: bool, -export_table: bool, - pub const Alignment = types.Alignment; pub const Segment = struct { @@ -238,27 +212,27 @@ pub const SymbolLoc = struct { file: ?u16, /// From a given location, returns the corresponding symbol in the wasm binary - pub fn getSymbol(loc: SymbolLoc, wasm_bin: *const Wasm) *Symbol { - if (wasm_bin.discarded.get(loc)) |new_loc| { - return new_loc.getSymbol(wasm_bin); + pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol { + if (wasm_file.discarded.get(loc)) |new_loc| { + return new_loc.getSymbol(wasm_file); } if (loc.file) |object_index| { - const object = wasm_bin.objects.items[object_index]; + const object = wasm_file.objects.items[object_index]; return &object.symtable[loc.index]; } - return &wasm_bin.symbols.items[loc.index]; + return &wasm_file.synthetic_symbols.items[loc.index]; } /// From a given location, returns the name of the symbol. - pub fn getName(loc: SymbolLoc, wasm_bin: *const Wasm) []const u8 { - if (wasm_bin.discarded.get(loc)) |new_loc| { - return new_loc.getName(wasm_bin); + pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 { + if (wasm_file.discarded.get(loc)) |new_loc| { + return new_loc.getName(wasm_file); } if (loc.file) |object_index| { - const object = wasm_bin.objects.items[object_index]; + const object = wasm_file.objects.items[object_index]; return object.string_table.get(object.symtable[loc.index].name); } - return wasm_bin.string_table.get(wasm_bin.symbols.items[loc.index].name); + return wasm_file.string_table.get(wasm_file.synthetic_symbols.items[loc.index].name); } /// From a given symbol location, returns the final location. @@ -266,9 +240,9 @@ pub const SymbolLoc = struct { /// in a different file, this will return said location. /// If the symbol wasn't replaced by another, this will return /// the given location itwasm. - pub fn finalLoc(loc: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc { - if (wasm_bin.discarded.get(loc)) |new_loc| { - return new_loc.finalLoc(wasm_bin); + pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc { + if (wasm_file.discarded.get(loc)) |new_loc| { + return new_loc.finalLoc(wasm_file); } return loc; } @@ -594,10 +568,10 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol } fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { - const sym_index = @as(u32, @intCast(wasm.symbols.items.len)); + const sym_index = @as(u32, @intCast(wasm.synthetic_symbols.items.len)); const loc: SymbolLoc = .{ .index = sym_index, .file = null }; const gpa = wasm.base.comp.gpa; - try wasm.symbols.append(gpa, .{ + try wasm.synthetic_symbols.append(gpa, .{ .name = name_offset, .flags = 0, .tag = tag, @@ -609,24 +583,6 @@ fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) ! 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 -/// and symbols come from the object files instead. -pub fn initDebugSections(wasm: *Wasm) !void { - if (wasm.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections - assert(wasm.debug_info_index == null); - // this will create an Atom and set the index for us. - wasm.debug_info_atom = try wasm.createDebugSectionForIndex(&wasm.debug_info_index, ".debug_info"); - wasm.debug_line_atom = try wasm.createDebugSectionForIndex(&wasm.debug_line_index, ".debug_line"); - wasm.debug_loc_atom = try wasm.createDebugSectionForIndex(&wasm.debug_loc_index, ".debug_loc"); - wasm.debug_abbrev_atom = try wasm.createDebugSectionForIndex(&wasm.debug_abbrev_index, ".debug_abbrev"); - wasm.debug_ranges_atom = try wasm.createDebugSectionForIndex(&wasm.debug_ranges_index, ".debug_ranges"); - wasm.debug_str_atom = try wasm.createDebugSectionForIndex(&wasm.debug_str_index, ".debug_str"); - wasm.debug_pubnames_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubnames_index, ".debug_pubnames"); - wasm.debug_pubtypes_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubtypes_index, ".debug_pubtypes"); -} - fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void { for (files) |path| { if (try wasm.parseObjectFile(path)) continue; @@ -652,33 +608,14 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { return true; } -/// For a given `InternPool.DeclIndex` 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: InternPool.DeclIndex) !Atom.Index { - const gpa = wasm.base.comp.gpa; - const gop = try wasm.decls.getOrPut(gpa, decl_index); - if (!gop.found_existing) { - const atom_index = try wasm.createAtom(); - gop.value_ptr.* = atom_index; - const atom = wasm.getAtom(atom_index); - const symbol = atom.symbolLoc().getSymbol(wasm); - const mod = wasm.base.comp.module.?; - const decl = mod.declPtr(decl_index); - const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); - symbol.name = try wasm.string_table.put(gpa, full_name); - } - return gop.value_ptr.*; -} - /// Creates a new empty `Atom` and returns its `Atom.Index` -fn createAtom(wasm: *Wasm) !Atom.Index { +pub fn createAtom(wasm: *Wasm, sym_index: u32) !Atom.Index { const gpa = wasm.base.comp.gpa; const index: Atom.Index = @intCast(wasm.managed_atoms.items.len); const atom = try wasm.managed_atoms.addOne(gpa); atom.* = Atom.empty; - atom.sym_index = try wasm.allocateSymbol(); - try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = atom.sym_index }, index); + atom.sym_index = sym_index; + try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = sym_index }, index); return index; } @@ -1386,40 +1323,12 @@ pub fn deinit(wasm: *Wasm) void { archive.deinit(gpa); } - // For decls and anon decls we free the memory of its atoms. - // The memory of atoms parsed from object files is managed by - // the object file itself, and therefore we can skip those. - { - var it = wasm.decls.valueIterator(); - while (it.next()) |atom_index_ptr| { - const atom = wasm.getAtomPtr(atom_index_ptr.*); - for (atom.locals.items) |local_index| { - const local_atom = wasm.getAtomPtr(local_index); - local_atom.deinit(gpa); - } - atom.deinit(gpa); - } - } - { - for (wasm.anon_decls.values()) |atom_index| { - const atom = wasm.getAtomPtr(atom_index); - for (atom.locals.items) |local_index| { - const local_atom = wasm.getAtomPtr(local_index); - local_atom.deinit(gpa); - } - atom.deinit(gpa); - } - } for (wasm.synthetic_functions.items) |atom_index| { const atom = wasm.getAtomPtr(atom_index); atom.deinit(gpa); } - wasm.decls.deinit(gpa); - wasm.anon_decls.deinit(gpa); - wasm.atom_types.deinit(gpa); - wasm.symbols.deinit(gpa); - wasm.symbols_free_list.deinit(gpa); + wasm.synthetic_symbols.deinit(gpa); wasm.globals.deinit(gpa); wasm.resolved_symbols.deinit(gpa); wasm.undefs.deinit(gpa); @@ -1446,32 +1355,6 @@ pub fn deinit(wasm: *Wasm) void { wasm.string_table.deinit(gpa); wasm.synthetic_functions.deinit(gpa); - - if (wasm.dwarf) |*dwarf| { - dwarf.deinit(); - } -} - -/// Allocates a new symbol and returns its index. -/// Will re-use slots when a symbol was freed at an earlier stage. -pub fn allocateSymbol(wasm: *Wasm) !u32 { - const gpa = wasm.base.comp.gpa; - - try wasm.symbols.ensureUnusedCapacity(gpa, 1); - const symbol: Symbol = .{ - .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls - .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), - .tag = .undefined, // will be set after updateDecl - .index = std.math.maxInt(u32), // will be set during atom parsing - .virtual_address = std.math.maxInt(u32), // will be set during atom allocation - }; - if (wasm.symbols_free_list.popOrNull()) |index| { - wasm.symbols.items[index] = symbol; - return index; - } - const index = @as(u32, @intCast(wasm.symbols.items.len)); - wasm.symbols.appendAssumeCapacity(symbol); - return index; } pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { @@ -1546,84 +1429,12 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) ! @panic("Attempted to compile for object format that was disabled by build configuration"); } if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index); - - const tracy = trace(@src()); - defer tracy.end(); - - const decl = mod.declPtr(decl_index); - if (decl.val.getFunction(mod)) |_| { - return; - } else if (decl.val.getExternFunc(mod)) |_| { - return; - } - - const gpa = wasm.base.comp.gpa; - const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); - const atom = wasm.getAtomPtr(atom_index); - atom.clear(); - - if (decl.isExtern(mod)) { - const variable = decl.getOwnedVariable(mod).?; - const name = mod.intern_pool.stringToSlice(decl.name); - const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); - return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null); - } - const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; - - var code_writer = std.ArrayList(u8).init(gpa); - defer code_writer.deinit(); - - const res = try codegen.generateSymbol( - &wasm.base, - decl.srcLoc(mod), - .{ .ty = decl.ty, .val = val }, - &code_writer, - .none, - .{ .parent_atom_index = atom.sym_index }, - ); - - const code = switch (res) { - .ok => code_writer.items, - .fail => |em| { - decl.analysis = .codegen_failure; - try mod.failed_decls.put(mod.gpa, decl_index, em); - return; - }, - }; - - return wasm.finishUpdateDecl(decl_index, code, .data); } pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !void { if (wasm.llvm_object) |_| return; - if (wasm.dwarf) |*dw| { - const tracy = trace(@src()); - defer tracy.end(); - - const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); - - log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); - try dw.updateDeclLineNumber(mod, decl_index); - } -} - -fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void { - const gpa = wasm.base.comp.gpa; - const mod = wasm.base.comp.module.?; - 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 = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); - symbol.name = try wasm.string_table.put(gpa, full_name); - symbol.tag = symbol_tag; - try atom.code.appendSlice(gpa, code); - try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); - - atom.size = @intCast(code.len); - if (code.len == 0) return; - atom.alignment = decl.getAlignment(mod); + _ = mod; + _ = decl_index; } /// From a given symbol location, returns its `wasm.GlobalType`. @@ -1673,82 +1484,9 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { /// Returns the symbol index of the local /// The given `decl` is the parent decl whom owns the constant. pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { - const gpa = wasm.base.comp.gpa; - const mod = wasm.base.comp.module.?; - assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions - const decl = mod.declPtr(decl_index); - - const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); - const parent_atom = wasm.getAtom(parent_atom_index); - const local_index = parent_atom.locals.items.len; - const fqn = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); - const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{ - fqn, local_index, - }); - defer gpa.free(name); - - switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) { - .ok => |atom_index| { - try wasm.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); - return wasm.getAtom(atom_index).getSymbolIndex().?; - }, - .fail => |em| { - decl.analysis = .codegen_failure; - try mod.failed_decls.put(mod.gpa, decl_index, em); - return error.CodegenFail; - }, - } -} - -const LowerConstResult = union(enum) { - ok: Atom.Index, - fail: *Module.ErrorMsg, -}; - -fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { - const gpa = wasm.base.comp.gpa; - const mod = wasm.base.comp.module.?; - - // Create and initialize a new local symbol and atom - const atom_index = try wasm.createAtom(); - var value_bytes = std.ArrayList(u8).init(gpa); - defer value_bytes.deinit(); - - const code = code: { - const atom = wasm.getAtomPtr(atom_index); - atom.alignment = tv.ty.abiAlignment(mod); - wasm.symbols.items[atom.sym_index] = .{ - .name = try wasm.string_table.put(gpa, name), - .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), - .tag = .data, - .index = undefined, - .virtual_address = undefined, - }; - try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {}); - - const result = try codegen.generateSymbol( - &wasm.base, - src_loc, - tv, - &value_bytes, - .none, - .{ - .parent_atom_index = atom.sym_index, - .addend = null, - }, - ); - break :code switch (result) { - .ok => value_bytes.items, - .fail => |em| { - return .{ .fail = em }; - }, - }; - }; - - const atom = wasm.getAtomPtr(atom_index); - atom.size = @intCast(code.len); - try atom.code.appendSlice(gpa, code); - return .{ .ok = atom_index }; + _ = wasm; + _ = tv; + _ = decl_index; } /// Returns the symbol index from a symbol of which its flag is set global, @@ -1757,34 +1495,8 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src /// and then returns the index to it. pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 { _ = lib_name; - const gpa = wasm.base.comp.gpa; - const name_index = try wasm.string_table.put(gpa, name); - const gop = try wasm.globals.getOrPut(gpa, name_index); - if (gop.found_existing) { - return gop.value_ptr.*.index; - } - - var symbol: Symbol = .{ - .name = name_index, - .flags = 0, - .index = undefined, // index to type will be set after merging function symbols - .tag = .function, - .virtual_address = undefined, - }; - symbol.setGlobal(true); - symbol.setUndefined(true); - - const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: { - const index: u32 = @intCast(wasm.symbols.items.len); - try wasm.symbols.ensureUnusedCapacity(gpa, 1); - wasm.symbols.items.len += 1; - break :blk index; - }; - wasm.symbols.items[sym_index] = symbol; - gop.value_ptr.* = .{ .index = sym_index, .file = null }; - try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {}); - try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*); - return sym_index; + _ = name; + _ = wasm; } /// For a given decl, find the given symbol index's atom, and create a relocation for the type. @@ -1794,42 +1506,9 @@ pub fn getDeclVAddr( decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo, ) !u64 { - const target = wasm.base.comp.root_mod.resolved_target.result; - const gpa = wasm.base.comp.gpa; - const mod = wasm.base.comp.module.?; - const decl = mod.declPtr(decl_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_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; - const atom = wasm.getAtomPtr(atom_index); - const is_wasm32 = target.cpu.arch == .wasm32; - if (decl.ty.zigTypeTag(mod) == .Fn) { - assert(reloc_info.addend == 0); // addend not allowed for function relocations - // We found a function pointer, so add it to our table, - // as function pointers are not allowed to be stored inside the data section. - // They are instead stored in a function table which are called by index. - try wasm.addTableFunction(target_symbol_index); - try atom.relocs.append(gpa, .{ - .index = target_symbol_index, - .offset = @intCast(reloc_info.offset), - .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, - }); - } else { - try atom.relocs.append(gpa, .{ - .index = target_symbol_index, - .offset = @intCast(reloc_info.offset), - .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, - .addend = @intCast(reloc_info.addend), - }); - } - // we do not know the final address at this point, - // as atom allocation will determine the address and relocations - // will calculate and rewrite this. Therefore, we simply return the symbol index - // that was targeted. - return target_symbol_index; + _ = wasm; + _ = decl_index; + _ = reloc_info; } pub fn lowerAnonDecl( @@ -1838,70 +1517,16 @@ pub fn lowerAnonDecl( explicit_alignment: Alignment, src_loc: Module.SrcLoc, ) !codegen.Result { - const gpa = wasm.base.comp.gpa; - const gop = try wasm.anon_decls.getOrPut(gpa, decl_val); - if (!gop.found_existing) { - const mod = wasm.base.comp.module.?; - const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); - const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) }; - var name_buf: [32]u8 = undefined; - const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ - @intFromEnum(decl_val), - }) catch unreachable; - - switch (try wasm.lowerConst(name, tv, src_loc)) { - .ok => |atom_index| wasm.anon_decls.values()[gop.index] = atom_index, - .fail => |em| return .{ .fail = em }, - } - } - - const atom = wasm.getAtomPtr(wasm.anon_decls.values()[gop.index]); - atom.alignment = switch (atom.alignment) { - .none => explicit_alignment, - else => switch (explicit_alignment) { - .none => atom.alignment, - else => atom.alignment.maxStrict(explicit_alignment), - }, - }; - return .ok; + _ = wasm; + _ = decl_val; + _ = explicit_alignment; + _ = src_loc; } pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - const gpa = wasm.base.comp.gpa; - const target = wasm.base.comp.root_mod.resolved_target.result; - const atom_index = wasm.anon_decls.get(decl_val).?; - const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?; - - const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; - const parent_atom = wasm.getAtomPtr(parent_atom_index); - const is_wasm32 = target.cpu.arch == .wasm32; - const mod = wasm.base.comp.module.?; - const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); - if (ty.zigTypeTag(mod) == .Fn) { - assert(reloc_info.addend == 0); // addend not allowed for function relocations - // We found a function pointer, so add it to our table, - // as function pointers are not allowed to be stored inside the data section. - // They are instead stored in a function table which are called by index. - try wasm.addTableFunction(target_symbol_index); - try parent_atom.relocs.append(gpa, .{ - .index = target_symbol_index, - .offset = @intCast(reloc_info.offset), - .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, - }); - } else { - try parent_atom.relocs.append(gpa, .{ - .index = target_symbol_index, - .offset = @intCast(reloc_info.offset), - .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, - .addend = @intCast(reloc_info.addend), - }); - } - - // we do not know the final address at this point, - // as atom allocation will determine the address and relocations - // will calculate and rewrite this. Therefore, we simply return the symbol index - // that was targeted. - return target_symbol_index; + _ = wasm; + _ = decl_val; + _ = reloc_info; } pub fn deleteDeclExport( @@ -1909,19 +1534,9 @@ pub fn deleteDeclExport( decl_index: InternPool.DeclIndex, name: InternPool.NullTerminatedString, ) void { - _ = name; if (wasm.llvm_object) |_| 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); - log.debug("Deleting export for decl '{s}'", .{symbol_name}); - if (wasm.export_names.fetchRemove(loc)) |kv| { - assert(wasm.globals.remove(kv.value)); - } else { - assert(wasm.globals.remove(symbol.name)); - } + _ = name; + _ = decl_index; } pub fn updateExports( @@ -1934,159 +1549,10 @@ pub fn updateExports( @panic("Attempted to compile for object format that was disabled by build configuration"); } if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); - - const decl_index = switch (exported) { - .decl_index => |i| i, - .value => |val| { - _ = val; - @panic("TODO: implement Wasm linker code for exporting a constant value"); - }, - }; - const decl = mod.declPtr(decl_index); - const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); - const atom = wasm.getAtom(atom_index); - const atom_sym = atom.symbolLoc().getSymbol(wasm).*; - const gpa = mod.gpa; - - for (exports) |exp| { - if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| { - try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - "Unimplemented: ExportOptions.section '{s}'", - .{section}, - )); - continue; - } - - const exported_decl_index = switch (exp.exported) { - .value => { - try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - "Unimplemented: exporting a named constant value", - .{}, - )); - continue; - }, - .decl_index => |i| i, - }; - const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index); - const exported_atom = wasm.getAtom(exported_atom_index); - const export_name = try wasm.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name)); - const sym_loc = exported_atom.symbolLoc(); - const symbol = sym_loc.getSymbol(wasm); - symbol.setGlobal(true); - symbol.setUndefined(false); - symbol.index = atom_sym.index; - symbol.tag = atom_sym.tag; - symbol.name = atom_sym.name; - - switch (exp.opts.linkage) { - .Internal => { - symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - symbol.setFlag(.WASM_SYM_BINDING_WEAK); - }, - .Weak => { - symbol.setFlag(.WASM_SYM_BINDING_WEAK); - }, - .Strong => {}, // symbols are strong by default - .LinkOnce => { - try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - "Unimplemented: LinkOnce", - .{}, - )); - continue; - }, - } - - if (wasm.globals.get(export_name)) |existing_loc| { - if (existing_loc.index == atom.sym_index) continue; - const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; - - if (!existing_sym.isUndefined()) blk: { - if (symbol.isWeak()) { - try wasm.discarded.put(gpa, existing_loc, sym_loc); - continue; // to-be-exported symbol is weak, so we keep the existing symbol - } - - // new symbol is not weak while existing is, replace existing symbol - if (existing_sym.isWeak()) { - break :blk; - } - // When both the to-be-exported symbol and the already existing symbol - // are strong symbols, we have a linker error. - // In the other case we replace one with the other. - try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - \\LinkError: symbol '{}' defined multiple times - \\ first definition in '{s}' - \\ next definition in '{s}' - , - .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, - )); - continue; - } - - // in this case the existing symbol must be replaced either because it's weak or undefined. - try wasm.discarded.put(gpa, existing_loc, sym_loc); - _ = wasm.imports.remove(existing_loc); - _ = wasm.undefs.swapRemove(existing_sym.name); - } - - // Ensure the symbol will be exported using the given name - if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { - try wasm.export_names.put(gpa, sym_loc, export_name); - } - - try wasm.globals.put( - gpa, - export_name, - sym_loc, - ); - } } pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); - const gpa = wasm.base.comp.gpa; - const mod = wasm.base.comp.module.?; - const decl = mod.declPtr(decl_index); - const atom_index = wasm.decls.get(decl_index).?; - const atom = wasm.getAtomPtr(atom_index); - atom.prev = null; - wasm.symbols_free_list.append(gpa, atom.sym_index) catch {}; - _ = wasm.decls.remove(decl_index); - wasm.symbols.items[atom.sym_index].tag = .dead; - 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(gpa, local_atom.sym_index) catch {}; - assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc())); - assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); - } - - if (decl.isExtern(mod)) { - _ = wasm.imports.remove(atom.symbolLoc()); - } - _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); - _ = wasm.symbol_atom.remove(atom.symbolLoc()); - - // if (wasm.dwarf) |*dwarf| { - // dwarf.freeDecl(decl_index); - // } - -} - -/// Appends a new entry to the indirect function table -pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void { - const gpa = wasm.base.comp.gpa; - const index: u32 = @intCast(wasm.function_table.count()); - try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index); } /// Assigns indexes to all indirect functions. @@ -2118,203 +1584,6 @@ fn mapFunctionTable(wasm: *Wasm) void { } } -/// Either creates a new import, or updates one if existing. -/// When `type_index` is non-null, we assume an external function. -/// In all other cases, a data-symbol will be created instead. -pub fn addOrUpdateImport( - wasm: *Wasm, - /// Name of the import - name: []const u8, - /// Symbol index that is external - symbol_index: u32, - /// Optional library name (i.e. `extern "c" fn foo() void` - lib_name: ?[:0]const u8, - /// The index of the type that represents the function signature - /// when the extern is a function. When this is null, a data-symbol - /// is asserted instead. - type_index: ?u32, -) !void { - const gpa = wasm.base.comp.gpa; - assert(symbol_index != 0); - // For the import name, we use the decl's name, rather than the fully qualified name - // Also mangle the name when the lib name is set and not equal to "C" so imports with the same - // name but different module can be resolved correctly. - const mangle_name = lib_name != null and - !std.mem.eql(u8, lib_name.?, "c"); - const full_name = if (mangle_name) full_name: { - break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? }); - } else name; - defer if (mangle_name) gpa.free(full_name); - - const decl_name_index = try wasm.string_table.put(gpa, full_name); - const symbol: *Symbol = &wasm.symbols.items[symbol_index]; - symbol.setUndefined(true); - symbol.setGlobal(true); - symbol.name = decl_name_index; - if (mangle_name) { - // we specified a specific name for the symbol that does not match the import name - symbol.setFlag(.WASM_SYM_EXPLICIT_NAME); - } - const global_gop = try wasm.globals.getOrPut(gpa, decl_name_index); - if (!global_gop.found_existing) { - const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; - global_gop.value_ptr.* = loc; - try wasm.resolved_symbols.put(gpa, loc, {}); - try wasm.undefs.putNoClobber(gpa, decl_name_index, loc); - } else if (global_gop.value_ptr.*.index != symbol_index) { - // We are not updating a symbol, but found an existing global - // symbol with the same name. This means we always favor the - // existing symbol, regardless whether it's defined or not. - // We can also skip storing the import as we will not output - // this symbol. - return wasm.discarded.put( - gpa, - .{ .file = null, .index = symbol_index }, - global_gop.value_ptr.*, - ); - } - - if (type_index) |ty_index| { - const gop = try wasm.imports.getOrPut(gpa, .{ .index = symbol_index, .file = null }); - const module_name = if (lib_name) |l_name| blk: { - break :blk l_name; - } else wasm.host_name; - if (!gop.found_existing) { - gop.value_ptr.* = .{ - .module_name = try wasm.string_table.put(gpa, module_name), - .name = try wasm.string_table.put(gpa, name), - .kind = .{ .function = ty_index }, - }; - } - } else { - // non-functions will not be imported from the runtime, but only resolved during link-time - symbol.tag = .data; - } -} - -/// Kind represents the type of an Atom, which is only -/// used to parse a decl into an Atom to define in which section -/// or segment it should be placed. -const Kind = union(enum) { - /// Represents the segment the data symbol should - /// be inserted into. - /// TODO: Add TLS segments - data: enum { - read_only, - uninitialized, - initialized, - }, - function: void, - - /// Returns the segment name the data kind represents. - /// Asserts `kind` has its active tag set to `data`. - fn segmentName(kind: Kind) []const u8 { - switch (kind.data) { - .read_only => return ".rodata.", - .uninitialized => return ".bss.", - .initialized => return ".data.", - } - } -}; - -/// Parses an Atom and inserts its metadata into the corresponding sections. -fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { - const comp = wasm.base.comp; - const gpa = comp.gpa; - const shared_memory = comp.config.shared_memory; - const import_memory = comp.config.import_memory; - const atom = wasm.getAtomPtr(atom_index); - const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); - const do_garbage_collect = wasm.base.gc_sections; - - if (symbol.isDead() and do_garbage_collect) { - // Prevent unreferenced symbols from being parsed. - return; - } - - const final_index: u32 = switch (kind) { - .function => result: { - const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); - const type_index = wasm.atom_types.get(atom_index).?; - try wasm.functions.putNoClobber( - gpa, - .{ .file = null, .index = index }, - .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, - ); - symbol.tag = .function; - symbol.index = index; - - if (wasm.code_section_index == null) { - wasm.code_section_index = @intCast(wasm.segments.items.len); - try wasm.segments.append(gpa, .{ - .alignment = atom.alignment, - .size = atom.size, - .offset = 0, - .flags = 0, - }); - } - - break :result wasm.code_section_index.?; - }, - .data => result: { - const segment_name = try std.mem.concat(gpa, u8, &.{ - kind.segmentName(), - wasm.string_table.get(symbol.name), - }); - errdefer gpa.free(segment_name); - const segment_info: types.Segment = .{ - .name = segment_name, - .alignment = atom.alignment, - .flags = 0, - }; - symbol.tag = .data; - - // when creating an object file, or importing memory and the data belongs in the .bss segment - // we set the entire region of it to zeroes. - // We do not have to do this when exporting the memory (the default) because the runtime - // will do it for us, and we do not emit the bss segment at all. - if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { - @memset(atom.code.items, 0); - } - - const should_merge = wasm.base.comp.config.output_mode != .Obj; - const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge)); - if (gop.found_existing) { - const index = gop.value_ptr.*; - wasm.segments.items[index].size += atom.size; - - symbol.index = @intCast(wasm.segment_info.getIndex(index).?); - // segment info already exists, so free its memory - gpa.free(segment_name); - break :result index; - } else { - const index: u32 = @intCast(wasm.segments.items.len); - var flags: u32 = 0; - if (shared_memory) { - flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); - } - try wasm.segments.append(gpa, .{ - .alignment = atom.alignment, - .size = 0, - .offset = 0, - .flags = flags, - }); - gop.value_ptr.* = index; - - const info_index: u32 = @intCast(wasm.segment_info.count()); - try wasm.segment_info.put(gpa, index, segment_info); - symbol.index = info_index; - break :result index; - } - }, - }; - - const segment: *Segment = &wasm.segments.items[final_index]; - segment.alignment = segment.alignment.max(atom.alignment); - - 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_index: Atom.Index) !void { @@ -2328,40 +1597,9 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void } } -/// Allocates debug atoms into their respective debug sections -/// to merge them with maybe-existing debug atoms from object files. -fn allocateDebugAtoms(wasm: *Wasm) !void { - if (wasm.dwarf == null) return; - - const allocAtom = struct { - fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void { - const index = maybe_index.* orelse idx: { - const index = @as(u32, @intCast(bin.segments.items.len)); - try bin.appendDummySegment(); - maybe_index.* = index; - break :idx index; - }; - const atom = bin.getAtomPtr(atom_index); - atom.size = @as(u32, @intCast(atom.code.items.len)); - bin.symbols.items[atom.sym_index].index = index; - try bin.appendAtomAtIndex(index, atom_index); - } - }.f; - - try allocAtom(wasm, &wasm.debug_info_index, wasm.debug_info_atom.?); - try allocAtom(wasm, &wasm.debug_line_index, wasm.debug_line_atom.?); - try allocAtom(wasm, &wasm.debug_loc_index, wasm.debug_loc_atom.?); - try allocAtom(wasm, &wasm.debug_str_index, wasm.debug_str_atom.?); - try allocAtom(wasm, &wasm.debug_ranges_index, wasm.debug_ranges_atom.?); - try allocAtom(wasm, &wasm.debug_abbrev_index, wasm.debug_abbrev_atom.?); - try allocAtom(wasm, &wasm.debug_pubnames_index, wasm.debug_pubnames_atom.?); - try allocAtom(wasm, &wasm.debug_pubtypes_index, wasm.debug_pubtypes_atom.?); -} - fn allocateAtoms(wasm: *Wasm) !void { // first sort the data segments try sortDataSegments(wasm); - try allocateDebugAtoms(wasm); var it = wasm.atoms.iterator(); while (it.next()) |entry| { @@ -2382,7 +1620,7 @@ fn allocateAtoms(wasm: *Wasm) !void { const sym = if (symbol_loc.file) |object_index| sym: { const object = wasm.objects.items[object_index]; break :sym object.symtable[symbol_loc.index]; - } else wasm.symbols.items[symbol_loc.index]; + } else wasm.synthetic_symbols.items[symbol_loc.index]; // Dead symbols must be unlinked from the linked-list to prevent them // from being emit into the binary. @@ -2521,34 +1759,6 @@ fn setupInitFunctions(wasm: *Wasm) !void { } } -/// Generates an atom containing the global error set' size. -/// This will only be generated if the symbol exists. -fn setupErrorsLen(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; - const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return; - - const errors_len = wasm.base.comp.module.?.global_error_set.count(); - // overwrite existing atom if it already exists (maybe the error set has increased) - // if not, allcoate a new atom. - const atom_index = if (wasm.symbol_atom.get(loc)) |index| blk: { - const atom = wasm.getAtomPtr(index); - atom.deinit(gpa); - break :blk index; - } else new_atom: { - const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); - try wasm.symbol_atom.put(gpa, loc, atom_index); - try wasm.managed_atoms.append(gpa, undefined); - break :new_atom atom_index; - }; - const atom = wasm.getAtomPtr(atom_index); - atom.* = Atom.empty; - atom.sym_index = loc.index; - atom.size = 2; - try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little); - - try wasm.parseAtom(atom_index, .{ .data = .read_only }); -} - /// Creates a function body for the `__wasm_call_ctors` symbol. /// Loops over all constructors found in `init_funcs` and calls them /// respectively based on their priority which was sorted by `setupInitFunctions`. @@ -3278,139 +2488,6 @@ fn appendDummySegment(wasm: *Wasm) !void { }); } -/// Returns the symbol index of the error name table. -/// -/// When the symbol does not yet exist, it will create a new one instead. -pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { - if (wasm.error_table_symbol) |symbol| { - return symbol; - } - - // no error was referenced yet, so create a new symbol and atom for it - // and then return said symbol's index. The final table will be populated - // during `flush` when we know all possible error names. - - const gpa = wasm.base.comp.gpa; - const atom_index = try wasm.createAtom(); - const atom = wasm.getAtomPtr(atom_index); - const slice_ty = Type.slice_const_u8_sentinel_0; - const mod = wasm.base.comp.module.?; - atom.alignment = slice_ty.abiAlignment(mod); - const sym_index = atom.sym_index; - - const sym_name = try wasm.string_table.put(gpa, "__zig_err_name_table"); - const symbol = &wasm.symbols.items[sym_index]; - symbol.* = .{ - .name = sym_name, - .tag = .data, - .flags = 0, - .index = 0, - .virtual_address = undefined, - }; - symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - symbol.mark(); - - try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); - - 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. -/// -/// This creates a table that consists of pointers and length to each error name. -/// The table is what is being pointed to within the runtime bodies that are generated. -fn populateErrorNameTable(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; - const symbol_index = wasm.error_table_symbol orelse return; - const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_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_index = try wasm.createAtom(); - const names_atom = wasm.getAtomPtr(names_atom_index); - names_atom.alignment = .@"1"; - const sym_name = try wasm.string_table.put(gpa, "__zig_err_names"); - const names_symbol = &wasm.symbols.items[names_atom.sym_index]; - names_symbol.* = .{ - .name = sym_name, - .tag = .data, - .flags = 0, - .index = 0, - .virtual_address = undefined, - }; - names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - names_symbol.mark(); - - log.debug("Populating error names", .{}); - - // Addend for each relocation to the table - var addend: u32 = 0; - const mod = wasm.base.comp.module.?; - for (mod.global_error_set.keys()) |error_name_nts| { - const atom = wasm.getAtomPtr(atom_index); - - const error_name = mod.intern_pool.stringToSlice(error_name_nts); - const len = @as(u32, @intCast(error_name.len + 1)); // names are 0-termianted - - const slice_ty = Type.slice_const_u8_sentinel_0; - const offset = @as(u32, @intCast(atom.code.items.len)); - // first we create the data for the slice of the name - try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated - try atom.code.writer(gpa).writeInt(u32, len - 1, .little); - // create relocation to the error name - try atom.relocs.append(gpa, .{ - .index = names_atom.sym_index, - .relocation_type = .R_WASM_MEMORY_ADDR_I32, - .offset = offset, - .addend = @as(i32, @intCast(addend)), - }); - atom.size += @as(u32, @intCast(slice_ty.abiSize(mod))); - addend += len; - - // as we updated the error name table, we now store the actual name within the names atom - try names_atom.code.ensureUnusedCapacity(gpa, len); - names_atom.code.appendSliceAssumeCapacity(error_name); - names_atom.code.appendAssumeCapacity(0); - - log.debug("Populated error name: '{s}'", .{error_name}); - } - names_atom.size = addend; - - const name_loc = names_atom.symbolLoc(); - try wasm.resolved_symbols.put(gpa, name_loc, {}); - try wasm.symbol_atom.put(gpa, 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_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.Index { - const gpa = wasm.base.comp.gpa; - const new_index: u32 = @intCast(wasm.segments.items.len); - index.* = new_index; - try wasm.appendDummySegment(); - - 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(gpa, name), - .index = 0, - .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), - }; - - atom.alignment = .@"1"; // debug sections are always 1-byte-aligned - return atom_index; -} - fn resetState(wasm: *Wasm) void { const gpa = wasm.base.comp.gpa; @@ -3418,16 +2495,19 @@ fn resetState(wasm: *Wasm) void { gpa.free(segment_info.name); } - var atom_it = wasm.decls.valueIterator(); - while (atom_it.next()) |atom_index| { - const atom = wasm.getAtomPtr(atom_index.*); - atom.prev = null; + // TODO: Revisit + // 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.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(); @@ -3684,7 +2764,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) defer sub_prog_node.end(); // ensure the error names table is populated when an error name is referenced - try wasm.populateErrorNameTable(); + // try wasm.populateErrorNameTable(); const objects = comp.objects; @@ -3722,66 +2802,66 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) try wasm.setupInitFunctions(); try wasm.setupStart(); try wasm.markReferences(); - try wasm.setupErrorsLen(); + // try wasm.setupErrorsLen(); try wasm.setupImports(); - if (comp.module) |mod| { - var decl_it = wasm.decls.iterator(); - while (decl_it.next()) |entry| { - const decl = mod.declPtr(entry.key_ptr.*); - if (decl.isExtern(mod)) continue; - const atom_index = entry.value_ptr.*; - const atom = wasm.getAtomPtr(atom_index); - if (decl.ty.zigTypeTag(mod) == .Fn) { - try wasm.parseAtom(atom_index, .function); - } else if (decl.getOwnedVariable(mod)) |variable| { - if (variable.is_const) { - try wasm.parseAtom(atom_index, .{ .data = .read_only }); - } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { - // for safe build modes, we store the atom in the data segment, - // whereas for unsafe build modes we store it in bss. - const decl_namespace = mod.namespacePtr(decl.src_namespace); - const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; - const is_initialized = switch (optimize_mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, - }; - try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); - } else { - // when the decl is all zeroes, we store the atom in the bss segment, - // in all other cases it will be in the data segment. - const is_zeroes = for (atom.code.items) |byte| { - if (byte != 0) break false; - } else true; - try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized }); - } - } else { - try wasm.parseAtom(atom_index, .{ .data = .read_only }); - } - - // also parse atoms for a decl's locals - for (atom.locals.items) |local_atom_index| { - try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); - } - } - // parse anonymous declarations - for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { - const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); - if (ty.zigTypeTag(mod) == .Fn) { - try wasm.parseAtom(atom_index, .function); - } else { - try wasm.parseAtom(atom_index, .{ .data = .read_only }); - } - } - - // also parse any backend-generated functions - for (wasm.synthetic_functions.items) |atom_index| { - try wasm.parseAtom(atom_index, .function); - } - - if (wasm.dwarf) |*dwarf| { - try dwarf.flushModule(comp.module.?); - } - } + // if (comp.module) |mod| { + // var decl_it = wasm.decls.iterator(); + // while (decl_it.next()) |entry| { + // const decl = mod.declPtr(entry.key_ptr.*); + // if (decl.isExtern(mod)) continue; + // const atom_index = entry.value_ptr.*; + // const atom = wasm.getAtomPtr(atom_index); + // if (decl.ty.zigTypeTag(mod) == .Fn) { + // try wasm.parseAtom(atom_index, .function); + // } else if (decl.getOwnedVariable(mod)) |variable| { + // if (variable.is_const) { + // try wasm.parseAtom(atom_index, .{ .data = .read_only }); + // } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { + // // for safe build modes, we store the atom in the data segment, + // // whereas for unsafe build modes we store it in bss. + // const decl_namespace = mod.namespacePtr(decl.src_namespace); + // const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; + // const is_initialized = switch (optimize_mode) { + // .Debug, .ReleaseSafe => true, + // .ReleaseFast, .ReleaseSmall => false, + // }; + // try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); + // } else { + // // when the decl is all zeroes, we store the atom in the bss segment, + // // in all other cases it will be in the data segment. + // const is_zeroes = for (atom.code.items) |byte| { + // if (byte != 0) break false; + // } else true; + // try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized }); + // } + // } else { + // try wasm.parseAtom(atom_index, .{ .data = .read_only }); + // } + + // // also parse atoms for a decl's locals + // for (atom.locals.items) |local_atom_index| { + // try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); + // } + // } + // // parse anonymous declarations + // for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { + // const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); + // if (ty.zigTypeTag(mod) == .Fn) { + // try wasm.parseAtom(atom_index, .function); + // } else { + // try wasm.parseAtom(atom_index, .{ .data = .read_only }); + // } + // } + + // // also parse any backend-generated functions + // for (wasm.synthetic_functions.items) |atom_index| { + // try wasm.parseAtom(atom_index, .function); + // } + + // if (wasm.dwarf) |*dwarf| { + // try dwarf.flushModule(comp.module.?); + // } + // } try wasm.mergeSections(); try wasm.mergeTypes(); @@ -4194,16 +3274,6 @@ fn writeToFile( else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), } - // if (wasm.dwarf) |*dwarf| { - // const mod = comp.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(gpa); defer debug_bytes.deinit(); @@ -5185,44 +4255,25 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { return false; } -pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 { - var index: u32 = 0; - while (index < wasm.func_types.items.len) : (index += 1) { - if (wasm.func_types.items[index].eql(func_type)) return index; - } - return null; -} - /// Searches for a matching function signature. When no matching signature is found, /// a new entry will be made. The value returned is the index of the type within `wasm.func_types`. pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { - if (wasm.getTypeIndex(func_type)) |index| { - return index; - } - const gpa = wasm.base.comp.gpa; - - // functype does not exist. - const index: u32 = @intCast(wasm.func_types.items.len); - const params = try gpa.dupe(std.wasm.Valtype, func_type.params); - errdefer gpa.free(params); - const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns); - errdefer gpa.free(returns); - try wasm.func_types.append(gpa, .{ - .params = params, - .returns = returns, - }); - return index; + _ = wasm; + _ = func_type; } /// For the given `decl_index`, stores the corresponding type representing the function signature. /// Asserts declaration has an associated `Atom`. /// Returns the index into the list of types. pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 { - const gpa = wasm.base.comp.gpa; - const atom_index = wasm.decls.get(decl_index).?; - const index = try wasm.putOrGetFuncType(func_type); - try wasm.atom_types.put(gpa, atom_index, index); - return index; + _ = wasm; + _ = decl_index; + _ = func_type; + // const gpa = wasm.base.comp.gpa; + // const atom_index = wasm.decls.get(decl_index).?; + // const index = try wasm.putOrGetFuncType(func_type); + // try wasm.atom_types.put(gpa, atom_index, index); + // return index; } /// Verifies all resolved symbols and checks whether itself needs to be marked alive, diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 275593f348..505d73a630 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -41,6 +41,36 @@ imported_globals_count: u32 = 0, /// of a new `ZigObject`. Codegen will make calls into this to create relocations for /// this symbol each time the stack pointer is moved. stack_pointer_sym: u32, +/// Debug information for the Zig module. +dwarf: ?Dwarf = null, +// Debug section atoms. These are only set when the current compilation +// 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.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, +/// The index of the segment representing the custom '.debug_info' section. +debug_info_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_line' section. +debug_line_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_loc' section. +debug_loc_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_ranges' section. +debug_ranges_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_pubnames' section. +debug_pubnames_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_pubtypes' section. +debug_pubtypes_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_pubtypes' section. +debug_str_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_pubtypes' section. +debug_abbrev_index: ?u32 = null, /// Frees and invalidates all memory of the incrementally compiled Zig module. /// It is illegal behavior to access the `ZigObject` after calling `deinit`. @@ -80,6 +110,9 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { zig_object.segment_info.deinit(gpa); zig_object.string_table.deinit(gpa); + if (zig_object.dwarf) |*dwarf| { + dwarf.deinit(); + } zig_object.* = undefined; } @@ -976,6 +1009,87 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void { // try wasm.parseAtom(atom_index, .{ .data = .read_only }); } +/// 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 +/// and symbols come from the object files instead. +pub fn initDebugSections(zig_object: *ZigObject) !void { + if (zig_object.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections + std.debug.assert(zig_object.debug_info_index == null); + // this will create an Atom and set the index for us. + zig_object.debug_info_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_info_index, ".debug_info"); + zig_object.debug_line_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_line_index, ".debug_line"); + zig_object.debug_loc_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_loc_index, ".debug_loc"); + zig_object.debug_abbrev_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_abbrev_index, ".debug_abbrev"); + zig_object.debug_ranges_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_ranges_index, ".debug_ranges"); + zig_object.debug_str_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_str_index, ".debug_str"); + zig_object.debug_pubnames_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_pubnames_index, ".debug_pubnames"); + zig_object.debug_pubtypes_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_pubtypes_index, ".debug_pubtypes"); +} + +/// 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(zig_object: *ZigObject, wasm_file: *Wasm, index: *?u32, name: []const u8) !Atom.Index { + const gpa = wasm_file.base.comp.gpa; + const new_index: u32 = @intCast(zig_object.segments.items.len); + index.* = new_index; + try zig_object.appendDummySegment(); + + const sym_index = try zig_object.allocateSymbol(gpa); + const atom_index = try wasm_file.createAtom(sym_index); + const atom = wasm_file.getAtomPtr(atom_index); + zig_object.symbols.items[sym_index] = .{ + .tag = .section, + .name = try zig_object.string_table.put(gpa, name), + .index = 0, + .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), + }; + + atom.alignment = .@"1"; // debug sections are always 1-byte-aligned + return atom_index; +} + +pub fn updateDeclLineNumber(zig_object: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void { + if (zig_object.dwarf) |*dw| { + const decl = mod.declPtr(decl_index); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + + log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); + try dw.updateDeclLineNumber(mod, decl_index); + } +} + +/// Allocates debug atoms into their respective debug sections +/// to merge them with maybe-existing debug atoms from object files. +fn allocateDebugAtoms(zig_object: *ZigObject) !void { + if (zig_object.dwarf == null) return; + + const allocAtom = struct { + fn f(ctx: *ZigObject, maybe_index: *?u32, atom_index: Atom.Index) !void { + const index = maybe_index.* orelse idx: { + const index = @as(u32, @intCast(ctx.segments.items.len)); + try ctx.appendDummySegment(); + maybe_index.* = index; + break :idx index; + }; + const atom = ctx.getAtomPtr(atom_index); + atom.size = @as(u32, @intCast(atom.code.items.len)); + ctx.symbols.items[atom.sym_index].index = index; + try ctx.appendAtomAtIndex(index, atom_index); + } + }.f; + + try allocAtom(zig_object, &zig_object.debug_info_index, zig_object.debug_info_atom.?); + try allocAtom(zig_object, &zig_object.debug_line_index, zig_object.debug_line_atom.?); + try allocAtom(zig_object, &zig_object.debug_loc_index, zig_object.debug_loc_atom.?); + try allocAtom(zig_object, &zig_object.debug_str_index, zig_object.debug_str_atom.?); + try allocAtom(zig_object, &zig_object.debug_ranges_index, zig_object.debug_ranges_atom.?); + try allocAtom(zig_object, &zig_object.debug_abbrev_index, zig_object.debug_abbrev_atom.?); + try allocAtom(zig_object, &zig_object.debug_pubnames_index, zig_object.debug_pubnames_atom.?); + try allocAtom(zig_object, &zig_object.debug_pubtypes_index, zig_object.debug_pubtypes_atom.?); +} + const build_options = @import("build_options"); const builtin = @import("builtin"); const codegen = @import("../../codegen.zig"); @@ -986,6 +1100,7 @@ const types = @import("types.zig"); const Air = @import("../../Air.zig"); const Atom = @import("Atom.zig"); +const Dwarf = @import("../Dwarf.zig"); const InternPool = @import("../../InternPool.zig"); const Liveness = @import("../../Liveness.zig"); const Module = @import("../../Module.zig"); |
