| ... | ... | @@ -1703,6 +1703,7 @@ pub fn updateDeclExports( |
| 1703 | 1703 | const decl = mod.declPtr(decl_index); |
| 1704 | 1704 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1705 | 1705 | const atom = wasm.getAtom(atom_index); |
| 1706 | const atom_sym = atom.symbolLoc().getSymbol(wasm).*; |
| 1706 | 1707 | const gpa = mod.gpa; |
| 1707 | 1708 | |
| 1708 | 1709 | for (exports) |exp| { |
| ... | ... | @@ -1716,43 +1717,21 @@ pub fn updateDeclExports( |
| 1716 | 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 | 1720 | const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl); |
| 1750 | 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 | 1723 | const sym_loc = exported_atom.symbolLoc(); |
| 1752 | 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 | 1731 | switch (exp.opts.linkage) { |
| 1754 | 1732 | .Internal => { |
| 1755 | 1733 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 1734 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 1756 | 1735 | }, |
| 1757 | 1736 | .Weak => { |
| 1758 | 1737 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| ... | ... | @@ -1768,22 +1747,52 @@ pub fn updateDeclExports( |
| 1768 | 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 | 1786 | // Ensure the symbol will be exported using the given name |
| 1772 | 1787 | if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 1773 | 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 | 1791 | try wasm.globals.put( |
| 1779 | 1792 | wasm.base.allocator, |
| 1780 | 1793 | export_name, |
| 1781 | 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 | |