| ... | ... | @@ -110,7 +110,7 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 110 | 110 | /// Output function section where the key is the original |
| 111 | 111 | /// function index and the value is function. |
| 112 | 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 | 114 | /// Output global section |
| 115 | 115 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, |
| 116 | 116 | /// Memory section |
| ... | ... | @@ -1584,7 +1584,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1584 | 1584 | const ty_index = wasm.imports.get(loc).?.kind.function; |
| 1585 | 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 | 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 | 2141 | try wasm.functions.putNoClobber( |
| 2142 | 2142 | wasm.base.allocator, |
| 2143 | 2143 | .{ .file = null, .index = index }, |
| 2144 | | .{ .type_index = type_index }, |
| 2144 | .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 2145 | 2145 | ); |
| 2146 | 2146 | symbol.tag = .function; |
| 2147 | 2147 | symbol.index = index; |
| ... | ... | @@ -2274,7 +2274,14 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2274 | 2274 | while (true) { |
| 2275 | 2275 | const atom = wasm.getAtomPtr(atom_index); |
| 2276 | 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 | 2285 | if (sym.isDead()) { |
| 2279 | 2286 | // Dead symbols must be unlinked from the linked-list to prevent them |
| 2280 | 2287 | // from being emit into the binary. |
| ... | ... | @@ -2477,7 +2484,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 2477 | 2484 | // call constructors |
| 2478 | 2485 | for (wasm.init_funcs.items) |init_func_loc| { |
| 2479 | 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 | 2488 | const ty = wasm.func_types.items[func.type_index]; |
| 2482 | 2489 | |
| 2483 | 2490 | // Call function by its function index |
| ... | ... | @@ -2519,7 +2526,7 @@ fn createSyntheticFunction( |
| 2519 | 2526 | try wasm.functions.putNoClobber( |
| 2520 | 2527 | wasm.base.allocator, |
| 2521 | 2528 | .{ .file = null, .index = func_index }, |
| 2522 | | .{ .type_index = ty_index }, |
| 2529 | .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, |
| 2523 | 2530 | ); |
| 2524 | 2531 | symbol.index = func_index; |
| 2525 | 2532 | |
| ... | ... | @@ -2740,6 +2747,9 @@ fn setupImports(wasm: *Wasm) !void { |
| 2740 | 2747 | /// Takes the global, function and table section from each linked object file |
| 2741 | 2748 | /// and merges it into a single section for each. |
| 2742 | 2749 | fn mergeSections(wasm: *Wasm) !void { |
| 2750 | var removed_duplicates = std.ArrayList(SymbolLoc).init(wasm.base.allocator); |
| 2751 | defer removed_duplicates.deinit(); |
| 2752 | |
| 2743 | 2753 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2744 | 2754 | if (sym_loc.file == null) { |
| 2745 | 2755 | // Zig code-generated symbols are already within the sections and do not |
| ... | ... | @@ -2767,9 +2777,19 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2767 | 2777 | wasm.base.allocator, |
| 2768 | 2778 | .{ .file = sym_loc.file, .index = symbol.index }, |
| 2769 | 2779 | ); |
| 2770 | | if (!gop.found_existing) { |
| 2771 | | gop.value_ptr.* = object.functions[index]; |
| 2780 | if (gop.found_existing) { |
| 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 | 2793 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; |
| 2774 | 2794 | }, |
| 2775 | 2795 | .global => { |
| ... | ... | @@ -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 | 2815 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); |
| 2790 | 2816 | log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len}); |
| 2791 | 2817 | log.debug("Merged ({d}) tables", .{wasm.tables.items.len}); |
| ... | ... | @@ -2821,7 +2847,7 @@ fn mergeTypes(wasm: *Wasm) !void { |
| 2821 | 2847 | import.kind.function = try wasm.putOrGetFuncType(original_type); |
| 2822 | 2848 | } else if (!dirty.contains(symbol.index)) { |
| 2823 | 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 | 2851 | func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]); |
| 2826 | 2852 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 2827 | 2853 | } |
| ... | ... | @@ -3498,12 +3524,12 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 3498 | 3524 | |
| 3499 | 3525 | try wasm.markReferences(); |
| 3500 | 3526 | try wasm.setupImports(); |
| 3527 | try wasm.mergeSections(); |
| 3528 | try wasm.mergeTypes(); |
| 3501 | 3529 | try wasm.allocateAtoms(); |
| 3502 | 3530 | try wasm.setupMemory(); |
| 3503 | 3531 | wasm.allocateVirtualAddresses(); |
| 3504 | 3532 | wasm.mapFunctionTable(); |
| 3505 | | try wasm.mergeSections(); |
| 3506 | | try wasm.mergeTypes(); |
| 3507 | 3533 | try wasm.initializeCallCtorsFunction(); |
| 3508 | 3534 | try wasm.setupInitMemoryFunction(); |
| 3509 | 3535 | try wasm.setupTLSRelocationsFunction(); |
| ... | ... | @@ -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 | 3670 | try wasm.allocateAtoms(); |
| 3643 | 3671 | try wasm.setupMemory(); |
| 3644 | 3672 | wasm.allocateVirtualAddresses(); |
| 3645 | 3673 | wasm.mapFunctionTable(); |
| 3646 | | try wasm.mergeSections(); |
| 3647 | | try wasm.mergeTypes(); |
| 3648 | 3674 | try wasm.initializeCallCtorsFunction(); |
| 3649 | 3675 | try wasm.setupInitMemoryFunction(); |
| 3650 | 3676 | try wasm.setupTLSRelocationsFunction(); |
| ... | ... | @@ -3745,7 +3771,7 @@ fn writeToFile( |
| 3745 | 3771 | if (wasm.functions.count() != 0) { |
| 3746 | 3772 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 3747 | 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 | 3777 | try writeVecSectionHeader( |
| ... | ... | @@ -3916,6 +3942,7 @@ fn writeToFile( |
| 3916 | 3942 | sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions |
| 3917 | 3943 | atom_index = atom.prev orelse break; |
| 3918 | 3944 | } |
| 3945 | std.debug.assert(wasm.functions.count() == sorted_atoms.items.len); |
| 3919 | 3946 | |
| 3920 | 3947 | const atom_sort_fn = struct { |
| 3921 | 3948 | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { |