| ... | ... | @@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null, |
| 187 | 187 | /// rather than by the linker. |
| 188 | 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 189 | 189 | |
| 190 | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. |
| 191 | anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, |
| 192 | |
| 190 | 193 | pub const Alignment = types.Alignment; |
| 191 | 194 | |
| 192 | 195 | pub const Segment = struct { |
| ... | ... | @@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1291 | 1294 | } |
| 1292 | 1295 | |
| 1293 | 1296 | wasm.decls.deinit(gpa); |
| 1297 | wasm.anon_decls.deinit(gpa); |
| 1294 | 1298 | wasm.atom_types.deinit(gpa); |
| 1295 | 1299 | wasm.symbols.deinit(gpa); |
| 1296 | 1300 | wasm.symbols_free_list.deinit(gpa); |
| ... | ... | @@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1548 | 1552 | assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions |
| 1549 | 1553 | const decl = mod.declPtr(decl_index); |
| 1550 | 1554 | |
| 1551 | | // Create and initialize a new local symbol and atom |
| 1552 | | const atom_index = try wasm.createAtom(); |
| 1553 | 1555 | const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1554 | | const parent_atom = wasm.getAtomPtr(parent_atom_index); |
| 1556 | const parent_atom = wasm.getAtom(parent_atom_index); |
| 1555 | 1557 | const local_index = parent_atom.locals.items.len; |
| 1556 | | try parent_atom.locals.append(wasm.base.allocator, atom_index); |
| 1557 | 1558 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1558 | 1559 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ |
| 1559 | 1560 | fqn, local_index, |
| 1560 | 1561 | }); |
| 1561 | 1562 | defer wasm.base.allocator.free(name); |
| 1563 | |
| 1564 | switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) { |
| 1565 | .ok => |atom_index| { |
| 1566 | try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index); |
| 1567 | return wasm.getAtom(atom_index).getSymbolIndex().?; |
| 1568 | }, |
| 1569 | .fail => |em| { |
| 1570 | decl.analysis = .codegen_failure; |
| 1571 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1572 | return error.CodegenFail; |
| 1573 | }, |
| 1574 | } |
| 1575 | } |
| 1576 | |
| 1577 | const LowerConstResult = union(enum) { |
| 1578 | ok: Atom.Index, |
| 1579 | fail: *Module.ErrorMsg, |
| 1580 | }; |
| 1581 | |
| 1582 | fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { |
| 1583 | const mod = wasm.base.options.module.?; |
| 1584 | |
| 1585 | // Create and initialize a new local symbol and atom |
| 1586 | const atom_index = try wasm.createAtom(); |
| 1562 | 1587 | var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
| 1563 | 1588 | defer value_bytes.deinit(); |
| 1564 | 1589 | |
| ... | ... | @@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1576 | 1601 | |
| 1577 | 1602 | const result = try codegen.generateSymbol( |
| 1578 | 1603 | &wasm.base, |
| 1579 | | decl.srcLoc(mod), |
| 1604 | src_loc, |
| 1580 | 1605 | tv, |
| 1581 | 1606 | &value_bytes, |
| 1582 | 1607 | .none, |
| ... | ... | @@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1588 | 1613 | break :code switch (result) { |
| 1589 | 1614 | .ok => value_bytes.items, |
| 1590 | 1615 | .fail => |em| { |
| 1591 | | decl.analysis = .codegen_failure; |
| 1592 | | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1593 | | return error.CodegenFail; |
| 1616 | return .{ .fail = em }; |
| 1594 | 1617 | }, |
| 1595 | 1618 | }; |
| 1596 | 1619 | }; |
| 1597 | 1620 | |
| 1598 | 1621 | const atom = wasm.getAtomPtr(atom_index); |
| 1599 | | atom.size = @as(u32, @intCast(code.len)); |
| 1622 | atom.size = @intCast(code.len); |
| 1600 | 1623 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1601 | | return atom.sym_index; |
| 1624 | return .{ .ok = atom_index }; |
| 1602 | 1625 | } |
| 1603 | 1626 | |
| 1604 | 1627 | /// Returns the symbol index from a symbol of which its flag is set global, |
| ... | ... | @@ -1679,27 +1702,61 @@ pub fn getDeclVAddr( |
| 1679 | 1702 | return target_symbol_index; |
| 1680 | 1703 | } |
| 1681 | 1704 | |
| 1682 | | pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { |
| 1683 | | // This is basically the same as lowerUnnamedConst. |
| 1684 | | // example: |
| 1685 | | // const ty = mod.intern_pool.typeOf(decl_val).toType(); |
| 1686 | | // const val = decl_val.toValue(); |
| 1687 | | // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`. |
| 1688 | | // It doesn't have an owner decl because it's just an unnamed constant that might |
| 1689 | | // be used by more than one function, however, its address is being used so we need |
| 1690 | | // to put it in some location. |
| 1691 | | // ... |
| 1692 | | _ = self; |
| 1693 | | _ = decl_val; |
| 1694 | | _ = src_loc; |
| 1695 | | _ = @panic("TODO: link/Wasm lowerAnonDecl"); |
| 1705 | pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { |
| 1706 | const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val); |
| 1707 | if (gop.found_existing) { |
| 1708 | return .ok; |
| 1709 | } |
| 1710 | |
| 1711 | const mod = wasm.base.options.module.?; |
| 1712 | const ty = mod.intern_pool.typeOf(decl_val).toType(); |
| 1713 | const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() }; |
| 1714 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)}); |
| 1715 | defer wasm.base.allocator.free(name); |
| 1716 | |
| 1717 | switch (try wasm.lowerConst(name, tv, src_loc)) { |
| 1718 | .ok => |atom_index| { |
| 1719 | gop.value_ptr.* = atom_index; |
| 1720 | return .ok; |
| 1721 | }, |
| 1722 | .fail => |em| return .{ .fail = em }, |
| 1723 | } |
| 1696 | 1724 | } |
| 1697 | 1725 | |
| 1698 | 1726 | pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 1699 | | _ = wasm; |
| 1700 | | _ = decl_val; |
| 1701 | | _ = reloc_info; |
| 1702 | | _ = @panic("TODO: link/Wasm getAnonDeclVAddr"); |
| 1727 | const atom_index = wasm.anon_decls.get(decl_val).?; |
| 1728 | const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?; |
| 1729 | |
| 1730 | const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 1731 | const parent_atom = wasm.getAtomPtr(parent_atom_index); |
| 1732 | const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32; |
| 1733 | const mod = wasm.base.options.module.?; |
| 1734 | const ty = mod.intern_pool.typeOf(decl_val).toType(); |
| 1735 | if (ty.zigTypeTag(mod) == .Fn) { |
| 1736 | assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 1737 | // We found a function pointer, so add it to our table, |
| 1738 | // as function pointers are not allowed to be stored inside the data section. |
| 1739 | // They are instead stored in a function table which are called by index. |
| 1740 | try wasm.addTableFunction(target_symbol_index); |
| 1741 | try parent_atom.relocs.append(wasm.base.allocator, .{ |
| 1742 | .index = target_symbol_index, |
| 1743 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| 1744 | .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, |
| 1745 | }); |
| 1746 | } else { |
| 1747 | try parent_atom.relocs.append(wasm.base.allocator, .{ |
| 1748 | .index = target_symbol_index, |
| 1749 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| 1750 | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, |
| 1751 | .addend = @as(i32, @intCast(reloc_info.addend)), |
| 1752 | }); |
| 1753 | } |
| 1754 | |
| 1755 | // we do not know the final address at this point, |
| 1756 | // as atom allocation will determine the address and relocations |
| 1757 | // will calculate and rewrite this. Therefore, we simply return the symbol index |
| 1758 | // that was targeted. |
| 1759 | return target_symbol_index; |
| 1703 | 1760 | } |
| 1704 | 1761 | |
| 1705 | 1762 | pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -3465,6 +3522,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3465 | 3522 | try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); |
| 3466 | 3523 | } |
| 3467 | 3524 | } |
| 3525 | // parse anonymous declarations |
| 3526 | for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { |
| 3527 | const ty = mod.intern_pool.typeOf(decl_val).toType(); |
| 3528 | if (ty.zigTypeTag(mod) == .Fn) { |
| 3529 | try wasm.parseAtom(atom_index, .function); |
| 3530 | } else { |
| 3531 | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3532 | } |
| 3533 | } |
| 3468 | 3534 | |
| 3469 | 3535 | // also parse any backend-generated functions |
| 3470 | 3536 | for (wasm.synthetic_functions.items) |atom_index| { |