Commit 3474057e5e

Andrew Kelley <andrew@ziglang.org>
2025-01-07 02:14:39
wasm linker: fix not merging object memories
1 parent e6a5fe7
Changed files (3)
src/link/Wasm/Flush.zig
@@ -484,18 +484,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
         }
         total_imports += wasm.table_imports.entries.len;
 
-        for (wasm.object_memory_imports.items) |*memory_import| {
-            try emitMemoryImport(wasm, binary_bytes, memory_import);
+        for (wasm.object_memory_imports.keys(), wasm.object_memory_imports.values()) |name, *memory_import| {
+            try emitMemoryImport(wasm, binary_bytes, name, memory_import);
             total_imports += 1;
         } else if (import_memory) {
-            try emitMemoryImport(wasm, binary_bytes, &.{
+            const name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory;
+            try emitMemoryImport(wasm, binary_bytes, name, &.{
                 // TODO the import_memory option needs to specify from which module
                 .module_name = wasm.object_host_name.unwrap().?,
-                .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory,
                 .limits_min = wasm.memories.limits.min,
                 .limits_max = wasm.memories.limits.max,
                 .limits_has_max = wasm.memories.limits.flags.has_max,
                 .limits_is_shared = wasm.memories.limits.flags.is_shared,
+                .source_location = .none,
             });
             total_imports += 1;
         }
@@ -1249,6 +1250,7 @@ fn emitLimits(
 fn emitMemoryImport(
     wasm: *Wasm,
     binary_bytes: *std.ArrayListUnmanaged(u8),
+    name_index: String,
     memory_import: *const Wasm.MemoryImport,
 ) Allocator.Error!void {
     const gpa = wasm.base.comp.gpa;
@@ -1256,7 +1258,7 @@ fn emitMemoryImport(
     try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len)));
     try binary_bytes.appendSlice(gpa, module_name);
 
-    const name = memory_import.name.slice(wasm);
+    const name = name_index.slice(wasm);
     try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
     try binary_bytes.appendSlice(gpa, name);
 
src/link/Wasm/Object.zig
@@ -710,14 +710,29 @@ pub fn parse(
                         },
                         .memory => {
                             const limits, pos = readLimits(bytes, pos);
-                            try wasm.object_memory_imports.append(gpa, .{
-                                .module_name = interned_module_name,
-                                .name = interned_name,
-                                .limits_min = limits.min,
-                                .limits_max = limits.max,
-                                .limits_has_max = limits.flags.has_max,
-                                .limits_is_shared = limits.flags.is_shared,
-                            });
+                            const gop = try wasm.object_memory_imports.getOrPut(gpa, interned_name);
+                            if (gop.found_existing) {
+                                if (gop.value_ptr.module_name != interned_module_name) {
+                                    var err = try diags.addErrorWithNotes(2);
+                                    try err.addMsg("memory '{s}' mismatching module names", .{name});
+                                    gop.value_ptr.source_location.addNote(&err, "module '{s}' here", .{
+                                        gop.value_ptr.module_name.slice(wasm),
+                                    });
+                                    source_location.addNote(&err, "module '{s}' here", .{module_name});
+                                }
+                                // TODO error for mismatching flags
+                                gop.value_ptr.limits_min = @min(gop.value_ptr.limits_min, limits.min);
+                                gop.value_ptr.limits_max = @max(gop.value_ptr.limits_max, limits.max);
+                            } else {
+                                gop.value_ptr.* = .{
+                                    .module_name = interned_module_name,
+                                    .limits_min = limits.min,
+                                    .limits_max = limits.max,
+                                    .limits_has_max = limits.flags.has_max,
+                                    .limits_is_shared = limits.flags.is_shared,
+                                    .source_location = source_location,
+                                };
+                            }
                         },
                         .global => {
                             const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
src/link/Wasm.zig
@@ -107,7 +107,7 @@ object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empt
 object_tables: std.ArrayListUnmanaged(Table) = .empty,
 
 /// All memory imports for all objects.
-object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,
+object_memory_imports: std.AutoArrayHashMapUnmanaged(String, MemoryImport) = .empty,
 /// All parsed memory sections for all objects.
 object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty,
 
@@ -2596,9 +2596,9 @@ pub const ObjectRelocation = struct {
 
 pub const MemoryImport = extern struct {
     module_name: String,
-    name: String,
     limits_min: u32,
     limits_max: u32,
+    source_location: SourceLocation,
     limits_has_max: bool,
     limits_is_shared: bool,
     padding: [2]u8 = .{ 0, 0 },