authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-18 22:11:20-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log4f8a6b0888c8d1df87d254b68344bb99edcfe57c
tree2685575e3ef8de7a9134e8a35a9067a67d8d365c
parent5fac6f380ef77a7650047c65450aec0d3215da2d

wasm linker: implement data fixups

one hash table lookup per fixup

3 files changed, 53 insertions(+), 7 deletions(-)

src/codegen.zig+6-4
...@@ -674,8 +674,9 @@ fn lowerUavRef(...@@ -674,8 +674,9 @@ fn lowerUavRef(
674 .addend = @intCast(offset),674 .addend = @intCast(offset),
675 });675 });
676 } else {676 } else {
677 try wasm.uav_fixups.append(gpa, .{677 try wasm.uav_fixups.ensureUnusedCapacity(gpa, 1);
678 .ip_index = uav.val,678 wasm.uav_fixups.appendAssumeCapacity(.{
679 .uavs_exe_index = try wasm.refUavExe(pt, uav.val),
679 .offset = @intCast(code.items.len),680 .offset = @intCast(code.items.len),
680 });681 });
681 }682 }
...@@ -745,8 +746,9 @@ fn lowerNavRef(...@@ -745,8 +746,9 @@ fn lowerNavRef(
745 .addend = @intCast(offset),746 .addend = @intCast(offset),
746 });747 });
747 } else {748 } else {
748 try wasm.nav_fixups.append(gpa, .{749 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
749 .nav_index = nav_index,750 wasm.nav_fixups.appendAssumeCapacity(.{
751 .navs_exe_index = try wasm.refNavExe(nav_index),
750 .offset = @intCast(code.items.len),752 .offset = @intCast(code.items.len),
751 });753 });
752 }754 }
src/link/Wasm.zig+21-3
...@@ -259,13 +259,13 @@ params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,...@@ -259,13 +259,13 @@ params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
259returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,259returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
260260
261pub const UavFixup = extern struct {261pub const UavFixup = extern struct {
262 ip_index: InternPool.Index,262 uavs_exe_index: UavsExeIndex,
263 /// Index into `string_bytes`.263 /// Index into `string_bytes`.
264 offset: u32,264 offset: u32,
265};265};
266266
267pub const NavFixup = extern struct {267pub const NavFixup = extern struct {
268 nav_index: InternPool.Nav.Index,268 navs_exe_index: NavsExeIndex,
269 /// Index into `string_bytes`.269 /// Index into `string_bytes`.
270 offset: u32,270 offset: u32,
271};271};
...@@ -2379,7 +2379,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -2379,7 +2379,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
2379 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);2379 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
2380 gop.value_ptr.* = .{2380 gop.value_ptr.* = .{
2381 .code = zcu_data.code,2381 .code = zcu_data.code,
2382 .count = 0,2382 .count = if (gop.found_existing) gop.value_ptr.count else 0,
2383 };2383 };
2384 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_exe = @enumFromInt(gop.index) }), {});2384 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_exe = @enumFromInt(gop.index) }), {});
2385}2385}
...@@ -3376,6 +3376,24 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua...@@ -3376,6 +3376,24 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua
3376 return uav_index;3376 return uav_index;
3377}3377}
33783378
3379pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
3380 const comp = wasm.base.comp;
3381 const gpa = comp.gpa;
3382 assert(comp.config.output_mode != .Obj);
3383 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
3384 if (gop.found_existing) {
3385 gop.value_ptr.count += 1;
3386 } else {
3387 gop.value_ptr.* = .{
3388 .code = undefined,
3389 .count = 1,
3390 };
3391 }
3392 const navs_exe_index: NavsExeIndex = @enumFromInt(gop.index);
3393 try wasm.data_segments.put(gpa, .pack(wasm, .{ .nav_exe = navs_exe_index }), {});
3394 return navs_exe_index;
3395}
3396
3379/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.3397/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
3380pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 {3398pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 {
3381 assert(wasm.flush_buffer.memory_layout_finished);3399 assert(wasm.flush_buffer.memory_layout_finished);
src/link/Wasm/Flush.zig+26
...@@ -60,6 +60,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -60,6 +60,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
60 const import_memory = comp.config.import_memory;60 const import_memory = comp.config.import_memory;
61 const export_memory = comp.config.export_memory;61 const export_memory = comp.config.export_memory;
62 const target = &comp.root_mod.resolved_target.result;62 const target = &comp.root_mod.resolved_target.result;
63 const is64 = switch (target.cpu.arch) {
64 .wasm32 => false,
65 .wasm64 => true,
66 else => unreachable,
67 };
63 const is_obj = comp.config.output_mode == .Obj;68 const is_obj = comp.config.output_mode == .Obj;
64 const allow_undefined = is_obj or wasm.import_symbols;69 const allow_undefined = is_obj or wasm.import_symbols;
65 const zcu = wasm.base.comp.zcu.?;70 const zcu = wasm.base.comp.zcu.?;
...@@ -650,6 +655,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -650,6 +655,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
650 section_index += 1;655 section_index += 1;
651 }656 }
652657
658 if (!is_obj) {
659 for (wasm.uav_fixups.items) |uav_fixup| {
660 const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_fixup.uavs_exe_index });
661 const vaddr = f.data_segments.get(ds_id).?;
662 if (!is64) {
663 mem.writeInt(u32, wasm.string_bytes.items[uav_fixup.offset..][0..4], vaddr, .little);
664 } else {
665 mem.writeInt(u64, wasm.string_bytes.items[uav_fixup.offset..][0..8], vaddr, .little);
666 }
667 }
668 for (wasm.nav_fixups.items) |nav_fixup| {
669 const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });
670 const vaddr = f.data_segments.get(ds_id).?;
671 if (!is64) {
672 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);
673 } else {
674 mem.writeInt(u64, wasm.string_bytes.items[nav_fixup.offset..][0..8], vaddr, .little);
675 }
676 }
677 }
678
653 // Data section.679 // Data section.
654 if (f.data_segment_groups.items.len != 0) {680 if (f.data_segment_groups.items.len != 0) {
655 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);681 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);