wasm-linker: support gc for wasm backend code
When using the Wasm backend, we will now also perform garbage collection there, to ensure unreferenced symbols do not get parsed nor emit into the final binary.
This commit is contained in:
@@ -1333,6 +1333,10 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
atom.deinit(gpa);
|
||||
}
|
||||
}
|
||||
for (wasm.synthetic_functions.items) |atom_index| {
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
atom.deinit(gpa);
|
||||
}
|
||||
|
||||
wasm.decls.deinit(gpa);
|
||||
wasm.anon_decls.deinit(gpa);
|
||||
@@ -1364,10 +1368,6 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
wasm.exports.deinit(gpa);
|
||||
|
||||
wasm.string_table.deinit(gpa);
|
||||
for (wasm.synthetic_functions.items) |atom_index| {
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
atom.deinit(gpa);
|
||||
}
|
||||
wasm.synthetic_functions.deinit(gpa);
|
||||
|
||||
if (wasm.dwarf) |*dwarf| {
|
||||
@@ -2134,9 +2134,13 @@ const Kind = union(enum) {
|
||||
fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
|
||||
if (symbol.isDead()) {
|
||||
// Prevent unreferenced symbols from being parsed.
|
||||
return;
|
||||
}
|
||||
const final_index: u32 = switch (kind) {
|
||||
.function => result: {
|
||||
const index = @as(u32, @intCast(wasm.functions.count() + wasm.imported_functions_count));
|
||||
const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count);
|
||||
const type_index = wasm.atom_types.get(atom_index).?;
|
||||
try wasm.functions.putNoClobber(
|
||||
wasm.base.allocator,
|
||||
@@ -2147,7 +2151,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
|
||||
symbol.index = index;
|
||||
|
||||
if (wasm.code_section_index == null) {
|
||||
wasm.code_section_index = @as(u32, @intCast(wasm.segments.items.len));
|
||||
wasm.code_section_index = @intCast(wasm.segments.items.len);
|
||||
try wasm.segments.append(wasm.base.allocator, .{
|
||||
.alignment = atom.alignment,
|
||||
.size = atom.size,
|
||||
@@ -2185,12 +2189,12 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
|
||||
const index = gop.value_ptr.*;
|
||||
wasm.segments.items[index].size += atom.size;
|
||||
|
||||
symbol.index = @as(u32, @intCast(wasm.segment_info.getIndex(index).?));
|
||||
symbol.index = @intCast(wasm.segment_info.getIndex(index).?);
|
||||
// segment info already exists, so free its memory
|
||||
wasm.base.allocator.free(segment_name);
|
||||
break :result index;
|
||||
} else {
|
||||
const index = @as(u32, @intCast(wasm.segments.items.len));
|
||||
const index: u32 = @intCast(wasm.segments.items.len);
|
||||
var flags: u32 = 0;
|
||||
if (wasm.base.options.shared_memory) {
|
||||
flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
|
||||
@@ -2203,7 +2207,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
|
||||
});
|
||||
gop.value_ptr.* = index;
|
||||
|
||||
const info_index = @as(u32, @intCast(wasm.segment_info.count()));
|
||||
const info_index: u32 = @intCast(wasm.segment_info.count());
|
||||
try wasm.segment_info.put(wasm.base.allocator, index, segment_info);
|
||||
symbol.index = info_index;
|
||||
break :result index;
|
||||
@@ -2318,8 +2322,10 @@ fn allocateAtoms(wasm: *Wasm) !void {
|
||||
fn allocateVirtualAddresses(wasm: *Wasm) void {
|
||||
for (wasm.resolved_symbols.keys()) |loc| {
|
||||
const symbol = loc.getSymbol(wasm);
|
||||
if (symbol.tag != .data) {
|
||||
continue; // only data symbols have virtual addresses
|
||||
if (symbol.tag != .data or symbol.isDead()) {
|
||||
// Only data symbols have virtual addresses.
|
||||
// Dead symbols do not get allocated, so we don't need to set their virtual address either.
|
||||
continue;
|
||||
}
|
||||
const atom_index = wasm.symbol_atom.get(loc) orelse {
|
||||
// synthetic symbol that does not contain an atom
|
||||
@@ -2681,10 +2687,10 @@ fn setupImports(wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
for (wasm.resolved_symbols.keys()) |symbol_loc| {
|
||||
if (symbol_loc.file == null) {
|
||||
const file_index = symbol_loc.file orelse {
|
||||
// imports generated by Zig code are already in the `import` section
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
const symbol = symbol_loc.getSymbol(wasm);
|
||||
if (symbol.isDead() or
|
||||
@@ -2695,7 +2701,7 @@ fn setupImports(wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});
|
||||
const object = wasm.objects.items[symbol_loc.file.?];
|
||||
const object = wasm.objects.items[file_index];
|
||||
const import = object.findImport(symbol.tag.externalType(), symbol.index);
|
||||
|
||||
// We copy the import to a new import to ensure the names contain references
|
||||
@@ -3092,6 +3098,11 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3
|
||||
.offset = 0,
|
||||
.flags = flags,
|
||||
});
|
||||
try wasm.segment_info.putNoClobber(wasm.base.allocator, index, .{
|
||||
.name = try wasm.base.allocator.dupe(u8, segment_info.name),
|
||||
.alignment = segment_info.alignment,
|
||||
.flags = segment_info.flags,
|
||||
});
|
||||
return index;
|
||||
} else return result.value_ptr.*;
|
||||
},
|
||||
@@ -3198,6 +3209,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
|
||||
.virtual_address = undefined,
|
||||
};
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.mark();
|
||||
|
||||
try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
|
||||
|
||||
@@ -3230,6 +3242,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
|
||||
.virtual_address = undefined,
|
||||
};
|
||||
names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
names_symbol.mark();
|
||||
|
||||
log.debug("Populating error names", .{});
|
||||
|
||||
@@ -3606,9 +3619,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
// So we can rebuild the binary file on each incremental update
|
||||
defer wasm.resetState();
|
||||
try wasm.setupInitFunctions();
|
||||
try wasm.setupErrorsLen();
|
||||
try wasm.setupStart();
|
||||
try wasm.markReferences();
|
||||
try wasm.setupErrorsLen();
|
||||
try wasm.setupImports();
|
||||
if (wasm.base.options.module) |mod| {
|
||||
var decl_it = wasm.decls.iterator();
|
||||
@@ -5152,14 +5165,15 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = loc.file orelse return; // Marking synthetic and Zig symbols is done seperately
|
||||
const object = &wasm.objects.items[file];
|
||||
const atom_index = try Object.parseSymbolIntoAtom(object, file, loc.index, wasm);
|
||||
const atom_index = if (loc.file) |file_index| idx: {
|
||||
const object = &wasm.objects.items[file_index];
|
||||
const atom_index = try object.parseSymbolIntoAtom(file_index, loc.index, wasm);
|
||||
break :idx atom_index;
|
||||
} else wasm.symbol_atom.get(loc) orelse return;
|
||||
|
||||
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 = file };
|
||||
for (atom.relocs.items) |reloc| {
|
||||
const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };
|
||||
try wasm.mark(target_loc.finalLoc(wasm));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user