| ... | ... | @@ -103,8 +103,10 @@ debug_aranges: std.ArrayListUnmanaged(u8) = .{}, |
| 103 | 103 | // Output sections |
| 104 | 104 | /// Output type section |
| 105 | 105 | func_types: std.ArrayListUnmanaged(wasm.Type) = .{}, |
| 106 | | /// Output function section |
| 107 | | functions: std.ArrayListUnmanaged(wasm.Func) = .{}, |
| 106 | /// Output function section where the key is the original |
| 107 | /// function index and the value is function. |
| 108 | /// This allows us to map multiple symbols to the same function. |
| 109 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, wasm.Func) = .{}, |
| 108 | 110 | /// Output global section |
| 109 | 111 | wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{}, |
| 110 | 112 | /// Memory section |
| ... | ... | @@ -1042,8 +1044,12 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1042 | 1044 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self); |
| 1043 | 1045 | const final_index: u32 = switch (kind) { |
| 1044 | 1046 | .function => |fn_data| result: { |
| 1045 | | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); |
| 1046 | | try self.functions.append(self.base.allocator, .{ .type_index = fn_data.type_index }); |
| 1047 | const index = @intCast(u32, self.functions.count() + self.imported_functions_count); |
| 1048 | try self.functions.putNoClobber( |
| 1049 | self.base.allocator, |
| 1050 | .{ .file = null, .index = index }, |
| 1051 | .{ .type_index = fn_data.type_index }, |
| 1052 | ); |
| 1047 | 1053 | symbol.tag = .function; |
| 1048 | 1054 | symbol.index = index; |
| 1049 | 1055 | |
| ... | ... | @@ -1256,8 +1262,14 @@ fn mergeSections(self: *Wasm) !void { |
| 1256 | 1262 | switch (symbol.tag) { |
| 1257 | 1263 | .function => { |
| 1258 | 1264 | const original_func = object.functions[index]; |
| 1259 | | symbol.index = @intCast(u32, self.functions.items.len) + self.imported_functions_count; |
| 1260 | | try self.functions.append(self.base.allocator, original_func); |
| 1265 | const gop = try self.functions.getOrPut( |
| 1266 | self.base.allocator, |
| 1267 | .{ .file = sym_loc.file, .index = symbol.index }, |
| 1268 | ); |
| 1269 | if (!gop.found_existing) { |
| 1270 | gop.value_ptr.* = original_func; |
| 1271 | } |
| 1272 | symbol.index = @intCast(u32, gop.index) + self.imported_functions_count; |
| 1261 | 1273 | }, |
| 1262 | 1274 | .global => { |
| 1263 | 1275 | const original_global = object.globals[index]; |
| ... | ... | @@ -1273,7 +1285,7 @@ fn mergeSections(self: *Wasm) !void { |
| 1273 | 1285 | } |
| 1274 | 1286 | } |
| 1275 | 1287 | |
| 1276 | | log.debug("Merged ({d}) functions", .{self.functions.items.len}); |
| 1288 | log.debug("Merged ({d}) functions", .{self.functions.count()}); |
| 1277 | 1289 | log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len}); |
| 1278 | 1290 | log.debug("Merged ({d}) tables", .{self.tables.items.len}); |
| 1279 | 1291 | } |
| ... | ... | @@ -1282,6 +1294,13 @@ fn mergeSections(self: *Wasm) !void { |
| 1282 | 1294 | /// 'types' section, while assigning the type index to the representing |
| 1283 | 1295 | /// section (import, export, function). |
| 1284 | 1296 | fn mergeTypes(self: *Wasm) !void { |
| 1297 | // A map to track which functions have already had their |
| 1298 | // type inserted. If we do this for the same function multiple times, |
| 1299 | // it will be overwritten with the incorrect type. |
| 1300 | var dirty = std.AutoHashMap(u32, void).init(self.base.allocator); |
| 1301 | try dirty.ensureUnusedCapacity(@intCast(u32, self.functions.count()) + self.imported_functions_count); |
| 1302 | defer dirty.deinit(); |
| 1303 | |
| 1285 | 1304 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 1286 | 1305 | if (sym_loc.file == null) { |
| 1287 | 1306 | // zig code-generated symbols are already present in final type section |
| ... | ... | @@ -1294,6 +1313,10 @@ fn mergeTypes(self: *Wasm) !void { |
| 1294 | 1313 | continue; |
| 1295 | 1314 | } |
| 1296 | 1315 | |
| 1316 | if (dirty.contains(symbol.index)) { |
| 1317 | continue; // We already added the type of this symbol |
| 1318 | } |
| 1319 | |
| 1297 | 1320 | if (symbol.isUndefined()) { |
| 1298 | 1321 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)}); |
| 1299 | 1322 | const import: *types.Import = self.imports.getPtr(sym_loc).?; |
| ... | ... | @@ -1301,9 +1324,11 @@ fn mergeTypes(self: *Wasm) !void { |
| 1301 | 1324 | import.kind.function = try self.putOrGetFuncType(original_type); |
| 1302 | 1325 | } else { |
| 1303 | 1326 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(self)}); |
| 1304 | | const func = &self.functions.items[symbol.index - self.imported_functions_count]; |
| 1327 | const func = &self.functions.values()[symbol.index - self.imported_functions_count]; |
| 1305 | 1328 | func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]); |
| 1306 | 1329 | } |
| 1330 | |
| 1331 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 1307 | 1332 | } |
| 1308 | 1333 | log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len}); |
| 1309 | 1334 | } |
| ... | ... | @@ -1711,7 +1736,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1711 | 1736 | for (comp.c_object_table.keys()) |c_object| { |
| 1712 | 1737 | try positionals.append(c_object.status.success.object_path); |
| 1713 | 1738 | } |
| 1714 | | // TODO: Also link with other objects such as compiler-rt |
| 1739 | |
| 1740 | if (comp.compiler_rt_static_lib) |lib| { |
| 1741 | try positionals.append(lib.full_object_path); |
| 1742 | } |
| 1743 | |
| 1715 | 1744 | try self.parseInputFiles(positionals.items); |
| 1716 | 1745 | |
| 1717 | 1746 | var object_index: u16 = 0; |
| ... | ... | @@ -1840,10 +1869,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1840 | 1869 | } |
| 1841 | 1870 | |
| 1842 | 1871 | // Function section |
| 1843 | | if (self.functions.items.len != 0) { |
| 1872 | if (self.functions.count() != 0) { |
| 1844 | 1873 | const header_offset = try reserveVecSectionHeader(file); |
| 1845 | 1874 | const writer = file.writer(); |
| 1846 | | for (self.functions.items) |function| { |
| 1875 | for (self.functions.values()) |function| { |
| 1847 | 1876 | try leb.writeULEB128(writer, function.type_index); |
| 1848 | 1877 | } |
| 1849 | 1878 | |
| ... | ... | @@ -1852,7 +1881,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1852 | 1881 | header_offset, |
| 1853 | 1882 | .function, |
| 1854 | 1883 | @intCast(u32, (try file.getPos()) - header_offset - header_size), |
| 1855 | | @intCast(u32, self.functions.items.len), |
| 1884 | @intCast(u32, self.functions.count()), |
| 1856 | 1885 | ); |
| 1857 | 1886 | section_count += 1; |
| 1858 | 1887 | } |
| ... | ... | @@ -1984,22 +2013,41 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1984 | 2013 | const header_offset = try reserveVecSectionHeader(file); |
| 1985 | 2014 | const writer = file.writer(); |
| 1986 | 2015 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); |
| 2016 | |
| 2017 | // The code section must be sorted in line with the function order. |
| 2018 | var sorted_atoms = try std.ArrayList(*Atom).initCapacity(self.base.allocator, self.functions.count()); |
| 2019 | defer sorted_atoms.deinit(); |
| 2020 | |
| 1987 | 2021 | while (true) { |
| 1988 | 2022 | if (!is_obj) { |
| 1989 | 2023 | try atom.resolveRelocs(self); |
| 1990 | 2024 | } |
| 1991 | | try leb.writeULEB128(writer, atom.size); |
| 1992 | | try writer.writeAll(atom.code.items); |
| 2025 | sorted_atoms.appendAssumeCapacity(atom); |
| 1993 | 2026 | atom = atom.next orelse break; |
| 1994 | 2027 | } |
| 1995 | 2028 | |
| 2029 | const atom_sort_fn = struct { |
| 2030 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { |
| 2031 | const lhs_sym = lhs.symbolLoc().getSymbol(ctx); |
| 2032 | const rhs_sym = rhs.symbolLoc().getSymbol(ctx); |
| 2033 | return lhs_sym.index < rhs_sym.index; |
| 2034 | } |
| 2035 | }.sort; |
| 2036 | |
| 2037 | std.sort.sort(*Atom, sorted_atoms.items, self, atom_sort_fn); |
| 2038 | |
| 2039 | for (sorted_atoms.items) |sorted_atom| { |
| 2040 | try leb.writeULEB128(writer, sorted_atom.size); |
| 2041 | try writer.writeAll(sorted_atom.code.items); |
| 2042 | } |
| 2043 | |
| 1996 | 2044 | code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size); |
| 1997 | 2045 | try writeVecSectionHeader( |
| 1998 | 2046 | file, |
| 1999 | 2047 | header_offset, |
| 2000 | 2048 | .code, |
| 2001 | 2049 | code_section_size, |
| 2002 | | @intCast(u32, self.functions.items.len), |
| 2050 | @intCast(u32, self.functions.count()), |
| 2003 | 2051 | ); |
| 2004 | 2052 | code_section_index = section_count; |
| 2005 | 2053 | section_count += 1; |
| ... | ... | @@ -2135,7 +2183,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2135 | 2183 | } |
| 2136 | 2184 | }; |
| 2137 | 2185 | |
| 2138 | | var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.items.len + self.imported_functions_count); |
| 2186 | var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.count() + self.imported_functions_count); |
| 2139 | 2187 | var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count); |
| 2140 | 2188 | var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count()); |
| 2141 | 2189 | |
| ... | ... | @@ -2145,7 +2193,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2145 | 2193 | break :blk self.string_table.get(self.imports.get(sym_loc).?.name); |
| 2146 | 2194 | } else sym_loc.getName(self); |
| 2147 | 2195 | switch (symbol.tag) { |
| 2148 | | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), |
| 2196 | .function => try funcs.append(.{ .index = symbol.index, .name = name }), |
| 2149 | 2197 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), |
| 2150 | 2198 | else => {}, |
| 2151 | 2199 | } |