| ... | @@ -103,8 +103,10 @@ debug_aranges: std.ArrayListUnmanaged(u8) = .{}, | ... | @@ -103,8 +103,10 @@ debug_aranges: std.ArrayListUnmanaged(u8) = .{}, |
| 103 | // Output sections | 103 | // Output sections |
| 104 | /// Output type section | 104 | /// Output type section |
| 105 | func_types: std.ArrayListUnmanaged(wasm.Type) = .{}, | 105 | func_types: std.ArrayListUnmanaged(wasm.Type) = .{}, |
| 106 | /// Output function section | 106 | /// Output function section where the key is the original |
| 107 | functions: std.ArrayListUnmanaged(wasm.Func) = .{}, | 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 | /// Output global section | 110 | /// Output global section |
| 109 | wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{}, | 111 | wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{}, |
| 110 | /// Memory section | 112 | /// Memory section |
| ... | @@ -1042,8 +1044,12 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { | ... | @@ -1042,8 +1044,12 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1042 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self); | 1044 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self); |
| 1043 | const final_index: u32 = switch (kind) { | 1045 | const final_index: u32 = switch (kind) { |
| 1044 | .function => |fn_data| result: { | 1046 | .function => |fn_data| result: { |
| 1045 | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); | 1047 | const index = @intCast(u32, self.functions.count() + self.imported_functions_count); |
| 1046 | try self.functions.append(self.base.allocator, .{ .type_index = fn_data.type_index }); | 1048 | try self.functions.putNoClobber( |
| | 1049 | self.base.allocator, |
| | 1050 | .{ .file = null, .index = index }, |
| | 1051 | .{ .type_index = fn_data.type_index }, |
| | 1052 | ); |
| 1047 | symbol.tag = .function; | 1053 | symbol.tag = .function; |
| 1048 | symbol.index = index; | 1054 | symbol.index = index; |
| 1049 | | 1055 | |
| ... | @@ -1256,8 +1262,14 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -1256,8 +1262,14 @@ fn mergeSections(self: *Wasm) !void { |
| 1256 | switch (symbol.tag) { | 1262 | switch (symbol.tag) { |
| 1257 | .function => { | 1263 | .function => { |
| 1258 | const original_func = object.functions[index]; | 1264 | const original_func = object.functions[index]; |
| 1259 | symbol.index = @intCast(u32, self.functions.items.len) + self.imported_functions_count; | 1265 | const gop = try self.functions.getOrPut( |
| 1260 | try self.functions.append(self.base.allocator, original_func); | 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 | .global => { | 1274 | .global => { |
| 1263 | const original_global = object.globals[index]; | 1275 | const original_global = object.globals[index]; |
| ... | @@ -1273,7 +1285,7 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -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 | log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len}); | 1289 | log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len}); |
| 1278 | log.debug("Merged ({d}) tables", .{self.tables.items.len}); | 1290 | log.debug("Merged ({d}) tables", .{self.tables.items.len}); |
| 1279 | } | 1291 | } |
| ... | @@ -1282,6 +1294,13 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -1282,6 +1294,13 @@ fn mergeSections(self: *Wasm) !void { |
| 1282 | /// 'types' section, while assigning the type index to the representing | 1294 | /// 'types' section, while assigning the type index to the representing |
| 1283 | /// section (import, export, function). | 1295 | /// section (import, export, function). |
| 1284 | fn mergeTypes(self: *Wasm) !void { | 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 | for (self.resolved_symbols.keys()) |sym_loc| { | 1304 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 1286 | if (sym_loc.file == null) { | 1305 | if (sym_loc.file == null) { |
| 1287 | // zig code-generated symbols are already present in final type section | 1306 | // zig code-generated symbols are already present in final type section |
| ... | @@ -1294,6 +1313,10 @@ fn mergeTypes(self: *Wasm) !void { | ... | @@ -1294,6 +1313,10 @@ fn mergeTypes(self: *Wasm) !void { |
| 1294 | continue; | 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 | if (symbol.isUndefined()) { | 1320 | if (symbol.isUndefined()) { |
| 1298 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)}); | 1321 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)}); |
| 1299 | const import: *types.Import = self.imports.getPtr(sym_loc).?; | 1322 | const import: *types.Import = self.imports.getPtr(sym_loc).?; |
| ... | @@ -1301,9 +1324,11 @@ fn mergeTypes(self: *Wasm) !void { | ... | @@ -1301,9 +1324,11 @@ fn mergeTypes(self: *Wasm) !void { |
| 1301 | import.kind.function = try self.putOrGetFuncType(original_type); | 1324 | import.kind.function = try self.putOrGetFuncType(original_type); |
| 1302 | } else { | 1325 | } else { |
| 1303 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(self)}); | 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 | func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]); | 1328 | func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]); |
| 1306 | } | 1329 | } |
| | 1330 | |
| | 1331 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 1307 | } | 1332 | } |
| 1308 | log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len}); | 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,7 +1736,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1711 | for (comp.c_object_table.keys()) |c_object| { | 1736 | for (comp.c_object_table.keys()) |c_object| { |
| 1712 | try positionals.append(c_object.status.success.object_path); | 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 | try self.parseInputFiles(positionals.items); | 1744 | try self.parseInputFiles(positionals.items); |
| 1716 | | 1745 | |
| 1717 | var object_index: u16 = 0; | 1746 | var object_index: u16 = 0; |
| ... | @@ -1840,10 +1869,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1840,10 +1869,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1840 | } | 1869 | } |
| 1841 | | 1870 | |
| 1842 | // Function section | 1871 | // Function section |
| 1843 | if (self.functions.items.len != 0) { | 1872 | if (self.functions.count() != 0) { |
| 1844 | const header_offset = try reserveVecSectionHeader(file); | 1873 | const header_offset = try reserveVecSectionHeader(file); |
| 1845 | const writer = file.writer(); | 1874 | const writer = file.writer(); |
| 1846 | for (self.functions.items) |function| { | 1875 | for (self.functions.values()) |function| { |
| 1847 | try leb.writeULEB128(writer, function.type_index); | 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,7 +1881,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1852 | header_offset, | 1881 | header_offset, |
| 1853 | .function, | 1882 | .function, |
| 1854 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 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 | section_count += 1; | 1886 | section_count += 1; |
| 1858 | } | 1887 | } |
| ... | @@ -1984,22 +2013,41 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1984,22 +2013,41 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1984 | const header_offset = try reserveVecSectionHeader(file); | 2013 | const header_offset = try reserveVecSectionHeader(file); |
| 1985 | const writer = file.writer(); | 2014 | const writer = file.writer(); |
| 1986 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); | 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 | while (true) { | 2021 | while (true) { |
| 1988 | if (!is_obj) { | 2022 | if (!is_obj) { |
| 1989 | try atom.resolveRelocs(self); | 2023 | try atom.resolveRelocs(self); |
| 1990 | } | 2024 | } |
| 1991 | try leb.writeULEB128(writer, atom.size); | 2025 | sorted_atoms.appendAssumeCapacity(atom); |
| 1992 | try writer.writeAll(atom.code.items); | | |
| 1993 | atom = atom.next orelse break; | 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 | code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size); | 2044 | code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size); |
| 1997 | try writeVecSectionHeader( | 2045 | try writeVecSectionHeader( |
| 1998 | file, | 2046 | file, |
| 1999 | header_offset, | 2047 | header_offset, |
| 2000 | .code, | 2048 | .code, |
| 2001 | code_section_size, | 2049 | code_section_size, |
| 2002 | @intCast(u32, self.functions.items.len), | 2050 | @intCast(u32, self.functions.count()), |
| 2003 | ); | 2051 | ); |
| 2004 | code_section_index = section_count; | 2052 | code_section_index = section_count; |
| 2005 | section_count += 1; | 2053 | section_count += 1; |
| ... | @@ -2135,7 +2183,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -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 | var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count); | 2187 | var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count); |
| 2140 | var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count()); | 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,7 +2193,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2145 | break :blk self.string_table.get(self.imports.get(sym_loc).?.name); | 2193 | break :blk self.string_table.get(self.imports.get(sym_loc).?.name); |
| 2146 | } else sym_loc.getName(self); | 2194 | } else sym_loc.getName(self); |
| 2147 | switch (symbol.tag) { | 2195 | switch (symbol.tag) { |
| 2148 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), | 2196 | .function => try funcs.append(.{ .index = symbol.index, .name = name }), |
| 2149 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), | 2197 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), |
| 2150 | else => {}, | 2198 | else => {}, |
| 2151 | } | 2199 | } |