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;
1919const leb = std.leb;
2020const log = std.log.scoped(.link);
2121const assert = std.debug.assert;
22const ArrayList = std.ArrayList;
2223
2324/// Ordered list of data segments that will appear in the final binary.
2425/// When sorted, to-be-merged segments will be made adjacent.
......@@ -27,9 +28,9 @@ data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty,
2728/// Each time a `data_segment` offset equals zero it indicates a new group, and
2829/// the next element in this array will contain the total merged segment size.
2930/// 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,
3334missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
3435function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,
3536global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,
......@@ -563,8 +564,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
563564 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);
564565 assert(binary_bytes.items.len == 8);
565566
566 const binary_writer = binary_bytes.writer(gpa);
567
568567 // Type section.
569568 for (f.function_imports.values()) |id| {
570569 try f.func_types.put(gpa, id.functionType(wasm), {});
......@@ -576,16 +575,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
576575 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
577576 for (f.func_types.keys()) |func_type_index| {
578577 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);
580579 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)));
582581 for (params) |param_ty| {
583 try leb.writeUleb128(binary_writer, @intFromEnum(param_ty));
582 try appendLeb128(gpa, binary_bytes, @intFromEnum(param_ty));
584583 }
585584 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)));
587586 for (returns) |ret_ty| {
588 try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty));
587 try appendLeb128(gpa, binary_bytes, @intFromEnum(ret_ty));
589588 }
590589 }
591590 replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len));
......@@ -605,31 +604,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
605604
606605 for (f.function_imports.values()) |id| {
607606 const module_name = id.moduleName(wasm).slice(wasm).?;
608 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
609 try binary_writer.writeAll(module_name);
607 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
608 try binary_bytes.appendSlice(gpa, module_name);
610609
611610 const name = id.importName(wasm).slice(wasm);
612 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
613 try binary_writer.writeAll(name);
611 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
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));
616615 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));
618617 }
619618 total_imports += f.function_imports.entries.len;
620619
621620 for (wasm.table_imports.values()) |id| {
622621 const table_import = id.value(wasm);
623622 const module_name = table_import.module_name.slice(wasm);
624 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
625 try binary_writer.writeAll(module_name);
623 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
624 try binary_bytes.appendSlice(gpa, module_name);
626625
627626 const name = table_import.name.slice(wasm);
628 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
629 try binary_writer.writeAll(name);
627 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
628 try binary_bytes.appendSlice(gpa, name);
630629
631 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table));
632 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));
630 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
631 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));
633632 try emitLimits(gpa, binary_bytes, table_import.limits());
634633 }
635634 total_imports += wasm.table_imports.entries.len;
......@@ -650,17 +649,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
650649
651650 for (f.global_imports.values()) |id| {
652651 const module_name = id.moduleName(wasm).slice(wasm).?;
653 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
654 try binary_writer.writeAll(module_name);
652 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
653 try binary_bytes.appendSlice(gpa, module_name);
655654
656655 const name = id.importName(wasm).slice(wasm);
657 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
658 try binary_writer.writeAll(name);
656 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
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));
661660 const global_type = id.globalType(wasm);
662 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
663 try binary_writer.writeByte(@intFromBool(global_type.mutable));
661 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
662 try binary_bytes.append(gpa, @intFromBool(global_type.mutable));
664663 }
665664 total_imports += f.global_imports.entries.len;
666665
......@@ -677,7 +676,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
677676 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
678677 for (wasm.functions.keys()) |function| {
679678 const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f);
680 try leb.writeUleb128(binary_writer, @intFromEnum(index));
679 try appendLeb128(gpa, binary_bytes, @intFromEnum(index));
681680 }
682681
683682 replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));
......@@ -689,7 +688,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
689688 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
690689
691690 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))));
693692 try emitLimits(gpa, binary_bytes, table.limits(wasm));
694693 }
695694
......@@ -743,39 +742,39 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
743742
744743 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {
745744 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)));
747746 try binary_bytes.appendSlice(gpa, name);
748747 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
749748 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));
751750 }
752751 exports_len += wasm.function_exports.entries.len;
753752
754753 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {
755754 const name = "__indirect_function_table";
756755 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)));
758757 try binary_bytes.appendSlice(gpa, name);
759758 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
760 try leb.writeUleb128(binary_writer, index);
759 try appendLeb128(gpa, binary_bytes, index);
761760 exports_len += 1;
762761 }
763762
764763 if (export_memory) {
765764 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)));
767766 try binary_bytes.appendSlice(gpa, name);
768767 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));
770769 exports_len += 1;
771770 }
772771
773772 for (wasm.global_exports.items) |exp| {
774773 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)));
776775 try binary_bytes.appendSlice(gpa, name);
777776 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));
779778 }
780779 exports_len += wasm.global_exports.items.len;
781780
......@@ -802,18 +801,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
802801 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
803802 // passive with implicit 0-index table or set table index manually
804803 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
805 try leb.writeUleb128(binary_writer, flags);
804 try appendLeb128(gpa, binary_bytes, flags);
806805 if (flags == 0x02) {
807 try leb.writeUleb128(binary_writer, table_index);
806 try appendLeb128(gpa, binary_bytes, table_index);
808807 }
809808 // 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 }
811814 if (flags == 0x02) {
812 try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref
815 try appendLeb128(gpa, binary_bytes, @as(u8, 0)); // represents funcref
813816 }
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)));
815818 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));
817820 }
818821
819822 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);
......@@ -851,7 +854,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
851854 .object_function => |i| {
852855 const ptr = i.ptr(wasm);
853856 const code = ptr.code.slice(wasm);
854 try leb.writeUleb128(binary_writer, code.len);
857 try appendLeb128(gpa, binary_bytes, code.len);
855858 const code_start = binary_bytes.items.len;
856859 try binary_bytes.appendSlice(gpa, code);
857860 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 {
946949 const group_size = group_end_addr - group_start_addr;
947950 log.debug("emit data section group, {d} bytes", .{group_size});
948951 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));
950953 // Passive segments are initialized at runtime.
951954 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)) });
953958 }
954 try leb.writeUleb128(binary_writer, group_size);
959 try appendLeb128(gpa, binary_bytes, group_size);
955960 }
956961 if (segment_id.isEmpty(wasm)) {
957962 // It counted for virtual memory but it does not go into the binary.
......@@ -1077,7 +1082,7 @@ const VirtualAddrs = struct {
10771082fn emitNameSection(
10781083 wasm: *Wasm,
10791084 data_segment_groups: []const DataSegmentGroup,
1080 binary_bytes: *std.ArrayListUnmanaged(u8),
1085 binary_bytes: *ArrayList(u8),
10811086) !void {
10821087 const f = &wasm.flush_buffer;
10831088 const comp = wasm.base.comp;
......@@ -1087,7 +1092,7 @@ fn emitNameSection(
10871092 defer writeCustomSectionHeader(binary_bytes, header_offset);
10881093
10891094 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));
10911096 try binary_bytes.appendSlice(gpa, name_name);
10921097
10931098 {
......@@ -1095,18 +1100,18 @@ fn emitNameSection(
10951100 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));
10961101
10971102 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
11001105 for (f.function_imports.keys(), 0..) |name_index, function_index| {
11011106 const name = name_index.slice(wasm);
1102 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));
1103 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
1107 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1108 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11041109 try binary_bytes.appendSlice(gpa, name);
11051110 }
11061111 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {
11071112 const name = resolution.name(wasm).?;
1108 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));
1109 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
1113 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1114 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11101115 try binary_bytes.appendSlice(gpa, name);
11111116 }
11121117 }
......@@ -1116,18 +1121,18 @@ fn emitNameSection(
11161121 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));
11171122
11181123 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
11211126 for (f.global_imports.keys(), 0..) |name_index, global_index| {
11221127 const name = name_index.slice(wasm);
1123 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));
1124 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
1128 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1129 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11251130 try binary_bytes.appendSlice(gpa, name);
11261131 }
11271132 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
11281133 const name = resolution.name(wasm).?;
1129 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));
1130 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
1134 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1135 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11311136 try binary_bytes.appendSlice(gpa, name);
11321137 }
11331138 }
......@@ -1137,12 +1142,12 @@ fn emitNameSection(
11371142 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));
11381143
11391144 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
11421147 for (data_segment_groups, 0..) |group, i| {
11431148 const name, _ = splitSegmentName(group.first_segment.name(wasm));
1144 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i)));
1145 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
1149 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(i)));
1150 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11461151 try binary_bytes.appendSlice(gpa, name);
11471152 }
11481153 }
......@@ -1150,7 +1155,7 @@ fn emitNameSection(
11501155
11511156fn emitFeaturesSection(
11521157 gpa: Allocator,
1153 binary_bytes: *std.ArrayListUnmanaged(u8),
1158 binary_bytes: *ArrayList(u8),
11541159 target: *const std.Target,
11551160) Allocator.Error!void {
11561161 const feature_count = target.cpu.features.count();
......@@ -1159,87 +1164,84 @@ fn emitFeaturesSection(
11591164 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
11601165 defer writeCustomSectionHeader(binary_bytes, header_offset);
11611166
1162 const writer = binary_bytes.writer(gpa);
11631167 const target_features = "target_features";
1164 try leb.writeUleb128(writer, @as(u32, @intCast(target_features.len)));
1165 try writer.writeAll(target_features);
1168 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(target_features.len)));
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
11691173 var safety_count = feature_count;
11701174 for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| {
11711175 if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue;
11721176 safety_count -= 1;
11731177
1174 try leb.writeUleb128(writer, @as(u32, '+'));
1178 try appendLeb128(gpa, binary_bytes, @as(u32, '+'));
11751179 // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions.
11761180 const name = feature.llvm_name.?;
1177 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));
1178 try writer.writeAll(name);
1181 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1182 try binary_bytes.appendSlice(gpa, name);
11791183 }
11801184 assert(safety_count == 0);
11811185}
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 {
11841188 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
11851189 defer writeCustomSectionHeader(binary_bytes, header_offset);
11861190
1187 const writer = binary_bytes.writer(gpa);
11881191 const hdr_build_id = "build_id";
1189 try leb.writeUleb128(writer, @as(u32, @intCast(hdr_build_id.len)));
1190 try writer.writeAll(hdr_build_id);
1192 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(hdr_build_id.len)));
1193 try binary_bytes.appendSlice(gpa, hdr_build_id);
11911194
1192 try leb.writeUleb128(writer, @as(u32, 1));
1193 try leb.writeUleb128(writer, @as(u32, @intCast(build_id.len)));
1194 try writer.writeAll(build_id);
1195 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
1196 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_id.len)));
1197 try binary_bytes.appendSlice(gpa, build_id);
11951198}
11961199
1197fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)) !void {
1200fn emitProducerSection(gpa: Allocator, binary_bytes: *ArrayList(u8)) !void {
11981201 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
11991202 defer writeCustomSectionHeader(binary_bytes, header_offset);
12001203
1201 const writer = binary_bytes.writer(gpa);
12021204 const producers = "producers";
1203 try leb.writeUleb128(writer, @as(u32, @intCast(producers.len)));
1204 try writer.writeAll(producers);
1205 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(producers.len)));
1206 try binary_bytes.appendSlice(gpa, producers);
12051207
1206 try leb.writeUleb128(writer, @as(u32, 2)); // 2 fields: Language + processed-by
1208 try appendLeb128(gpa, binary_bytes, @as(u32, 2)); // 2 fields: Language + processed-by
12071209
12081210 // language field
12091211 {
12101212 const language = "language";
1211 try leb.writeUleb128(writer, @as(u32, @intCast(language.len)));
1212 try writer.writeAll(language);
1213 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(language.len)));
1214 try binary_bytes.appendSlice(gpa, language);
12131215
12141216 // 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
12171219 // versioned name
12181220 {
1219 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"
1220 try writer.writeAll("Zig");
1221 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1222 try binary_bytes.appendSlice(gpa, "Zig");
12211223
1222 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));
1223 try writer.writeAll(build_options.version);
1224 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1225 try binary_bytes.appendSlice(gpa, build_options.version);
12241226 }
12251227 }
12261228
12271229 // processed-by field
12281230 {
12291231 const processed_by = "processed-by";
1230 try leb.writeUleb128(writer, @as(u32, @intCast(processed_by.len)));
1231 try writer.writeAll(processed_by);
1232 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(processed_by.len)));
1233 try binary_bytes.appendSlice(gpa, processed_by);
12321234
12331235 // 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
12361238 // versioned name
12371239 {
1238 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"
1239 try writer.writeAll("Zig");
1240 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1241 try binary_bytes.appendSlice(gpa, "Zig");
12401242
1241 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));
1242 try writer.writeAll(build_options.version);
1243 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1244 try binary_bytes.appendSlice(gpa, build_options.version);
12431245 }
12441246 }
12451247}
......@@ -1280,99 +1282,97 @@ fn wantSegmentMerge(
12801282const section_header_reserve_size = 1 + 5 + 5;
12811283const 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 {
12841286 try bytes.appendNTimes(gpa, 0, section_header_reserve_size);
12851287 return @intCast(bytes.items.len - section_header_reserve_size);
12861288}
12871289
12881290fn replaceVecSectionHeader(
1289 bytes: *std.ArrayListUnmanaged(u8),
1291 bytes: *ArrayList(u8),
12901292 offset: u32,
12911293 section: std.wasm.Section,
12921294 n_items: u32,
12931295) void {
12941296 const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items));
12951297 var buf: [section_header_reserve_size]u8 = undefined;
1296 var fbw = std.io.fixedBufferStream(&buf);
1297 const w = fbw.writer();
1298 var w: std.Io.Writer = .fixed(&buf);
12981299 w.writeByte(@intFromEnum(section)) catch unreachable;
1299 leb.writeUleb128(w, size) catch unreachable;
1300 leb.writeUleb128(w, n_items) catch unreachable;
1301 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten());
1300 w.writeUleb128(size) catch unreachable;
1301 w.writeUleb128(n_items) catch unreachable;
1302 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, w.buffered());
13021303}
13031304
1304fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
1305fn reserveCustomSectionHeader(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
13051306 try bytes.appendNTimes(gpa, 0, section_header_size);
13061307 return @intCast(bytes.items.len - section_header_size);
13071308}
13081309
1309fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {
1310fn writeCustomSectionHeader(bytes: *ArrayList(u8), offset: u32) void {
13101311 return replaceHeader(bytes, offset, 0); // 0 = 'custom' section
13111312}
13121313
1313fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void {
1314fn replaceHeader(bytes: *ArrayList(u8), offset: u32, tag: u8) void {
13141315 const size: u32 = @intCast(bytes.items.len - offset - section_header_size);
13151316 var buf: [section_header_size]u8 = undefined;
1316 var fbw = std.io.fixedBufferStream(&buf);
1317 const w = fbw.writer();
1317 var w: std.Io.Writer = .fixed(&buf);
13181318 w.writeByte(tag) catch unreachable;
1319 leb.writeUleb128(w, size) catch unreachable;
1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten());
1319 w.writeUleb128(size) catch unreachable;
1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, w.buffered());
13211321}
13221322
13231323const 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 {
13261326 try bytes.appendNTimes(gpa, 0, max_size_encoding);
13271327 return @intCast(bytes.items.len - max_size_encoding);
13281328}
13291329
1330fn replaceSize(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {
1330fn replaceSize(bytes: *ArrayList(u8), offset: u32) void {
13311331 const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding);
13321332 var buf: [max_size_encoding]u8 = undefined;
1333 var fbw = std.io.fixedBufferStream(&buf);
1334 leb.writeUleb128(fbw.writer(), size) catch unreachable;
1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, fbw.getWritten());
1333 var w: std.Io.Writer = .fixed(&buf);
1334 w.writeUleb128(size) catch unreachable;
1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, w.buffered());
13361336}
13371337
13381338fn emitLimits(
13391339 gpa: Allocator,
1340 binary_bytes: *std.ArrayListUnmanaged(u8),
1340 binary_bytes: *ArrayList(u8),
13411341 limits: std.wasm.Limits,
13421342) Allocator.Error!void {
13431343 try binary_bytes.append(gpa, @bitCast(limits.flags));
1344 try leb.writeUleb128(binary_bytes.writer(gpa), limits.min);
1345 if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max);
1344 try appendLeb128(gpa, binary_bytes, limits.min);
1345 if (limits.flags.has_max) try appendLeb128(gpa, binary_bytes, limits.max);
13461346}
13471347
13481348fn emitMemoryImport(
13491349 wasm: *Wasm,
1350 binary_bytes: *std.ArrayListUnmanaged(u8),
1350 binary_bytes: *ArrayList(u8),
13511351 name_index: String,
13521352 memory_import: *const Wasm.MemoryImport,
13531353) Allocator.Error!void {
13541354 const gpa = wasm.base.comp.gpa;
13551355 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)));
13571357 try binary_bytes.appendSlice(gpa, module_name);
13581358
13591359 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)));
13611361 try binary_bytes.appendSlice(gpa, name);
13621362
13631363 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
13641364 try emitLimits(gpa, binary_bytes, memory_import.limits());
13651365}
13661366
1367pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
1367fn emitInit(writer: *std.Io.Writer, init_expr: std.wasm.InitExpression) !void {
13681368 switch (init_expr) {
13691369 .i32_const => |val| {
13701370 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const));
1371 try leb.writeIleb128(writer, val);
1371 try writer.writeSleb128(val);
13721372 },
13731373 .i64_const => |val| {
13741374 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const));
1375 try leb.writeIleb128(writer, val);
1375 try writer.writeSleb128(val);
13761376 },
13771377 .f32_const => |val| {
13781378 try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const));
......@@ -1384,13 +1384,13 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
13841384 },
13851385 .global_get => |val| {
13861386 try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get));
1387 try leb.writeUleb128(writer, val);
1387 try writer.writeUleb128(val);
13881388 },
13891389 }
13901390 try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));
13911391}
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 {
13941394 const gpa = wasm.base.comp.gpa;
13951395 const slice = expr.slice(wasm);
13961396 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
13981398
13991399fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {
14001400 const gpa = wasm.base.comp.gpa;
1401 const writer = binary_bytes.writer(gpa);
1402 try leb.writeUleb128(writer, @intFromEnum(Wasm.SubsectionType.segment_info));
1401 try appendLeb128(gpa, binary_bytes, @intFromEnum(Wasm.SubsectionType.segment_info));
14031402 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())));
14061405 for (wasm.segment_info.values()) |segment_info| {
14071406 log.debug("Emit segment: {s} align({d}) flags({b})", .{
14081407 segment_info.name,
14091408 segment_info.alignment,
14101409 segment_info.flags,
14111410 });
1412 try leb.writeUleb128(writer, @as(u32, @intCast(segment_info.name.len)));
1413 try writer.writeAll(segment_info.name);
1414 try leb.writeUleb128(writer, segment_info.alignment.toLog2Units());
1415 try leb.writeUleb128(writer, segment_info.flags);
1411 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_info.name.len)));
1412 try binary_bytes.appendSlice(gpa, segment_info.name);
1413 try appendLeb128(gpa, binary_bytes, segment_info.alignment.toLog2Units());
1414 try appendLeb128(gpa, binary_bytes, segment_info.flags);
14161415 }
14171416
14181417 var buf: [5]u8 = undefined;
......@@ -1429,7 +1428,7 @@ fn uleb128size(x: u32) u32 {
14291428
14301429fn emitTagNameTable(
14311430 gpa: Allocator,
1432 code: *std.ArrayListUnmanaged(u8),
1431 code: *ArrayList(u8),
14331432 tag_name_offs: []const u32,
14341433 tag_name_bytes: []const u8,
14351434 base: u32,
......@@ -1604,7 +1603,7 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void {
16041603 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));
16051604}
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 {
16081607 const gpa = wasm.base.comp.gpa;
16091608
16101609 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);
......@@ -1631,7 +1630,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage
16311630
16321631fn emitInitMemoryFunction(
16331632 wasm: *const Wasm,
1634 binary_bytes: *std.ArrayListUnmanaged(u8),
1633 binary_bytes: *ArrayList(u8),
16351634 virtual_addrs: *const VirtualAddrs,
16361635) Allocator.Error!void {
16371636 const comp = wasm.base.comp;
......@@ -1734,7 +1733,7 @@ fn emitInitMemoryFunction(
17341733 // notify any waiters for segment initialization completion
17351734 appendReservedI32Const(binary_bytes, flag_address);
17361735 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
1737 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i32, -1)) catch unreachable; // number of waiters
1736 appendReservedLeb128(binary_bytes, @as(i32, -1)); // number of waiters
17381737 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
17391738 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify));
17401739 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
......@@ -1750,7 +1749,7 @@ fn emitInitMemoryFunction(
17501749 appendReservedI32Const(binary_bytes, flag_address);
17511750 appendReservedI32Const(binary_bytes, 1); // expected flag value
17521751 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
1753 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i64, -1)) catch unreachable; // timeout
1752 appendReservedLeb128(binary_bytes, @as(i64, -1)); // timeout
17541753 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
17551754 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32));
17561755 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
......@@ -1779,7 +1778,7 @@ fn emitInitMemoryFunction(
17791778 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
17801779}
17811780
1782fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void {
1781fn emitInitTlsFunction(wasm: *const Wasm, bytes: *ArrayList(u8)) Allocator.Error!void {
17831782 const comp = wasm.base.comp;
17841783 const gpa = comp.gpa;
17851784
......@@ -1840,14 +1839,14 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al
18401839 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
18411840}
18421841
1843fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void {
1842fn emitStartSection(gpa: Allocator, bytes: *ArrayList(u8), i: Wasm.OutputFunctionIndex) !void {
18441843 const header_offset = try reserveVecSectionHeader(gpa, bytes);
18451844 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));
18461845}
18471846
18481847fn emitTagNameFunction(
18491848 wasm: *Wasm,
1850 code: *std.ArrayListUnmanaged(u8),
1849 code: *ArrayList(u8),
18511850 table_base_addr: u32,
18521851 table_index: u32,
18531852 enum_type_ip: InternPool.Index,
......@@ -1959,22 +1958,34 @@ fn emitTagNameFunction(
19591958}
19601959
19611960/// 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 {
19631962 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 };
19651968}
19661969
19671970/// 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 {
19691972 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 };
19711978}
19721979
1973fn appendReservedUleb32(bytes: *std.ArrayListUnmanaged(u8), val: u32) void {
1974 leb.writeUleb128(bytes.fixedWriter(), val) catch unreachable;
1980fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void {
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 };
19751986}
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 {
19781989 try bytes.ensureUnusedCapacity(gpa, 9);
19791990 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32));
19801991 bytes.appendAssumeCapacity(mutable);
......@@ -1982,3 +1993,19 @@ fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8,
19821993 appendReservedUleb32(bytes, val);
19831994 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
19841995}
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}