Commit ee999d5a14
src/link/Wasm/Flush.zig
@@ -71,10 +71,26 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
};
const is_obj = comp.config.output_mode == .Obj;
const allow_undefined = is_obj or wasm.import_symbols;
- const zcu = wasm.base.comp.zcu.?;
- const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!
- {
+ if (comp.zcu) |zcu| {
+ const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!
+
+ if (wasm.error_name_table_ref_count > 0) {
+ // Ensure Zcu error name structures are populated.
+ const full_error_names = ip.global_error_set.getNamesFromMainThread();
+ try wasm.error_name_offs.ensureTotalCapacity(gpa, full_error_names.len + 1);
+ if (wasm.error_name_offs.items.len == 0) {
+ // Dummy entry at index 0 to avoid a sub instruction at `@errorName` sites.
+ wasm.error_name_offs.appendAssumeCapacity(0);
+ }
+ const new_error_names = full_error_names[wasm.error_name_offs.items.len - 1 ..];
+ for (new_error_names) |error_name| {
+ wasm.error_name_offs.appendAssumeCapacity(@intCast(wasm.error_name_bytes.items.len));
+ const s: [:0]const u8 = error_name.toSlice(ip);
+ try wasm.error_name_bytes.appendSlice(gpa, s[0 .. s.len + 1]);
+ }
+ }
+
const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;
for (wasm.nav_exports.keys()) |*nav_export| {
@@ -144,7 +160,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
// unused segments can be omitted.
try f.data_segments.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len +
wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len +
- wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 1);
+ wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 2);
if (is_obj) assert(wasm.uavs_exe.entries.len == 0);
if (is_obj) assert(wasm.navs_exe.entries.len == 0);
if (!is_obj) assert(wasm.uavs_obj.entries.len == 0);
@@ -170,6 +186,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
}), @as(u32, undefined));
}
if (wasm.error_name_table_ref_count > 0) {
+ f.data_segments.putAssumeCapacity(.__zig_error_names, @as(u32, undefined));
f.data_segments.putAssumeCapacity(.__zig_error_name_table, @as(u32, undefined));
}
@@ -546,7 +563,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
.__tls_align => @panic("TODO"),
.__tls_base => @panic("TODO"),
.__tls_size => @panic("TODO"),
- .__zig_error_name_table => @panic("TODO"),
.object_global => |i| {
const global = i.ptr(wasm);
try binary_writer.writeByte(@intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())));
@@ -730,8 +746,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
const code_start = binary_bytes.items.len;
append: {
const code = switch (segment_id.unpack(wasm)) {
+ .__zig_error_names => {
+ try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items);
+ break :append;
+ },
.__zig_error_name_table => {
- if (true) @panic("TODO lower zig error name table");
+ if (is_obj) @panic("TODO error name table reloc");
+ const base = f.data_segments.get(.__zig_error_names).?;
+ if (!is64) {
+ try emitErrorNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32);
+ } else {
+ try emitErrorNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64);
+ }
break :append;
},
.object => |i| c: {
@@ -1491,3 +1517,20 @@ fn uleb128size(x: u32) u32 {
while (value != 0) : (size += 1) value >>= 7;
return size;
}
+
+fn emitErrorNameTable(
+ gpa: Allocator,
+ code: *std.ArrayListUnmanaged(u8),
+ error_name_offs: []const u32,
+ error_name_bytes: []const u8,
+ base: u32,
+ comptime Int: type,
+) error{OutOfMemory}!void {
+ const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8);
+ try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * error_name_offs.len);
+ for (error_name_offs) |off| {
+ const name_len: u32 = @intCast(mem.indexOfScalar(u8, error_name_bytes[off..], 0).?);
+ mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little);
+ mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);
+ }
+}
src/link/Wasm.zig
@@ -253,6 +253,13 @@ all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,
params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
+/// All Zcu error names in order, null-terminated, concatenated. No need to
+/// serialize; trivially reconstructed.
+error_name_bytes: std.ArrayListUnmanaged(u8) = .empty,
+/// For each Zcu error, in order, offset into `error_name_bytes` where the name
+/// is stored. No need to serialize; trivially reconstructed.
+error_name_offs: std.ArrayListUnmanaged(u32) = .empty,
+
pub const UavFixup = extern struct {
uavs_exe_index: UavsExeIndex,
/// Index into `string_bytes`.
@@ -979,12 +986,11 @@ pub const GlobalImport = extern struct {
__tls_align,
__tls_base,
__tls_size,
- __zig_error_name_table,
// Next, index into `object_globals`.
// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
_,
- const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
+ const first_object_global = @intFromEnum(Resolution.__tls_size) + 1;
pub const Unpacked = union(enum) {
unresolved,
@@ -994,7 +1000,6 @@ pub const GlobalImport = extern struct {
__tls_align,
__tls_base,
__tls_size,
- __zig_error_name_table,
object_global: ObjectGlobalIndex,
nav_exe: NavsExeIndex,
nav_obj: NavsObjIndex,
@@ -1009,7 +1014,6 @@ pub const GlobalImport = extern struct {
.__tls_align => .__tls_align,
.__tls_base => .__tls_base,
.__tls_size => .__tls_size,
- .__zig_error_name_table => .__zig_error_name_table,
_ => {
const i: u32 = @intFromEnum(r);
const object_global_index = i - first_object_global;
@@ -1036,7 +1040,6 @@ pub const GlobalImport = extern struct {
.__tls_align => .__tls_align,
.__tls_base => .__tls_base,
.__tls_size => .__tls_size,
- .__zig_error_name_table => .__zig_error_name_table,
.object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),
.nav_obj => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
.nav_exe => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
@@ -1062,7 +1065,6 @@ pub const GlobalImport = extern struct {
.__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),
@@ -1332,6 +1334,7 @@ pub const DataSegment = extern struct {
};
pub const Id = enum(u32) {
+ __zig_error_names,
__zig_error_name_table,
/// First, an `ObjectDataSegmentIndex`.
/// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
@@ -1341,6 +1344,7 @@ pub const DataSegment = extern struct {
const first_object = @intFromEnum(Id.__zig_error_name_table) + 1;
pub const Unpacked = union(enum) {
+ __zig_error_names,
__zig_error_name_table,
object: ObjectDataSegmentIndex,
uav_exe: UavsExeIndex,
@@ -1351,6 +1355,7 @@ pub const DataSegment = extern struct {
pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Id {
return switch (unpacked) {
+ .__zig_error_names => .__zig_error_names,
.__zig_error_name_table => .__zig_error_name_table,
.object => |i| @enumFromInt(first_object + @intFromEnum(i)),
inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),
@@ -1361,6 +1366,7 @@ pub const DataSegment = extern struct {
pub fn unpack(id: Id, wasm: *const Wasm) Unpacked {
return switch (id) {
+ .__zig_error_names => .__zig_error_names,
.__zig_error_name_table => .__zig_error_name_table,
_ => {
const object_index = @intFromEnum(id) - first_object;
@@ -1393,7 +1399,7 @@ pub const DataSegment = extern struct {
pub fn category(id: Id, wasm: *const Wasm) Category {
return switch (unpack(id, wasm)) {
- .__zig_error_name_table => .data,
+ .__zig_error_names, .__zig_error_name_table => .data,
.object => |i| {
const ptr = i.ptr(wasm);
if (ptr.flags.tls) return .tls;
@@ -1414,7 +1420,7 @@ pub const DataSegment = extern struct {
pub fn isTls(id: Id, wasm: *const Wasm) bool {
return switch (unpack(id, wasm)) {
- .__zig_error_name_table => false,
+ .__zig_error_names, .__zig_error_name_table => false,
.object => |i| i.ptr(wasm).flags.tls,
.uav_exe, .uav_obj => false,
inline .nav_exe, .nav_obj => |i| {
@@ -1432,7 +1438,7 @@ pub const DataSegment = extern struct {
pub fn name(id: Id, wasm: *const Wasm) []const u8 {
return switch (unpack(id, wasm)) {
- .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
+ .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
.object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
inline .nav_exe, .nav_obj => |i| {
const zcu = wasm.base.comp.zcu.?;
@@ -1445,6 +1451,7 @@ pub const DataSegment = extern struct {
pub fn alignment(id: Id, wasm: *const Wasm) Alignment {
return switch (unpack(id, wasm)) {
+ .__zig_error_names => .@"1",
.__zig_error_name_table => wasm.pointerAlignment(),
.object => |i| i.ptr(wasm).flags.alignment,
inline .uav_exe, .uav_obj => |i| {
@@ -1472,6 +1479,7 @@ pub const DataSegment = extern struct {
pub fn refCount(id: Id, wasm: *const Wasm) u32 {
return switch (unpack(id, wasm)) {
+ .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
.__zig_error_name_table => wasm.error_name_table_ref_count,
.object, .uav_obj, .nav_obj => 0,
inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
@@ -1481,7 +1489,7 @@ pub const DataSegment = extern struct {
pub fn isPassive(id: Id, wasm: *const Wasm) bool {
if (wasm.base.comp.config.import_memory and !id.isBss(wasm)) return true;
return switch (unpack(id, wasm)) {
- .__zig_error_name_table => false,
+ .__zig_error_names, .__zig_error_name_table => false,
.object => |i| i.ptr(wasm).flags.is_passive,
.uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
};
@@ -1489,7 +1497,7 @@ pub const DataSegment = extern struct {
pub fn isEmpty(id: Id, wasm: *const Wasm) bool {
return switch (unpack(id, wasm)) {
- .__zig_error_name_table => false,
+ .__zig_error_names, .__zig_error_name_table => false,
.object => |i| i.ptr(wasm).payload.off == .none,
inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
};
@@ -1497,10 +1505,11 @@ pub const DataSegment = extern struct {
pub fn size(id: Id, wasm: *const Wasm) u32 {
return switch (unpack(id, wasm)) {
+ .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
.__zig_error_name_table => {
const comp = wasm.base.comp;
const zcu = comp.zcu.?;
- const errors_len = 1 + zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
+ const errors_len = wasm.error_name_offs.items.len;
const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
return @intCast(errors_len * elem_size);
},
@@ -1589,8 +1598,8 @@ const PreloadedStrings = struct {
__wasm_init_memory: String,
__wasm_init_memory_flag: String,
__wasm_init_tls: String,
- __zig_error_name_table: String,
__zig_error_names: String,
+ __zig_error_name_table: String,
__zig_errors_len: String,
_initialize: String,
_start: String,
@@ -2367,6 +2376,9 @@ pub fn deinit(wasm: *Wasm) void {
wasm.params_scratch.deinit(gpa);
wasm.returns_scratch.deinit(gpa);
+ wasm.error_name_bytes.deinit(gpa);
+ wasm.error_name_offs.deinit(gpa);
+
wasm.missing_exports.deinit(gpa);
}