| ... | ... | @@ -52,7 +52,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { |
| 52 | 52 | f.* = undefined; |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | | pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { |
| 55 | pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 56 | 56 | const comp = wasm.base.comp; |
| 57 | 57 | const shared_memory = comp.config.shared_memory; |
| 58 | 58 | const diags = &comp.link_diags; |
| ... | ... | @@ -685,7 +685,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { |
| 685 | 685 | // try wasm.emitDataRelocations(binary_bytes, data_index, symbol_table); |
| 686 | 686 | //} |
| 687 | 687 | } else if (comp.config.debug_format != .strip) { |
| 688 | | try emitNameSection(wasm, binary_bytes, arena); |
| 688 | try emitNameSection(wasm, &f.data_segments, binary_bytes); |
| 689 | 689 | } |
| 690 | 690 | |
| 691 | 691 | if (comp.config.debug_format != .strip) { |
| ... | ... | @@ -732,117 +732,77 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { |
| 732 | 732 | try file.setEndPos(binary_bytes.items.len); |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | | fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), arena: Allocator) !void { |
| 736 | | if (true) { |
| 737 | | std.log.warn("TODO emit name section", .{}); |
| 738 | | return; |
| 739 | | } |
| 735 | fn emitNameSection( |
| 736 | wasm: *Wasm, |
| 737 | data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Index, u32), |
| 738 | binary_bytes: *std.ArrayListUnmanaged(u8), |
| 739 | ) !void { |
| 740 | 740 | const comp = wasm.base.comp; |
| 741 | 741 | const gpa = comp.gpa; |
| 742 | | const import_memory = comp.config.import_memory; |
| 743 | 742 | |
| 744 | | // Deduplicate symbols that point to the same function. |
| 745 | | var funcs: std.AutoArrayHashMapUnmanaged(u32, String) = .empty; |
| 746 | | try funcs.ensureUnusedCapacityPrecise(arena, wasm.functions.count() + wasm.function_imports.items.len); |
| 743 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 744 | defer writeCustomSectionHeader(binary_bytes, header_offset); |
| 747 | 745 | |
| 748 | | const NamedIndex = struct { |
| 749 | | index: u32, |
| 750 | | name: String, |
| 751 | | }; |
| 746 | const name_name = "name"; |
| 747 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len)); |
| 748 | try binary_bytes.appendSlice(gpa, name_name); |
| 752 | 749 | |
| 753 | | var globals: std.MultiArrayList(NamedIndex) = .empty; |
| 754 | | try globals.ensureTotalCapacityPrecise(arena, wasm.globals.items.len + wasm.global_imports.items.len); |
| 755 | | |
| 756 | | var segments: std.MultiArrayList(NamedIndex) = .empty; |
| 757 | | try segments.ensureTotalCapacityPrecise(arena, wasm.data_segments.count()); |
| 758 | | |
| 759 | | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 760 | | const symbol = wasm.finalSymbolByLoc(sym_loc).*; |
| 761 | | if (!symbol.flags.alive) continue; |
| 762 | | const name = wasm.finalSymbolByLoc(sym_loc).name; |
| 763 | | switch (symbol.tag) { |
| 764 | | .function => { |
| 765 | | const index = if (symbol.flags.undefined) |
| 766 | | @intFromEnum(symbol.pointee.function_import) |
| 767 | | else |
| 768 | | wasm.function_imports.items.len + @intFromEnum(symbol.pointee.function); |
| 769 | | const gop = funcs.getOrPutAssumeCapacity(index); |
| 770 | | if (gop.found_existing) { |
| 771 | | assert(gop.value_ptr.* == name); |
| 772 | | } else { |
| 773 | | gop.value_ptr.* = name; |
| 774 | | } |
| 775 | | }, |
| 776 | | .global => { |
| 777 | | globals.appendAssumeCapacity(.{ |
| 778 | | .index = if (symbol.flags.undefined) |
| 779 | | @intFromEnum(symbol.pointee.global_import) |
| 780 | | else |
| 781 | | @intFromEnum(symbol.pointee.global), |
| 782 | | .name = name, |
| 783 | | }); |
| 784 | | }, |
| 785 | | else => {}, |
| 750 | { |
| 751 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 752 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function)); |
| 753 | |
| 754 | const total_functions: u32 = @intCast(wasm.function_imports.entries.len + wasm.functions.entries.len); |
| 755 | try leb.writeUleb128(binary_bytes.writer(gpa), total_functions); |
| 756 | |
| 757 | for (wasm.function_imports.keys(), 0..) |name_index, function_index| { |
| 758 | const name = name_index.slice(wasm); |
| 759 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); |
| 760 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 761 | try binary_bytes.appendSlice(gpa, name); |
| 762 | } |
| 763 | for (wasm.functions.keys(), wasm.function_imports.entries.len..) |resolution, function_index| { |
| 764 | const name = resolution.name(wasm).?; |
| 765 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); |
| 766 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 767 | try binary_bytes.appendSlice(gpa, name); |
| 786 | 768 | } |
| 787 | 769 | } |
| 788 | 770 | |
| 789 | | for (wasm.data_segments.keys(), 0..) |key, index| { |
| 790 | | // bss section is not emitted when this condition holds true, so we also |
| 791 | | // do not output a name for it. |
| 792 | | if (!import_memory and mem.eql(u8, key, ".bss")) continue; |
| 793 | | segments.appendAssumeCapacity(.{ .index = @intCast(index), .name = key }); |
| 794 | | } |
| 771 | { |
| 772 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 773 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global)); |
| 795 | 774 | |
| 796 | | const Sort = struct { |
| 797 | | indexes: []const u32, |
| 798 | | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { |
| 799 | | return ctx.indexes[lhs] < ctx.indexes[rhs]; |
| 775 | const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); |
| 776 | try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); |
| 777 | |
| 778 | for (wasm.global_imports.keys(), 0..) |name_index, global_index| { |
| 779 | const name = name_index.slice(wasm); |
| 780 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); |
| 781 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 782 | try binary_bytes.appendSlice(gpa, name); |
| 800 | 783 | } |
| 801 | | }; |
| 802 | | funcs.entries.sortUnstable(@as(Sort, .{ .indexes = funcs.keys() })); |
| 803 | | globals.sortUnstable(@as(Sort, .{ .indexes = globals.items(.index) })); |
| 804 | | // Data segments are already ordered. |
| 784 | for (wasm.globals.keys(), wasm.global_imports.entries.len..) |resolution, global_index| { |
| 785 | const name = resolution.name(wasm).?; |
| 786 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); |
| 787 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 788 | try binary_bytes.appendSlice(gpa, name); |
| 789 | } |
| 790 | } |
| 805 | 791 | |
| 806 | | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 807 | | defer writeCustomSectionHeader(binary_bytes, header_offset); |
| 792 | { |
| 793 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 794 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); |
| 808 | 795 | |
| 809 | | const writer = binary_bytes.writer(gpa); |
| 810 | | try leb.writeUleb128(writer, @as(u32, @intCast("name".len))); |
| 811 | | try writer.writeAll("name"); |
| 796 | const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); |
| 797 | try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); |
| 812 | 798 | |
| 813 | | try emitNameSubsection(wasm, binary_bytes, .function, funcs.keys(), funcs.values()); |
| 814 | | try emitNameSubsection(wasm, binary_bytes, .global, globals.items(.index), globals.items(.name)); |
| 815 | | try emitNameSubsection(wasm, binary_bytes, .data_segment, segments.items(.index), segments.items(.name)); |
| 816 | | } |
| 817 | | |
| 818 | | fn emitNameSubsection( |
| 819 | | wasm: *const Wasm, |
| 820 | | binary_bytes: *std.ArrayListUnmanaged(u8), |
| 821 | | section_id: std.wasm.NameSubsection, |
| 822 | | indexes: []const u32, |
| 823 | | names: []const String, |
| 824 | | ) !void { |
| 825 | | assert(indexes.len == names.len); |
| 826 | | const gpa = wasm.base.comp.gpa; |
| 827 | | // We must emit subsection size, so first write to a temporary list |
| 828 | | var section_list: std.ArrayListUnmanaged(u8) = .empty; |
| 829 | | defer section_list.deinit(gpa); |
| 830 | | const sub_writer = section_list.writer(gpa); |
| 831 | | |
| 832 | | try leb.writeUleb128(sub_writer, @as(u32, @intCast(names.len))); |
| 833 | | for (indexes, names) |index, name_index| { |
| 834 | | const name = name_index.slice(wasm); |
| 835 | | log.debug("emit symbol '{s}' type({s})", .{ name, @tagName(section_id) }); |
| 836 | | try leb.writeUleb128(sub_writer, index); |
| 837 | | try leb.writeUleb128(sub_writer, @as(u32, @intCast(name.len))); |
| 838 | | try sub_writer.writeAll(name); |
| 799 | for (data_segments.keys(), 0..) |ds, i| { |
| 800 | const name = ds.ptr(wasm).name.slice(wasm).?; |
| 801 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i))); |
| 802 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 803 | try binary_bytes.appendSlice(gpa, name); |
| 804 | } |
| 839 | 805 | } |
| 840 | | |
| 841 | | // From now, write to the actual writer |
| 842 | | const writer = binary_bytes.writer(gpa); |
| 843 | | try leb.writeUleb128(writer, @intFromEnum(section_id)); |
| 844 | | try leb.writeUleb128(writer, @as(u32, @intCast(section_list.items.len))); |
| 845 | | try binary_bytes.appendSlice(gpa, section_list.items); |
| 846 | 806 | } |
| 847 | 807 | |
| 848 | 808 | fn emitFeaturesSection( |
| ... | ... | @@ -1094,11 +1054,15 @@ fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8) |
| 1094 | 1054 | } |
| 1095 | 1055 | |
| 1096 | 1056 | fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { |
| 1057 | return replaceHeader(bytes, offset, 0); // 0 = 'custom' section |
| 1058 | } |
| 1059 | |
| 1060 | fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void { |
| 1097 | 1061 | const size: u32 = @intCast(bytes.items.len - offset - section_header_size); |
| 1098 | 1062 | var buf: [section_header_size]u8 = undefined; |
| 1099 | 1063 | var fbw = std.io.fixedBufferStream(&buf); |
| 1100 | 1064 | const w = fbw.writer(); |
| 1101 | | w.writeByte(0) catch unreachable; // 0 = 'custom' section |
| 1065 | w.writeByte(tag) catch unreachable; |
| 1102 | 1066 | leb.writeUleb128(w, size) catch unreachable; |
| 1103 | 1067 | bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); |
| 1104 | 1068 | } |