implement error table and error names data segments
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user