authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-01-14 15:36:28+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-02-29 15:23:02+01:00
loge54177e852e5674ff14a850586b7517697e52297
treed1745f35884d814236bb2f98d5d65d55f079f540
parentba0e84a411074fe661b7df14edb2595267edcd30
signaturelock-open Commit is signed but in an unrecognized format.

wasm: move incremental Dwarf info into ZigObject


4 files changed, 329 insertions(+), 1166 deletions(-)

src/arch/wasm/CodeGen.zig-1
...@@ -3191,7 +3191,6 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl...@@ -3191,7 +3191,6 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl
31913191
3192 const target_sym_index = atom.sym_index;3192 const target_sym_index = atom.sym_index;
3193 if (decl.ty.zigTypeTag(mod) == .Fn) {3193 if (decl.ty.zigTypeTag(mod) == .Fn) {
3194 try func.bin_file.addTableFunction(target_sym_index);
3195 return WValue{ .function_index = target_sym_index };3194 return WValue{ .function_index = target_sym_index };
3196 } else if (offset == 0) {3195 } else if (offset == 0) {
3197 return WValue{ .memory = target_sym_index };3196 return WValue{ .memory = target_sym_index };
src/link/Dwarf.zig+82-84
...@@ -1297,9 +1297,9 @@ pub fn commitDeclState(...@@ -1297,9 +1297,9 @@ pub fn commitDeclState(
1297 }1297 }
1298 },1298 },
1299 .wasm => {1299 .wasm => {
1300 const wasm_file = self.bin_file.cast(File.Wasm).?;1300 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1301 const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;1301 // const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
1302 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);1302 // writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
1303 },1303 },
1304 else => unreachable,1304 else => unreachable,
1305 }1305 }
...@@ -1390,26 +1390,26 @@ pub fn commitDeclState(...@@ -1390,26 +1390,26 @@ pub fn commitDeclState(
1390 },1390 },
13911391
1392 .wasm => {1392 .wasm => {
1393 const wasm_file = self.bin_file.cast(File.Wasm).?;1393 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1394 const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?);1394 // const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?);
1395 const debug_line = &atom.code;1395 // const debug_line = &atom.code;
1396 const segment_size = debug_line.items.len;1396 // const segment_size = debug_line.items.len;
1397 if (needed_size != segment_size) {1397 // if (needed_size != segment_size) {
1398 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});1398 // log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
1399 if (needed_size > segment_size) {1399 // if (needed_size > segment_size) {
1400 log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size});1400 // log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size});
1401 try debug_line.resize(self.allocator, needed_size);1401 // try debug_line.resize(self.allocator, needed_size);
1402 @memset(debug_line.items[segment_size..], 0);1402 // @memset(debug_line.items[segment_size..], 0);
1403 }1403 // }
1404 debug_line.items.len = needed_size;1404 // debug_line.items.len = needed_size;
1405 }1405 // }
1406 writeDbgLineNopsBuffered(1406 // writeDbgLineNopsBuffered(
1407 debug_line.items,1407 // debug_line.items,
1408 src_fn.off,1408 // src_fn.off,
1409 prev_padding_size,1409 // prev_padding_size,
1410 dbg_line_buffer.items,1410 // dbg_line_buffer.items,
1411 next_padding_size,1411 // next_padding_size,
1412 );1412 // );
1413 },1413 },
1414 else => unreachable,1414 else => unreachable,
1415 }1415 }
...@@ -1553,10 +1553,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)...@@ -1553,10 +1553,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
1553 }1553 }
1554 },1554 },
1555 .wasm => {1555 .wasm => {
1556 const wasm_file = self.bin_file.cast(File.Wasm).?;1556 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1557 const debug_info_index = wasm_file.debug_info_atom.?;1557 // const debug_info_index = wasm_file.debug_info_atom.?;
1558 const debug_info = &wasm_file.getAtomPtr(debug_info_index).code;1558 // const debug_info = &wasm_file.getAtomPtr(debug_info_index).code;
1559 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);1559 // try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
1560 },1560 },
1561 else => unreachable,1561 else => unreachable,
1562 }1562 }
...@@ -1594,7 +1594,6 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons...@@ -1594,7 +1594,6 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
1594 // This logic is nearly identical to the logic above in `updateDecl` for1594 // This logic is nearly identical to the logic above in `updateDecl` for
1595 // `SrcFn` and the line number programs. If you are editing this logic, you1595 // `SrcFn` and the line number programs. If you are editing this logic, you
1596 // probably need to edit that logic too.1596 // probably need to edit that logic too.
1597 const gpa = self.allocator;
15981597
1599 const atom = self.getAtom(.di_atom, atom_index);1598 const atom = self.getAtom(.di_atom, atom_index);
1600 const last_decl_index = self.di_atom_last_index.?;1599 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...@@ -1665,31 +1664,31 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
1665 },1664 },
16661665
1667 .wasm => {1666 .wasm => {
1668 const wasm_file = self.bin_file.cast(File.Wasm).?;1667 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1669 const info_atom = wasm_file.debug_info_atom.?;1668 // const info_atom = wasm_file.debug_info_atom.?;
1670 const debug_info = &wasm_file.getAtomPtr(info_atom).code;1669 // const debug_info = &wasm_file.getAtomPtr(info_atom).code;
1671 const segment_size = debug_info.items.len;1670 // const segment_size = debug_info.items.len;
1672 if (needed_size != segment_size) {1671 // if (needed_size != segment_size) {
1673 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});1672 // log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
1674 if (needed_size > segment_size) {1673 // if (needed_size > segment_size) {
1675 log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size});1674 // log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size});
1676 try debug_info.resize(self.allocator, needed_size);1675 // try debug_info.resize(self.allocator, needed_size);
1677 @memset(debug_info.items[segment_size..], 0);1676 // @memset(debug_info.items[segment_size..], 0);
1678 }1677 // }
1679 debug_info.items.len = needed_size;1678 // debug_info.items.len = needed_size;
1680 }1679 // }
1681 log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{1680 // log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{
1682 debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size,1681 // debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size,
1683 });1682 // });
1684 try writeDbgInfoNopsToArrayList(1683 // try writeDbgInfoNopsToArrayList(
1685 gpa,1684 // gpa,
1686 debug_info,1685 // debug_info,
1687 atom.off,1686 // atom.off,
1688 prev_padding_size,1687 // prev_padding_size,
1689 dbg_info_buf,1688 // dbg_info_buf,
1690 next_padding_size,1689 // next_padding_size,
1691 trailing_zero,1690 // trailing_zero,
1692 );1691 // );
1693 },1692 },
1694 else => unreachable,1693 else => unreachable,
1695 }1694 }
...@@ -1735,10 +1734,10 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D...@@ -1735,10 +1734,10 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: InternPool.D
1735 }1734 }
1736 },1735 },
1737 .wasm => {1736 .wasm => {
1738 const wasm_file = self.bin_file.cast(File.Wasm).?;1737 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1739 const offset = atom.off + self.getRelocDbgLineOff();1738 // const offset = atom.off + self.getRelocDbgLineOff();
1740 const line_atom_index = wasm_file.debug_line_atom.?;1739 // const line_atom_index = wasm_file.debug_line_atom.?;
1741 wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data;1740 // wasm_file.getAtomPtr(line_atom_index).code.items[offset..][0..data.len].* = data;
1742 },1741 },
1743 else => unreachable,1742 else => unreachable,
1744 }1743 }
...@@ -1803,7 +1802,6 @@ pub fn freeDecl(self: *Dwarf, decl_index: InternPool.DeclIndex) void {...@@ -1803,7 +1802,6 @@ pub fn freeDecl(self: *Dwarf, decl_index: InternPool.DeclIndex) void {
1803}1802}
18041803
1805pub fn writeDbgAbbrev(self: *Dwarf) !void {1804pub fn writeDbgAbbrev(self: *Dwarf) !void {
1806 const gpa = self.allocator;
1807 // These are LEB encoded but since the values are all less than 1271805 // These are LEB encoded but since the values are all less than 127
1808 // we can simply append these bytes.1806 // we can simply append these bytes.
1809 // zig fmt: off1807 // zig fmt: off
...@@ -1960,10 +1958,10 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {...@@ -1960,10 +1958,10 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
1960 }1958 }
1961 },1959 },
1962 .wasm => {1960 .wasm => {
1963 const wasm_file = self.bin_file.cast(File.Wasm).?;1961 // const wasm_file = self.bin_file.cast(File.Wasm).?;
1964 const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;1962 // const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
1965 try debug_abbrev.resize(gpa, needed_size);1963 // try debug_abbrev.resize(gpa, needed_size);
1966 debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf;1964 // debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf;
1967 },1965 },
1968 else => unreachable,1966 else => unreachable,
1969 }1967 }
...@@ -2055,9 +2053,9 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64)...@@ -2055,9 +2053,9 @@ pub fn writeDbgInfoHeader(self: *Dwarf, zcu: *Module, low_pc: u64, high_pc: u64)
2055 }2053 }
2056 },2054 },
2057 .wasm => {2055 .wasm => {
2058 const wasm_file = self.bin_file.cast(File.Wasm).?;2056 // const wasm_file = self.bin_file.cast(File.Wasm).?;
2059 const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;2057 // const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2060 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);2058 // try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
2061 },2059 },
2062 else => unreachable,2060 else => unreachable,
2063 }2061 }
...@@ -2318,7 +2316,6 @@ fn writeDbgInfoNopsToArrayList(...@@ -2318,7 +2316,6 @@ fn writeDbgInfoNopsToArrayList(
23182316
2319pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {2317pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2320 const comp = self.bin_file.comp;2318 const comp = self.bin_file.comp;
2321 const gpa = comp.gpa;
2322 const target = comp.root_mod.resolved_target.result;2319 const target = comp.root_mod.resolved_target.result;
2323 const target_endian = target.cpu.arch.endian();2320 const target_endian = target.cpu.arch.endian();
2324 const ptr_width_bytes = self.ptrWidthBytes();2321 const ptr_width_bytes = self.ptrWidthBytes();
...@@ -2391,10 +2388,10 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2391,10 +2388,10 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2391 }2388 }
2392 },2389 },
2393 .wasm => {2390 .wasm => {
2394 const wasm_file = self.bin_file.cast(File.Wasm).?;2391 // const wasm_file = self.bin_file.cast(File.Wasm).?;
2395 const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;2392 // const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;
2396 try debug_ranges.resize(gpa, needed_size);2393 // try debug_ranges.resize(gpa, needed_size);
2397 @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items);2394 // @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items);
2398 },2395 },
2399 else => unreachable,2396 else => unreachable,
2400 }2397 }
...@@ -2548,14 +2545,15 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2548,14 +2545,15 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2548 }2545 }
2549 },2546 },
2550 .wasm => {2547 .wasm => {
2551 const wasm_file = self.bin_file.cast(File.Wasm).?;2548 _ = &buffer;
2552 const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;2549 // const wasm_file = self.bin_file.cast(File.Wasm).?;
2553 {2550 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2554 const src = debug_line.items[first_fn.off..];2551 // {
2555 @memcpy(buffer[0..src.len], src);2552 // const src = debug_line.items[first_fn.off..];
2556 }2553 // @memcpy(buffer[0..src.len], src);
2557 try debug_line.resize(self.allocator, debug_line.items.len + delta);2554 // }
2558 @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer);2555 // try debug_line.resize(self.allocator, debug_line.items.len + delta);
2556 // @memcpy(debug_line.items[first_fn.off + delta ..][0..buffer.len], buffer);
2559 },2557 },
2560 else => unreachable,2558 else => unreachable,
2561 }2559 }
...@@ -2604,9 +2602,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2604,9 +2602,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2604 }2602 }
2605 },2603 },
2606 .wasm => {2604 .wasm => {
2607 const wasm_file = self.bin_file.cast(File.Wasm).?;2605 // const wasm_file = self.bin_file.cast(File.Wasm).?;
2608 const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;2606 // const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2609 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);2607 // writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
2610 },2608 },
2611 else => unreachable,2609 else => unreachable,
2612 }2610 }
...@@ -2754,9 +2752,9 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2754,9 +2752,9 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2754 }2752 }
2755 },2753 },
2756 .wasm => {2754 .wasm => {
2757 const wasm_file = self.bin_file.cast(File.Wasm).?;2755 // const wasm_file = self.bin_file.cast(File.Wasm).?;
2758 const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;2756 // const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2759 debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf;2757 // debug_info.items[atom.off + reloc.offset ..][0..buf.len].* = buf;
2760 },2758 },
2761 else => unreachable,2759 else => unreachable,
2762 }2760 }
src/link/Wasm.zig+132-1081
...@@ -37,12 +37,22 @@ pub const Relocation = types.Relocation;...@@ -37,12 +37,22 @@ pub const Relocation = types.Relocation;
37pub const base_tag: link.File.Tag = .wasm;37pub const base_tag: link.File.Tag = .wasm;
3838
39base: link.File,39base: link.File,
40/// Symbol name of the entry function to export
40entry_name: ?[]const u8,41entry_name: ?[]const u8,
42/// When true, will allow undefined symbols
41import_symbols: bool,43import_symbols: bool,
44/// List of *global* symbol names to export to the host environment.
42export_symbol_names: []const []const u8,45export_symbol_names: []const []const u8,
46/// When defined, sets the start of the data section.
43global_base: ?u64,47global_base: ?u64,
48/// When defined, sets the initial memory size of the memory.
44initial_memory: ?u64,49initial_memory: ?u64,
50/// When defined, sets the maximum memory size of the memory.
45max_memory: ?u64,51max_memory: ?u64,
52/// When true, will import the function table from the host environment.
53import_table: bool,
54/// When true, will export the function table to the host environment.
55export_table: bool,
46/// Output name of the file56/// Output name of the file
47name: []const u8,57name: []const u8,
48/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.58/// 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,...@@ -52,16 +62,8 @@ llvm_object: ?*LlvmObject = null,
52/// to support existing code.62/// to support existing code.
53/// TODO: Allow setting this through a flag?63/// TODO: Allow setting this through a flag?
54host_name: []const u8 = "env",64host_name: []const u8 = "env",
55/// List of all `Decl` that are currently alive.
56/// Each index maps to the corresponding `Atom.Index`.
57decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{},
58/// Mapping between an `Atom` and its type index representing the Wasm
59/// type of the function signature.
60atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .{},
61/// List of all symbols generated by Zig code.65/// List of all symbols generated by Zig code.
62symbols: std.ArrayListUnmanaged(Symbol) = .{},66synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .{},
63/// List of symbol indexes which are free to be used.
64symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
65/// Maps atoms to their segment index67/// Maps atoms to their segment index
66atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},68atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
67/// List of all atoms.69/// List of all atoms.
...@@ -107,8 +109,6 @@ data_segments: std.StringArrayHashMapUnmanaged(u32) = .{},...@@ -107,8 +109,6 @@ data_segments: std.StringArrayHashMapUnmanaged(u32) = .{},
107segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{},109segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{},
108/// Deduplicated string table for strings used by symbols, imports and exports.110/// Deduplicated string table for strings used by symbols, imports and exports.
109string_table: StringTable = .{},111string_table: StringTable = .{},
110/// Debug information for wasm
111dwarf: ?Dwarf = null,
112112
113// Output sections113// Output sections
114/// Output type section114/// Output type section
...@@ -170,36 +170,10 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{},...@@ -170,36 +170,10 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{},
170/// Note: The value represents the offset into the string table, rather than the actual string.170/// Note: The value represents the offset into the string table, rather than the actual string.
171export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},171export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
172172
173/// Represents the symbol index of the error name table
174/// When this is `null`, no code references an error using runtime `@errorName`.
175/// During initializion, a symbol with corresponding atom will be created that is
176/// used to perform relocations to the pointer of this table.
177/// The actual table is populated during `flush`.
178error_table_symbol: ?u32 = null,
179
180// Debug section atoms. These are only set when the current compilation
181// unit contains Zig code. The lifetime of these atoms are extended
182// until the end of the compiler's lifetime. Meaning they're not freed
183// during `flush()` in incremental-mode.
184debug_info_atom: ?Atom.Index = null,
185debug_line_atom: ?Atom.Index = null,
186debug_loc_atom: ?Atom.Index = null,
187debug_ranges_atom: ?Atom.Index = null,
188debug_abbrev_atom: ?Atom.Index = null,
189debug_str_atom: ?Atom.Index = null,
190debug_pubnames_atom: ?Atom.Index = null,
191debug_pubtypes_atom: ?Atom.Index = null,
192
193/// List of atom indexes of functions that are generated by the backend,173/// List of atom indexes of functions that are generated by the backend,
194/// rather than by the linker.174/// rather than by the linker.
195synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},175synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
196176
197/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
198anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
199
200import_table: bool,
201export_table: bool,
202
203pub const Alignment = types.Alignment;177pub const Alignment = types.Alignment;
204178
205pub const Segment = struct {179pub const Segment = struct {
...@@ -238,27 +212,27 @@ pub const SymbolLoc = struct {...@@ -238,27 +212,27 @@ pub const SymbolLoc = struct {
238 file: ?u16,212 file: ?u16,
239213
240 /// From a given location, returns the corresponding symbol in the wasm binary214 /// From a given location, returns the corresponding symbol in the wasm binary
241 pub fn getSymbol(loc: SymbolLoc, wasm_bin: *const Wasm) *Symbol {215 pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol {
242 if (wasm_bin.discarded.get(loc)) |new_loc| {216 if (wasm_file.discarded.get(loc)) |new_loc| {
243 return new_loc.getSymbol(wasm_bin);217 return new_loc.getSymbol(wasm_file);
244 }218 }
245 if (loc.file) |object_index| {219 if (loc.file) |object_index| {
246 const object = wasm_bin.objects.items[object_index];220 const object = wasm_file.objects.items[object_index];
247 return &object.symtable[loc.index];221 return &object.symtable[loc.index];
248 }222 }
249 return &wasm_bin.symbols.items[loc.index];223 return &wasm_file.synthetic_symbols.items[loc.index];
250 }224 }
251225
252 /// From a given location, returns the name of the symbol.226 /// From a given location, returns the name of the symbol.
253 pub fn getName(loc: SymbolLoc, wasm_bin: *const Wasm) []const u8 {227 pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 {
254 if (wasm_bin.discarded.get(loc)) |new_loc| {228 if (wasm_file.discarded.get(loc)) |new_loc| {
255 return new_loc.getName(wasm_bin);229 return new_loc.getName(wasm_file);
256 }230 }
257 if (loc.file) |object_index| {231 if (loc.file) |object_index| {
258 const object = wasm_bin.objects.items[object_index];232 const object = wasm_file.objects.items[object_index];
259 return object.string_table.get(object.symtable[loc.index].name);233 return object.string_table.get(object.symtable[loc.index].name);
260 }234 }
261 return wasm_bin.string_table.get(wasm_bin.symbols.items[loc.index].name);235 return wasm_file.string_table.get(wasm_file.synthetic_symbols.items[loc.index].name);
262 }236 }
263237
264 /// From a given symbol location, returns the final location.238 /// From a given symbol location, returns the final location.
...@@ -266,9 +240,9 @@ pub const SymbolLoc = struct {...@@ -266,9 +240,9 @@ pub const SymbolLoc = struct {
266 /// in a different file, this will return said location.240 /// in a different file, this will return said location.
267 /// If the symbol wasn't replaced by another, this will return241 /// If the symbol wasn't replaced by another, this will return
268 /// the given location itwasm.242 /// the given location itwasm.
269 pub fn finalLoc(loc: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc {243 pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc {
270 if (wasm_bin.discarded.get(loc)) |new_loc| {244 if (wasm_file.discarded.get(loc)) |new_loc| {
271 return new_loc.finalLoc(wasm_bin);245 return new_loc.finalLoc(wasm_file);
272 }246 }
273 return loc;247 return loc;
274 }248 }
...@@ -594,10 +568,10 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol...@@ -594,10 +568,10 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol
594}568}
595569
596fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {570fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
597 const sym_index = @as(u32, @intCast(wasm.symbols.items.len));571 const sym_index = @as(u32, @intCast(wasm.synthetic_symbols.items.len));
598 const loc: SymbolLoc = .{ .index = sym_index, .file = null };572 const loc: SymbolLoc = .{ .index = sym_index, .file = null };
599 const gpa = wasm.base.comp.gpa;573 const gpa = wasm.base.comp.gpa;
600 try wasm.symbols.append(gpa, .{574 try wasm.synthetic_symbols.append(gpa, .{
601 .name = name_offset,575 .name = name_offset,
602 .flags = 0,576 .flags = 0,
603 .tag = tag,577 .tag = tag,
...@@ -609,24 +583,6 @@ fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !...@@ -609,24 +583,6 @@ fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !
609 return loc;583 return loc;
610}584}
611585
612/// Initializes symbols and atoms for the debug sections
613/// Initialization is only done when compiling Zig code.
614/// When Zig is invoked as a linker instead, the atoms
615/// and symbols come from the object files instead.
616pub fn initDebugSections(wasm: *Wasm) !void {
617 if (wasm.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections
618 assert(wasm.debug_info_index == null);
619 // this will create an Atom and set the index for us.
620 wasm.debug_info_atom = try wasm.createDebugSectionForIndex(&wasm.debug_info_index, ".debug_info");
621 wasm.debug_line_atom = try wasm.createDebugSectionForIndex(&wasm.debug_line_index, ".debug_line");
622 wasm.debug_loc_atom = try wasm.createDebugSectionForIndex(&wasm.debug_loc_index, ".debug_loc");
623 wasm.debug_abbrev_atom = try wasm.createDebugSectionForIndex(&wasm.debug_abbrev_index, ".debug_abbrev");
624 wasm.debug_ranges_atom = try wasm.createDebugSectionForIndex(&wasm.debug_ranges_index, ".debug_ranges");
625 wasm.debug_str_atom = try wasm.createDebugSectionForIndex(&wasm.debug_str_index, ".debug_str");
626 wasm.debug_pubnames_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubnames_index, ".debug_pubnames");
627 wasm.debug_pubtypes_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubtypes_index, ".debug_pubtypes");
628}
629
630fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {586fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {
631 for (files) |path| {587 for (files) |path| {
632 if (try wasm.parseObjectFile(path)) continue;588 if (try wasm.parseObjectFile(path)) continue;
...@@ -652,33 +608,14 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -652,33 +608,14 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
652 return true;608 return true;
653}609}
654610
655/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
656/// When the index was not found, a new `Atom` will be created, and its index will be returned.
657/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
658pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index {
659 const gpa = wasm.base.comp.gpa;
660 const gop = try wasm.decls.getOrPut(gpa, decl_index);
661 if (!gop.found_existing) {
662 const atom_index = try wasm.createAtom();
663 gop.value_ptr.* = atom_index;
664 const atom = wasm.getAtom(atom_index);
665 const symbol = atom.symbolLoc().getSymbol(wasm);
666 const mod = wasm.base.comp.module.?;
667 const decl = mod.declPtr(decl_index);
668 const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
669 symbol.name = try wasm.string_table.put(gpa, full_name);
670 }
671 return gop.value_ptr.*;
672}
673
674/// Creates a new empty `Atom` and returns its `Atom.Index`611/// Creates a new empty `Atom` and returns its `Atom.Index`
675fn createAtom(wasm: *Wasm) !Atom.Index {612pub fn createAtom(wasm: *Wasm, sym_index: u32) !Atom.Index {
676 const gpa = wasm.base.comp.gpa;613 const gpa = wasm.base.comp.gpa;
677 const index: Atom.Index = @intCast(wasm.managed_atoms.items.len);614 const index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
678 const atom = try wasm.managed_atoms.addOne(gpa);615 const atom = try wasm.managed_atoms.addOne(gpa);
679 atom.* = Atom.empty;616 atom.* = Atom.empty;
680 atom.sym_index = try wasm.allocateSymbol();617 atom.sym_index = sym_index;
681 try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = atom.sym_index }, index);618 try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = sym_index }, index);
682619
683 return index;620 return index;
684}621}
...@@ -1386,40 +1323,12 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1386,40 +1323,12 @@ pub fn deinit(wasm: *Wasm) void {
1386 archive.deinit(gpa);1323 archive.deinit(gpa);
1387 }1324 }
13881325
1389 // For decls and anon decls we free the memory of its atoms.
1390 // The memory of atoms parsed from object files is managed by
1391 // the object file itself, and therefore we can skip those.
1392 {
1393 var it = wasm.decls.valueIterator();
1394 while (it.next()) |atom_index_ptr| {
1395 const atom = wasm.getAtomPtr(atom_index_ptr.*);
1396 for (atom.locals.items) |local_index| {
1397 const local_atom = wasm.getAtomPtr(local_index);
1398 local_atom.deinit(gpa);
1399 }
1400 atom.deinit(gpa);
1401 }
1402 }
1403 {
1404 for (wasm.anon_decls.values()) |atom_index| {
1405 const atom = wasm.getAtomPtr(atom_index);
1406 for (atom.locals.items) |local_index| {
1407 const local_atom = wasm.getAtomPtr(local_index);
1408 local_atom.deinit(gpa);
1409 }
1410 atom.deinit(gpa);
1411 }
1412 }
1413 for (wasm.synthetic_functions.items) |atom_index| {1326 for (wasm.synthetic_functions.items) |atom_index| {
1414 const atom = wasm.getAtomPtr(atom_index);1327 const atom = wasm.getAtomPtr(atom_index);
1415 atom.deinit(gpa);1328 atom.deinit(gpa);
1416 }1329 }
14171330
1418 wasm.decls.deinit(gpa);1331 wasm.synthetic_symbols.deinit(gpa);
1419 wasm.anon_decls.deinit(gpa);
1420 wasm.atom_types.deinit(gpa);
1421 wasm.symbols.deinit(gpa);
1422 wasm.symbols_free_list.deinit(gpa);
1423 wasm.globals.deinit(gpa);1332 wasm.globals.deinit(gpa);
1424 wasm.resolved_symbols.deinit(gpa);1333 wasm.resolved_symbols.deinit(gpa);
1425 wasm.undefs.deinit(gpa);1334 wasm.undefs.deinit(gpa);
...@@ -1446,32 +1355,6 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1446,32 +1355,6 @@ pub fn deinit(wasm: *Wasm) void {
14461355
1447 wasm.string_table.deinit(gpa);1356 wasm.string_table.deinit(gpa);
1448 wasm.synthetic_functions.deinit(gpa);1357 wasm.synthetic_functions.deinit(gpa);
1449
1450 if (wasm.dwarf) |*dwarf| {
1451 dwarf.deinit();
1452 }
1453}
1454
1455/// Allocates a new symbol and returns its index.
1456/// Will re-use slots when a symbol was freed at an earlier stage.
1457pub fn allocateSymbol(wasm: *Wasm) !u32 {
1458 const gpa = wasm.base.comp.gpa;
1459
1460 try wasm.symbols.ensureUnusedCapacity(gpa, 1);
1461 const symbol: Symbol = .{
1462 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls
1463 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1464 .tag = .undefined, // will be set after updateDecl
1465 .index = std.math.maxInt(u32), // will be set during atom parsing
1466 .virtual_address = std.math.maxInt(u32), // will be set during atom allocation
1467 };
1468 if (wasm.symbols_free_list.popOrNull()) |index| {
1469 wasm.symbols.items[index] = symbol;
1470 return index;
1471 }
1472 const index = @as(u32, @intCast(wasm.symbols.items.len));
1473 wasm.symbols.appendAssumeCapacity(symbol);
1474 return index;
1475}1358}
14761359
1477pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {1360pub 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) !...@@ -1546,84 +1429,12 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !
1546 @panic("Attempted to compile for object format that was disabled by build configuration");1429 @panic("Attempted to compile for object format that was disabled by build configuration");
1547 }1430 }
1548 if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);1431 if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
1549
1550 const tracy = trace(@src());
1551 defer tracy.end();
1552
1553 const decl = mod.declPtr(decl_index);
1554 if (decl.val.getFunction(mod)) |_| {
1555 return;
1556 } else if (decl.val.getExternFunc(mod)) |_| {
1557 return;
1558 }
1559
1560 const gpa = wasm.base.comp.gpa;
1561 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1562 const atom = wasm.getAtomPtr(atom_index);
1563 atom.clear();
1564
1565 if (decl.isExtern(mod)) {
1566 const variable = decl.getOwnedVariable(mod).?;
1567 const name = mod.intern_pool.stringToSlice(decl.name);
1568 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
1569 return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null);
1570 }
1571 const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
1572
1573 var code_writer = std.ArrayList(u8).init(gpa);
1574 defer code_writer.deinit();
1575
1576 const res = try codegen.generateSymbol(
1577 &wasm.base,
1578 decl.srcLoc(mod),
1579 .{ .ty = decl.ty, .val = val },
1580 &code_writer,
1581 .none,
1582 .{ .parent_atom_index = atom.sym_index },
1583 );
1584
1585 const code = switch (res) {
1586 .ok => code_writer.items,
1587 .fail => |em| {
1588 decl.analysis = .codegen_failure;
1589 try mod.failed_decls.put(mod.gpa, decl_index, em);
1590 return;
1591 },
1592 };
1593
1594 return wasm.finishUpdateDecl(decl_index, code, .data);
1595}1432}
15961433
1597pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !void {1434pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !void {
1598 if (wasm.llvm_object) |_| return;1435 if (wasm.llvm_object) |_| return;
1599 if (wasm.dwarf) |*dw| {1436 _ = mod;
1600 const tracy = trace(@src());1437 _ = decl_index;
1601 defer tracy.end();
1602
1603 const decl = mod.declPtr(decl_index);
1604 const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
1605
1606 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1607 try dw.updateDeclLineNumber(mod, decl_index);
1608 }
1609}
1610
1611fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void {
1612 const gpa = wasm.base.comp.gpa;
1613 const mod = wasm.base.comp.module.?;
1614 const decl = mod.declPtr(decl_index);
1615 const atom_index = wasm.decls.get(decl_index).?;
1616 const atom = wasm.getAtomPtr(atom_index);
1617 const symbol = &wasm.symbols.items[atom.sym_index];
1618 const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
1619 symbol.name = try wasm.string_table.put(gpa, full_name);
1620 symbol.tag = symbol_tag;
1621 try atom.code.appendSlice(gpa, code);
1622 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
1623
1624 atom.size = @intCast(code.len);
1625 if (code.len == 0) return;
1626 atom.alignment = decl.getAlignment(mod);
1627}1438}
16281439
1629/// From a given symbol location, returns its `wasm.GlobalType`.1440/// From a given symbol location, returns its `wasm.GlobalType`.
...@@ -1673,82 +1484,9 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {...@@ -1673,82 +1484,9 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1673/// Returns the symbol index of the local1484/// Returns the symbol index of the local
1674/// The given `decl` is the parent decl whom owns the constant.1485/// The given `decl` is the parent decl whom owns the constant.
1675pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {1486pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
1676 const gpa = wasm.base.comp.gpa;1487 _ = wasm;
1677 const mod = wasm.base.comp.module.?;1488 _ = tv;
1678 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions1489 _ = decl_index;
1679 const decl = mod.declPtr(decl_index);
1680
1681 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1682 const parent_atom = wasm.getAtom(parent_atom_index);
1683 const local_index = parent_atom.locals.items.len;
1684 const fqn = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
1685 const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{
1686 fqn, local_index,
1687 });
1688 defer gpa.free(name);
1689
1690 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
1691 .ok => |atom_index| {
1692 try wasm.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index);
1693 return wasm.getAtom(atom_index).getSymbolIndex().?;
1694 },
1695 .fail => |em| {
1696 decl.analysis = .codegen_failure;
1697 try mod.failed_decls.put(mod.gpa, decl_index, em);
1698 return error.CodegenFail;
1699 },
1700 }
1701}
1702
1703const LowerConstResult = union(enum) {
1704 ok: Atom.Index,
1705 fail: *Module.ErrorMsg,
1706};
1707
1708fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
1709 const gpa = wasm.base.comp.gpa;
1710 const mod = wasm.base.comp.module.?;
1711
1712 // Create and initialize a new local symbol and atom
1713 const atom_index = try wasm.createAtom();
1714 var value_bytes = std.ArrayList(u8).init(gpa);
1715 defer value_bytes.deinit();
1716
1717 const code = code: {
1718 const atom = wasm.getAtomPtr(atom_index);
1719 atom.alignment = tv.ty.abiAlignment(mod);
1720 wasm.symbols.items[atom.sym_index] = .{
1721 .name = try wasm.string_table.put(gpa, name),
1722 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1723 .tag = .data,
1724 .index = undefined,
1725 .virtual_address = undefined,
1726 };
1727 try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {});
1728
1729 const result = try codegen.generateSymbol(
1730 &wasm.base,
1731 src_loc,
1732 tv,
1733 &value_bytes,
1734 .none,
1735 .{
1736 .parent_atom_index = atom.sym_index,
1737 .addend = null,
1738 },
1739 );
1740 break :code switch (result) {
1741 .ok => value_bytes.items,
1742 .fail => |em| {
1743 return .{ .fail = em };
1744 },
1745 };
1746 };
1747
1748 const atom = wasm.getAtomPtr(atom_index);
1749 atom.size = @intCast(code.len);
1750 try atom.code.appendSlice(gpa, code);
1751 return .{ .ok = atom_index };
1752}1490}
17531491
1754/// Returns the symbol index from a symbol of which its flag is set global,1492/// 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...@@ -1757,34 +1495,8 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src
1757/// and then returns the index to it.1495/// and then returns the index to it.
1758pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {1496pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {
1759 _ = lib_name;1497 _ = lib_name;
1760 const gpa = wasm.base.comp.gpa;1498 _ = name;
1761 const name_index = try wasm.string_table.put(gpa, name);1499 _ = wasm;
1762 const gop = try wasm.globals.getOrPut(gpa, name_index);
1763 if (gop.found_existing) {
1764 return gop.value_ptr.*.index;
1765 }
1766
1767 var symbol: Symbol = .{
1768 .name = name_index,
1769 .flags = 0,
1770 .index = undefined, // index to type will be set after merging function symbols
1771 .tag = .function,
1772 .virtual_address = undefined,
1773 };
1774 symbol.setGlobal(true);
1775 symbol.setUndefined(true);
1776
1777 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: {
1778 const index: u32 = @intCast(wasm.symbols.items.len);
1779 try wasm.symbols.ensureUnusedCapacity(gpa, 1);
1780 wasm.symbols.items.len += 1;
1781 break :blk index;
1782 };
1783 wasm.symbols.items[sym_index] = symbol;
1784 gop.value_ptr.* = .{ .index = sym_index, .file = null };
1785 try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {});
1786 try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*);
1787 return sym_index;
1788}1500}
17891501
1790/// For a given decl, find the given symbol index's atom, and create a relocation for the type.1502/// 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(...@@ -1794,42 +1506,9 @@ pub fn getDeclVAddr(
1794 decl_index: InternPool.DeclIndex,1506 decl_index: InternPool.DeclIndex,
1795 reloc_info: link.File.RelocInfo,1507 reloc_info: link.File.RelocInfo,
1796) !u64 {1508) !u64 {
1797 const target = wasm.base.comp.root_mod.resolved_target.result;1509 _ = wasm;
1798 const gpa = wasm.base.comp.gpa;1510 _ = decl_index;
1799 const mod = wasm.base.comp.module.?;1511 _ = reloc_info;
1800 const decl = mod.declPtr(decl_index);
1801
1802 const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1803 const target_symbol_index = wasm.getAtom(target_atom_index).sym_index;
1804
1805 assert(reloc_info.parent_atom_index != 0);
1806 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1807 const atom = wasm.getAtomPtr(atom_index);
1808 const is_wasm32 = target.cpu.arch == .wasm32;
1809 if (decl.ty.zigTypeTag(mod) == .Fn) {
1810 assert(reloc_info.addend == 0); // addend not allowed for function relocations
1811 // We found a function pointer, so add it to our table,
1812 // as function pointers are not allowed to be stored inside the data section.
1813 // They are instead stored in a function table which are called by index.
1814 try wasm.addTableFunction(target_symbol_index);
1815 try atom.relocs.append(gpa, .{
1816 .index = target_symbol_index,
1817 .offset = @intCast(reloc_info.offset),
1818 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1819 });
1820 } else {
1821 try atom.relocs.append(gpa, .{
1822 .index = target_symbol_index,
1823 .offset = @intCast(reloc_info.offset),
1824 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1825 .addend = @intCast(reloc_info.addend),
1826 });
1827 }
1828 // we do not know the final address at this point,
1829 // as atom allocation will determine the address and relocations
1830 // will calculate and rewrite this. Therefore, we simply return the symbol index
1831 // that was targeted.
1832 return target_symbol_index;
1833}1512}
18341513
1835pub fn lowerAnonDecl(1514pub fn lowerAnonDecl(
...@@ -1838,70 +1517,16 @@ pub fn lowerAnonDecl(...@@ -1838,70 +1517,16 @@ pub fn lowerAnonDecl(
1838 explicit_alignment: Alignment,1517 explicit_alignment: Alignment,
1839 src_loc: Module.SrcLoc,1518 src_loc: Module.SrcLoc,
1840) !codegen.Result {1519) !codegen.Result {
1841 const gpa = wasm.base.comp.gpa;1520 _ = wasm;
1842 const gop = try wasm.anon_decls.getOrPut(gpa, decl_val);1521 _ = decl_val;
1843 if (!gop.found_existing) {1522 _ = explicit_alignment;
1844 const mod = wasm.base.comp.module.?;1523 _ = src_loc;
1845 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
1846 const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) };
1847 var name_buf: [32]u8 = undefined;
1848 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
1849 @intFromEnum(decl_val),
1850 }) catch unreachable;
1851
1852 switch (try wasm.lowerConst(name, tv, src_loc)) {
1853 .ok => |atom_index| wasm.anon_decls.values()[gop.index] = atom_index,
1854 .fail => |em| return .{ .fail = em },
1855 }
1856 }
1857
1858 const atom = wasm.getAtomPtr(wasm.anon_decls.values()[gop.index]);
1859 atom.alignment = switch (atom.alignment) {
1860 .none => explicit_alignment,
1861 else => switch (explicit_alignment) {
1862 .none => atom.alignment,
1863 else => atom.alignment.maxStrict(explicit_alignment),
1864 },
1865 };
1866 return .ok;
1867}1524}
18681525
1869pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1526pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1870 const gpa = wasm.base.comp.gpa;1527 _ = wasm;
1871 const target = wasm.base.comp.root_mod.resolved_target.result;1528 _ = decl_val;
1872 const atom_index = wasm.anon_decls.get(decl_val).?;1529 _ = reloc_info;
1873 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
1874
1875 const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1876 const parent_atom = wasm.getAtomPtr(parent_atom_index);
1877 const is_wasm32 = target.cpu.arch == .wasm32;
1878 const mod = wasm.base.comp.module.?;
1879 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
1880 if (ty.zigTypeTag(mod) == .Fn) {
1881 assert(reloc_info.addend == 0); // addend not allowed for function relocations
1882 // We found a function pointer, so add it to our table,
1883 // as function pointers are not allowed to be stored inside the data section.
1884 // They are instead stored in a function table which are called by index.
1885 try wasm.addTableFunction(target_symbol_index);
1886 try parent_atom.relocs.append(gpa, .{
1887 .index = target_symbol_index,
1888 .offset = @intCast(reloc_info.offset),
1889 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1890 });
1891 } else {
1892 try parent_atom.relocs.append(gpa, .{
1893 .index = target_symbol_index,
1894 .offset = @intCast(reloc_info.offset),
1895 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1896 .addend = @intCast(reloc_info.addend),
1897 });
1898 }
1899
1900 // we do not know the final address at this point,
1901 // as atom allocation will determine the address and relocations
1902 // will calculate and rewrite this. Therefore, we simply return the symbol index
1903 // that was targeted.
1904 return target_symbol_index;
1905}1530}
19061531
1907pub fn deleteDeclExport(1532pub fn deleteDeclExport(
...@@ -1909,19 +1534,9 @@ pub fn deleteDeclExport(...@@ -1909,19 +1534,9 @@ pub fn deleteDeclExport(
1909 decl_index: InternPool.DeclIndex,1534 decl_index: InternPool.DeclIndex,
1910 name: InternPool.NullTerminatedString,1535 name: InternPool.NullTerminatedString,
1911) void {1536) void {
1912 _ = name;
1913 if (wasm.llvm_object) |_| return;1537 if (wasm.llvm_object) |_| return;
1914 const atom_index = wasm.decls.get(decl_index) orelse return;1538 _ = name;
1915 const sym_index = wasm.getAtom(atom_index).sym_index;1539 _ = decl_index;
1916 const loc: SymbolLoc = .{ .file = null, .index = sym_index };
1917 const symbol = loc.getSymbol(wasm);
1918 const symbol_name = wasm.string_table.get(symbol.name);
1919 log.debug("Deleting export for decl '{s}'", .{symbol_name});
1920 if (wasm.export_names.fetchRemove(loc)) |kv| {
1921 assert(wasm.globals.remove(kv.value));
1922 } else {
1923 assert(wasm.globals.remove(symbol.name));
1924 }
1925}1540}
19261541
1927pub fn updateExports(1542pub fn updateExports(
...@@ -1934,159 +1549,10 @@ pub fn updateExports(...@@ -1934,159 +1549,10 @@ pub fn updateExports(
1934 @panic("Attempted to compile for object format that was disabled by build configuration");1549 @panic("Attempted to compile for object format that was disabled by build configuration");
1935 }1550 }
1936 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);1551 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
1937
1938 const decl_index = switch (exported) {
1939 .decl_index => |i| i,
1940 .value => |val| {
1941 _ = val;
1942 @panic("TODO: implement Wasm linker code for exporting a constant value");
1943 },
1944 };
1945 const decl = mod.declPtr(decl_index);
1946 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1947 const atom = wasm.getAtom(atom_index);
1948 const atom_sym = atom.symbolLoc().getSymbol(wasm).*;
1949 const gpa = mod.gpa;
1950
1951 for (exports) |exp| {
1952 if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| {
1953 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1954 gpa,
1955 decl.srcLoc(mod),
1956 "Unimplemented: ExportOptions.section '{s}'",
1957 .{section},
1958 ));
1959 continue;
1960 }
1961
1962 const exported_decl_index = switch (exp.exported) {
1963 .value => {
1964 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1965 gpa,
1966 decl.srcLoc(mod),
1967 "Unimplemented: exporting a named constant value",
1968 .{},
1969 ));
1970 continue;
1971 },
1972 .decl_index => |i| i,
1973 };
1974 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);
1975 const exported_atom = wasm.getAtom(exported_atom_index);
1976 const export_name = try wasm.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name));
1977 const sym_loc = exported_atom.symbolLoc();
1978 const symbol = sym_loc.getSymbol(wasm);
1979 symbol.setGlobal(true);
1980 symbol.setUndefined(false);
1981 symbol.index = atom_sym.index;
1982 symbol.tag = atom_sym.tag;
1983 symbol.name = atom_sym.name;
1984
1985 switch (exp.opts.linkage) {
1986 .Internal => {
1987 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
1988 symbol.setFlag(.WASM_SYM_BINDING_WEAK);
1989 },
1990 .Weak => {
1991 symbol.setFlag(.WASM_SYM_BINDING_WEAK);
1992 },
1993 .Strong => {}, // symbols are strong by default
1994 .LinkOnce => {
1995 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1996 gpa,
1997 decl.srcLoc(mod),
1998 "Unimplemented: LinkOnce",
1999 .{},
2000 ));
2001 continue;
2002 },
2003 }
2004
2005 if (wasm.globals.get(export_name)) |existing_loc| {
2006 if (existing_loc.index == atom.sym_index) continue;
2007 const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
2008
2009 if (!existing_sym.isUndefined()) blk: {
2010 if (symbol.isWeak()) {
2011 try wasm.discarded.put(gpa, existing_loc, sym_loc);
2012 continue; // to-be-exported symbol is weak, so we keep the existing symbol
2013 }
2014
2015 // new symbol is not weak while existing is, replace existing symbol
2016 if (existing_sym.isWeak()) {
2017 break :blk;
2018 }
2019 // When both the to-be-exported symbol and the already existing symbol
2020 // are strong symbols, we have a linker error.
2021 // In the other case we replace one with the other.
2022 try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create(
2023 gpa,
2024 decl.srcLoc(mod),
2025 \\LinkError: symbol '{}' defined multiple times
2026 \\ first definition in '{s}'
2027 \\ next definition in '{s}'
2028 ,
2029 .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name },
2030 ));
2031 continue;
2032 }
2033
2034 // in this case the existing symbol must be replaced either because it's weak or undefined.
2035 try wasm.discarded.put(gpa, existing_loc, sym_loc);
2036 _ = wasm.imports.remove(existing_loc);
2037 _ = wasm.undefs.swapRemove(existing_sym.name);
2038 }
2039
2040 // Ensure the symbol will be exported using the given name
2041 if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) {
2042 try wasm.export_names.put(gpa, sym_loc, export_name);
2043 }
2044
2045 try wasm.globals.put(
2046 gpa,
2047 export_name,
2048 sym_loc,
2049 );
2050 }
2051}1552}
20521553
2053pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {1554pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
2054 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);1555 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
2055 const gpa = wasm.base.comp.gpa;
2056 const mod = wasm.base.comp.module.?;
2057 const decl = mod.declPtr(decl_index);
2058 const atom_index = wasm.decls.get(decl_index).?;
2059 const atom = wasm.getAtomPtr(atom_index);
2060 atom.prev = null;
2061 wasm.symbols_free_list.append(gpa, atom.sym_index) catch {};
2062 _ = wasm.decls.remove(decl_index);
2063 wasm.symbols.items[atom.sym_index].tag = .dead;
2064 for (atom.locals.items) |local_atom_index| {
2065 const local_atom = wasm.getAtom(local_atom_index);
2066 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
2067 local_symbol.tag = .dead; // also for any local symbol
2068 wasm.symbols_free_list.append(gpa, local_atom.sym_index) catch {};
2069 assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc()));
2070 assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));
2071 }
2072
2073 if (decl.isExtern(mod)) {
2074 _ = wasm.imports.remove(atom.symbolLoc());
2075 }
2076 _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());
2077 _ = wasm.symbol_atom.remove(atom.symbolLoc());
2078
2079 // if (wasm.dwarf) |*dwarf| {
2080 // dwarf.freeDecl(decl_index);
2081 // }
2082
2083}
2084
2085/// Appends a new entry to the indirect function table
2086pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {
2087 const gpa = wasm.base.comp.gpa;
2088 const index: u32 = @intCast(wasm.function_table.count());
2089 try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index);
2090}1556}
20911557
2092/// Assigns indexes to all indirect functions.1558/// Assigns indexes to all indirect functions.
...@@ -2118,203 +1584,6 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -2118,203 +1584,6 @@ fn mapFunctionTable(wasm: *Wasm) void {
2118 }1584 }
2119}1585}
21201586
2121/// Either creates a new import, or updates one if existing.
2122/// When `type_index` is non-null, we assume an external function.
2123/// In all other cases, a data-symbol will be created instead.
2124pub fn addOrUpdateImport(
2125 wasm: *Wasm,
2126 /// Name of the import
2127 name: []const u8,
2128 /// Symbol index that is external
2129 symbol_index: u32,
2130 /// Optional library name (i.e. `extern "c" fn foo() void`
2131 lib_name: ?[:0]const u8,
2132 /// The index of the type that represents the function signature
2133 /// when the extern is a function. When this is null, a data-symbol
2134 /// is asserted instead.
2135 type_index: ?u32,
2136) !void {
2137 const gpa = wasm.base.comp.gpa;
2138 assert(symbol_index != 0);
2139 // For the import name, we use the decl's name, rather than the fully qualified name
2140 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same
2141 // name but different module can be resolved correctly.
2142 const mangle_name = lib_name != null and
2143 !std.mem.eql(u8, lib_name.?, "c");
2144 const full_name = if (mangle_name) full_name: {
2145 break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? });
2146 } else name;
2147 defer if (mangle_name) gpa.free(full_name);
2148
2149 const decl_name_index = try wasm.string_table.put(gpa, full_name);
2150 const symbol: *Symbol = &wasm.symbols.items[symbol_index];
2151 symbol.setUndefined(true);
2152 symbol.setGlobal(true);
2153 symbol.name = decl_name_index;
2154 if (mangle_name) {
2155 // we specified a specific name for the symbol that does not match the import name
2156 symbol.setFlag(.WASM_SYM_EXPLICIT_NAME);
2157 }
2158 const global_gop = try wasm.globals.getOrPut(gpa, decl_name_index);
2159 if (!global_gop.found_existing) {
2160 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };
2161 global_gop.value_ptr.* = loc;
2162 try wasm.resolved_symbols.put(gpa, loc, {});
2163 try wasm.undefs.putNoClobber(gpa, decl_name_index, loc);
2164 } else if (global_gop.value_ptr.*.index != symbol_index) {
2165 // We are not updating a symbol, but found an existing global
2166 // symbol with the same name. This means we always favor the
2167 // existing symbol, regardless whether it's defined or not.
2168 // We can also skip storing the import as we will not output
2169 // this symbol.
2170 return wasm.discarded.put(
2171 gpa,
2172 .{ .file = null, .index = symbol_index },
2173 global_gop.value_ptr.*,
2174 );
2175 }
2176
2177 if (type_index) |ty_index| {
2178 const gop = try wasm.imports.getOrPut(gpa, .{ .index = symbol_index, .file = null });
2179 const module_name = if (lib_name) |l_name| blk: {
2180 break :blk l_name;
2181 } else wasm.host_name;
2182 if (!gop.found_existing) {
2183 gop.value_ptr.* = .{
2184 .module_name = try wasm.string_table.put(gpa, module_name),
2185 .name = try wasm.string_table.put(gpa, name),
2186 .kind = .{ .function = ty_index },
2187 };
2188 }
2189 } else {
2190 // non-functions will not be imported from the runtime, but only resolved during link-time
2191 symbol.tag = .data;
2192 }
2193}
2194
2195/// Kind represents the type of an Atom, which is only
2196/// used to parse a decl into an Atom to define in which section
2197/// or segment it should be placed.
2198const Kind = union(enum) {
2199 /// Represents the segment the data symbol should
2200 /// be inserted into.
2201 /// TODO: Add TLS segments
2202 data: enum {
2203 read_only,
2204 uninitialized,
2205 initialized,
2206 },
2207 function: void,
2208
2209 /// Returns the segment name the data kind represents.
2210 /// Asserts `kind` has its active tag set to `data`.
2211 fn segmentName(kind: Kind) []const u8 {
2212 switch (kind.data) {
2213 .read_only => return ".rodata.",
2214 .uninitialized => return ".bss.",
2215 .initialized => return ".data.",
2216 }
2217 }
2218};
2219
2220/// Parses an Atom and inserts its metadata into the corresponding sections.
2221fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2222 const comp = wasm.base.comp;
2223 const gpa = comp.gpa;
2224 const shared_memory = comp.config.shared_memory;
2225 const import_memory = comp.config.import_memory;
2226 const atom = wasm.getAtomPtr(atom_index);
2227 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
2228 const do_garbage_collect = wasm.base.gc_sections;
2229
2230 if (symbol.isDead() and do_garbage_collect) {
2231 // Prevent unreferenced symbols from being parsed.
2232 return;
2233 }
2234
2235 const final_index: u32 = switch (kind) {
2236 .function => result: {
2237 const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count);
2238 const type_index = wasm.atom_types.get(atom_index).?;
2239 try wasm.functions.putNoClobber(
2240 gpa,
2241 .{ .file = null, .index = index },
2242 .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index },
2243 );
2244 symbol.tag = .function;
2245 symbol.index = index;
2246
2247 if (wasm.code_section_index == null) {
2248 wasm.code_section_index = @intCast(wasm.segments.items.len);
2249 try wasm.segments.append(gpa, .{
2250 .alignment = atom.alignment,
2251 .size = atom.size,
2252 .offset = 0,
2253 .flags = 0,
2254 });
2255 }
2256
2257 break :result wasm.code_section_index.?;
2258 },
2259 .data => result: {
2260 const segment_name = try std.mem.concat(gpa, u8, &.{
2261 kind.segmentName(),
2262 wasm.string_table.get(symbol.name),
2263 });
2264 errdefer gpa.free(segment_name);
2265 const segment_info: types.Segment = .{
2266 .name = segment_name,
2267 .alignment = atom.alignment,
2268 .flags = 0,
2269 };
2270 symbol.tag = .data;
2271
2272 // when creating an object file, or importing memory and the data belongs in the .bss segment
2273 // we set the entire region of it to zeroes.
2274 // We do not have to do this when exporting the memory (the default) because the runtime
2275 // will do it for us, and we do not emit the bss segment at all.
2276 if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) {
2277 @memset(atom.code.items, 0);
2278 }
2279
2280 const should_merge = wasm.base.comp.config.output_mode != .Obj;
2281 const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge));
2282 if (gop.found_existing) {
2283 const index = gop.value_ptr.*;
2284 wasm.segments.items[index].size += atom.size;
2285
2286 symbol.index = @intCast(wasm.segment_info.getIndex(index).?);
2287 // segment info already exists, so free its memory
2288 gpa.free(segment_name);
2289 break :result index;
2290 } else {
2291 const index: u32 = @intCast(wasm.segments.items.len);
2292 var flags: u32 = 0;
2293 if (shared_memory) {
2294 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
2295 }
2296 try wasm.segments.append(gpa, .{
2297 .alignment = atom.alignment,
2298 .size = 0,
2299 .offset = 0,
2300 .flags = flags,
2301 });
2302 gop.value_ptr.* = index;
2303
2304 const info_index: u32 = @intCast(wasm.segment_info.count());
2305 try wasm.segment_info.put(gpa, index, segment_info);
2306 symbol.index = info_index;
2307 break :result index;
2308 }
2309 },
2310 };
2311
2312 const segment: *Segment = &wasm.segments.items[final_index];
2313 segment.alignment = segment.alignment.max(atom.alignment);
2314
2315 try wasm.appendAtomAtIndex(final_index, atom_index);
2316}
2317
2318/// From a given index, append the given `Atom` at the back of the linked list.1587/// From a given index, append the given `Atom` at the back of the linked list.
2319/// Simply inserts it into the map of atoms when it doesn't exist yet.1588/// Simply inserts it into the map of atoms when it doesn't exist yet.
2320pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {1589pub 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...@@ -2328,40 +1597,9 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void
2328 }1597 }
2329}1598}
23301599
2331/// Allocates debug atoms into their respective debug sections
2332/// to merge them with maybe-existing debug atoms from object files.
2333fn allocateDebugAtoms(wasm: *Wasm) !void {
2334 if (wasm.dwarf == null) return;
2335
2336 const allocAtom = struct {
2337 fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void {
2338 const index = maybe_index.* orelse idx: {
2339 const index = @as(u32, @intCast(bin.segments.items.len));
2340 try bin.appendDummySegment();
2341 maybe_index.* = index;
2342 break :idx index;
2343 };
2344 const atom = bin.getAtomPtr(atom_index);
2345 atom.size = @as(u32, @intCast(atom.code.items.len));
2346 bin.symbols.items[atom.sym_index].index = index;
2347 try bin.appendAtomAtIndex(index, atom_index);
2348 }
2349 }.f;
2350
2351 try allocAtom(wasm, &wasm.debug_info_index, wasm.debug_info_atom.?);
2352 try allocAtom(wasm, &wasm.debug_line_index, wasm.debug_line_atom.?);
2353 try allocAtom(wasm, &wasm.debug_loc_index, wasm.debug_loc_atom.?);
2354 try allocAtom(wasm, &wasm.debug_str_index, wasm.debug_str_atom.?);
2355 try allocAtom(wasm, &wasm.debug_ranges_index, wasm.debug_ranges_atom.?);
2356 try allocAtom(wasm, &wasm.debug_abbrev_index, wasm.debug_abbrev_atom.?);
2357 try allocAtom(wasm, &wasm.debug_pubnames_index, wasm.debug_pubnames_atom.?);
2358 try allocAtom(wasm, &wasm.debug_pubtypes_index, wasm.debug_pubtypes_atom.?);
2359}
2360
2361fn allocateAtoms(wasm: *Wasm) !void {1600fn allocateAtoms(wasm: *Wasm) !void {
2362 // first sort the data segments1601 // first sort the data segments
2363 try sortDataSegments(wasm);1602 try sortDataSegments(wasm);
2364 try allocateDebugAtoms(wasm);
23651603
2366 var it = wasm.atoms.iterator();1604 var it = wasm.atoms.iterator();
2367 while (it.next()) |entry| {1605 while (it.next()) |entry| {
...@@ -2382,7 +1620,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -2382,7 +1620,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
2382 const sym = if (symbol_loc.file) |object_index| sym: {1620 const sym = if (symbol_loc.file) |object_index| sym: {
2383 const object = wasm.objects.items[object_index];1621 const object = wasm.objects.items[object_index];
2384 break :sym object.symtable[symbol_loc.index];1622 break :sym object.symtable[symbol_loc.index];
2385 } else wasm.symbols.items[symbol_loc.index];1623 } else wasm.synthetic_symbols.items[symbol_loc.index];
23861624
2387 // Dead symbols must be unlinked from the linked-list to prevent them1625 // Dead symbols must be unlinked from the linked-list to prevent them
2388 // from being emit into the binary.1626 // from being emit into the binary.
...@@ -2521,34 +1759,6 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -2521,34 +1759,6 @@ fn setupInitFunctions(wasm: *Wasm) !void {
2521 }1759 }
2522}1760}
25231761
2524/// Generates an atom containing the global error set' size.
2525/// This will only be generated if the symbol exists.
2526fn setupErrorsLen(wasm: *Wasm) !void {
2527 const gpa = wasm.base.comp.gpa;
2528 const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;
2529
2530 const errors_len = wasm.base.comp.module.?.global_error_set.count();
2531 // overwrite existing atom if it already exists (maybe the error set has increased)
2532 // if not, allcoate a new atom.
2533 const atom_index = if (wasm.symbol_atom.get(loc)) |index| blk: {
2534 const atom = wasm.getAtomPtr(index);
2535 atom.deinit(gpa);
2536 break :blk index;
2537 } else new_atom: {
2538 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
2539 try wasm.symbol_atom.put(gpa, loc, atom_index);
2540 try wasm.managed_atoms.append(gpa, undefined);
2541 break :new_atom atom_index;
2542 };
2543 const atom = wasm.getAtomPtr(atom_index);
2544 atom.* = Atom.empty;
2545 atom.sym_index = loc.index;
2546 atom.size = 2;
2547 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
2548
2549 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2550}
2551
2552/// Creates a function body for the `__wasm_call_ctors` symbol.1762/// Creates a function body for the `__wasm_call_ctors` symbol.
2553/// Loops over all constructors found in `init_funcs` and calls them1763/// Loops over all constructors found in `init_funcs` and calls them
2554/// respectively based on their priority which was sorted by `setupInitFunctions`.1764/// respectively based on their priority which was sorted by `setupInitFunctions`.
...@@ -3278,139 +2488,6 @@ fn appendDummySegment(wasm: *Wasm) !void {...@@ -3278,139 +2488,6 @@ fn appendDummySegment(wasm: *Wasm) !void {
3278 });2488 });
3279}2489}
32802490
3281/// Returns the symbol index of the error name table.
3282///
3283/// When the symbol does not yet exist, it will create a new one instead.
3284pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
3285 if (wasm.error_table_symbol) |symbol| {
3286 return symbol;
3287 }
3288
3289 // no error was referenced yet, so create a new symbol and atom for it
3290 // and then return said symbol's index. The final table will be populated
3291 // during `flush` when we know all possible error names.
3292
3293 const gpa = wasm.base.comp.gpa;
3294 const atom_index = try wasm.createAtom();
3295 const atom = wasm.getAtomPtr(atom_index);
3296 const slice_ty = Type.slice_const_u8_sentinel_0;
3297 const mod = wasm.base.comp.module.?;
3298 atom.alignment = slice_ty.abiAlignment(mod);
3299 const sym_index = atom.sym_index;
3300
3301 const sym_name = try wasm.string_table.put(gpa, "__zig_err_name_table");
3302 const symbol = &wasm.symbols.items[sym_index];
3303 symbol.* = .{
3304 .name = sym_name,
3305 .tag = .data,
3306 .flags = 0,
3307 .index = 0,
3308 .virtual_address = undefined,
3309 };
3310 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
3311 symbol.mark();
3312
3313 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
3314
3315 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
3316 wasm.error_table_symbol = sym_index;
3317 return sym_index;
3318}
3319
3320/// Populates the error name table, when `error_table_symbol` is not null.
3321///
3322/// This creates a table that consists of pointers and length to each error name.
3323/// The table is what is being pointed to within the runtime bodies that are generated.
3324fn populateErrorNameTable(wasm: *Wasm) !void {
3325 const gpa = wasm.base.comp.gpa;
3326 const symbol_index = wasm.error_table_symbol orelse return;
3327 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
3328
3329 // Rather than creating a symbol for each individual error name,
3330 // we create a symbol for the entire region of error names. We then calculate
3331 // the pointers into the list using addends which are appended to the relocation.
3332 const names_atom_index = try wasm.createAtom();
3333 const names_atom = wasm.getAtomPtr(names_atom_index);
3334 names_atom.alignment = .@"1";
3335 const sym_name = try wasm.string_table.put(gpa, "__zig_err_names");
3336 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
3337 names_symbol.* = .{
3338 .name = sym_name,
3339 .tag = .data,
3340 .flags = 0,
3341 .index = 0,
3342 .virtual_address = undefined,
3343 };
3344 names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
3345 names_symbol.mark();
3346
3347 log.debug("Populating error names", .{});
3348
3349 // Addend for each relocation to the table
3350 var addend: u32 = 0;
3351 const mod = wasm.base.comp.module.?;
3352 for (mod.global_error_set.keys()) |error_name_nts| {
3353 const atom = wasm.getAtomPtr(atom_index);
3354
3355 const error_name = mod.intern_pool.stringToSlice(error_name_nts);
3356 const len = @as(u32, @intCast(error_name.len + 1)); // names are 0-termianted
3357
3358 const slice_ty = Type.slice_const_u8_sentinel_0;
3359 const offset = @as(u32, @intCast(atom.code.items.len));
3360 // first we create the data for the slice of the name
3361 try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated
3362 try atom.code.writer(gpa).writeInt(u32, len - 1, .little);
3363 // create relocation to the error name
3364 try atom.relocs.append(gpa, .{
3365 .index = names_atom.sym_index,
3366 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
3367 .offset = offset,
3368 .addend = @as(i32, @intCast(addend)),
3369 });
3370 atom.size += @as(u32, @intCast(slice_ty.abiSize(mod)));
3371 addend += len;
3372
3373 // as we updated the error name table, we now store the actual name within the names atom
3374 try names_atom.code.ensureUnusedCapacity(gpa, len);
3375 names_atom.code.appendSliceAssumeCapacity(error_name);
3376 names_atom.code.appendAssumeCapacity(0);
3377
3378 log.debug("Populated error name: '{s}'", .{error_name});
3379 }
3380 names_atom.size = addend;
3381
3382 const name_loc = names_atom.symbolLoc();
3383 try wasm.resolved_symbols.put(gpa, name_loc, {});
3384 try wasm.symbol_atom.put(gpa, name_loc, names_atom_index);
3385
3386 // link the atoms with the rest of the binary so they can be allocated
3387 // and relocations will be performed.
3388 try wasm.parseAtom(atom_index, .{ .data = .read_only });
3389 try wasm.parseAtom(names_atom_index, .{ .data = .read_only });
3390}
3391
3392/// From a given index variable, creates a new debug section.
3393/// This initializes the index, appends a new segment,
3394/// and finally, creates a managed `Atom`.
3395pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
3396 const gpa = wasm.base.comp.gpa;
3397 const new_index: u32 = @intCast(wasm.segments.items.len);
3398 index.* = new_index;
3399 try wasm.appendDummySegment();
3400
3401 const atom_index = try wasm.createAtom();
3402 const atom = wasm.getAtomPtr(atom_index);
3403 wasm.symbols.items[atom.sym_index] = .{
3404 .tag = .section,
3405 .name = try wasm.string_table.put(gpa, name),
3406 .index = 0,
3407 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
3408 };
3409
3410 atom.alignment = .@"1"; // debug sections are always 1-byte-aligned
3411 return atom_index;
3412}
3413
3414fn resetState(wasm: *Wasm) void {2491fn resetState(wasm: *Wasm) void {
3415 const gpa = wasm.base.comp.gpa;2492 const gpa = wasm.base.comp.gpa;
34162493
...@@ -3418,16 +2495,19 @@ fn resetState(wasm: *Wasm) void {...@@ -3418,16 +2495,19 @@ fn resetState(wasm: *Wasm) void {
3418 gpa.free(segment_info.name);2495 gpa.free(segment_info.name);
3419 }2496 }
34202497
3421 var atom_it = wasm.decls.valueIterator();2498 // TODO: Revisit
3422 while (atom_it.next()) |atom_index| {2499 // var atom_it = wasm.decls.valueIterator();
3423 const atom = wasm.getAtomPtr(atom_index.*);2500 // while (atom_it.next()) |atom_index| {
3424 atom.prev = null;2501 // const atom = wasm.getAtomPtr(atom_index.*);
2502 // atom.next = null;
2503 // atom.prev = null;
34252504
3426 for (atom.locals.items) |local_atom_index| {2505 // for (atom.locals.items) |local_atom_index| {
3427 const local_atom = wasm.getAtomPtr(local_atom_index);2506 // const local_atom = wasm.getAtomPtr(local_atom_index);
3428 local_atom.prev = null;2507 // local_atom.next = null;
3429 }2508 // local_atom.prev = null;
3430 }2509 // }
2510 // }
34312511
3432 wasm.functions.clearRetainingCapacity();2512 wasm.functions.clearRetainingCapacity();
3433 wasm.exports.clearRetainingCapacity();2513 wasm.exports.clearRetainingCapacity();
...@@ -3684,7 +2764,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)...@@ -3684,7 +2764,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)
3684 defer sub_prog_node.end();2764 defer sub_prog_node.end();
36852765
3686 // ensure the error names table is populated when an error name is referenced2766 // ensure the error names table is populated when an error name is referenced
3687 try wasm.populateErrorNameTable();2767 // try wasm.populateErrorNameTable();
36882768
3689 const objects = comp.objects;2769 const objects = comp.objects;
36902770
...@@ -3722,66 +2802,66 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)...@@ -3722,66 +2802,66 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)
3722 try wasm.setupInitFunctions();2802 try wasm.setupInitFunctions();
3723 try wasm.setupStart();2803 try wasm.setupStart();
3724 try wasm.markReferences();2804 try wasm.markReferences();
3725 try wasm.setupErrorsLen();2805 // try wasm.setupErrorsLen();
3726 try wasm.setupImports();2806 try wasm.setupImports();
3727 if (comp.module) |mod| {2807 // if (comp.module) |mod| {
3728 var decl_it = wasm.decls.iterator();2808 // var decl_it = wasm.decls.iterator();
3729 while (decl_it.next()) |entry| {2809 // while (decl_it.next()) |entry| {
3730 const decl = mod.declPtr(entry.key_ptr.*);2810 // const decl = mod.declPtr(entry.key_ptr.*);
3731 if (decl.isExtern(mod)) continue;2811 // if (decl.isExtern(mod)) continue;
3732 const atom_index = entry.value_ptr.*;2812 // const atom_index = entry.value_ptr.*;
3733 const atom = wasm.getAtomPtr(atom_index);2813 // const atom = wasm.getAtomPtr(atom_index);
3734 if (decl.ty.zigTypeTag(mod) == .Fn) {2814 // if (decl.ty.zigTypeTag(mod) == .Fn) {
3735 try wasm.parseAtom(atom_index, .function);2815 // try wasm.parseAtom(atom_index, .function);
3736 } else if (decl.getOwnedVariable(mod)) |variable| {2816 // } else if (decl.getOwnedVariable(mod)) |variable| {
3737 if (variable.is_const) {2817 // if (variable.is_const) {
3738 try wasm.parseAtom(atom_index, .{ .data = .read_only });2818 // try wasm.parseAtom(atom_index, .{ .data = .read_only });
3739 } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) {2819 // } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
3740 // for safe build modes, we store the atom in the data segment,2820 // // for safe build modes, we store the atom in the data segment,
3741 // whereas for unsafe build modes we store it in bss.2821 // // whereas for unsafe build modes we store it in bss.
3742 const decl_namespace = mod.namespacePtr(decl.src_namespace);2822 // const decl_namespace = mod.namespacePtr(decl.src_namespace);
3743 const optimize_mode = decl_namespace.file_scope.mod.optimize_mode;2823 // const optimize_mode = decl_namespace.file_scope.mod.optimize_mode;
3744 const is_initialized = switch (optimize_mode) {2824 // const is_initialized = switch (optimize_mode) {
3745 .Debug, .ReleaseSafe => true,2825 // .Debug, .ReleaseSafe => true,
3746 .ReleaseFast, .ReleaseSmall => false,2826 // .ReleaseFast, .ReleaseSmall => false,
3747 };2827 // };
3748 try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized });2828 // try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized });
3749 } else {2829 // } else {
3750 // when the decl is all zeroes, we store the atom in the bss segment,2830 // // when the decl is all zeroes, we store the atom in the bss segment,
3751 // in all other cases it will be in the data segment.2831 // // in all other cases it will be in the data segment.
3752 const is_zeroes = for (atom.code.items) |byte| {2832 // const is_zeroes = for (atom.code.items) |byte| {
3753 if (byte != 0) break false;2833 // if (byte != 0) break false;
3754 } else true;2834 // } else true;
3755 try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized });2835 // try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized });
3756 }2836 // }
3757 } else {2837 // } else {
3758 try wasm.parseAtom(atom_index, .{ .data = .read_only });2838 // try wasm.parseAtom(atom_index, .{ .data = .read_only });
3759 }2839 // }
37602840
3761 // also parse atoms for a decl's locals2841 // // also parse atoms for a decl's locals
3762 for (atom.locals.items) |local_atom_index| {2842 // for (atom.locals.items) |local_atom_index| {
3763 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });2843 // try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
3764 }2844 // }
3765 }2845 // }
3766 // parse anonymous declarations2846 // // parse anonymous declarations
3767 for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| {2847 // for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| {
3768 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));2848 // const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
3769 if (ty.zigTypeTag(mod) == .Fn) {2849 // if (ty.zigTypeTag(mod) == .Fn) {
3770 try wasm.parseAtom(atom_index, .function);2850 // try wasm.parseAtom(atom_index, .function);
3771 } else {2851 // } else {
3772 try wasm.parseAtom(atom_index, .{ .data = .read_only });2852 // try wasm.parseAtom(atom_index, .{ .data = .read_only });
3773 }2853 // }
3774 }2854 // }
37752855
3776 // also parse any backend-generated functions2856 // // also parse any backend-generated functions
3777 for (wasm.synthetic_functions.items) |atom_index| {2857 // for (wasm.synthetic_functions.items) |atom_index| {
3778 try wasm.parseAtom(atom_index, .function);2858 // try wasm.parseAtom(atom_index, .function);
3779 }2859 // }
37802860
3781 if (wasm.dwarf) |*dwarf| {2861 // if (wasm.dwarf) |*dwarf| {
3782 try dwarf.flushModule(comp.module.?);2862 // try dwarf.flushModule(comp.module.?);
3783 }2863 // }
3784 }2864 // }
37852865
3786 try wasm.mergeSections();2866 try wasm.mergeSections();
3787 try wasm.mergeTypes();2867 try wasm.mergeTypes();
...@@ -4194,16 +3274,6 @@ fn writeToFile(...@@ -4194,16 +3274,6 @@ fn writeToFile(
4194 else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}),3274 else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}),
4195 }3275 }
41963276
4197 // if (wasm.dwarf) |*dwarf| {
4198 // const mod = comp.module.?;
4199 // try dwarf.writeDbgAbbrev();
4200 // // for debug info and ranges, the address is always 0,
4201 // // as locations are always offsets relative to 'code' section.
4202 // try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
4203 // try dwarf.writeDbgAranges(0, code_section_size);
4204 // try dwarf.writeDbgLineHeader();
4205 // }
4206
4207 var debug_bytes = std.ArrayList(u8).init(gpa);3277 var debug_bytes = std.ArrayList(u8).init(gpa);
4208 defer debug_bytes.deinit();3278 defer debug_bytes.deinit();
42093279
...@@ -5185,44 +4255,25 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {...@@ -5185,44 +4255,25 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
5185 return false;4255 return false;
5186}4256}
51874257
5188pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 {
5189 var index: u32 = 0;
5190 while (index < wasm.func_types.items.len) : (index += 1) {
5191 if (wasm.func_types.items[index].eql(func_type)) return index;
5192 }
5193 return null;
5194}
5195
5196/// Searches for a matching function signature. When no matching signature is found,4258/// Searches for a matching function signature. When no matching signature is found,
5197/// a new entry will be made. The value returned is the index of the type within `wasm.func_types`.4259/// a new entry will be made. The value returned is the index of the type within `wasm.func_types`.
5198pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {4260pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
5199 if (wasm.getTypeIndex(func_type)) |index| {4261 _ = wasm;
5200 return index;4262 _ = func_type;
5201 }
5202 const gpa = wasm.base.comp.gpa;
5203
5204 // functype does not exist.
5205 const index: u32 = @intCast(wasm.func_types.items.len);
5206 const params = try gpa.dupe(std.wasm.Valtype, func_type.params);
5207 errdefer gpa.free(params);
5208 const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns);
5209 errdefer gpa.free(returns);
5210 try wasm.func_types.append(gpa, .{
5211 .params = params,
5212 .returns = returns,
5213 });
5214 return index;
5215}4263}
52164264
5217/// For the given `decl_index`, stores the corresponding type representing the function signature.4265/// For the given `decl_index`, stores the corresponding type representing the function signature.
5218/// Asserts declaration has an associated `Atom`.4266/// Asserts declaration has an associated `Atom`.
5219/// Returns the index into the list of types.4267/// Returns the index into the list of types.
5220pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {4268pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {
5221 const gpa = wasm.base.comp.gpa;4269 _ = wasm;
5222 const atom_index = wasm.decls.get(decl_index).?;4270 _ = decl_index;
5223 const index = try wasm.putOrGetFuncType(func_type);4271 _ = func_type;
5224 try wasm.atom_types.put(gpa, atom_index, index);4272 // const gpa = wasm.base.comp.gpa;
5225 return index;4273 // const atom_index = wasm.decls.get(decl_index).?;
4274 // const index = try wasm.putOrGetFuncType(func_type);
4275 // try wasm.atom_types.put(gpa, atom_index, index);
4276 // return index;
5226}4277}
52274278
5228/// Verifies all resolved symbols and checks whether itself needs to be marked alive,4279/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
src/link/Wasm/ZigObject.zig+115
...@@ -41,6 +41,36 @@ imported_globals_count: u32 = 0,...@@ -41,6 +41,36 @@ imported_globals_count: u32 = 0,
41/// of a new `ZigObject`. Codegen will make calls into this to create relocations for41/// of a new `ZigObject`. Codegen will make calls into this to create relocations for
42/// this symbol each time the stack pointer is moved.42/// this symbol each time the stack pointer is moved.
43stack_pointer_sym: u32,43stack_pointer_sym: u32,
44/// Debug information for the Zig module.
45dwarf: ?Dwarf = null,
46// Debug section atoms. These are only set when the current compilation
47// unit contains Zig code. The lifetime of these atoms are extended
48// until the end of the compiler's lifetime. Meaning they're not freed
49// during `flush()` in incremental-mode.
50debug_info_atom: ?Atom.Index = null,
51debug_line_atom: ?Atom.Index = null,
52debug_loc_atom: ?Atom.Index = null,
53debug_ranges_atom: ?Atom.Index = null,
54debug_abbrev_atom: ?Atom.Index = null,
55debug_str_atom: ?Atom.Index = null,
56debug_pubnames_atom: ?Atom.Index = null,
57debug_pubtypes_atom: ?Atom.Index = null,
58/// The index of the segment representing the custom '.debug_info' section.
59debug_info_index: ?u32 = null,
60/// The index of the segment representing the custom '.debug_line' section.
61debug_line_index: ?u32 = null,
62/// The index of the segment representing the custom '.debug_loc' section.
63debug_loc_index: ?u32 = null,
64/// The index of the segment representing the custom '.debug_ranges' section.
65debug_ranges_index: ?u32 = null,
66/// The index of the segment representing the custom '.debug_pubnames' section.
67debug_pubnames_index: ?u32 = null,
68/// The index of the segment representing the custom '.debug_pubtypes' section.
69debug_pubtypes_index: ?u32 = null,
70/// The index of the segment representing the custom '.debug_pubtypes' section.
71debug_str_index: ?u32 = null,
72/// The index of the segment representing the custom '.debug_pubtypes' section.
73debug_abbrev_index: ?u32 = null,
4474
45/// Frees and invalidates all memory of the incrementally compiled Zig module.75/// Frees and invalidates all memory of the incrementally compiled Zig module.
46/// It is illegal behavior to access the `ZigObject` after calling `deinit`.76/// 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 {...@@ -80,6 +110,9 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void {
80 zig_object.segment_info.deinit(gpa);110 zig_object.segment_info.deinit(gpa);
81111
82 zig_object.string_table.deinit(gpa);112 zig_object.string_table.deinit(gpa);
113 if (zig_object.dwarf) |*dwarf| {
114 dwarf.deinit();
115 }
83 zig_object.* = undefined;116 zig_object.* = undefined;
84}117}
85118
...@@ -976,6 +1009,87 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {...@@ -976,6 +1009,87 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {
976 // try wasm.parseAtom(atom_index, .{ .data = .read_only });1009 // try wasm.parseAtom(atom_index, .{ .data = .read_only });
977}1010}
9781011
1012/// Initializes symbols and atoms for the debug sections
1013/// Initialization is only done when compiling Zig code.
1014/// When Zig is invoked as a linker instead, the atoms
1015/// and symbols come from the object files instead.
1016pub fn initDebugSections(zig_object: *ZigObject) !void {
1017 if (zig_object.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections
1018 std.debug.assert(zig_object.debug_info_index == null);
1019 // this will create an Atom and set the index for us.
1020 zig_object.debug_info_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_info_index, ".debug_info");
1021 zig_object.debug_line_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_line_index, ".debug_line");
1022 zig_object.debug_loc_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_loc_index, ".debug_loc");
1023 zig_object.debug_abbrev_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_abbrev_index, ".debug_abbrev");
1024 zig_object.debug_ranges_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_ranges_index, ".debug_ranges");
1025 zig_object.debug_str_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_str_index, ".debug_str");
1026 zig_object.debug_pubnames_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_pubnames_index, ".debug_pubnames");
1027 zig_object.debug_pubtypes_atom = try zig_object.createDebugSectionForIndex(&zig_object.debug_pubtypes_index, ".debug_pubtypes");
1028}
1029
1030/// From a given index variable, creates a new debug section.
1031/// This initializes the index, appends a new segment,
1032/// and finally, creates a managed `Atom`.
1033pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm_file: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
1034 const gpa = wasm_file.base.comp.gpa;
1035 const new_index: u32 = @intCast(zig_object.segments.items.len);
1036 index.* = new_index;
1037 try zig_object.appendDummySegment();
1038
1039 const sym_index = try zig_object.allocateSymbol(gpa);
1040 const atom_index = try wasm_file.createAtom(sym_index);
1041 const atom = wasm_file.getAtomPtr(atom_index);
1042 zig_object.symbols.items[sym_index] = .{
1043 .tag = .section,
1044 .name = try zig_object.string_table.put(gpa, name),
1045 .index = 0,
1046 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1047 };
1048
1049 atom.alignment = .@"1"; // debug sections are always 1-byte-aligned
1050 return atom_index;
1051}
1052
1053pub fn updateDeclLineNumber(zig_object: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void {
1054 if (zig_object.dwarf) |*dw| {
1055 const decl = mod.declPtr(decl_index);
1056 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1057
1058 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1059 try dw.updateDeclLineNumber(mod, decl_index);
1060 }
1061}
1062
1063/// Allocates debug atoms into their respective debug sections
1064/// to merge them with maybe-existing debug atoms from object files.
1065fn allocateDebugAtoms(zig_object: *ZigObject) !void {
1066 if (zig_object.dwarf == null) return;
1067
1068 const allocAtom = struct {
1069 fn f(ctx: *ZigObject, maybe_index: *?u32, atom_index: Atom.Index) !void {
1070 const index = maybe_index.* orelse idx: {
1071 const index = @as(u32, @intCast(ctx.segments.items.len));
1072 try ctx.appendDummySegment();
1073 maybe_index.* = index;
1074 break :idx index;
1075 };
1076 const atom = ctx.getAtomPtr(atom_index);
1077 atom.size = @as(u32, @intCast(atom.code.items.len));
1078 ctx.symbols.items[atom.sym_index].index = index;
1079 try ctx.appendAtomAtIndex(index, atom_index);
1080 }
1081 }.f;
1082
1083 try allocAtom(zig_object, &zig_object.debug_info_index, zig_object.debug_info_atom.?);
1084 try allocAtom(zig_object, &zig_object.debug_line_index, zig_object.debug_line_atom.?);
1085 try allocAtom(zig_object, &zig_object.debug_loc_index, zig_object.debug_loc_atom.?);
1086 try allocAtom(zig_object, &zig_object.debug_str_index, zig_object.debug_str_atom.?);
1087 try allocAtom(zig_object, &zig_object.debug_ranges_index, zig_object.debug_ranges_atom.?);
1088 try allocAtom(zig_object, &zig_object.debug_abbrev_index, zig_object.debug_abbrev_atom.?);
1089 try allocAtom(zig_object, &zig_object.debug_pubnames_index, zig_object.debug_pubnames_atom.?);
1090 try allocAtom(zig_object, &zig_object.debug_pubtypes_index, zig_object.debug_pubtypes_atom.?);
1091}
1092
979const build_options = @import("build_options");1093const build_options = @import("build_options");
980const builtin = @import("builtin");1094const builtin = @import("builtin");
981const codegen = @import("../../codegen.zig");1095const codegen = @import("../../codegen.zig");
...@@ -986,6 +1100,7 @@ const types = @import("types.zig");...@@ -986,6 +1100,7 @@ const types = @import("types.zig");
9861100
987const Air = @import("../../Air.zig");1101const Air = @import("../../Air.zig");
988const Atom = @import("Atom.zig");1102const Atom = @import("Atom.zig");
1103const Dwarf = @import("../Dwarf.zig");
989const InternPool = @import("../../InternPool.zig");1104const InternPool = @import("../../InternPool.zig");
990const Liveness = @import("../../Liveness.zig");1105const Liveness = @import("../../Liveness.zig");
991const Module = @import("../../Module.zig");1106const Module = @import("../../Module.zig");