authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-11 23:34:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
logc8b983c59a91441a6cfa134764c6413195e824ad
tree683cfcff0caa2a07dffd5544d8e5f3627e81a080
parent57dbc9e74a3f19802e4592f35061f1524c218a8f

link.Wasm: update for new writer API


1 files changed, 176 insertions(+), 149 deletions(-)

src/link/Wasm/Flush.zig+176-149
...@@ -19,6 +19,7 @@ const mem = std.mem;...@@ -19,6 +19,7 @@ const mem = std.mem;
19const leb = std.leb;19const leb = std.leb;
20const log = std.log.scoped(.link);20const log = std.log.scoped(.link);
21const assert = std.debug.assert;21const assert = std.debug.assert;
22const ArrayList = std.ArrayList;
2223
23/// Ordered list of data segments that will appear in the final binary.24/// Ordered list of data segments that will appear in the final binary.
24/// When sorted, to-be-merged segments will be made adjacent.25/// When sorted, to-be-merged segments will be made adjacent.
...@@ -27,9 +28,9 @@ data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty,...@@ -27,9 +28,9 @@ data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty,
27/// Each time a `data_segment` offset equals zero it indicates a new group, and28/// Each time a `data_segment` offset equals zero it indicates a new group, and
28/// the next element in this array will contain the total merged segment size.29/// the next element in this array will contain the total merged segment size.
29/// Value is the virtual memory address of the end of the segment.30/// Value is the virtual memory address of the end of the segment.
30data_segment_groups: std.ArrayListUnmanaged(DataSegmentGroup) = .empty,31data_segment_groups: ArrayList(DataSegmentGroup) = .empty,
3132
32binary_bytes: std.ArrayListUnmanaged(u8) = .empty,33binary_bytes: ArrayList(u8) = .empty,
33missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,34missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
34function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,35function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,
35global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,36global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,
...@@ -563,8 +564,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -563,8 +564,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
563 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);564 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);
564 assert(binary_bytes.items.len == 8);565 assert(binary_bytes.items.len == 8);
565566
566 const binary_writer = binary_bytes.writer(gpa);
567
568 // Type section.567 // Type section.
569 for (f.function_imports.values()) |id| {568 for (f.function_imports.values()) |id| {
570 try f.func_types.put(gpa, id.functionType(wasm), {});569 try f.func_types.put(gpa, id.functionType(wasm), {});
...@@ -576,16 +575,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -576,16 +575,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
576 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);575 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
577 for (f.func_types.keys()) |func_type_index| {576 for (f.func_types.keys()) |func_type_index| {
578 const func_type = func_type_index.ptr(wasm);577 const func_type = func_type_index.ptr(wasm);
579 try leb.writeUleb128(binary_writer, std.wasm.function_type);578 try appendLeb128(gpa, binary_bytes, std.wasm.function_type);
580 const params = func_type.params.slice(wasm);579 const params = func_type.params.slice(wasm);
581 try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len)));580 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(params.len)));
582 for (params) |param_ty| {581 for (params) |param_ty| {
583 try leb.writeUleb128(binary_writer, @intFromEnum(param_ty));582 try appendLeb128(gpa, binary_bytes, @intFromEnum(param_ty));
584 }583 }
585 const returns = func_type.returns.slice(wasm);584 const returns = func_type.returns.slice(wasm);
586 try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len)));585 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(returns.len)));
587 for (returns) |ret_ty| {586 for (returns) |ret_ty| {
588 try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty));587 try appendLeb128(gpa, binary_bytes, @intFromEnum(ret_ty));
589 }588 }
590 }589 }
591 replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len));590 replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len));
...@@ -605,31 +604,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -605,31 +604,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
605604
606 for (f.function_imports.values()) |id| {605 for (f.function_imports.values()) |id| {
607 const module_name = id.moduleName(wasm).slice(wasm).?;606 const module_name = id.moduleName(wasm).slice(wasm).?;
608 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));607 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
609 try binary_writer.writeAll(module_name);608 try binary_bytes.appendSlice(gpa, module_name);
610609
611 const name = id.importName(wasm).slice(wasm);610 const name = id.importName(wasm).slice(wasm);
612 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));611 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
613 try binary_writer.writeAll(name);612 try binary_bytes.appendSlice(gpa, name);
614613
615 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));614 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
616 const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f);615 const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f);
617 try leb.writeUleb128(binary_writer, @intFromEnum(type_index));616 try appendLeb128(gpa, binary_bytes, @intFromEnum(type_index));
618 }617 }
619 total_imports += f.function_imports.entries.len;618 total_imports += f.function_imports.entries.len;
620619
621 for (wasm.table_imports.values()) |id| {620 for (wasm.table_imports.values()) |id| {
622 const table_import = id.value(wasm);621 const table_import = id.value(wasm);
623 const module_name = table_import.module_name.slice(wasm);622 const module_name = table_import.module_name.slice(wasm);
624 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));623 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
625 try binary_writer.writeAll(module_name);624 try binary_bytes.appendSlice(gpa, module_name);
626625
627 const name = table_import.name.slice(wasm);626 const name = table_import.name.slice(wasm);
628 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));627 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
629 try binary_writer.writeAll(name);628 try binary_bytes.appendSlice(gpa, name);
630629
631 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table));630 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
632 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));631 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));
633 try emitLimits(gpa, binary_bytes, table_import.limits());632 try emitLimits(gpa, binary_bytes, table_import.limits());
634 }633 }
635 total_imports += wasm.table_imports.entries.len;634 total_imports += wasm.table_imports.entries.len;
...@@ -650,17 +649,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -650,17 +649,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
650649
651 for (f.global_imports.values()) |id| {650 for (f.global_imports.values()) |id| {
652 const module_name = id.moduleName(wasm).slice(wasm).?;651 const module_name = id.moduleName(wasm).slice(wasm).?;
653 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));652 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
654 try binary_writer.writeAll(module_name);653 try binary_bytes.appendSlice(gpa, module_name);
655654
656 const name = id.importName(wasm).slice(wasm);655 const name = id.importName(wasm).slice(wasm);
657 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));656 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
658 try binary_writer.writeAll(name);657 try binary_bytes.appendSlice(gpa, name);
659658
660 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global));659 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
661 const global_type = id.globalType(wasm);660 const global_type = id.globalType(wasm);
662 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));661 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
663 try binary_writer.writeByte(@intFromBool(global_type.mutable));662 try binary_bytes.append(gpa, @intFromBool(global_type.mutable));
664 }663 }
665 total_imports += f.global_imports.entries.len;664 total_imports += f.global_imports.entries.len;
666665
...@@ -677,7 +676,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -677,7 +676,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
677 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);676 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
678 for (wasm.functions.keys()) |function| {677 for (wasm.functions.keys()) |function| {
679 const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f);678 const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f);
680 try leb.writeUleb128(binary_writer, @intFromEnum(index));679 try appendLeb128(gpa, binary_bytes, @intFromEnum(index));
681 }680 }
682681
683 replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));682 replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));
...@@ -689,7 +688,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -689,7 +688,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
689 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);688 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
690689
691 for (wasm.tables.keys()) |table| {690 for (wasm.tables.keys()) |table| {
692 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm))));691 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm))));
693 try emitLimits(gpa, binary_bytes, table.limits(wasm));692 try emitLimits(gpa, binary_bytes, table.limits(wasm));
694 }693 }
695694
...@@ -743,39 +742,39 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -743,39 +742,39 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
743742
744 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {743 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {
745 const name = exp_name.slice(wasm);744 const name = exp_name.slice(wasm);
746 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));745 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
747 try binary_bytes.appendSlice(gpa, name);746 try binary_bytes.appendSlice(gpa, name);
748 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));747 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
749 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index);748 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index);
750 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));749 try appendLeb128(gpa, binary_bytes, @intFromEnum(func_index));
751 }750 }
752 exports_len += wasm.function_exports.entries.len;751 exports_len += wasm.function_exports.entries.len;
753752
754 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {753 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {
755 const name = "__indirect_function_table";754 const name = "__indirect_function_table";
756 const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);755 const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
757 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));756 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
758 try binary_bytes.appendSlice(gpa, name);757 try binary_bytes.appendSlice(gpa, name);
759 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));758 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
760 try leb.writeUleb128(binary_writer, index);759 try appendLeb128(gpa, binary_bytes, index);
761 exports_len += 1;760 exports_len += 1;
762 }761 }
763762
764 if (export_memory) {763 if (export_memory) {
765 const name = "memory";764 const name = "memory";
766 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));765 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
767 try binary_bytes.appendSlice(gpa, name);766 try binary_bytes.appendSlice(gpa, name);
768 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));767 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
769 try leb.writeUleb128(binary_writer, @as(u32, 0));768 try appendLeb128(gpa, binary_bytes, @as(u32, 0));
770 exports_len += 1;769 exports_len += 1;
771 }770 }
772771
773 for (wasm.global_exports.items) |exp| {772 for (wasm.global_exports.items) |exp| {
774 const name = exp.name.slice(wasm);773 const name = exp.name.slice(wasm);
775 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));774 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
776 try binary_bytes.appendSlice(gpa, name);775 try binary_bytes.appendSlice(gpa, name);
777 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));776 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
778 try leb.writeUleb128(binary_writer, @intFromEnum(exp.global_index));777 try appendLeb128(gpa, binary_bytes, @intFromEnum(exp.global_index));
779 }778 }
780 exports_len += wasm.global_exports.items.len;779 exports_len += wasm.global_exports.items.len;
781780
...@@ -802,18 +801,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -802,18 +801,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
802 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);801 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
803 // passive with implicit 0-index table or set table index manually802 // passive with implicit 0-index table or set table index manually
804 const flags: u32 = if (table_index == 0) 0x0 else 0x02;803 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
805 try leb.writeUleb128(binary_writer, flags);804 try appendLeb128(gpa, binary_bytes, flags);
806 if (flags == 0x02) {805 if (flags == 0x02) {
807 try leb.writeUleb128(binary_writer, table_index);806 try appendLeb128(gpa, binary_bytes, table_index);
808 }807 }
809 // We start at index 1, so unresolved function pointers are invalid808 // We start at index 1, so unresolved function pointers are invalid
810 try emitInit(binary_writer, .{ .i32_const = 1 });809 {
810 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, binary_bytes);
811 defer binary_bytes.* = aw.toArrayList();
812 try emitInit(&aw.writer, .{ .i32_const = 1 });
813 }
811 if (flags == 0x02) {814 if (flags == 0x02) {
812 try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref815 try appendLeb128(gpa, binary_bytes, @as(u8, 0)); // represents funcref
813 }816 }
814 try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.entries.len)));817 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(f.indirect_function_table.entries.len)));
815 for (f.indirect_function_table.keys()) |func_index| {818 for (f.indirect_function_table.keys()) |func_index| {
816 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));819 try appendLeb128(gpa, binary_bytes, @intFromEnum(func_index));
817 }820 }
818821
819 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);822 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);
...@@ -851,7 +854,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -851,7 +854,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
851 .object_function => |i| {854 .object_function => |i| {
852 const ptr = i.ptr(wasm);855 const ptr = i.ptr(wasm);
853 const code = ptr.code.slice(wasm);856 const code = ptr.code.slice(wasm);
854 try leb.writeUleb128(binary_writer, code.len);857 try appendLeb128(gpa, binary_bytes, code.len);
855 const code_start = binary_bytes.items.len;858 const code_start = binary_bytes.items.len;
856 try binary_bytes.appendSlice(gpa, code);859 try binary_bytes.appendSlice(gpa, code);
857 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);860 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
...@@ -946,12 +949,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -946,12 +949,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
946 const group_size = group_end_addr - group_start_addr;949 const group_size = group_end_addr - group_start_addr;
947 log.debug("emit data section group, {d} bytes", .{group_size});950 log.debug("emit data section group, {d} bytes", .{group_size});
948 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;951 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;
949 try leb.writeUleb128(binary_writer, @intFromEnum(flags));952 try appendLeb128(gpa, binary_bytes, @intFromEnum(flags));
950 // Passive segments are initialized at runtime.953 // Passive segments are initialized at runtime.
951 if (flags != .passive) {954 if (flags != .passive) {
952 try emitInit(binary_writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) });955 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, binary_bytes);
956 defer binary_bytes.* = aw.toArrayList();
957 try emitInit(&aw.writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) });
953 }958 }
954 try leb.writeUleb128(binary_writer, group_size);959 try appendLeb128(gpa, binary_bytes, group_size);
955 }960 }
956 if (segment_id.isEmpty(wasm)) {961 if (segment_id.isEmpty(wasm)) {
957 // It counted for virtual memory but it does not go into the binary.962 // It counted for virtual memory but it does not go into the binary.
...@@ -1077,7 +1082,7 @@ const VirtualAddrs = struct {...@@ -1077,7 +1082,7 @@ const VirtualAddrs = struct {
1077fn emitNameSection(1082fn emitNameSection(
1078 wasm: *Wasm,1083 wasm: *Wasm,
1079 data_segment_groups: []const DataSegmentGroup,1084 data_segment_groups: []const DataSegmentGroup,
1080 binary_bytes: *std.ArrayListUnmanaged(u8),1085 binary_bytes: *ArrayList(u8),
1081) !void {1086) !void {
1082 const f = &wasm.flush_buffer;1087 const f = &wasm.flush_buffer;
1083 const comp = wasm.base.comp;1088 const comp = wasm.base.comp;
...@@ -1087,7 +1092,7 @@ fn emitNameSection(...@@ -1087,7 +1092,7 @@ fn emitNameSection(
1087 defer writeCustomSectionHeader(binary_bytes, header_offset);1092 defer writeCustomSectionHeader(binary_bytes, header_offset);
10881093
1089 const name_name = "name";1094 const name_name = "name";
1090 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len));1095 try appendLeb128(gpa, binary_bytes, @as(u32, name_name.len));
1091 try binary_bytes.appendSlice(gpa, name_name);1096 try binary_bytes.appendSlice(gpa, name_name);
10921097
1093 {1098 {
...@@ -1095,18 +1100,18 @@ fn emitNameSection(...@@ -1095,18 +1100,18 @@ fn emitNameSection(
1095 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));1100 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));
10961101
1097 const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);1102 const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);
1098 try leb.writeUleb128(binary_bytes.writer(gpa), total_functions);1103 try appendLeb128(gpa, binary_bytes, total_functions);
10991104
1100 for (f.function_imports.keys(), 0..) |name_index, function_index| {1105 for (f.function_imports.keys(), 0..) |name_index, function_index| {
1101 const name = name_index.slice(wasm);1106 const name = name_index.slice(wasm);
1102 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));1107 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1103 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1108 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1104 try binary_bytes.appendSlice(gpa, name);1109 try binary_bytes.appendSlice(gpa, name);
1105 }1110 }
1106 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {1111 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {
1107 const name = resolution.name(wasm).?;1112 const name = resolution.name(wasm).?;
1108 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));1113 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1109 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1114 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1110 try binary_bytes.appendSlice(gpa, name);1115 try binary_bytes.appendSlice(gpa, name);
1111 }1116 }
1112 }1117 }
...@@ -1116,18 +1121,18 @@ fn emitNameSection(...@@ -1116,18 +1121,18 @@ fn emitNameSection(
1116 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));1121 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));
11171122
1118 const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);1123 const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);
1119 try leb.writeUleb128(binary_bytes.writer(gpa), total_globals);1124 try appendLeb128(gpa, binary_bytes, total_globals);
11201125
1121 for (f.global_imports.keys(), 0..) |name_index, global_index| {1126 for (f.global_imports.keys(), 0..) |name_index, global_index| {
1122 const name = name_index.slice(wasm);1127 const name = name_index.slice(wasm);
1123 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));1128 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1124 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1129 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1125 try binary_bytes.appendSlice(gpa, name);1130 try binary_bytes.appendSlice(gpa, name);
1126 }1131 }
1127 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {1132 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
1128 const name = resolution.name(wasm).?;1133 const name = resolution.name(wasm).?;
1129 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));1134 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1130 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1135 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1131 try binary_bytes.appendSlice(gpa, name);1136 try binary_bytes.appendSlice(gpa, name);
1132 }1137 }
1133 }1138 }
...@@ -1137,12 +1142,12 @@ fn emitNameSection(...@@ -1137,12 +1142,12 @@ fn emitNameSection(
1137 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));1142 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));
11381143
1139 const total_data_segments: u32 = @intCast(data_segment_groups.len);1144 const total_data_segments: u32 = @intCast(data_segment_groups.len);
1140 try leb.writeUleb128(binary_bytes.writer(gpa), total_data_segments);1145 try appendLeb128(gpa, binary_bytes, total_data_segments);
11411146
1142 for (data_segment_groups, 0..) |group, i| {1147 for (data_segment_groups, 0..) |group, i| {
1143 const name, _ = splitSegmentName(group.first_segment.name(wasm));1148 const name, _ = splitSegmentName(group.first_segment.name(wasm));
1144 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i)));1149 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(i)));
1145 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1150 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1146 try binary_bytes.appendSlice(gpa, name);1151 try binary_bytes.appendSlice(gpa, name);
1147 }1152 }
1148 }1153 }
...@@ -1150,7 +1155,7 @@ fn emitNameSection(...@@ -1150,7 +1155,7 @@ fn emitNameSection(
11501155
1151fn emitFeaturesSection(1156fn emitFeaturesSection(
1152 gpa: Allocator,1157 gpa: Allocator,
1153 binary_bytes: *std.ArrayListUnmanaged(u8),1158 binary_bytes: *ArrayList(u8),
1154 target: *const std.Target,1159 target: *const std.Target,
1155) Allocator.Error!void {1160) Allocator.Error!void {
1156 const feature_count = target.cpu.features.count();1161 const feature_count = target.cpu.features.count();
...@@ -1159,87 +1164,84 @@ fn emitFeaturesSection(...@@ -1159,87 +1164,84 @@ fn emitFeaturesSection(
1159 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1164 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1160 defer writeCustomSectionHeader(binary_bytes, header_offset);1165 defer writeCustomSectionHeader(binary_bytes, header_offset);
11611166
1162 const writer = binary_bytes.writer(gpa);
1163 const target_features = "target_features";1167 const target_features = "target_features";
1164 try leb.writeUleb128(writer, @as(u32, @intCast(target_features.len)));1168 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(target_features.len)));
1165 try writer.writeAll(target_features);1169 try binary_bytes.appendSlice(gpa, target_features);
11661170
1167 try leb.writeUleb128(writer, @as(u32, @intCast(feature_count)));1171 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(feature_count)));
11681172
1169 var safety_count = feature_count;1173 var safety_count = feature_count;
1170 for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| {1174 for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| {
1171 if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue;1175 if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue;
1172 safety_count -= 1;1176 safety_count -= 1;
11731177
1174 try leb.writeUleb128(writer, @as(u32, '+'));1178 try appendLeb128(gpa, binary_bytes, @as(u32, '+'));
1175 // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions.1179 // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions.
1176 const name = feature.llvm_name.?;1180 const name = feature.llvm_name.?;
1177 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));1181 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1178 try writer.writeAll(name);1182 try binary_bytes.appendSlice(gpa, name);
1179 }1183 }
1180 assert(safety_count == 0);1184 assert(safety_count == 0);
1181}1185}
11821186
1183fn emitBuildIdSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8), build_id: []const u8) !void {1187fn emitBuildIdSection(gpa: Allocator, binary_bytes: *ArrayList(u8), build_id: []const u8) !void {
1184 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1188 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1185 defer writeCustomSectionHeader(binary_bytes, header_offset);1189 defer writeCustomSectionHeader(binary_bytes, header_offset);
11861190
1187 const writer = binary_bytes.writer(gpa);
1188 const hdr_build_id = "build_id";1191 const hdr_build_id = "build_id";
1189 try leb.writeUleb128(writer, @as(u32, @intCast(hdr_build_id.len)));1192 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(hdr_build_id.len)));
1190 try writer.writeAll(hdr_build_id);1193 try binary_bytes.appendSlice(gpa, hdr_build_id);
11911194
1192 try leb.writeUleb128(writer, @as(u32, 1));1195 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
1193 try leb.writeUleb128(writer, @as(u32, @intCast(build_id.len)));1196 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_id.len)));
1194 try writer.writeAll(build_id);1197 try binary_bytes.appendSlice(gpa, build_id);
1195}1198}
11961199
1197fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)) !void {1200fn emitProducerSection(gpa: Allocator, binary_bytes: *ArrayList(u8)) !void {
1198 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1201 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1199 defer writeCustomSectionHeader(binary_bytes, header_offset);1202 defer writeCustomSectionHeader(binary_bytes, header_offset);
12001203
1201 const writer = binary_bytes.writer(gpa);
1202 const producers = "producers";1204 const producers = "producers";
1203 try leb.writeUleb128(writer, @as(u32, @intCast(producers.len)));1205 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(producers.len)));
1204 try writer.writeAll(producers);1206 try binary_bytes.appendSlice(gpa, producers);
12051207
1206 try leb.writeUleb128(writer, @as(u32, 2)); // 2 fields: Language + processed-by1208 try appendLeb128(gpa, binary_bytes, @as(u32, 2)); // 2 fields: Language + processed-by
12071209
1208 // language field1210 // language field
1209 {1211 {
1210 const language = "language";1212 const language = "language";
1211 try leb.writeUleb128(writer, @as(u32, @intCast(language.len)));1213 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(language.len)));
1212 try writer.writeAll(language);1214 try binary_bytes.appendSlice(gpa, language);
12131215
1214 // field_value_count (TODO: Parse object files for producer sections to detect their language)1216 // field_value_count (TODO: Parse object files for producer sections to detect their language)
1215 try leb.writeUleb128(writer, @as(u32, 1));1217 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
12161218
1217 // versioned name1219 // versioned name
1218 {1220 {
1219 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"1221 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1220 try writer.writeAll("Zig");1222 try binary_bytes.appendSlice(gpa, "Zig");
12211223
1222 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));1224 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1223 try writer.writeAll(build_options.version);1225 try binary_bytes.appendSlice(gpa, build_options.version);
1224 }1226 }
1225 }1227 }
12261228
1227 // processed-by field1229 // processed-by field
1228 {1230 {
1229 const processed_by = "processed-by";1231 const processed_by = "processed-by";
1230 try leb.writeUleb128(writer, @as(u32, @intCast(processed_by.len)));1232 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(processed_by.len)));
1231 try writer.writeAll(processed_by);1233 try binary_bytes.appendSlice(gpa, processed_by);
12321234
1233 // field_value_count (TODO: Parse object files for producer sections to detect other used tools)1235 // field_value_count (TODO: Parse object files for producer sections to detect other used tools)
1234 try leb.writeUleb128(writer, @as(u32, 1));1236 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
12351237
1236 // versioned name1238 // versioned name
1237 {1239 {
1238 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"1240 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1239 try writer.writeAll("Zig");1241 try binary_bytes.appendSlice(gpa, "Zig");
12401242
1241 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));1243 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1242 try writer.writeAll(build_options.version);1244 try binary_bytes.appendSlice(gpa, build_options.version);
1243 }1245 }
1244 }1246 }
1245}1247}
...@@ -1280,99 +1282,97 @@ fn wantSegmentMerge(...@@ -1280,99 +1282,97 @@ fn wantSegmentMerge(
1280const section_header_reserve_size = 1 + 5 + 5;1282const section_header_reserve_size = 1 + 5 + 5;
1281const section_header_size = 5 + 1;1283const section_header_size = 5 + 1;
12821284
1283fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1285fn reserveVecSectionHeader(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1284 try bytes.appendNTimes(gpa, 0, section_header_reserve_size);1286 try bytes.appendNTimes(gpa, 0, section_header_reserve_size);
1285 return @intCast(bytes.items.len - section_header_reserve_size);1287 return @intCast(bytes.items.len - section_header_reserve_size);
1286}1288}
12871289
1288fn replaceVecSectionHeader(1290fn replaceVecSectionHeader(
1289 bytes: *std.ArrayListUnmanaged(u8),1291 bytes: *ArrayList(u8),
1290 offset: u32,1292 offset: u32,
1291 section: std.wasm.Section,1293 section: std.wasm.Section,
1292 n_items: u32,1294 n_items: u32,
1293) void {1295) void {
1294 const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items));1296 const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items));
1295 var buf: [section_header_reserve_size]u8 = undefined;1297 var buf: [section_header_reserve_size]u8 = undefined;
1296 var fbw = std.io.fixedBufferStream(&buf);1298 var w: std.Io.Writer = .fixed(&buf);
1297 const w = fbw.writer();
1298 w.writeByte(@intFromEnum(section)) catch unreachable;1299 w.writeByte(@intFromEnum(section)) catch unreachable;
1299 leb.writeUleb128(w, size) catch unreachable;1300 w.writeUleb128(size) catch unreachable;
1300 leb.writeUleb128(w, n_items) catch unreachable;1301 w.writeUleb128(n_items) catch unreachable;
1301 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten());1302 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, w.buffered());
1302}1303}
13031304
1304fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1305fn reserveCustomSectionHeader(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1305 try bytes.appendNTimes(gpa, 0, section_header_size);1306 try bytes.appendNTimes(gpa, 0, section_header_size);
1306 return @intCast(bytes.items.len - section_header_size);1307 return @intCast(bytes.items.len - section_header_size);
1307}1308}
13081309
1309fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {1310fn writeCustomSectionHeader(bytes: *ArrayList(u8), offset: u32) void {
1310 return replaceHeader(bytes, offset, 0); // 0 = 'custom' section1311 return replaceHeader(bytes, offset, 0); // 0 = 'custom' section
1311}1312}
13121313
1313fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void {1314fn replaceHeader(bytes: *ArrayList(u8), offset: u32, tag: u8) void {
1314 const size: u32 = @intCast(bytes.items.len - offset - section_header_size);1315 const size: u32 = @intCast(bytes.items.len - offset - section_header_size);
1315 var buf: [section_header_size]u8 = undefined;1316 var buf: [section_header_size]u8 = undefined;
1316 var fbw = std.io.fixedBufferStream(&buf);1317 var w: std.Io.Writer = .fixed(&buf);
1317 const w = fbw.writer();
1318 w.writeByte(tag) catch unreachable;1318 w.writeByte(tag) catch unreachable;
1319 leb.writeUleb128(w, size) catch unreachable;1319 w.writeUleb128(size) catch unreachable;
1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten());1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, w.buffered());
1321}1321}
13221322
1323const max_size_encoding = 5;1323const max_size_encoding = 5;
13241324
1325fn reserveSize(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1325fn reserveSize(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1326 try bytes.appendNTimes(gpa, 0, max_size_encoding);1326 try bytes.appendNTimes(gpa, 0, max_size_encoding);
1327 return @intCast(bytes.items.len - max_size_encoding);1327 return @intCast(bytes.items.len - max_size_encoding);
1328}1328}
13291329
1330fn replaceSize(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {1330fn replaceSize(bytes: *ArrayList(u8), offset: u32) void {
1331 const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding);1331 const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding);
1332 var buf: [max_size_encoding]u8 = undefined;1332 var buf: [max_size_encoding]u8 = undefined;
1333 var fbw = std.io.fixedBufferStream(&buf);1333 var w: std.Io.Writer = .fixed(&buf);
1334 leb.writeUleb128(fbw.writer(), size) catch unreachable;1334 w.writeUleb128(size) catch unreachable;
1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, fbw.getWritten());1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, w.buffered());
1336}1336}
13371337
1338fn emitLimits(1338fn emitLimits(
1339 gpa: Allocator,1339 gpa: Allocator,
1340 binary_bytes: *std.ArrayListUnmanaged(u8),1340 binary_bytes: *ArrayList(u8),
1341 limits: std.wasm.Limits,1341 limits: std.wasm.Limits,
1342) Allocator.Error!void {1342) Allocator.Error!void {
1343 try binary_bytes.append(gpa, @bitCast(limits.flags));1343 try binary_bytes.append(gpa, @bitCast(limits.flags));
1344 try leb.writeUleb128(binary_bytes.writer(gpa), limits.min);1344 try appendLeb128(gpa, binary_bytes, limits.min);
1345 if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max);1345 if (limits.flags.has_max) try appendLeb128(gpa, binary_bytes, limits.max);
1346}1346}
13471347
1348fn emitMemoryImport(1348fn emitMemoryImport(
1349 wasm: *Wasm,1349 wasm: *Wasm,
1350 binary_bytes: *std.ArrayListUnmanaged(u8),1350 binary_bytes: *ArrayList(u8),
1351 name_index: String,1351 name_index: String,
1352 memory_import: *const Wasm.MemoryImport,1352 memory_import: *const Wasm.MemoryImport,
1353) Allocator.Error!void {1353) Allocator.Error!void {
1354 const gpa = wasm.base.comp.gpa;1354 const gpa = wasm.base.comp.gpa;
1355 const module_name = memory_import.module_name.slice(wasm);1355 const module_name = memory_import.module_name.slice(wasm);
1356 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len)));1356 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
1357 try binary_bytes.appendSlice(gpa, module_name);1357 try binary_bytes.appendSlice(gpa, module_name);
13581358
1359 const name = name_index.slice(wasm);1359 const name = name_index.slice(wasm);
1360 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1360 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1361 try binary_bytes.appendSlice(gpa, name);1361 try binary_bytes.appendSlice(gpa, name);
13621362
1363 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));1363 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
1364 try emitLimits(gpa, binary_bytes, memory_import.limits());1364 try emitLimits(gpa, binary_bytes, memory_import.limits());
1365}1365}
13661366
1367pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {1367fn emitInit(writer: *std.Io.Writer, init_expr: std.wasm.InitExpression) !void {
1368 switch (init_expr) {1368 switch (init_expr) {
1369 .i32_const => |val| {1369 .i32_const => |val| {
1370 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const));1370 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const));
1371 try leb.writeIleb128(writer, val);1371 try writer.writeSleb128(val);
1372 },1372 },
1373 .i64_const => |val| {1373 .i64_const => |val| {
1374 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const));1374 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const));
1375 try leb.writeIleb128(writer, val);1375 try writer.writeSleb128(val);
1376 },1376 },
1377 .f32_const => |val| {1377 .f32_const => |val| {
1378 try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const));1378 try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const));
...@@ -1384,13 +1384,13 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {...@@ -1384,13 +1384,13 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
1384 },1384 },
1385 .global_get => |val| {1385 .global_get => |val| {
1386 try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get));1386 try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get));
1387 try leb.writeUleb128(writer, val);1387 try writer.writeUleb128(val);
1388 },1388 },
1389 }1389 }
1390 try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));1390 try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));
1391}1391}
13921392
1393pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void {1393pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr) Allocator.Error!void {
1394 const gpa = wasm.base.comp.gpa;1394 const gpa = wasm.base.comp.gpa;
1395 const slice = expr.slice(wasm);1395 const slice = expr.slice(wasm);
1396 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode1396 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode
...@@ -1398,21 +1398,20 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), ex...@@ -1398,21 +1398,20 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), ex
13981398
1399fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {1399fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {
1400 const gpa = wasm.base.comp.gpa;1400 const gpa = wasm.base.comp.gpa;
1401 const writer = binary_bytes.writer(gpa);1401 try appendLeb128(gpa, binary_bytes, @intFromEnum(Wasm.SubsectionType.segment_info));
1402 try leb.writeUleb128(writer, @intFromEnum(Wasm.SubsectionType.segment_info));
1403 const segment_offset = binary_bytes.items.len;1402 const segment_offset = binary_bytes.items.len;
14041403
1405 try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count())));1404 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(wasm.segment_info.count())));
1406 for (wasm.segment_info.values()) |segment_info| {1405 for (wasm.segment_info.values()) |segment_info| {
1407 log.debug("Emit segment: {s} align({d}) flags({b})", .{1406 log.debug("Emit segment: {s} align({d}) flags({b})", .{
1408 segment_info.name,1407 segment_info.name,
1409 segment_info.alignment,1408 segment_info.alignment,
1410 segment_info.flags,1409 segment_info.flags,
1411 });1410 });
1412 try leb.writeUleb128(writer, @as(u32, @intCast(segment_info.name.len)));1411 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_info.name.len)));
1413 try writer.writeAll(segment_info.name);1412 try binary_bytes.appendSlice(gpa, segment_info.name);
1414 try leb.writeUleb128(writer, segment_info.alignment.toLog2Units());1413 try appendLeb128(gpa, binary_bytes, segment_info.alignment.toLog2Units());
1415 try leb.writeUleb128(writer, segment_info.flags);1414 try appendLeb128(gpa, binary_bytes, segment_info.flags);
1416 }1415 }
14171416
1418 var buf: [5]u8 = undefined;1417 var buf: [5]u8 = undefined;
...@@ -1429,7 +1428,7 @@ fn uleb128size(x: u32) u32 {...@@ -1429,7 +1428,7 @@ fn uleb128size(x: u32) u32 {
14291428
1430fn emitTagNameTable(1429fn emitTagNameTable(
1431 gpa: Allocator,1430 gpa: Allocator,
1432 code: *std.ArrayListUnmanaged(u8),1431 code: *ArrayList(u8),
1433 tag_name_offs: []const u32,1432 tag_name_offs: []const u32,
1434 tag_name_bytes: []const u8,1433 tag_name_bytes: []const u8,
1435 base: u32,1434 base: u32,
...@@ -1604,7 +1603,7 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void {...@@ -1604,7 +1603,7 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void {
1604 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));1603 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));
1605}1604}
16061605
1607fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void {1606fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *ArrayList(u8)) Allocator.Error!void {
1608 const gpa = wasm.base.comp.gpa;1607 const gpa = wasm.base.comp.gpa;
16091608
1610 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);1609 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);
...@@ -1631,7 +1630,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage...@@ -1631,7 +1630,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage
16311630
1632fn emitInitMemoryFunction(1631fn emitInitMemoryFunction(
1633 wasm: *const Wasm,1632 wasm: *const Wasm,
1634 binary_bytes: *std.ArrayListUnmanaged(u8),1633 binary_bytes: *ArrayList(u8),
1635 virtual_addrs: *const VirtualAddrs,1634 virtual_addrs: *const VirtualAddrs,
1636) Allocator.Error!void {1635) Allocator.Error!void {
1637 const comp = wasm.base.comp;1636 const comp = wasm.base.comp;
...@@ -1734,7 +1733,7 @@ fn emitInitMemoryFunction(...@@ -1734,7 +1733,7 @@ fn emitInitMemoryFunction(
1734 // notify any waiters for segment initialization completion1733 // notify any waiters for segment initialization completion
1735 appendReservedI32Const(binary_bytes, flag_address);1734 appendReservedI32Const(binary_bytes, flag_address);
1736 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));1735 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
1737 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i32, -1)) catch unreachable; // number of waiters1736 appendReservedLeb128(binary_bytes, @as(i32, -1)); // number of waiters
1738 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));1737 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
1739 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify));1738 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify));
1740 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment1739 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
...@@ -1750,7 +1749,7 @@ fn emitInitMemoryFunction(...@@ -1750,7 +1749,7 @@ fn emitInitMemoryFunction(
1750 appendReservedI32Const(binary_bytes, flag_address);1749 appendReservedI32Const(binary_bytes, flag_address);
1751 appendReservedI32Const(binary_bytes, 1); // expected flag value1750 appendReservedI32Const(binary_bytes, 1); // expected flag value
1752 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));1751 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
1753 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i64, -1)) catch unreachable; // timeout1752 appendReservedLeb128(binary_bytes, @as(i64, -1)); // timeout
1754 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));1753 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
1755 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32));1754 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32));
1756 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment1755 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
...@@ -1779,7 +1778,7 @@ fn emitInitMemoryFunction(...@@ -1779,7 +1778,7 @@ fn emitInitMemoryFunction(
1779 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1778 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1780}1779}
17811780
1782fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void {1781fn emitInitTlsFunction(wasm: *const Wasm, bytes: *ArrayList(u8)) Allocator.Error!void {
1783 const comp = wasm.base.comp;1782 const comp = wasm.base.comp;
1784 const gpa = comp.gpa;1783 const gpa = comp.gpa;
17851784
...@@ -1840,14 +1839,14 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al...@@ -1840,14 +1839,14 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al
1840 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1839 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1841}1840}
18421841
1843fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void {1842fn emitStartSection(gpa: Allocator, bytes: *ArrayList(u8), i: Wasm.OutputFunctionIndex) !void {
1844 const header_offset = try reserveVecSectionHeader(gpa, bytes);1843 const header_offset = try reserveVecSectionHeader(gpa, bytes);
1845 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));1844 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));
1846}1845}
18471846
1848fn emitTagNameFunction(1847fn emitTagNameFunction(
1849 wasm: *Wasm,1848 wasm: *Wasm,
1850 code: *std.ArrayListUnmanaged(u8),1849 code: *ArrayList(u8),
1851 table_base_addr: u32,1850 table_base_addr: u32,
1852 table_index: u32,1851 table_index: u32,
1853 enum_type_ip: InternPool.Index,1852 enum_type_ip: InternPool.Index,
...@@ -1959,22 +1958,34 @@ fn emitTagNameFunction(...@@ -1959,22 +1958,34 @@ fn emitTagNameFunction(
1959}1958}
19601959
1961/// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value.1960/// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value.
1962fn appendReservedI32Const(bytes: *std.ArrayListUnmanaged(u8), val: u32) void {1961fn appendReservedI32Const(bytes: *ArrayList(u8), val: u32) void {
1963 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));1962 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
1964 leb.writeIleb128(bytes.fixedWriter(), @as(i32, @bitCast(val))) catch unreachable;1963 var w: std.Io.Writer = .fromArrayList(bytes);
1964 defer bytes.* = w.toArrayList();
1965 return w.writeSleb128(val) catch |err| switch (err) {
1966 error.WriteFailed => unreachable,
1967 };
1965}1968}
19661969
1967/// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value.1970/// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value.
1968fn appendReservedI64Const(bytes: *std.ArrayListUnmanaged(u8), val: u64) void {1971fn appendReservedI64Const(bytes: *ArrayList(u8), val: u64) void {
1969 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));1972 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
1970 leb.writeIleb128(bytes.fixedWriter(), @as(i64, @bitCast(val))) catch unreachable;1973 var w: std.Io.Writer = .fromArrayList(bytes);
1974 defer bytes.* = w.toArrayList();
1975 return w.writeSleb128(val) catch |err| switch (err) {
1976 error.WriteFailed => unreachable,
1977 };
1971}1978}
19721979
1973fn appendReservedUleb32(bytes: *std.ArrayListUnmanaged(u8), val: u32) void {1980fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void {
1974 leb.writeUleb128(bytes.fixedWriter(), val) catch unreachable;1981 var w: std.Io.Writer = .fromArrayList(bytes);
1982 defer bytes.* = w.toArrayList();
1983 return w.writeUleb128(val) catch |err| switch (err) {
1984 error.WriteFailed => unreachable,
1985 };
1975}1986}
19761987
1977fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8, val: u32) Allocator.Error!void {1988fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u32) Allocator.Error!void {
1978 try bytes.ensureUnusedCapacity(gpa, 9);1989 try bytes.ensureUnusedCapacity(gpa, 9);
1979 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32));1990 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32));
1980 bytes.appendAssumeCapacity(mutable);1991 bytes.appendAssumeCapacity(mutable);
...@@ -1982,3 +1993,19 @@ fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8,...@@ -1982,3 +1993,19 @@ fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8,
1982 appendReservedUleb32(bytes, val);1993 appendReservedUleb32(bytes, val);
1983 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1994 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1984}1995}
1996
1997fn appendLeb128(gpa: Allocator, bytes: *ArrayList(u8), value: anytype) Allocator.Error!void {
1998 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, bytes);
1999 defer bytes.* = aw.toArrayList();
2000 return aw.writer.writeLeb128(value) catch |err| switch (err) {
2001 error.WriteFailed => return error.OutOfMemory,
2002 };
2003}
2004
2005fn appendReservedLeb128(bytes: *ArrayList(u8), value: anytype) void {
2006 var w: std.Io.Writer = .fromArrayList(bytes);
2007 defer bytes.* = w.toArrayList();
2008 return w.writeLeb128(value) catch |err| switch (err) {
2009 error.WriteFailed => unreachable,
2010 };
2011}