authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-04 23:22:09-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
log943dac3e8558712096d55a30897057d75444178c
tree71642efb143c8811cd59c407479dfacbc9723942
parent9bf715de74a7d5badeae932afb594b7c6b33afa3

compiler: add type safety for export indices


18 files changed, 213 insertions(+), 126 deletions(-)

src/Sema.zig+5-5
......@@ -38298,7 +38298,7 @@ pub fn flushExports(sema: *Sema) !void {
3829838298 // So, pick up and delete any existing exports. This strategy performs
3829938299 // redundant work, but that's okay, because this case is exceedingly rare.
3830038300 if (zcu.single_exports.get(sema.owner)) |export_idx| {
38301 try sema.exports.append(gpa, zcu.all_exports.items[export_idx]);
38301 try sema.exports.append(gpa, export_idx.ptr(zcu).*);
3830238302 } else if (zcu.multi_exports.get(sema.owner)) |info| {
3830338303 try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
3830438304 }
......@@ -38307,12 +38307,12 @@ pub fn flushExports(sema: *Sema) !void {
3830738307 // `sema.exports` is completed; store the data into the `Zcu`.
3830838308 if (sema.exports.items.len == 1) {
3830938309 try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
38310 const export_idx = zcu.free_exports.popOrNull() orelse idx: {
38310 const export_idx: Zcu.Export.Index = zcu.free_exports.popOrNull() orelse idx: {
3831138311 _ = try zcu.all_exports.addOne(gpa);
38312 break :idx zcu.all_exports.items.len - 1;
38312 break :idx @enumFromInt(zcu.all_exports.items.len - 1);
3831338313 };
38314 zcu.all_exports.items[export_idx] = sema.exports.items[0];
38315 zcu.single_exports.putAssumeCapacityNoClobber(sema.owner, @intCast(export_idx));
38314 export_idx.ptr(zcu).* = sema.exports.items[0];
38315 zcu.single_exports.putAssumeCapacityNoClobber(sema.owner, export_idx);
3831638316 } else {
3831738317 try zcu.multi_exports.ensureUnusedCapacity(gpa, 1);
3831838318 const exports_base = zcu.all_exports.items.len;
src/Zcu.zig+11-13
......@@ -79,11 +79,11 @@ local_zir_cache: Compilation.Directory,
7979all_exports: std.ArrayListUnmanaged(Export) = .empty,
8080/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
8181/// future semantic analysis.
82free_exports: std.ArrayListUnmanaged(u32) = .empty,
82free_exports: std.ArrayListUnmanaged(Export.Index) = .empty,
8383/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
8484/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
8585/// whose analysis triggered the export.
86single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty,
86single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, Export.Index) = .empty,
8787/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
8888/// The exports are `all_exports.items[index..][0..len]`.
8989multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
......@@ -145,8 +145,7 @@ compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
145145failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .empty,
146146/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
147147failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .empty,
148/// Key is index into `all_exports`.
149failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .empty,
148failed_exports: std.AutoArrayHashMapUnmanaged(Export.Index, *ErrorMsg) = .empty,
150149/// If analysis failed due to a cimport error, the corresponding Clang errors
151150/// are stored here.
152151cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .empty,
......@@ -3101,7 +3100,7 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
31013100 const gpa = zcu.gpa;
31023101
31033102 const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
3104 .{ kv.value, 1 }
3103 .{ @intFromEnum(kv.value), 1 }
31053104 else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
31063105 .{ info.value.index, info.value.len }
31073106 else
......@@ -3115,11 +3114,12 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
31153114 // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
31163115 // within a single update.
31173116 if (dev.env.supports(.incremental)) {
3118 for (exports, exports_base..) |exp, export_idx| {
3117 for (exports, exports_base..) |exp, export_index_usize| {
3118 const export_idx: Export.Index = @enumFromInt(export_index_usize);
31193119 if (zcu.comp.bin_file) |lf| {
31203120 lf.deleteExport(exp.exported, exp.opts.name);
31213121 }
3122 if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
3122 if (zcu.failed_exports.fetchSwapRemove(export_idx)) |failed_kv| {
31233123 failed_kv.value.destroy(gpa);
31243124 }
31253125 }
......@@ -3131,7 +3131,7 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
31313131 return;
31323132 };
31333133 for (exports_base..exports_base + exports_len) |export_idx| {
3134 zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
3134 zcu.free_exports.appendAssumeCapacity(@enumFromInt(export_idx));
31353135 }
31363136}
31373137
......@@ -3277,7 +3277,7 @@ fn lockAndClearFileCompileError(zcu: *Zcu, file: *File) void {
32773277
32783278pub fn handleUpdateExports(
32793279 zcu: *Zcu,
3280 export_indices: []const u32,
3280 export_indices: []const Export.Index,
32813281 result: link.File.UpdateExportsError!void,
32823282) Allocator.Error!void {
32833283 const gpa = zcu.gpa;
......@@ -3285,12 +3285,10 @@ pub fn handleUpdateExports(
32853285 error.OutOfMemory => return error.OutOfMemory,
32863286 error.AnalysisFail => {
32873287 const export_idx = export_indices[0];
3288 const new_export = &zcu.all_exports.items[export_idx];
3288 const new_export = export_idx.ptr(zcu);
32893289 new_export.status = .failed_retryable;
32903290 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
3291 const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{
3292 @errorName(err),
3293 });
3291 const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{@errorName(err)});
32943292 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
32953293 },
32963294 };
src/Zcu/PerThread.zig+8-8
......@@ -2815,8 +2815,8 @@ pub fn processExports(pt: Zcu.PerThread) !void {
28152815 const gpa = zcu.gpa;
28162816
28172817 // First, construct a mapping of every exported value and Nav to the indices of all its different exports.
2818 var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(u32)) = .empty;
2819 var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(u32)) = .empty;
2818 var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty;
2819 var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty;
28202820 defer {
28212821 for (nav_exports.values()) |*exports| {
28222822 exports.deinit(gpa);
......@@ -2835,7 +2835,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
28352835 try nav_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count());
28362836
28372837 for (zcu.single_exports.values()) |export_idx| {
2838 const exp = zcu.all_exports.items[export_idx];
2838 const exp = export_idx.ptr(zcu);
28392839 const value_ptr, const found_existing = switch (exp.exported) {
28402840 .nav => |nav| gop: {
28412841 const gop = try nav_exports.getOrPut(gpa, nav);
......@@ -2863,7 +2863,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
28632863 },
28642864 };
28652865 if (!found_existing) value_ptr.* = .{};
2866 try value_ptr.append(gpa, @intCast(export_idx));
2866 try value_ptr.append(gpa, @enumFromInt(export_idx));
28672867 }
28682868 }
28692869
......@@ -2882,20 +2882,20 @@ pub fn processExports(pt: Zcu.PerThread) !void {
28822882 }
28832883}
28842884
2885const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
2885const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Zcu.Export.Index);
28862886
28872887fn processExportsInner(
28882888 pt: Zcu.PerThread,
28892889 symbol_exports: *SymbolExports,
28902890 exported: Zcu.Exported,
2891 export_indices: []const u32,
2891 export_indices: []const Zcu.Export.Index,
28922892) error{OutOfMemory}!void {
28932893 const zcu = pt.zcu;
28942894 const gpa = zcu.gpa;
28952895 const ip = &zcu.intern_pool;
28962896
28972897 for (export_indices) |export_idx| {
2898 const new_export = &zcu.all_exports.items[export_idx];
2898 const new_export = export_idx.ptr(zcu);
28992899 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
29002900 if (gop.found_existing) {
29012901 new_export.status = .failed_retryable;
......@@ -2904,7 +2904,7 @@ fn processExportsInner(
29042904 new_export.opts.name.fmt(ip),
29052905 });
29062906 errdefer msg.destroy(gpa);
2907 const other_export = zcu.all_exports.items[gop.value_ptr.*];
2907 const other_export = gop.value_ptr.ptr(zcu);
29082908 try zcu.errNote(other_export.src, msg, "other symbol here", .{});
29092909 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
29102910 new_export.status = .failed;
src/arch/wasm/CodeGen.zig+8-15
......@@ -1,7 +1,6 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const Allocator = std.mem.Allocator;
4const ArrayList = std.ArrayList;
54const assert = std.debug.assert;
65const testing = std.testing;
76const leb = std.leb;
......@@ -631,7 +630,7 @@ blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, struct {
631630/// Maps `loop` instructions to their label. `br` to here repeats the loop.
632631loops: std.AutoHashMapUnmanaged(Air.Inst.Index, u32) = .empty,
633632/// `bytes` contains the wasm bytecode belonging to the 'code' section.
634code: *ArrayList(u8),
633code: *std.ArrayListUnmanaged(u8),
635634/// The index the next local generated will have
636635/// NOTE: arguments share the index with locals therefore the first variable
637636/// will have the index that comes after the last argument's index
......@@ -639,8 +638,6 @@ local_index: u32 = 0,
639638/// The index of the current argument.
640639/// Used to track which argument is being referenced in `airArg`.
641640arg_index: u32 = 0,
642/// If codegen fails, an error messages will be allocated and saved in `err_msg`
643err_msg: *Zcu.ErrorMsg,
644641/// List of all locals' types generated throughout this declaration
645642/// used to emit locals count at start of 'code' section.
646643locals: std.ArrayListUnmanaged(u8),
......@@ -732,10 +729,9 @@ pub fn deinit(func: *CodeGen) void {
732729 func.* = undefined;
733730}
734731
735/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
736fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
737 func.err_msg = try Zcu.ErrorMsg.create(func.gpa, func.src_loc, fmt, args);
738 return error.CodegenFail;
732fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
733 const msg = try Zcu.ErrorMsg.create(func.gpa, func.src_loc, fmt, args);
734 return func.pt.zcu.codegenFailMsg(func.owner_nav, msg);
739735}
740736
741737/// Resolves the `WValue` for the given instruction `inst`
......@@ -1173,9 +1169,9 @@ pub fn generate(
11731169 func_index: InternPool.Index,
11741170 air: Air,
11751171 liveness: Liveness,
1176 code: *std.ArrayList(u8),
1172 code: *std.ArrayListUnmanaged(u8),
11771173 debug_output: link.File.DebugInfoOutput,
1178) codegen.CodeGenError!codegen.Result {
1174) codegen.CodeGenError!void {
11791175 const zcu = pt.zcu;
11801176 const gpa = zcu.gpa;
11811177 const func = zcu.funcInfo(func_index);
......@@ -1189,7 +1185,6 @@ pub fn generate(
11891185 .code = code,
11901186 .owner_nav = func.owner_nav,
11911187 .src_loc = src_loc,
1192 .err_msg = undefined,
11931188 .locals = .{},
11941189 .target = target,
11951190 .bin_file = bin_file.cast(.wasm).?,
......@@ -1199,11 +1194,9 @@ pub fn generate(
11991194 defer code_gen.deinit();
12001195
12011196 genFunc(&code_gen) catch |err| switch (err) {
1202 error.CodegenFail => return codegen.Result{ .fail = code_gen.err_msg },
1203 else => |e| return e,
1197 error.CodegenFail => return error.CodegenFail,
1198 else => |e| return code_gen.fail("failed to generate function: {s}", .{@errorName(e)}),
12041199 };
1205
1206 return codegen.Result.ok;
12071200}
12081201
12091202fn genFunc(func: *CodeGen) InnerError!void {
src/arch/wasm/Mir.zig+4-4
......@@ -80,15 +80,15 @@ pub const Inst = struct {
8080 ///
8181 /// Uses `nop`
8282 @"return" = 0x0F,
83 /// Calls a function using `nav_index`.
84 call_nav,
85 /// Calls a function using `func_index`.
86 call_func,
8783 /// Calls a function pointer by its function signature
8884 /// and index into the function table.
8985 ///
9086 /// Uses `label`
9187 call_indirect = 0x11,
88 /// Calls a function using `nav_index`.
89 call_nav,
90 /// Calls a function using `func_index`.
91 call_func,
9292 /// Calls a function by its index.
9393 ///
9494 /// The function is the auto-generated tag name function for the type
src/codegen/c.zig+4-4
......@@ -3052,12 +3052,12 @@ pub fn genDeclValue(
30523052 try w.writeAll(";\n");
30533053}
30543054
3055pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const u32) !void {
3055pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void {
30563056 const zcu = dg.pt.zcu;
30573057 const ip = &zcu.intern_pool;
30583058 const fwd = dg.fwdDeclWriter();
30593059
3060 const main_name = zcu.all_exports.items[export_indices[0]].opts.name;
3060 const main_name = export_indices[0].ptr(zcu).opts.name;
30613061 try fwd.writeAll("#define ");
30623062 switch (exported) {
30633063 .nav => |nav| try dg.renderNavName(fwd, nav),
......@@ -3069,7 +3069,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
30693069
30703070 const exported_val = exported.getValue(zcu);
30713071 if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| {
3072 const @"export" = &zcu.all_exports.items[export_index];
3072 const @"export" = export_index.ptr(zcu);
30733073 try fwd.writeAll("zig_extern ");
30743074 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
30753075 try dg.renderFunctionSignature(
......@@ -3091,7 +3091,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
30913091 else => true,
30923092 };
30933093 for (export_indices) |export_index| {
3094 const @"export" = &zcu.all_exports.items[export_index];
3094 const @"export" = export_index.ptr(zcu);
30953095 try fwd.writeAll("zig_extern ");
30963096 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
30973097 const extern_name = @"export".opts.name.toSlice(ip);
src/codegen/llvm.zig+1-1
......@@ -1810,7 +1810,7 @@ pub const Object = struct {
18101810 self: *Object,
18111811 pt: Zcu.PerThread,
18121812 exported: Zcu.Exported,
1813 export_indices: []const u32,
1813 export_indices: []const Zcu.Export.Index,
18141814 ) link.File.UpdateExportsError!void {
18151815 assert(std.meta.eql(pt, self.pt));
18161816 const zcu = pt.zcu;
src/link.zig+1-1
......@@ -817,7 +817,7 @@ pub const File = struct {
817817 base: *File,
818818 pt: Zcu.PerThread,
819819 exported: Zcu.Exported,
820 export_indices: []const u32,
820 export_indices: []const Zcu.Export.Index,
821821 ) UpdateExportsError!void {
822822 switch (base.tag) {
823823 inline else => |tag| {
src/link/C.zig+1-1
......@@ -840,7 +840,7 @@ pub fn updateExports(
840840 self: *C,
841841 pt: Zcu.PerThread,
842842 exported: Zcu.Exported,
843 export_indices: []const u32,
843 export_indices: []const Zcu.Export.Index,
844844) !void {
845845 const zcu = pt.zcu;
846846 const gpa = zcu.gpa;
src/link/Elf.zig+1-1
......@@ -2393,7 +2393,7 @@ pub fn updateExports(
23932393 self: *Elf,
23942394 pt: Zcu.PerThread,
23952395 exported: Zcu.Exported,
2396 export_indices: []const u32,
2396 export_indices: []const Zcu.Export.Index,
23972397) link.File.UpdateExportsError!void {
23982398 if (build_options.skip_non_native and builtin.object_format != .elf) {
23992399 @panic("Attempted to compile for object format that was disabled by build configuration");
src/link/Elf/ZigObject.zig+1-1
......@@ -1745,7 +1745,7 @@ pub fn updateExports(
17451745 elf_file: *Elf,
17461746 pt: Zcu.PerThread,
17471747 exported: Zcu.Exported,
1748 export_indices: []const u32,
1748 export_indices: []const Zcu.Export.Index,
17491749) link.File.UpdateExportsError!void {
17501750 const tracy = trace(@src());
17511751 defer tracy.end();
src/link/MachO.zig+1-1
......@@ -3056,7 +3056,7 @@ pub fn updateExports(
30563056 self: *MachO,
30573057 pt: Zcu.PerThread,
30583058 exported: Zcu.Exported,
3059 export_indices: []const u32,
3059 export_indices: []const Zcu.Export.Index,
30603060) link.File.UpdateExportsError!void {
30613061 if (build_options.skip_non_native and builtin.object_format != .macho) {
30623062 @panic("Attempted to compile for object format that was disabled by build configuration");
src/link/MachO/ZigObject.zig+1-1
......@@ -1246,7 +1246,7 @@ pub fn updateExports(
12461246 macho_file: *MachO,
12471247 pt: Zcu.PerThread,
12481248 exported: Zcu.Exported,
1249 export_indices: []const u32,
1249 export_indices: []const Zcu.Export.Index,
12501250) link.File.UpdateExportsError!void {
12511251 const tracy = trace(@src());
12521252 defer tracy.end();
src/link/NvPtx.zig+1-1
......@@ -100,7 +100,7 @@ pub fn updateExports(
100100 self: *NvPtx,
101101 pt: Zcu.PerThread,
102102 exported: Zcu.Exported,
103 export_indices: []const u32,
103 export_indices: []const Zcu.Export.Index,
104104) !void {
105105 if (build_options.skip_non_native and builtin.object_format != .nvptx)
106106 @panic("Attempted to compile for object format that was disabled by build configuration");
src/link/Plan9.zig+3-3
......@@ -60,7 +60,7 @@ fn_nav_table: std.AutoArrayHashMapUnmanaged(
6060data_nav_table: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u8) = .empty,
6161/// When `updateExports` is called, we store the export indices here, to be used
6262/// during flush.
63nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u32) = .empty,
63nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []Zcu.Export.Index) = .empty,
6464
6565lazy_syms: LazySymbolTable = .{},
6666
......@@ -1007,7 +1007,7 @@ pub fn updateExports(
10071007 self: *Plan9,
10081008 pt: Zcu.PerThread,
10091009 exported: Zcu.Exported,
1010 export_indices: []const u32,
1010 export_indices: []const Zcu.Export.Index,
10111011) !void {
10121012 const gpa = self.base.comp.gpa;
10131013 switch (exported) {
......@@ -1018,7 +1018,7 @@ pub fn updateExports(
10181018 gpa.free(kv.value);
10191019 }
10201020 try self.nav_exports.ensureUnusedCapacity(gpa, 1);
1021 const duped_indices = try gpa.dupe(u32, export_indices);
1021 const duped_indices = try gpa.dupe(Zcu.Export.Index, export_indices);
10221022 self.nav_exports.putAssumeCapacityNoClobber(nav, duped_indices);
10231023 },
10241024 }
src/link/SpirV.zig+2-2
......@@ -155,7 +155,7 @@ pub fn updateExports(
155155 self: *SpirV,
156156 pt: Zcu.PerThread,
157157 exported: Zcu.Exported,
158 export_indices: []const u32,
158 export_indices: []const Zcu.Export.Index,
159159) !void {
160160 const zcu = pt.zcu;
161161 const ip = &zcu.intern_pool;
......@@ -190,7 +190,7 @@ pub fn updateExports(
190190 };
191191
192192 for (export_indices) |export_idx| {
193 const exp = zcu.all_exports.items[export_idx];
193 const exp = export_idx.ptr(zcu);
194194 try self.object.spv.declareEntryPoint(
195195 spv_decl_index,
196196 exp.opts.name.toSlice(ip),
src/link/Wasm.zig+155-58
......@@ -56,6 +56,10 @@ base: link.File,
5656/// string_table entries for them. Alternately those sites could be moved to
5757/// use a different byte array for this purpose.
5858string_bytes: std.ArrayListUnmanaged(u8),
59/// Sometimes we have logic that wants to borrow string bytes to store
60/// arbitrary things in there. In this case it is not allowed to intern new
61/// strings during this time. This safety lock is used to detect misuses.
62string_bytes_lock: std.debug.SafetyLock = .{},
5963/// Omitted when serializing linker state.
6064string_table: String.Table,
6165/// Symbol name of the entry function to export
......@@ -202,6 +206,10 @@ any_exports_updated: bool = true,
202206/// Index into `objects`.
203207pub const ObjectIndex = enum(u32) {
204208 _,
209
210 pub fn ptr(index: ObjectIndex, wasm: *const Wasm) *Object {
211 return &wasm.objects.items[@intFromEnum(index)];
212 }
205213};
206214
207215/// Index into `functions`.
......@@ -269,12 +277,26 @@ pub const SourceLocation = enum(u32) {
269277 };
270278 }
271279
280 pub fn unpack(sl: SourceLocation, wasm: *const Wasm) Unpacked {
281 return switch (sl) {
282 .zig_object_nofile => .zig_object_nofile,
283 .none => .none,
284 _ => {
285 const i = @intFromEnum(sl);
286 if (i < wasm.objects.items.len) return .{ .object_index = @enumFromInt(i) };
287 const sl_index = i - wasm.objects.items.len;
288 _ = sl_index;
289 @panic("TODO");
290 },
291 };
292 }
293
272294 pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {
273295 const diags = &wasm.base.comp.link_diags;
274296 switch (sl.unpack(wasm)) {
275297 .none => unreachable,
276298 .zig_object_nofile => diags.addError("zig compilation unit: " ++ f, args),
277 .object_index => |i| diags.addError("{}: " ++ f, .{wasm.objects.items[i].path} ++ args),
299 .object_index => |i| diags.addError("{}: " ++ f, .{i.ptr(wasm).path} ++ args),
278300 .source_location_index => @panic("TODO"),
279301 }
280302 }
......@@ -520,6 +542,10 @@ pub const FunctionImport = extern struct {
520542 /// Index into `object_function_imports`.
521543 pub const Index = enum(u32) {
522544 _,
545
546 pub fn ptr(index: FunctionImport.Index, wasm: *const Wasm) *FunctionImport {
547 return &wasm.object_function_imports.items[@intFromEnum(index)];
548 }
523549 };
524550};
525551
......@@ -543,7 +569,8 @@ pub const GlobalImport = extern struct {
543569 source_location: SourceLocation,
544570 resolution: Resolution,
545571
546 /// Represents a synthetic global, or a global from an object.
572 /// Represents a synthetic global, a global from an object, or a global
573 /// from the Zcu.
547574 pub const Resolution = enum(u32) {
548575 unresolved,
549576 __heap_base,
......@@ -556,6 +583,68 @@ pub const GlobalImport = extern struct {
556583 // Next, index into `object_globals`.
557584 // Next, index into `navs`.
558585 _,
586
587 const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
588
589 pub const Unpacked = union(enum) {
590 unresolved,
591 __heap_base,
592 __heap_end,
593 __stack_pointer,
594 __tls_align,
595 __tls_base,
596 __tls_size,
597 __zig_error_name_table,
598 object_global: ObjectGlobalIndex,
599 nav: Nav.Index,
600 };
601
602 pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
603 return switch (r) {
604 .unresolved => .unresolved,
605 .__wasm_apply_global_tls_relocs => .__wasm_apply_global_tls_relocs,
606 .__wasm_call_ctors => .__wasm_call_ctors,
607 .__wasm_init_memory => .__wasm_init_memory,
608 .__wasm_init_tls => .__wasm_init_tls,
609 .__zig_error_names => .__zig_error_names,
610 _ => {
611 const i: u32 = @intFromEnum(r);
612 const object_global_index = i - first_object_global;
613 if (object_global_index < wasm.object_globals.items.len)
614 return .{ .object_global = @enumFromInt(object_global_index) };
615 const nav_index = object_global_index - wasm.object_globals.items.len;
616 return .{ .nav = @enumFromInt(nav_index) };
617 },
618 };
619 }
620
621 pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Resolution {
622 return switch (unpacked) {
623 .unresolved => .unresolved,
624 .__heap_base => .__heap_base,
625 .__heap_end => .__heap_end,
626 .__stack_pointer => .__stack_pointer,
627 .__tls_align => .__tls_align,
628 .__tls_base => .__tls_base,
629 .__tls_size => .__tls_size,
630 .__zig_error_name_table => .__zig_error_name_table,
631 .object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),
632 .nav => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
633 };
634 }
635
636 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
637 return pack(wasm, .{ .nav = @enumFromInt(wasm.navs.getIndex(ip_nav).?) });
638 }
639 };
640
641 /// Index into `object_global_imports`.
642 pub const Index = enum(u32) {
643 _,
644
645 pub fn ptr(index: Index, wasm: *const Wasm) *GlobalImport {
646 return &wasm.object_global_imports.items[@intFromEnum(index)];
647 }
559648 };
560649};
561650
......@@ -634,20 +723,6 @@ pub const ObjectSectionIndex = enum(u32) {
634723 _,
635724};
636725
637/// Index into `object_function_imports`.
638pub const ObjectFunctionImportIndex = enum(u32) {
639 _,
640
641 pub fn ptr(index: ObjectFunctionImportIndex, wasm: *const Wasm) *FunctionImport {
642 return &wasm.object_function_imports.items[@intFromEnum(index)];
643 }
644};
645
646/// Index into `object_global_imports`.
647pub const ObjectGlobalImportIndex = enum(u32) {
648 _,
649};
650
651726/// Index into `object_table_imports`.
652727pub const ObjectTableImportIndex = enum(u32) {
653728 _,
......@@ -861,11 +936,35 @@ pub const ValtypeList = enum(u32) {
861936 }
862937};
863938
939/// Index into `imports`.
940pub const ZcuImportIndex = enum(u32) {
941 _,
942};
943
864944/// 0. Index into `object_function_imports`.
865945/// 1. Index into `imports`.
866946pub const FunctionImportId = enum(u32) {
867947 _,
868948
949 pub const Unpacked = union(enum) {
950 object_function_import: FunctionImport.Index,
951 zcu_import: ZcuImportIndex,
952 };
953
954 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) FunctionImportId {
955 return switch (unpacked) {
956 .object_function_import => |i| @enumFromInt(@intFromEnum(i)),
957 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_function_imports.entries.len),
958 };
959 }
960
961 pub fn unpack(id: FunctionImportId, wasm: *const Wasm) Unpacked {
962 const i = @intFromEnum(id);
963 if (i < wasm.object_function_imports.entries.len) return .{ .object_function_import = @enumFromInt(i) };
964 const zcu_import_i = i - wasm.object_function_imports.entries.len;
965 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
966 }
967
869968 /// This function is allowed O(N) lookup because it is only called during
870969 /// diagnostic generation.
871970 pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
......@@ -873,10 +972,10 @@ pub const FunctionImportId = enum(u32) {
873972 .object_function_import => |obj_func_index| {
874973 // TODO binary search
875974 for (wasm.objects.items, 0..) |o, i| {
876 if (o.function_imports.off <= obj_func_index and
877 o.function_imports.off + o.function_imports.len > obj_func_index)
975 if (o.function_imports.off <= @intFromEnum(obj_func_index) and
976 o.function_imports.off + o.function_imports.len > @intFromEnum(obj_func_index))
878977 {
879 return .pack(wasm, .{ .object_index = @enumFromInt(i) });
978 return .pack(.{ .object_index = @enumFromInt(i) }, wasm);
880979 }
881980 } else unreachable;
882981 },
......@@ -890,17 +989,36 @@ pub const FunctionImportId = enum(u32) {
890989pub const GlobalImportId = enum(u32) {
891990 _,
892991
992 pub const Unpacked = union(enum) {
993 object_global_import: GlobalImport.Index,
994 zcu_import: ZcuImportIndex,
995 };
996
997 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
998 return switch (unpacked) {
999 .object_global_import => |i| @enumFromInt(@intFromEnum(i)),
1000 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_global_imports.entries.len),
1001 };
1002 }
1003
1004 pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked {
1005 const i = @intFromEnum(id);
1006 if (i < wasm.object_global_imports.entries.len) return .{ .object_global_import = @enumFromInt(i) };
1007 const zcu_import_i = i - wasm.object_global_imports.entries.len;
1008 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
1009 }
1010
8931011 /// This function is allowed O(N) lookup because it is only called during
8941012 /// diagnostic generation.
8951013 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
8961014 switch (id.unpack(wasm)) {
897 .object_global_import => |obj_func_index| {
1015 .object_global_import => |obj_global_index| {
8981016 // TODO binary search
8991017 for (wasm.objects.items, 0..) |o, i| {
900 if (o.global_imports.off <= obj_func_index and
901 o.global_imports.off + o.global_imports.len > obj_func_index)
1018 if (o.global_imports.off <= @intFromEnum(obj_global_index) and
1019 o.global_imports.off + o.global_imports.len > @intFromEnum(obj_global_index))
9021020 {
903 return .pack(wasm, .{ .object_index = @enumFromInt(i) });
1021 return .pack(.{ .object_index = @enumFromInt(i) }, wasm);
9041022 }
9051023 } else unreachable;
9061024 },
......@@ -1330,23 +1448,13 @@ pub fn deinit(wasm: *Wasm) void {
13301448 wasm.object_memories.deinit(gpa);
13311449
13321450 wasm.object_data_segments.deinit(gpa);
1333 wasm.object_relocatable_codes.deinit(gpa);
13341451 wasm.object_custom_segments.deinit(gpa);
1335 wasm.object_symbols.deinit(gpa);
1336 wasm.object_named_segments.deinit(gpa);
13371452 wasm.object_init_funcs.deinit(gpa);
13381453 wasm.object_comdats.deinit(gpa);
1339 wasm.object_relocations.deinit(gpa);
13401454 wasm.object_relocations_table.deinit(gpa);
13411455 wasm.object_comdat_symbols.deinit(gpa);
13421456 wasm.objects.deinit(gpa);
13431457
1344 wasm.synthetic_symbols.deinit(gpa);
1345 wasm.undefs.deinit(gpa);
1346 wasm.discarded.deinit(gpa);
1347 wasm.segments.deinit(gpa);
1348 wasm.segment_info.deinit(gpa);
1349
13501458 wasm.func_types.deinit(gpa);
13511459 wasm.function_exports.deinit(gpa);
13521460 wasm.function_imports.deinit(gpa);
......@@ -1354,8 +1462,6 @@ pub fn deinit(wasm: *Wasm) void {
13541462 wasm.globals.deinit(gpa);
13551463 wasm.global_imports.deinit(gpa);
13561464 wasm.table_imports.deinit(gpa);
1357 wasm.output_globals.deinit(gpa);
1358 wasm.exports.deinit(gpa);
13591465
13601466 wasm.string_bytes.deinit(gpa);
13611467 wasm.string_table.deinit(gpa);
......@@ -1374,12 +1480,11 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
13741480 const nav_index = func.owner_nav;
13751481
13761482 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
1377 const relocs_start: u32 = @intCast(wasm.relocations.items.len);
1483 const relocs_start: u32 = @intCast(wasm.relocations.len);
13781484 wasm.string_bytes_lock.lock();
13791485
1380 const wasm_codegen = @import("../../arch/wasm/CodeGen.zig");
13811486 dev.check(.wasm_backend);
1382 const result = try wasm_codegen.generate(
1487 try CodeGen.generate(
13831488 &wasm.base,
13841489 pt,
13851490 zcu.navSrcLoc(nav_index),
......@@ -1391,18 +1496,12 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
13911496 );
13921497
13931498 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
1394 const relocs_len: u32 = @intCast(wasm.relocations.items.len - relocs_start);
1499 const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);
13951500 wasm.string_bytes_lock.unlock();
13961501
1397 const code: Nav.Code = switch (result) {
1398 .ok => .{
1399 .off = code_start,
1400 .len = code_len,
1401 },
1402 .fail => |em| {
1403 try pt.zcu.failed_codegen.put(gpa, nav_index, em);
1404 return;
1405 },
1502 const code: Nav.Code = .{
1503 .off = code_start,
1504 .len = code_len,
14061505 };
14071506
14081507 const gop = try wasm.navs.getOrPut(gpa, nav_index);
......@@ -1445,24 +1544,22 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
14451544
14461545 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
14471546 _ = wasm.imports.swapRemove(nav_index);
1448 if (wasm.navs.swapRemove(nav_index)) |old| {
1449 _ = old;
1547 if (wasm.navs.swapRemove(nav_index)) {
14501548 @panic("TODO reclaim resources");
14511549 }
14521550 return;
14531551 }
14541552
14551553 if (is_extern) {
1456 try wasm.imports.put(nav_index, {});
1457 if (wasm.navs.swapRemove(nav_index)) |old| {
1458 _ = old;
1554 try wasm.imports.put(gpa, nav_index, {});
1555 if (wasm.navs.swapRemove(nav_index)) {
14591556 @panic("TODO reclaim resources");
14601557 }
14611558 return;
14621559 }
14631560
14641561 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
1465 const relocs_start: u32 = @intCast(wasm.relocations.items.len);
1562 const relocs_start: u32 = @intCast(wasm.relocations.len);
14661563 wasm.string_bytes_lock.lock();
14671564
14681565 const res = try codegen.generateSymbol(
......@@ -1475,7 +1572,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
14751572 );
14761573
14771574 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
1478 const relocs_len: u32 = @intCast(wasm.relocations.items.len - relocs_start);
1575 const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);
14791576 wasm.string_bytes_lock.unlock();
14801577
14811578 const code: Nav.Code = switch (res) {
......@@ -1531,7 +1628,7 @@ pub fn updateExports(
15311628 wasm: *Wasm,
15321629 pt: Zcu.PerThread,
15331630 exported: Zcu.Exported,
1534 export_indices: []const u32,
1631 export_indices: []const Zcu.Export.Index,
15351632) !void {
15361633 if (build_options.skip_non_native and builtin.object_format != .wasm) {
15371634 @panic("Attempted to compile for object format that was disabled by build configuration");
......@@ -1668,7 +1765,7 @@ fn markFunction(
16681765 wasm: *Wasm,
16691766 name: String,
16701767 import: *FunctionImport,
1671 func_index: ObjectFunctionImportIndex,
1768 func_index: FunctionImport.Index,
16721769) error{OutOfMemory}!void {
16731770 if (import.flags.alive) return;
16741771 import.flags.alive = true;
......@@ -1712,7 +1809,7 @@ fn markGlobal(
17121809 wasm: *Wasm,
17131810 name: String,
17141811 import: *GlobalImport,
1715 global_index: ObjectGlobalImportIndex,
1812 global_index: GlobalImport.Index,
17161813) !void {
17171814 if (import.flags.alive) return;
17181815 import.flags.alive = true;
src/link/Wasm/Flush.zig+5-6
......@@ -137,13 +137,12 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
137137
138138 // Merge and order the data segments. Depends on garbage collection so that
139139 // unused segments can be omitted.
140 try f.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len);
140 try f.data_segments.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len);
141141 for (wasm.object_data_segments.items, 0..) |*ds, i| {
142142 if (!ds.flags.alive) continue;
143 const data_segment_index: Wasm.DataSegment.Index = @enumFromInt(i);
143144 any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !isBss(wasm, ds.name));
144 f.data_segments.putAssumeCapacityNoClobber(@intCast(i), .{
145 .offset = undefined,
146 });
145 f.data_segments.putAssumeCapacityNoClobber(data_segment_index, .{ .offset = undefined });
147146 }
148147
149148 try wasm.functions.ensureUnusedCapacity(gpa, 3);
......@@ -1082,8 +1081,8 @@ fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)
10821081// try writeCustomSectionHeader(binary_bytes.items, header_offset, size);
10831082//}
10841083
1085fn isBss(wasm: *Wasm, name: String) bool {
1086 const s = name.slice(wasm);
1084fn isBss(wasm: *Wasm, optional_name: Wasm.OptionalString) bool {
1085 const s = optional_name.slice(wasm) orelse return false;
10871086 return mem.eql(u8, s, ".bss") or mem.startsWith(u8, s, ".bss.");
10881087}
10891088