mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
Zcu: eliminate Decl.alive field
Legacy anon decls now have three uses: * Type owner decls * Function owner decls * `@export` and `@extern` Therefore, there are no longer any cases where we wish to explicitly omit legacy anon decls from the binary. This means we can remove the concept of an "alive" vs "dead" `Decl`, which also allows us to remove the separate `anon_work_queue` in `Compilation`.
This commit is contained in:
parent
152a2ceaf7
commit
26a94e8481
@ -102,7 +102,6 @@ link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
|
||||
lld_errors: std.ArrayListUnmanaged(LldError) = .{},
|
||||
|
||||
work_queue: std.fifo.LinearFifo(Job, .Dynamic),
|
||||
anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic),
|
||||
|
||||
/// These jobs are to invoke the Clang compiler to create an object file, which
|
||||
/// gets linked with the Compilation.
|
||||
@ -1417,7 +1416,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
|
||||
.emit_llvm_ir = options.emit_llvm_ir,
|
||||
.emit_llvm_bc = options.emit_llvm_bc,
|
||||
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
|
||||
.anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
|
||||
.c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
|
||||
.win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa),
|
||||
.astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa),
|
||||
@ -1840,7 +1838,6 @@ pub fn destroy(comp: *Compilation) void {
|
||||
if (comp.module) |zcu| zcu.deinit();
|
||||
comp.cache_use.deinit();
|
||||
comp.work_queue.deinit();
|
||||
comp.anon_work_queue.deinit();
|
||||
comp.c_object_work_queue.deinit();
|
||||
if (!build_options.only_core_functionality) {
|
||||
comp.win32_resource_work_queue.deinit();
|
||||
@ -3354,18 +3351,11 @@ pub fn performAllTheWork(
|
||||
mod.sema_prog_node = undefined;
|
||||
};
|
||||
|
||||
// In this main loop we give priority to non-anonymous Decls in the work queue, so
|
||||
// that they can establish references to anonymous Decls, setting alive=true in the
|
||||
// backend, preventing anonymous Decls from being prematurely destroyed.
|
||||
while (true) {
|
||||
if (comp.work_queue.readItem()) |work_item| {
|
||||
try processOneJob(comp, work_item, main_progress_node);
|
||||
continue;
|
||||
}
|
||||
if (comp.anon_work_queue.readItem()) |work_item| {
|
||||
try processOneJob(comp, work_item, main_progress_node);
|
||||
continue;
|
||||
}
|
||||
if (comp.module) |zcu| {
|
||||
// If there's no work queued, check if there's anything outdated
|
||||
// which we need to work on, and queue it if so.
|
||||
@ -3413,14 +3403,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
|
||||
|
||||
assert(decl.has_tv);
|
||||
|
||||
if (decl.alive) {
|
||||
try module.linkerUpdateDecl(decl_index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Instead of sending this decl to the linker, we actually will delete it
|
||||
// because we found out that it in fact was never referenced.
|
||||
module.deleteUnusedDecl(decl_index);
|
||||
try module.linkerUpdateDecl(decl_index);
|
||||
return;
|
||||
},
|
||||
}
|
||||
|
||||
@ -6740,7 +6740,6 @@ fn finishFuncInstance(
|
||||
.zir_decl_index = fn_owner_decl.zir_decl_index,
|
||||
.is_pub = fn_owner_decl.is_pub,
|
||||
.is_exported = fn_owner_decl.is_exported,
|
||||
.alive = true,
|
||||
.kind = .anon,
|
||||
});
|
||||
errdefer ip.destroyDecl(gpa, decl_index);
|
||||
|
||||
@ -394,15 +394,6 @@ pub const Decl = struct {
|
||||
is_pub: bool,
|
||||
/// Whether the corresponding AST decl has a `export` keyword.
|
||||
is_exported: bool,
|
||||
/// Flag used by garbage collection to mark and sweep.
|
||||
/// Decls which correspond to an AST node always have this field set to `true`.
|
||||
/// Anonymous Decls are initialized with this field set to `false` and then it
|
||||
/// is the responsibility of machine code backends to mark it `true` whenever
|
||||
/// a `decl_ref` Value is encountered that points to this Decl.
|
||||
/// When the `codegen_decl` job is encountered in the main work queue, if the
|
||||
/// Decl is marked alive, then it sends the Decl to the linker. Otherwise it
|
||||
/// deletes the Decl on the spot.
|
||||
alive: bool,
|
||||
/// If true `name` is already fully qualified.
|
||||
name_fully_qualified: bool = false,
|
||||
/// What kind of a declaration is this.
|
||||
@ -3525,7 +3516,6 @@ fn semaFile(mod: *Module, file: *File) SemaError!void {
|
||||
new_decl.is_exported = false;
|
||||
new_decl.alignment = .none;
|
||||
new_decl.@"linksection" = .none;
|
||||
new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
|
||||
new_decl.analysis = .in_progress;
|
||||
|
||||
if (file.status != .success_zir) {
|
||||
@ -4375,7 +4365,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
|
||||
const decl = zcu.declPtr(decl_index);
|
||||
const was_exported = decl.is_exported;
|
||||
assert(decl.kind == kind); // ZIR tracking should preserve this
|
||||
assert(decl.alive);
|
||||
decl.name = decl_name;
|
||||
decl.src_node = decl_node;
|
||||
decl.src_line = line;
|
||||
@ -4392,7 +4381,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
|
||||
new_decl.is_pub = declaration.flags.is_pub;
|
||||
new_decl.is_exported = declaration.flags.is_export;
|
||||
new_decl.zir_decl_index = tracked_inst.toOptional();
|
||||
new_decl.alive = true; // This Decl corresponds to an AST node and is therefore always alive.
|
||||
break :decl_index .{ false, new_decl_index };
|
||||
};
|
||||
|
||||
@ -4470,12 +4458,8 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
|
||||
|
||||
/// Finalize the creation of an anon decl.
|
||||
pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
|
||||
// The Decl starts off with alive=false and the codegen backend will set alive=true
|
||||
// if the Decl is referenced by an instruction or another constant. Otherwise,
|
||||
// the Decl will be garbage collected by the `codegen_decl` task instead of sent
|
||||
// to the linker.
|
||||
if (mod.declPtr(decl_index).typeOf(mod).isFnOrHasRuntimeBits(mod)) {
|
||||
try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = decl_index });
|
||||
try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
|
||||
}
|
||||
}
|
||||
|
||||
@ -4815,7 +4799,6 @@ pub fn allocateNewDecl(
|
||||
.zir_decl_index = .none,
|
||||
.is_pub = false,
|
||||
.is_exported = false,
|
||||
.alive = false,
|
||||
.kind = .anon,
|
||||
});
|
||||
|
||||
@ -5582,51 +5565,6 @@ fn reportRetryableFileError(
|
||||
gop.value_ptr.* = err_msg;
|
||||
}
|
||||
|
||||
pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
|
||||
switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.variable => |variable| try mod.markDeclIndexAlive(variable.decl),
|
||||
.extern_func => |extern_func| try mod.markDeclIndexAlive(extern_func.decl),
|
||||
.func => |func| try mod.markDeclIndexAlive(func.owner_decl),
|
||||
.error_union => |error_union| switch (error_union.val) {
|
||||
.err_name => {},
|
||||
.payload => |payload| try mod.markReferencedDeclsAlive(Value.fromInterned(payload)),
|
||||
},
|
||||
.slice => |slice| {
|
||||
try mod.markReferencedDeclsAlive(Value.fromInterned(slice.ptr));
|
||||
try mod.markReferencedDeclsAlive(Value.fromInterned(slice.len));
|
||||
},
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl| try mod.markDeclIndexAlive(decl),
|
||||
.anon_decl => {},
|
||||
.int, .comptime_field, .comptime_alloc => {},
|
||||
.eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),
|
||||
.elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),
|
||||
},
|
||||
.opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(opt.val)),
|
||||
.aggregate => |aggregate| for (aggregate.storage.values()) |elem|
|
||||
try mod.markReferencedDeclsAlive(Value.fromInterned(elem)),
|
||||
.un => |un| {
|
||||
if (un.tag != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(un.tag));
|
||||
try mod.markReferencedDeclsAlive(Value.fromInterned(un.val));
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
|
||||
if (decl.alive) return;
|
||||
decl.alive = true;
|
||||
|
||||
// This is the first time we are marking this Decl alive. We must
|
||||
// therefore recurse into its value and mark any Decl it references
|
||||
// as also alive, so that any Decl referenced does not get garbage collected.
|
||||
try mod.markReferencedDeclsAlive(decl.val);
|
||||
}
|
||||
|
||||
fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
|
||||
return mod.markDeclAlive(mod.declPtr(decl_index));
|
||||
}
|
||||
|
||||
pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
|
||||
const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
|
||||
if (gop.found_existing) {
|
||||
|
||||
@ -6445,8 +6445,6 @@ pub fn analyzeExport(
|
||||
return sema.fail(block, src, "export target cannot be extern", .{});
|
||||
}
|
||||
|
||||
// This decl is alive no matter what, since it's being exported
|
||||
try mod.markDeclAlive(exported_decl);
|
||||
try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
|
||||
|
||||
try addExport(mod, .{
|
||||
|
||||
@ -3121,7 +3121,6 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
|
||||
fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
|
||||
const mod = func.bin_file.base.comp.module.?;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
try mod.markDeclAlive(decl);
|
||||
const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod));
|
||||
return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
|
||||
}
|
||||
@ -3178,7 +3177,6 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl
|
||||
return WValue{ .imm32 = 0xaaaaaaaa };
|
||||
}
|
||||
|
||||
try mod.markDeclAlive(decl);
|
||||
const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index);
|
||||
const atom = func.bin_file.getAtom(atom_index);
|
||||
|
||||
|
||||
@ -12263,7 +12263,6 @@ fn genCall(self: *Self, info: union(enum) {
|
||||
},
|
||||
}) {
|
||||
.func => |func| {
|
||||
try mod.markDeclAlive(mod.declPtr(func.owner_decl));
|
||||
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
@ -12323,7 +12322,6 @@ fn genCall(self: *Self, info: union(enum) {
|
||||
},
|
||||
.extern_func => |extern_func| {
|
||||
const owner_decl = mod.declPtr(extern_func.decl);
|
||||
try mod.markDeclAlive(owner_decl);
|
||||
const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name);
|
||||
const decl_name = mod.intern_pool.stringToSlice(owner_decl.name);
|
||||
try self.genExternSymbolRef(.call, lib_name, decl_name);
|
||||
|
||||
@ -835,8 +835,6 @@ fn lowerDeclRef(
|
||||
return Result.ok;
|
||||
}
|
||||
|
||||
try zcu.markDeclAlive(decl);
|
||||
|
||||
const vaddr = try lf.getDeclVAddr(decl_index, .{
|
||||
.parent_atom_index = reloc_info.parent_atom_index,
|
||||
.offset = code.items.len,
|
||||
@ -958,8 +956,6 @@ fn genDeclRef(
|
||||
}
|
||||
}
|
||||
|
||||
try zcu.markDeclAlive(decl);
|
||||
|
||||
const decl_namespace = zcu.namespacePtr(decl.src_namespace);
|
||||
const single_threaded = decl_namespace.file_scope.mod.single_threaded;
|
||||
const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded;
|
||||
|
||||
@ -2010,7 +2010,6 @@ pub const DeclGen = struct {
|
||||
fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void {
|
||||
const mod = dg.module;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
try mod.markDeclAlive(decl);
|
||||
|
||||
if (mod.decl_exports.get(decl_index)) |exports| {
|
||||
try writer.print("{ }", .{
|
||||
|
||||
@ -3722,15 +3722,11 @@ pub const Object = struct {
|
||||
=> unreachable, // non-runtime values
|
||||
.extern_func => |extern_func| {
|
||||
const fn_decl_index = extern_func.decl;
|
||||
const fn_decl = mod.declPtr(fn_decl_index);
|
||||
try mod.markDeclAlive(fn_decl);
|
||||
const function_index = try o.resolveLlvmFunction(fn_decl_index);
|
||||
return function_index.ptrConst(&o.builder).global.toConst();
|
||||
},
|
||||
.func => |func| {
|
||||
const fn_decl_index = func.owner_decl;
|
||||
const fn_decl = mod.declPtr(fn_decl_index);
|
||||
try mod.markDeclAlive(fn_decl);
|
||||
const function_index = try o.resolveLlvmFunction(fn_decl_index);
|
||||
return function_index.ptrConst(&o.builder).global.toConst();
|
||||
},
|
||||
@ -4262,7 +4258,6 @@ pub const Object = struct {
|
||||
fn lowerParentPtrDecl(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {
|
||||
const mod = o.module;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
try mod.markDeclAlive(decl);
|
||||
const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod));
|
||||
return o.lowerDeclRefValue(ptr_ty, decl_index);
|
||||
}
|
||||
@ -4455,8 +4450,6 @@ pub const Object = struct {
|
||||
if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or
|
||||
(is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ty);
|
||||
|
||||
try mod.markDeclAlive(decl);
|
||||
|
||||
const llvm_global = if (is_fn_body)
|
||||
(try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
|
||||
else
|
||||
|
||||
@ -255,7 +255,6 @@ pub const Object = struct {
|
||||
pub fn resolveDecl(self: *Object, mod: *Module, decl_index: InternPool.DeclIndex) !SpvModule.Decl.Index {
|
||||
const decl = mod.declPtr(decl_index);
|
||||
assert(decl.has_tv); // TODO: Do we need to handle a situation where this is false?
|
||||
try mod.markDeclAlive(decl);
|
||||
|
||||
const entry = try self.decl_link.getOrPut(self.gpa, decl_index);
|
||||
if (!entry.found_existing) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user