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 {
8989 if (is_obj) {
9090 try wasm.out_relocs.append(gpa, .{
9191 .offset = @intCast(code.items.len),
92 .index = try wasm.errorNameTableSymbolIndex(),
92 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },
9393 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
9494 .addend = 0,
9595 });
......@@ -143,7 +143,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
143143 if (is_obj) {
144144 try wasm.out_relocs.append(gpa, .{
145145 .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) },
147147 .tag = .FUNCTION_INDEX_LEB,
148148 .addend = 0,
149149 });
......@@ -164,7 +164,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
164164 if (is_obj) {
165165 try wasm.out_relocs.append(gpa, .{
166166 .offset = @intCast(code.items.len),
167 .index = func_ty_index,
167 .pointee = .{ .type_index = func_ty_index },
168168 .tag = .TYPE_INDEX_LEB,
169169 .addend = 0,
170170 });
......@@ -184,7 +184,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
184184 if (is_obj) {
185185 try wasm.out_relocs.append(gpa, .{
186186 .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) },
188188 .tag = .FUNCTION_INDEX_LEB,
189189 .addend = 0,
190190 });
......@@ -209,7 +209,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
209209 if (is_obj) {
210210 try wasm.out_relocs.append(gpa, .{
211211 .offset = @intCast(code.items.len),
212 .index = try wasm.symbolNameIndex(symbol_name),
212 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },
213213 .tag = .FUNCTION_INDEX_LEB,
214214 .addend = 0,
215215 });
......@@ -229,7 +229,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
229229 if (is_obj) {
230230 try wasm.out_relocs.append(gpa, .{
231231 .offset = @intCast(code.items.len),
232 .index = try wasm.stackPointerSymbolIndex(),
232 .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },
233233 .tag = .GLOBAL_INDEX_LEB,
234234 .addend = 0,
235235 });
......@@ -249,7 +249,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
249249 if (is_obj) {
250250 try wasm.out_relocs.append(gpa, .{
251251 .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) },
253253 .tag = .TABLE_INDEX_SLEB,
254254 .addend = 0,
255255 });
......@@ -691,7 +691,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
691691 if (is_obj) {
692692 try wasm.out_relocs.append(gpa, .{
693693 .offset = @intCast(code.items.len),
694 .index = try wasm.uavSymbolIndex(data.ip_index),
694 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.ip_index) },
695695 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
696696 .addend = data.offset,
697697 });
......@@ -700,7 +700,7 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
700700 }
701701
702702 // 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);
704704 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
705705}
706706
......@@ -720,13 +720,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
720720 if (is_obj) {
721721 try wasm.out_relocs.append(gpa, .{
722722 .offset = @intCast(code.items.len),
723 .index = try wasm.navSymbolIndex(data.nav_index),
723 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
724724 .tag = .TABLE_INDEX_SLEB,
725725 .addend = data.offset,
726726 });
727727 code.appendNTimesAssumeCapacity(0, 5);
728728 } else {
729 const addr: i64 = try wasm.navAddr(data.nav_index);
729 const addr = try wasm.navAddr(data.nav_index);
730730 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
731731 }
732732 } else {
......@@ -735,13 +735,13 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
735735 if (is_obj) {
736736 try wasm.out_relocs.append(gpa, .{
737737 .offset = @intCast(code.items.len),
738 .index = try wasm.navSymbolIndex(data.nav_index),
738 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
739739 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
740740 .addend = data.offset,
741741 });
742742 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
743743 } else {
744 const addr: i64 = try wasm.navAddr(data.nav_index);
744 const addr = try wasm.navAddr(data.nav_index);
745745 leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
746746 }
747747 }
src/codegen.zig+47-27
......@@ -2,7 +2,6 @@ const std = @import("std");
22const build_options = @import("build_options");
33const builtin = @import("builtin");
44const assert = std.debug.assert;
5const leb128 = std.leb;
65const link = @import("link.zig");
76const log = std.log.scoped(.codegen);
87const mem = std.mem;
......@@ -643,15 +642,19 @@ fn lowerUavRef(
643642 const zcu = pt.zcu;
644643 const gpa = zcu.gpa;
645644 const ip = &zcu.intern_pool;
646 const target = lf.comp.root_mod.resolved_target.result;
647
645 const comp = lf.comp;
646 const target = &comp.root_mod.resolved_target.result;
648647 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
648 const is_obj = comp.config.output_mode == .Obj;
649649 const uav_val = uav.val;
650650 const uav_ty = Type.fromInterned(ip.typeOf(uav_val));
651 log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)});
652651 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
653656 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);
655658 return;
656659 }
657660
......@@ -663,13 +666,20 @@ fn lowerUavRef(
663666 dev.check(link.File.Tag.wasm.devFeature());
664667 const wasm = lf.cast(.wasm).?;
665668 assert(reloc_parent == .none);
666 try wasm.relocations.append(gpa, .{
667 .tag = .uav_index,
668 .addend = @intCast(offset),
669 .offset = @intCast(code.items.len),
670 .pointee = .{ .uav_index = uav.val },
671 });
672 try code.appendNTimes(gpa, 0, ptr_width_bytes);
669 if (is_obj) {
670 try wasm.out_relocs.append(gpa, .{
671 .offset = @intCast(code.items.len),
672 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) },
673 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
674 .addend = @intCast(offset),
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);
673683 return;
674684 },
675685 else => {},
......@@ -688,9 +698,9 @@ fn lowerUavRef(
688698 });
689699 const endian = target.cpu.arch.endian();
690700 switch (ptr_width_bytes) {
691 2 => mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(vaddr), endian),
692 4 => mem.writeInt(u32, try code.addManyAsArray(gpa, 4), @intCast(vaddr), endian),
693 8 => mem.writeInt(u64, try code.addManyAsArray(gpa, 8), vaddr, endian),
701 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),
702 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),
703 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),
694704 else => unreachable,
695705 }
696706}
......@@ -709,12 +719,15 @@ fn lowerNavRef(
709719 const gpa = zcu.gpa;
710720 const ip = &zcu.intern_pool;
711721 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
712
713722 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
723 const is_obj = lf.comp.config.output_mode == .Obj;
714724 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
715725 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
726
727 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
728
716729 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);
718731 return;
719732 }
720733
......@@ -726,13 +739,20 @@ fn lowerNavRef(
726739 dev.check(link.File.Tag.wasm.devFeature());
727740 const wasm = lf.cast(.wasm).?;
728741 assert(reloc_parent == .none);
729 try wasm.relocations.append(gpa, .{
730 .tag = .nav_index,
731 .addend = @intCast(offset),
732 .offset = @intCast(code.items.len),
733 .pointee = .{ .nav_index = nav_index },
734 });
735 try code.appendNTimes(gpa, 0, ptr_width_bytes);
742 if (is_obj) {
743 try wasm.out_relocs.append(gpa, .{
744 .offset = @intCast(code.items.len),
745 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
746 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
747 .addend = @intCast(offset),
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);
736756 return;
737757 },
738758 else => {},
......@@ -745,9 +765,9 @@ fn lowerNavRef(
745765 }) catch @panic("TODO rework getNavVAddr");
746766 const endian = target.cpu.arch.endian();
747767 switch (ptr_width_bytes) {
748 2 => mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(vaddr), endian),
749 4 => mem.writeInt(u32, try code.addManyAsArray(gpa, 4), @intCast(vaddr), endian),
750 8 => mem.writeInt(u64, try code.addManyAsArray(gpa, 8), vaddr, endian),
768 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),
769 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),
770 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),
751771 else => unreachable,
752772 }
753773}
src/link/Wasm.zig+324-95
......@@ -100,7 +100,7 @@ object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .em
100100object_globals: std.ArrayListUnmanaged(Global) = .empty,
101101
102102/// All table imports for all objects.
103object_table_imports: std.ArrayListUnmanaged(TableImport) = .empty,
103object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty,
104104/// All parsed table sections for all objects.
105105object_tables: std.ArrayListUnmanaged(Table) = .empty,
106106
......@@ -109,12 +109,28 @@ object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,
109109/// All parsed memory sections for all objects.
110110object_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
112116/// List of initialization functions. These must be called in order of priority
113117/// by the (synthetic) __wasm_call_ctors function.
114118object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
115/// All relocations from all objects concatenated. `relocs_start` marks the end
116/// point of object relocations and start point of Zcu relocations.
117relocations: std.MultiArrayList(Relocation) = .empty,
119
120/// Relocations to be emitted into an object file. Remains empty when not
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
119135/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
120136object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty,
......@@ -125,7 +141,7 @@ object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, Custom
125141object_comdats: std.ArrayListUnmanaged(Comdat) = .empty,
126142/// A table that maps the relocations to be performed where the key represents
127143/// 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,
129145/// Incremented across all objects in order to enable calculation of `ObjectSectionIndex` values.
130146object_total_sections: u32 = 0,
131147/// All comdat symbols from all objects concatenated.
......@@ -151,7 +167,10 @@ dump_argv_list: std.ArrayListUnmanaged([]const u8),
151167
152168preloaded_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,
155174zcu_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuFunc) = .empty,
156175nav_exports: std.AutoArrayHashMapUnmanaged(NavExport, Zcu.Export.Index) = .empty,
157176uav_exports: std.AutoArrayHashMapUnmanaged(UavExport, Zcu.Export.Index) = .empty,
......@@ -201,9 +220,14 @@ global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,
201220/// Ordered list of non-import tables that will appear in the final binary.
202221/// Empty until prelink.
203222tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,
204table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .empty,
223table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty,
205224
206225any_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
208232/// All MIR instructions for all Zcu functions.
209233mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
......@@ -212,6 +236,18 @@ mir_extra: std.ArrayListUnmanaged(u32) = .empty,
212236/// All local types for all Zcu functions.
213237all_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
215251/// Index into `objects`.
216252pub const ObjectIndex = enum(u32) {
217253 _,
......@@ -300,6 +336,10 @@ pub const SourceLocation = enum(u32) {
300336 };
301337 }
302338
339 pub fn fromObject(object_index: ObjectIndex, wasm: *const Wasm) SourceLocation {
340 return pack(.{ .object_index = object_index }, wasm);
341 }
342
303343 pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {
304344 const diags = &wasm.base.comp.link_diags;
305345 switch (sl.unpack(wasm)) {
......@@ -345,7 +385,7 @@ pub const SymbolFlags = packed struct(u32) {
345385
346386 // Above here matches the tooling conventions ABI.
347387
348 padding1: u8 = 0,
388 padding1: u5 = 0,
349389 /// Zig-specific. Dead things are allowed to be garbage collected.
350390 alive: bool = false,
351391 /// Zig-specific. Segments only. Signals that the segment contains only
......@@ -360,6 +400,12 @@ pub const SymbolFlags = packed struct(u32) {
360400 alignment: Alignment = .none,
361401 /// Zig-specific. Globals only.
362402 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
364410 pub const Binding = enum(u2) {
365411 strong = 0,
......@@ -378,13 +424,16 @@ pub const SymbolFlags = packed struct(u32) {
378424 };
379425
380426 pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {
427 flags.no_strip = no_strip;
381428 flags.alive = false;
382429 flags.strings = false;
383430 flags.must_link = must_link;
384 flags.no_strip = no_strip;
431 flags.is_passive = false;
385432 flags.alignment = .none;
386433 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;
388437 }
389438
390439 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool {
......@@ -427,11 +476,28 @@ pub const SymbolFlags = packed struct(u32) {
427476 }
428477};
429478
430pub const Nav = extern struct {
479pub const NavObj = extern struct {
431480 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
436502 /// Index into `navs`.
437503 /// Note that swapRemove is sometimes performed on `navs`.
......@@ -439,11 +505,11 @@ pub const Nav = extern struct {
439505 _,
440506
441507 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)];
443509 }
444510
445 pub fn value(i: @This(), wasm: *const Wasm) *Nav {
446 return &wasm.navs.values()[@intFromEnum(i)];
511 pub fn value(i: @This(), wasm: *const Wasm) *NavExe {
512 return &wasm.navs_exe.values()[@intFromEnum(i)];
447513 }
448514 };
449515};
......@@ -506,7 +572,7 @@ pub const FunctionImport = extern struct {
506572 __wasm_init_tls,
507573 __zig_error_names,
508574 // 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.
510576 _,
511577
512578 const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1;
......@@ -519,7 +585,8 @@ pub const FunctionImport = extern struct {
519585 __wasm_init_tls,
520586 __zig_error_names,
521587 object_function: ObjectFunctionIndex,
522 nav: Nav.Index,
588 nav_exe: NavExe.Index,
589 nav_obj: NavExe.Index,
523590 };
524591
525592 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
......@@ -535,8 +602,14 @@ pub const FunctionImport = extern struct {
535602 const object_function_index = i - first_object_function;
536603 if (object_function_index < wasm.object_functions.items.len)
537604 return .{ .object_function = @enumFromInt(object_function_index) };
605 const comp = wasm.base.comp;
606 const is_obj = comp.config.output_mode == .Obj;
538607 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 };
540613 },
541614 };
542615 }
......@@ -550,17 +623,24 @@ pub const FunctionImport = extern struct {
550623 .__wasm_init_tls => .__wasm_init_tls,
551624 .__zig_error_names => .__zig_error_names,
552625 .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)),
554628 };
555629 }
556630
557631 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 });
559639 }
560640
561641 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
562642 return switch (r.unpack(wasm)) {
563 .unresolved, .nav => true,
643 .unresolved, .nav_obj, .nav_exe => true,
564644 else => false,
565645 };
566646 }
......@@ -608,7 +688,7 @@ pub const GlobalImport = extern struct {
608688 __tls_size,
609689 __zig_error_name_table,
610690 // 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.
612692 _,
613693
614694 const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
......@@ -623,7 +703,8 @@ pub const GlobalImport = extern struct {
623703 __tls_size,
624704 __zig_error_name_table,
625705 object_global: ObjectGlobalIndex,
626 nav: Nav.Index,
706 nav_exe: NavExe.Index,
707 nav_obj: NavObj.Index,
627708 };
628709
629710 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
......@@ -639,8 +720,14 @@ pub const GlobalImport = extern struct {
639720 const object_global_index = i - first_object_global;
640721 if (object_global_index < wasm.object_globals.items.len)
641722 return .{ .object_global = @enumFromInt(object_global_index) };
723 const comp = wasm.base.comp;
724 const is_obj = comp.config.output_mode == .Obj;
642725 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 };
644731 },
645732 };
646733 }
......@@ -656,12 +743,19 @@ pub const GlobalImport = extern struct {
656743 .__tls_size => .__tls_size,
657744 .__zig_error_name_table => .__zig_error_name_table,
658745 .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)),
660748 };
661749 }
662750
663751 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 });
665759 }
666760 };
667761
......@@ -717,11 +811,32 @@ pub const Global = extern struct {
717811 };
718812};
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
720833pub const TableImport = extern struct {
721834 flags: SymbolFlags,
722835 module_name: String,
723836 source_location: SourceLocation,
724837 resolution: Resolution,
838 limits_min: u32,
839 limits_max: u32,
725840
726841 /// Represents a synthetic table, or a table from an object.
727842 pub const Resolution = enum(u32) {
......@@ -730,35 +845,36 @@ pub const TableImport = extern struct {
730845 // Next, index into `object_tables`.
731846 _,
732847 };
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 };
733861};
734862
735863pub const Table = extern struct {
736 module_name: String,
737 name: String,
864 module_name: OptionalString,
865 name: OptionalString,
738866 flags: SymbolFlags,
739867 limits_min: u32,
740868 limits_max: u32,
741 limits_has_max: bool,
742 limits_is_shared: bool,
743 reftype: std.wasm.RefType,
744 padding: [1]u8 = .{0},
745869};
746870
747/// Uniquely identifies a section across all objects. Each Object has a section_start field.
748/// By subtracting that value from this one, the Object section index is obtained.
871/// Uniquely identifies a section across all objects. By subtracting
872/// `Object.local_section_index_base` from this one, the Object section index
873/// is obtained.
749874pub const ObjectSectionIndex = enum(u32) {
750875 _,
751876};
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
762878/// Index into `object_tables`.
763879pub const ObjectTableIndex = enum(u32) {
764880 _,
......@@ -820,13 +936,18 @@ pub const DataSegment = extern struct {
820936 len: u32,
821937
822938 fn slice(p: DataSegment.Payload, wasm: *const Wasm) []const u8 {
939 assert(p.off != p.len);
823940 return wasm.string_bytes.items[p.off..][0..p.len];
824941 }
825942 };
826943
827 /// Index into `object_data_segments`.
944 /// Index into `Wasm.object_data_segments`.
828945 pub const Index = enum(u32) {
829946 _,
947
948 pub fn ptr(i: Index, wasm: *const Wasm) *DataSegment {
949 return &wasm.object_data_segments.items[@intFromEnum(i)];
950 }
830951 };
831952};
832953
......@@ -992,6 +1113,10 @@ pub const FunctionImportId = enum(u32) {
9921113 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
9931114 }
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
9951120 /// This function is allowed O(N) lookup because it is only called during
9961121 /// diagnostic generation.
9971122 pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
......@@ -1035,6 +1160,10 @@ pub const GlobalImportId = enum(u32) {
10351160 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
10361161 }
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
10381167 /// This function is allowed O(N) lookup because it is only called during
10391168 /// diagnostic generation.
10401169 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
......@@ -1054,7 +1183,38 @@ pub const GlobalImportId = enum(u32) {
10541183 }
10551184};
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 {
10581218 tag: Tag,
10591219 /// Offset of the value to rewrite relative to the relevant section's contents.
10601220 /// When `offset` is zero, its position is immediately after the id and size of the section.
......@@ -1067,8 +1227,6 @@ pub const Relocation = struct {
10671227 symbol_name: String,
10681228 type_index: FunctionType.Index,
10691229 section: ObjectSectionIndex,
1070 nav_index: InternPool.Nav.Index,
1071 uav_index: InternPool.Index,
10721230 };
10731231
10741232 pub const Slice = extern struct {
......@@ -1076,7 +1234,7 @@ pub const Relocation = struct {
10761234 off: u32,
10771235 len: u32,
10781236
1079 pub fn slice(s: Slice, wasm: *const Wasm) []Relocation {
1237 pub fn slice(s: Slice, wasm: *const Wasm) []ObjectRelocation {
10801238 return wasm.relocations.items[s.off..][0..s.len];
10811239 }
10821240 };
......@@ -1122,11 +1280,6 @@ pub const Relocation = struct {
11221280 // Above here, the tags correspond to symbol table ABI described in
11231281 // https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
11241282 // 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,
11301283 };
11311284};
11321285
......@@ -1456,7 +1609,8 @@ pub fn deinit(wasm: *Wasm) void {
14561609 const gpa = wasm.base.comp.gpa;
14571610 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);
14601614 wasm.zcu_funcs.deinit(gpa);
14611615 wasm.nav_exports.deinit(gpa);
14621616 wasm.uav_exports.deinit(gpa);
......@@ -1478,7 +1632,7 @@ pub fn deinit(wasm: *Wasm) void {
14781632 wasm.object_tables.deinit(gpa);
14791633 wasm.object_memory_imports.deinit(gpa);
14801634 wasm.object_memories.deinit(gpa);
1481
1635 wasm.object_relocations.deinit(gpa);
14821636 wasm.object_data_segments.deinit(gpa);
14831637 wasm.object_custom_segments.deinit(gpa);
14841638 wasm.object_init_funcs.deinit(gpa);
......@@ -1492,8 +1646,13 @@ pub fn deinit(wasm: *Wasm) void {
14921646 wasm.function_imports.deinit(gpa);
14931647 wasm.functions.deinit(gpa);
14941648 wasm.globals.deinit(gpa);
1649 wasm.global_exports.deinit(gpa);
14951650 wasm.global_imports.deinit(gpa);
14961651 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
14981657 wasm.string_bytes.deinit(gpa);
14991658 wasm.string_table.deinit(gpa);
......@@ -1527,7 +1686,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
15271686 const zcu = pt.zcu;
15281687 const ip = &zcu.intern_pool;
15291688 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
15321693 const nav_val = zcu.navValue(nav_index);
15331694 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
15421703
15431704 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
15441705 _ = wasm.imports.swapRemove(nav_index);
1545 if (wasm.navs.swapRemove(nav_index)) {
1546 @panic("TODO reclaim resources");
1706 if (is_obj) {
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");
15471710 }
15481711 return;
15491712 }
15501713
15511714 if (is_extern) {
15521715 try wasm.imports.put(gpa, nav_index, {});
1553 if (wasm.navs.swapRemove(nav_index)) {
1554 @panic("TODO reclaim resources");
1716 if (is_obj) {
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");
15551720 }
15561721 return;
15571722 }
15581723
15591724 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);
15611726 wasm.string_bytes_lock.lock();
15621727
15631728 try codegen.generateSymbol(
......@@ -1570,15 +1735,45 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
15701735 );
15711736
15721737 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);
15741739 wasm.string_bytes_lock.unlock();
15751740
1576 const code: Nav.Code = .{
1741 const naive_code: DataSegment.Payload = .{
15771742 .off = code_start,
15781743 .len = code_len,
15791744 };
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);
15821777 if (gop.found_existing) {
15831778 @panic("TODO reuse these resources");
15841779 } else {
......@@ -1586,10 +1781,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
15861781 }
15871782 gop.value_ptr.* = .{
15881783 .code = code,
1589 .relocs = .{
1590 .off = relocs_start,
1591 .len = relocs_len,
1592 },
15931784 };
15941785}
15951786
......@@ -1705,6 +1896,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
17051896 continue;
17061897 }
17071898 }
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 }
17081905 try missing_exports.put(gpa, exp_name_interned, {});
17091906 }
17101907 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
17241921 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {
17251922 if (import.flags.isIncluded(rdynamic)) {
17261923 try markFunction(wasm, name, import, @enumFromInt(i));
1727 continue;
17281924 }
17291925 }
17301926 wasm.functions_len = @intCast(wasm.functions.entries.len);
17311927 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());
17331929 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
17341930
17351931 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
17361932 if (import.flags.isIncluded(rdynamic)) {
17371933 try markGlobal(wasm, name, import, @enumFromInt(i));
1738 continue;
17391934 }
17401935 }
1741 wasm.globals_len = @intCast(wasm.globals.items.len);
1936 wasm.globals_len = @intCast(wasm.globals.entries.len);
17421937 wasm.global_imports_init_keys = try gpa.dupe(String, wasm.global_imports.keys());
17431938 wasm.global_imports_init_vals = try gpa.dupe(GlobalImportId, wasm.global_imports.values());
17441939 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| {
17471942 if (import.flags.isIncluded(rdynamic)) {
1748 try markTable(wasm, import.name, import, @enumFromInt(i));
1749 continue;
1943 try markTable(wasm, name, import, @enumFromInt(i));
17501944 }
17511945 }
1752 wasm.tables_len = @intCast(wasm.tables.items.len);
17531946}
17541947
17551948/// Recursively mark alive everything referenced by the function.
......@@ -1758,7 +1951,7 @@ fn markFunction(
17581951 name: String,
17591952 import: *FunctionImport,
17601953 func_index: FunctionImport.Index,
1761) error{OutOfMemory}!void {
1954) Allocator.Error!void {
17621955 if (import.flags.alive) return;
17631956 import.flags.alive = true;
17641957
......@@ -1783,15 +1976,15 @@ fn markFunction(
17831976 import.resolution = .__wasm_init_tls;
17841977 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
17851978 } else {
1786 try wasm.function_imports.put(gpa, name, .fromObject(func_index));
1979 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
17871980 }
17881981 } else {
17891982 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
17901983
17911984 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|
17951988 try wasm.markReloc(reloc);
17961989 }
17971990}
......@@ -1833,15 +2026,15 @@ fn markGlobal(
18332026 import.resolution = .__tls_size;
18342027 wasm.globals.putAssumeCapacity(.__tls_size, {});
18352028 } else {
1836 try wasm.global_imports.put(gpa, name, .fromObject(global_index));
2029 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
18372030 }
18382031 } else {
18392032 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
18402033
18412034 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|
18452038 try wasm.markReloc(reloc);
18462039 }
18472040}
......@@ -1850,7 +2043,7 @@ fn markTable(
18502043 wasm: *Wasm,
18512044 name: String,
18522045 import: *TableImport,
1853 table_index: ObjectTableImportIndex,
2046 table_index: TableImport.Index,
18542047) !void {
18552048 if (import.flags.alive) return;
18562049 import.flags.alive = true;
......@@ -1865,7 +2058,7 @@ fn markTable(
18652058 import.resolution = .__indirect_function_table;
18662059 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
18672060 } else {
1868 try wasm.table_imports.put(gpa, name, .fromObject(table_index));
2061 try wasm.table_imports.put(gpa, name, table_index);
18692062 }
18702063 } else {
18712064 wasm.tables.putAssumeCapacity(import.resolution, {});
......@@ -1873,18 +2066,24 @@ fn markTable(
18732066 }
18742067}
18752068
1876fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const Relocation {
1877 assert(resolution != .none);
2069fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const ObjectRelocation {
2070 assert(resolution != .unresolved);
18782071 _ = wasm;
18792072 @panic("TODO");
18802073}
18812074
1882fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const Relocation {
1883 assert(resolution != .none);
2075fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const ObjectRelocation {
2076 assert(resolution != .unresolved);
18842077 _ = wasm;
18852078 @panic("TODO");
18862079}
18872080
2081fn markReloc(wasm: *Wasm, reloc: ObjectRelocation) !void {
2082 _ = wasm;
2083 _ = reloc;
2084 @panic("TODO");
2085}
2086
18882087pub fn flushModule(
18892088 wasm: *Wasm,
18902089 arena: Allocator,
......@@ -2349,8 +2548,10 @@ fn defaultEntrySymbolName(
23492548 };
23502549}
23512550
2352pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
2551pub fn internString(wasm: *Wasm, bytes: []const u8) Allocator.Error!String {
23532552 assert(mem.indexOfScalar(u8, bytes, 0) == null);
2553 wasm.string_bytes_lock.lock();
2554 defer wasm.string_bytes_lock.unlock();
23542555 const gpa = wasm.base.comp.gpa;
23552556 const gop = try wasm.string_table.getOrPutContextAdapted(
23562557 gpa,
......@@ -2371,6 +2572,13 @@ pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
23712572 return new_off;
23722573}
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
23742582pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
23752583 assert(mem.indexOfScalar(u8, bytes, 0) == null);
23762584 return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{
......@@ -2378,17 +2586,17 @@ pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
23782586 }));
23792587}
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 {
23822590 return .fromString(try internString(wasm, @ptrCast(valtype_list)));
23832591}
23842592
2385pub fn addFuncType(wasm: *Wasm, ft: FunctionType) error{OutOfMemory}!FunctionType.Index {
2593pub fn addFuncType(wasm: *Wasm, ft: FunctionType) Allocator.Error!FunctionType.Index {
23862594 const gpa = wasm.base.comp.gpa;
23872595 const gop = try wasm.func_types.getOrPut(gpa, ft);
23882596 return @enumFromInt(gop.index);
23892597}
23902598
2391pub fn addExpr(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!Expr {
2599pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
23922600 const gpa = wasm.base.comp.gpa;
23932601 // We can't use string table deduplication here since these expressions can
23942602 // 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 {
23982606 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
23992607}
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 {
24022610 const gpa = wasm.base.comp.gpa;
24032611 try wasm.string_bytes.appendSlice(gpa, bytes);
24042612 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
24052613}
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 {
4242 f.data_segments.clearRetainingCapacity();
4343 f.data_segment_groups.clearRetainingCapacity();
4444 f.indirect_function_table.clearRetainingCapacity();
45 f.global_exports.clearRetainingCapacity();
4645}
4746
4847pub fn deinit(f: *Flush, gpa: Allocator) void {
......@@ -50,11 +49,10 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
5049 f.data_segments.deinit(gpa);
5150 f.data_segment_groups.deinit(gpa);
5251 f.indirect_function_table.deinit(gpa);
53 f.global_exports.deinit(gpa);
5452 f.* = undefined;
5553}
5654
57pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
55pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
5856 const comp = wasm.base.comp;
5957 const shared_memory = comp.config.shared_memory;
6058 const diags = &comp.link_diags;
......@@ -115,7 +113,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
115113 src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});
116114 }
117115 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;
119117 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});
120118 }
121119 }
......@@ -142,7 +140,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
142140 if (!ds.flags.alive) continue;
143141 const data_segment_index: Wasm.DataSegment.Index = @enumFromInt(i);
144142 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));
146144 }
147145
148146 try wasm.functions.ensureUnusedCapacity(gpa, 3);
......@@ -159,8 +157,10 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
159157 // When we have TLS GOT entries and shared memory is enabled,
160158 // we must perform runtime relocations or else we don't create the function.
161159 if (shared_memory) {
162 if (f.need_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
163 wasm.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});
160 // This logic that checks `any_tls_relocs` is missing the part where it
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, {});
164164 }
165165
166166 // Sort order:
......@@ -178,14 +178,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
178178 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
179179 const lhs_segment_index = ctx.segments[lhs];
180180 const rhs_segment_index = ctx.segments[rhs];
181 const lhs_segment = lhs_segment_index.ptr(wasm);
182 const rhs_segment = rhs_segment_index.ptr(wasm);
181 const lhs_segment = lhs_segment_index.ptr(ctx.wasm);
182 const rhs_segment = rhs_segment_index.ptr(ctx.wasm);
183183 const lhs_tls = @intFromBool(lhs_segment.flags.tls);
184184 const rhs_tls = @intFromBool(rhs_segment.flags.tls);
185185 if (lhs_tls < rhs_tls) return true;
186186 if (lhs_tls > rhs_tls) return false;
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));
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));
189189 switch (mem.order(u8, lhs_prefix, rhs_prefix)) {
190190 .lt => return true,
191191 .gt => return false,
......@@ -213,14 +213,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
213213 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
214214 const pointer_alignment: Alignment = .@"4";
215215 // 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
218218 const VirtualAddrs = struct {
219219 stack_pointer: u32,
220220 heap_base: u32,
221221 heap_end: u32,
222222 tls_base: ?u32,
223 tls_align: ?u32,
223 tls_align: Alignment,
224224 tls_size: ?u32,
225225 init_memory_flag: ?u32,
226226 };
......@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
229229 .heap_base = undefined,
230230 .heap_end = undefined,
231231 .tls_base = null,
232 .tls_align = null,
232 .tls_align = .none,
233233 .tls_size = null,
234234 .init_memory_flag = null,
235235 };
......@@ -237,7 +237,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
237237 if (place_stack_first and !is_obj) {
238238 memory_ptr = stack_alignment.forward(memory_ptr);
239239 memory_ptr += wasm.base.stack_size;
240 virtual_addrs.stack_pointer = memory_ptr;
240 virtual_addrs.stack_pointer = @intCast(memory_ptr);
241241 }
242242
243243 const segment_indexes = f.data_segments.keys();
......@@ -247,27 +247,27 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
247247 var seen_tls: enum { before, during, after } = .before;
248248 var offset: u32 = 0;
249249 for (segment_indexes, segment_offsets, 0..) |segment_index, *segment_offset, i| {
250 const segment = segment_index.ptr(f);
251 memory_ptr = segment.alignment.forward(memory_ptr);
250 const segment = segment_index.ptr(wasm);
251 memory_ptr = segment.flags.alignment.forward(memory_ptr);
252252
253253 const want_new_segment = b: {
254254 if (is_obj) break :b false;
255255 switch (seen_tls) {
256256 .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);
258258 virtual_addrs.tls_align = segment.flags.alignment;
259259 seen_tls = .during;
260260 break :b true;
261261 },
262262 .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.?);
264264 virtual_addrs.tls_align = virtual_addrs.tls_align.maxStrict(segment.flags.alignment);
265265 seen_tls = .after;
266266 break :b true;
267267 },
268268 .after => {},
269269 }
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);
271271 };
272272 if (want_new_segment) {
273273 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 {
275275 }
276276
277277 segment_offset.* = offset;
278 offset += segment.size;
279 memory_ptr += segment.size;
278 offset += segment.payload.len;
279 memory_ptr += segment.payload.len;
280280 }
281281 if (offset > 0) try f.data_segment_groups.append(gpa, offset);
282282 }
283283
284284 if (shared_memory and any_passive_inits) {
285285 memory_ptr = pointer_alignment.forward(memory_ptr);
286 virtual_addrs.init_memory_flag = memory_ptr;
286 virtual_addrs.init_memory_flag = @intCast(memory_ptr);
287287 memory_ptr += 4;
288288 }
289289
290290 if (!place_stack_first and !is_obj) {
291291 memory_ptr = stack_alignment.forward(memory_ptr);
292292 memory_ptr += wasm.base.stack_size;
293 virtual_addrs.stack_pointer = memory_ptr;
293 virtual_addrs.stack_pointer = @intCast(memory_ptr);
294294 }
295295
296296 memory_ptr = heap_alignment.forward(memory_ptr);
297 virtual_addrs.heap_base = memory_ptr;
297 virtual_addrs.heap_base = @intCast(memory_ptr);
298298
299299 if (wasm.initial_memory) |initial_memory| {
300300 if (!mem.isAlignedGeneric(u64, initial_memory, page_size)) {
......@@ -311,7 +311,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
311311 } else {
312312 memory_ptr = mem.alignForward(u64, memory_ptr, std.wasm.page_size);
313313 }
314 virtual_addrs.heap_end = memory_ptr;
314 virtual_addrs.heap_end = @intCast(memory_ptr);
315315
316316 // In case we do not import memory, but define it ourselves, set the
317317 // minimum amount of pages on the memory section.
......@@ -326,7 +326,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
326326 diags.addError("maximum memory value {d} insufficient; minimum {d}", .{ max_memory, memory_ptr });
327327 }
328328 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});
330330 }
331331 if (diags.hasErrors()) return error.LinkFailure;
332332 wasm.memories.limits.max = @intCast(max_memory / page_size);
......@@ -346,24 +346,26 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
346346 const binary_bytes = &f.binary_bytes;
347347 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);
350350 assert(binary_bytes.items.len == 8);
351351
352352 const binary_writer = binary_bytes.writer(gpa);
353353
354354 // Type section
355 if (wasm.func_types.items.len != 0) {
355 if (wasm.func_types.entries.len != 0) {
356356 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
357 log.debug("Writing type section. Count: ({d})", .{wasm.func_types.items.len});
358 for (wasm.func_types.items) |func_type| {
357 log.debug("Writing type section. Count: ({d})", .{wasm.func_types.entries.len});
358 for (wasm.func_types.keys()) |func_type| {
359359 try leb.writeUleb128(binary_writer, std.wasm.function_type);
360 try leb.writeUleb128(binary_writer, @as(u32, @intCast(func_type.params.len)));
361 for (func_type.params) |param_ty| {
362 try leb.writeUleb128(binary_writer, std.wasm.valtype(param_ty));
360 const params = func_type.params.slice(wasm);
361 try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len)));
362 for (params) |param_ty| {
363 try leb.writeUleb128(binary_writer, @intFromEnum(param_ty));
363364 }
364 try leb.writeUleb128(binary_writer, @as(u32, @intCast(func_type.returns.len)));
365 for (func_type.returns) |ret_ty| {
366 try leb.writeUleb128(binary_writer, std.wasm.valtype(ret_ty));
365 const returns = func_type.returns.slice(wasm);
366 try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len)));
367 for (returns) |ret_ty| {
368 try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty));
367369 }
368370 }
369371
......@@ -372,19 +374,19 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
372374 header_offset,
373375 .type,
374376 @intCast(binary_bytes.items.len - header_offset - header_size),
375 @intCast(wasm.func_types.items.len),
377 @intCast(wasm.func_types.entries.len),
376378 );
377379 section_index += 1;
378380 }
379381
380382 // Import section
381 const total_imports_len = wasm.function_imports.items.len + wasm.global_imports.items.len +
382 wasm.table_imports.items.len + wasm.memory_imports.items.len + @intFromBool(import_memory);
383 const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len +
384 wasm.table_imports.entries.len + wasm.memory_imports.items.len + @intFromBool(import_memory);
383385
384386 if (total_imports_len > 0) {
385387 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| {
388390 const module_name = function_import.module_name.slice(wasm);
389391 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
390392 try binary_writer.writeAll(module_name);
......@@ -397,7 +399,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
397399 try leb.writeUleb128(binary_writer, function_import.index);
398400 }
399401
400 for (wasm.table_imports.items) |*table_import| {
402 for (wasm.table_imports.values()) |*table_import| {
401403 const module_name = table_import.module_name.slice(wasm);
402404 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
403405 try binary_writer.writeAll(module_name);
......@@ -424,7 +426,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
424426 });
425427 }
426428
427 for (wasm.global_imports.items) |*global_import| {
429 for (wasm.global_imports.values()) |*global_import| {
428430 const module_name = global_import.module_name.slice(wasm);
429431 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
430432 try binary_writer.writeAll(module_name);
......@@ -504,7 +506,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
504506 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
505507
506508 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));
508510 try binary_writer.writeByte(@intFromBool(global.global_type.mutable));
509511 try emitInit(binary_writer, global.init);
510512 }
......@@ -841,7 +843,7 @@ fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void {
841843 buffer[offset..][0..buf.len].* = buf;
842844}
843845
844fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!u32 {
846fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
845847 // unlike regular section, we don't emit the count
846848 const header_size = 1 + 5;
847849 try bytes.appendNTimes(gpa, 0, header_size);
......@@ -1099,12 +1101,12 @@ fn wantSegmentMerge(wasm: *const Wasm, a_index: Wasm.DataSegment.Index, b_index:
10991101 if (a.flags.tls != b.flags.tls) return false;
11001102 if (a.flags.is_passive != b.flags.is_passive) return false;
11011103 if (a.name == b.name) return true;
1102 const a_prefix, _ = splitSegmentName(a.name.slice(wasm));
1103 const b_prefix, _ = splitSegmentName(b.name.slice(wasm));
1104 const a_prefix, _ = splitSegmentName(a.name.slice(wasm).?);
1105 const b_prefix, _ = splitSegmentName(b.name.slice(wasm).?);
11041106 return a_prefix.len > 0 and mem.eql(u8, a_prefix, b_prefix);
11051107}
11061108
1107fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!u32 {
1109fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
11081110 // section id + fixed leb contents size + fixed leb vector length
11091111 const header_size = 1 + 5 + 5;
11101112 try bytes.appendNTimes(gpa, 0, header_size);
......@@ -1125,7 +1127,7 @@ fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
11251127 if (limits.flags.has_max) try leb.writeUleb128(writer, limits.max);
11261128}
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 {
11291131 const module_name = memory_import.module_name.slice(wasm);
11301132 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
11311133 try writer.writeAll(module_name);
src/link/Wasm/Object.zig+111-79
......@@ -36,7 +36,7 @@ global_imports: RelativeSlice,
3636table_imports: RelativeSlice,
3737/// Points into Wasm object_custom_segments
3838custom_segments: RelativeSlice,
39/// For calculating local section index from `Wasm.SectionIndex`.
39/// For calculating local section index from `Wasm.ObjectSectionIndex`.
4040local_section_index_base: u32,
4141/// Points into Wasm object_init_funcs
4242init_funcs: RelativeSlice,
......@@ -109,10 +109,10 @@ pub const Symbol = struct {
109109 },
110110 data_import: void,
111111 global: Wasm.ObjectGlobalIndex,
112 global_import: Wasm.ObjectGlobalImportIndex,
112 global_import: Wasm.GlobalImport.Index,
113113 section: Wasm.ObjectSectionIndex,
114114 table: Wasm.ObjectTableIndex,
115 table_import: Wasm.ObjectTableImportIndex,
115 table_import: Wasm.TableImport.Index,
116116 };
117117};
118118
......@@ -159,7 +159,7 @@ pub const ScratchSpace = struct {
159159 }
160160};
161161
162fn parse(
162pub fn parse(
163163 wasm: *Wasm,
164164 bytes: []const u8,
165165 path: Path,
......@@ -181,18 +181,18 @@ fn parse(
181181 pos += 4;
182182
183183 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);
185185 const functions_start: u32 = @intCast(wasm.object_functions.items.len);
186186 const tables_start: u32 = @intCast(wasm.object_tables.items.len);
187187 const memories_start: u32 = @intCast(wasm.object_memories.items.len);
188188 const globals_start: u32 = @intCast(wasm.object_globals.items.len);
189189 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);
190190 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);
191 const function_imports_start: u32 = @intCast(wasm.object_function_imports.items.len);
192 const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len);
193 const table_imports_start: u32 = @intCast(wasm.object_table_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.entries.len);
193 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);
194194 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
197197 ss.clear();
198198
......@@ -200,10 +200,9 @@ fn parse(
200200 var opt_features: ?Wasm.Feature.Set = null;
201201 var saw_linking_section = false;
202202 var has_tls = false;
203 var local_section_index: u32 = 0;
204203 var table_count: usize = 0;
205 while (pos < bytes.len) : (local_section_index += 1) {
206 const section_index: Wasm.SectionIndex = @enumFromInt(local_section_index_base + local_section_index);
204 while (pos < bytes.len) : (wasm.object_total_sections += 1) {
205 const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections);
207206
208207 const section_tag: std.wasm.Section = @enumFromInt(bytes[pos]);
209208 pos += 1;
......@@ -245,7 +244,7 @@ fn parse(
245244 .strings = flags.strings,
246245 .tls = tls,
247246 .alignment = @enumFromInt(alignment),
248 .no_strip = flags.retain,
247 .retain = flags.retain,
249248 },
250249 };
251250 }
......@@ -257,13 +256,13 @@ fn parse(
257256 if (symbol_index > ss.symbol_table.items.len)
258257 return diags.failParse(path, "init_funcs before symbol table", .{});
259258 const sym = &ss.symbol_table.items[symbol_index];
260 if (sym.tag != .function) {
259 if (sym.pointee != .function) {
261260 return diags.failParse(path, "init_func symbol '{s}' not a function", .{
262 wasm.stringSlice(sym.name),
261 sym.name.slice(wasm).?,
263262 });
264263 } else if (sym.flags.undefined) {
265264 return diags.failParse(path, "init_func symbol '{s}' is an import", .{
266 wasm.stringSlice(sym.name),
265 sym.name.slice(wasm).?,
267266 });
268267 }
269268 func.* = .{
......@@ -278,22 +277,23 @@ fn parse(
278277 const flags, pos = readLeb(u32, bytes, pos);
279278 if (flags != 0) return error.UnexpectedComdatFlags;
280279 const symbol_count, pos = readLeb(u32, bytes, pos);
281 const start_off: u32 = @intCast(wasm.object_comdat_symbols.items.len);
282 for (try wasm.object_comdat_symbols.addManyAsSlice(gpa, symbol_count)) |*symbol| {
280 const start_off: u32 = @intCast(wasm.object_comdat_symbols.len);
281 try wasm.object_comdat_symbols.ensureUnusedCapacity(gpa, symbol_count);
282 for (0..symbol_count) |_| {
283283 const kind, pos = readEnum(Wasm.Comdat.Symbol.Type, bytes, pos);
284284 const index, pos = readLeb(u32, bytes, pos);
285285 if (true) @panic("TODO rebase index depending on kind");
286 symbol.* = .{
286 wasm.object_comdat_symbols.appendAssumeCapacity(.{
287287 .kind = kind,
288288 .index = index,
289 };
289 });
290290 }
291291 comdat.* = .{
292292 .name = try wasm.internString(name),
293293 .flags = flags,
294294 .symbols = .{
295295 .off = start_off,
296 .len = @intCast(wasm.object_comdat_symbols.items.len - start_off),
296 .len = @intCast(wasm.object_comdat_symbols.len - start_off),
297297 },
298298 };
299299 }
......@@ -321,7 +321,7 @@ fn parse(
321321 const size, pos = readLeb(u32, bytes, pos);
322322
323323 symbol.pointee = .{ .data = .{
324 .index = @enumFromInt(data_segment_start + segment_index),
324 .segment_index = @enumFromInt(data_segment_start + segment_index),
325325 .segment_offset = segment_offset,
326326 .size = size,
327327 } };
......@@ -329,7 +329,7 @@ fn parse(
329329 },
330330 .section => {
331331 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);
333333 symbol.pointee = .{ .section = section };
334334 },
335335
......@@ -337,7 +337,7 @@ fn parse(
337337 const local_index, pos = readLeb(u32, bytes, pos);
338338 if (symbol.flags.undefined) {
339339 symbol.pointee = .{ .function_import = @enumFromInt(local_index) };
340 if (flags.explicit_name) {
340 if (symbol.flags.explicit_name) {
341341 const name, pos = readBytes(bytes, pos);
342342 symbol.name = (try wasm.internString(name)).toOptional();
343343 }
......@@ -351,7 +351,7 @@ fn parse(
351351 const local_index, pos = readLeb(u32, bytes, pos);
352352 if (symbol.flags.undefined) {
353353 symbol.pointee = .{ .global_import = @enumFromInt(global_imports_start + local_index) };
354 if (flags.explicit_name) {
354 if (symbol.flags.explicit_name) {
355355 const name, pos = readBytes(bytes, pos);
356356 symbol.name = (try wasm.internString(name)).toOptional();
357357 }
......@@ -366,7 +366,7 @@ fn parse(
366366 const local_index, pos = readLeb(u32, bytes, pos);
367367 if (symbol.flags.undefined) {
368368 symbol.pointee = .{ .table_import = @enumFromInt(table_imports_start + local_index) };
369 if (flags.explicit_name) {
369 if (symbol.flags.explicit_name) {
370370 const name, pos = readBytes(bytes, pos);
371371 symbol.name = (try wasm.internString(name)).toOptional();
372372 }
......@@ -377,7 +377,7 @@ fn parse(
377377 }
378378 },
379379 else => {
380 log.debug("unrecognized symbol type tag: {x}", .{tag});
380 log.debug("unrecognized symbol type tag: {x}", .{@intFromEnum(tag)});
381381 return error.UnrecognizedSymbolType;
382382 },
383383 }
......@@ -396,14 +396,14 @@ fn parse(
396396 // "Relocation sections can only target code, data and custom sections."
397397 const local_section, pos = readLeb(u32, bytes, pos);
398398 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
401401 log.debug("found {d} relocations for section={d}", .{ count, section });
402402
403403 var prev_offset: u32 = 0;
404 try wasm.relocations.ensureUnusedCapacity(gpa, count);
404 try wasm.object_relocations.ensureUnusedCapacity(gpa, count);
405405 for (0..count) |_| {
406 const tag: Wasm.Relocation.Tag = @enumFromInt(bytes[pos]);
406 const tag: Wasm.ObjectRelocation.Tag = @enumFromInt(bytes[pos]);
407407 pos += 1;
408408 const offset, pos = readLeb(u32, bytes, pos);
409409 const index, pos = readLeb(u32, bytes, pos);
......@@ -426,9 +426,10 @@ fn parse(
426426 .MEMORY_ADDR_TLS_SLEB64,
427427 .FUNCTION_OFFSET_I32,
428428 .SECTION_OFFSET_I32,
429 .FUNCTION_OFFSET_I64,
429430 => {
430431 const addend: i32, pos = readLeb(i32, bytes, pos);
431 wasm.relocations.appendAssumeCapacity(.{
432 wasm.object_relocations.appendAssumeCapacity(.{
432433 .tag = tag,
433434 .offset = offset,
434435 .pointee = .{ .section = ss.symbol_table.items[index].pointee.section },
......@@ -436,7 +437,7 @@ fn parse(
436437 });
437438 },
438439 .TYPE_INDEX_LEB => {
439 wasm.relocations.appendAssumeCapacity(.{
440 wasm.object_relocations.appendAssumeCapacity(.{
440441 .tag = tag,
441442 .offset = offset,
442443 .pointee = .{ .type_index = ss.func_types.items[index] },
......@@ -444,9 +445,19 @@ fn parse(
444445 });
445446 },
446447 .FUNCTION_INDEX_LEB,
448 .FUNCTION_INDEX_I32,
447449 .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,
448459 => {
449 wasm.relocations.appendAssumeCapacity(.{
460 wasm.object_relocations.appendAssumeCapacity(.{
450461 .tag = tag,
451462 .offset = offset,
452463 .pointee = .{ .symbol_name = ss.symbol_table.items[index].name.unwrap().? },
......@@ -457,7 +468,7 @@ fn parse(
457468 }
458469
459470 try wasm.object_relocations_table.putNoClobber(gpa, section, .{
460 .off = @intCast(wasm.relocations.items.len - count),
471 .off = @intCast(wasm.object_relocations.len - count),
461472 .len = count,
462473 });
463474 } else if (std.mem.eql(u8, section_name, "target_features")) {
......@@ -466,15 +477,15 @@ fn parse(
466477 const debug_content = bytes[pos..section_end];
467478 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);
470481 try wasm.string_bytes.appendSlice(gpa, debug_content);
471482
472483 try wasm.object_custom_segments.put(gpa, section_index, .{
473 .data_off = data_off,
474 .flags = .{
475 .data_len = @intCast(debug_content.len),
476 .represented = false, // set when scanning symbol table
484 .payload = .{
485 .off = data_off,
486 .len = @intCast(debug_content.len),
477487 },
488 .flags = .{},
478489 .section_name = try wasm.internString(section_name),
479490 });
480491 } else {
......@@ -483,7 +494,7 @@ fn parse(
483494 },
484495 .type => {
485496 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| {
487498 if (bytes[pos] != std.wasm.function_type) return error.ExpectedFuncType;
488499 pos += 1;
489500
......@@ -509,7 +520,7 @@ fn parse(
509520 try ss.func_imports.append(gpa, .{
510521 .module_name = interned_module_name,
511522 .name = interned_name,
512 .index = function,
523 .function_index = @enumFromInt(function),
513524 });
514525 },
515526 .memory => {
......@@ -527,24 +538,32 @@ fn parse(
527538 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
528539 const mutable = bytes[pos] == 0x01;
529540 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 },
531548 .module_name = interned_module_name,
532 .name = interned_name,
533 .mutable = mutable,
534 .valtype = valtype,
549 .source_location = source_location,
550 .resolution = .unresolved,
535551 });
536552 },
537553 .table => {
538 const reftype, pos = readEnum(std.wasm.RefType, bytes, pos);
554 const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos);
539555 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 },
541562 .module_name = interned_module_name,
542 .name = interned_name,
563 .source_location = source_location,
564 .resolution = .unresolved,
543565 .limits_min = limits.min,
544566 .limits_max = limits.max,
545 .limits_has_max = limits.flags.has_max,
546 .limits_is_shared = limits.flags.is_shared,
547 .reftype = reftype,
548567 });
549568 },
550569 }
......@@ -553,17 +572,25 @@ fn parse(
553572 .function => {
554573 const functions_len, pos = readLeb(u32, bytes, pos);
555574 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);
557577 }
558578 },
559579 .table => {
560580 const tables_len, pos = readLeb(u32, bytes, pos);
561581 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);
563583 const limits, pos = readLimits(bytes, pos);
564584 table.* = .{
565 .reftype = reftype,
566 .limits = limits,
585 .name = .none,
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,
567594 };
568595 }
569596 },
......@@ -582,8 +609,13 @@ fn parse(
582609 pos += 1;
583610 const expr, pos = try readInit(wasm, bytes, pos);
584611 global.* = .{
585 .valtype = valtype,
586 .mutable = mutable,
612 .name = .none,
613 .flags = .{
614 .global_type = .{
615 .valtype = .from(valtype),
616 .mutable = mutable,
617 },
618 },
587619 .expr = expr,
588620 };
589621 }
......@@ -668,8 +700,6 @@ fn parse(
668700 }
669701 if (!saw_linking_section) return error.MissingLinkingSection;
670702
671 wasm.object_total_sections = local_section_index_base + local_section_index;
672
673703 if (has_tls) {
674704 const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features;
675705 if (!std.Target.wasm.featureSetHas(cpu_features, .atomics))
......@@ -770,7 +800,7 @@ fn parse(
770800 ptr.name = symbol.name;
771801 ptr.flags = symbol.flags;
772802 if (symbol.flags.undefined and symbol.flags.binding == .local) {
773 const name = wasm.stringSlice(ptr.name.unwrap().?);
803 const name = ptr.name.slice(wasm).?;
774804 diags.addParseError(path, "local symbol '{s}' references import", .{name});
775805 }
776806 },
......@@ -779,7 +809,7 @@ fn parse(
779809 const ptr = i.ptr(wasm);
780810 ptr.flags = symbol.flags;
781811 if (symbol.flags.undefined and symbol.flags.binding == .local) {
782 const name = wasm.stringSlice(ptr.name);
812 const name = ptr.name.slice(wasm);
783813 diags.addParseError(path, "local symbol '{s}' references import", .{name});
784814 }
785815 },
......@@ -806,19 +836,20 @@ fn parse(
806836 data.flags.no_strip = info.flags.retain;
807837 data.flags.alignment = info.flags.alignment;
808838 if (data.flags.undefined and data.flags.binding == .local) {
809 const name = wasm.stringSlice(info.name);
839 const name = info.name.slice(wasm);
810840 diags.addParseError(path, "local symbol '{s}' references import", .{name});
811841 }
812842 }
813843
814844 // Check for indirect function table in case of an MVP object file.
815845 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..];
817848 // 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;
819850 if (table_count != 0) {
820851 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,
822853 });
823854 }
824855 // MVP object files cannot have any table definitions, only
......@@ -827,16 +858,16 @@ fn parse(
827858 if (tables.len > 0) {
828859 return diags.failParse(path, "table definition without representing table symbols", .{});
829860 }
830 if (table_imports.len != 1) {
861 if (table_import_names.len != 1) {
831862 return diags.failParse(path, "found more than one table import, but no representing table symbols", .{});
832863 }
833 const table_import_name = table_imports[0].name;
864 const table_import_name = table_import_names[0];
834865 if (table_import_name != wasm.preloaded_strings.__indirect_function_table) {
835866 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),
837868 });
838869 }
839 table_imports[0].flags = .{
870 table_import_values[0].flags = .{
840871 .undefined = true,
841872 .no_strip = true,
842873 };
......@@ -874,11 +905,11 @@ fn parse(
874905 },
875906 .function_imports = .{
876907 .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),
878909 },
879910 .global_imports = .{
880911 .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),
882913 },
883914 .table_imports = .{
884915 .off = table_imports_start,
......@@ -894,7 +925,7 @@ fn parse(
894925 },
895926 .custom_segments = .{
896927 .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),
898929 },
899930 .local_section_index_base = local_section_index_base,
900931 };
......@@ -920,7 +951,7 @@ fn parseFeatures(
920951 '-' => .@"-",
921952 '+' => .@"+",
922953 '=' => .@"=",
923 else => return error.InvalidFeaturePrefix,
954 else => |b| return diags.failParse(path, "invalid feature prefix: 0x{x}", .{b}),
924955 };
925956 pos += 1;
926957 const name, pos = readBytes(bytes, pos);
......@@ -935,7 +966,7 @@ fn parseFeatures(
935966 std.mem.sortUnstable(Wasm.Feature, feature_buffer, {}, Wasm.Feature.lessThan);
936967
937968 return .{
938 .fromString(try wasm.internString(@bitCast(feature_buffer))),
969 .fromString(try wasm.internString(@ptrCast(feature_buffer))),
939970 pos,
940971 };
941972}
......@@ -966,9 +997,9 @@ fn readEnum(comptime T: type, bytes: []const u8, pos: usize) struct { T, usize }
966997}
967998
968999fn 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]);
9701001 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 };
9721003 return .{ .{
9731004 .flags = flags,
9741005 .min = min,
......@@ -977,7 +1008,7 @@ fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usi
9771008}
9781009
9791010fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usize } {
980 const end_pos = skipInit(bytes, pos); // one after the end opcode
1011 const end_pos = try skipInit(bytes, pos); // one after the end opcode
9811012 return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos };
9821013}
9831014
......@@ -991,6 +1022,7 @@ fn skipInit(bytes: []const u8, pos: usize) !usize {
9911022 .global_get => readLeb(u32, bytes, pos + 1)[1],
9921023 else => return error.InvalidInitOpcode,
9931024 };
994 if (readEnum(std.wasm.Opcode, bytes, end_pos) != .end) return error.InitExprMissingEnd;
995 return end_pos + 1;
1025 const op, const final_pos = readEnum(std.wasm.Opcode, bytes, end_pos);
1026 if (op != .end) return error.InitExprMissingEnd;
1027 return final_pos;
9961028}