| ... | @@ -110,7 +110,7 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, | ... | @@ -110,7 +110,7 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 110 | /// Output function section where the key is the original | 110 | /// Output function section where the key is the original |
| 111 | /// function index and the value is function. | 111 | /// function index and the value is function. |
| 112 | /// This allows us to map multiple symbols to the same function. | 112 | /// This allows us to map multiple symbols to the same function. |
| 113 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{}, | 113 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, struct { func: std.wasm.Func, sym_index: u32 }) = .{}, |
| 114 | /// Output global section | 114 | /// Output global section |
| 115 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, | 115 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, |
| 116 | /// Memory section | 116 | /// Memory section |
| ... | @@ -1242,6 +1242,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1242,6 +1242,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1242 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | 1242 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1243 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); | 1243 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); |
| 1244 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 1244 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| | 1245 | _ = wasm.resolved_symbols.swapRemove(kv.value); |
| | 1246 | const symbol = loc.getSymbol(wasm); |
| | 1247 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 1248 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| | 1249 | try wasm.wasm_globals.append(wasm.base.allocator, .{ |
| | 1250 | .global_type = .{ .valtype = .i32, .mutable = true }, |
| | 1251 | .init = .{ .i32_const = undefined }, |
| | 1252 | }); |
| 1245 | } | 1253 | } |
| 1246 | } | 1254 | } |
| 1247 | } | 1255 | } |
| ... | @@ -1301,6 +1309,35 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1301,6 +1309,35 @@ pub fn deinit(wasm: *Wasm) void { |
| 1301 | archive.deinit(gpa); | 1309 | archive.deinit(gpa); |
| 1302 | } | 1310 | } |
| 1303 | | 1311 | |
| | 1312 | // For decls and anon decls we free the memory of its atoms. |
| | 1313 | // The memory of atoms parsed from object files is managed by |
| | 1314 | // the object file itself, and therefore we can skip those. |
| | 1315 | { |
| | 1316 | var it = wasm.decls.valueIterator(); |
| | 1317 | while (it.next()) |atom_index_ptr| { |
| | 1318 | const atom = wasm.getAtomPtr(atom_index_ptr.*); |
| | 1319 | for (atom.locals.items) |local_index| { |
| | 1320 | const local_atom = wasm.getAtomPtr(local_index); |
| | 1321 | local_atom.deinit(gpa); |
| | 1322 | } |
| | 1323 | atom.deinit(gpa); |
| | 1324 | } |
| | 1325 | } |
| | 1326 | { |
| | 1327 | for (wasm.anon_decls.values()) |atom_index| { |
| | 1328 | const atom = wasm.getAtomPtr(atom_index); |
| | 1329 | for (atom.locals.items) |local_index| { |
| | 1330 | const local_atom = wasm.getAtomPtr(local_index); |
| | 1331 | local_atom.deinit(gpa); |
| | 1332 | } |
| | 1333 | atom.deinit(gpa); |
| | 1334 | } |
| | 1335 | } |
| | 1336 | for (wasm.synthetic_functions.items) |atom_index| { |
| | 1337 | const atom = wasm.getAtomPtr(atom_index); |
| | 1338 | atom.deinit(gpa); |
| | 1339 | } |
| | 1340 | |
| 1304 | wasm.decls.deinit(gpa); | 1341 | wasm.decls.deinit(gpa); |
| 1305 | wasm.anon_decls.deinit(gpa); | 1342 | wasm.anon_decls.deinit(gpa); |
| 1306 | wasm.atom_types.deinit(gpa); | 1343 | wasm.atom_types.deinit(gpa); |
| ... | @@ -1313,9 +1350,6 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1313,9 +1350,6 @@ pub fn deinit(wasm: *Wasm) void { |
| 1313 | wasm.symbol_atom.deinit(gpa); | 1350 | wasm.symbol_atom.deinit(gpa); |
| 1314 | wasm.export_names.deinit(gpa); | 1351 | wasm.export_names.deinit(gpa); |
| 1315 | wasm.atoms.deinit(gpa); | 1352 | wasm.atoms.deinit(gpa); |
| 1316 | for (wasm.managed_atoms.items) |*managed_atom| { | | |
| 1317 | managed_atom.deinit(wasm); | | |
| 1318 | } | | |
| 1319 | wasm.managed_atoms.deinit(gpa); | 1353 | wasm.managed_atoms.deinit(gpa); |
| 1320 | wasm.segments.deinit(gpa); | 1354 | wasm.segments.deinit(gpa); |
| 1321 | wasm.data_segments.deinit(gpa); | 1355 | wasm.data_segments.deinit(gpa); |
| ... | @@ -1550,7 +1584,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | ... | @@ -1550,7 +1584,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1550 | const ty_index = wasm.imports.get(loc).?.kind.function; | 1584 | const ty_index = wasm.imports.get(loc).?.kind.function; |
| 1551 | return wasm.func_types.items[ty_index]; | 1585 | return wasm.func_types.items[ty_index]; |
| 1552 | } | 1586 | } |
| 1553 | return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = loc.index }).?.type_index]; | 1587 | return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = symbol.index }).?.func.type_index]; |
| 1554 | } | 1588 | } |
| 1555 | | 1589 | |
| 1556 | /// Lowers a constant typed value to a local symbol and atom. | 1590 | /// Lowers a constant typed value to a local symbol and atom. |
| ... | @@ -1973,10 +2007,16 @@ pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void { | ... | @@ -1973,10 +2007,16 @@ pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void { |
| 1973 | /// Starts at offset 1, where the value `0` represents an unresolved function pointer | 2007 | /// Starts at offset 1, where the value `0` represents an unresolved function pointer |
| 1974 | /// or null-pointer | 2008 | /// or null-pointer |
| 1975 | fn mapFunctionTable(wasm: *Wasm) void { | 2009 | fn mapFunctionTable(wasm: *Wasm) void { |
| 1976 | var it = wasm.function_table.valueIterator(); | 2010 | var it = wasm.function_table.iterator(); |
| 1977 | var index: u32 = 1; | 2011 | var index: u32 = 1; |
| 1978 | while (it.next()) |value_ptr| : (index += 1) { | 2012 | while (it.next()) |entry| { |
| 1979 | value_ptr.* = index; | 2013 | const symbol = entry.key_ptr.*.getSymbol(wasm); |
| | 2014 | if (symbol.isAlive()) { |
| | 2015 | entry.value_ptr.* = index; |
| | 2016 | index += 1; |
| | 2017 | } else { |
| | 2018 | wasm.function_table.removeByPtr(entry.key_ptr); |
| | 2019 | } |
| 1980 | } | 2020 | } |
| 1981 | | 2021 | |
| 1982 | if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) { | 2022 | if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) { |
| ... | @@ -2094,20 +2134,28 @@ const Kind = union(enum) { | ... | @@ -2094,20 +2134,28 @@ const Kind = union(enum) { |
| 2094 | fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | 2134 | fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2095 | const atom = wasm.getAtomPtr(atom_index); | 2135 | const atom = wasm.getAtomPtr(atom_index); |
| 2096 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); | 2136 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); |
| | 2137 | const do_garbage_collect = wasm.base.options.gc_sections orelse |
| | 2138 | (wasm.base.options.output_mode != .Obj); |
| | 2139 | |
| | 2140 | if (symbol.isDead() and do_garbage_collect) { |
| | 2141 | // Prevent unreferenced symbols from being parsed. |
| | 2142 | return; |
| | 2143 | } |
| | 2144 | |
| 2097 | const final_index: u32 = switch (kind) { | 2145 | const final_index: u32 = switch (kind) { |
| 2098 | .function => result: { | 2146 | .function => result: { |
| 2099 | const index = @as(u32, @intCast(wasm.functions.count() + wasm.imported_functions_count)); | 2147 | const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); |
| 2100 | const type_index = wasm.atom_types.get(atom_index).?; | 2148 | const type_index = wasm.atom_types.get(atom_index).?; |
| 2101 | try wasm.functions.putNoClobber( | 2149 | try wasm.functions.putNoClobber( |
| 2102 | wasm.base.allocator, | 2150 | wasm.base.allocator, |
| 2103 | .{ .file = null, .index = index }, | 2151 | .{ .file = null, .index = index }, |
| 2104 | .{ .type_index = type_index }, | 2152 | .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 2105 | ); | 2153 | ); |
| 2106 | symbol.tag = .function; | 2154 | symbol.tag = .function; |
| 2107 | symbol.index = index; | 2155 | symbol.index = index; |
| 2108 | | 2156 | |
| 2109 | if (wasm.code_section_index == null) { | 2157 | if (wasm.code_section_index == null) { |
| 2110 | wasm.code_section_index = @as(u32, @intCast(wasm.segments.items.len)); | 2158 | wasm.code_section_index = @intCast(wasm.segments.items.len); |
| 2111 | try wasm.segments.append(wasm.base.allocator, .{ | 2159 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2112 | .alignment = atom.alignment, | 2160 | .alignment = atom.alignment, |
| 2113 | .size = atom.size, | 2161 | .size = atom.size, |
| ... | @@ -2145,12 +2193,12 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | ... | @@ -2145,12 +2193,12 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2145 | const index = gop.value_ptr.*; | 2193 | const index = gop.value_ptr.*; |
| 2146 | wasm.segments.items[index].size += atom.size; | 2194 | wasm.segments.items[index].size += atom.size; |
| 2147 | | 2195 | |
| 2148 | symbol.index = @as(u32, @intCast(wasm.segment_info.getIndex(index).?)); | 2196 | symbol.index = @intCast(wasm.segment_info.getIndex(index).?); |
| 2149 | // segment info already exists, so free its memory | 2197 | // segment info already exists, so free its memory |
| 2150 | wasm.base.allocator.free(segment_name); | 2198 | wasm.base.allocator.free(segment_name); |
| 2151 | break :result index; | 2199 | break :result index; |
| 2152 | } else { | 2200 | } else { |
| 2153 | const index = @as(u32, @intCast(wasm.segments.items.len)); | 2201 | const index: u32 = @intCast(wasm.segments.items.len); |
| 2154 | var flags: u32 = 0; | 2202 | var flags: u32 = 0; |
| 2155 | if (wasm.base.options.shared_memory) { | 2203 | if (wasm.base.options.shared_memory) { |
| 2156 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); | 2204 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| ... | @@ -2163,7 +2211,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | ... | @@ -2163,7 +2211,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2163 | }); | 2211 | }); |
| 2164 | gop.value_ptr.* = index; | 2212 | gop.value_ptr.* = index; |
| 2165 | | 2213 | |
| 2166 | const info_index = @as(u32, @intCast(wasm.segment_info.count())); | 2214 | const info_index: u32 = @intCast(wasm.segment_info.count()); |
| 2167 | try wasm.segment_info.put(wasm.base.allocator, index, segment_info); | 2215 | try wasm.segment_info.put(wasm.base.allocator, index, segment_info); |
| 2168 | symbol.index = info_index; | 2216 | symbol.index = info_index; |
| 2169 | break :result index; | 2217 | break :result index; |
| ... | @@ -2234,14 +2282,37 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2234,14 +2282,37 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2234 | while (true) { | 2282 | while (true) { |
| 2235 | const atom = wasm.getAtomPtr(atom_index); | 2283 | const atom = wasm.getAtomPtr(atom_index); |
| 2236 | const symbol_loc = atom.symbolLoc(); | 2284 | const symbol_loc = atom.symbolLoc(); |
| 2237 | if (wasm.code_section_index) |index| { | 2285 | // Ensure we get the original symbol, so we verify the correct symbol on whether |
| 2238 | if (index == entry.key_ptr.*) { | 2286 | // it is dead or not and ensure an atom is removed when dead. |
| 2239 | if (!wasm.resolved_symbols.contains(symbol_loc)) { | 2287 | // This is required as we may have parsed aliases into atoms. |
| 2240 | // only allocate resolved function body's. | 2288 | const sym = if (symbol_loc.file) |object_index| sym: { |
| 2241 | atom_index = atom.prev orelse break; | 2289 | const object = wasm.objects.items[object_index]; |
| 2242 | continue; | 2290 | break :sym object.symtable[symbol_loc.index]; |
| | 2291 | } else wasm.symbols.items[symbol_loc.index]; |
| | 2292 | |
| | 2293 | if (sym.isDead()) { |
| | 2294 | // Dead symbols must be unlinked from the linked-list to prevent them |
| | 2295 | // from being emit into the binary. |
| | 2296 | if (atom.next) |next_index| { |
| | 2297 | const next = wasm.getAtomPtr(next_index); |
| | 2298 | next.prev = atom.prev; |
| | 2299 | } else if (entry.value_ptr.* == atom_index) { |
| | 2300 | // When the atom is dead and is also the first atom retrieved from wasm.atoms(index) we update |
| | 2301 | // the entry to point it to the previous atom to ensure we do not start with a dead symbol that |
| | 2302 | // was removed and therefore do not emit any code at all. |
| | 2303 | if (atom.prev) |prev| { |
| | 2304 | entry.value_ptr.* = prev; |
| 2243 | } | 2305 | } |
| 2244 | } | 2306 | } |
| | 2307 | atom_index = atom.prev orelse { |
| | 2308 | atom.next = null; |
| | 2309 | break; |
| | 2310 | }; |
| | 2311 | const prev = wasm.getAtomPtr(atom_index); |
| | 2312 | prev.next = atom.next; |
| | 2313 | atom.prev = null; |
| | 2314 | atom.next = null; |
| | 2315 | continue; |
| 2245 | } | 2316 | } |
| 2246 | offset = @intCast(atom.alignment.forward(offset)); | 2317 | offset = @intCast(atom.alignment.forward(offset)); |
| 2247 | atom.offset = offset; | 2318 | atom.offset = offset; |
| ... | @@ -2262,8 +2333,10 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2262,8 +2333,10 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2262 | fn allocateVirtualAddresses(wasm: *Wasm) void { | 2333 | fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 2263 | for (wasm.resolved_symbols.keys()) |loc| { | 2334 | for (wasm.resolved_symbols.keys()) |loc| { |
| 2264 | const symbol = loc.getSymbol(wasm); | 2335 | const symbol = loc.getSymbol(wasm); |
| 2265 | if (symbol.tag != .data) { | 2336 | if (symbol.tag != .data or symbol.isDead()) { |
| 2266 | continue; // only data symbols have virtual addresses | 2337 | // Only data symbols have virtual addresses. |
| | 2338 | // Dead symbols do not get allocated, so we don't need to set their virtual address either. |
| | 2339 | continue; |
| 2267 | } | 2340 | } |
| 2268 | const atom_index = wasm.symbol_atom.get(loc) orelse { | 2341 | const atom_index = wasm.symbol_atom.get(loc) orelse { |
| 2269 | // synthetic symbol that does not contain an atom | 2342 | // synthetic symbol that does not contain an atom |
| ... | @@ -2350,11 +2423,17 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -2350,11 +2423,17 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 2350 | .file = @as(u16, @intCast(file_index)), | 2423 | .file = @as(u16, @intCast(file_index)), |
| 2351 | .priority = init_func.priority, | 2424 | .priority = init_func.priority, |
| 2352 | }); | 2425 | }); |
| | 2426 | try wasm.mark(.{ .index = init_func.symbol_index, .file = @intCast(file_index) }); |
| 2353 | } | 2427 | } |
| 2354 | } | 2428 | } |
| 2355 | | 2429 | |
| 2356 | // sort the initfunctions based on their priority | 2430 | // sort the initfunctions based on their priority |
| 2357 | mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); | 2431 | mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); |
| | 2432 | |
| | 2433 | if (wasm.init_funcs.items.len > 0) { |
| | 2434 | const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?; |
| | 2435 | try wasm.mark(loc); |
| | 2436 | } |
| 2358 | } | 2437 | } |
| 2359 | | 2438 | |
| 2360 | /// Generates an atom containing the global error set' size. | 2439 | /// Generates an atom containing the global error set' size. |
| ... | @@ -2377,7 +2456,7 @@ fn setupErrorsLen(wasm: *Wasm) !void { | ... | @@ -2377,7 +2456,7 @@ fn setupErrorsLen(wasm: *Wasm) !void { |
| 2377 | prev_atom.next = atom.next; | 2456 | prev_atom.next = atom.next; |
| 2378 | atom.prev = null; | 2457 | atom.prev = null; |
| 2379 | } | 2458 | } |
| 2380 | atom.deinit(wasm); | 2459 | atom.deinit(wasm.base.allocator); |
| 2381 | break :blk index; | 2460 | break :blk index; |
| 2382 | } else new_atom: { | 2461 | } else new_atom: { |
| 2383 | const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); | 2462 | const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); |
| ... | @@ -2422,7 +2501,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { | ... | @@ -2422,7 +2501,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 2422 | // call constructors | 2501 | // call constructors |
| 2423 | for (wasm.init_funcs.items) |init_func_loc| { | 2502 | for (wasm.init_funcs.items) |init_func_loc| { |
| 2424 | const symbol = init_func_loc.getSymbol(wasm); | 2503 | const symbol = init_func_loc.getSymbol(wasm); |
| 2425 | const func = wasm.functions.values()[symbol.index - wasm.imported_functions_count]; | 2504 | const func = wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; |
| 2426 | const ty = wasm.func_types.items[func.type_index]; | 2505 | const ty = wasm.func_types.items[func.type_index]; |
| 2427 | | 2506 | |
| 2428 | // Call function by its function index | 2507 | // Call function by its function index |
| ... | @@ -2455,13 +2534,16 @@ fn createSyntheticFunction( | ... | @@ -2455,13 +2534,16 @@ fn createSyntheticFunction( |
| 2455 | const loc = wasm.findGlobalSymbol(symbol_name) orelse | 2534 | const loc = wasm.findGlobalSymbol(symbol_name) orelse |
| 2456 | try wasm.createSyntheticSymbol(symbol_name, .function); | 2535 | try wasm.createSyntheticSymbol(symbol_name, .function); |
| 2457 | const symbol = loc.getSymbol(wasm); | 2536 | const symbol = loc.getSymbol(wasm); |
| | 2537 | if (symbol.isDead()) { |
| | 2538 | return; |
| | 2539 | } |
| 2458 | const ty_index = try wasm.putOrGetFuncType(func_ty); | 2540 | const ty_index = try wasm.putOrGetFuncType(func_ty); |
| 2459 | // create function with above type | 2541 | // create function with above type |
| 2460 | const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count())); | 2542 | const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count())); |
| 2461 | try wasm.functions.putNoClobber( | 2543 | try wasm.functions.putNoClobber( |
| 2462 | wasm.base.allocator, | 2544 | wasm.base.allocator, |
| 2463 | .{ .file = null, .index = func_index }, | 2545 | .{ .file = null, .index = func_index }, |
| 2464 | .{ .type_index = ty_index }, | 2546 | .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, |
| 2465 | ); | 2547 | ); |
| 2466 | symbol.index = func_index; | 2548 | symbol.index = func_index; |
| 2467 | | 2549 | |
| ... | @@ -2477,6 +2559,7 @@ fn createSyntheticFunction( | ... | @@ -2477,6 +2559,7 @@ fn createSyntheticFunction( |
| 2477 | .next = null, | 2559 | .next = null, |
| 2478 | .prev = null, | 2560 | .prev = null, |
| 2479 | .code = function_body.moveToUnmanaged(), | 2561 | .code = function_body.moveToUnmanaged(), |
| | 2562 | .original_offset = 0, |
| 2480 | }; | 2563 | }; |
| 2481 | try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index); | 2564 | try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index); |
| 2482 | try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); | 2565 | try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); |
| ... | @@ -2513,6 +2596,7 @@ pub fn createFunction( | ... | @@ -2513,6 +2596,7 @@ pub fn createFunction( |
| 2513 | .prev = null, | 2596 | .prev = null, |
| 2514 | .code = function_body.moveToUnmanaged(), | 2597 | .code = function_body.moveToUnmanaged(), |
| 2515 | .relocs = relocations.moveToUnmanaged(), | 2598 | .relocs = relocations.moveToUnmanaged(), |
| | 2599 | .original_offset = 0, |
| 2516 | }; | 2600 | }; |
| 2517 | const symbol = loc.getSymbol(wasm); | 2601 | const symbol = loc.getSymbol(wasm); |
| 2518 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // ensure function does not get exported | 2602 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // ensure function does not get exported |
| ... | @@ -2614,21 +2698,21 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -2614,21 +2698,21 @@ fn setupImports(wasm: *Wasm) !void { |
| 2614 | } | 2698 | } |
| 2615 | | 2699 | |
| 2616 | for (wasm.resolved_symbols.keys()) |symbol_loc| { | 2700 | for (wasm.resolved_symbols.keys()) |symbol_loc| { |
| 2617 | if (symbol_loc.file == null) { | 2701 | const file_index = symbol_loc.file orelse { |
| 2618 | // imports generated by Zig code are already in the `import` section | 2702 | // imports generated by Zig code are already in the `import` section |
| 2619 | continue; | 2703 | continue; |
| 2620 | } | 2704 | }; |
| 2621 | | 2705 | |
| 2622 | const symbol = symbol_loc.getSymbol(wasm); | 2706 | const symbol = symbol_loc.getSymbol(wasm); |
| 2623 | if (std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table")) { | 2707 | if (symbol.isDead() or |
| 2624 | continue; | 2708 | !symbol.requiresImport() or |
| 2625 | } | 2709 | std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table")) |
| 2626 | if (!symbol.requiresImport()) { | 2710 | { |
| 2627 | continue; | 2711 | continue; |
| 2628 | } | 2712 | } |
| 2629 | | 2713 | |
| 2630 | log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)}); | 2714 | log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)}); |
| 2631 | const object = wasm.objects.items[symbol_loc.file.?]; | 2715 | const object = wasm.objects.items[file_index]; |
| 2632 | const import = object.findImport(symbol.tag.externalType(), symbol.index); | 2716 | const import = object.findImport(symbol.tag.externalType(), symbol.index); |
| 2633 | | 2717 | |
| 2634 | // We copy the import to a new import to ensure the names contain references | 2718 | // We copy the import to a new import to ensure the names contain references |
| ... | @@ -2680,6 +2764,9 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -2680,6 +2764,9 @@ fn setupImports(wasm: *Wasm) !void { |
| 2680 | /// Takes the global, function and table section from each linked object file | 2764 | /// Takes the global, function and table section from each linked object file |
| 2681 | /// and merges it into a single section for each. | 2765 | /// and merges it into a single section for each. |
| 2682 | fn mergeSections(wasm: *Wasm) !void { | 2766 | fn mergeSections(wasm: *Wasm) !void { |
| | 2767 | var removed_duplicates = std.ArrayList(SymbolLoc).init(wasm.base.allocator); |
| | 2768 | defer removed_duplicates.deinit(); |
| | 2769 | |
| 2683 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 2770 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2684 | if (sym_loc.file == null) { | 2771 | if (sym_loc.file == null) { |
| 2685 | // Zig code-generated symbols are already within the sections and do not | 2772 | // Zig code-generated symbols are already within the sections and do not |
| ... | @@ -2689,7 +2776,11 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2689,7 +2776,11 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2689 | | 2776 | |
| 2690 | const object = &wasm.objects.items[sym_loc.file.?]; | 2777 | const object = &wasm.objects.items[sym_loc.file.?]; |
| 2691 | const symbol = &object.symtable[sym_loc.index]; | 2778 | const symbol = &object.symtable[sym_loc.index]; |
| 2692 | if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) { | 2779 | |
| | 2780 | if (symbol.isDead() or |
| | 2781 | symbol.isUndefined() or |
| | 2782 | (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) |
| | 2783 | { |
| 2693 | // Skip undefined symbols as they go in the `import` section | 2784 | // Skip undefined symbols as they go in the `import` section |
| 2694 | // Also skip symbols that do not need to have a section merged. | 2785 | // Also skip symbols that do not need to have a section merged. |
| 2695 | continue; | 2786 | continue; |
| ... | @@ -2703,9 +2794,20 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2703,9 +2794,20 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2703 | wasm.base.allocator, | 2794 | wasm.base.allocator, |
| 2704 | .{ .file = sym_loc.file, .index = symbol.index }, | 2795 | .{ .file = sym_loc.file, .index = symbol.index }, |
| 2705 | ); | 2796 | ); |
| 2706 | if (!gop.found_existing) { | 2797 | if (gop.found_existing) { |
| 2707 | gop.value_ptr.* = object.functions[index]; | 2798 | // We found an alias to the same function, discard this symbol in favor of |
| | 2799 | // the original symbol and point the discard function to it. This ensures |
| | 2800 | // we only emit a single function, instead of duplicates. |
| | 2801 | symbol.unmark(); |
| | 2802 | try wasm.discarded.putNoClobber( |
| | 2803 | wasm.base.allocator, |
| | 2804 | sym_loc, |
| | 2805 | .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index }, |
| | 2806 | ); |
| | 2807 | try removed_duplicates.append(sym_loc); |
| | 2808 | continue; |
| 2708 | } | 2809 | } |
| | 2810 | gop.value_ptr.* = .{ .func = object.functions[index], .sym_index = sym_loc.index }; |
| 2709 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; | 2811 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; |
| 2710 | }, | 2812 | }, |
| 2711 | .global => { | 2813 | .global => { |
| ... | @@ -2722,6 +2824,11 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2722,6 +2824,11 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2722 | } | 2824 | } |
| 2723 | } | 2825 | } |
| 2724 | | 2826 | |
| | 2827 | // For any removed duplicates, remove them from the resolved symbols list |
| | 2828 | for (removed_duplicates.items) |sym_loc| { |
| | 2829 | assert(wasm.resolved_symbols.swapRemove(sym_loc)); |
| | 2830 | } |
| | 2831 | |
| 2725 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); | 2832 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); |
| 2726 | log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len}); | 2833 | log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len}); |
| 2727 | log.debug("Merged ({d}) tables", .{wasm.tables.items.len}); | 2834 | log.debug("Merged ({d}) tables", .{wasm.tables.items.len}); |
| ... | @@ -2745,8 +2852,8 @@ fn mergeTypes(wasm: *Wasm) !void { | ... | @@ -2745,8 +2852,8 @@ fn mergeTypes(wasm: *Wasm) !void { |
| 2745 | } | 2852 | } |
| 2746 | const object = wasm.objects.items[sym_loc.file.?]; | 2853 | const object = wasm.objects.items[sym_loc.file.?]; |
| 2747 | const symbol = object.symtable[sym_loc.index]; | 2854 | const symbol = object.symtable[sym_loc.index]; |
| 2748 | if (symbol.tag != .function) { | 2855 | if (symbol.tag != .function or symbol.isDead()) { |
| 2749 | // Only functions have types | 2856 | // Only functions have types. Only retrieve the type of referenced functions. |
| 2750 | continue; | 2857 | continue; |
| 2751 | } | 2858 | } |
| 2752 | | 2859 | |
| ... | @@ -2757,7 +2864,7 @@ fn mergeTypes(wasm: *Wasm) !void { | ... | @@ -2757,7 +2864,7 @@ fn mergeTypes(wasm: *Wasm) !void { |
| 2757 | import.kind.function = try wasm.putOrGetFuncType(original_type); | 2864 | import.kind.function = try wasm.putOrGetFuncType(original_type); |
| 2758 | } else if (!dirty.contains(symbol.index)) { | 2865 | } else if (!dirty.contains(symbol.index)) { |
| 2759 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)}); | 2866 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)}); |
| 2760 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count]; | 2867 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; |
| 2761 | func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]); | 2868 | func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]); |
| 2762 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); | 2869 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 2763 | } | 2870 | } |
| ... | @@ -2980,14 +3087,14 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2980,14 +3087,14 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2980 | /// From a given object's index and the index of the segment, returns the corresponding | 3087 | /// From a given object's index and the index of the segment, returns the corresponding |
| 2981 | /// index of the segment within the final data section. When the segment does not yet | 3088 | /// index of the segment within the final data section. When the segment does not yet |
| 2982 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. | 3089 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. |
| 2983 | pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32) !?u32 { | 3090 | pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 { |
| 2984 | const object: Object = wasm.objects.items[object_index]; | 3091 | const object: Object = wasm.objects.items[object_index]; |
| 2985 | const relocatable_data = object.relocatable_data[relocatable_index]; | 3092 | const symbol = object.symtable[symbol_index]; |
| 2986 | const index = @as(u32, @intCast(wasm.segments.items.len)); | 3093 | const index = @as(u32, @intCast(wasm.segments.items.len)); |
| 2987 | | 3094 | |
| 2988 | switch (relocatable_data.type) { | 3095 | switch (symbol.tag) { |
| 2989 | .data => { | 3096 | .data => { |
| 2990 | const segment_info = object.segment_info[relocatable_data.index]; | 3097 | const segment_info = object.segment_info[symbol.index]; |
| 2991 | const merge_segment = wasm.base.options.output_mode != .Obj; | 3098 | const merge_segment = wasm.base.options.output_mode != .Obj; |
| 2992 | const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment)); | 3099 | const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment)); |
| 2993 | if (!result.found_existing) { | 3100 | if (!result.found_existing) { |
| ... | @@ -3002,70 +3109,75 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -3002,70 +3109,75 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 3002 | .offset = 0, | 3109 | .offset = 0, |
| 3003 | .flags = flags, | 3110 | .flags = flags, |
| 3004 | }); | 3111 | }); |
| | 3112 | try wasm.segment_info.putNoClobber(wasm.base.allocator, index, .{ |
| | 3113 | .name = try wasm.base.allocator.dupe(u8, segment_info.name), |
| | 3114 | .alignment = segment_info.alignment, |
| | 3115 | .flags = segment_info.flags, |
| | 3116 | }); |
| 3005 | return index; | 3117 | return index; |
| 3006 | } else return result.value_ptr.*; | 3118 | } else return result.value_ptr.*; |
| 3007 | }, | 3119 | }, |
| 3008 | .code => return wasm.code_section_index orelse blk: { | 3120 | .function => return wasm.code_section_index orelse blk: { |
| 3009 | wasm.code_section_index = index; | 3121 | wasm.code_section_index = index; |
| 3010 | try wasm.appendDummySegment(); | 3122 | try wasm.appendDummySegment(); |
| 3011 | break :blk index; | 3123 | break :blk index; |
| 3012 | }, | 3124 | }, |
| 3013 | .debug => { | 3125 | .section => { |
| 3014 | const debug_name = object.getDebugName(relocatable_data); | 3126 | const section_name = object.string_table.get(symbol.name); |
| 3015 | if (mem.eql(u8, debug_name, ".debug_info")) { | 3127 | if (mem.eql(u8, section_name, ".debug_info")) { |
| 3016 | return wasm.debug_info_index orelse blk: { | 3128 | return wasm.debug_info_index orelse blk: { |
| 3017 | wasm.debug_info_index = index; | 3129 | wasm.debug_info_index = index; |
| 3018 | try wasm.appendDummySegment(); | 3130 | try wasm.appendDummySegment(); |
| 3019 | break :blk index; | 3131 | break :blk index; |
| 3020 | }; | 3132 | }; |
| 3021 | } else if (mem.eql(u8, debug_name, ".debug_line")) { | 3133 | } else if (mem.eql(u8, section_name, ".debug_line")) { |
| 3022 | return wasm.debug_line_index orelse blk: { | 3134 | return wasm.debug_line_index orelse blk: { |
| 3023 | wasm.debug_line_index = index; | 3135 | wasm.debug_line_index = index; |
| 3024 | try wasm.appendDummySegment(); | 3136 | try wasm.appendDummySegment(); |
| 3025 | break :blk index; | 3137 | break :blk index; |
| 3026 | }; | 3138 | }; |
| 3027 | } else if (mem.eql(u8, debug_name, ".debug_loc")) { | 3139 | } else if (mem.eql(u8, section_name, ".debug_loc")) { |
| 3028 | return wasm.debug_loc_index orelse blk: { | 3140 | return wasm.debug_loc_index orelse blk: { |
| 3029 | wasm.debug_loc_index = index; | 3141 | wasm.debug_loc_index = index; |
| 3030 | try wasm.appendDummySegment(); | 3142 | try wasm.appendDummySegment(); |
| 3031 | break :blk index; | 3143 | break :blk index; |
| 3032 | }; | 3144 | }; |
| 3033 | } else if (mem.eql(u8, debug_name, ".debug_ranges")) { | 3145 | } else if (mem.eql(u8, section_name, ".debug_ranges")) { |
| 3034 | return wasm.debug_line_index orelse blk: { | 3146 | return wasm.debug_line_index orelse blk: { |
| 3035 | wasm.debug_ranges_index = index; | 3147 | wasm.debug_ranges_index = index; |
| 3036 | try wasm.appendDummySegment(); | 3148 | try wasm.appendDummySegment(); |
| 3037 | break :blk index; | 3149 | break :blk index; |
| 3038 | }; | 3150 | }; |
| 3039 | } else if (mem.eql(u8, debug_name, ".debug_pubnames")) { | 3151 | } else if (mem.eql(u8, section_name, ".debug_pubnames")) { |
| 3040 | return wasm.debug_pubnames_index orelse blk: { | 3152 | return wasm.debug_pubnames_index orelse blk: { |
| 3041 | wasm.debug_pubnames_index = index; | 3153 | wasm.debug_pubnames_index = index; |
| 3042 | try wasm.appendDummySegment(); | 3154 | try wasm.appendDummySegment(); |
| 3043 | break :blk index; | 3155 | break :blk index; |
| 3044 | }; | 3156 | }; |
| 3045 | } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) { | 3157 | } else if (mem.eql(u8, section_name, ".debug_pubtypes")) { |
| 3046 | return wasm.debug_pubtypes_index orelse blk: { | 3158 | return wasm.debug_pubtypes_index orelse blk: { |
| 3047 | wasm.debug_pubtypes_index = index; | 3159 | wasm.debug_pubtypes_index = index; |
| 3048 | try wasm.appendDummySegment(); | 3160 | try wasm.appendDummySegment(); |
| 3049 | break :blk index; | 3161 | break :blk index; |
| 3050 | }; | 3162 | }; |
| 3051 | } else if (mem.eql(u8, debug_name, ".debug_abbrev")) { | 3163 | } else if (mem.eql(u8, section_name, ".debug_abbrev")) { |
| 3052 | return wasm.debug_abbrev_index orelse blk: { | 3164 | return wasm.debug_abbrev_index orelse blk: { |
| 3053 | wasm.debug_abbrev_index = index; | 3165 | wasm.debug_abbrev_index = index; |
| 3054 | try wasm.appendDummySegment(); | 3166 | try wasm.appendDummySegment(); |
| 3055 | break :blk index; | 3167 | break :blk index; |
| 3056 | }; | 3168 | }; |
| 3057 | } else if (mem.eql(u8, debug_name, ".debug_str")) { | 3169 | } else if (mem.eql(u8, section_name, ".debug_str")) { |
| 3058 | return wasm.debug_str_index orelse blk: { | 3170 | return wasm.debug_str_index orelse blk: { |
| 3059 | wasm.debug_str_index = index; | 3171 | wasm.debug_str_index = index; |
| 3060 | try wasm.appendDummySegment(); | 3172 | try wasm.appendDummySegment(); |
| 3061 | break :blk index; | 3173 | break :blk index; |
| 3062 | }; | 3174 | }; |
| 3063 | } else { | 3175 | } else { |
| 3064 | log.warn("found unknown debug section '{s}'", .{debug_name}); | 3176 | log.warn("found unknown section '{s}'", .{section_name}); |
| 3065 | log.warn(" debug section will be skipped", .{}); | 3177 | return error.UnexpectedValue; |
| 3066 | return null; | | |
| 3067 | } | 3178 | } |
| 3068 | }, | 3179 | }, |
| | 3180 | else => unreachable, |
| 3069 | } | 3181 | } |
| 3070 | } | 3182 | } |
| 3071 | | 3183 | |
| ... | @@ -3108,6 +3220,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { | ... | @@ -3108,6 +3220,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 3108 | .virtual_address = undefined, | 3220 | .virtual_address = undefined, |
| 3109 | }; | 3221 | }; |
| 3110 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 3222 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 3223 | symbol.mark(); |
| 3111 | | 3224 | |
| 3112 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); | 3225 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); |
| 3113 | | 3226 | |
| ... | @@ -3140,6 +3253,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -3140,6 +3253,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3140 | .virtual_address = undefined, | 3253 | .virtual_address = undefined, |
| 3141 | }; | 3254 | }; |
| 3142 | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 3255 | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 3256 | names_symbol.mark(); |
| 3143 | | 3257 | |
| 3144 | log.debug("Populating error names", .{}); | 3258 | log.debug("Populating error names", .{}); |
| 3145 | | 3259 | |
| ... | @@ -3431,18 +3545,15 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -3431,18 +3545,15 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 3431 | | 3545 | |
| 3432 | try wasm.setupInitFunctions(); | 3546 | try wasm.setupInitFunctions(); |
| 3433 | try wasm.setupStart(); | 3547 | try wasm.setupStart(); |
| 3434 | try wasm.setupImports(); | | |
| 3435 | | | |
| 3436 | for (wasm.objects.items, 0..) |*object, object_index| { | | |
| 3437 | try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm); | | |
| 3438 | } | | |
| 3439 | | 3548 | |
| | 3549 | try wasm.markReferences(); |
| | 3550 | try wasm.setupImports(); |
| | 3551 | try wasm.mergeSections(); |
| | 3552 | try wasm.mergeTypes(); |
| 3440 | try wasm.allocateAtoms(); | 3553 | try wasm.allocateAtoms(); |
| 3441 | try wasm.setupMemory(); | 3554 | try wasm.setupMemory(); |
| 3442 | wasm.allocateVirtualAddresses(); | 3555 | wasm.allocateVirtualAddresses(); |
| 3443 | wasm.mapFunctionTable(); | 3556 | wasm.mapFunctionTable(); |
| 3444 | try wasm.mergeSections(); | | |
| 3445 | try wasm.mergeTypes(); | | |
| 3446 | try wasm.initializeCallCtorsFunction(); | 3557 | try wasm.initializeCallCtorsFunction(); |
| 3447 | try wasm.setupInitMemoryFunction(); | 3558 | try wasm.setupInitMemoryFunction(); |
| 3448 | try wasm.setupTLSRelocationsFunction(); | 3559 | try wasm.setupTLSRelocationsFunction(); |
| ... | @@ -3519,8 +3630,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -3519,8 +3630,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3519 | // So we can rebuild the binary file on each incremental update | 3630 | // So we can rebuild the binary file on each incremental update |
| 3520 | defer wasm.resetState(); | 3631 | defer wasm.resetState(); |
| 3521 | try wasm.setupInitFunctions(); | 3632 | try wasm.setupInitFunctions(); |
| 3522 | try wasm.setupErrorsLen(); | | |
| 3523 | try wasm.setupStart(); | 3633 | try wasm.setupStart(); |
| | 3634 | try wasm.markReferences(); |
| | 3635 | try wasm.setupErrorsLen(); |
| 3524 | try wasm.setupImports(); | 3636 | try wasm.setupImports(); |
| 3525 | if (wasm.base.options.module) |mod| { | 3637 | if (wasm.base.options.module) |mod| { |
| 3526 | var decl_it = wasm.decls.iterator(); | 3638 | var decl_it = wasm.decls.iterator(); |
| ... | @@ -3577,16 +3689,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -3577,16 +3689,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3577 | } | 3689 | } |
| 3578 | } | 3690 | } |
| 3579 | | 3691 | |
| 3580 | for (wasm.objects.items, 0..) |*object, object_index| { | 3692 | try wasm.mergeSections(); |
| 3581 | try object.parseIntoAtoms(wasm.base.allocator, @as(u16, @intCast(object_index)), wasm); | 3693 | try wasm.mergeTypes(); |
| 3582 | } | | |
| 3583 | | | |
| 3584 | try wasm.allocateAtoms(); | 3694 | try wasm.allocateAtoms(); |
| 3585 | try wasm.setupMemory(); | 3695 | try wasm.setupMemory(); |
| 3586 | wasm.allocateVirtualAddresses(); | 3696 | wasm.allocateVirtualAddresses(); |
| 3587 | wasm.mapFunctionTable(); | 3697 | wasm.mapFunctionTable(); |
| 3588 | try wasm.mergeSections(); | | |
| 3589 | try wasm.mergeTypes(); | | |
| 3590 | try wasm.initializeCallCtorsFunction(); | 3698 | try wasm.initializeCallCtorsFunction(); |
| 3591 | try wasm.setupInitMemoryFunction(); | 3699 | try wasm.setupInitMemoryFunction(); |
| 3592 | try wasm.setupTLSRelocationsFunction(); | 3700 | try wasm.setupTLSRelocationsFunction(); |
| ... | @@ -3644,8 +3752,8 @@ fn writeToFile( | ... | @@ -3644,8 +3752,8 @@ fn writeToFile( |
| 3644 | binary_bytes.items, | 3752 | binary_bytes.items, |
| 3645 | header_offset, | 3753 | header_offset, |
| 3646 | .type, | 3754 | .type, |
| 3647 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3755 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3648 | @as(u32, @intCast(wasm.func_types.items.len)), | 3756 | @intCast(wasm.func_types.items.len), |
| 3649 | ); | 3757 | ); |
| 3650 | section_count += 1; | 3758 | section_count += 1; |
| 3651 | } | 3759 | } |
| ... | @@ -3677,8 +3785,8 @@ fn writeToFile( | ... | @@ -3677,8 +3785,8 @@ fn writeToFile( |
| 3677 | binary_bytes.items, | 3785 | binary_bytes.items, |
| 3678 | header_offset, | 3786 | header_offset, |
| 3679 | .import, | 3787 | .import, |
| 3680 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3788 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3681 | @as(u32, @intCast(wasm.imports.count() + @intFromBool(import_memory))), | 3789 | @intCast(wasm.imports.count() + @intFromBool(import_memory)), |
| 3682 | ); | 3790 | ); |
| 3683 | section_count += 1; | 3791 | section_count += 1; |
| 3684 | } | 3792 | } |
| ... | @@ -3687,15 +3795,15 @@ fn writeToFile( | ... | @@ -3687,15 +3795,15 @@ fn writeToFile( |
| 3687 | if (wasm.functions.count() != 0) { | 3795 | if (wasm.functions.count() != 0) { |
| 3688 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 3796 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 3689 | for (wasm.functions.values()) |function| { | 3797 | for (wasm.functions.values()) |function| { |
| 3690 | try leb.writeULEB128(binary_writer, function.type_index); | 3798 | try leb.writeULEB128(binary_writer, function.func.type_index); |
| 3691 | } | 3799 | } |
| 3692 | | 3800 | |
| 3693 | try writeVecSectionHeader( | 3801 | try writeVecSectionHeader( |
| 3694 | binary_bytes.items, | 3802 | binary_bytes.items, |
| 3695 | header_offset, | 3803 | header_offset, |
| 3696 | .function, | 3804 | .function, |
| 3697 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3805 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3698 | @as(u32, @intCast(wasm.functions.count())), | 3806 | @intCast(wasm.functions.count()), |
| 3699 | ); | 3807 | ); |
| 3700 | section_count += 1; | 3808 | section_count += 1; |
| 3701 | } | 3809 | } |
| ... | @@ -3713,8 +3821,8 @@ fn writeToFile( | ... | @@ -3713,8 +3821,8 @@ fn writeToFile( |
| 3713 | binary_bytes.items, | 3821 | binary_bytes.items, |
| 3714 | header_offset, | 3822 | header_offset, |
| 3715 | .table, | 3823 | .table, |
| 3716 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3824 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3717 | @as(u32, @intCast(wasm.tables.items.len)), | 3825 | @intCast(wasm.tables.items.len), |
| 3718 | ); | 3826 | ); |
| 3719 | section_count += 1; | 3827 | section_count += 1; |
| 3720 | } | 3828 | } |
| ... | @@ -3728,8 +3836,8 @@ fn writeToFile( | ... | @@ -3728,8 +3836,8 @@ fn writeToFile( |
| 3728 | binary_bytes.items, | 3836 | binary_bytes.items, |
| 3729 | header_offset, | 3837 | header_offset, |
| 3730 | .memory, | 3838 | .memory, |
| 3731 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3839 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3732 | @as(u32, 1), // wasm currently only supports 1 linear memory segment | 3840 | 1, // wasm currently only supports 1 linear memory segment |
| 3733 | ); | 3841 | ); |
| 3734 | section_count += 1; | 3842 | section_count += 1; |
| 3735 | } | 3843 | } |
| ... | @@ -3748,8 +3856,8 @@ fn writeToFile( | ... | @@ -3748,8 +3856,8 @@ fn writeToFile( |
| 3748 | binary_bytes.items, | 3856 | binary_bytes.items, |
| 3749 | header_offset, | 3857 | header_offset, |
| 3750 | .global, | 3858 | .global, |
| 3751 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3859 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3752 | @as(u32, @intCast(wasm.wasm_globals.items.len)), | 3860 | @intCast(wasm.wasm_globals.items.len), |
| 3753 | ); | 3861 | ); |
| 3754 | section_count += 1; | 3862 | section_count += 1; |
| 3755 | } | 3863 | } |
| ... | @@ -3777,8 +3885,8 @@ fn writeToFile( | ... | @@ -3777,8 +3885,8 @@ fn writeToFile( |
| 3777 | binary_bytes.items, | 3885 | binary_bytes.items, |
| 3778 | header_offset, | 3886 | header_offset, |
| 3779 | .@"export", | 3887 | .@"export", |
| 3780 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3888 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3781 | @as(u32, @intCast(wasm.exports.items.len)) + @intFromBool(export_memory), | 3889 | @intCast(wasm.exports.items.len + @intFromBool(export_memory)), |
| 3782 | ); | 3890 | ); |
| 3783 | section_count += 1; | 3891 | section_count += 1; |
| 3784 | } | 3892 | } |
| ... | @@ -3813,15 +3921,16 @@ fn writeToFile( | ... | @@ -3813,15 +3921,16 @@ fn writeToFile( |
| 3813 | try leb.writeULEB128(binary_writer, @as(u32, @intCast(wasm.function_table.count()))); | 3921 | try leb.writeULEB128(binary_writer, @as(u32, @intCast(wasm.function_table.count()))); |
| 3814 | var symbol_it = wasm.function_table.keyIterator(); | 3922 | var symbol_it = wasm.function_table.keyIterator(); |
| 3815 | while (symbol_it.next()) |symbol_loc_ptr| { | 3923 | while (symbol_it.next()) |symbol_loc_ptr| { |
| 3816 | try leb.writeULEB128(binary_writer, symbol_loc_ptr.*.getSymbol(wasm).index); | 3924 | const sym = symbol_loc_ptr.*.getSymbol(wasm); |
| | 3925 | try leb.writeULEB128(binary_writer, sym.index); |
| 3817 | } | 3926 | } |
| 3818 | | 3927 | |
| 3819 | try writeVecSectionHeader( | 3928 | try writeVecSectionHeader( |
| 3820 | binary_bytes.items, | 3929 | binary_bytes.items, |
| 3821 | header_offset, | 3930 | header_offset, |
| 3822 | .element, | 3931 | .element, |
| 3823 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3932 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3824 | @as(u32, 1), | 3933 | 1, |
| 3825 | ); | 3934 | ); |
| 3826 | section_count += 1; | 3935 | section_count += 1; |
| 3827 | } | 3936 | } |
| ... | @@ -3834,8 +3943,8 @@ fn writeToFile( | ... | @@ -3834,8 +3943,8 @@ fn writeToFile( |
| 3834 | binary_bytes.items, | 3943 | binary_bytes.items, |
| 3835 | header_offset, | 3944 | header_offset, |
| 3836 | .data_count, | 3945 | .data_count, |
| 3837 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 3946 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3838 | @as(u32, @intCast(data_segments_count)), | 3947 | @intCast(data_segments_count), |
| 3839 | ); | 3948 | ); |
| 3840 | } | 3949 | } |
| 3841 | | 3950 | |
| ... | @@ -3846,20 +3955,18 @@ fn writeToFile( | ... | @@ -3846,20 +3955,18 @@ fn writeToFile( |
| 3846 | var atom_index = wasm.atoms.get(code_index).?; | 3955 | var atom_index = wasm.atoms.get(code_index).?; |
| 3847 | | 3956 | |
| 3848 | // The code section must be sorted in line with the function order. | 3957 | // The code section must be sorted in line with the function order. |
| 3849 | var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count()); | 3958 | var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(wasm.base.allocator, wasm.functions.count()); |
| 3850 | defer sorted_atoms.deinit(); | 3959 | defer sorted_atoms.deinit(); |
| 3851 | | 3960 | |
| 3852 | while (true) { | 3961 | while (true) { |
| 3853 | var atom = wasm.getAtomPtr(atom_index); | 3962 | const atom = wasm.getAtomPtr(atom_index); |
| 3854 | if (wasm.resolved_symbols.contains(atom.symbolLoc())) { | 3963 | if (!is_obj) { |
| 3855 | if (!is_obj) { | 3964 | atom.resolveRelocs(wasm); |
| 3856 | atom.resolveRelocs(wasm); | | |
| 3857 | } | | |
| 3858 | sorted_atoms.appendAssumeCapacity(atom); | | |
| 3859 | } | 3965 | } |
| 3860 | // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; | 3966 | sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions |
| 3861 | atom_index = atom.prev orelse break; | 3967 | atom_index = atom.prev orelse break; |
| 3862 | } | 3968 | } |
| | 3969 | std.debug.assert(wasm.functions.count() == sorted_atoms.items.len); |
| 3863 | | 3970 | |
| 3864 | const atom_sort_fn = struct { | 3971 | const atom_sort_fn = struct { |
| 3865 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { | 3972 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { |
| ... | @@ -3869,7 +3976,7 @@ fn writeToFile( | ... | @@ -3869,7 +3976,7 @@ fn writeToFile( |
| 3869 | } | 3976 | } |
| 3870 | }.sort; | 3977 | }.sort; |
| 3871 | | 3978 | |
| 3872 | mem.sort(*Atom, sorted_atoms.items, wasm, atom_sort_fn); | 3979 | mem.sort(*const Atom, sorted_atoms.items, wasm, atom_sort_fn); |
| 3873 | | 3980 | |
| 3874 | for (sorted_atoms.items) |sorted_atom| { | 3981 | for (sorted_atoms.items) |sorted_atom| { |
| 3875 | try leb.writeULEB128(binary_writer, sorted_atom.size); | 3982 | try leb.writeULEB128(binary_writer, sorted_atom.size); |
| ... | @@ -3882,7 +3989,7 @@ fn writeToFile( | ... | @@ -3882,7 +3989,7 @@ fn writeToFile( |
| 3882 | header_offset, | 3989 | header_offset, |
| 3883 | .code, | 3990 | .code, |
| 3884 | code_section_size, | 3991 | code_section_size, |
| 3885 | @as(u32, @intCast(wasm.functions.count())), | 3992 | @intCast(wasm.functions.count()), |
| 3886 | ); | 3993 | ); |
| 3887 | code_section_index = section_count; | 3994 | code_section_index = section_count; |
| 3888 | section_count += 1; | 3995 | section_count += 1; |
| ... | @@ -3953,8 +4060,8 @@ fn writeToFile( | ... | @@ -3953,8 +4060,8 @@ fn writeToFile( |
| 3953 | binary_bytes.items, | 4060 | binary_bytes.items, |
| 3954 | header_offset, | 4061 | header_offset, |
| 3955 | .data, | 4062 | .data, |
| 3956 | @as(u32, @intCast(binary_bytes.items.len - header_offset - header_size)), | 4063 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3957 | @as(u32, @intCast(segment_count)), | 4064 | @intCast(segment_count), |
| 3958 | ); | 4065 | ); |
| 3959 | data_section_index = section_count; | 4066 | data_section_index = section_count; |
| 3960 | section_count += 1; | 4067 | section_count += 1; |
| ... | @@ -4210,6 +4317,9 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem | ... | @@ -4210,6 +4317,9 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem |
| 4210 | | 4317 | |
| 4211 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 4318 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 4212 | const symbol = sym_loc.getSymbol(wasm).*; | 4319 | const symbol = sym_loc.getSymbol(wasm).*; |
| | 4320 | if (symbol.isDead()) { |
| | 4321 | continue; |
| | 4322 | } |
| 4213 | const name = sym_loc.getName(wasm); | 4323 | const name = sym_loc.getName(wasm); |
| 4214 | switch (symbol.tag) { | 4324 | switch (symbol.tag) { |
| 4215 | .function => { | 4325 | .function => { |
| ... | @@ -4498,6 +4608,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -4498,6 +4608,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 4498 | try argv.append("--export-table"); | 4608 | try argv.append("--export-table"); |
| 4499 | } | 4609 | } |
| 4500 | | 4610 | |
| | 4611 | if (wasm.base.options.gc_sections) |gc| { |
| | 4612 | // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly |
| | 4613 | // specified it as garbage collection is enabled by default. |
| | 4614 | if (!gc) { |
| | 4615 | try argv.append("--no-gc-sections"); |
| | 4616 | } |
| | 4617 | } |
| | 4618 | |
| 4501 | if (wasm.base.options.strip) { | 4619 | if (wasm.base.options.strip) { |
| 4502 | try argv.append("-s"); | 4620 | try argv.append("-s"); |
| 4503 | } | 4621 | } |
| ... | @@ -4783,7 +4901,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -4783,7 +4901,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 4783 | try wasm.emitSymbolTable(binary_bytes, symbol_table); | 4901 | try wasm.emitSymbolTable(binary_bytes, symbol_table); |
| 4784 | try wasm.emitSegmentInfo(binary_bytes); | 4902 | try wasm.emitSegmentInfo(binary_bytes); |
| 4785 | | 4903 | |
| 4786 | const size = @as(u32, @intCast(binary_bytes.items.len - offset - 6)); | 4904 | const size: u32 = @intCast(binary_bytes.items.len - offset - 6); |
| 4787 | try writeCustomSectionHeader(binary_bytes.items, offset, size); | 4905 | try writeCustomSectionHeader(binary_bytes.items, offset, size); |
| 4788 | } | 4906 | } |
| 4789 | | 4907 | |
| ... | @@ -4831,7 +4949,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -4831,7 +4949,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 4831 | } | 4949 | } |
| 4832 | | 4950 | |
| 4833 | var buf: [10]u8 = undefined; | 4951 | var buf: [10]u8 = undefined; |
| 4834 | leb.writeUnsignedFixed(5, buf[0..5], @as(u32, @intCast(binary_bytes.items.len - table_offset + 5))); | 4952 | leb.writeUnsignedFixed(5, buf[0..5], @intCast(binary_bytes.items.len - table_offset + 5)); |
| 4835 | leb.writeUnsignedFixed(5, buf[5..], symbol_count); | 4953 | leb.writeUnsignedFixed(5, buf[5..], symbol_count); |
| 4836 | try binary_bytes.insertSlice(table_offset, &buf); | 4954 | try binary_bytes.insertSlice(table_offset, &buf); |
| 4837 | } | 4955 | } |
| ... | @@ -4914,7 +5032,7 @@ fn emitCodeRelocations( | ... | @@ -4914,7 +5032,7 @@ fn emitCodeRelocations( |
| 4914 | var buf: [5]u8 = undefined; | 5032 | var buf: [5]u8 = undefined; |
| 4915 | leb.writeUnsignedFixed(5, &buf, count); | 5033 | leb.writeUnsignedFixed(5, &buf, count); |
| 4916 | try binary_bytes.insertSlice(reloc_start, &buf); | 5034 | try binary_bytes.insertSlice(reloc_start, &buf); |
| 4917 | const size = @as(u32, @intCast(binary_bytes.items.len - header_offset - 6)); | 5035 | const size: u32 = @intCast(binary_bytes.items.len - header_offset - 6); |
| 4918 | try writeCustomSectionHeader(binary_bytes.items, header_offset, size); | 5036 | try writeCustomSectionHeader(binary_bytes.items, header_offset, size); |
| 4919 | } | 5037 | } |
| 4920 | | 5038 | |
| ... | @@ -5018,3 +5136,67 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s | ... | @@ -5018,3 +5136,67 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s |
| 5018 | try wasm.atom_types.put(wasm.base.allocator, atom_index, index); | 5136 | try wasm.atom_types.put(wasm.base.allocator, atom_index, index); |
| 5019 | return index; | 5137 | return index; |
| 5020 | } | 5138 | } |
| | 5139 | |
| | 5140 | /// Verifies all resolved symbols and checks whether itself needs to be marked alive, |
| | 5141 | /// as well as any of its references. |
| | 5142 | fn markReferences(wasm: *Wasm) !void { |
| | 5143 | const tracy = trace(@src()); |
| | 5144 | defer tracy.end(); |
| | 5145 | const do_garbage_collect = wasm.base.options.gc_sections orelse |
| | 5146 | (wasm.base.options.output_mode != .Obj); |
| | 5147 | |
| | 5148 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| | 5149 | const sym = sym_loc.getSymbol(wasm); |
| | 5150 | if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { |
| | 5151 | try wasm.mark(sym_loc); |
| | 5152 | continue; |
| | 5153 | } |
| | 5154 | |
| | 5155 | // Debug sections may require to be parsed and marked when it contains |
| | 5156 | // relocations to alive symbols. |
| | 5157 | if (sym.tag == .section and !wasm.base.options.strip) { |
| | 5158 | const file = sym_loc.file orelse continue; // Incremental debug info is done independently |
| | 5159 | const object = &wasm.objects.items[file]; |
| | 5160 | const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm); |
| | 5161 | const atom = wasm.getAtom(atom_index); |
| | 5162 | for (atom.relocs.items) |reloc| { |
| | 5163 | const target_loc: SymbolLoc = .{ .index = reloc.index, .file = atom.file }; |
| | 5164 | const target_sym = target_loc.getSymbol(wasm); |
| | 5165 | if (target_sym.isAlive() or !do_garbage_collect) { |
| | 5166 | sym.mark(); |
| | 5167 | continue; // Skip all other relocations as this debug atom is already marked now |
| | 5168 | } |
| | 5169 | } |
| | 5170 | } |
| | 5171 | } |
| | 5172 | } |
| | 5173 | |
| | 5174 | /// Marks a symbol as 'alive' recursively so itself and any references it contains to |
| | 5175 | /// other symbols will not be omit from the binary. |
| | 5176 | fn mark(wasm: *Wasm, loc: SymbolLoc) !void { |
| | 5177 | const symbol = loc.getSymbol(wasm); |
| | 5178 | if (symbol.isAlive()) { |
| | 5179 | // Symbol is already marked alive, including its references. |
| | 5180 | // This means we can skip it so we don't end up marking the same symbols |
| | 5181 | // multiple times. |
| | 5182 | return; |
| | 5183 | } |
| | 5184 | symbol.mark(); |
| | 5185 | if (symbol.isUndefined()) { |
| | 5186 | // undefined symbols do not have an associated `Atom` and therefore also |
| | 5187 | // do not contain relocations. |
| | 5188 | return; |
| | 5189 | } |
| | 5190 | |
| | 5191 | const atom_index = if (loc.file) |file_index| idx: { |
| | 5192 | const object = &wasm.objects.items[file_index]; |
| | 5193 | const atom_index = try object.parseSymbolIntoAtom(file_index, loc.index, wasm); |
| | 5194 | break :idx atom_index; |
| | 5195 | } else wasm.symbol_atom.get(loc) orelse return; |
| | 5196 | |
| | 5197 | const atom = wasm.getAtom(atom_index); |
| | 5198 | for (atom.relocs.items) |reloc| { |
| | 5199 | const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file }; |
| | 5200 | try wasm.mark(target_loc.finalLoc(wasm)); |
| | 5201 | } |
| | 5202 | } |