| ... | @@ -52,7 +52,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { | ... | @@ -52,7 +52,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { |
| 52 | f.* = undefined; | 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 | const comp = wasm.base.comp; | 56 | const comp = wasm.base.comp; |
| 57 | const shared_memory = comp.config.shared_memory; | 57 | const shared_memory = comp.config.shared_memory; |
| 58 | const diags = &comp.link_diags; | 58 | const diags = &comp.link_diags; |
| ... | @@ -685,7 +685,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { | ... | @@ -685,7 +685,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { |
| 685 | // try wasm.emitDataRelocations(binary_bytes, data_index, symbol_table); | 685 | // try wasm.emitDataRelocations(binary_bytes, data_index, symbol_table); |
| 686 | //} | 686 | //} |
| 687 | } else if (comp.config.debug_format != .strip) { | 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 | if (comp.config.debug_format != .strip) { | 691 | if (comp.config.debug_format != .strip) { |
| ... | @@ -732,117 +732,77 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { | ... | @@ -732,117 +732,77 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { |
| 732 | try file.setEndPos(binary_bytes.items.len); | 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 { | 735 | fn emitNameSection( |
| 736 | if (true) { | 736 | wasm: *Wasm, |
| 737 | std.log.warn("TODO emit name section", .{}); | 737 | data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Index, u32), |
| 738 | return; | 738 | binary_bytes: *std.ArrayListUnmanaged(u8), |
| 739 | } | 739 | ) !void { |
| 740 | const comp = wasm.base.comp; | 740 | const comp = wasm.base.comp; |
| 741 | const gpa = comp.gpa; | 741 | const gpa = comp.gpa; |
| 742 | const import_memory = comp.config.import_memory; | | |
| 743 | | 742 | |
| 744 | // Deduplicate symbols that point to the same function. | 743 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 745 | var funcs: std.AutoArrayHashMapUnmanaged(u32, String) = .empty; | 744 | defer writeCustomSectionHeader(binary_bytes, header_offset); |
| 746 | try funcs.ensureUnusedCapacityPrecise(arena, wasm.functions.count() + wasm.function_imports.items.len); | | |
| 747 | | 745 | |
| 748 | const NamedIndex = struct { | 746 | const name_name = "name"; |
| 749 | index: u32, | 747 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len)); |
| 750 | name: String, | 748 | try binary_bytes.appendSlice(gpa, name_name); |
| 751 | }; | | |
| 752 | | 749 | |
| 753 | var globals: std.MultiArrayList(NamedIndex) = .empty; | 750 | { |
| 754 | try globals.ensureTotalCapacityPrecise(arena, wasm.globals.items.len + wasm.global_imports.items.len); | 751 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 755 | | 752 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function)); |
| 756 | var segments: std.MultiArrayList(NamedIndex) = .empty; | 753 | |
| 757 | try segments.ensureTotalCapacityPrecise(arena, wasm.data_segments.count()); | 754 | const total_functions: u32 = @intCast(wasm.function_imports.entries.len + wasm.functions.entries.len); |
| 758 | | 755 | try leb.writeUleb128(binary_bytes.writer(gpa), total_functions); |
| 759 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 756 | |
| 760 | const symbol = wasm.finalSymbolByLoc(sym_loc).*; | 757 | for (wasm.function_imports.keys(), 0..) |name_index, function_index| { |
| 761 | if (!symbol.flags.alive) continue; | 758 | const name = name_index.slice(wasm); |
| 762 | const name = wasm.finalSymbolByLoc(sym_loc).name; | 759 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); |
| 763 | switch (symbol.tag) { | 760 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 764 | .function => { | 761 | try binary_bytes.appendSlice(gpa, name); |
| 765 | const index = if (symbol.flags.undefined) | 762 | } |
| 766 | @intFromEnum(symbol.pointee.function_import) | 763 | for (wasm.functions.keys(), wasm.function_imports.entries.len..) |resolution, function_index| { |
| 767 | else | 764 | const name = resolution.name(wasm).?; |
| 768 | wasm.function_imports.items.len + @intFromEnum(symbol.pointee.function); | 765 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); |
| 769 | const gop = funcs.getOrPutAssumeCapacity(index); | 766 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 770 | if (gop.found_existing) { | 767 | try binary_bytes.appendSlice(gpa, name); |
| 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 => {}, | | |
| 786 | } | 768 | } |
| 787 | } | 769 | } |
| 788 | | 770 | |
| 789 | for (wasm.data_segments.keys(), 0..) |key, index| { | 771 | { |
| 790 | // bss section is not emitted when this condition holds true, so we also | 772 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); |
| 791 | // do not output a name for it. | 773 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global)); |
| 792 | if (!import_memory and mem.eql(u8, key, ".bss")) continue; | | |
| 793 | segments.appendAssumeCapacity(.{ .index = @intCast(index), .name = key }); | | |
| 794 | } | | |
| 795 | | 774 | |
| 796 | const Sort = struct { | 775 | const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); |
| 797 | indexes: []const u32, | 776 | try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); |
| 798 | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { | 777 | |
| 799 | return ctx.indexes[lhs] < ctx.indexes[rhs]; | 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 | }; | 784 | for (wasm.globals.keys(), wasm.global_imports.entries.len..) |resolution, global_index| { |
| 802 | funcs.entries.sortUnstable(@as(Sort, .{ .indexes = funcs.keys() })); | 785 | const name = resolution.name(wasm).?; |
| 803 | globals.sortUnstable(@as(Sort, .{ .indexes = globals.items(.index) })); | 786 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); |
| 804 | // Data segments are already ordered. | 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); | 792 | { |
| 807 | defer writeCustomSectionHeader(binary_bytes, header_offset); | 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); | 796 | const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); |
| 810 | try leb.writeUleb128(writer, @as(u32, @intCast("name".len))); | 797 | try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); |
| 811 | try writer.writeAll("name"); | | |
| 812 | | 798 | |
| 813 | try emitNameSubsection(wasm, binary_bytes, .function, funcs.keys(), funcs.values()); | 799 | for (data_segments.keys(), 0..) |ds, i| { |
| 814 | try emitNameSubsection(wasm, binary_bytes, .global, globals.items(.index), globals.items(.name)); | 800 | const name = ds.ptr(wasm).name.slice(wasm).?; |
| 815 | try emitNameSubsection(wasm, binary_bytes, .data_segment, segments.items(.index), segments.items(.name)); | 801 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i))); |
| 816 | } | 802 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); |
| 817 | | 803 | try binary_bytes.appendSlice(gpa, name); |
| 818 | fn emitNameSubsection( | 804 | } |
| 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); | | |
| 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 | fn emitFeaturesSection( | 808 | fn emitFeaturesSection( |
| ... | @@ -1094,11 +1054,15 @@ fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8) | ... | @@ -1094,11 +1054,15 @@ fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8) |
| 1094 | } | 1054 | } |
| 1095 | | 1055 | |
| 1096 | fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { | 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 | const size: u32 = @intCast(bytes.items.len - offset - section_header_size); | 1061 | const size: u32 = @intCast(bytes.items.len - offset - section_header_size); |
| 1098 | var buf: [section_header_size]u8 = undefined; | 1062 | var buf: [section_header_size]u8 = undefined; |
| 1099 | var fbw = std.io.fixedBufferStream(&buf); | 1063 | var fbw = std.io.fixedBufferStream(&buf); |
| 1100 | const w = fbw.writer(); | 1064 | const w = fbw.writer(); |
| 1101 | w.writeByte(0) catch unreachable; // 0 = 'custom' section | 1065 | w.writeByte(tag) catch unreachable; |
| 1102 | leb.writeUleb128(w, size) catch unreachable; | 1066 | leb.writeUleb128(w, size) catch unreachable; |
| 1103 | bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); | 1067 | bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); |
| 1104 | } | 1068 | } |