authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-09 14:37:32-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
log031c84c8cb29e9b22cd5a131c147d3910c5ba345
treebde0cd18d6f125711a320f2cdca220d2d206d62f
parentb3ecdb21eedeb8be099cf1ef43ceff68592593ed

wasm: fix many compilation errors

Still, the branch is not yet passing semantic analysis.

5 files changed, 546 insertions(+), 263 deletions(-)

src/arch/wasm/Emit.zig+13-13
...@@ -89,7 +89,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -89,7 +89,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
89 if (is_obj) {89 if (is_obj) {
90 try wasm.out_relocs.append(gpa, .{90 try wasm.out_relocs.append(gpa, .{
91 .offset = @intCast(code.items.len),91 .offset = @intCast(code.items.len),
92 .index = try wasm.errorNameTableSymbolIndex(),92 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },
93 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,93 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
94 .addend = 0,94 .addend = 0,
95 });95 });
...@@ -143,7 +143,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -143,7 +143,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
143 if (is_obj) {143 if (is_obj) {
144 try wasm.out_relocs.append(gpa, .{144 try wasm.out_relocs.append(gpa, .{
145 .offset = @intCast(code.items.len),145 .offset = @intCast(code.items.len),
146 .index = try wasm.navSymbolIndex(datas[inst].nav_index),146 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },
147 .tag = .FUNCTION_INDEX_LEB,147 .tag = .FUNCTION_INDEX_LEB,
148 .addend = 0,148 .addend = 0,
149 });149 });
...@@ -164,7 +164,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -164,7 +164,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
164 if (is_obj) {164 if (is_obj) {
165 try wasm.out_relocs.append(gpa, .{165 try wasm.out_relocs.append(gpa, .{
166 .offset = @intCast(code.items.len),166 .offset = @intCast(code.items.len),
167 .index = func_ty_index,167 .pointee = .{ .type_index = func_ty_index },
168 .tag = .TYPE_INDEX_LEB,168 .tag = .TYPE_INDEX_LEB,
169 .addend = 0,169 .addend = 0,
170 });170 });
...@@ -184,7 +184,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -184,7 +184,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
184 if (is_obj) {184 if (is_obj) {
185 try wasm.out_relocs.append(gpa, .{185 try wasm.out_relocs.append(gpa, .{
186 .offset = @intCast(code.items.len),186 .offset = @intCast(code.items.len),
187 .index = try wasm.tagNameSymbolIndex(datas[inst].ip_index),187 .pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) },
188 .tag = .FUNCTION_INDEX_LEB,188 .tag = .FUNCTION_INDEX_LEB,
189 .addend = 0,189 .addend = 0,
190 });190 });
...@@ -209,7 +209,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -209,7 +209,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
209 if (is_obj) {209 if (is_obj) {
210 try wasm.out_relocs.append(gpa, .{210 try wasm.out_relocs.append(gpa, .{
211 .offset = @intCast(code.items.len),211 .offset = @intCast(code.items.len),
212 .index = try wasm.symbolNameIndex(symbol_name),212 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },
213 .tag = .FUNCTION_INDEX_LEB,213 .tag = .FUNCTION_INDEX_LEB,
214 .addend = 0,214 .addend = 0,
215 });215 });
...@@ -229,7 +229,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -229,7 +229,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
229 if (is_obj) {229 if (is_obj) {
230 try wasm.out_relocs.append(gpa, .{230 try wasm.out_relocs.append(gpa, .{
231 .offset = @intCast(code.items.len),231 .offset = @intCast(code.items.len),
232 .index = try wasm.stackPointerSymbolIndex(),232 .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },
233 .tag = .GLOBAL_INDEX_LEB,233 .tag = .GLOBAL_INDEX_LEB,
234 .addend = 0,234 .addend = 0,
235 });235 });
...@@ -249,7 +249,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -249,7 +249,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
249 if (is_obj) {249 if (is_obj) {
250 try wasm.out_relocs.append(gpa, .{250 try wasm.out_relocs.append(gpa, .{
251 .offset = @intCast(code.items.len),251 .offset = @intCast(code.items.len),
252 .index = try wasm.functionSymbolIndex(datas[inst].ip_index),252 .pointee = .{ .symbol_index = try wasm.functionSymbolIndex(datas[inst].ip_index) },
253 .tag = .TABLE_INDEX_SLEB,253 .tag = .TABLE_INDEX_SLEB,
254 .addend = 0,254 .addend = 0,
255 });255 });
...@@ -691,7 +691,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir...@@ -691,7 +691,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
691 if (is_obj) {691 if (is_obj) {
692 try wasm.out_relocs.append(gpa, .{692 try wasm.out_relocs.append(gpa, .{
693 .offset = @intCast(code.items.len),693 .offset = @intCast(code.items.len),
694 .index = try wasm.uavSymbolIndex(data.ip_index),694 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.ip_index) },
695 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,695 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
696 .addend = data.offset,696 .addend = data.offset,
697 });697 });
...@@ -700,7 +700,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir...@@ -700,7 +700,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
700 }700 }
701701
702 // When linking into the final binary, no relocation mechanism is necessary.702 // When linking into the final binary, no relocation mechanism is necessary.
703 const addr: i64 = try wasm.uavAddr(data.ip_index);703 const addr = try wasm.uavAddr(data.ip_index);
704 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;704 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
705}705}
706706
...@@ -720,13 +720,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir...@@ -720,13 +720,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
720 if (is_obj) {720 if (is_obj) {
721 try wasm.out_relocs.append(gpa, .{721 try wasm.out_relocs.append(gpa, .{
722 .offset = @intCast(code.items.len),722 .offset = @intCast(code.items.len),
723 .index = try wasm.navSymbolIndex(data.nav_index),723 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
724 .tag = .TABLE_INDEX_SLEB,724 .tag = .TABLE_INDEX_SLEB,
725 .addend = data.offset,725 .addend = data.offset,
726 });726 });
727 code.appendNTimesAssumeCapacity(0, 5);727 code.appendNTimesAssumeCapacity(0, 5);
728 } else {728 } else {
729 const addr: i64 = try wasm.navAddr(data.nav_index);729 const addr = try wasm.navAddr(data.nav_index);
730 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;730 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
731 }731 }
732 } else {732 } else {
...@@ -735,13 +735,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir...@@ -735,13 +735,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
735 if (is_obj) {735 if (is_obj) {
736 try wasm.out_relocs.append(gpa, .{736 try wasm.out_relocs.append(gpa, .{
737 .offset = @intCast(code.items.len),737 .offset = @intCast(code.items.len),
738 .index = try wasm.navSymbolIndex(data.nav_index),738 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
739 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,739 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
740 .addend = data.offset,740 .addend = data.offset,
741 });741 });
742 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);742 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
743 } else {743 } else {
744 const addr: i64 = try wasm.navAddr(data.nav_index);744 const addr = try wasm.navAddr(data.nav_index);
745 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;745 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
746 }746 }
747 }747 }
src/codegen.zig+47-27
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const build_options = @import("build_options");2const build_options = @import("build_options");
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const leb128 = std.leb;
6const link = @import("link.zig");5const link = @import("link.zig");
7const log = std.log.scoped(.codegen);6const log = std.log.scoped(.codegen);
8const mem = std.mem;7const mem = std.mem;
...@@ -643,15 +642,19 @@ fn lowerUavRef(...@@ -643,15 +642,19 @@ fn lowerUavRef(
643 const zcu = pt.zcu;642 const zcu = pt.zcu;
644 const gpa = zcu.gpa;643 const gpa = zcu.gpa;
645 const ip = &zcu.intern_pool;644 const ip = &zcu.intern_pool;
646 const target = lf.comp.root_mod.resolved_target.result;645 const comp = lf.comp;
647646 const target = &comp.root_mod.resolved_target.result;
648 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);647 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
648 const is_obj = comp.config.output_mode == .Obj;
649 const uav_val = uav.val;649 const uav_val = uav.val;
650 const uav_ty = Type.fromInterned(ip.typeOf(uav_val));650 const uav_ty = Type.fromInterned(ip.typeOf(uav_val));
651 log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)});
652 const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";651 const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";
652
653 log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)});
654 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
655
653 if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) {656 if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) {
654 try code.appendNTimes(gpa, 0xaa, ptr_width_bytes);657 code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes);
655 return;658 return;
656 }659 }
657660
...@@ -663,13 +666,20 @@ fn lowerUavRef(...@@ -663,13 +666,20 @@ fn lowerUavRef(
663 dev.check(link.File.Tag.wasm.devFeature());666 dev.check(link.File.Tag.wasm.devFeature());
664 const wasm = lf.cast(.wasm).?;667 const wasm = lf.cast(.wasm).?;
665 assert(reloc_parent == .none);668 assert(reloc_parent == .none);
666 try wasm.relocations.append(gpa, .{669 if (is_obj) {
667 .tag = .uav_index,670 try wasm.out_relocs.append(gpa, .{
668 .addend = @intCast(offset),671 .offset = @intCast(code.items.len),
669 .offset = @intCast(code.items.len),672 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) },
670 .pointee = .{ .uav_index = uav.val },673 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
671 });674 .addend = @intCast(offset),
672 try code.appendNTimes(gpa, 0, ptr_width_bytes);675 });
676 } else {
677 try wasm.uav_fixups.append(gpa, .{
678 .ip_index = uav.val,
679 .offset = @intCast(code.items.len),
680 });
681 }
682 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);
673 return;683 return;
674 },684 },
675 else => {},685 else => {},
...@@ -688,9 +698,9 @@ fn lowerUavRef(...@@ -688,9 +698,9 @@ fn lowerUavRef(
688 });698 });
689 const endian = target.cpu.arch.endian();699 const endian = target.cpu.arch.endian();
690 switch (ptr_width_bytes) {700 switch (ptr_width_bytes) {
691 2 => mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(vaddr), endian),701 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),
692 4 => mem.writeInt(u32, try code.addManyAsArray(gpa, 4), @intCast(vaddr), endian),702 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),
693 8 => mem.writeInt(u64, try code.addManyAsArray(gpa, 8), vaddr, endian),703 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),
694 else => unreachable,704 else => unreachable,
695 }705 }
696}706}
...@@ -709,12 +719,15 @@ fn lowerNavRef(...@@ -709,12 +719,15 @@ fn lowerNavRef(
709 const gpa = zcu.gpa;719 const gpa = zcu.gpa;
710 const ip = &zcu.intern_pool;720 const ip = &zcu.intern_pool;
711 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;721 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
712
713 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);722 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
723 const is_obj = lf.comp.config.output_mode == .Obj;
714 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));724 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
715 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";725 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
726
727 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
728
716 if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {729 if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {
717 try code.appendNTimes(gpa, 0xaa, ptr_width_bytes);730 code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes);
718 return;731 return;
719 }732 }
720733
...@@ -726,13 +739,20 @@ fn lowerNavRef(...@@ -726,13 +739,20 @@ fn lowerNavRef(
726 dev.check(link.File.Tag.wasm.devFeature());739 dev.check(link.File.Tag.wasm.devFeature());
727 const wasm = lf.cast(.wasm).?;740 const wasm = lf.cast(.wasm).?;
728 assert(reloc_parent == .none);741 assert(reloc_parent == .none);
729 try wasm.relocations.append(gpa, .{742 if (is_obj) {
730 .tag = .nav_index,743 try wasm.out_relocs.append(gpa, .{
731 .addend = @intCast(offset),744 .offset = @intCast(code.items.len),
732 .offset = @intCast(code.items.len),745 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
733 .pointee = .{ .nav_index = nav_index },746 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
734 });747 .addend = @intCast(offset),
735 try code.appendNTimes(gpa, 0, ptr_width_bytes);748 });
749 } else {
750 try wasm.nav_fixups.append(gpa, .{
751 .nav_index = nav_index,
752 .offset = @intCast(code.items.len),
753 });
754 }
755 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);
736 return;756 return;
737 },757 },
738 else => {},758 else => {},
...@@ -745,9 +765,9 @@ fn lowerNavRef(...@@ -745,9 +765,9 @@ fn lowerNavRef(
745 }) catch @panic("TODO rework getNavVAddr");765 }) catch @panic("TODO rework getNavVAddr");
746 const endian = target.cpu.arch.endian();766 const endian = target.cpu.arch.endian();
747 switch (ptr_width_bytes) {767 switch (ptr_width_bytes) {
748 2 => mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(vaddr), endian),768 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),
749 4 => mem.writeInt(u32, try code.addManyAsArray(gpa, 4), @intCast(vaddr), endian),769 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),
750 8 => mem.writeInt(u64, try code.addManyAsArray(gpa, 8), vaddr, endian),770 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),
751 else => unreachable,771 else => unreachable,
752 }772 }
753}773}
src/link/Wasm.zig+324-95
...@@ -100,7 +100,7 @@ object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .em...@@ -100,7 +100,7 @@ object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .em
100object_globals: std.ArrayListUnmanaged(Global) = .empty,100object_globals: std.ArrayListUnmanaged(Global) = .empty,
101101
102/// All table imports for all objects.102/// All table imports for all objects.
103object_table_imports: std.ArrayListUnmanaged(TableImport) = .empty,103object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty,
104/// All parsed table sections for all objects.104/// All parsed table sections for all objects.
105object_tables: std.ArrayListUnmanaged(Table) = .empty,105object_tables: std.ArrayListUnmanaged(Table) = .empty,
106106
...@@ -109,12 +109,28 @@ object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,...@@ -109,12 +109,28 @@ object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,
109/// All parsed memory sections for all objects.109/// All parsed memory sections for all objects.
110object_memories: std.ArrayListUnmanaged(std.wasm.Memory) = .empty,110object_memories: std.ArrayListUnmanaged(std.wasm.Memory) = .empty,
111111
112/// All relocations from all objects concatenated. `relocs_start` marks the end
113/// point of object relocations and start point of Zcu relocations.
114object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,
115
112/// List of initialization functions. These must be called in order of priority116/// List of initialization functions. These must be called in order of priority
113/// by the (synthetic) __wasm_call_ctors function.117/// by the (synthetic) __wasm_call_ctors function.
114object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,118object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
115/// All relocations from all objects concatenated. `relocs_start` marks the end119
116/// point of object relocations and start point of Zcu relocations.120/// Relocations to be emitted into an object file. Remains empty when not
117relocations: std.MultiArrayList(Relocation) = .empty,121/// emitting an object file.
122out_relocs: std.MultiArrayList(OutReloc) = .empty,
123/// List of locations within `string_bytes` that must be patched with the virtual
124/// memory address of a Uav during `flush`.
125/// When emitting an object file, `out_relocs` is used instead.
126uav_fixups: std.ArrayListUnmanaged(UavFixup) = .empty,
127/// List of locations within `string_bytes` that must be patched with the virtual
128/// memory address of a Nav during `flush`.
129/// When emitting an object file, `out_relocs` is used instead.
130nav_fixups: std.ArrayListUnmanaged(NavFixup) = .empty,
131/// Symbols to be emitted into an object file. Remains empty when not emitting
132/// an object file.
133symbol_table: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
118134
119/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.135/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
120object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty,136object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty,
...@@ -125,7 +141,7 @@ object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, Custom...@@ -125,7 +141,7 @@ object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, Custom
125object_comdats: std.ArrayListUnmanaged(Comdat) = .empty,141object_comdats: std.ArrayListUnmanaged(Comdat) = .empty,
126/// A table that maps the relocations to be performed where the key represents142/// A table that maps the relocations to be performed where the key represents
127/// the section (across all objects) that the slice of relocations applies to.143/// the section (across all objects) that the slice of relocations applies to.
128object_relocations_table: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, Relocation.Slice) = .empty,144object_relocations_table: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, ObjectRelocation.Slice) = .empty,
129/// Incremented across all objects in order to enable calculation of `ObjectSectionIndex` values.145/// Incremented across all objects in order to enable calculation of `ObjectSectionIndex` values.
130object_total_sections: u32 = 0,146object_total_sections: u32 = 0,
131/// All comdat symbols from all objects concatenated.147/// All comdat symbols from all objects concatenated.
...@@ -151,7 +167,10 @@ dump_argv_list: std.ArrayListUnmanaged([]const u8),...@@ -151,7 +167,10 @@ dump_argv_list: std.ArrayListUnmanaged([]const u8),
151167
152preloaded_strings: PreloadedStrings,168preloaded_strings: PreloadedStrings,
153169
154navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Nav) = .empty,170/// This field is used when emitting an object; `navs_exe` used otherwise.
171navs_obj: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, NavObj) = .empty,
172/// This field is unused when emitting an object; `navs_exe` used otherwise.
173navs_exe: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, NavExe) = .empty,
155zcu_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuFunc) = .empty,174zcu_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuFunc) = .empty,
156nav_exports: std.AutoArrayHashMapUnmanaged(NavExport, Zcu.Export.Index) = .empty,175nav_exports: std.AutoArrayHashMapUnmanaged(NavExport, Zcu.Export.Index) = .empty,
157uav_exports: std.AutoArrayHashMapUnmanaged(UavExport, Zcu.Export.Index) = .empty,176uav_exports: std.AutoArrayHashMapUnmanaged(UavExport, Zcu.Export.Index) = .empty,
...@@ -201,9 +220,14 @@ global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,...@@ -201,9 +220,14 @@ global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,
201/// Ordered list of non-import tables that will appear in the final binary.220/// Ordered list of non-import tables that will appear in the final binary.
202/// Empty until prelink.221/// Empty until prelink.
203tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,222tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,
204table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .empty,223table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty,
205224
206any_exports_updated: bool = true,225any_exports_updated: bool = true,
226/// Set to true if any `GLOBAL_INDEX` relocation is encountered with
227/// `SymbolFlags.tls` set to true. This is for objects only; final
228/// value must be this OR'd with the same logic for zig functions
229/// (set to true if any threadlocal global is used).
230any_tls_relocs: bool = false,
207231
208/// All MIR instructions for all Zcu functions.232/// All MIR instructions for all Zcu functions.
209mir_instructions: std.MultiArrayList(Mir.Inst) = .{},233mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -212,6 +236,18 @@ mir_extra: std.ArrayListUnmanaged(u32) = .empty,...@@ -212,6 +236,18 @@ mir_extra: std.ArrayListUnmanaged(u32) = .empty,
212/// All local types for all Zcu functions.236/// All local types for all Zcu functions.
213all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,237all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,
214238
239pub const UavFixup = extern struct {
240 ip_index: InternPool.Index,
241 /// Index into `string_bytes`.
242 offset: u32,
243};
244
245pub const NavFixup = extern struct {
246 nav_index: InternPool.Nav.Index,
247 /// Index into `string_bytes`.
248 offset: u32,
249};
250
215/// Index into `objects`.251/// Index into `objects`.
216pub const ObjectIndex = enum(u32) {252pub const ObjectIndex = enum(u32) {
217 _,253 _,
...@@ -300,6 +336,10 @@ pub const SourceLocation = enum(u32) {...@@ -300,6 +336,10 @@ pub const SourceLocation = enum(u32) {
300 };336 };
301 }337 }
302338
339 pub fn fromObject(object_index: ObjectIndex, wasm: *const Wasm) SourceLocation {
340 return pack(.{ .object_index = object_index }, wasm);
341 }
342
303 pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {343 pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {
304 const diags = &wasm.base.comp.link_diags;344 const diags = &wasm.base.comp.link_diags;
305 switch (sl.unpack(wasm)) {345 switch (sl.unpack(wasm)) {
...@@ -345,7 +385,7 @@ pub const SymbolFlags = packed struct(u32) {...@@ -345,7 +385,7 @@ pub const SymbolFlags = packed struct(u32) {
345385
346 // Above here matches the tooling conventions ABI.386 // Above here matches the tooling conventions ABI.
347387
348 padding1: u8 = 0,388 padding1: u5 = 0,
349 /// Zig-specific. Dead things are allowed to be garbage collected.389 /// Zig-specific. Dead things are allowed to be garbage collected.
350 alive: bool = false,390 alive: bool = false,
351 /// Zig-specific. Segments only. Signals that the segment contains only391 /// Zig-specific. Segments only. Signals that the segment contains only
...@@ -360,6 +400,12 @@ pub const SymbolFlags = packed struct(u32) {...@@ -360,6 +400,12 @@ pub const SymbolFlags = packed struct(u32) {
360 alignment: Alignment = .none,400 alignment: Alignment = .none,
361 /// Zig-specific. Globals only.401 /// Zig-specific. Globals only.
362 global_type: Global.Type = .zero,402 global_type: Global.Type = .zero,
403 /// Zig-specific. Tables only.
404 limits_has_max: bool = false,
405 /// Zig-specific. Tables only.
406 limits_is_shared: bool = false,
407 /// Zig-specific. Tables only.
408 ref_type: RefType1 = .funcref,
363409
364 pub const Binding = enum(u2) {410 pub const Binding = enum(u2) {
365 strong = 0,411 strong = 0,
...@@ -378,13 +424,16 @@ pub const SymbolFlags = packed struct(u32) {...@@ -378,13 +424,16 @@ pub const SymbolFlags = packed struct(u32) {
378 };424 };
379425
380 pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {426 pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {
427 flags.no_strip = no_strip;
381 flags.alive = false;428 flags.alive = false;
382 flags.strings = false;429 flags.strings = false;
383 flags.must_link = must_link;430 flags.must_link = must_link;
384 flags.no_strip = no_strip;431 flags.is_passive = false;
385 flags.alignment = .none;432 flags.alignment = .none;
386 flags.global_type = .zero;433 flags.global_type = .zero;
387 flags.is_passive = false;434 flags.limits_has_max = false;
435 flags.limits_is_shared = false;
436 flags.ref_type = .funcref;
388 }437 }
389438
390 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool {439 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool {
...@@ -427,11 +476,28 @@ pub const SymbolFlags = packed struct(u32) {...@@ -427,11 +476,28 @@ pub const SymbolFlags = packed struct(u32) {
427 }476 }
428};477};
429478
430pub const Nav = extern struct {479pub const NavObj = extern struct {
431 code: DataSegment.Payload,480 code: DataSegment.Payload,
432 relocs: Relocation.Slice,481 /// Empty if not emitting an object.
482 relocs: OutReloc.Slice,
433483
434 pub const Code = DataSegment.Payload;484 /// Index into `navs`.
485 /// Note that swapRemove is sometimes performed on `navs`.
486 pub const Index = enum(u32) {
487 _,
488
489 pub fn key(i: @This(), wasm: *const Wasm) *InternPool.Nav.Index {
490 return &wasm.navs_obj.keys()[@intFromEnum(i)];
491 }
492
493 pub fn value(i: @This(), wasm: *const Wasm) *NavObj {
494 return &wasm.navs_obj.values()[@intFromEnum(i)];
495 }
496 };
497};
498
499pub const NavExe = extern struct {
500 code: DataSegment.Payload,
435501
436 /// Index into `navs`.502 /// Index into `navs`.
437 /// Note that swapRemove is sometimes performed on `navs`.503 /// Note that swapRemove is sometimes performed on `navs`.
...@@ -439,11 +505,11 @@ pub const Nav = extern struct {...@@ -439,11 +505,11 @@ pub const Nav = extern struct {
439 _,505 _,
440506
441 pub fn key(i: @This(), wasm: *const Wasm) *InternPool.Nav.Index {507 pub fn key(i: @This(), wasm: *const Wasm) *InternPool.Nav.Index {
442 return &wasm.navs.keys()[@intFromEnum(i)];508 return &wasm.navs_exe.keys()[@intFromEnum(i)];
443 }509 }
444510
445 pub fn value(i: @This(), wasm: *const Wasm) *Nav {511 pub fn value(i: @This(), wasm: *const Wasm) *NavExe {
446 return &wasm.navs.values()[@intFromEnum(i)];512 return &wasm.navs_exe.values()[@intFromEnum(i)];
447 }513 }
448 };514 };
449};515};
...@@ -506,7 +572,7 @@ pub const FunctionImport = extern struct {...@@ -506,7 +572,7 @@ pub const FunctionImport = extern struct {
506 __wasm_init_tls,572 __wasm_init_tls,
507 __zig_error_names,573 __zig_error_names,
508 // Next, index into `object_functions`.574 // Next, index into `object_functions`.
509 // Next, index into `navs`.575 // Next, index into `navs_exe` or `navs_obj` depending on whether emitting an object.
510 _,576 _,
511577
512 const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1;578 const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1;
...@@ -519,7 +585,8 @@ pub const FunctionImport = extern struct {...@@ -519,7 +585,8 @@ pub const FunctionImport = extern struct {
519 __wasm_init_tls,585 __wasm_init_tls,
520 __zig_error_names,586 __zig_error_names,
521 object_function: ObjectFunctionIndex,587 object_function: ObjectFunctionIndex,
522 nav: Nav.Index,588 nav_exe: NavExe.Index,
589 nav_obj: NavExe.Index,
523 };590 };
524591
525 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {592 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
...@@ -535,8 +602,14 @@ pub const FunctionImport = extern struct {...@@ -535,8 +602,14 @@ pub const FunctionImport = extern struct {
535 const object_function_index = i - first_object_function;602 const object_function_index = i - first_object_function;
536 if (object_function_index < wasm.object_functions.items.len)603 if (object_function_index < wasm.object_functions.items.len)
537 return .{ .object_function = @enumFromInt(object_function_index) };604 return .{ .object_function = @enumFromInt(object_function_index) };
605 const comp = wasm.base.comp;
606 const is_obj = comp.config.output_mode == .Obj;
538 const nav_index = object_function_index - wasm.object_functions.items.len;607 const nav_index = object_function_index - wasm.object_functions.items.len;
539 return .{ .nav = @enumFromInt(nav_index) };608 return if (is_obj) .{
609 .nav_obj = @enumFromInt(nav_index),
610 } else .{
611 .nav_exe = @enumFromInt(nav_index),
612 };
540 },613 },
541 };614 };
542 }615 }
...@@ -550,17 +623,24 @@ pub const FunctionImport = extern struct {...@@ -550,17 +623,24 @@ pub const FunctionImport = extern struct {
550 .__wasm_init_tls => .__wasm_init_tls,623 .__wasm_init_tls => .__wasm_init_tls,
551 .__zig_error_names => .__zig_error_names,624 .__zig_error_names => .__zig_error_names,
552 .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)),625 .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)),
553 .nav => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),626 .nav_obj => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),
627 .nav_exe => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),
554 };628 };
555 }629 }
556630
557 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {631 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
558 return pack(wasm, .{ .nav = @enumFromInt(wasm.navs.getIndex(ip_nav).?) });632 const comp = wasm.base.comp;
633 const is_obj = comp.config.output_mode == .Obj;
634 return pack(wasm, if (is_obj) .{
635 .nav_obj = @enumFromInt(wasm.navs_obj.getIndex(ip_nav).?),
636 } else .{
637 .nav_exe = @enumFromInt(wasm.navs_exe.getIndex(ip_nav).?),
638 });
559 }639 }
560640
561 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {641 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
562 return switch (r.unpack(wasm)) {642 return switch (r.unpack(wasm)) {
563 .unresolved, .nav => true,643 .unresolved, .nav_obj, .nav_exe => true,
564 else => false,644 else => false,
565 };645 };
566 }646 }
...@@ -608,7 +688,7 @@ pub const GlobalImport = extern struct {...@@ -608,7 +688,7 @@ pub const GlobalImport = extern struct {
608 __tls_size,688 __tls_size,
609 __zig_error_name_table,689 __zig_error_name_table,
610 // Next, index into `object_globals`.690 // Next, index into `object_globals`.
611 // Next, index into `navs`.691 // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
612 _,692 _,
613693
614 const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;694 const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
...@@ -623,7 +703,8 @@ pub const GlobalImport = extern struct {...@@ -623,7 +703,8 @@ pub const GlobalImport = extern struct {
623 __tls_size,703 __tls_size,
624 __zig_error_name_table,704 __zig_error_name_table,
625 object_global: ObjectGlobalIndex,705 object_global: ObjectGlobalIndex,
626 nav: Nav.Index,706 nav_exe: NavExe.Index,
707 nav_obj: NavObj.Index,
627 };708 };
628709
629 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {710 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
...@@ -639,8 +720,14 @@ pub const GlobalImport = extern struct {...@@ -639,8 +720,14 @@ pub const GlobalImport = extern struct {
639 const object_global_index = i - first_object_global;720 const object_global_index = i - first_object_global;
640 if (object_global_index < wasm.object_globals.items.len)721 if (object_global_index < wasm.object_globals.items.len)
641 return .{ .object_global = @enumFromInt(object_global_index) };722 return .{ .object_global = @enumFromInt(object_global_index) };
723 const comp = wasm.base.comp;
724 const is_obj = comp.config.output_mode == .Obj;
642 const nav_index = object_global_index - wasm.object_globals.items.len;725 const nav_index = object_global_index - wasm.object_globals.items.len;
643 return .{ .nav = @enumFromInt(nav_index) };726 return if (is_obj) .{
727 .nav_obj = @enumFromInt(nav_index),
728 } else .{
729 .nav_exe = @enumFromInt(nav_index),
730 };
644 },731 },
645 };732 };
646 }733 }
...@@ -656,12 +743,19 @@ pub const GlobalImport = extern struct {...@@ -656,12 +743,19 @@ pub const GlobalImport = extern struct {
656 .__tls_size => .__tls_size,743 .__tls_size => .__tls_size,
657 .__zig_error_name_table => .__zig_error_name_table,744 .__zig_error_name_table => .__zig_error_name_table,
658 .object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),745 .object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),
659 .nav => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),746 .nav_obj => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
747 .nav_exe => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
660 };748 };
661 }749 }
662750
663 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {751 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
664 return pack(wasm, .{ .nav = @enumFromInt(wasm.navs.getIndex(ip_nav).?) });752 const comp = wasm.base.comp;
753 const is_obj = comp.config.output_mode == .Obj;
754 return pack(wasm, if (is_obj) .{
755 .nav_obj = @enumFromInt(wasm.navs_obj.getIndex(ip_nav).?),
756 } else .{
757 .nav_exe = @enumFromInt(wasm.navs_exe.getIndex(ip_nav).?),
758 });
665 }759 }
666 };760 };
667761
...@@ -717,11 +811,32 @@ pub const Global = extern struct {...@@ -717,11 +811,32 @@ pub const Global = extern struct {
717 };811 };
718};812};
719813
814pub const RefType1 = enum(u1) {
815 funcref,
816 externref,
817
818 pub fn from(rt: std.wasm.RefType) RefType1 {
819 return switch (rt) {
820 .funcref => .funcref,
821 .externref => .externref,
822 };
823 }
824
825 pub fn to(rt: RefType1) std.wasm.RefType {
826 return switch (rt) {
827 .funcref => .funcref,
828 .externref => .externref,
829 };
830 }
831};
832
720pub const TableImport = extern struct {833pub const TableImport = extern struct {
721 flags: SymbolFlags,834 flags: SymbolFlags,
722 module_name: String,835 module_name: String,
723 source_location: SourceLocation,836 source_location: SourceLocation,
724 resolution: Resolution,837 resolution: Resolution,
838 limits_min: u32,
839 limits_max: u32,
725840
726 /// Represents a synthetic table, or a table from an object.841 /// Represents a synthetic table, or a table from an object.
727 pub const Resolution = enum(u32) {842 pub const Resolution = enum(u32) {
...@@ -730,35 +845,36 @@ pub const TableImport = extern struct {...@@ -730,35 +845,36 @@ pub const TableImport = extern struct {
730 // Next, index into `object_tables`.845 // Next, index into `object_tables`.
731 _,846 _,
732 };847 };
848
849 /// Index into `object_table_imports`.
850 pub const Index = enum(u32) {
851 _,
852
853 pub fn key(index: Index, wasm: *const Wasm) *String {
854 return &wasm.object_table_imports.keys()[@intFromEnum(index)];
855 }
856
857 pub fn value(index: Index, wasm: *const Wasm) *TableImport {
858 return &wasm.object_table_imports.values()[@intFromEnum(index)];
859 }
860 };
733};861};
734862
735pub const Table = extern struct {863pub const Table = extern struct {
736 module_name: String,864 module_name: OptionalString,
737 name: String,865 name: OptionalString,
738 flags: SymbolFlags,866 flags: SymbolFlags,
739 limits_min: u32,867 limits_min: u32,
740 limits_max: u32,868 limits_max: u32,
741 limits_has_max: bool,
742 limits_is_shared: bool,
743 reftype: std.wasm.RefType,
744 padding: [1]u8 = .{0},
745};869};
746870
747/// Uniquely identifies a section across all objects. Each Object has a section_start field.871/// Uniquely identifies a section across all objects. By subtracting
748/// By subtracting that value from this one, the Object section index is obtained.872/// `Object.local_section_index_base` from this one, the Object section index
873/// is obtained.
749pub const ObjectSectionIndex = enum(u32) {874pub const ObjectSectionIndex = enum(u32) {
750 _,875 _,
751};876};
752877
753/// Index into `object_table_imports`.
754pub const ObjectTableImportIndex = enum(u32) {
755 _,
756
757 pub fn ptr(index: ObjectTableImportIndex, wasm: *const Wasm) *TableImport {
758 return &wasm.object_table_imports.items[@intFromEnum(index)];
759 }
760};
761
762/// Index into `object_tables`.878/// Index into `object_tables`.
763pub const ObjectTableIndex = enum(u32) {879pub const ObjectTableIndex = enum(u32) {
764 _,880 _,
...@@ -820,13 +936,18 @@ pub const DataSegment = extern struct {...@@ -820,13 +936,18 @@ pub const DataSegment = extern struct {
820 len: u32,936 len: u32,
821937
822 fn slice(p: DataSegment.Payload, wasm: *const Wasm) []const u8 {938 fn slice(p: DataSegment.Payload, wasm: *const Wasm) []const u8 {
939 assert(p.off != p.len);
823 return wasm.string_bytes.items[p.off..][0..p.len];940 return wasm.string_bytes.items[p.off..][0..p.len];
824 }941 }
825 };942 };
826943
827 /// Index into `object_data_segments`.944 /// Index into `Wasm.object_data_segments`.
828 pub const Index = enum(u32) {945 pub const Index = enum(u32) {
829 _,946 _,
947
948 pub fn ptr(i: Index, wasm: *const Wasm) *DataSegment {
949 return &wasm.object_data_segments.items[@intFromEnum(i)];
950 }
830 };951 };
831};952};
832953
...@@ -992,6 +1113,10 @@ pub const FunctionImportId = enum(u32) {...@@ -992,6 +1113,10 @@ pub const FunctionImportId = enum(u32) {
992 return .{ .zcu_import = @enumFromInt(zcu_import_i) };1113 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
993 }1114 }
9941115
1116 pub fn fromObject(function_import_index: FunctionImport.Index, wasm: *const Wasm) FunctionImportId {
1117 return pack(.{ .object_function_import = function_import_index }, wasm);
1118 }
1119
995 /// This function is allowed O(N) lookup because it is only called during1120 /// This function is allowed O(N) lookup because it is only called during
996 /// diagnostic generation.1121 /// diagnostic generation.
997 pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {1122 pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
...@@ -1035,6 +1160,10 @@ pub const GlobalImportId = enum(u32) {...@@ -1035,6 +1160,10 @@ pub const GlobalImportId = enum(u32) {
1035 return .{ .zcu_import = @enumFromInt(zcu_import_i) };1160 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
1036 }1161 }
10371162
1163 pub fn fromObject(object_global_import: GlobalImport.Index, wasm: *const Wasm) GlobalImportId {
1164 return pack(.{ .object_global_import = object_global_import }, wasm);
1165 }
1166
1038 /// This function is allowed O(N) lookup because it is only called during1167 /// This function is allowed O(N) lookup because it is only called during
1039 /// diagnostic generation.1168 /// diagnostic generation.
1040 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {1169 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
...@@ -1054,7 +1183,38 @@ pub const GlobalImportId = enum(u32) {...@@ -1054,7 +1183,38 @@ pub const GlobalImportId = enum(u32) {
1054 }1183 }
1055};1184};
10561185
1057pub const Relocation = struct {1186/// Index into `Wasm.symbol_table`.
1187pub const SymbolTableIndex = enum(u32) {
1188 _,
1189
1190 pub fn key(i: @This(), wasm: *const Wasm) *String {
1191 return &wasm.symbol_table.keys()[@intFromEnum(i)];
1192 }
1193};
1194
1195pub const OutReloc = struct {
1196 tag: ObjectRelocation.Tag,
1197 offset: u32,
1198 pointee: Pointee,
1199 addend: i32,
1200
1201 pub const Pointee = union {
1202 symbol_index: SymbolTableIndex,
1203 type_index: FunctionType.Index,
1204 };
1205
1206 pub const Slice = extern struct {
1207 /// Index into `out_relocs`.
1208 off: u32,
1209 len: u32,
1210
1211 pub fn slice(s: Slice, wasm: *const Wasm) []OutReloc {
1212 return wasm.relocations.items[s.off..][0..s.len];
1213 }
1214 };
1215};
1216
1217pub const ObjectRelocation = struct {
1058 tag: Tag,1218 tag: Tag,
1059 /// Offset of the value to rewrite relative to the relevant section's contents.1219 /// Offset of the value to rewrite relative to the relevant section's contents.
1060 /// When `offset` is zero, its position is immediately after the id and size of the section.1220 /// When `offset` is zero, its position is immediately after the id and size of the section.
...@@ -1067,8 +1227,6 @@ pub const Relocation = struct {...@@ -1067,8 +1227,6 @@ pub const Relocation = struct {
1067 symbol_name: String,1227 symbol_name: String,
1068 type_index: FunctionType.Index,1228 type_index: FunctionType.Index,
1069 section: ObjectSectionIndex,1229 section: ObjectSectionIndex,
1070 nav_index: InternPool.Nav.Index,
1071 uav_index: InternPool.Index,
1072 };1230 };
10731231
1074 pub const Slice = extern struct {1232 pub const Slice = extern struct {
...@@ -1076,7 +1234,7 @@ pub const Relocation = struct {...@@ -1076,7 +1234,7 @@ pub const Relocation = struct {
1076 off: u32,1234 off: u32,
1077 len: u32,1235 len: u32,
10781236
1079 pub fn slice(s: Slice, wasm: *const Wasm) []Relocation {1237 pub fn slice(s: Slice, wasm: *const Wasm) []ObjectRelocation {
1080 return wasm.relocations.items[s.off..][0..s.len];1238 return wasm.relocations.items[s.off..][0..s.len];
1081 }1239 }
1082 };1240 };
...@@ -1122,11 +1280,6 @@ pub const Relocation = struct {...@@ -1122,11 +1280,6 @@ pub const Relocation = struct {
1122 // Above here, the tags correspond to symbol table ABI described in1280 // Above here, the tags correspond to symbol table ABI described in
1123 // https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md1281 // https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
1124 // Below, the tags are compiler-internal.1282 // Below, the tags are compiler-internal.
1125
1126 /// Uses `nav_index`. 4 or 8 bytes depending on wasm32 or wasm64.
1127 nav_index,
1128 /// Uses `uav_index`. 4 or 8 bytes depending on wasm32 or wasm64.
1129 uav_index,
1130 };1283 };
1131};1284};
11321285
...@@ -1456,7 +1609,8 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1456,7 +1609,8 @@ pub fn deinit(wasm: *Wasm) void {
1456 const gpa = wasm.base.comp.gpa;1609 const gpa = wasm.base.comp.gpa;
1457 if (wasm.llvm_object) |llvm_object| llvm_object.deinit();1610 if (wasm.llvm_object) |llvm_object| llvm_object.deinit();
14581611
1459 wasm.navs.deinit(gpa);1612 wasm.navs_exe.deinit(gpa);
1613 wasm.navs_obj.deinit(gpa);
1460 wasm.zcu_funcs.deinit(gpa);1614 wasm.zcu_funcs.deinit(gpa);
1461 wasm.nav_exports.deinit(gpa);1615 wasm.nav_exports.deinit(gpa);
1462 wasm.uav_exports.deinit(gpa);1616 wasm.uav_exports.deinit(gpa);
...@@ -1478,7 +1632,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1478,7 +1632,7 @@ pub fn deinit(wasm: *Wasm) void {
1478 wasm.object_tables.deinit(gpa);1632 wasm.object_tables.deinit(gpa);
1479 wasm.object_memory_imports.deinit(gpa);1633 wasm.object_memory_imports.deinit(gpa);
1480 wasm.object_memories.deinit(gpa);1634 wasm.object_memories.deinit(gpa);
14811635 wasm.object_relocations.deinit(gpa);
1482 wasm.object_data_segments.deinit(gpa);1636 wasm.object_data_segments.deinit(gpa);
1483 wasm.object_custom_segments.deinit(gpa);1637 wasm.object_custom_segments.deinit(gpa);
1484 wasm.object_init_funcs.deinit(gpa);1638 wasm.object_init_funcs.deinit(gpa);
...@@ -1492,8 +1646,13 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1492,8 +1646,13 @@ pub fn deinit(wasm: *Wasm) void {
1492 wasm.function_imports.deinit(gpa);1646 wasm.function_imports.deinit(gpa);
1493 wasm.functions.deinit(gpa);1647 wasm.functions.deinit(gpa);
1494 wasm.globals.deinit(gpa);1648 wasm.globals.deinit(gpa);
1649 wasm.global_exports.deinit(gpa);
1495 wasm.global_imports.deinit(gpa);1650 wasm.global_imports.deinit(gpa);
1496 wasm.table_imports.deinit(gpa);1651 wasm.table_imports.deinit(gpa);
1652 wasm.symbol_table.deinit(gpa);
1653 wasm.out_relocs.deinit(gpa);
1654 wasm.uav_fixups.deinit(gpa);
1655 wasm.nav_fixups.deinit(gpa);
14971656
1498 wasm.string_bytes.deinit(gpa);1657 wasm.string_bytes.deinit(gpa);
1499 wasm.string_table.deinit(gpa);1658 wasm.string_table.deinit(gpa);
...@@ -1527,7 +1686,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -1527,7 +1686,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
1527 const zcu = pt.zcu;1686 const zcu = pt.zcu;
1528 const ip = &zcu.intern_pool;1687 const ip = &zcu.intern_pool;
1529 const nav = ip.getNav(nav_index);1688 const nav = ip.getNav(nav_index);
1530 const gpa = wasm.base.comp.gpa;1689 const comp = wasm.base.comp;
1690 const gpa = comp.gpa;
1691 const is_obj = comp.config.output_mode == .Obj;
15311692
1532 const nav_val = zcu.navValue(nav_index);1693 const nav_val = zcu.navValue(nav_index);
1533 const is_extern, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {1694 const is_extern, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
...@@ -1542,22 +1703,26 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -1542,22 +1703,26 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
15421703
1543 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {1704 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
1544 _ = wasm.imports.swapRemove(nav_index);1705 _ = wasm.imports.swapRemove(nav_index);
1545 if (wasm.navs.swapRemove(nav_index)) {1706 if (is_obj) {
1546 @panic("TODO reclaim resources");1707 if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources");
1708 } else {
1709 if (wasm.navs_exe.swapRemove(nav_index)) @panic("TODO reclaim resources");
1547 }1710 }
1548 return;1711 return;
1549 }1712 }
15501713
1551 if (is_extern) {1714 if (is_extern) {
1552 try wasm.imports.put(gpa, nav_index, {});1715 try wasm.imports.put(gpa, nav_index, {});
1553 if (wasm.navs.swapRemove(nav_index)) {1716 if (is_obj) {
1554 @panic("TODO reclaim resources");1717 if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources");
1718 } else {
1719 if (wasm.navs_exe.swapRemove(nav_index)) @panic("TODO reclaim resources");
1555 }1720 }
1556 return;1721 return;
1557 }1722 }
15581723
1559 const code_start: u32 = @intCast(wasm.string_bytes.items.len);1724 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
1560 const relocs_start: u32 = @intCast(wasm.relocations.len);1725 const relocs_start: u32 = @intCast(wasm.out_relocs.len);
1561 wasm.string_bytes_lock.lock();1726 wasm.string_bytes_lock.lock();
15621727
1563 try codegen.generateSymbol(1728 try codegen.generateSymbol(
...@@ -1570,15 +1735,45 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -1570,15 +1735,45 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
1570 );1735 );
15711736
1572 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);1737 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
1573 const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);1738 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);
1574 wasm.string_bytes_lock.unlock();1739 wasm.string_bytes_lock.unlock();
15751740
1576 const code: Nav.Code = .{1741 const naive_code: DataSegment.Payload = .{
1577 .off = code_start,1742 .off = code_start,
1578 .len = code_len,1743 .len = code_len,
1579 };1744 };
15801745
1581 const gop = try wasm.navs.getOrPut(gpa, nav_index);1746 // Only nonzero init values need to take up space in the output.
1747 const all_zeroes = std.mem.allEqual(u8, naive_code.slice(wasm), 0);
1748 const code: DataSegment.Payload = if (!all_zeroes) naive_code else c: {
1749 wasm.string_bytes.shrinkRetainingCapacity(code_start);
1750 // Indicate empty by making off and len the same value, however, still
1751 // transmit the data size by using the size as that value.
1752 break :c .{
1753 .off = naive_code.len,
1754 .len = naive_code.len,
1755 };
1756 };
1757
1758 if (is_obj) {
1759 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
1760 if (gop.found_existing) {
1761 @panic("TODO reuse these resources");
1762 } else {
1763 _ = wasm.imports.swapRemove(nav_index);
1764 }
1765 gop.value_ptr.* = .{
1766 .code = code,
1767 .relocs = .{
1768 .off = relocs_start,
1769 .len = relocs_len,
1770 },
1771 };
1772 }
1773
1774 assert(relocs_len == 0);
1775
1776 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
1582 if (gop.found_existing) {1777 if (gop.found_existing) {
1583 @panic("TODO reuse these resources");1778 @panic("TODO reuse these resources");
1584 } else {1779 } else {
...@@ -1586,10 +1781,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -1586,10 +1781,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
1586 }1781 }
1587 gop.value_ptr.* = .{1782 gop.value_ptr.* = .{
1588 .code = code,1783 .code = code,
1589 .relocs = .{
1590 .off = relocs_start,
1591 .len = relocs_len,
1592 },
1593 };1784 };
1594}1785}
15951786
...@@ -1705,6 +1896,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -1705,6 +1896,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
1705 continue;1896 continue;
1706 }1897 }
1707 }1898 }
1899 if (wasm.object_table_imports.getPtr(exp_name_interned)) |import| {
1900 if (import.resolution != .unresolved) {
1901 import.flags.exported = true;
1902 continue;
1903 }
1904 }
1708 try missing_exports.put(gpa, exp_name_interned, {});1905 try missing_exports.put(gpa, exp_name_interned, {});
1709 }1906 }
1710 wasm.missing_exports_init = try gpa.dupe(String, missing_exports.keys());1907 wasm.missing_exports_init = try gpa.dupe(String, missing_exports.keys());
...@@ -1724,32 +1921,28 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -1724,32 +1921,28 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
1724 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {1921 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {
1725 if (import.flags.isIncluded(rdynamic)) {1922 if (import.flags.isIncluded(rdynamic)) {
1726 try markFunction(wasm, name, import, @enumFromInt(i));1923 try markFunction(wasm, name, import, @enumFromInt(i));
1727 continue;
1728 }1924 }
1729 }1925 }
1730 wasm.functions_len = @intCast(wasm.functions.entries.len);1926 wasm.functions_len = @intCast(wasm.functions.entries.len);
1731 wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys());1927 wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys());
1732 wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.vals());1928 wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.values());
1733 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);1929 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
17341930
1735 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {1931 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
1736 if (import.flags.isIncluded(rdynamic)) {1932 if (import.flags.isIncluded(rdynamic)) {
1737 try markGlobal(wasm, name, import, @enumFromInt(i));1933 try markGlobal(wasm, name, import, @enumFromInt(i));
1738 continue;
1739 }1934 }
1740 }1935 }
1741 wasm.globals_len = @intCast(wasm.globals.items.len);1936 wasm.globals_len = @intCast(wasm.globals.entries.len);
1742 wasm.global_imports_init_keys = try gpa.dupe(String, wasm.global_imports.keys());1937 wasm.global_imports_init_keys = try gpa.dupe(String, wasm.global_imports.keys());
1743 wasm.global_imports_init_vals = try gpa.dupe(GlobalImportId, wasm.global_imports.values());1938 wasm.global_imports_init_vals = try gpa.dupe(GlobalImportId, wasm.global_imports.values());
1744 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);1939 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);
17451940
1746 for (wasm.object_table_imports.items, 0..) |*import, i| {1941 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
1747 if (import.flags.isIncluded(rdynamic)) {1942 if (import.flags.isIncluded(rdynamic)) {
1748 try markTable(wasm, import.name, import, @enumFromInt(i));1943 try markTable(wasm, name, import, @enumFromInt(i));
1749 continue;
1750 }1944 }
1751 }1945 }
1752 wasm.tables_len = @intCast(wasm.tables.items.len);
1753}1946}
17541947
1755/// Recursively mark alive everything referenced by the function.1948/// Recursively mark alive everything referenced by the function.
...@@ -1758,7 +1951,7 @@ fn markFunction(...@@ -1758,7 +1951,7 @@ fn markFunction(
1758 name: String,1951 name: String,
1759 import: *FunctionImport,1952 import: *FunctionImport,
1760 func_index: FunctionImport.Index,1953 func_index: FunctionImport.Index,
1761) error{OutOfMemory}!void {1954) Allocator.Error!void {
1762 if (import.flags.alive) return;1955 if (import.flags.alive) return;
1763 import.flags.alive = true;1956 import.flags.alive = true;
17641957
...@@ -1783,15 +1976,15 @@ fn markFunction(...@@ -1783,15 +1976,15 @@ fn markFunction(
1783 import.resolution = .__wasm_init_tls;1976 import.resolution = .__wasm_init_tls;
1784 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});1977 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
1785 } else {1978 } else {
1786 try wasm.function_imports.put(gpa, name, .fromObject(func_index));1979 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
1787 }1980 }
1788 } else {1981 } else {
1789 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);1982 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
17901983
1791 if (!is_obj and import.flags.isExported(rdynamic))1984 if (!is_obj and import.flags.isExported(rdynamic))
1792 try wasm.function_exports.append(gpa, @intCast(gop.index));1985 try wasm.function_exports.append(gpa, @enumFromInt(gop.index));
17931986
1794 for (wasm.functionResolutionRelocSlice(import.resolution)) |reloc|1987 for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|
1795 try wasm.markReloc(reloc);1988 try wasm.markReloc(reloc);
1796 }1989 }
1797}1990}
...@@ -1833,15 +2026,15 @@ fn markGlobal(...@@ -1833,15 +2026,15 @@ fn markGlobal(
1833 import.resolution = .__tls_size;2026 import.resolution = .__tls_size;
1834 wasm.globals.putAssumeCapacity(.__tls_size, {});2027 wasm.globals.putAssumeCapacity(.__tls_size, {});
1835 } else {2028 } else {
1836 try wasm.global_imports.put(gpa, name, .fromObject(global_index));2029 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
1837 }2030 }
1838 } else {2031 } else {
1839 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);2032 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
18402033
1841 if (!is_obj and import.flags.isExported(rdynamic))2034 if (!is_obj and import.flags.isExported(rdynamic))
1842 try wasm.global_exports.append(gpa, @intCast(gop.index));2035 try wasm.global_exports.append(gpa, @enumFromInt(gop.index));
18432036
1844 for (wasm.globalResolutionRelocSlice(import.resolution)) |reloc|2037 for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|
1845 try wasm.markReloc(reloc);2038 try wasm.markReloc(reloc);
1846 }2039 }
1847}2040}
...@@ -1850,7 +2043,7 @@ fn markTable(...@@ -1850,7 +2043,7 @@ fn markTable(
1850 wasm: *Wasm,2043 wasm: *Wasm,
1851 name: String,2044 name: String,
1852 import: *TableImport,2045 import: *TableImport,
1853 table_index: ObjectTableImportIndex,2046 table_index: TableImport.Index,
1854) !void {2047) !void {
1855 if (import.flags.alive) return;2048 if (import.flags.alive) return;
1856 import.flags.alive = true;2049 import.flags.alive = true;
...@@ -1865,7 +2058,7 @@ fn markTable(...@@ -1865,7 +2058,7 @@ fn markTable(
1865 import.resolution = .__indirect_function_table;2058 import.resolution = .__indirect_function_table;
1866 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});2059 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
1867 } else {2060 } else {
1868 try wasm.table_imports.put(gpa, name, .fromObject(table_index));2061 try wasm.table_imports.put(gpa, name, table_index);
1869 }2062 }
1870 } else {2063 } else {
1871 wasm.tables.putAssumeCapacity(import.resolution, {});2064 wasm.tables.putAssumeCapacity(import.resolution, {});
...@@ -1873,18 +2066,24 @@ fn markTable(...@@ -1873,18 +2066,24 @@ fn markTable(
1873 }2066 }
1874}2067}
18752068
1876fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const Relocation {2069fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const ObjectRelocation {
1877 assert(resolution != .none);2070 assert(resolution != .unresolved);
1878 _ = wasm;2071 _ = wasm;
1879 @panic("TODO");2072 @panic("TODO");
1880}2073}
18812074
1882fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const Relocation {2075fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const ObjectRelocation {
1883 assert(resolution != .none);2076 assert(resolution != .unresolved);
1884 _ = wasm;2077 _ = wasm;
1885 @panic("TODO");2078 @panic("TODO");
1886}2079}
18872080
2081fn markReloc(wasm: *Wasm, reloc: ObjectRelocation) !void {
2082 _ = wasm;
2083 _ = reloc;
2084 @panic("TODO");
2085}
2086
1888pub fn flushModule(2087pub fn flushModule(
1889 wasm: *Wasm,2088 wasm: *Wasm,
1890 arena: Allocator,2089 arena: Allocator,
...@@ -2349,8 +2548,10 @@ fn defaultEntrySymbolName(...@@ -2349,8 +2548,10 @@ fn defaultEntrySymbolName(
2349 };2548 };
2350}2549}
23512550
2352pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {2551pub fn internString(wasm: *Wasm, bytes: []const u8) Allocator.Error!String {
2353 assert(mem.indexOfScalar(u8, bytes, 0) == null);2552 assert(mem.indexOfScalar(u8, bytes, 0) == null);
2553 wasm.string_bytes_lock.lock();
2554 defer wasm.string_bytes_lock.unlock();
2354 const gpa = wasm.base.comp.gpa;2555 const gpa = wasm.base.comp.gpa;
2355 const gop = try wasm.string_table.getOrPutContextAdapted(2556 const gop = try wasm.string_table.getOrPutContextAdapted(
2356 gpa,2557 gpa,
...@@ -2371,6 +2572,13 @@ pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {...@@ -2371,6 +2572,13 @@ pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
2371 return new_off;2572 return new_off;
2372}2573}
23732574
2575// TODO implement instead by appending to string_bytes
2576pub fn internStringFmt(wasm: *Wasm, comptime format: []const u8, args: anytype) Allocator.Error!String {
2577 var buffer: [32]u8 = undefined;
2578 const slice = std.fmt.bufPrint(&buffer, format, args) catch unreachable;
2579 return internString(wasm, slice);
2580}
2581
2374pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {2582pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
2375 assert(mem.indexOfScalar(u8, bytes, 0) == null);2583 assert(mem.indexOfScalar(u8, bytes, 0) == null);
2376 return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{2584 return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{
...@@ -2378,17 +2586,17 @@ pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {...@@ -2378,17 +2586,17 @@ pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
2378 }));2586 }));
2379}2587}
23802588
2381pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) error{OutOfMemory}!ValtypeList {2589pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Allocator.Error!ValtypeList {
2382 return .fromString(try internString(wasm, @ptrCast(valtype_list)));2590 return .fromString(try internString(wasm, @ptrCast(valtype_list)));
2383}2591}
23842592
2385pub fn addFuncType(wasm: *Wasm, ft: FunctionType) error{OutOfMemory}!FunctionType.Index {2593pub fn addFuncType(wasm: *Wasm, ft: FunctionType) Allocator.Error!FunctionType.Index {
2386 const gpa = wasm.base.comp.gpa;2594 const gpa = wasm.base.comp.gpa;
2387 const gop = try wasm.func_types.getOrPut(gpa, ft);2595 const gop = try wasm.func_types.getOrPut(gpa, ft);
2388 return @enumFromInt(gop.index);2596 return @enumFromInt(gop.index);
2389}2597}
23902598
2391pub fn addExpr(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!Expr {2599pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
2392 const gpa = wasm.base.comp.gpa;2600 const gpa = wasm.base.comp.gpa;
2393 // We can't use string table deduplication here since these expressions can2601 // We can't use string table deduplication here since these expressions can
2394 // have null bytes in them however it may be interesting to explore since2602 // have null bytes in them however it may be interesting to explore since
...@@ -2398,8 +2606,29 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!Expr {...@@ -2398,8 +2606,29 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!Expr {
2398 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);2606 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
2399}2607}
24002608
2401pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!DataSegment.Payload {2609pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {
2402 const gpa = wasm.base.comp.gpa;2610 const gpa = wasm.base.comp.gpa;
2403 try wasm.string_bytes.appendSlice(gpa, bytes);2611 try wasm.string_bytes.appendSlice(gpa, bytes);
2404 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);2612 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
2405}2613}
2614
2615pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {
2616 const comp = wasm.base.comp;
2617 assert(comp.config.output_mode == .Obj);
2618 const gpa = comp.gpa;
2619 const name = try wasm.internStringFmt("__anon_{d}", .{@intFromEnum(ip_index)});
2620 const gop = try wasm.symbol_table.getOrPut(gpa, name);
2621 return @enumFromInt(gop.index);
2622}
2623
2624pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Error!SymbolTableIndex {
2625 const comp = wasm.base.comp;
2626 assert(comp.config.output_mode == .Obj);
2627 const zcu = comp.zcu.?;
2628 const ip = &zcu.intern_pool;
2629 const gpa = comp.gpa;
2630 const nav = ip.getNav(nav_index);
2631 const name = try wasm.internString(nav.fqn.toSlice(ip));
2632 const gop = try wasm.symbol_table.getOrPut(gpa, name);
2633 return @enumFromInt(gop.index);
2634}
src/link/Wasm/Flush.zig+51-49
...@@ -42,7 +42,6 @@ pub fn clear(f: *Flush) void {...@@ -42,7 +42,6 @@ pub fn clear(f: *Flush) void {
42 f.data_segments.clearRetainingCapacity();42 f.data_segments.clearRetainingCapacity();
43 f.data_segment_groups.clearRetainingCapacity();43 f.data_segment_groups.clearRetainingCapacity();
44 f.indirect_function_table.clearRetainingCapacity();44 f.indirect_function_table.clearRetainingCapacity();
45 f.global_exports.clearRetainingCapacity();
46}45}
4746
48pub fn deinit(f: *Flush, gpa: Allocator) void {47pub fn deinit(f: *Flush, gpa: Allocator) void {
...@@ -50,11 +49,10 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {...@@ -50,11 +49,10 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
50 f.data_segments.deinit(gpa);49 f.data_segments.deinit(gpa);
51 f.data_segment_groups.deinit(gpa);50 f.data_segment_groups.deinit(gpa);
52 f.indirect_function_table.deinit(gpa);51 f.indirect_function_table.deinit(gpa);
53 f.global_exports.deinit(gpa);
54 f.* = undefined;52 f.* = undefined;
55}53}
5654
57pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {55pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
58 const comp = wasm.base.comp;56 const comp = wasm.base.comp;
59 const shared_memory = comp.config.shared_memory;57 const shared_memory = comp.config.shared_memory;
60 const diags = &comp.link_diags;58 const diags = &comp.link_diags;
...@@ -115,7 +113,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -115,7 +113,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
115 src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});113 src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});
116 }114 }
117 for (wasm.table_imports.keys(), wasm.table_imports.values()) |name, table_import_id| {115 for (wasm.table_imports.keys(), wasm.table_imports.values()) |name, table_import_id| {
118 const src_loc = table_import_id.ptr(wasm).source_location;116 const src_loc = table_import_id.value(wasm).source_location;
119 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});117 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});
120 }118 }
121 }119 }
...@@ -142,7 +140,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -142,7 +140,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
142 if (!ds.flags.alive) continue;140 if (!ds.flags.alive) continue;
143 const data_segment_index: Wasm.DataSegment.Index = @enumFromInt(i);141 const data_segment_index: Wasm.DataSegment.Index = @enumFromInt(i);
144 any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !isBss(wasm, ds.name));142 any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !isBss(wasm, ds.name));
145 f.data_segments.putAssumeCapacityNoClobber(data_segment_index, .{ .offset = undefined });143 f.data_segments.putAssumeCapacityNoClobber(data_segment_index, @as(u32, undefined));
146 }144 }
147145
148 try wasm.functions.ensureUnusedCapacity(gpa, 3);146 try wasm.functions.ensureUnusedCapacity(gpa, 3);
...@@ -159,8 +157,10 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -159,8 +157,10 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
159 // When we have TLS GOT entries and shared memory is enabled,157 // When we have TLS GOT entries and shared memory is enabled,
160 // we must perform runtime relocations or else we don't create the function.158 // we must perform runtime relocations or else we don't create the function.
161 if (shared_memory) {159 if (shared_memory) {
162 if (f.need_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});160 // This logic that checks `any_tls_relocs` is missing the part where it
163 wasm.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});161 // also notices threadlocal globals from Zcu code.
162 if (wasm.any_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
163 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
164 }164 }
165165
166 // Sort order:166 // Sort order:
...@@ -178,14 +178,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -178,14 +178,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
178 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {178 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
179 const lhs_segment_index = ctx.segments[lhs];179 const lhs_segment_index = ctx.segments[lhs];
180 const rhs_segment_index = ctx.segments[rhs];180 const rhs_segment_index = ctx.segments[rhs];
181 const lhs_segment = lhs_segment_index.ptr(wasm);181 const lhs_segment = lhs_segment_index.ptr(ctx.wasm);
182 const rhs_segment = rhs_segment_index.ptr(wasm);182 const rhs_segment = rhs_segment_index.ptr(ctx.wasm);
183 const lhs_tls = @intFromBool(lhs_segment.flags.tls);183 const lhs_tls = @intFromBool(lhs_segment.flags.tls);
184 const rhs_tls = @intFromBool(rhs_segment.flags.tls);184 const rhs_tls = @intFromBool(rhs_segment.flags.tls);
185 if (lhs_tls < rhs_tls) return true;185 if (lhs_tls < rhs_tls) return true;
186 if (lhs_tls > rhs_tls) return false;186 if (lhs_tls > rhs_tls) return false;
187 const lhs_prefix, const lhs_suffix = splitSegmentName(lhs_segment.name.unwrap().slice(ctx.wasm));187 const lhs_prefix, const lhs_suffix = splitSegmentName(lhs_segment.name.unwrap().?.slice(ctx.wasm));
188 const rhs_prefix, const rhs_suffix = splitSegmentName(rhs_segment.name.unwrap().slice(ctx.wasm));188 const rhs_prefix, const rhs_suffix = splitSegmentName(rhs_segment.name.unwrap().?.slice(ctx.wasm));
189 switch (mem.order(u8, lhs_prefix, rhs_prefix)) {189 switch (mem.order(u8, lhs_prefix, rhs_prefix)) {
190 .lt => return true,190 .lt => return true,
191 .gt => return false,191 .gt => return false,
...@@ -213,14 +213,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -213,14 +213,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
213 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention213 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
214 const pointer_alignment: Alignment = .@"4";214 const pointer_alignment: Alignment = .@"4";
215 // Always place the stack at the start by default unless the user specified the global-base flag.215 // Always place the stack at the start by default unless the user specified the global-base flag.
216 const place_stack_first, var memory_ptr: u32 = if (wasm.global_base) |base| .{ false, base } else .{ true, 0 };216 const place_stack_first, var memory_ptr: u64 = if (wasm.global_base) |base| .{ false, base } else .{ true, 0 };
217217
218 const VirtualAddrs = struct {218 const VirtualAddrs = struct {
219 stack_pointer: u32,219 stack_pointer: u32,
220 heap_base: u32,220 heap_base: u32,
221 heap_end: u32,221 heap_end: u32,
222 tls_base: ?u32,222 tls_base: ?u32,
223 tls_align: ?u32,223 tls_align: Alignment,
224 tls_size: ?u32,224 tls_size: ?u32,
225 init_memory_flag: ?u32,225 init_memory_flag: ?u32,
226 };226 };
...@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
229 .heap_base = undefined,229 .heap_base = undefined,
230 .heap_end = undefined,230 .heap_end = undefined,
231 .tls_base = null,231 .tls_base = null,
232 .tls_align = null,232 .tls_align = .none,
233 .tls_size = null,233 .tls_size = null,
234 .init_memory_flag = null,234 .init_memory_flag = null,
235 };235 };
...@@ -237,7 +237,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -237,7 +237,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
237 if (place_stack_first and !is_obj) {237 if (place_stack_first and !is_obj) {
238 memory_ptr = stack_alignment.forward(memory_ptr);238 memory_ptr = stack_alignment.forward(memory_ptr);
239 memory_ptr += wasm.base.stack_size;239 memory_ptr += wasm.base.stack_size;
240 virtual_addrs.stack_pointer = memory_ptr;240 virtual_addrs.stack_pointer = @intCast(memory_ptr);
241 }241 }
242242
243 const segment_indexes = f.data_segments.keys();243 const segment_indexes = f.data_segments.keys();
...@@ -247,27 +247,27 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -247,27 +247,27 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
247 var seen_tls: enum { before, during, after } = .before;247 var seen_tls: enum { before, during, after } = .before;
248 var offset: u32 = 0;248 var offset: u32 = 0;
249 for (segment_indexes, segment_offsets, 0..) |segment_index, *segment_offset, i| {249 for (segment_indexes, segment_offsets, 0..) |segment_index, *segment_offset, i| {
250 const segment = segment_index.ptr(f);250 const segment = segment_index.ptr(wasm);
251 memory_ptr = segment.alignment.forward(memory_ptr);251 memory_ptr = segment.flags.alignment.forward(memory_ptr);
252252
253 const want_new_segment = b: {253 const want_new_segment = b: {
254 if (is_obj) break :b false;254 if (is_obj) break :b false;
255 switch (seen_tls) {255 switch (seen_tls) {
256 .before => if (segment.flags.tls) {256 .before => if (segment.flags.tls) {
257 virtual_addrs.tls_base = if (shared_memory) 0 else memory_ptr;257 virtual_addrs.tls_base = if (shared_memory) 0 else @intCast(memory_ptr);
258 virtual_addrs.tls_align = segment.flags.alignment;258 virtual_addrs.tls_align = segment.flags.alignment;
259 seen_tls = .during;259 seen_tls = .during;
260 break :b true;260 break :b true;
261 },261 },
262 .during => if (!segment.flags.tls) {262 .during => if (!segment.flags.tls) {
263 virtual_addrs.tls_size = memory_ptr - virtual_addrs.tls_base;263 virtual_addrs.tls_size = @intCast(memory_ptr - virtual_addrs.tls_base.?);
264 virtual_addrs.tls_align = virtual_addrs.tls_align.maxStrict(segment.flags.alignment);264 virtual_addrs.tls_align = virtual_addrs.tls_align.maxStrict(segment.flags.alignment);
265 seen_tls = .after;265 seen_tls = .after;
266 break :b true;266 break :b true;
267 },267 },
268 .after => {},268 .after => {},
269 }269 }
270 break :b i >= 1 and !wasm.wantSegmentMerge(segment_indexes[i - 1], segment_index);270 break :b i >= 1 and !wantSegmentMerge(wasm, segment_indexes[i - 1], segment_index);
271 };271 };
272 if (want_new_segment) {272 if (want_new_segment) {
273 if (offset > 0) try f.data_segment_groups.append(gpa, offset);273 if (offset > 0) try f.data_segment_groups.append(gpa, offset);
...@@ -275,26 +275,26 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -275,26 +275,26 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
275 }275 }
276276
277 segment_offset.* = offset;277 segment_offset.* = offset;
278 offset += segment.size;278 offset += segment.payload.len;
279 memory_ptr += segment.size;279 memory_ptr += segment.payload.len;
280 }280 }
281 if (offset > 0) try f.data_segment_groups.append(gpa, offset);281 if (offset > 0) try f.data_segment_groups.append(gpa, offset);
282 }282 }
283283
284 if (shared_memory and any_passive_inits) {284 if (shared_memory and any_passive_inits) {
285 memory_ptr = pointer_alignment.forward(memory_ptr);285 memory_ptr = pointer_alignment.forward(memory_ptr);
286 virtual_addrs.init_memory_flag = memory_ptr;286 virtual_addrs.init_memory_flag = @intCast(memory_ptr);
287 memory_ptr += 4;287 memory_ptr += 4;
288 }288 }
289289
290 if (!place_stack_first and !is_obj) {290 if (!place_stack_first and !is_obj) {
291 memory_ptr = stack_alignment.forward(memory_ptr);291 memory_ptr = stack_alignment.forward(memory_ptr);
292 memory_ptr += wasm.base.stack_size;292 memory_ptr += wasm.base.stack_size;
293 virtual_addrs.stack_pointer = memory_ptr;293 virtual_addrs.stack_pointer = @intCast(memory_ptr);
294 }294 }
295295
296 memory_ptr = heap_alignment.forward(memory_ptr);296 memory_ptr = heap_alignment.forward(memory_ptr);
297 virtual_addrs.heap_base = memory_ptr;297 virtual_addrs.heap_base = @intCast(memory_ptr);
298298
299 if (wasm.initial_memory) |initial_memory| {299 if (wasm.initial_memory) |initial_memory| {
300 if (!mem.isAlignedGeneric(u64, initial_memory, page_size)) {300 if (!mem.isAlignedGeneric(u64, initial_memory, page_size)) {
...@@ -311,7 +311,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -311,7 +311,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
311 } else {311 } else {
312 memory_ptr = mem.alignForward(u64, memory_ptr, std.wasm.page_size);312 memory_ptr = mem.alignForward(u64, memory_ptr, std.wasm.page_size);
313 }313 }
314 virtual_addrs.heap_end = memory_ptr;314 virtual_addrs.heap_end = @intCast(memory_ptr);
315315
316 // In case we do not import memory, but define it ourselves, set the316 // In case we do not import memory, but define it ourselves, set the
317 // minimum amount of pages on the memory section.317 // minimum amount of pages on the memory section.
...@@ -326,7 +326,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -326,7 +326,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
326 diags.addError("maximum memory value {d} insufficient; minimum {d}", .{ max_memory, memory_ptr });326 diags.addError("maximum memory value {d} insufficient; minimum {d}", .{ max_memory, memory_ptr });
327 }327 }
328 if (max_memory > std.math.maxInt(u32)) {328 if (max_memory > std.math.maxInt(u32)) {
329 diags.addError("maximum memory exceeds 32-bit address space", .{max_memory});329 diags.addError("maximum memory value {d} exceeds 32-bit address space", .{max_memory});
330 }330 }
331 if (diags.hasErrors()) return error.LinkFailure;331 if (diags.hasErrors()) return error.LinkFailure;
332 wasm.memories.limits.max = @intCast(max_memory / page_size);332 wasm.memories.limits.max = @intCast(max_memory / page_size);
...@@ -346,24 +346,26 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -346,24 +346,26 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
346 const binary_bytes = &f.binary_bytes;346 const binary_bytes = &f.binary_bytes;
347 assert(binary_bytes.items.len == 0);347 assert(binary_bytes.items.len == 0);
348348
349 try binary_bytes.appendSlice(gpa, std.wasm.magic ++ std.wasm.version);349 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);
350 assert(binary_bytes.items.len == 8);350 assert(binary_bytes.items.len == 8);
351351
352 const binary_writer = binary_bytes.writer(gpa);352 const binary_writer = binary_bytes.writer(gpa);
353353
354 // Type section354 // Type section
355 if (wasm.func_types.items.len != 0) {355 if (wasm.func_types.entries.len != 0) {
356 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);356 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
357 log.debug("Writing type section. Count: ({d})", .{wasm.func_types.items.len});357 log.debug("Writing type section. Count: ({d})", .{wasm.func_types.entries.len});
358 for (wasm.func_types.items) |func_type| {358 for (wasm.func_types.keys()) |func_type| {
359 try leb.writeUleb128(binary_writer, std.wasm.function_type);359 try leb.writeUleb128(binary_writer, std.wasm.function_type);
360 try leb.writeUleb128(binary_writer, @as(u32, @intCast(func_type.params.len)));360 const params = func_type.params.slice(wasm);
361 for (func_type.params) |param_ty| {361 try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len)));
362 try leb.writeUleb128(binary_writer, std.wasm.valtype(param_ty));362 for (params) |param_ty| {
363 try leb.writeUleb128(binary_writer, @intFromEnum(param_ty));
363 }364 }
364 try leb.writeUleb128(binary_writer, @as(u32, @intCast(func_type.returns.len)));365 const returns = func_type.returns.slice(wasm);
365 for (func_type.returns) |ret_ty| {366 try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len)));
366 try leb.writeUleb128(binary_writer, std.wasm.valtype(ret_ty));367 for (returns) |ret_ty| {
368 try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty));
367 }369 }
368 }370 }
369371
...@@ -372,19 +374,19 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -372,19 +374,19 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
372 header_offset,374 header_offset,
373 .type,375 .type,
374 @intCast(binary_bytes.items.len - header_offset - header_size),376 @intCast(binary_bytes.items.len - header_offset - header_size),
375 @intCast(wasm.func_types.items.len),377 @intCast(wasm.func_types.entries.len),
376 );378 );
377 section_index += 1;379 section_index += 1;
378 }380 }
379381
380 // Import section382 // Import section
381 const total_imports_len = wasm.function_imports.items.len + wasm.global_imports.items.len +383 const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len +
382 wasm.table_imports.items.len + wasm.memory_imports.items.len + @intFromBool(import_memory);384 wasm.table_imports.entries.len + wasm.memory_imports.items.len + @intFromBool(import_memory);
383385
384 if (total_imports_len > 0) {386 if (total_imports_len > 0) {
385 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);387 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
386388
387 for (wasm.function_imports.items) |*function_import| {389 for (wasm.function_imports.values()) |*function_import| {
388 const module_name = function_import.module_name.slice(wasm);390 const module_name = function_import.module_name.slice(wasm);
389 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));391 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
390 try binary_writer.writeAll(module_name);392 try binary_writer.writeAll(module_name);
...@@ -397,7 +399,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -397,7 +399,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
397 try leb.writeUleb128(binary_writer, function_import.index);399 try leb.writeUleb128(binary_writer, function_import.index);
398 }400 }
399401
400 for (wasm.table_imports.items) |*table_import| {402 for (wasm.table_imports.values()) |*table_import| {
401 const module_name = table_import.module_name.slice(wasm);403 const module_name = table_import.module_name.slice(wasm);
402 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));404 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
403 try binary_writer.writeAll(module_name);405 try binary_writer.writeAll(module_name);
...@@ -424,7 +426,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -424,7 +426,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
424 });426 });
425 }427 }
426428
427 for (wasm.global_imports.items) |*global_import| {429 for (wasm.global_imports.values()) |*global_import| {
428 const module_name = global_import.module_name.slice(wasm);430 const module_name = global_import.module_name.slice(wasm);
429 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));431 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
430 try binary_writer.writeAll(module_name);432 try binary_writer.writeAll(module_name);
...@@ -504,7 +506,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -504,7 +506,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
504 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);506 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
505507
506 for (wasm.output_globals.items) |global| {508 for (wasm.output_globals.items) |global| {
507 try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype));509 try binary_writer.writeByte(@intFromEnum(global.global_type.valtype));
508 try binary_writer.writeByte(@intFromBool(global.global_type.mutable));510 try binary_writer.writeByte(@intFromBool(global.global_type.mutable));
509 try emitInit(binary_writer, global.init);511 try emitInit(binary_writer, global.init);
510 }512 }
...@@ -841,7 +843,7 @@ fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void {...@@ -841,7 +843,7 @@ fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void {
841 buffer[offset..][0..buf.len].* = buf;843 buffer[offset..][0..buf.len].* = buf;
842}844}
843845
844fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!u32 {846fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
845 // unlike regular section, we don't emit the count847 // unlike regular section, we don't emit the count
846 const header_size = 1 + 5;848 const header_size = 1 + 5;
847 try bytes.appendNTimes(gpa, 0, header_size);849 try bytes.appendNTimes(gpa, 0, header_size);
...@@ -1099,12 +1101,12 @@ fn wantSegmentMerge(wasm: *const Wasm, a_index: Wasm.DataSegment.Index, b_index:...@@ -1099,12 +1101,12 @@ fn wantSegmentMerge(wasm: *const Wasm, a_index: Wasm.DataSegment.Index, b_index:
1099 if (a.flags.tls != b.flags.tls) return false;1101 if (a.flags.tls != b.flags.tls) return false;
1100 if (a.flags.is_passive != b.flags.is_passive) return false;1102 if (a.flags.is_passive != b.flags.is_passive) return false;
1101 if (a.name == b.name) return true;1103 if (a.name == b.name) return true;
1102 const a_prefix, _ = splitSegmentName(a.name.slice(wasm));1104 const a_prefix, _ = splitSegmentName(a.name.slice(wasm).?);
1103 const b_prefix, _ = splitSegmentName(b.name.slice(wasm));1105 const b_prefix, _ = splitSegmentName(b.name.slice(wasm).?);
1104 return a_prefix.len > 0 and mem.eql(u8, a_prefix, b_prefix);1106 return a_prefix.len > 0 and mem.eql(u8, a_prefix, b_prefix);
1105}1107}
11061108
1107fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!u32 {1109fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
1108 // section id + fixed leb contents size + fixed leb vector length1110 // section id + fixed leb contents size + fixed leb vector length
1109 const header_size = 1 + 5 + 5;1111 const header_size = 1 + 5 + 5;
1110 try bytes.appendNTimes(gpa, 0, header_size);1112 try bytes.appendNTimes(gpa, 0, header_size);
...@@ -1125,7 +1127,7 @@ fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {...@@ -1125,7 +1127,7 @@ fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
1125 if (limits.flags.has_max) try leb.writeUleb128(writer, limits.max);1127 if (limits.flags.has_max) try leb.writeUleb128(writer, limits.max);
1126}1128}
11271129
1128fn emitMemoryImport(wasm: *Wasm, writer: anytype, memory_import: *const Wasm.MemoryImport) error{OutOfMemory}!void {1130fn emitMemoryImport(wasm: *Wasm, writer: anytype, memory_import: *const Wasm.MemoryImport) Allocator.Error!void {
1129 const module_name = memory_import.module_name.slice(wasm);1131 const module_name = memory_import.module_name.slice(wasm);
1130 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));1132 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
1131 try writer.writeAll(module_name);1133 try writer.writeAll(module_name);
src/link/Wasm/Object.zig+111-79
...@@ -36,7 +36,7 @@ global_imports: RelativeSlice,...@@ -36,7 +36,7 @@ global_imports: RelativeSlice,
36table_imports: RelativeSlice,36table_imports: RelativeSlice,
37/// Points into Wasm object_custom_segments37/// Points into Wasm object_custom_segments
38custom_segments: RelativeSlice,38custom_segments: RelativeSlice,
39/// For calculating local section index from `Wasm.SectionIndex`.39/// For calculating local section index from `Wasm.ObjectSectionIndex`.
40local_section_index_base: u32,40local_section_index_base: u32,
41/// Points into Wasm object_init_funcs41/// Points into Wasm object_init_funcs
42init_funcs: RelativeSlice,42init_funcs: RelativeSlice,
...@@ -109,10 +109,10 @@ pub const Symbol = struct {...@@ -109,10 +109,10 @@ pub const Symbol = struct {
109 },109 },
110 data_import: void,110 data_import: void,
111 global: Wasm.ObjectGlobalIndex,111 global: Wasm.ObjectGlobalIndex,
112 global_import: Wasm.ObjectGlobalImportIndex,112 global_import: Wasm.GlobalImport.Index,
113 section: Wasm.ObjectSectionIndex,113 section: Wasm.ObjectSectionIndex,
114 table: Wasm.ObjectTableIndex,114 table: Wasm.ObjectTableIndex,
115 table_import: Wasm.ObjectTableImportIndex,115 table_import: Wasm.TableImport.Index,
116 };116 };
117};117};
118118
...@@ -159,7 +159,7 @@ pub const ScratchSpace = struct {...@@ -159,7 +159,7 @@ pub const ScratchSpace = struct {
159 }159 }
160};160};
161161
162fn parse(162pub fn parse(
163 wasm: *Wasm,163 wasm: *Wasm,
164 bytes: []const u8,164 bytes: []const u8,
165 path: Path,165 path: Path,
...@@ -181,18 +181,18 @@ fn parse(...@@ -181,18 +181,18 @@ fn parse(
181 pos += 4;181 pos += 4;
182182
183 const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len);183 const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len);
184 const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.items.len);184 const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.entries.len);
185 const functions_start: u32 = @intCast(wasm.object_functions.items.len);185 const functions_start: u32 = @intCast(wasm.object_functions.items.len);
186 const tables_start: u32 = @intCast(wasm.object_tables.items.len);186 const tables_start: u32 = @intCast(wasm.object_tables.items.len);
187 const memories_start: u32 = @intCast(wasm.object_memories.items.len);187 const memories_start: u32 = @intCast(wasm.object_memories.items.len);
188 const globals_start: u32 = @intCast(wasm.object_globals.items.len);188 const globals_start: u32 = @intCast(wasm.object_globals.items.len);
189 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);189 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);
190 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);190 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);
191 const function_imports_start: u32 = @intCast(wasm.object_function_imports.items.len);191 const function_imports_start: u32 = @intCast(wasm.object_function_imports.entries.len);
192 const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len);192 const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);
193 const table_imports_start: u32 = @intCast(wasm.object_table_imports.items.len);193 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);
194 const local_section_index_base = wasm.object_total_sections;194 const local_section_index_base = wasm.object_total_sections;
195 const source_location: Wasm.SourceLocation = .fromObjectIndex(wasm.objects.items.len);195 const source_location: Wasm.SourceLocation = .fromObject(@enumFromInt(wasm.objects.items.len), wasm);
196196
197 ss.clear();197 ss.clear();
198198
...@@ -200,10 +200,9 @@ fn parse(...@@ -200,10 +200,9 @@ fn parse(
200 var opt_features: ?Wasm.Feature.Set = null;200 var opt_features: ?Wasm.Feature.Set = null;
201 var saw_linking_section = false;201 var saw_linking_section = false;
202 var has_tls = false;202 var has_tls = false;
203 var local_section_index: u32 = 0;
204 var table_count: usize = 0;203 var table_count: usize = 0;
205 while (pos < bytes.len) : (local_section_index += 1) {204 while (pos < bytes.len) : (wasm.object_total_sections += 1) {
206 const section_index: Wasm.SectionIndex = @enumFromInt(local_section_index_base + local_section_index);205 const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections);
207206
208 const section_tag: std.wasm.Section = @enumFromInt(bytes[pos]);207 const section_tag: std.wasm.Section = @enumFromInt(bytes[pos]);
209 pos += 1;208 pos += 1;
...@@ -245,7 +244,7 @@ fn parse(...@@ -245,7 +244,7 @@ fn parse(
245 .strings = flags.strings,244 .strings = flags.strings,
246 .tls = tls,245 .tls = tls,
247 .alignment = @enumFromInt(alignment),246 .alignment = @enumFromInt(alignment),
248 .no_strip = flags.retain,247 .retain = flags.retain,
249 },248 },
250 };249 };
251 }250 }
...@@ -257,13 +256,13 @@ fn parse(...@@ -257,13 +256,13 @@ fn parse(
257 if (symbol_index > ss.symbol_table.items.len)256 if (symbol_index > ss.symbol_table.items.len)
258 return diags.failParse(path, "init_funcs before symbol table", .{});257 return diags.failParse(path, "init_funcs before symbol table", .{});
259 const sym = &ss.symbol_table.items[symbol_index];258 const sym = &ss.symbol_table.items[symbol_index];
260 if (sym.tag != .function) {259 if (sym.pointee != .function) {
261 return diags.failParse(path, "init_func symbol '{s}' not a function", .{260 return diags.failParse(path, "init_func symbol '{s}' not a function", .{
262 wasm.stringSlice(sym.name),261 sym.name.slice(wasm).?,
263 });262 });
264 } else if (sym.flags.undefined) {263 } else if (sym.flags.undefined) {
265 return diags.failParse(path, "init_func symbol '{s}' is an import", .{264 return diags.failParse(path, "init_func symbol '{s}' is an import", .{
266 wasm.stringSlice(sym.name),265 sym.name.slice(wasm).?,
267 });266 });
268 }267 }
269 func.* = .{268 func.* = .{
...@@ -278,22 +277,23 @@ fn parse(...@@ -278,22 +277,23 @@ fn parse(
278 const flags, pos = readLeb(u32, bytes, pos);277 const flags, pos = readLeb(u32, bytes, pos);
279 if (flags != 0) return error.UnexpectedComdatFlags;278 if (flags != 0) return error.UnexpectedComdatFlags;
280 const symbol_count, pos = readLeb(u32, bytes, pos);279 const symbol_count, pos = readLeb(u32, bytes, pos);
281 const start_off: u32 = @intCast(wasm.object_comdat_symbols.items.len);280 const start_off: u32 = @intCast(wasm.object_comdat_symbols.len);
282 for (try wasm.object_comdat_symbols.addManyAsSlice(gpa, symbol_count)) |*symbol| {281 try wasm.object_comdat_symbols.ensureUnusedCapacity(gpa, symbol_count);
282 for (0..symbol_count) |_| {
283 const kind, pos = readEnum(Wasm.Comdat.Symbol.Type, bytes, pos);283 const kind, pos = readEnum(Wasm.Comdat.Symbol.Type, bytes, pos);
284 const index, pos = readLeb(u32, bytes, pos);284 const index, pos = readLeb(u32, bytes, pos);
285 if (true) @panic("TODO rebase index depending on kind");285 if (true) @panic("TODO rebase index depending on kind");
286 symbol.* = .{286 wasm.object_comdat_symbols.appendAssumeCapacity(.{
287 .kind = kind,287 .kind = kind,
288 .index = index,288 .index = index,
289 };289 });
290 }290 }
291 comdat.* = .{291 comdat.* = .{
292 .name = try wasm.internString(name),292 .name = try wasm.internString(name),
293 .flags = flags,293 .flags = flags,
294 .symbols = .{294 .symbols = .{
295 .off = start_off,295 .off = start_off,
296 .len = @intCast(wasm.object_comdat_symbols.items.len - start_off),296 .len = @intCast(wasm.object_comdat_symbols.len - start_off),
297 },297 },
298 };298 };
299 }299 }
...@@ -321,7 +321,7 @@ fn parse(...@@ -321,7 +321,7 @@ fn parse(
321 const size, pos = readLeb(u32, bytes, pos);321 const size, pos = readLeb(u32, bytes, pos);
322322
323 symbol.pointee = .{ .data = .{323 symbol.pointee = .{ .data = .{
324 .index = @enumFromInt(data_segment_start + segment_index),324 .segment_index = @enumFromInt(data_segment_start + segment_index),
325 .segment_offset = segment_offset,325 .segment_offset = segment_offset,
326 .size = size,326 .size = size,
327 } };327 } };
...@@ -329,7 +329,7 @@ fn parse(...@@ -329,7 +329,7 @@ fn parse(
329 },329 },
330 .section => {330 .section => {
331 const local_section, pos = readLeb(u32, bytes, pos);331 const local_section, pos = readLeb(u32, bytes, pos);
332 const section: Wasm.SectionIndex = @enumFromInt(local_section_index_base + local_section);332 const section: Wasm.ObjectSectionIndex = @enumFromInt(local_section_index_base + local_section);
333 symbol.pointee = .{ .section = section };333 symbol.pointee = .{ .section = section };
334 },334 },
335335
...@@ -337,7 +337,7 @@ fn parse(...@@ -337,7 +337,7 @@ fn parse(
337 const local_index, pos = readLeb(u32, bytes, pos);337 const local_index, pos = readLeb(u32, bytes, pos);
338 if (symbol.flags.undefined) {338 if (symbol.flags.undefined) {
339 symbol.pointee = .{ .function_import = @enumFromInt(local_index) };339 symbol.pointee = .{ .function_import = @enumFromInt(local_index) };
340 if (flags.explicit_name) {340 if (symbol.flags.explicit_name) {
341 const name, pos = readBytes(bytes, pos);341 const name, pos = readBytes(bytes, pos);
342 symbol.name = (try wasm.internString(name)).toOptional();342 symbol.name = (try wasm.internString(name)).toOptional();
343 }343 }
...@@ -351,7 +351,7 @@ fn parse(...@@ -351,7 +351,7 @@ fn parse(
351 const local_index, pos = readLeb(u32, bytes, pos);351 const local_index, pos = readLeb(u32, bytes, pos);
352 if (symbol.flags.undefined) {352 if (symbol.flags.undefined) {
353 symbol.pointee = .{ .global_import = @enumFromInt(global_imports_start + local_index) };353 symbol.pointee = .{ .global_import = @enumFromInt(global_imports_start + local_index) };
354 if (flags.explicit_name) {354 if (symbol.flags.explicit_name) {
355 const name, pos = readBytes(bytes, pos);355 const name, pos = readBytes(bytes, pos);
356 symbol.name = (try wasm.internString(name)).toOptional();356 symbol.name = (try wasm.internString(name)).toOptional();
357 }357 }
...@@ -366,7 +366,7 @@ fn parse(...@@ -366,7 +366,7 @@ fn parse(
366 const local_index, pos = readLeb(u32, bytes, pos);366 const local_index, pos = readLeb(u32, bytes, pos);
367 if (symbol.flags.undefined) {367 if (symbol.flags.undefined) {
368 symbol.pointee = .{ .table_import = @enumFromInt(table_imports_start + local_index) };368 symbol.pointee = .{ .table_import = @enumFromInt(table_imports_start + local_index) };
369 if (flags.explicit_name) {369 if (symbol.flags.explicit_name) {
370 const name, pos = readBytes(bytes, pos);370 const name, pos = readBytes(bytes, pos);
371 symbol.name = (try wasm.internString(name)).toOptional();371 symbol.name = (try wasm.internString(name)).toOptional();
372 }372 }
...@@ -377,7 +377,7 @@ fn parse(...@@ -377,7 +377,7 @@ fn parse(
377 }377 }
378 },378 },
379 else => {379 else => {
380 log.debug("unrecognized symbol type tag: {x}", .{tag});380 log.debug("unrecognized symbol type tag: {x}", .{@intFromEnum(tag)});
381 return error.UnrecognizedSymbolType;381 return error.UnrecognizedSymbolType;
382 },382 },
383 }383 }
...@@ -396,14 +396,14 @@ fn parse(...@@ -396,14 +396,14 @@ fn parse(
396 // "Relocation sections can only target code, data and custom sections."396 // "Relocation sections can only target code, data and custom sections."
397 const local_section, pos = readLeb(u32, bytes, pos);397 const local_section, pos = readLeb(u32, bytes, pos);
398 const count, pos = readLeb(u32, bytes, pos);398 const count, pos = readLeb(u32, bytes, pos);
399 const section: Wasm.SectionIndex = @enumFromInt(local_section_index_base + local_section);399 const section: Wasm.ObjectSectionIndex = @enumFromInt(local_section_index_base + local_section);
400400
401 log.debug("found {d} relocations for section={d}", .{ count, section });401 log.debug("found {d} relocations for section={d}", .{ count, section });
402402
403 var prev_offset: u32 = 0;403 var prev_offset: u32 = 0;
404 try wasm.relocations.ensureUnusedCapacity(gpa, count);404 try wasm.object_relocations.ensureUnusedCapacity(gpa, count);
405 for (0..count) |_| {405 for (0..count) |_| {
406 const tag: Wasm.Relocation.Tag = @enumFromInt(bytes[pos]);406 const tag: Wasm.ObjectRelocation.Tag = @enumFromInt(bytes[pos]);
407 pos += 1;407 pos += 1;
408 const offset, pos = readLeb(u32, bytes, pos);408 const offset, pos = readLeb(u32, bytes, pos);
409 const index, pos = readLeb(u32, bytes, pos);409 const index, pos = readLeb(u32, bytes, pos);
...@@ -426,9 +426,10 @@ fn parse(...@@ -426,9 +426,10 @@ fn parse(
426 .MEMORY_ADDR_TLS_SLEB64,426 .MEMORY_ADDR_TLS_SLEB64,
427 .FUNCTION_OFFSET_I32,427 .FUNCTION_OFFSET_I32,
428 .SECTION_OFFSET_I32,428 .SECTION_OFFSET_I32,
429 .FUNCTION_OFFSET_I64,
429 => {430 => {
430 const addend: i32, pos = readLeb(i32, bytes, pos);431 const addend: i32, pos = readLeb(i32, bytes, pos);
431 wasm.relocations.appendAssumeCapacity(.{432 wasm.object_relocations.appendAssumeCapacity(.{
432 .tag = tag,433 .tag = tag,
433 .offset = offset,434 .offset = offset,
434 .pointee = .{ .section = ss.symbol_table.items[index].pointee.section },435 .pointee = .{ .section = ss.symbol_table.items[index].pointee.section },
...@@ -436,7 +437,7 @@ fn parse(...@@ -436,7 +437,7 @@ fn parse(
436 });437 });
437 },438 },
438 .TYPE_INDEX_LEB => {439 .TYPE_INDEX_LEB => {
439 wasm.relocations.appendAssumeCapacity(.{440 wasm.object_relocations.appendAssumeCapacity(.{
440 .tag = tag,441 .tag = tag,
441 .offset = offset,442 .offset = offset,
442 .pointee = .{ .type_index = ss.func_types.items[index] },443 .pointee = .{ .type_index = ss.func_types.items[index] },
...@@ -444,9 +445,19 @@ fn parse(...@@ -444,9 +445,19 @@ fn parse(
444 });445 });
445 },446 },
446 .FUNCTION_INDEX_LEB,447 .FUNCTION_INDEX_LEB,
448 .FUNCTION_INDEX_I32,
447 .GLOBAL_INDEX_LEB,449 .GLOBAL_INDEX_LEB,
450 .GLOBAL_INDEX_I32,
451 .TABLE_INDEX_SLEB,
452 .TABLE_INDEX_I32,
453 .TABLE_INDEX_SLEB64,
454 .TABLE_INDEX_I64,
455 .TABLE_NUMBER_LEB,
456 .TABLE_INDEX_REL_SLEB,
457 .TABLE_INDEX_REL_SLEB64,
458 .TAG_INDEX_LEB,
448 => {459 => {
449 wasm.relocations.appendAssumeCapacity(.{460 wasm.object_relocations.appendAssumeCapacity(.{
450 .tag = tag,461 .tag = tag,
451 .offset = offset,462 .offset = offset,
452 .pointee = .{ .symbol_name = ss.symbol_table.items[index].name.unwrap().? },463 .pointee = .{ .symbol_name = ss.symbol_table.items[index].name.unwrap().? },
...@@ -457,7 +468,7 @@ fn parse(...@@ -457,7 +468,7 @@ fn parse(
457 }468 }
458469
459 try wasm.object_relocations_table.putNoClobber(gpa, section, .{470 try wasm.object_relocations_table.putNoClobber(gpa, section, .{
460 .off = @intCast(wasm.relocations.items.len - count),471 .off = @intCast(wasm.object_relocations.len - count),
461 .len = count,472 .len = count,
462 });473 });
463 } else if (std.mem.eql(u8, section_name, "target_features")) {474 } else if (std.mem.eql(u8, section_name, "target_features")) {
...@@ -466,15 +477,15 @@ fn parse(...@@ -466,15 +477,15 @@ fn parse(
466 const debug_content = bytes[pos..section_end];477 const debug_content = bytes[pos..section_end];
467 pos = section_end;478 pos = section_end;
468479
469 const data_off: u32 = @enumFromInt(wasm.string_bytes.items.len);480 const data_off: u32 = @intCast(wasm.string_bytes.items.len);
470 try wasm.string_bytes.appendSlice(gpa, debug_content);481 try wasm.string_bytes.appendSlice(gpa, debug_content);
471482
472 try wasm.object_custom_segments.put(gpa, section_index, .{483 try wasm.object_custom_segments.put(gpa, section_index, .{
473 .data_off = data_off,484 .payload = .{
474 .flags = .{485 .off = data_off,
475 .data_len = @intCast(debug_content.len),486 .len = @intCast(debug_content.len),
476 .represented = false, // set when scanning symbol table
477 },487 },
488 .flags = .{},
478 .section_name = try wasm.internString(section_name),489 .section_name = try wasm.internString(section_name),
479 });490 });
480 } else {491 } else {
...@@ -483,7 +494,7 @@ fn parse(...@@ -483,7 +494,7 @@ fn parse(
483 },494 },
484 .type => {495 .type => {
485 const func_types_len, pos = readLeb(u32, bytes, pos);496 const func_types_len, pos = readLeb(u32, bytes, pos);
486 for (ss.func_types.addManyAsSlice(gpa, func_types_len)) |*func_type| {497 for (try ss.func_types.addManyAsSlice(gpa, func_types_len)) |*func_type| {
487 if (bytes[pos] != std.wasm.function_type) return error.ExpectedFuncType;498 if (bytes[pos] != std.wasm.function_type) return error.ExpectedFuncType;
488 pos += 1;499 pos += 1;
489500
...@@ -509,7 +520,7 @@ fn parse(...@@ -509,7 +520,7 @@ fn parse(
509 try ss.func_imports.append(gpa, .{520 try ss.func_imports.append(gpa, .{
510 .module_name = interned_module_name,521 .module_name = interned_module_name,
511 .name = interned_name,522 .name = interned_name,
512 .index = function,523 .function_index = @enumFromInt(function),
513 });524 });
514 },525 },
515 .memory => {526 .memory => {
...@@ -527,24 +538,32 @@ fn parse(...@@ -527,24 +538,32 @@ fn parse(
527 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);538 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
528 const mutable = bytes[pos] == 0x01;539 const mutable = bytes[pos] == 0x01;
529 pos += 1;540 pos += 1;
530 try wasm.object_global_imports.append(gpa, .{541 try wasm.object_global_imports.put(gpa, interned_name, .{
542 .flags = .{
543 .global_type = .{
544 .valtype = .from(valtype),
545 .mutable = mutable,
546 },
547 },
531 .module_name = interned_module_name,548 .module_name = interned_module_name,
532 .name = interned_name,549 .source_location = source_location,
533 .mutable = mutable,550 .resolution = .unresolved,
534 .valtype = valtype,
535 });551 });
536 },552 },
537 .table => {553 .table => {
538 const reftype, pos = readEnum(std.wasm.RefType, bytes, pos);554 const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos);
539 const limits, pos = readLimits(bytes, pos);555 const limits, pos = readLimits(bytes, pos);
540 try wasm.object_table_imports.append(gpa, .{556 try wasm.object_table_imports.put(gpa, interned_name, .{
557 .flags = .{
558 .limits_has_max = limits.flags.has_max,
559 .limits_is_shared = limits.flags.is_shared,
560 .ref_type = .from(ref_type),
561 },
541 .module_name = interned_module_name,562 .module_name = interned_module_name,
542 .name = interned_name,563 .source_location = source_location,
564 .resolution = .unresolved,
543 .limits_min = limits.min,565 .limits_min = limits.min,
544 .limits_max = limits.max,566 .limits_max = limits.max,
545 .limits_has_max = limits.flags.has_max,
546 .limits_is_shared = limits.flags.is_shared,
547 .reftype = reftype,
548 });567 });
549 },568 },
550 }569 }
...@@ -553,17 +572,25 @@ fn parse(...@@ -553,17 +572,25 @@ fn parse(
553 .function => {572 .function => {
554 const functions_len, pos = readLeb(u32, bytes, pos);573 const functions_len, pos = readLeb(u32, bytes, pos);
555 for (try ss.func_type_indexes.addManyAsSlice(gpa, functions_len)) |*func_type_index| {574 for (try ss.func_type_indexes.addManyAsSlice(gpa, functions_len)) |*func_type_index| {
556 func_type_index.*, pos = readLeb(u32, bytes, pos);575 const i, pos = readLeb(u32, bytes, pos);
576 func_type_index.* = @enumFromInt(i);
557 }577 }
558 },578 },
559 .table => {579 .table => {
560 const tables_len, pos = readLeb(u32, bytes, pos);580 const tables_len, pos = readLeb(u32, bytes, pos);
561 for (try wasm.object_tables.addManyAsSlice(gpa, tables_len)) |*table| {581 for (try wasm.object_tables.addManyAsSlice(gpa, tables_len)) |*table| {
562 const reftype, pos = readEnum(std.wasm.RefType, bytes, pos);582 const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos);
563 const limits, pos = readLimits(bytes, pos);583 const limits, pos = readLimits(bytes, pos);
564 table.* = .{584 table.* = .{
565 .reftype = reftype,585 .name = .none,
566 .limits = limits,586 .module_name = .none,
587 .flags = .{
588 .ref_type = .from(ref_type),
589 .limits_has_max = limits.flags.has_max,
590 .limits_is_shared = limits.flags.is_shared,
591 },
592 .limits_min = limits.min,
593 .limits_max = limits.max,
567 };594 };
568 }595 }
569 },596 },
...@@ -582,8 +609,13 @@ fn parse(...@@ -582,8 +609,13 @@ fn parse(
582 pos += 1;609 pos += 1;
583 const expr, pos = try readInit(wasm, bytes, pos);610 const expr, pos = try readInit(wasm, bytes, pos);
584 global.* = .{611 global.* = .{
585 .valtype = valtype,612 .name = .none,
586 .mutable = mutable,613 .flags = .{
614 .global_type = .{
615 .valtype = .from(valtype),
616 .mutable = mutable,
617 },
618 },
587 .expr = expr,619 .expr = expr,
588 };620 };
589 }621 }
...@@ -668,8 +700,6 @@ fn parse(...@@ -668,8 +700,6 @@ fn parse(
668 }700 }
669 if (!saw_linking_section) return error.MissingLinkingSection;701 if (!saw_linking_section) return error.MissingLinkingSection;
670702
671 wasm.object_total_sections = local_section_index_base + local_section_index;
672
673 if (has_tls) {703 if (has_tls) {
674 const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features;704 const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features;
675 if (!std.Target.wasm.featureSetHas(cpu_features, .atomics))705 if (!std.Target.wasm.featureSetHas(cpu_features, .atomics))
...@@ -770,7 +800,7 @@ fn parse(...@@ -770,7 +800,7 @@ fn parse(
770 ptr.name = symbol.name;800 ptr.name = symbol.name;
771 ptr.flags = symbol.flags;801 ptr.flags = symbol.flags;
772 if (symbol.flags.undefined and symbol.flags.binding == .local) {802 if (symbol.flags.undefined and symbol.flags.binding == .local) {
773 const name = wasm.stringSlice(ptr.name.unwrap().?);803 const name = ptr.name.slice(wasm).?;
774 diags.addParseError(path, "local symbol '{s}' references import", .{name});804 diags.addParseError(path, "local symbol '{s}' references import", .{name});
775 }805 }
776 },806 },
...@@ -779,7 +809,7 @@ fn parse(...@@ -779,7 +809,7 @@ fn parse(
779 const ptr = i.ptr(wasm);809 const ptr = i.ptr(wasm);
780 ptr.flags = symbol.flags;810 ptr.flags = symbol.flags;
781 if (symbol.flags.undefined and symbol.flags.binding == .local) {811 if (symbol.flags.undefined and symbol.flags.binding == .local) {
782 const name = wasm.stringSlice(ptr.name);812 const name = ptr.name.slice(wasm);
783 diags.addParseError(path, "local symbol '{s}' references import", .{name});813 diags.addParseError(path, "local symbol '{s}' references import", .{name});
784 }814 }
785 },815 },
...@@ -806,19 +836,20 @@ fn parse(...@@ -806,19 +836,20 @@ fn parse(
806 data.flags.no_strip = info.flags.retain;836 data.flags.no_strip = info.flags.retain;
807 data.flags.alignment = info.flags.alignment;837 data.flags.alignment = info.flags.alignment;
808 if (data.flags.undefined and data.flags.binding == .local) {838 if (data.flags.undefined and data.flags.binding == .local) {
809 const name = wasm.stringSlice(info.name);839 const name = info.name.slice(wasm);
810 diags.addParseError(path, "local symbol '{s}' references import", .{name});840 diags.addParseError(path, "local symbol '{s}' references import", .{name});
811 }841 }
812 }842 }
813843
814 // Check for indirect function table in case of an MVP object file.844 // Check for indirect function table in case of an MVP object file.
815 legacy_indirect_function_table: {845 legacy_indirect_function_table: {
816 const table_imports = wasm.object_table_imports.items[table_imports_start..];846 const table_import_names = wasm.object_table_imports.keys()[table_imports_start..];
847 const table_import_values = wasm.object_table_imports.values()[table_imports_start..];
817 // If there is a symbol for each import table, this is not a legacy object file.848 // If there is a symbol for each import table, this is not a legacy object file.
818 if (table_imports.len == table_count) break :legacy_indirect_function_table;849 if (table_import_names.len == table_count) break :legacy_indirect_function_table;
819 if (table_count != 0) {850 if (table_count != 0) {
820 return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{851 return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{
821 table_imports.len, table_count,852 table_import_names.len, table_count,
822 });853 });
823 }854 }
824 // MVP object files cannot have any table definitions, only855 // MVP object files cannot have any table definitions, only
...@@ -827,16 +858,16 @@ fn parse(...@@ -827,16 +858,16 @@ fn parse(
827 if (tables.len > 0) {858 if (tables.len > 0) {
828 return diags.failParse(path, "table definition without representing table symbols", .{});859 return diags.failParse(path, "table definition without representing table symbols", .{});
829 }860 }
830 if (table_imports.len != 1) {861 if (table_import_names.len != 1) {
831 return diags.failParse(path, "found more than one table import, but no representing table symbols", .{});862 return diags.failParse(path, "found more than one table import, but no representing table symbols", .{});
832 }863 }
833 const table_import_name = table_imports[0].name;864 const table_import_name = table_import_names[0];
834 if (table_import_name != wasm.preloaded_strings.__indirect_function_table) {865 if (table_import_name != wasm.preloaded_strings.__indirect_function_table) {
835 return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{866 return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
836 wasm.stringSlice(table_import_name),867 table_import_name.slice(wasm),
837 });868 });
838 }869 }
839 table_imports[0].flags = .{870 table_import_values[0].flags = .{
840 .undefined = true,871 .undefined = true,
841 .no_strip = true,872 .no_strip = true,
842 };873 };
...@@ -874,11 +905,11 @@ fn parse(...@@ -874,11 +905,11 @@ fn parse(
874 },905 },
875 .function_imports = .{906 .function_imports = .{
876 .off = function_imports_start,907 .off = function_imports_start,
877 .len = @intCast(wasm.object_function_imports.items.len - function_imports_start),908 .len = @intCast(wasm.object_function_imports.entries.len - function_imports_start),
878 },909 },
879 .global_imports = .{910 .global_imports = .{
880 .off = global_imports_start,911 .off = global_imports_start,
881 .len = @intCast(wasm.object_global_imports.items.len - global_imports_start),912 .len = @intCast(wasm.object_global_imports.entries.len - global_imports_start),
882 },913 },
883 .table_imports = .{914 .table_imports = .{
884 .off = table_imports_start,915 .off = table_imports_start,
...@@ -894,7 +925,7 @@ fn parse(...@@ -894,7 +925,7 @@ fn parse(
894 },925 },
895 .custom_segments = .{926 .custom_segments = .{
896 .off = custom_segment_start,927 .off = custom_segment_start,
897 .len = @intCast(wasm.object_custom_segments.items.len - custom_segment_start),928 .len = @intCast(wasm.object_custom_segments.entries.len - custom_segment_start),
898 },929 },
899 .local_section_index_base = local_section_index_base,930 .local_section_index_base = local_section_index_base,
900 };931 };
...@@ -920,7 +951,7 @@ fn parseFeatures(...@@ -920,7 +951,7 @@ fn parseFeatures(
920 '-' => .@"-",951 '-' => .@"-",
921 '+' => .@"+",952 '+' => .@"+",
922 '=' => .@"=",953 '=' => .@"=",
923 else => return error.InvalidFeaturePrefix,954 else => |b| return diags.failParse(path, "invalid feature prefix: 0x{x}", .{b}),
924 };955 };
925 pos += 1;956 pos += 1;
926 const name, pos = readBytes(bytes, pos);957 const name, pos = readBytes(bytes, pos);
...@@ -935,7 +966,7 @@ fn parseFeatures(...@@ -935,7 +966,7 @@ fn parseFeatures(
935 std.mem.sortUnstable(Wasm.Feature, feature_buffer, {}, Wasm.Feature.lessThan);966 std.mem.sortUnstable(Wasm.Feature, feature_buffer, {}, Wasm.Feature.lessThan);
936967
937 return .{968 return .{
938 .fromString(try wasm.internString(@bitCast(feature_buffer))),969 .fromString(try wasm.internString(@ptrCast(feature_buffer))),
939 pos,970 pos,
940 };971 };
941}972}
...@@ -966,9 +997,9 @@ fn readEnum(comptime T: type, bytes: []const u8, pos: usize) struct { T, usize }...@@ -966,9 +997,9 @@ fn readEnum(comptime T: type, bytes: []const u8, pos: usize) struct { T, usize }
966}997}
967998
968fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usize } {999fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usize } {
969 const flags = bytes[start_pos];1000 const flags: std.wasm.Limits.Flags = @bitCast(bytes[start_pos]);
970 const min, const max_pos = readLeb(u32, bytes, start_pos + 1);1001 const min, const max_pos = readLeb(u32, bytes, start_pos + 1);
971 const max, const end_pos = if (flags.has_max) readLeb(u32, bytes, max_pos) else .{ undefined, max_pos };1002 const max, const end_pos = if (flags.has_max) readLeb(u32, bytes, max_pos) else .{ 0, max_pos };
972 return .{ .{1003 return .{ .{
973 .flags = flags,1004 .flags = flags,
974 .min = min,1005 .min = min,
...@@ -977,7 +1008,7 @@ fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usi...@@ -977,7 +1008,7 @@ fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usi
977}1008}
9781009
979fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usize } {1010fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usize } {
980 const end_pos = skipInit(bytes, pos); // one after the end opcode1011 const end_pos = try skipInit(bytes, pos); // one after the end opcode
981 return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos };1012 return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos };
982}1013}
9831014
...@@ -991,6 +1022,7 @@ fn skipInit(bytes: []const u8, pos: usize) !usize {...@@ -991,6 +1022,7 @@ fn skipInit(bytes: []const u8, pos: usize) !usize {
991 .global_get => readLeb(u32, bytes, pos + 1)[1],1022 .global_get => readLeb(u32, bytes, pos + 1)[1],
992 else => return error.InvalidInitOpcode,1023 else => return error.InvalidInitOpcode,
993 };1024 };
994 if (readEnum(std.wasm.Opcode, bytes, end_pos) != .end) return error.InitExprMissingEnd;1025 const op, const final_pos = readEnum(std.wasm.Opcode, bytes, end_pos);
995 return end_pos + 1;1026 if (op != .end) return error.InitExprMissingEnd;
1027 return final_pos;
996}1028}