stage2 .debug_line: handle Decl line numbers changing
parent
30ee08dfc2
commit
0d696a48da
|
@ -89,6 +89,9 @@ const WorkItem = union(enum) {
|
||||||
/// It may have already be analyzed, or it may have been determined
|
/// It may have already be analyzed, or it may have been determined
|
||||||
/// to be outdated; in this case perform semantic analysis again.
|
/// to be outdated; in this case perform semantic analysis again.
|
||||||
analyze_decl: *Decl,
|
analyze_decl: *Decl,
|
||||||
|
/// The source file containing the Decl has been updated, and so the
|
||||||
|
/// Decl may need its line number information updated in the debug info.
|
||||||
|
update_line_number: *Decl,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Export = struct {
|
pub const Export = struct {
|
||||||
|
@ -1064,22 +1067,14 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
|
||||||
error.AnalysisFail => {
|
error.AnalysisFail => {
|
||||||
decl.analysis = .dependency_failure;
|
decl.analysis = .dependency_failure;
|
||||||
},
|
},
|
||||||
error.CGenFailure => {
|
|
||||||
// Error is handled by CBE, don't try adding it again
|
|
||||||
},
|
|
||||||
else => {
|
else => {
|
||||||
try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
|
try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
|
||||||
const result = self.failed_decls.getOrPutAssumeCapacity(decl);
|
self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
|
||||||
if (result.found_existing) {
|
self.gpa,
|
||||||
std.debug.panic("Internal error: attempted to override error '{}' with 'unable to codegen: {}'", .{ result.entry.value.msg, @errorName(err) });
|
decl.src(),
|
||||||
} else {
|
"unable to codegen: {}",
|
||||||
result.entry.value = try ErrorMsg.create(
|
.{@errorName(err)},
|
||||||
self.gpa,
|
));
|
||||||
decl.src(),
|
|
||||||
"unable to codegen: {}",
|
|
||||||
.{@errorName(err)},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
decl.analysis = .codegen_failure_retryable;
|
decl.analysis = .codegen_failure_retryable;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1091,6 +1086,18 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
|
||||||
error.AnalysisFail => continue,
|
error.AnalysisFail => continue,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.update_line_number => |decl| {
|
||||||
|
self.bin_file.updateDeclLineNumber(self, decl) catch |err| {
|
||||||
|
try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
|
||||||
|
self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
|
||||||
|
self.gpa,
|
||||||
|
decl.src(),
|
||||||
|
"unable to update line number: {}",
|
||||||
|
.{@errorName(err)},
|
||||||
|
));
|
||||||
|
decl.analysis = .codegen_failure_retryable;
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1530,6 +1537,10 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||||
if (!srcHashEql(decl.contents_hash, contents_hash)) {
|
if (!srcHashEql(decl.contents_hash, contents_hash)) {
|
||||||
try self.markOutdatedDecl(decl);
|
try self.markOutdatedDecl(decl);
|
||||||
decl.contents_hash = contents_hash;
|
decl.contents_hash = contents_hash;
|
||||||
|
} else if (decl.fn_link.len != 0) {
|
||||||
|
// TODO Look into detecting when this would be unnecessary by storing enough state
|
||||||
|
// in `Decl` to notice that the line number did not change.
|
||||||
|
self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -85,6 +85,13 @@ pub const File = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void {
|
||||||
|
switch (base.tag) {
|
||||||
|
.elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
|
||||||
|
.c => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
|
pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
|
||||||
switch (base.tag) {
|
switch (base.tag) {
|
||||||
.elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
|
.elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
|
||||||
|
@ -203,7 +210,7 @@ pub const File = struct {
|
||||||
|
|
||||||
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
|
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
|
||||||
self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);
|
self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);
|
||||||
return error.CGenFailure;
|
return error.AnalysisFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *File.C) void {
|
pub fn deinit(self: *File.C) void {
|
||||||
|
@ -217,7 +224,7 @@ pub const File = struct {
|
||||||
|
|
||||||
pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
|
pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
|
||||||
c_codegen.generate(self, decl) catch |err| {
|
c_codegen.generate(self, decl) catch |err| {
|
||||||
if (err == error.CGenFailure) {
|
if (err == error.AnalysisFail) {
|
||||||
try module.failed_decls.put(module.gpa, decl, self.error_msg);
|
try module.failed_decls.put(module.gpa, decl, self.error_msg);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
|
@ -2088,6 +2095,28 @@ pub const File = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Must be called only after a successful call to `updateDecl`.
|
||||||
|
pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void {
|
||||||
|
const tracy = trace(@src());
|
||||||
|
defer tracy.end();
|
||||||
|
|
||||||
|
const scope_file = decl.scope.cast(Module.Scope.File).?;
|
||||||
|
const tree = scope_file.contents.tree;
|
||||||
|
const file_ast_decls = tree.root_node.decls();
|
||||||
|
// TODO Look into improving the performance here by adding a token-index-to-line
|
||||||
|
// lookup table. Currently this involves scanning over the source code for newlines.
|
||||||
|
const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
|
||||||
|
const block = fn_proto.body().?.castTag(.Block).?;
|
||||||
|
const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
|
||||||
|
const casted_line_off = @intCast(u28, line_delta);
|
||||||
|
|
||||||
|
const shdr = &self.sections.items[self.debug_line_section_index.?];
|
||||||
|
const file_pos = shdr.sh_offset + decl.fn_link.off + self.getRelocDbgLineOff();
|
||||||
|
var data: [4]u8 = undefined;
|
||||||
|
leb128.writeUnsignedFixed(4, &data, casted_line_off);
|
||||||
|
try self.file.?.pwriteAll(&data, file_pos);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deleteExport(self: *Elf, exp: Export) void {
|
pub fn deleteExport(self: *Elf, exp: Export) void {
|
||||||
const sym_index = exp.sym_index orelse return;
|
const sym_index = exp.sym_index orelse return;
|
||||||
self.global_symbol_free_list.append(self.allocator, sym_index) catch {};
|
self.global_symbol_free_list.append(self.allocator, sym_index) catch {};
|
||||||
|
|
Loading…
Reference in New Issue