| ... | @@ -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 |
| ... | @@ -1584,7 +1584,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | ... | @@ -1584,7 +1584,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1584 | const ty_index = wasm.imports.get(loc).?.kind.function; | 1584 | const ty_index = wasm.imports.get(loc).?.kind.function; |
| 1585 | return wasm.func_types.items[ty_index]; | 1585 | return wasm.func_types.items[ty_index]; |
| 1586 | } | 1586 | } |
| 1587 | 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]; |
| 1588 | } | 1588 | } |
| 1589 | | 1589 | |
| 1590 | /// Lowers a constant typed value to a local symbol and atom. | 1590 | /// Lowers a constant typed value to a local symbol and atom. |
| ... | @@ -2141,7 +2141,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | ... | @@ -2141,7 +2141,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2141 | try wasm.functions.putNoClobber( | 2141 | try wasm.functions.putNoClobber( |
| 2142 | wasm.base.allocator, | 2142 | wasm.base.allocator, |
| 2143 | .{ .file = null, .index = index }, | 2143 | .{ .file = null, .index = index }, |
| 2144 | .{ .type_index = type_index }, | 2144 | .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 2145 | ); | 2145 | ); |
| 2146 | symbol.tag = .function; | 2146 | symbol.tag = .function; |
| 2147 | symbol.index = index; | 2147 | symbol.index = index; |
| ... | @@ -2274,7 +2274,14 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2274,7 +2274,14 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2274 | while (true) { | 2274 | while (true) { |
| 2275 | const atom = wasm.getAtomPtr(atom_index); | 2275 | const atom = wasm.getAtomPtr(atom_index); |
| 2276 | const symbol_loc = atom.symbolLoc(); | 2276 | const symbol_loc = atom.symbolLoc(); |
| 2277 | const sym = symbol_loc.getSymbol(wasm); | 2277 | // Ensure we get the original symbol, so we verify the correct symbol on whether |
| | 2278 | // it is dead or not and ensure an atom is removed when dead. |
| | 2279 | // This is required as we may have parsed aliases into atoms. |
| | 2280 | const sym = if (symbol_loc.file) |object_index| sym: { |
| | 2281 | const object = wasm.objects.items[object_index]; |
| | 2282 | break :sym object.symtable[symbol_loc.index]; |
| | 2283 | } else wasm.symbols.items[symbol_loc.index]; |
| | 2284 | |
| 2278 | if (sym.isDead()) { | 2285 | if (sym.isDead()) { |
| 2279 | // Dead symbols must be unlinked from the linked-list to prevent them | 2286 | // Dead symbols must be unlinked from the linked-list to prevent them |
| 2280 | // from being emit into the binary. | 2287 | // from being emit into the binary. |
| ... | @@ -2477,7 +2484,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { | ... | @@ -2477,7 +2484,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 2477 | // call constructors | 2484 | // call constructors |
| 2478 | for (wasm.init_funcs.items) |init_func_loc| { | 2485 | for (wasm.init_funcs.items) |init_func_loc| { |
| 2479 | const symbol = init_func_loc.getSymbol(wasm); | 2486 | const symbol = init_func_loc.getSymbol(wasm); |
| 2480 | const func = wasm.functions.values()[symbol.index - wasm.imported_functions_count]; | 2487 | const func = wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; |
| 2481 | const ty = wasm.func_types.items[func.type_index]; | 2488 | const ty = wasm.func_types.items[func.type_index]; |
| 2482 | | 2489 | |
| 2483 | // Call function by its function index | 2490 | // Call function by its function index |
| ... | @@ -2519,7 +2526,7 @@ fn createSyntheticFunction( | ... | @@ -2519,7 +2526,7 @@ fn createSyntheticFunction( |
| 2519 | try wasm.functions.putNoClobber( | 2526 | try wasm.functions.putNoClobber( |
| 2520 | wasm.base.allocator, | 2527 | wasm.base.allocator, |
| 2521 | .{ .file = null, .index = func_index }, | 2528 | .{ .file = null, .index = func_index }, |
| 2522 | .{ .type_index = ty_index }, | 2529 | .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, |
| 2523 | ); | 2530 | ); |
| 2524 | symbol.index = func_index; | 2531 | symbol.index = func_index; |
| 2525 | | 2532 | |
| ... | @@ -2740,6 +2747,9 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -2740,6 +2747,9 @@ fn setupImports(wasm: *Wasm) !void { |
| 2740 | /// Takes the global, function and table section from each linked object file | 2747 | /// Takes the global, function and table section from each linked object file |
| 2741 | /// and merges it into a single section for each. | 2748 | /// and merges it into a single section for each. |
| 2742 | fn mergeSections(wasm: *Wasm) !void { | 2749 | fn mergeSections(wasm: *Wasm) !void { |
| | 2750 | var removed_duplicates = std.ArrayList(SymbolLoc).init(wasm.base.allocator); |
| | 2751 | defer removed_duplicates.deinit(); |
| | 2752 | |
| 2743 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 2753 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2744 | if (sym_loc.file == null) { | 2754 | if (sym_loc.file == null) { |
| 2745 | // Zig code-generated symbols are already within the sections and do not | 2755 | // Zig code-generated symbols are already within the sections and do not |
| ... | @@ -2767,9 +2777,19 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2767,9 +2777,19 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2767 | wasm.base.allocator, | 2777 | wasm.base.allocator, |
| 2768 | .{ .file = sym_loc.file, .index = symbol.index }, | 2778 | .{ .file = sym_loc.file, .index = symbol.index }, |
| 2769 | ); | 2779 | ); |
| 2770 | if (!gop.found_existing) { | 2780 | if (gop.found_existing) { |
| 2771 | gop.value_ptr.* = object.functions[index]; | 2781 | // We found an alias to the same function, discard this symbol in favor of |
| | 2782 | // the original symbol and point the discard function to it. This ensures |
| | 2783 | // we only emit a single function, instead of duplicates. |
| | 2784 | try wasm.discarded.putNoClobber( |
| | 2785 | wasm.base.allocator, |
| | 2786 | sym_loc, |
| | 2787 | .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index }, |
| | 2788 | ); |
| | 2789 | try removed_duplicates.append(sym_loc); |
| | 2790 | continue; |
| 2772 | } | 2791 | } |
| | 2792 | gop.value_ptr.* = .{ .func = object.functions[index], .sym_index = sym_loc.index }; |
| 2773 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; | 2793 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; |
| 2774 | }, | 2794 | }, |
| 2775 | .global => { | 2795 | .global => { |
| ... | @@ -2786,6 +2806,12 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2786,6 +2806,12 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2786 | } | 2806 | } |
| 2787 | } | 2807 | } |
| 2788 | | 2808 | |
| | 2809 | // For any removed duplicates, remove them from the resolved symbols list |
| | 2810 | for (removed_duplicates.items) |sym_loc| { |
| | 2811 | assert(wasm.resolved_symbols.swapRemove(sym_loc)); |
| | 2812 | sym_loc.getSymbol(wasm).unmark(); |
| | 2813 | } |
| | 2814 | |
| 2789 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); | 2815 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); |
| 2790 | log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len}); | 2816 | log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len}); |
| 2791 | log.debug("Merged ({d}) tables", .{wasm.tables.items.len}); | 2817 | log.debug("Merged ({d}) tables", .{wasm.tables.items.len}); |
| ... | @@ -2821,7 +2847,7 @@ fn mergeTypes(wasm: *Wasm) !void { | ... | @@ -2821,7 +2847,7 @@ fn mergeTypes(wasm: *Wasm) !void { |
| 2821 | import.kind.function = try wasm.putOrGetFuncType(original_type); | 2847 | import.kind.function = try wasm.putOrGetFuncType(original_type); |
| 2822 | } else if (!dirty.contains(symbol.index)) { | 2848 | } else if (!dirty.contains(symbol.index)) { |
| 2823 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)}); | 2849 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)}); |
| 2824 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count]; | 2850 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; |
| 2825 | func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]); | 2851 | func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]); |
| 2826 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); | 2852 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 2827 | } | 2853 | } |
| ... | @@ -3498,12 +3524,12 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -3498,12 +3524,12 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 3498 | | 3524 | |
| 3499 | try wasm.markReferences(); | 3525 | try wasm.markReferences(); |
| 3500 | try wasm.setupImports(); | 3526 | try wasm.setupImports(); |
| | 3527 | try wasm.mergeSections(); |
| | 3528 | try wasm.mergeTypes(); |
| 3501 | try wasm.allocateAtoms(); | 3529 | try wasm.allocateAtoms(); |
| 3502 | try wasm.setupMemory(); | 3530 | try wasm.setupMemory(); |
| 3503 | wasm.allocateVirtualAddresses(); | 3531 | wasm.allocateVirtualAddresses(); |
| 3504 | wasm.mapFunctionTable(); | 3532 | wasm.mapFunctionTable(); |
| 3505 | try wasm.mergeSections(); | | |
| 3506 | try wasm.mergeTypes(); | | |
| 3507 | try wasm.initializeCallCtorsFunction(); | 3533 | try wasm.initializeCallCtorsFunction(); |
| 3508 | try wasm.setupInitMemoryFunction(); | 3534 | try wasm.setupInitMemoryFunction(); |
| 3509 | try wasm.setupTLSRelocationsFunction(); | 3535 | try wasm.setupTLSRelocationsFunction(); |
| ... | @@ -3639,12 +3665,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -3639,12 +3665,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3639 | } | 3665 | } |
| 3640 | } | 3666 | } |
| 3641 | | 3667 | |
| | 3668 | try wasm.mergeSections(); |
| | 3669 | try wasm.mergeTypes(); |
| 3642 | try wasm.allocateAtoms(); | 3670 | try wasm.allocateAtoms(); |
| 3643 | try wasm.setupMemory(); | 3671 | try wasm.setupMemory(); |
| 3644 | wasm.allocateVirtualAddresses(); | 3672 | wasm.allocateVirtualAddresses(); |
| 3645 | wasm.mapFunctionTable(); | 3673 | wasm.mapFunctionTable(); |
| 3646 | try wasm.mergeSections(); | | |
| 3647 | try wasm.mergeTypes(); | | |
| 3648 | try wasm.initializeCallCtorsFunction(); | 3674 | try wasm.initializeCallCtorsFunction(); |
| 3649 | try wasm.setupInitMemoryFunction(); | 3675 | try wasm.setupInitMemoryFunction(); |
| 3650 | try wasm.setupTLSRelocationsFunction(); | 3676 | try wasm.setupTLSRelocationsFunction(); |
| ... | @@ -3745,7 +3771,7 @@ fn writeToFile( | ... | @@ -3745,7 +3771,7 @@ fn writeToFile( |
| 3745 | if (wasm.functions.count() != 0) { | 3771 | if (wasm.functions.count() != 0) { |
| 3746 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 3772 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 3747 | for (wasm.functions.values()) |function| { | 3773 | for (wasm.functions.values()) |function| { |
| 3748 | try leb.writeULEB128(binary_writer, function.type_index); | 3774 | try leb.writeULEB128(binary_writer, function.func.type_index); |
| 3749 | } | 3775 | } |
| 3750 | | 3776 | |
| 3751 | try writeVecSectionHeader( | 3777 | try writeVecSectionHeader( |
| ... | @@ -3916,6 +3942,7 @@ fn writeToFile( | ... | @@ -3916,6 +3942,7 @@ fn writeToFile( |
| 3916 | sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions | 3942 | sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions |
| 3917 | atom_index = atom.prev orelse break; | 3943 | atom_index = atom.prev orelse break; |
| 3918 | } | 3944 | } |
| | 3945 | std.debug.assert(wasm.functions.count() == sorted_atoms.items.len); |
| 3919 | | 3946 | |
| 3920 | const atom_sort_fn = struct { | 3947 | const atom_sort_fn = struct { |
| 3921 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { | 3948 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { |