| ... | @@ -1703,6 +1703,7 @@ pub fn updateDeclExports( | ... | @@ -1703,6 +1703,7 @@ pub fn updateDeclExports( |
| 1703 | const decl = mod.declPtr(decl_index); | 1703 | const decl = mod.declPtr(decl_index); |
| 1704 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); | 1704 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1705 | const atom = wasm.getAtom(atom_index); | 1705 | const atom = wasm.getAtom(atom_index); |
| | 1706 | const atom_sym = atom.symbolLoc().getSymbol(wasm).*; |
| 1706 | const gpa = mod.gpa; | 1707 | const gpa = mod.gpa; |
| 1707 | | 1708 | |
| 1708 | for (exports) |exp| { | 1709 | for (exports) |exp| { |
| ... | @@ -1716,43 +1717,21 @@ pub fn updateDeclExports( | ... | @@ -1716,43 +1717,21 @@ pub fn updateDeclExports( |
| 1716 | continue; | 1717 | continue; |
| 1717 | } | 1718 | } |
| 1718 | | 1719 | |
| 1719 | const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); | | |
| 1720 | if (wasm.globals.getPtr(export_name)) |existing_loc| { | | |
| 1721 | if (existing_loc.index == atom.sym_index) continue; | | |
| 1722 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; | | |
| 1723 | | | |
| 1724 | const exp_is_weak = exp.opts.linkage == .Internal or exp.opts.linkage == .Weak; | | |
| 1725 | // When both the to-be-exported symbol and the already existing symbol | | |
| 1726 | // are strong symbols, we have a linker error. | | |
| 1727 | // In the other case we replace one with the other. | | |
| 1728 | if (!exp_is_weak and !existing_sym.isWeak()) { | | |
| 1729 | try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( | | |
| 1730 | gpa, | | |
| 1731 | decl.srcLoc(mod), | | |
| 1732 | \\LinkError: symbol '{}' defined multiple times | | |
| 1733 | \\ first definition in '{s}' | | |
| 1734 | \\ next definition in '{s}' | | |
| 1735 | , | | |
| 1736 | .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, | | |
| 1737 | )); | | |
| 1738 | continue; | | |
| 1739 | } else if (exp_is_weak) { | | |
| 1740 | continue; // to-be-exported symbol is weak, so we keep the existing symbol | | |
| 1741 | } else { | | |
| 1742 | // TODO: Revisit this, why was this needed? | | |
| 1743 | existing_loc.index = atom.sym_index; | | |
| 1744 | existing_loc.file = null; | | |
| 1745 | // exp.link.wasm.sym_index = existing_loc.index; | | |
| 1746 | } | | |
| 1747 | } | | |
| 1748 | | | |
| 1749 | const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl); | 1720 | const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl); |
| 1750 | const exported_atom = wasm.getAtom(exported_atom_index); | 1721 | const exported_atom = wasm.getAtom(exported_atom_index); |
| | 1722 | const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 1751 | const sym_loc = exported_atom.symbolLoc(); | 1723 | const sym_loc = exported_atom.symbolLoc(); |
| 1752 | const symbol = sym_loc.getSymbol(wasm); | 1724 | const symbol = sym_loc.getSymbol(wasm); |
| | 1725 | symbol.setGlobal(true); |
| | 1726 | symbol.setUndefined(false); |
| | 1727 | symbol.index = atom_sym.index; |
| | 1728 | symbol.tag = atom_sym.tag; |
| | 1729 | symbol.name = atom_sym.name; |
| | 1730 | |
| 1753 | switch (exp.opts.linkage) { | 1731 | switch (exp.opts.linkage) { |
| 1754 | .Internal => { | 1732 | .Internal => { |
| 1755 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 1733 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 1734 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 1756 | }, | 1735 | }, |
| 1757 | .Weak => { | 1736 | .Weak => { |
| 1758 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); | 1737 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| ... | @@ -1768,22 +1747,52 @@ pub fn updateDeclExports( | ... | @@ -1768,22 +1747,52 @@ pub fn updateDeclExports( |
| 1768 | continue; | 1747 | continue; |
| 1769 | }, | 1748 | }, |
| 1770 | } | 1749 | } |
| | 1750 | |
| | 1751 | if (wasm.globals.get(export_name)) |existing_loc| { |
| | 1752 | if (existing_loc.index == atom.sym_index) continue; |
| | 1753 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; |
| | 1754 | |
| | 1755 | if (!existing_sym.isUndefined()) blk: { |
| | 1756 | if (symbol.isWeak()) { |
| | 1757 | try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); |
| | 1758 | continue; // to-be-exported symbol is weak, so we keep the existing symbol |
| | 1759 | } |
| | 1760 | |
| | 1761 | // new symbol is not weak while existing is, replace existing symbol |
| | 1762 | if (existing_sym.isWeak()) { |
| | 1763 | break :blk; |
| | 1764 | } |
| | 1765 | // When both the to-be-exported symbol and the already existing symbol |
| | 1766 | // are strong symbols, we have a linker error. |
| | 1767 | // In the other case we replace one with the other. |
| | 1768 | try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( |
| | 1769 | gpa, |
| | 1770 | decl.srcLoc(mod), |
| | 1771 | \\LinkError: symbol '{}' defined multiple times |
| | 1772 | \\ first definition in '{s}' |
| | 1773 | \\ next definition in '{s}' |
| | 1774 | , |
| | 1775 | .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, |
| | 1776 | )); |
| | 1777 | continue; |
| | 1778 | } |
| | 1779 | |
| | 1780 | // in this case the existing symbol must be replaced either because it's weak or undefined. |
| | 1781 | try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); |
| | 1782 | _ = wasm.imports.remove(existing_loc); |
| | 1783 | _ = wasm.undefs.swapRemove(existing_sym.name); |
| | 1784 | } |
| | 1785 | |
| 1771 | // Ensure the symbol will be exported using the given name | 1786 | // Ensure the symbol will be exported using the given name |
| 1772 | if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { | 1787 | if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 1773 | try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); | 1788 | try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); |
| 1774 | } | 1789 | } |
| 1775 | | 1790 | |
| 1776 | symbol.setGlobal(true); | | |
| 1777 | symbol.setUndefined(false); | | |
| 1778 | try wasm.globals.put( | 1791 | try wasm.globals.put( |
| 1779 | wasm.base.allocator, | 1792 | wasm.base.allocator, |
| 1780 | export_name, | 1793 | export_name, |
| 1781 | sym_loc, | 1794 | sym_loc, |
| 1782 | ); | 1795 | ); |
| 1783 | | | |
| 1784 | // if the symbol was previously undefined, remove it as an import | | |
| 1785 | _ = wasm.imports.remove(sym_loc); | | |
| 1786 | _ = wasm.undefs.swapRemove(export_name); | | |
| 1787 | } | 1796 | } |
| 1788 | } | 1797 | } |
| 1789 | | 1798 | |