mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
wasm linker: implement name subsection
unlike the previous implementation, we can simply iterate an array.
This commit is contained in:
parent
e80a203768
commit
d6b42e585b
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)}),
|
||||
|
||||
@ -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 NamedIndex = struct {
|
||||
index: u32,
|
||||
name: String,
|
||||
};
|
||||
|
||||
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 => {},
|
||||
}
|
||||
}
|
||||
|
||||
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 Sort = struct {
|
||||
indexes: []const u32,
|
||||
pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
|
||||
return ctx.indexes[lhs] < ctx.indexes[rhs];
|
||||
}
|
||||
};
|
||||
funcs.entries.sortUnstable(@as(Sort, .{ .indexes = funcs.keys() }));
|
||||
globals.sortUnstable(@as(Sort, .{ .indexes = globals.items(.index) }));
|
||||
// Data segments are already ordered.
|
||||
|
||||
const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer writeCustomSectionHeader(binary_bytes, header_offset);
|
||||
|
||||
const writer = binary_bytes.writer(gpa);
|
||||
try leb.writeUleb128(writer, @as(u32, @intCast("name".len)));
|
||||
try writer.writeAll("name");
|
||||
const name_name = "name";
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len));
|
||||
try binary_bytes.appendSlice(gpa, name_name);
|
||||
|
||||
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));
|
||||
}
|
||||
{
|
||||
const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));
|
||||
|
||||
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);
|
||||
const total_functions: u32 = @intCast(wasm.function_imports.entries.len + wasm.functions.entries.len);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), total_functions);
|
||||
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
{
|
||||
const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));
|
||||
|
||||
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);
|
||||
}
|
||||
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 sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));
|
||||
|
||||
const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), total_globals);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user