authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-08-08 01:18:22+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-07 19:25:06-04:00
log2fc18b52788f789ceba7b4f60e850de3ce67495c
tree750f7dccac4515a5f337c1aac8bd613c2efd6f81
parenta2bb246db4c2bb88f402215d5db79a535dbff4b6

stage2: make link data in Decl into unions

This will allow for implementation of non-Elf backends without wasting memory.

3 files changed, 69 insertions(+), 49 deletions(-)

src-self-hosted/Module.zig+17-7
......@@ -177,14 +177,14 @@ pub const Decl = struct {
177177
178178 /// Represents the position of the code in the output file.
179179 /// This is populated regardless of semantic analysis and code generation.
180 link: link.File.Elf.TextBlock = link.File.Elf.TextBlock.empty,
180 link: link.File.LinkBlock,
181181
182182 /// Represents the function in the linked output file, if the `Decl` is a function.
183183 /// This is stored here and not in `Fn` because `Decl` survives across updates but
184184 /// `Fn` does not.
185185 /// TODO Look into making `Fn` a longer lived structure and moving this field there
186186 /// to save on memory usage.
187 fn_link: link.File.Elf.SrcFn = link.File.Elf.SrcFn.empty,
187 fn_link: link.File.LinkFn,
188188
189189 contents_hash: std.zig.SrcHash,
190190
......@@ -1538,10 +1538,13 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
15381538 if (!srcHashEql(decl.contents_hash, contents_hash)) {
15391539 try self.markOutdatedDecl(decl);
15401540 decl.contents_hash = contents_hash;
1541 } else if (decl.fn_link.len != 0) {
1542 // TODO Look into detecting when this would be unnecessary by storing enough state
1543 // in `Decl` to notice that the line number did not change.
1544 self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
1541 } else switch (self.bin_file.tag) {
1542 .elf => if (decl.fn_link.elf.len != 0) {
1543 // TODO Look into detecting when this would be unnecessary by storing enough state
1544 // in `Decl` to notice that the line number did not change.
1545 self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
1546 },
1547 .c => {},
15451548 }
15461549 }
15471550 } else {
......@@ -1745,7 +1748,14 @@ fn allocateNewDecl(
17451748 .analysis = .unreferenced,
17461749 .deletion_flag = false,
17471750 .contents_hash = contents_hash,
1748 .link = link.File.Elf.TextBlock.empty,
1751 .link = switch (self.bin_file.tag) {
1752 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
1753 .c => .{ .c = {} },
1754 },
1755 .fn_link = switch (self.bin_file.tag) {
1756 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
1757 .c => .{ .c = {} },
1758 },
17491759 .generation = 0,
17501760 };
17511761 return new_decl;
src-self-hosted/codegen.zig+5-5
......@@ -145,10 +145,10 @@ pub fn generateSymbol(
145145 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
146146 const decl = payload.decl;
147147 if (decl.analysis != .complete) return error.AnalysisFail;
148 assert(decl.link.local_sym_index != 0);
148 assert(decl.link.elf.local_sym_index != 0);
149149 // TODO handle the dependency of this symbol on the decl's vaddr.
150150 // If the decl changes vaddr, then this symbol needs to get regenerated.
151 const vaddr = bin_file.local_symbols.items[decl.link.local_sym_index].st_value;
151 const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value;
152152 const endian = bin_file.base.options.target.cpu.arch.endian();
153153 switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {
154154 16 => {
......@@ -1085,7 +1085,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10851085 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
10861086 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
10871087 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1088 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
1088 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
10891089 // ff 14 25 xx xx xx xx call [addr]
10901090 try self.code.ensureCapacity(self.code.items.len + 7);
10911091 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
......@@ -1106,7 +1106,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
11061106 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
11071107 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
11081108 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1109 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
1109 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
11101110
11111111 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
11121112 const jalr = instructions.Jalr{
......@@ -1934,7 +1934,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19341934 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
19351935 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
19361936 const decl = payload.decl;
1937 const got_addr = got.p_vaddr + decl.link.offset_table_index * ptr_bytes;
1937 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
19381938 return MCValue{ .memory = got_addr };
19391939 }
19401940 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
src-self-hosted/link.zig+47-37
......@@ -38,6 +38,16 @@ pub const Options = struct {
3838
3939
4040pub const File = struct {
41 pub const LinkBlock = union {
42 elf: Elf.TextBlock,
43 c: void,
44 };
45
46 pub const LinkFn = union {
47 elf: Elf.SrcFn,
48 c: void,
49 };
50
4151 tag: Tag,
4252 options: Options,
4353 file: ?fs.File,
......@@ -1720,31 +1730,31 @@ pub const File = struct {
17201730 }
17211731
17221732 pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
1723 if (decl.link.local_sym_index != 0) return;
1733 if (decl.link.elf.local_sym_index != 0) return;
17241734
17251735 try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
17261736 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
17271737
17281738 if (self.local_symbol_free_list.popOrNull()) |i| {
17291739 log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name });
1730 decl.link.local_sym_index = i;
1740 decl.link.elf.local_sym_index = i;
17311741 } else {
17321742 log.debug(.link, "allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
1733 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
1743 decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len);
17341744 _ = self.local_symbols.addOneAssumeCapacity();
17351745 }
17361746
17371747 if (self.offset_table_free_list.popOrNull()) |i| {
1738 decl.link.offset_table_index = i;
1748 decl.link.elf.offset_table_index = i;
17391749 } else {
1740 decl.link.offset_table_index = @intCast(u32, self.offset_table.items.len);
1750 decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len);
17411751 _ = self.offset_table.addOneAssumeCapacity();
17421752 self.offset_table_count_dirty = true;
17431753 }
17441754
17451755 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
17461756
1747 self.local_symbols.items[decl.link.local_sym_index] = .{
1757 self.local_symbols.items[decl.link.elf.local_sym_index] = .{
17481758 .st_name = 0,
17491759 .st_info = 0,
17501760 .st_other = 0,
......@@ -1752,39 +1762,39 @@ pub const File = struct {
17521762 .st_value = phdr.p_vaddr,
17531763 .st_size = 0,
17541764 };
1755 self.offset_table.items[decl.link.offset_table_index] = 0;
1765 self.offset_table.items[decl.link.elf.offset_table_index] = 0;
17561766 }
17571767
17581768 pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
17591769 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1760 self.freeTextBlock(&decl.link);
1761 if (decl.link.local_sym_index != 0) {
1762 self.local_symbol_free_list.append(self.base.allocator, decl.link.local_sym_index) catch {};
1763 self.offset_table_free_list.append(self.base.allocator, decl.link.offset_table_index) catch {};
1770 self.freeTextBlock(&decl.link.elf);
1771 if (decl.link.elf.local_sym_index != 0) {
1772 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
1773 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
17641774
1765 self.local_symbols.items[decl.link.local_sym_index].st_info = 0;
1775 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
17661776
1767 decl.link.local_sym_index = 0;
1777 decl.link.elf.local_sym_index = 0;
17681778 }
17691779 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
17701780 // is desired for both.
1771 _ = self.dbg_line_fn_free_list.remove(&decl.fn_link);
1772 if (decl.fn_link.prev) |prev| {
1781 _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf);
1782 if (decl.fn_link.elf.prev) |prev| {
17731783 _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
1774 prev.next = decl.fn_link.next;
1775 if (decl.fn_link.next) |next| {
1784 prev.next = decl.fn_link.elf.next;
1785 if (decl.fn_link.elf.next) |next| {
17761786 next.prev = prev;
17771787 } else {
17781788 self.dbg_line_fn_last = prev;
17791789 }
1780 } else if (decl.fn_link.next) |next| {
1790 } else if (decl.fn_link.elf.next) |next| {
17811791 self.dbg_line_fn_first = next;
17821792 next.prev = null;
17831793 }
1784 if (self.dbg_line_fn_first == &decl.fn_link) {
1794 if (self.dbg_line_fn_first == &decl.fn_link.elf) {
17851795 self.dbg_line_fn_first = null;
17861796 }
1787 if (self.dbg_line_fn_last == &decl.fn_link) {
1797 if (self.dbg_line_fn_last == &decl.fn_link.elf) {
17881798 self.dbg_line_fn_last = null;
17891799 }
17901800 }
......@@ -1870,24 +1880,24 @@ pub const File = struct {
18701880
18711881 const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
18721882
1873 assert(decl.link.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
1874 const local_sym = &self.local_symbols.items[decl.link.local_sym_index];
1883 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
1884 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
18751885 if (local_sym.st_size != 0) {
1876 const capacity = decl.link.capacity(self.*);
1886 const capacity = decl.link.elf.capacity(self.*);
18771887 const need_realloc = code.len > capacity or
18781888 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
18791889 if (need_realloc) {
1880 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
1890 const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment);
18811891 log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
18821892 if (vaddr != local_sym.st_value) {
18831893 local_sym.st_value = vaddr;
18841894
18851895 log.debug(.link, " (writing new offset table entry)\n", .{});
1886 self.offset_table.items[decl.link.offset_table_index] = vaddr;
1887 try self.writeOffsetTableEntry(decl.link.offset_table_index);
1896 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
1897 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
18881898 }
18891899 } else if (code.len < local_sym.st_size) {
1890 self.shrinkTextBlock(&decl.link, code.len);
1900 self.shrinkTextBlock(&decl.link.elf, code.len);
18911901 }
18921902 local_sym.st_size = code.len;
18931903 local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));
......@@ -1895,13 +1905,13 @@ pub const File = struct {
18951905 local_sym.st_other = 0;
18961906 local_sym.st_shndx = self.text_section_index.?;
18971907 // TODO this write could be avoided if no fields of the symbol were changed.
1898 try self.writeSymbol(decl.link.local_sym_index);
1908 try self.writeSymbol(decl.link.elf.local_sym_index);
18991909 } else {
19001910 const decl_name = mem.spanZ(decl.name);
19011911 const name_str_index = try self.makeString(decl_name);
1902 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
1912 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment);
19031913 log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1904 errdefer self.freeTextBlock(&decl.link);
1914 errdefer self.freeTextBlock(&decl.link.elf);
19051915
19061916 local_sym.* = .{
19071917 .st_name = name_str_index,
......@@ -1911,10 +1921,10 @@ pub const File = struct {
19111921 .st_value = vaddr,
19121922 .st_size = code.len,
19131923 };
1914 self.offset_table.items[decl.link.offset_table_index] = vaddr;
1924 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
19151925
1916 try self.writeSymbol(decl.link.local_sym_index);
1917 try self.writeOffsetTableEntry(decl.link.offset_table_index);
1926 try self.writeSymbol(decl.link.elf.local_sym_index);
1927 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
19181928 }
19191929
19201930 const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr;
......@@ -1941,7 +1951,7 @@ pub const File = struct {
19411951 // Now we have the full contents and may allocate a region to store it.
19421952
19431953 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
1944 const src_fn = &decl.fn_link;
1954 const src_fn = &decl.fn_link.elf;
19451955 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
19461956 if (self.dbg_line_fn_last) |last| {
19471957 if (src_fn.next) |next| {
......@@ -2026,8 +2036,8 @@ pub const File = struct {
20262036
20272037 try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
20282038 const typed_value = decl.typed_value.most_recent.typed_value;
2029 if (decl.link.local_sym_index == 0) return;
2030 const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
2039 if (decl.link.elf.local_sym_index == 0) return;
2040 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
20312041
20322042 for (exports) |exp| {
20332043 if (exp.options.section) |section_name| {
......@@ -2105,7 +2115,7 @@ pub const File = struct {
21052115 const casted_line_off = @intCast(u28, line_delta);
21062116
21072117 const shdr = &self.sections.items[self.debug_line_section_index.?];
2108 const file_pos = shdr.sh_offset + decl.fn_link.off + self.getRelocDbgLineOff();
2118 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
21092119 var data: [4]u8 = undefined;
21102120 leb128.writeUnsignedFixed(4, &data, casted_line_off);
21112121 try self.base.file.?.pwriteAll(&data, file_pos);