Commit 91efc5c98b

Andrew Kelley <andrew@ziglang.org>
2024-12-19 01:43:14
wasm linker: fix calling imported functions
and more disciplined type safety for output function indexes
1 parent 1a58ae2
Changed files (3)
src/arch/wasm/Emit.zig
@@ -30,7 +30,6 @@ pub fn lowerToCode(emit: *Emit) Error!void {
     const is_obj = comp.config.output_mode == .Obj;
     const target = &comp.root_mod.resolved_target.result;
     const is_wasm32 = target.cpu.arch == .wasm32;
-    const function_imports_len: u32 = @intCast(wasm.function_imports.entries.len);
 
     const tags = mir.instruction_tags;
     const datas = mir.instruction_datas;
@@ -159,8 +158,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
                 });
                 code.appendNTimesAssumeCapacity(0, 5);
             } else {
-                const func_index = Wasm.FunctionIndex.fromIpNav(wasm, datas[inst].nav_index).?;
-                leb.writeUleb128(code.fixedWriter(), function_imports_len + @intFromEnum(func_index)) catch unreachable;
+                appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index));
             }
 
             inst += 1;
@@ -200,8 +198,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
                 });
                 code.appendNTimesAssumeCapacity(0, 5);
             } else {
-                const func_index = Wasm.FunctionIndex.fromTagNameType(wasm, datas[inst].ip_index).?;
-                leb.writeUleb128(code.fixedWriter(), function_imports_len + @intFromEnum(func_index)) catch unreachable;
+                appendOutputFunctionIndex(code, .fromTagNameType(wasm, datas[inst].ip_index));
             }
 
             inst += 1;
@@ -225,8 +222,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
                 });
                 code.appendNTimesAssumeCapacity(0, 5);
             } else {
-                const func_index = Wasm.FunctionIndex.fromSymbolName(wasm, symbol_name).?;
-                leb.writeUleb128(code.fixedWriter(), function_imports_len + @intFromEnum(func_index)) catch unreachable;
+                appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name));
             }
 
             inst += 1;
@@ -978,3 +974,7 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff
         }
     }
 }
+
+fn appendOutputFunctionIndex(code: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) void {
+    leb.writeUleb128(code.fixedWriter(), @intFromEnum(i)) catch unreachable;
+}
src/link/Wasm.zig
@@ -283,10 +283,6 @@ pub const FunctionIndex = enum(u32) {
         return &wasm.functions.keys()[@intFromEnum(index)];
     }
 
-    pub fn toOutputFunctionIndex(index: FunctionIndex, wasm: *const Wasm) OutputFunctionIndex {
-        return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));
-    }
-
     pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {
         return fromResolution(wasm, .fromIpNav(wasm, nav_index));
     }
@@ -324,6 +320,31 @@ pub const GlobalExport = extern struct {
 /// `flush`.
 pub const OutputFunctionIndex = enum(u32) {
     _,
+
+    pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex {
+        return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));
+    }
+
+    pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) OutputFunctionIndex {
+        const zcu = wasm.base.comp.zcu.?;
+        const ip = &zcu.intern_pool;
+        const nav = ip.getNav(nav_index);
+        if (nav.toExtern(ip)) |ext| {
+            const name = wasm.getExistingString(ext.name.toSlice(ip)).?;
+            if (wasm.function_imports.getIndex(name)) |i| return @enumFromInt(i);
+            return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name).?);
+        } else {
+            return fromFunctionIndex(wasm, FunctionIndex.fromIpNav(wasm, nav_index).?);
+        }
+    }
+
+    pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {
+        return fromFunctionIndex(wasm, FunctionIndex.fromTagNameType(wasm, tag_type).?);
+    }
+
+    pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {
+        return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name).?);
+    }
 };
 
 /// Index into `Wasm.globals`.
@@ -788,6 +809,7 @@ pub const FunctionImport = extern struct {
             const zcu = wasm.base.comp.zcu.?;
             const ip = &zcu.intern_pool;
             const nav = ip.getNav(nav_index);
+            //log.debug("Resolution.fromIpNav {}({})", .{ nav.fqn.fmt(ip), nav_index });
             return pack(wasm, .{
                 .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(nav.status.resolved.val).?),
             });
src/InternPool.zig
@@ -620,6 +620,14 @@ pub const Nav = struct {
         };
     }
 
+    /// Asserts that `status == .resolved`.
+    pub fn toExtern(nav: *const Nav, ip: *const InternPool) ?Key.Extern {
+        return switch (ip.indexToKey(nav.status.resolved.val)) {
+            .@"extern" => |ext| ext,
+            else => null,
+        };
+    }
+
     /// Asserts that `status == .resolved`.
     pub fn isThreadLocal(nav: Nav, ip: *const InternPool) bool {
         const val = nav.status.resolved.val;