aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/link/Wasm.zig82
-rw-r--r--src/link/Wasm/Atom.zig2
2 files changed, 66 insertions, 18 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 2e6a5dbc96..71f5c6f784 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -103,8 +103,10 @@ debug_aranges: std.ArrayListUnmanaged(u8) = .{},
// Output sections
/// Output type section
func_types: std.ArrayListUnmanaged(wasm.Type) = .{},
-/// Output function section
-functions: std.ArrayListUnmanaged(wasm.Func) = .{},
+/// Output function section where the key is the original
+/// function index and the value is function.
+/// This allows us to map multiple symbols to the same function.
+functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, wasm.Func) = .{},
/// Output global section
wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{},
/// Memory section
@@ -1042,8 +1044,12 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self);
const final_index: u32 = switch (kind) {
.function => |fn_data| result: {
- const index = @intCast(u32, self.functions.items.len + self.imported_functions_count);
- try self.functions.append(self.base.allocator, .{ .type_index = fn_data.type_index });
+ const index = @intCast(u32, self.functions.count() + self.imported_functions_count);
+ try self.functions.putNoClobber(
+ self.base.allocator,
+ .{ .file = null, .index = index },
+ .{ .type_index = fn_data.type_index },
+ );
symbol.tag = .function;
symbol.index = index;
@@ -1256,8 +1262,14 @@ fn mergeSections(self: *Wasm) !void {
switch (symbol.tag) {
.function => {
const original_func = object.functions[index];
- symbol.index = @intCast(u32, self.functions.items.len) + self.imported_functions_count;
- try self.functions.append(self.base.allocator, original_func);
+ const gop = try self.functions.getOrPut(
+ self.base.allocator,
+ .{ .file = sym_loc.file, .index = symbol.index },
+ );
+ if (!gop.found_existing) {
+ gop.value_ptr.* = original_func;
+ }
+ symbol.index = @intCast(u32, gop.index) + self.imported_functions_count;
},
.global => {
const original_global = object.globals[index];
@@ -1273,7 +1285,7 @@ fn mergeSections(self: *Wasm) !void {
}
}
- log.debug("Merged ({d}) functions", .{self.functions.items.len});
+ log.debug("Merged ({d}) functions", .{self.functions.count()});
log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len});
log.debug("Merged ({d}) tables", .{self.tables.items.len});
}
@@ -1282,6 +1294,13 @@ fn mergeSections(self: *Wasm) !void {
/// 'types' section, while assigning the type index to the representing
/// section (import, export, function).
fn mergeTypes(self: *Wasm) !void {
+ // A map to track which functions have already had their
+ // type inserted. If we do this for the same function multiple times,
+ // it will be overwritten with the incorrect type.
+ var dirty = std.AutoHashMap(u32, void).init(self.base.allocator);
+ try dirty.ensureUnusedCapacity(@intCast(u32, self.functions.count()) + self.imported_functions_count);
+ defer dirty.deinit();
+
for (self.resolved_symbols.keys()) |sym_loc| {
if (sym_loc.file == null) {
// zig code-generated symbols are already present in final type section
@@ -1294,6 +1313,10 @@ fn mergeTypes(self: *Wasm) !void {
continue;
}
+ if (dirty.contains(symbol.index)) {
+ continue; // We already added the type of this symbol
+ }
+
if (symbol.isUndefined()) {
log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)});
const import: *types.Import = self.imports.getPtr(sym_loc).?;
@@ -1301,9 +1324,11 @@ fn mergeTypes(self: *Wasm) !void {
import.kind.function = try self.putOrGetFuncType(original_type);
} else {
log.debug("Adding type from function '{s}'", .{sym_loc.getName(self)});
- const func = &self.functions.items[symbol.index - self.imported_functions_count];
+ const func = &self.functions.values()[symbol.index - self.imported_functions_count];
func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]);
}
+
+ dirty.putAssumeCapacityNoClobber(symbol.index, {});
}
log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len});
}
@@ -1711,7 +1736,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
for (comp.c_object_table.keys()) |c_object| {
try positionals.append(c_object.status.success.object_path);
}
- // TODO: Also link with other objects such as compiler-rt
+
+ if (comp.compiler_rt_static_lib) |lib| {
+ try positionals.append(lib.full_object_path);
+ }
+
try self.parseInputFiles(positionals.items);
var object_index: u16 = 0;
@@ -1840,10 +1869,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
}
// Function section
- if (self.functions.items.len != 0) {
+ if (self.functions.count() != 0) {
const header_offset = try reserveVecSectionHeader(file);
const writer = file.writer();
- for (self.functions.items) |function| {
+ for (self.functions.values()) |function| {
try leb.writeULEB128(writer, function.type_index);
}
@@ -1852,7 +1881,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
header_offset,
.function,
@intCast(u32, (try file.getPos()) - header_offset - header_size),
- @intCast(u32, self.functions.items.len),
+ @intCast(u32, self.functions.count()),
);
section_count += 1;
}
@@ -1984,22 +2013,41 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
const header_offset = try reserveVecSectionHeader(file);
const writer = file.writer();
var atom: *Atom = self.atoms.get(code_index).?.getFirst();
+
+ // The code section must be sorted in line with the function order.
+ var sorted_atoms = try std.ArrayList(*Atom).initCapacity(self.base.allocator, self.functions.count());
+ defer sorted_atoms.deinit();
+
while (true) {
if (!is_obj) {
try atom.resolveRelocs(self);
}
- try leb.writeULEB128(writer, atom.size);
- try writer.writeAll(atom.code.items);
+ sorted_atoms.appendAssumeCapacity(atom);
atom = atom.next orelse break;
}
+ const atom_sort_fn = struct {
+ fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool {
+ const lhs_sym = lhs.symbolLoc().getSymbol(ctx);
+ const rhs_sym = rhs.symbolLoc().getSymbol(ctx);
+ return lhs_sym.index < rhs_sym.index;
+ }
+ }.sort;
+
+ std.sort.sort(*Atom, sorted_atoms.items, self, atom_sort_fn);
+
+ for (sorted_atoms.items) |sorted_atom| {
+ try leb.writeULEB128(writer, sorted_atom.size);
+ try writer.writeAll(sorted_atom.code.items);
+ }
+
code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size);
try writeVecSectionHeader(
file,
header_offset,
.code,
code_section_size,
- @intCast(u32, self.functions.items.len),
+ @intCast(u32, self.functions.count()),
);
code_section_index = section_count;
section_count += 1;
@@ -2135,7 +2183,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
}
};
- var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.items.len + self.imported_functions_count);
+ var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.count() + self.imported_functions_count);
var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count);
var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count());
@@ -2145,7 +2193,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
break :blk self.string_table.get(self.imports.get(sym_loc).?.name);
} else sym_loc.getName(self);
switch (symbol.tag) {
- .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = name }),
+ .function => try funcs.append(.{ .index = symbol.index, .name = name }),
.global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = name }),
else => {},
}
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig
index 03b6fc6cf4..40b7f64804 100644
--- a/src/link/Wasm/Atom.zig
+++ b/src/link/Wasm/Atom.zig
@@ -155,7 +155,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_INDEX_SLEB64,
=> return wasm_bin.function_table.get(target_loc) orelse 0,
- .R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.items[symbol.index].type_index,
+ .R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.values()[symbol.index - wasm_bin.imported_functions_count].type_index,
.R_WASM_GLOBAL_INDEX_I32,
.R_WASM_GLOBAL_INDEX_LEB,
=> return symbol.index,