Commit 589aef1537
Changed files (2)
src
link
src/link/Wasm/Symbol.zig
@@ -79,6 +79,9 @@ pub const Flag = enum(u32) {
WASM_SYM_NO_STRIP = 0x80,
/// Indicates a symbol is TLS
WASM_SYM_TLS = 0x100,
+ /// Zig specific flag. Uses the most significant bit of the flag to annotate whether a symbol is
+ /// alive or not. Dead symbols are allowed to be garbage collected.
+ alive = 0x80000000,
};
/// Verifies if the given symbol should be imported from the
@@ -92,6 +95,19 @@ pub fn requiresImport(symbol: Symbol) bool {
return true;
}
+/// Marks a symbol as 'alive', ensuring the garbage collector will not collect the trash.
+pub fn mark(symbol: *Symbol) void {
+ symbol.flags |= @intFromEnum(Flag.alive);
+}
+
+pub fn isAlive(symbol: Symbol) bool {
+ return symbol.flags & @intFromEnum(Flag.alive) != 0;
+}
+
+pub fn isDead(symbol: Symbol) bool {
+ return symbol.flags & @intFromEnum(Flag.alive) == 0;
+}
+
pub fn isTLS(symbol: Symbol) bool {
return symbol.flags & @intFromEnum(Flag.WASM_SYM_TLS) != 0;
}
src/link/Wasm.zig
@@ -3439,12 +3439,13 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
try wasm.setupInitFunctions();
try wasm.setupStart();
- try wasm.setupImports();
for (wasm.objects.items, 0..) |*object, object_index| {
try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm);
}
+ wasm.markReferences();
+ try wasm.setupImports();
try wasm.allocateAtoms();
try wasm.setupMemory();
wasm.allocateVirtualAddresses();
@@ -3529,6 +3530,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.setupInitFunctions();
try wasm.setupErrorsLen();
try wasm.setupStart();
+ wasm.markReferences();
try wasm.setupImports();
if (wasm.base.options.module) |mod| {
var decl_it = wasm.decls.iterator();
@@ -5026,3 +5028,38 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
try wasm.atom_types.put(wasm.base.allocator, atom_index, index);
return index;
}
+
+/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
+/// as well as any of its references.
+fn markReferences(wasm: *Wasm) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+ for (wasm.resolved_symbols.keys()) |sym_loc| {
+ const sym = sym_loc.getSymbol(wasm);
+ if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {
+ wasm.mark(sym_loc);
+ }
+ }
+}
+
+/// Marks a symbol as 'alive' recursively so itself and any references it contains to
+/// other symbols will not be omit from the binary.
+fn mark(wasm: *Wasm, loc: SymbolLoc) void {
+ const symbol = loc.getSymbol(wasm);
+ if (symbol.isAlive()) {
+ // Symbol is already marked alive, including its references.
+ // This means we can skip it so we don't end up marking the same symbols
+ // multiple times.
+ return;
+ }
+ symbol.mark();
+
+ if (wasm.symbol_atom.get(loc)) |atom_index| {
+ const atom = wasm.getAtom(atom_index);
+ const relocations: []const types.Relocation = atom.relocs.items;
+ for (relocations) |reloc| {
+ const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };
+ wasm.mark(target_loc.finalLoc(wasm));
+ }
+ }
+}