authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-04 00:22:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-04 00:22:11-07:00
log0d696a48dadffbb3dcd3f7ada6867129da4d70c8
tree963b8e3b841189b720e77770afc6dfa3c3c6da83
parent30ee08dfc2236a9c25826dbde82f9865bae5cf30

stage2 .debug_line: handle Decl line numbers changing


2 files changed, 56 insertions(+), 16 deletions(-)

src-self-hosted/Module.zig+25-14
...@@ -89,6 +89,9 @@ const WorkItem = union(enum) {...@@ -89,6 +89,9 @@ const WorkItem = union(enum) {
89 /// It may have already be analyzed, or it may have been determined89 /// It may have already be analyzed, or it may have been determined
90 /// to be outdated; in this case perform semantic analysis again.90 /// to be outdated; in this case perform semantic analysis again.
91 analyze_decl: *Decl,91 analyze_decl: *Decl,
92 /// The source file containing the Decl has been updated, and so the
93 /// Decl may need its line number information updated in the debug info.
94 update_line_number: *Decl,
92};95};
9396
94pub const Export = struct {97pub const Export = struct {
...@@ -1064,22 +1067,14 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -1064,22 +1067,14 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1064 error.AnalysisFail => {1067 error.AnalysisFail => {
1065 decl.analysis = .dependency_failure;1068 decl.analysis = .dependency_failure;
1066 },1069 },
1067 error.CGenFailure => {
1068 // Error is handled by CBE, don't try adding it again
1069 },
1070 else => {1070 else => {
1071 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);1071 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
1072 const result = self.failed_decls.getOrPutAssumeCapacity(decl);1072 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1073 if (result.found_existing) {1073 self.gpa,
1074 std.debug.panic("Internal error: attempted to override error '{}' with 'unable to codegen: {}'", .{ result.entry.value.msg, @errorName(err) });1074 decl.src(),
1075 } else {1075 "unable to codegen: {}",
1076 result.entry.value = try ErrorMsg.create(1076 .{@errorName(err)},
1077 self.gpa,1077 ));
1078 decl.src(),
1079 "unable to codegen: {}",
1080 .{@errorName(err)},
1081 );
1082 }
1083 decl.analysis = .codegen_failure_retryable;1078 decl.analysis = .codegen_failure_retryable;
1084 },1079 },
1085 };1080 };
...@@ -1091,6 +1086,18 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -1091,6 +1086,18 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1091 error.AnalysisFail => continue,1086 error.AnalysisFail => continue,
1092 };1087 };
1093 },1088 },
1089 .update_line_number => |decl| {
1090 self.bin_file.updateDeclLineNumber(self, decl) catch |err| {
1091 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
1092 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1093 self.gpa,
1094 decl.src(),
1095 "unable to update line number: {}",
1096 .{@errorName(err)},
1097 ));
1098 decl.analysis = .codegen_failure_retryable;
1099 };
1100 },
1094 };1101 };
1095}1102}
10961103
...@@ -1530,6 +1537,10 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1530,6 +1537,10 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1530 if (!srcHashEql(decl.contents_hash, contents_hash)) {1537 if (!srcHashEql(decl.contents_hash, contents_hash)) {
1531 try self.markOutdatedDecl(decl);1538 try self.markOutdatedDecl(decl);
1532 decl.contents_hash = contents_hash;1539 decl.contents_hash = contents_hash;
1540 } else if (decl.fn_link.len != 0) {
1541 // TODO Look into detecting when this would be unnecessary by storing enough state
1542 // in `Decl` to notice that the line number did not change.
1543 self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
1533 }1544 }
1534 }1545 }
1535 } else {1546 } else {
src-self-hosted/link.zig+31-2
...@@ -85,6 +85,13 @@ pub const File = struct {...@@ -85,6 +85,13 @@ pub const File = struct {
85 }85 }
86 }86 }
8787
88 pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void {
89 switch (base.tag) {
90 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
91 .c => {},
92 }
93 }
94
88 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {95 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
89 switch (base.tag) {96 switch (base.tag) {
90 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),97 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
...@@ -203,7 +210,7 @@ pub const File = struct {...@@ -203,7 +210,7 @@ pub const File = struct {
203210
204 pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {211 pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
205 self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);212 self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);
206 return error.CGenFailure;213 return error.AnalysisFail;
207 }214 }
208215
209 pub fn deinit(self: *File.C) void {216 pub fn deinit(self: *File.C) void {
...@@ -217,7 +224,7 @@ pub const File = struct {...@@ -217,7 +224,7 @@ pub const File = struct {
217224
218 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {225 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
219 c_codegen.generate(self, decl) catch |err| {226 c_codegen.generate(self, decl) catch |err| {
220 if (err == error.CGenFailure) {227 if (err == error.AnalysisFail) {
221 try module.failed_decls.put(module.gpa, decl, self.error_msg);228 try module.failed_decls.put(module.gpa, decl, self.error_msg);
222 }229 }
223 return err;230 return err;
...@@ -2088,6 +2095,28 @@ pub const File = struct {...@@ -2088,6 +2095,28 @@ pub const File = struct {
2088 }2095 }
2089 }2096 }
20902097
2098 /// Must be called only after a successful call to `updateDecl`.
2099 pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void {
2100 const tracy = trace(@src());
2101 defer tracy.end();
2102
2103 const scope_file = decl.scope.cast(Module.Scope.File).?;
2104 const tree = scope_file.contents.tree;
2105 const file_ast_decls = tree.root_node.decls();
2106 // TODO Look into improving the performance here by adding a token-index-to-line
2107 // lookup table. Currently this involves scanning over the source code for newlines.
2108 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
2109 const block = fn_proto.body().?.castTag(.Block).?;
2110 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
2111 const casted_line_off = @intCast(u28, line_delta);
2112
2113 const shdr = &self.sections.items[self.debug_line_section_index.?];
2114 const file_pos = shdr.sh_offset + decl.fn_link.off + self.getRelocDbgLineOff();
2115 var data: [4]u8 = undefined;
2116 leb128.writeUnsignedFixed(4, &data, casted_line_off);
2117 try self.file.?.pwriteAll(&data, file_pos);
2118 }
2119
2091 pub fn deleteExport(self: *Elf, exp: Export) void {2120 pub fn deleteExport(self: *Elf, exp: Export) void {
2092 const sym_index = exp.sym_index orelse return;2121 const sym_index = exp.sym_index orelse return;
2093 self.global_symbol_free_list.append(self.allocator, sym_index) catch {};2122 self.global_symbol_free_list.append(self.allocator, sym_index) catch {};