| author | |
| committer | |
| log | 0d696a48dadffbb3dcd3f7ada6867129da4d70c8 |
| tree | 963b8e3b841189b720e77770afc6dfa3c3c6da83 |
| parent | 30ee08dfc2236a9c25826dbde82f9865bae5cf30 |
2 files changed, 56 insertions(+), 16 deletions(-)
src-self-hosted/Module.zig+25-14| ... | ... | @@ -89,6 +89,9 @@ const WorkItem = union(enum) { |
| 89 | 89 | /// It may have already be analyzed, or it may have been determined |
| 90 | 90 | /// to be outdated; in this case perform semantic analysis again. |
| 91 | 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 | }; |
| 93 | 96 | |
| 94 | 97 | pub const Export = struct { |
| ... | ... | @@ -1064,22 +1067,14 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { |
| 1064 | 1067 | error.AnalysisFail => { |
| 1065 | 1068 | decl.analysis = .dependency_failure; |
| 1066 | 1069 | }, |
| 1067 | error.CGenFailure => { | |
| 1068 | // Error is handled by CBE, don't try adding it again | |
| 1069 | }, | |
| 1070 | 1070 | else => { |
| 1071 | 1071 | try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1); |
| 1072 | const result = self.failed_decls.getOrPutAssumeCapacity(decl); | |
| 1073 | if (result.found_existing) { | |
| 1074 | std.debug.panic("Internal error: attempted to override error '{}' with 'unable to codegen: {}'", .{ result.entry.value.msg, @errorName(err) }); | |
| 1075 | } else { | |
| 1076 | result.entry.value = try ErrorMsg.create( | |
| 1077 | self.gpa, | |
| 1078 | decl.src(), | |
| 1079 | "unable to codegen: {}", | |
| 1080 | .{@errorName(err)}, | |
| 1081 | ); | |
| 1082 | } | |
| 1072 | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( | |
| 1073 | self.gpa, | |
| 1074 | decl.src(), | |
| 1075 | "unable to codegen: {}", | |
| 1076 | .{@errorName(err)}, | |
| 1077 | )); | |
| 1083 | 1078 | decl.analysis = .codegen_failure_retryable; |
| 1084 | 1079 | }, |
| 1085 | 1080 | }; |
| ... | ... | @@ -1091,6 +1086,18 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { |
| 1091 | 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 | } |
| 1096 | 1103 | |
| ... | ... | @@ -1530,6 +1537,10 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1530 | 1537 | if (!srcHashEql(decl.contents_hash, contents_hash)) { |
| 1531 | 1538 | try self.markOutdatedDecl(decl); |
| 1532 | 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 | 1546 | } else { |
src-self-hosted/link.zig+31-2| ... | ... | @@ -85,6 +85,13 @@ pub const File = struct { |
| 85 | 85 | } |
| 86 | 86 | } |
| 87 | 87 | |
| 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 | 95 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { |
| 89 | 96 | switch (base.tag) { |
| 90 | 97 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), |
| ... | ... | @@ -203,7 +210,7 @@ pub const File = struct { |
| 203 | 210 | |
| 204 | 211 | pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void { |
| 205 | 212 | self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args); |
| 206 | return error.CGenFailure; | |
| 213 | return error.AnalysisFail; | |
| 207 | 214 | } |
| 208 | 215 | |
| 209 | 216 | pub fn deinit(self: *File.C) void { |
| ... | ... | @@ -217,7 +224,7 @@ pub const File = struct { |
| 217 | 224 | |
| 218 | 225 | pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { |
| 219 | 226 | c_codegen.generate(self, decl) catch |err| { |
| 220 | if (err == error.CGenFailure) { | |
| 227 | if (err == error.AnalysisFail) { | |
| 221 | 228 | try module.failed_decls.put(module.gpa, decl, self.error_msg); |
| 222 | 229 | } |
| 223 | 230 | return err; |
| ... | ... | @@ -2088,6 +2095,28 @@ pub const File = struct { |
| 2088 | 2095 | } |
| 2089 | 2096 | } |
| 2090 | 2097 | |
| 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 | 2120 | pub fn deleteExport(self: *Elf, exp: Export) void { |
| 2092 | 2121 | const sym_index = exp.sym_index orelse return; |
| 2093 | 2122 | self.global_symbol_free_list.append(self.allocator, sym_index) catch {}; |