diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/InternPool.zig | 4 | ||||
| -rw-r--r-- | src/Zcu.zig | 2 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 63 | ||||
| -rw-r--r-- | src/link/Wasm/Flush.zig | 164 |
4 files changed, 128 insertions, 105 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index 7a2e6d8ce3..92fab343a0 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -11801,6 +11801,10 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E { return @enumFromInt(ip.indexToKey(int).int.storage.u64); } +pub fn toFunc(ip: *const InternPool, i: Index) Key.Func { + return ip.indexToKey(i).func; +} + pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { return switch (ip.indexToKey(ty)) { .struct_type => ip.loadStructType(ty).field_types.len, diff --git a/src/Zcu.zig b/src/Zcu.zig index 2ae8b240e7..48c7e3f131 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -3483,7 +3483,7 @@ pub fn iesFuncIndex(zcu: *const Zcu, ies_index: InternPool.Index) InternPool.Ind } pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Func { - return zcu.intern_pool.indexToKey(func_index).func; + return zcu.intern_pool.toFunc(func_index); } pub fn toEnum(zcu: *const Zcu, comptime E: type, val: Value) E { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 2257c91067..bebff7a694 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -550,7 +550,7 @@ pub const NavObj = extern struct { /// Empty if not emitting an object. relocs: OutReloc.Slice, - /// Index into `navs`. + /// Index into `Wasm.navs_obj`. /// Note that swapRemove is sometimes performed on `navs`. pub const Index = enum(u32) { _, @@ -562,13 +562,20 @@ pub const NavObj = extern struct { pub fn value(i: @This(), wasm: *const Wasm) *NavObj { return &wasm.navs_obj.values()[@intFromEnum(i)]; } + + pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(i.key(wasm).*); + return nav.fqn.toSlice(ip); + } }; }; pub const NavExe = extern struct { code: DataSegment.Payload, - /// Index into `navs`. + /// Index into `Wasm.navs_exe`. /// Note that swapRemove is sometimes performed on `navs`. pub const Index = enum(u32) { _, @@ -580,6 +587,13 @@ pub const NavExe = extern struct { pub fn value(i: @This(), wasm: *const Wasm) *NavExe { return &wasm.navs_exe.values()[@intFromEnum(i)]; } + + pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(i.key(wasm).*); + return nav.fqn.toSlice(ip); + } }; }; @@ -598,6 +612,14 @@ pub const ZcuFunc = extern struct { pub fn value(i: @This(), wasm: *const Wasm) *ZcuFunc { return &wasm.zcu_funcs.values()[@intFromEnum(i)]; } + + pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const func = ip.toFunc(i.key(wasm).*); + const nav = ip.getNav(func.owner_nav); + return nav.fqn.toSlice(ip); + } }; }; @@ -720,6 +742,19 @@ pub const FunctionImport = extern struct { .zcu_func => @panic("TODO"), }; } + + pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__wasm_apply_global_tls_relocs => @tagName(Unpacked.__wasm_apply_global_tls_relocs), + .__wasm_call_ctors => @tagName(Unpacked.__wasm_call_ctors), + .__wasm_init_memory => @tagName(Unpacked.__wasm_init_memory), + .__wasm_init_tls => @tagName(Unpacked.__wasm_init_tls), + .__zig_error_names => @tagName(Unpacked.__zig_error_names), + .object_function => |i| i.ptr(wasm).name.slice(wasm), + .zcu_func => |i| i.name(wasm), + }; + } }; /// Index into `object_function_imports`. @@ -851,6 +886,22 @@ pub const GlobalImport = extern struct { .nav_exe = @enumFromInt(wasm.navs_exe.getIndex(ip_nav).?), }); } + + pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__heap_base => @tagName(Unpacked.__heap_base), + .__heap_end => @tagName(Unpacked.__heap_end), + .__stack_pointer => @tagName(Unpacked.__stack_pointer), + .__tls_align => @tagName(Unpacked.__tls_align), + .__tls_base => @tagName(Unpacked.__tls_base), + .__tls_size => @tagName(Unpacked.__tls_size), + .__zig_error_name_table => @tagName(Unpacked.__zig_error_name_table), + .object_global => |i| i.name(wasm).slice(wasm), + .nav_obj => |i| i.name(wasm), + .nav_exe => |i| i.name(wasm), + }; + } }; /// Index into `Wasm.object_global_imports`. @@ -1038,6 +1089,10 @@ pub const ObjectGlobalIndex = enum(u32) { pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global { return &wasm.object_globals.items[@intFromEnum(index)]; } + + pub fn name(index: ObjectGlobalIndex, wasm: *const Wasm) OptionalString { + return index.ptr(wasm).name; + } }; /// Index into `Wasm.object_memories`. @@ -1049,7 +1104,7 @@ pub const ObjectMemoryIndex = enum(u32) { } }; -/// Index into `object_functions`. +/// Index into `Wasm.object_functions`. pub const ObjectFunctionIndex = enum(u32) { _, @@ -2397,7 +2452,7 @@ pub fn flushModule( defer sub_prog_node.end(); wasm.flush_buffer.clear(); - return wasm.flush_buffer.finish(wasm, arena) catch |err| switch (err) { + return wasm.flush_buffer.finish(wasm) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("failed to flush wasm: {s}", .{@errorName(e)}), diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 320dbc9ad1..8cd5b3297f 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -52,7 +52,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { f.* = undefined; } -pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { +pub fn finish(f: *Flush, wasm: *Wasm) !void { const comp = wasm.base.comp; const shared_memory = comp.config.shared_memory; const diags = &comp.link_diags; @@ -685,7 +685,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { // try wasm.emitDataRelocations(binary_bytes, data_index, symbol_table); //} } else if (comp.config.debug_format != .strip) { - try emitNameSection(wasm, binary_bytes, arena); + try emitNameSection(wasm, &f.data_segments, binary_bytes); } if (comp.config.debug_format != .strip) { @@ -732,117 +732,77 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { try file.setEndPos(binary_bytes.items.len); } -fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), arena: Allocator) !void { - if (true) { - std.log.warn("TODO emit name section", .{}); - return; - } +fn emitNameSection( + wasm: *Wasm, + data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Index, u32), + binary_bytes: *std.ArrayListUnmanaged(u8), +) !void { const comp = wasm.base.comp; const gpa = comp.gpa; - const import_memory = comp.config.import_memory; - // Deduplicate symbols that point to the same function. - var funcs: std.AutoArrayHashMapUnmanaged(u32, String) = .empty; - try funcs.ensureUnusedCapacityPrecise(arena, wasm.functions.count() + wasm.function_imports.items.len); + const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer writeCustomSectionHeader(binary_bytes, header_offset); - const NamedIndex = struct { - index: u32, - name: String, - }; + const name_name = "name"; + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len)); + try binary_bytes.appendSlice(gpa, name_name); - var globals: std.MultiArrayList(NamedIndex) = .empty; - try globals.ensureTotalCapacityPrecise(arena, wasm.globals.items.len + wasm.global_imports.items.len); - - var segments: std.MultiArrayList(NamedIndex) = .empty; - try segments.ensureTotalCapacityPrecise(arena, wasm.data_segments.count()); - - for (wasm.resolved_symbols.keys()) |sym_loc| { - const symbol = wasm.finalSymbolByLoc(sym_loc).*; - if (!symbol.flags.alive) continue; - const name = wasm.finalSymbolByLoc(sym_loc).name; - switch (symbol.tag) { - .function => { - const index = if (symbol.flags.undefined) - @intFromEnum(symbol.pointee.function_import) - else - wasm.function_imports.items.len + @intFromEnum(symbol.pointee.function); - const gop = funcs.getOrPutAssumeCapacity(index); - if (gop.found_existing) { - assert(gop.value_ptr.* == name); - } else { - gop.value_ptr.* = name; - } - }, - .global => { - globals.appendAssumeCapacity(.{ - .index = if (symbol.flags.undefined) - @intFromEnum(symbol.pointee.global_import) - else - @intFromEnum(symbol.pointee.global), - .name = name, - }); - }, - else => {}, + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function)); + + const total_functions: u32 = @intCast(wasm.function_imports.entries.len + wasm.functions.entries.len); + try leb.writeUleb128(binary_bytes.writer(gpa), total_functions); + + for (wasm.function_imports.keys(), 0..) |name_index, function_index| { + const name = name_index.slice(wasm); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + } + for (wasm.functions.keys(), wasm.function_imports.entries.len..) |resolution, function_index| { + const name = resolution.name(wasm).?; + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); } } - for (wasm.data_segments.keys(), 0..) |key, index| { - // bss section is not emitted when this condition holds true, so we also - // do not output a name for it. - if (!import_memory and mem.eql(u8, key, ".bss")) continue; - segments.appendAssumeCapacity(.{ .index = @intCast(index), .name = key }); - } + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global)); - const Sort = struct { - indexes: []const u32, - pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { - return ctx.indexes[lhs] < ctx.indexes[rhs]; + const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); + try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); + + for (wasm.global_imports.keys(), 0..) |name_index, global_index| { + const name = name_index.slice(wasm); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); } - }; - funcs.entries.sortUnstable(@as(Sort, .{ .indexes = funcs.keys() })); - globals.sortUnstable(@as(Sort, .{ .indexes = globals.items(.index) })); - // Data segments are already ordered. + for (wasm.globals.keys(), wasm.global_imports.entries.len..) |resolution, global_index| { + const name = resolution.name(wasm).?; + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + } + } - const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer writeCustomSectionHeader(binary_bytes, header_offset); + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); - const writer = binary_bytes.writer(gpa); - try leb.writeUleb128(writer, @as(u32, @intCast("name".len))); - try writer.writeAll("name"); + const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len); + try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); - try emitNameSubsection(wasm, binary_bytes, .function, funcs.keys(), funcs.values()); - try emitNameSubsection(wasm, binary_bytes, .global, globals.items(.index), globals.items(.name)); - try emitNameSubsection(wasm, binary_bytes, .data_segment, segments.items(.index), segments.items(.name)); -} - -fn emitNameSubsection( - wasm: *const Wasm, - binary_bytes: *std.ArrayListUnmanaged(u8), - section_id: std.wasm.NameSubsection, - indexes: []const u32, - names: []const String, -) !void { - assert(indexes.len == names.len); - const gpa = wasm.base.comp.gpa; - // We must emit subsection size, so first write to a temporary list - var section_list: std.ArrayListUnmanaged(u8) = .empty; - defer section_list.deinit(gpa); - const sub_writer = section_list.writer(gpa); - - try leb.writeUleb128(sub_writer, @as(u32, @intCast(names.len))); - for (indexes, names) |index, name_index| { - const name = name_index.slice(wasm); - log.debug("emit symbol '{s}' type({s})", .{ name, @tagName(section_id) }); - try leb.writeUleb128(sub_writer, index); - try leb.writeUleb128(sub_writer, @as(u32, @intCast(name.len))); - try sub_writer.writeAll(name); + for (data_segments.keys(), 0..) |ds, i| { + const name = ds.ptr(wasm).name.slice(wasm).?; + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i))); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + } } - - // From now, write to the actual writer - const writer = binary_bytes.writer(gpa); - try leb.writeUleb128(writer, @intFromEnum(section_id)); - try leb.writeUleb128(writer, @as(u32, @intCast(section_list.items.len))); - try binary_bytes.appendSlice(gpa, section_list.items); } fn emitFeaturesSection( @@ -1094,11 +1054,15 @@ fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8) } fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { + return replaceHeader(bytes, offset, 0); // 0 = 'custom' section +} + +fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void { const size: u32 = @intCast(bytes.items.len - offset - section_header_size); var buf: [section_header_size]u8 = undefined; var fbw = std.io.fixedBufferStream(&buf); const w = fbw.writer(); - w.writeByte(0) catch unreachable; // 0 = 'custom' section + w.writeByte(tag) catch unreachable; leb.writeUleb128(w, size) catch unreachable; bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); } |
