| 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,6 +89,9 @@ const WorkItem = union(enum) { |
| 89 | /// It may have already be analyzed, or it may have been determined | 89 | /// 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 | }; |
| 93 | 96 | ||
| 94 | pub const Export = struct { | 97 | pub 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 | } |
| 1096 | 1103 | ||
| ... | @@ -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 | } |
| 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 | 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 { |
| 203 | 210 | ||
| 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 | } |
| 208 | 215 | ||
| 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 { |
| 217 | 224 | ||
| 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 | } |
| 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 | 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 {}; |