diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-12-15 18:37:02 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-01-15 15:11:35 -0800 |
| commit | e80a2037687343ba18d240c771ff86d6891b5785 (patch) | |
| tree | 46e65c22994e3b34d4a9529881a986f8d6790d63 /src | |
| parent | 4ecc4addc432792514a86f6a8fde0285de4468b2 (diff) | |
| download | zig-e80a2037687343ba18d240c771ff86d6891b5785.tar.gz zig-e80a2037687343ba18d240c771ff86d6891b5785.zip | |
wasm linker fixes
* function resolution now links to zcu_funcs, not navs_exe/navs_obj
* updateFunc now adds things to output functions
* updateNav now handles function aliases correctly
* only report start symbol missing when it is unresolved
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Wasm.zig | 101 | ||||
| -rw-r--r-- | src/link/Wasm/Flush.zig | 22 |
2 files changed, 54 insertions, 69 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 6078b7c7d4..2257c91067 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -586,7 +586,7 @@ pub const NavExe = extern struct { pub const ZcuFunc = extern struct { function: CodeGen.Function, - /// Index into `zcu_funcs`. + /// Index into `Wasm.zcu_funcs`. /// Note that swapRemove is sometimes performed on `zcu_funcs`. pub const Index = enum(u32) { _, @@ -641,7 +641,7 @@ pub const FunctionImport = extern struct { __wasm_init_tls, __zig_error_names, // Next, index into `object_functions`. - // Next, index into `navs_exe` or `navs_obj` depending on whether emitting an object. + // Next, index into `zcu_funcs`. _, const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1; @@ -654,8 +654,7 @@ pub const FunctionImport = extern struct { __wasm_init_tls, __zig_error_names, object_function: ObjectFunctionIndex, - nav_exe: NavExe.Index, - nav_obj: NavObj.Index, + zcu_func: ZcuFunc.Index, }; pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked { @@ -669,16 +668,13 @@ pub const FunctionImport = extern struct { _ => { const i: u32 = @intFromEnum(r); const object_function_index = i - first_object_function; - if (object_function_index < wasm.object_functions.items.len) + if (object_function_index < wasm.object_functions.items.len) { return .{ .object_function = @enumFromInt(object_function_index) }; - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; - const nav_index = object_function_index - wasm.object_functions.items.len; - return if (is_obj) .{ - .nav_obj = @enumFromInt(nav_index), - } else .{ - .nav_exe = @enumFromInt(nav_index), - }; + } else { + return .{ + .zcu_func = @enumFromInt(object_function_index - wasm.object_functions.items.len), + }; + } }, }; } @@ -692,24 +688,22 @@ pub const FunctionImport = extern struct { .__wasm_init_tls => .__wasm_init_tls, .__zig_error_names => .__zig_error_names, .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)), - .nav_obj => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)), - .nav_exe => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)), + .zcu_func => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)), }; } - pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution { - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; - return pack(wasm, if (is_obj) .{ - .nav_obj = @enumFromInt(wasm.navs_obj.getIndex(ip_nav).?), - } else .{ - .nav_exe = @enumFromInt(wasm.navs_exe.getIndex(ip_nav).?), + pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(nav_index); + return pack(wasm, .{ + .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(nav.status.resolved.val).?), }); } pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool { return switch (r.unpack(wasm)) { - .unresolved, .nav_obj, .nav_exe => true, + .unresolved, .zcu_func => true, else => false, }; } @@ -723,8 +717,7 @@ pub const FunctionImport = extern struct { .__wasm_init_tls => @panic("TODO"), .__zig_error_names => @panic("TODO"), .object_function => |i| i.ptr(wasm).type_index, - .nav_exe => @panic("TODO"), - .nav_obj => @panic("TODO"), + .zcu_func => @panic("TODO"), }; } }; @@ -1940,13 +1933,18 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, dev.check(.wasm_backend); + const gpa = pt.zcu.gpa; + try wasm.functions.ensureUnusedCapacity(gpa, 1); + try wasm.zcu_funcs.ensureUnusedCapacity(gpa, 1); + // This converts AIR to MIR but does not yet lower to wasm code. // That lowering happens during `flush`, after garbage collection, which // can affect function and global indexes, which affects the LEB integer // encoding, which affects the output binary size. - try wasm.zcu_funcs.put(pt.zcu.gpa, func_index, .{ + wasm.zcu_funcs.putAssumeCapacity(func_index, .{ .function = try CodeGen.function(wasm, pt, func_index, air, liveness), }); + wasm.functions.putAssumeCapacity(.pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.entries.len - 1) }), {}); } // Generate code for the "Nav", storing it in memory to be later written to @@ -1963,19 +1961,14 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index const gpa = comp.gpa; const is_obj = comp.config.output_mode == .Obj; - const nav_val = zcu.navValue(nav_index); - const is_extern, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| .{ false, Value.fromInterned(variable.init) }, - .func => unreachable, - .@"extern" => b: { - assert(!ip.isFunctionType(nav.typeOf(ip))); - break :b .{ true, nav_val }; - }, - else => .{ false, nav_val }, + const is_extern, const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => return, + .@"extern" => .{ true, .none }, + .variable => |variable| .{ false, variable.init }, + else => .{ false, nav.status.resolved.val }, }; - - if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { - _ = wasm.imports.swapRemove(nav_index); + if (is_extern) { + try wasm.imports.put(gpa, nav_index, {}); if (is_obj) { if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources"); } else { @@ -1983,9 +1976,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index } return; } + _ = wasm.imports.swapRemove(nav_index); - if (is_extern) { - try wasm.imports.put(gpa, nav_index, {}); + if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) { if (is_obj) { if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources"); } else { @@ -2002,7 +1995,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index &wasm.base, pt, zcu.navSrcLoc(nav_index), - nav_init, + Value.fromInterned(nav_init), &wasm.string_bytes, .none, ); @@ -2030,11 +2023,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index if (is_obj) { const gop = try wasm.navs_obj.getOrPut(gpa, nav_index); - if (gop.found_existing) { - @panic("TODO reuse these resources"); - } else { - _ = wasm.imports.swapRemove(nav_index); - } gop.value_ptr.* = .{ .code = code, .relocs = .{ @@ -2047,11 +2035,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index assert(relocs_len == 0); const gop = try wasm.navs_exe.getOrPut(gpa, nav_index); - if (gop.found_existing) { - @panic("TODO reuse these resources"); - } else { - _ = wasm.imports.swapRemove(nav_index); - } gop.value_ptr.* = .{ .code = code, }; @@ -2072,9 +2055,13 @@ pub fn deleteExport( const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; - const export_name = wasm.getExistingString(name.toSlice(ip)).?; + const name_slice = name.toSlice(ip); + const export_name = wasm.getExistingString(name_slice).?; switch (exported) { - .nav => |nav_index| assert(wasm.nav_exports.swapRemove(.{ .nav_index = nav_index, .name = export_name })), + .nav => |nav_index| { + log.debug("deleteExport '{s}' nav={d}", .{ name_slice, @intFromEnum(nav_index) }); + assert(wasm.nav_exports.swapRemove(.{ .nav_index = nav_index, .name = export_name })); + }, .uav => |uav_index| assert(wasm.uav_exports.swapRemove(.{ .uav_index = uav_index, .name = export_name })), } wasm.any_exports_updated = true; @@ -2096,9 +2083,13 @@ pub fn updateExports( const ip = &zcu.intern_pool; for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); - const name = try wasm.internString(exp.opts.name.toSlice(ip)); + const name_slice = exp.opts.name.toSlice(ip); + const name = try wasm.internString(name_slice); switch (exported) { - .nav => |nav_index| try wasm.nav_exports.put(gpa, .{ .nav_index = nav_index, .name = name }, export_idx), + .nav => |nav_index| { + log.debug("updateExports '{s}' nav={d}", .{ name_slice, @intFromEnum(nav_index) }); + try wasm.nav_exports.put(gpa, .{ .nav_index = nav_index, .name = name }, export_idx); + }, .uav => |uav_index| try wasm.uav_exports.put(gpa, .{ .uav_index = uav_index, .name = name }, export_idx), } } diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index c40b9b1294..320dbc9ad1 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -79,6 +79,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { for (wasm.nav_exports.keys()) |*nav_export| { if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) { + log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index }); try wasm.function_exports.append(gpa, .{ .name = nav_export.name, .function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?, @@ -103,9 +104,11 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { } if (entry_name.unwrap()) |name| { - var err = try diags.addErrorWithNotes(1); - try err.addMsg("entry symbol '{s}' missing", .{name.slice(wasm)}); - try err.addNote("'-fno-entry' suppresses this error", .{}); + if (wasm.entry_resolution == .unresolved) { + var err = try diags.addErrorWithNotes(1); + try err.addMsg("entry symbol '{s}' missing", .{name.slice(wasm)}); + try err.addNote("'-fno-entry' suppresses this error", .{}); + } } } @@ -615,19 +618,10 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { //try leb.writeUleb128(binary_writer, atom.code.len); //try binary_bytes.appendSlice(gpa, atom.code.slice(wasm)); }, - .nav_exe => |i| { - assert(!is_obj); - _ = i; - _ = start_offset; - @panic("TODO lower nav exe code and apply relocations"); - //try leb.writeUleb128(binary_writer, atom.code.len); - //try binary_bytes.appendSlice(gpa, atom.code.slice(wasm)); - }, - .nav_obj => |i| { - assert(is_obj); + .zcu_func => |i| { _ = i; _ = start_offset; - @panic("TODO lower nav obj code and apply relocations"); + @panic("TODO lower zcu_func code and apply relocations"); //try leb.writeUleb128(binary_writer, atom.code.len); //try binary_bytes.appendSlice(gpa, atom.code.slice(wasm)); }, |
