authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-19 22:39:21-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
logee999d5a14c925b71d4b8c216bf1bd7c1b55e00f
tree9fe8c4e215a6bfa179135d807069a2d7cec601dc
parent7bf53d236d29776b524a3abb65e3f042237e0141

implement error table and error names data segments


2 files changed, 74 insertions(+), 19 deletions(-)

src/link/Wasm.zig+25-13
......@@ -253,6 +253,13 @@ all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,
253253params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
254254returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
255255
256/// All Zcu error names in order, null-terminated, concatenated. No need to
257/// serialize; trivially reconstructed.
258error_name_bytes: std.ArrayListUnmanaged(u8) = .empty,
259/// For each Zcu error, in order, offset into `error_name_bytes` where the name
260/// is stored. No need to serialize; trivially reconstructed.
261error_name_offs: std.ArrayListUnmanaged(u32) = .empty,
262
256263pub const UavFixup = extern struct {
257264 uavs_exe_index: UavsExeIndex,
258265 /// Index into `string_bytes`.
......@@ -979,12 +986,11 @@ pub const GlobalImport = extern struct {
979986 __tls_align,
980987 __tls_base,
981988 __tls_size,
982 __zig_error_name_table,
983989 // Next, index into `object_globals`.
984990 // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
985991 _,
986992
987 const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
993 const first_object_global = @intFromEnum(Resolution.__tls_size) + 1;
988994
989995 pub const Unpacked = union(enum) {
990996 unresolved,
......@@ -994,7 +1000,6 @@ pub const GlobalImport = extern struct {
9941000 __tls_align,
9951001 __tls_base,
9961002 __tls_size,
997 __zig_error_name_table,
9981003 object_global: ObjectGlobalIndex,
9991004 nav_exe: NavsExeIndex,
10001005 nav_obj: NavsObjIndex,
......@@ -1009,7 +1014,6 @@ pub const GlobalImport = extern struct {
10091014 .__tls_align => .__tls_align,
10101015 .__tls_base => .__tls_base,
10111016 .__tls_size => .__tls_size,
1012 .__zig_error_name_table => .__zig_error_name_table,
10131017 _ => {
10141018 const i: u32 = @intFromEnum(r);
10151019 const object_global_index = i - first_object_global;
......@@ -1036,7 +1040,6 @@ pub const GlobalImport = extern struct {
10361040 .__tls_align => .__tls_align,
10371041 .__tls_base => .__tls_base,
10381042 .__tls_size => .__tls_size,
1039 .__zig_error_name_table => .__zig_error_name_table,
10401043 .object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),
10411044 .nav_obj => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
10421045 .nav_exe => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
......@@ -1062,7 +1065,6 @@ pub const GlobalImport = extern struct {
10621065 .__tls_align => @tagName(Unpacked.__tls_align),
10631066 .__tls_base => @tagName(Unpacked.__tls_base),
10641067 .__tls_size => @tagName(Unpacked.__tls_size),
1065 .__zig_error_name_table => @tagName(Unpacked.__zig_error_name_table),
10661068 .object_global => |i| i.name(wasm).slice(wasm),
10671069 .nav_obj => |i| i.name(wasm),
10681070 .nav_exe => |i| i.name(wasm),
......@@ -1332,6 +1334,7 @@ pub const DataSegment = extern struct {
13321334 };
13331335
13341336 pub const Id = enum(u32) {
1337 __zig_error_names,
13351338 __zig_error_name_table,
13361339 /// First, an `ObjectDataSegmentIndex`.
13371340 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
......@@ -1341,6 +1344,7 @@ pub const DataSegment = extern struct {
13411344 const first_object = @intFromEnum(Id.__zig_error_name_table) + 1;
13421345
13431346 pub const Unpacked = union(enum) {
1347 __zig_error_names,
13441348 __zig_error_name_table,
13451349 object: ObjectDataSegmentIndex,
13461350 uav_exe: UavsExeIndex,
......@@ -1351,6 +1355,7 @@ pub const DataSegment = extern struct {
13511355
13521356 pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Id {
13531357 return switch (unpacked) {
1358 .__zig_error_names => .__zig_error_names,
13541359 .__zig_error_name_table => .__zig_error_name_table,
13551360 .object => |i| @enumFromInt(first_object + @intFromEnum(i)),
13561361 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 {
13611366
13621367 pub fn unpack(id: Id, wasm: *const Wasm) Unpacked {
13631368 return switch (id) {
1369 .__zig_error_names => .__zig_error_names,
13641370 .__zig_error_name_table => .__zig_error_name_table,
13651371 _ => {
13661372 const object_index = @intFromEnum(id) - first_object;
......@@ -1393,7 +1399,7 @@ pub const DataSegment = extern struct {
13931399
13941400 pub fn category(id: Id, wasm: *const Wasm) Category {
13951401 return switch (unpack(id, wasm)) {
1396 .__zig_error_name_table => .data,
1402 .__zig_error_names, .__zig_error_name_table => .data,
13971403 .object => |i| {
13981404 const ptr = i.ptr(wasm);
13991405 if (ptr.flags.tls) return .tls;
......@@ -1414,7 +1420,7 @@ pub const DataSegment = extern struct {
14141420
14151421 pub fn isTls(id: Id, wasm: *const Wasm) bool {
14161422 return switch (unpack(id, wasm)) {
1417 .__zig_error_name_table => false,
1423 .__zig_error_names, .__zig_error_name_table => false,
14181424 .object => |i| i.ptr(wasm).flags.tls,
14191425 .uav_exe, .uav_obj => false,
14201426 inline .nav_exe, .nav_obj => |i| {
......@@ -1432,7 +1438,7 @@ pub const DataSegment = extern struct {
14321438
14331439 pub fn name(id: Id, wasm: *const Wasm) []const u8 {
14341440 return switch (unpack(id, wasm)) {
1435 .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
1441 .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
14361442 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
14371443 inline .nav_exe, .nav_obj => |i| {
14381444 const zcu = wasm.base.comp.zcu.?;
......@@ -1445,6 +1451,7 @@ pub const DataSegment = extern struct {
14451451
14461452 pub fn alignment(id: Id, wasm: *const Wasm) Alignment {
14471453 return switch (unpack(id, wasm)) {
1454 .__zig_error_names => .@"1",
14481455 .__zig_error_name_table => wasm.pointerAlignment(),
14491456 .object => |i| i.ptr(wasm).flags.alignment,
14501457 inline .uav_exe, .uav_obj => |i| {
......@@ -1472,6 +1479,7 @@ pub const DataSegment = extern struct {
14721479
14731480 pub fn refCount(id: Id, wasm: *const Wasm) u32 {
14741481 return switch (unpack(id, wasm)) {
1482 .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
14751483 .__zig_error_name_table => wasm.error_name_table_ref_count,
14761484 .object, .uav_obj, .nav_obj => 0,
14771485 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
......@@ -1481,7 +1489,7 @@ pub const DataSegment = extern struct {
14811489 pub fn isPassive(id: Id, wasm: *const Wasm) bool {
14821490 if (wasm.base.comp.config.import_memory and !id.isBss(wasm)) return true;
14831491 return switch (unpack(id, wasm)) {
1484 .__zig_error_name_table => false,
1492 .__zig_error_names, .__zig_error_name_table => false,
14851493 .object => |i| i.ptr(wasm).flags.is_passive,
14861494 .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
14871495 };
......@@ -1489,7 +1497,7 @@ pub const DataSegment = extern struct {
14891497
14901498 pub fn isEmpty(id: Id, wasm: *const Wasm) bool {
14911499 return switch (unpack(id, wasm)) {
1492 .__zig_error_name_table => false,
1500 .__zig_error_names, .__zig_error_name_table => false,
14931501 .object => |i| i.ptr(wasm).payload.off == .none,
14941502 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
14951503 };
......@@ -1497,10 +1505,11 @@ pub const DataSegment = extern struct {
14971505
14981506 pub fn size(id: Id, wasm: *const Wasm) u32 {
14991507 return switch (unpack(id, wasm)) {
1508 .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
15001509 .__zig_error_name_table => {
15011510 const comp = wasm.base.comp;
15021511 const zcu = comp.zcu.?;
1503 const errors_len = 1 + zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
1512 const errors_len = wasm.error_name_offs.items.len;
15041513 const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
15051514 return @intCast(errors_len * elem_size);
15061515 },
......@@ -1589,8 +1598,8 @@ const PreloadedStrings = struct {
15891598 __wasm_init_memory: String,
15901599 __wasm_init_memory_flag: String,
15911600 __wasm_init_tls: String,
1592 __zig_error_name_table: String,
15931601 __zig_error_names: String,
1602 __zig_error_name_table: String,
15941603 __zig_errors_len: String,
15951604 _initialize: String,
15961605 _start: String,
......@@ -2367,6 +2376,9 @@ pub fn deinit(wasm: *Wasm) void {
23672376 wasm.params_scratch.deinit(gpa);
23682377 wasm.returns_scratch.deinit(gpa);
23692378
2379 wasm.error_name_bytes.deinit(gpa);
2380 wasm.error_name_offs.deinit(gpa);
2381
23702382 wasm.missing_exports.deinit(gpa);
23712383}
23722384
src/link/Wasm/Flush.zig+49-6
......@@ -71,10 +71,26 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
7171 };
7272 const is_obj = comp.config.output_mode == .Obj;
7373 const allow_undefined = is_obj or wasm.import_symbols;
74 const zcu = wasm.base.comp.zcu.?;
75 const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!
7674
77 {
75 if (comp.zcu) |zcu| {
76 const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!
77
78 if (wasm.error_name_table_ref_count > 0) {
79 // Ensure Zcu error name structures are populated.
80 const full_error_names = ip.global_error_set.getNamesFromMainThread();
81 try wasm.error_name_offs.ensureTotalCapacity(gpa, full_error_names.len + 1);
82 if (wasm.error_name_offs.items.len == 0) {
83 // Dummy entry at index 0 to avoid a sub instruction at `@errorName` sites.
84 wasm.error_name_offs.appendAssumeCapacity(0);
85 }
86 const new_error_names = full_error_names[wasm.error_name_offs.items.len - 1 ..];
87 for (new_error_names) |error_name| {
88 wasm.error_name_offs.appendAssumeCapacity(@intCast(wasm.error_name_bytes.items.len));
89 const s: [:0]const u8 = error_name.toSlice(ip);
90 try wasm.error_name_bytes.appendSlice(gpa, s[0 .. s.len + 1]);
91 }
92 }
93
7894 const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;
7995
8096 for (wasm.nav_exports.keys()) |*nav_export| {
......@@ -144,7 +160,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
144160 // unused segments can be omitted.
145161 try f.data_segments.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len +
146162 wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len +
147 wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 1);
163 wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 2);
148164 if (is_obj) assert(wasm.uavs_exe.entries.len == 0);
149165 if (is_obj) assert(wasm.navs_exe.entries.len == 0);
150166 if (!is_obj) assert(wasm.uavs_obj.entries.len == 0);
......@@ -170,6 +186,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
170186 }), @as(u32, undefined));
171187 }
172188 if (wasm.error_name_table_ref_count > 0) {
189 f.data_segments.putAssumeCapacity(.__zig_error_names, @as(u32, undefined));
173190 f.data_segments.putAssumeCapacity(.__zig_error_name_table, @as(u32, undefined));
174191 }
175192
......@@ -546,7 +563,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
546563 .__tls_align => @panic("TODO"),
547564 .__tls_base => @panic("TODO"),
548565 .__tls_size => @panic("TODO"),
549 .__zig_error_name_table => @panic("TODO"),
550566 .object_global => |i| {
551567 const global = i.ptr(wasm);
552568 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 {
730746 const code_start = binary_bytes.items.len;
731747 append: {
732748 const code = switch (segment_id.unpack(wasm)) {
749 .__zig_error_names => {
750 try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items);
751 break :append;
752 },
733753 .__zig_error_name_table => {
734 if (true) @panic("TODO lower zig error name table");
754 if (is_obj) @panic("TODO error name table reloc");
755 const base = f.data_segments.get(.__zig_error_names).?;
756 if (!is64) {
757 try emitErrorNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32);
758 } else {
759 try emitErrorNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64);
760 }
735761 break :append;
736762 },
737763 .object => |i| c: {
......@@ -1491,3 +1517,20 @@ fn uleb128size(x: u32) u32 {
14911517 while (value != 0) : (size += 1) value >>= 7;
14921518 return size;
14931519}
1520
1521fn emitErrorNameTable(
1522 gpa: Allocator,
1523 code: *std.ArrayListUnmanaged(u8),
1524 error_name_offs: []const u32,
1525 error_name_bytes: []const u8,
1526 base: u32,
1527 comptime Int: type,
1528) error{OutOfMemory}!void {
1529 const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8);
1530 try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * error_name_offs.len);
1531 for (error_name_offs) |off| {
1532 const name_len: u32 = @intCast(mem.indexOfScalar(u8, error_name_bytes[off..], 0).?);
1533 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little);
1534 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);
1535 }
1536}