| author | |
| committer | |
| log | 26a94e8481385619ae049143dd67e551f333fa3f |
| tree | 2106272eed6fb7b15a8309c6fc5137e6fec93234 |
| parent | 152a2ceaf738301cd59165a4f17d915391321bdc |
| signature |
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`.10 files changed, 2 insertions(+), 101 deletions(-)
src/Compilation.zig+1-18| ... | ... | @@ -102,7 +102,6 @@ link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, |
| 102 | 102 | lld_errors: std.ArrayListUnmanaged(LldError) = .{}, |
| 103 | 103 | |
| 104 | 104 | work_queue: std.fifo.LinearFifo(Job, .Dynamic), |
| 105 | anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic), | |
| 106 | 105 | |
| 107 | 106 | /// These jobs are to invoke the Clang compiler to create an object file, which |
| 108 | 107 | /// gets linked with the Compilation. |
| ... | ... | @@ -1417,7 +1416,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1417 | 1416 | .emit_llvm_ir = options.emit_llvm_ir, |
| 1418 | 1417 | .emit_llvm_bc = options.emit_llvm_bc, |
| 1419 | 1418 | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), |
| 1420 | .anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), | |
| 1421 | 1419 | .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), |
| 1422 | 1420 | .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa), |
| 1423 | 1421 | .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa), |
| ... | ... | @@ -1840,7 +1838,6 @@ pub fn destroy(comp: *Compilation) void { |
| 1840 | 1838 | if (comp.module) |zcu| zcu.deinit(); |
| 1841 | 1839 | comp.cache_use.deinit(); |
| 1842 | 1840 | comp.work_queue.deinit(); |
| 1843 | comp.anon_work_queue.deinit(); | |
| 1844 | 1841 | comp.c_object_work_queue.deinit(); |
| 1845 | 1842 | if (!build_options.only_core_functionality) { |
| 1846 | 1843 | comp.win32_resource_work_queue.deinit(); |
| ... | ... | @@ -3354,18 +3351,11 @@ pub fn performAllTheWork( |
| 3354 | 3351 | mod.sema_prog_node = undefined; |
| 3355 | 3352 | }; |
| 3356 | 3353 | |
| 3357 | // In this main loop we give priority to non-anonymous Decls in the work queue, so | |
| 3358 | // that they can establish references to anonymous Decls, setting alive=true in the | |
| 3359 | // backend, preventing anonymous Decls from being prematurely destroyed. | |
| 3360 | 3354 | while (true) { |
| 3361 | 3355 | if (comp.work_queue.readItem()) |work_item| { |
| 3362 | 3356 | try processOneJob(comp, work_item, main_progress_node); |
| 3363 | 3357 | continue; |
| 3364 | 3358 | } |
| 3365 | if (comp.anon_work_queue.readItem()) |work_item| { | |
| 3366 | try processOneJob(comp, work_item, main_progress_node); | |
| 3367 | continue; | |
| 3368 | } | |
| 3369 | 3359 | if (comp.module) |zcu| { |
| 3370 | 3360 | // If there's no work queued, check if there's anything outdated |
| 3371 | 3361 | // 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 |
| 3413 | 3403 | |
| 3414 | 3404 | assert(decl.has_tv); |
| 3415 | 3405 | |
| 3416 | if (decl.alive) { | |
| 3417 | try module.linkerUpdateDecl(decl_index); | |
| 3418 | return; | |
| 3419 | } | |
| 3420 | ||
| 3421 | // Instead of sending this decl to the linker, we actually will delete it | |
| 3422 | // because we found out that it in fact was never referenced. | |
| 3423 | module.deleteUnusedDecl(decl_index); | |
| 3406 | try module.linkerUpdateDecl(decl_index); | |
| 3424 | 3407 | return; |
| 3425 | 3408 | }, |
| 3426 | 3409 | } |
src/InternPool.zig-1| ... | ... | @@ -6740,7 +6740,6 @@ fn finishFuncInstance( |
| 6740 | 6740 | .zir_decl_index = fn_owner_decl.zir_decl_index, |
| 6741 | 6741 | .is_pub = fn_owner_decl.is_pub, |
| 6742 | 6742 | .is_exported = fn_owner_decl.is_exported, |
| 6743 | .alive = true, | |
| 6744 | 6743 | .kind = .anon, |
| 6745 | 6744 | }); |
| 6746 | 6745 | errdefer ip.destroyDecl(gpa, decl_index); |
src/Module.zig+1-63| ... | ... | @@ -394,15 +394,6 @@ pub const Decl = struct { |
| 394 | 394 | is_pub: bool, |
| 395 | 395 | /// Whether the corresponding AST decl has a `export` keyword. |
| 396 | 396 | is_exported: bool, |
| 397 | /// Flag used by garbage collection to mark and sweep. | |
| 398 | /// Decls which correspond to an AST node always have this field set to `true`. | |
| 399 | /// Anonymous Decls are initialized with this field set to `false` and then it | |
| 400 | /// is the responsibility of machine code backends to mark it `true` whenever | |
| 401 | /// a `decl_ref` Value is encountered that points to this Decl. | |
| 402 | /// When the `codegen_decl` job is encountered in the main work queue, if the | |
| 403 | /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it | |
| 404 | /// deletes the Decl on the spot. | |
| 405 | alive: bool, | |
| 406 | 397 | /// If true `name` is already fully qualified. |
| 407 | 398 | name_fully_qualified: bool = false, |
| 408 | 399 | /// What kind of a declaration is this. |
| ... | ... | @@ -3525,7 +3516,6 @@ fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3525 | 3516 | new_decl.is_exported = false; |
| 3526 | 3517 | new_decl.alignment = .none; |
| 3527 | 3518 | new_decl.@"linksection" = .none; |
| 3528 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. | |
| 3529 | 3519 | new_decl.analysis = .in_progress; |
| 3530 | 3520 | |
| 3531 | 3521 | if (file.status != .success_zir) { |
| ... | ... | @@ -4375,7 +4365,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void |
| 4375 | 4365 | const decl = zcu.declPtr(decl_index); |
| 4376 | 4366 | const was_exported = decl.is_exported; |
| 4377 | 4367 | assert(decl.kind == kind); // ZIR tracking should preserve this |
| 4378 | assert(decl.alive); | |
| 4379 | 4368 | decl.name = decl_name; |
| 4380 | 4369 | decl.src_node = decl_node; |
| 4381 | 4370 | decl.src_line = line; |
| ... | ... | @@ -4392,7 +4381,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void |
| 4392 | 4381 | new_decl.is_pub = declaration.flags.is_pub; |
| 4393 | 4382 | new_decl.is_exported = declaration.flags.is_export; |
| 4394 | 4383 | new_decl.zir_decl_index = tracked_inst.toOptional(); |
| 4395 | new_decl.alive = true; // This Decl corresponds to an AST node and is therefore always alive. | |
| 4396 | 4384 | break :decl_index .{ false, new_decl_index }; |
| 4397 | 4385 | }; |
| 4398 | 4386 | |
| ... | ... | @@ -4470,12 +4458,8 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { |
| 4470 | 4458 | |
| 4471 | 4459 | /// Finalize the creation of an anon decl. |
| 4472 | 4460 | pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { |
| 4473 | // The Decl starts off with alive=false and the codegen backend will set alive=true | |
| 4474 | // if the Decl is referenced by an instruction or another constant. Otherwise, | |
| 4475 | // the Decl will be garbage collected by the `codegen_decl` task instead of sent | |
| 4476 | // to the linker. | |
| 4477 | 4461 | if (mod.declPtr(decl_index).typeOf(mod).isFnOrHasRuntimeBits(mod)) { |
| 4478 | try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = decl_index }); | |
| 4462 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); | |
| 4479 | 4463 | } |
| 4480 | 4464 | } |
| 4481 | 4465 | |
| ... | ... | @@ -4815,7 +4799,6 @@ pub fn allocateNewDecl( |
| 4815 | 4799 | .zir_decl_index = .none, |
| 4816 | 4800 | .is_pub = false, |
| 4817 | 4801 | .is_exported = false, |
| 4818 | .alive = false, | |
| 4819 | 4802 | .kind = .anon, |
| 4820 | 4803 | }); |
| 4821 | 4804 | |
| ... | ... | @@ -5582,51 +5565,6 @@ fn reportRetryableFileError( |
| 5582 | 5565 | gop.value_ptr.* = err_msg; |
| 5583 | 5566 | } |
| 5584 | 5567 | |
| 5585 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { | |
| 5586 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 5587 | .variable => |variable| try mod.markDeclIndexAlive(variable.decl), | |
| 5588 | .extern_func => |extern_func| try mod.markDeclIndexAlive(extern_func.decl), | |
| 5589 | .func => |func| try mod.markDeclIndexAlive(func.owner_decl), | |
| 5590 | .error_union => |error_union| switch (error_union.val) { | |
| 5591 | .err_name => {}, | |
| 5592 | .payload => |payload| try mod.markReferencedDeclsAlive(Value.fromInterned(payload)), | |
| 5593 | }, | |
| 5594 | .slice => |slice| { | |
| 5595 | try mod.markReferencedDeclsAlive(Value.fromInterned(slice.ptr)); | |
| 5596 | try mod.markReferencedDeclsAlive(Value.fromInterned(slice.len)); | |
| 5597 | }, | |
| 5598 | .ptr => |ptr| switch (ptr.addr) { | |
| 5599 | .decl => |decl| try mod.markDeclIndexAlive(decl), | |
| 5600 | .anon_decl => {}, | |
| 5601 | .int, .comptime_field, .comptime_alloc => {}, | |
| 5602 | .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)), | |
| 5603 | .elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)), | |
| 5604 | }, | |
| 5605 | .opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(opt.val)), | |
| 5606 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| | |
| 5607 | try mod.markReferencedDeclsAlive(Value.fromInterned(elem)), | |
| 5608 | .un => |un| { | |
| 5609 | if (un.tag != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(un.tag)); | |
| 5610 | try mod.markReferencedDeclsAlive(Value.fromInterned(un.val)); | |
| 5611 | }, | |
| 5612 | else => {}, | |
| 5613 | } | |
| 5614 | } | |
| 5615 | ||
| 5616 | pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void { | |
| 5617 | if (decl.alive) return; | |
| 5618 | decl.alive = true; | |
| 5619 | ||
| 5620 | // This is the first time we are marking this Decl alive. We must | |
| 5621 | // therefore recurse into its value and mark any Decl it references | |
| 5622 | // as also alive, so that any Decl referenced does not get garbage collected. | |
| 5623 | try mod.markReferencedDeclsAlive(decl.val); | |
| 5624 | } | |
| 5625 | ||
| 5626 | fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { | |
| 5627 | return mod.markDeclAlive(mod.declPtr(decl_index)); | |
| 5628 | } | |
| 5629 | ||
| 5630 | 5568 | pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void { |
| 5631 | 5569 | const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index); |
| 5632 | 5570 | if (gop.found_existing) { |
src/Sema.zig-2| ... | ... | @@ -6445,8 +6445,6 @@ pub fn analyzeExport( |
| 6445 | 6445 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 6446 | 6446 | } |
| 6447 | 6447 | |
| 6448 | // This decl is alive no matter what, since it's being exported | |
| 6449 | try mod.markDeclAlive(exported_decl); | |
| 6450 | 6448 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); |
| 6451 | 6449 | |
| 6452 | 6450 | try addExport(mod, .{ |
src/arch/wasm/CodeGen.zig-2| ... | ... | @@ -3121,7 +3121,6 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 3121 | 3121 | fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { |
| 3122 | 3122 | const mod = func.bin_file.base.comp.module.?; |
| 3123 | 3123 | const decl = mod.declPtr(decl_index); |
| 3124 | try mod.markDeclAlive(decl); | |
| 3125 | 3124 | const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); |
| 3126 | 3125 | return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); |
| 3127 | 3126 | } |
| ... | ... | @@ -3178,7 +3177,6 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl |
| 3178 | 3177 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3179 | 3178 | } |
| 3180 | 3179 | |
| 3181 | try mod.markDeclAlive(decl); | |
| 3182 | 3180 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); |
| 3183 | 3181 | const atom = func.bin_file.getAtom(atom_index); |
| 3184 | 3182 |
src/arch/x86_64/CodeGen.zig-2| ... | ... | @@ -12263,7 +12263,6 @@ fn genCall(self: *Self, info: union(enum) { |
| 12263 | 12263 | }, |
| 12264 | 12264 | }) { |
| 12265 | 12265 | .func => |func| { |
| 12266 | try mod.markDeclAlive(mod.declPtr(func.owner_decl)); | |
| 12267 | 12266 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 12268 | 12267 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); |
| 12269 | 12268 | const sym = elf_file.symbol(sym_index); |
| ... | ... | @@ -12323,7 +12322,6 @@ fn genCall(self: *Self, info: union(enum) { |
| 12323 | 12322 | }, |
| 12324 | 12323 | .extern_func => |extern_func| { |
| 12325 | 12324 | const owner_decl = mod.declPtr(extern_func.decl); |
| 12326 | try mod.markDeclAlive(owner_decl); | |
| 12327 | 12325 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); |
| 12328 | 12326 | const decl_name = mod.intern_pool.stringToSlice(owner_decl.name); |
| 12329 | 12327 | try self.genExternSymbolRef(.call, lib_name, decl_name); |
src/codegen.zig-4| ... | ... | @@ -835,8 +835,6 @@ fn lowerDeclRef( |
| 835 | 835 | return Result.ok; |
| 836 | 836 | } |
| 837 | 837 | |
| 838 | try zcu.markDeclAlive(decl); | |
| 839 | ||
| 840 | 838 | const vaddr = try lf.getDeclVAddr(decl_index, .{ |
| 841 | 839 | .parent_atom_index = reloc_info.parent_atom_index, |
| 842 | 840 | .offset = code.items.len, |
| ... | ... | @@ -958,8 +956,6 @@ fn genDeclRef( |
| 958 | 956 | } |
| 959 | 957 | } |
| 960 | 958 | |
| 961 | try zcu.markDeclAlive(decl); | |
| 962 | ||
| 963 | 959 | const decl_namespace = zcu.namespacePtr(decl.src_namespace); |
| 964 | 960 | const single_threaded = decl_namespace.file_scope.mod.single_threaded; |
| 965 | 961 | const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded; |
src/codegen/c.zig-1| ... | ... | @@ -2010,7 +2010,6 @@ pub const DeclGen = struct { |
| 2010 | 2010 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void { |
| 2011 | 2011 | const mod = dg.module; |
| 2012 | 2012 | const decl = mod.declPtr(decl_index); |
| 2013 | try mod.markDeclAlive(decl); | |
| 2014 | 2013 | |
| 2015 | 2014 | if (mod.decl_exports.get(decl_index)) |exports| { |
| 2016 | 2015 | try writer.print("{ }", .{ |
src/codegen/llvm.zig-7| ... | ... | @@ -3722,15 +3722,11 @@ pub const Object = struct { |
| 3722 | 3722 | => unreachable, // non-runtime values |
| 3723 | 3723 | .extern_func => |extern_func| { |
| 3724 | 3724 | const fn_decl_index = extern_func.decl; |
| 3725 | const fn_decl = mod.declPtr(fn_decl_index); | |
| 3726 | try mod.markDeclAlive(fn_decl); | |
| 3727 | 3725 | const function_index = try o.resolveLlvmFunction(fn_decl_index); |
| 3728 | 3726 | return function_index.ptrConst(&o.builder).global.toConst(); |
| 3729 | 3727 | }, |
| 3730 | 3728 | .func => |func| { |
| 3731 | 3729 | const fn_decl_index = func.owner_decl; |
| 3732 | const fn_decl = mod.declPtr(fn_decl_index); | |
| 3733 | try mod.markDeclAlive(fn_decl); | |
| 3734 | 3730 | const function_index = try o.resolveLlvmFunction(fn_decl_index); |
| 3735 | 3731 | return function_index.ptrConst(&o.builder).global.toConst(); |
| 3736 | 3732 | }, |
| ... | ... | @@ -4262,7 +4258,6 @@ pub const Object = struct { |
| 4262 | 4258 | fn lowerParentPtrDecl(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant { |
| 4263 | 4259 | const mod = o.module; |
| 4264 | 4260 | const decl = mod.declPtr(decl_index); |
| 4265 | try mod.markDeclAlive(decl); | |
| 4266 | 4261 | const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod)); |
| 4267 | 4262 | return o.lowerDeclRefValue(ptr_ty, decl_index); |
| 4268 | 4263 | } |
| ... | ... | @@ -4455,8 +4450,6 @@ pub const Object = struct { |
| 4455 | 4450 | if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or |
| 4456 | 4451 | (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ty); |
| 4457 | 4452 | |
| 4458 | try mod.markDeclAlive(decl); | |
| 4459 | ||
| 4460 | 4453 | const llvm_global = if (is_fn_body) |
| 4461 | 4454 | (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global |
| 4462 | 4455 | else |
src/codegen/spirv.zig-1| ... | ... | @@ -255,7 +255,6 @@ pub const Object = struct { |
| 255 | 255 | pub fn resolveDecl(self: *Object, mod: *Module, decl_index: InternPool.DeclIndex) !SpvModule.Decl.Index { |
| 256 | 256 | const decl = mod.declPtr(decl_index); |
| 257 | 257 | assert(decl.has_tv); // TODO: Do we need to handle a situation where this is false? |
| 258 | try mod.markDeclAlive(decl); | |
| 259 | 258 | |
| 260 | 259 | const entry = try self.decl_link.getOrPut(self.gpa, decl_index); |
| 261 | 260 | if (!entry.found_existing) { |