Commit 97448e4d5f

Luuk de Gram <luuk@degram.dev>
2022-03-26 17:14:56
wasm: Only generate import when referenced
Rather than creating an import for externs on updateDecl, we now generate them when they're referenced. This is required so using @TypeOf(extern_fn()) will not emit the import into the binary (causing an incorrect function type index as it won't be fully analyzed).
1 parent af84493
Changed files (2)
src
arch
link
src/arch/wasm/CodeGen.zig
@@ -64,7 +64,7 @@ const WValue = union(enum) {
     /// loads and stores without requiring checks everywhere.
     fn offset(self: WValue) u32 {
         switch (self) {
-            .stack_offset => |offset| return offset,
+            .stack_offset => |stack_offset| return stack_offset,
             else => return 0,
         }
     }
@@ -1549,6 +1549,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
             var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target);
             defer func_type.deinit(self.gpa);
             ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
+            try self.bin_file.addOrUpdateImport(ext_decl);
             break :blk ext_decl;
         } else if (func_val.castTag(.decl_ref)) |decl_ref| {
             break :blk decl_ref.data;
@@ -1939,6 +1940,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
         const decl = decl_ref.data;
         return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl);
     }
+    if (val.castTag(.decl_ref_mut)) |decl_ref| {
+        const decl = decl_ref.data.decl;
+        return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl);
+    }
 
     const target = self.target;
 
src/link/Wasm.zig
@@ -496,8 +496,6 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
         atom.sym_index = @intCast(u32, self.symbols.items.len);
         self.symbols.appendAssumeCapacity(symbol);
     }
-
-    try self.resolved_symbols.putNoClobber(self.base.allocator, atom.symbolLoc(), {});
     try self.symbol_atom.putNoClobber(self.base.allocator, atom.symbolLoc(), atom);
 }
 
@@ -552,7 +550,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
     decl.link.wasm.clear();
 
     if (decl.isExtern()) {
-        return self.addOrUpdateImport(decl);
+        return;
     }
 
     if (decl.val.castTag(.function)) |_| {
@@ -588,10 +586,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
 }
 
 fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
-    if (decl.isExtern()) {
-        return self.addOrUpdateImport(decl);
-    }
-
     if (code.len == 0) return;
     const atom: *Atom = &decl.link.wasm;
     atom.size = @intCast(u32, code.len);
@@ -602,6 +596,8 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
     defer self.base.allocator.free(full_name);
     symbol.name = try self.string_table.put(self.base.allocator, full_name);
     try atom.code.appendSlice(self.base.allocator, code);
+
+    try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});
 }
 
 /// Lowers a constant typed value to a local symbol and atom.
@@ -831,10 +827,10 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
     }
 
     if (decl.isExtern()) {
-        assert(self.imports.remove(atom.symbolLoc()));
+        _ = self.imports.remove(atom.symbolLoc());
     }
-    assert(self.resolved_symbols.swapRemove(atom.symbolLoc()));
-    _ = self.symbol_atom.remove(atom.symbolLoc()); // not all decl's exist in symbol_atom
+    _ = self.resolved_symbols.swapRemove(atom.symbolLoc());
+    _ = self.symbol_atom.remove(atom.symbolLoc());
     atom.deinit(self.base.allocator);
 }
 
@@ -855,19 +851,19 @@ fn mapFunctionTable(self: *Wasm) void {
     }
 }
 
-fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
+pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
     // For the import name itself, we use the decl's name, rather than the fully qualified name
     const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0));
     const symbol_index = decl.link.wasm.sym_index;
     const symbol: *Symbol = &self.symbols.items[symbol_index];
     symbol.setUndefined(true);
     symbol.setGlobal(true);
-    try self.globals.putNoClobber(
-        self.base.allocator,
-        decl_name_index,
-        .{ .file = null, .index = symbol_index },
-    );
-    try self.resolved_symbols.put(self.base.allocator, .{ .file = null, .index = symbol_index }, {});
+    const global_gop = try self.globals.getOrPut(self.base.allocator, decl_name_index);
+    if (!global_gop.found_existing) {
+        const loc: SymbolLoc = .{ .file = null, .index = symbol_index };
+        global_gop.value_ptr.* = loc;
+        try self.resolved_symbols.put(self.base.allocator, loc, {});
+    }
 
     switch (decl.ty.zigTypeTag()) {
         .Fn => {