authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-06-29 01:36:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-07-04 21:01:41+01:00
log7e552dc1e9a8388f71cc32083deb9dd848e79808
treeb1c1086002c91be0e6c1195cc18966906a171ce3
parentbc8cd135987c7dc7419d034ba31178331d606cfa
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: rework exports

This commit reworks our representation of exported Decls and values in Zcu to be memory-optimized and trivially serialized. All exports are now stored in the `all_exports` array on `Zcu`. An `AnalUnit` which performs an export (either through an `export` annotation or by containing an analyzed `@export`) gains an entry into `single_exports` if it performs only one export, or `multi_exports` if it performs multiple. We no longer store a persistent mapping from a `Decl`/value to all exports of that entity; this state is not necessary for the majority of the pipeline. Instead, we construct it in `Zcu.processExports`, just before flush. This does not affect the algorithmic complexity of `processExports`, since this function already iterates all exports in the `Zcu`. The elimination of `decl_exports` and `value_exports` led to a few non-trivial backend changes. The LLVM backend has been wrangled into a more reasonable state in general regarding exports and externs. The C backend is currently disabled in this commit, because its support for `export` was quite broken, and that was exposed by this work -- I'm hoping @jacobly0 will be able to pick this up!

16 files changed, 498 insertions(+), 450 deletions(-)

src/Sema.zig+72-42
......@@ -117,6 +117,10 @@ maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAll
117117/// Backed by gpa.
118118comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{},
119119
120/// A list of exports performed by this analysis. After this `Sema` terminates,
121/// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`.
122exports: std.ArrayListUnmanaged(Zcu.Export) = .{},
123
120124const MaybeComptimeAlloc = struct {
121125 /// The runtime index of the `alloc` instruction.
122126 runtime_index: Value.RuntimeIndex,
......@@ -186,6 +190,7 @@ const build_options = @import("build_options");
186190const Compilation = @import("Compilation.zig");
187191const InternPool = @import("InternPool.zig");
188192const Alignment = InternPool.Alignment;
193const AnalUnit = InternPool.AnalUnit;
189194const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
190195
191196pub const default_branch_quota = 1000;
......@@ -875,6 +880,7 @@ pub fn deinit(sema: *Sema) void {
875880 sema.base_allocs.deinit(gpa);
876881 sema.maybe_comptime_allocs.deinit(gpa);
877882 sema.comptime_allocs.deinit(gpa);
883 sema.exports.deinit(gpa);
878884 sema.* = undefined;
879885}
880886
......@@ -2735,12 +2741,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
27352741 if (!zcu.comp.debug_incremental) return false;
27362742
27372743 const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
2738 const decl_as_depender = InternPool.AnalUnit.wrap(.{ .decl = decl_index });
2744 const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
27392745 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
27402746 zcu.potentially_outdated.swapRemove(decl_as_depender);
27412747 if (!was_outdated) return false;
27422748 _ = zcu.outdated_ready.swapRemove(decl_as_depender);
2743 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
2749 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
27442750 zcu.intern_pool.remove(ty);
27452751 zcu.declPtr(decl_index).analysis = .dependency_failure;
27462752 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
......@@ -2834,7 +2840,7 @@ fn zirStructDecl(
28342840 if (sema.mod.comp.debug_incremental) {
28352841 try ip.addDependency(
28362842 sema.gpa,
2837 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
2843 AnalUnit.wrap(.{ .decl = new_decl_index }),
28382844 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
28392845 );
28402846 }
......@@ -3068,7 +3074,7 @@ fn zirEnumDecl(
30683074 if (sema.mod.comp.debug_incremental) {
30693075 try mod.intern_pool.addDependency(
30703076 sema.gpa,
3071 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
3077 AnalUnit.wrap(.{ .decl = new_decl_index }),
30723078 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
30733079 );
30743080 }
......@@ -3334,7 +3340,7 @@ fn zirUnionDecl(
33343340 if (sema.mod.comp.debug_incremental) {
33353341 try mod.intern_pool.addDependency(
33363342 sema.gpa,
3337 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
3343 AnalUnit.wrap(.{ .decl = new_decl_index }),
33383344 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
33393345 );
33403346 }
......@@ -3422,7 +3428,7 @@ fn zirOpaqueDecl(
34223428 if (sema.mod.comp.debug_incremental) {
34233429 try ip.addDependency(
34243430 gpa,
3425 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
3431 AnalUnit.wrap(.{ .decl = new_decl_index }),
34263432 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
34273433 );
34283434 }
......@@ -6423,10 +6429,9 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
64236429 return sema.analyzeExport(block, src, options, decl_index);
64246430 }
64256431
6426 try addExport(mod, .{
6432 try sema.exports.append(mod.gpa, .{
64276433 .opts = options,
64286434 .src = src,
6429 .owner_decl = sema.owner_decl_index,
64306435 .exported = .{ .value = operand.toIntern() },
64316436 .status = .in_progress,
64326437 });
......@@ -6469,46 +6474,14 @@ pub fn analyzeExport(
64696474
64706475 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
64716476
6472 try addExport(mod, .{
6477 try sema.exports.append(gpa, .{
64736478 .opts = options,
64746479 .src = src,
6475 .owner_decl = sema.owner_decl_index,
64766480 .exported = .{ .decl_index = exported_decl_index },
64776481 .status = .in_progress,
64786482 });
64796483}
64806484
6481fn addExport(mod: *Module, export_init: Module.Export) error{OutOfMemory}!void {
6482 const gpa = mod.gpa;
6483
6484 try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
6485 try mod.value_exports.ensureUnusedCapacity(gpa, 1);
6486 try mod.export_owners.ensureUnusedCapacity(gpa, 1);
6487
6488 const new_export = try gpa.create(Module.Export);
6489 errdefer gpa.destroy(new_export);
6490
6491 new_export.* = export_init;
6492
6493 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(export_init.owner_decl);
6494 if (!eo_gop.found_existing) eo_gop.value_ptr.* = .{};
6495 try eo_gop.value_ptr.append(gpa, new_export);
6496 errdefer _ = eo_gop.value_ptr.pop();
6497
6498 switch (export_init.exported) {
6499 .decl_index => |decl_index| {
6500 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(decl_index);
6501 if (!de_gop.found_existing) de_gop.value_ptr.* = .{};
6502 try de_gop.value_ptr.append(gpa, new_export);
6503 },
6504 .value => |value| {
6505 const ve_gop = mod.value_exports.getOrPutAssumeCapacity(value);
6506 if (!ve_gop.found_existing) ve_gop.value_ptr.* = .{};
6507 try ve_gop.value_ptr.append(gpa, new_export);
6508 },
6509 }
6510}
6511
65126485fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
65136486 const mod = sema.mod;
65146487 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
......@@ -8411,6 +8384,9 @@ fn instantiateGenericCall(
84118384 });
84128385 sema.appendRefsAssumeCapacity(runtime_args.items);
84138386
8387 // `child_sema` is owned by us, so just take its exports.
8388 try sema.exports.appendSlice(sema.gpa, child_sema.exports.items);
8389
84148390 if (ensure_result_used) {
84158391 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
84168392 }
......@@ -35263,6 +35239,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3526335239 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
3526435240 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
3526535241 }
35242
35243 try sema.flushExports();
3526635244}
3526735245
3526835246fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
......@@ -36225,6 +36203,8 @@ fn semaStructFields(
3622536203
3622636204 struct_type.clearTypesWip(ip);
3622736205 if (!any_inits) struct_type.setHaveFieldInits(ip);
36206
36207 try sema.flushExports();
3622836208}
3622936209
3623036210// This logic must be kept in sync with `semaStructFields`
......@@ -36365,6 +36345,8 @@ fn semaStructFieldInits(
3636536345 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
3636636346 }
3636736347 }
36348
36349 try sema.flushExports();
3636836350}
3636936351
3637036352fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {
......@@ -36738,6 +36720,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3673836720 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
3673936721 union_type.tagTypePtr(ip).* = enum_ty;
3674036722 }
36723
36724 try sema.flushExports();
3674136725}
3674236726
3674336727fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value {
......@@ -38362,7 +38346,7 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3836238346 return;
3836338347 }
3836438348
38365 const depender = InternPool.AnalUnit.wrap(
38349 const depender = AnalUnit.wrap(
3836638350 if (sema.owner_func_index != .none)
3836738351 .{ .func = sema.owner_func_index }
3836838352 else
......@@ -38494,6 +38478,52 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check:
3849438478 }
3849538479}
3849638480
38481/// This should be called exactly once, at the end of a `Sema`'s lifetime.
38482/// It takes the exports stored in `sema.export` and flushes them to the `Zcu`
38483/// to be processed by the linker after the update.
38484pub fn flushExports(sema: *Sema) !void {
38485 if (sema.exports.items.len == 0) return;
38486
38487 const zcu = sema.mod;
38488 const gpa = zcu.gpa;
38489
38490 const unit: AnalUnit = if (sema.owner_func_index != .none)
38491 AnalUnit.wrap(.{ .func = sema.owner_func_index })
38492 else
38493 AnalUnit.wrap(.{ .decl = sema.owner_decl_index });
38494
38495 // There may be existing exports. For instance, a struct may export
38496 // things during both field type resolution and field default resolution.
38497 //
38498 // So, pick up and delete any existing exports. This strategy performs
38499 // redundant work, but that's okay, because this case is exceedingly rare.
38500 if (zcu.single_exports.get(unit)) |export_idx| {
38501 try sema.exports.append(gpa, zcu.all_exports.items[export_idx]);
38502 } else if (zcu.multi_exports.get(unit)) |info| {
38503 try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
38504 }
38505 zcu.deleteUnitExports(unit);
38506
38507 // `sema.exports` is completed; store the data into the `Zcu`.
38508 if (sema.exports.items.len == 1) {
38509 try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
38510 const export_idx = zcu.free_exports.popOrNull() orelse idx: {
38511 _ = try zcu.all_exports.addOne(gpa);
38512 break :idx zcu.all_exports.items.len - 1;
38513 };
38514 zcu.all_exports.items[export_idx] = sema.exports.items[0];
38515 zcu.single_exports.putAssumeCapacityNoClobber(unit, @intCast(export_idx));
38516 } else {
38517 try zcu.multi_exports.ensureUnusedCapacity(gpa, 1);
38518 const exports_base = zcu.all_exports.items.len;
38519 try zcu.all_exports.appendSlice(gpa, sema.exports.items);
38520 zcu.multi_exports.putAssumeCapacityNoClobber(unit, .{
38521 .index = @intCast(exports_base),
38522 .len = @intCast(sema.exports.items.len),
38523 });
38524 }
38525}
38526
3849738527pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
3849838528pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
3849938529
src/Zcu.zig+160-143
......@@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir;
3535const clang = @import("clang.zig");
3636const InternPool = @import("InternPool.zig");
3737const Alignment = InternPool.Alignment;
38const AnalUnit = InternPool.AnalUnit;
3839const BuiltinFn = std.zig.BuiltinFn;
3940const LlvmObject = @import("codegen/llvm.zig").Object;
4041
......@@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined,
7172global_zir_cache: Compilation.Directory,
7273/// Used by AstGen worker to load and store ZIR cache.
7374local_zir_cache: Compilation.Directory,
74/// It's rare for a decl to be exported, so we save memory by having a sparse
75/// map of Decl indexes to details about them being exported.
76/// The Export memory is owned by the `export_owners` table; the slice itself
77/// is owned by this table. The slice is guaranteed to not be empty.
78decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
79/// Same as `decl_exports` but for exported constant values.
80value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
81/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
82/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
83/// is performing the export of another Decl.
84/// This table owns the Export memory.
85export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
75/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
76/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
77all_exports: ArrayListUnmanaged(Export) = .{},
78/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
79/// future semantic analysis.
80free_exports: ArrayListUnmanaged(u32) = .{},
81/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
82/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
83/// whose analysis triggered the export.
84single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
85/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
86/// The exports are `all_exports.items[index..][0..len]`.
87multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
88 index: u32,
89 len: u32,
90}) = .{},
8691/// The set of all the Zig source files in the Module. We keep track of this in order
8792/// to iterate over it and check which source files have been modified on the file system when
8893/// an update is requested, as well as to cache `@import` results.
......@@ -126,9 +131,8 @@ compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
126131failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
127132/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
128133failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
129/// Using a map here for consistency with the other fields here.
130/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
131failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
134/// Key is index into `all_exports`.
135failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{},
132136/// If a decl failed due to a cimport error, the corresponding Clang errors
133137/// are stored here.
134138cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},
......@@ -140,14 +144,14 @@ global_error_set: GlobalErrorSet = .{},
140144error_limit: ErrorInt,
141145
142146/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
143potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{},
147potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
144148/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
145149/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
146outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{},
150outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
147151/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
148152/// Such `AnalUnit`s are ready for immediate re-analysis.
149153/// See `findOutdatedToAnalyze` for details.
150outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, void) = .{},
154outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
151155/// This contains a set of Decls which may not be in `outdated`, but are the
152156/// root Decls of files which have updated source and thus must be re-analyzed.
153157/// If such a Decl is only in this set, the struct type index may be preserved
......@@ -158,7 +162,7 @@ outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
158162/// failure was something like running out of disk space, and trying again may
159163/// succeed. On the next update, we will flush this list, marking all members of
160164/// it as outdated.
161retryable_failures: std.ArrayListUnmanaged(InternPool.AnalUnit) = .{},
165retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{},
162166
163167stage1_flags: packed struct {
164168 have_winmain: bool = false,
......@@ -267,8 +271,6 @@ pub const Exported = union(enum) {
267271pub const Export = struct {
268272 opts: Options,
269273 src: LazySrcLoc,
270 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
271 owner_decl: Decl.Index,
272274 exported: Exported,
273275 status: enum {
274276 in_progress,
......@@ -2507,20 +2509,10 @@ pub fn deinit(zcu: *Zcu) void {
25072509
25082510 zcu.compile_log_decls.deinit(gpa);
25092511
2510 for (zcu.decl_exports.values()) |*export_list| {
2511 export_list.deinit(gpa);
2512 }
2513 zcu.decl_exports.deinit(gpa);
2514
2515 for (zcu.value_exports.values()) |*export_list| {
2516 export_list.deinit(gpa);
2517 }
2518 zcu.value_exports.deinit(gpa);
2519
2520 for (zcu.export_owners.values()) |*value| {
2521 freeExportList(gpa, value);
2522 }
2523 zcu.export_owners.deinit(gpa);
2512 zcu.all_exports.deinit(gpa);
2513 zcu.free_exports.deinit(gpa);
2514 zcu.single_exports.deinit(gpa);
2515 zcu.multi_exports.deinit(gpa);
25242516
25252517 zcu.global_error_set.deinit(gpa);
25262518
......@@ -2590,11 +2582,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
25902582 return decl_index == namespace.decl_index;
25912583}
25922584
2593fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void {
2594 for (export_list.items) |exp| gpa.destroy(exp);
2595 export_list.deinit(gpa);
2596}
2597
25982585// TODO https://github.com/ziglang/zig/issues/8643
25992586const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
26002587const HackDataLayout = extern struct {
......@@ -3139,7 +3126,7 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
31393126
31403127/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
31413128/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
3142fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.AnalUnit) !void {
3129fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
31433130 var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
31443131 .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
31453132 .func => |func_index| .{ .func_ies = func_index },
......@@ -3166,7 +3153,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP
31663153 }
31673154}
31683155
3169pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
3156pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
31703157 if (!zcu.comp.debug_incremental) return null;
31713158
31723159 if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
......@@ -3197,7 +3184,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
31973184 // `outdated`. This set will be small (number of files changed in this
31983185 // update), so it's alright for us to just iterate here.
31993186 for (zcu.outdated_file_root.keys()) |file_decl| {
3200 const decl_depender = InternPool.AnalUnit.wrap(.{ .decl = file_decl });
3187 const decl_depender = AnalUnit.wrap(.{ .decl = file_decl });
32013188 if (zcu.outdated.contains(decl_depender)) {
32023189 // Since we didn't hit this in the first loop, this Decl must have
32033190 // pending dependencies, so is ineligible.
......@@ -3271,7 +3258,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
32713258 chosen_decl_dependers,
32723259 });
32733260
3274 return InternPool.AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
3261 return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
32753262}
32763263
32773264/// During an incremental update, before semantic analysis, call this to flush all values from
......@@ -3456,7 +3443,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
34563443 // which tries to limit re-analysis to Decls whose previously listed
34573444 // dependencies are all up-to-date.
34583445
3459 const decl_as_depender = InternPool.AnalUnit.wrap(.{ .decl = decl_index });
3446 const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
34603447 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
34613448 mod.potentially_outdated.swapRemove(decl_as_depender);
34623449
......@@ -3485,7 +3472,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
34853472 // The exports this Decl performs will be re-discovered, so we remove them here
34863473 // prior to re-analysis.
34873474 if (build_options.only_c) unreachable;
3488 try mod.deleteDeclExports(decl_index);
3475 mod.deleteUnitExports(AnalUnit.wrap(.{ .decl = decl_index }));
34893476 }
34903477
34913478 const sema_result: SemaDeclResult = blk: {
......@@ -3522,7 +3509,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
35223509 else => |e| {
35233510 decl.analysis = .sema_failure;
35243511 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
3525 try mod.retryable_failures.append(mod.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
3512 try mod.retryable_failures.append(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
35263513 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
35273514 mod.gpa,
35283515 decl.navSrcLoc(mod).upgrade(mod),
......@@ -3581,7 +3568,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
35813568 // that's the case, we should remove this function from the binary.
35823569 if (decl.val.ip_index != func_index) {
35833570 try zcu.markDependeeOutdated(.{ .func_ies = func_index });
3584 ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
3571 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
35853572 ip.remove(func_index);
35863573 @panic("TODO: remove orphaned function from binary");
35873574 }
......@@ -3607,12 +3594,14 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36073594 .complete => {},
36083595 }
36093596
3610 const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index });
3597 const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
36113598 const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
36123599 zcu.potentially_outdated.swapRemove(func_as_depender);
36133600
36143601 if (was_outdated) {
3602 if (build_options.only_c) unreachable;
36153603 _ = zcu.outdated_ready.swapRemove(func_as_depender);
3604 zcu.deleteUnitExports(AnalUnit.wrap(.{ .func = func_index }));
36163605 }
36173606
36183607 switch (func.analysis(ip).state) {
......@@ -3728,16 +3717,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
37283717 .{@errorName(err)},
37293718 ));
37303719 func.analysis(ip).state = .codegen_failure;
3731 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
3720 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
37323721 },
37333722 };
37343723 } else if (zcu.llvm_object) |llvm_object| {
37353724 if (build_options.only_c) unreachable;
37363725 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
37373726 error.OutOfMemory => return error.OutOfMemory,
3738 error.AnalysisFail => {
3739 func.analysis(ip).state = .codegen_failure;
3740 },
37413727 };
37423728 }
37433729}
......@@ -3773,7 +3759,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
37733759
37743760 assert(decl.has_tv);
37753761
3776 const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index });
3762 const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
37773763 const is_outdated = mod.outdated.contains(func_as_depender) or
37783764 mod.potentially_outdated.contains(func_as_depender);
37793765
......@@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
38573843 if (zcu.comp.debug_incremental) {
38583844 try ip.addDependency(
38593845 gpa,
3860 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
3846 AnalUnit.wrap(.{ .decl = decl_index }),
38613847 .{ .src_hash = tracked_inst },
38623848 );
38633849 }
......@@ -3906,7 +3892,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
39063892
39073893 if (type_outdated) {
39083894 // Invalidate the existing type, reusing the decl and namespace.
3909 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = file.root_decl.unwrap().? }));
3895 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = file.root_decl.unwrap().? }));
39103896 zcu.intern_pool.remove(decl.val.toIntern());
39113897 decl.val = undefined;
39123898 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
......@@ -4097,7 +4083,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
40974083 break :ip_index .none;
40984084 };
40994085
4100 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
4086 mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .decl = decl_index }));
41014087
41024088 decl.analysis = .in_progress;
41034089
......@@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
42934279 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
42944280 }
42954281
4282 try sema.flushExports();
4283
42964284 return result;
42974285}
42984286
......@@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
43234311 // with a new Decl.
43244312 //
43254313 // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
4326 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
4314 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
43274315 zcu.intern_pool.remove(decl.val.toIntern());
43284316 decl.analysis = .dependency_failure;
43294317 return .{
......@@ -4949,63 +4937,44 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo
49494937 }
49504938}
49514939
4952/// Delete all the Export objects that are caused by this Decl. Re-analysis of
4953/// this Decl will cause them to be re-created (or not).
4954fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
4955 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
4956
4957 for (export_owners.items) |exp| {
4958 switch (exp.exported) {
4959 .decl_index => |exported_decl_index| {
4960 if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
4961 // Remove exports with owner_decl matching the regenerating decl.
4962 const list = export_list.items;
4963 var i: usize = 0;
4964 var new_len = list.len;
4965 while (i < new_len) {
4966 if (list[i].owner_decl == decl_index) {
4967 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4968 new_len -= 1;
4969 } else {
4970 i += 1;
4971 }
4972 }
4973 export_list.shrinkAndFree(mod.gpa, new_len);
4974 if (new_len == 0) {
4975 assert(mod.decl_exports.swapRemove(exported_decl_index));
4976 }
4977 }
4978 },
4979 .value => |value| {
4980 if (mod.value_exports.getPtr(value)) |export_list| {
4981 // Remove exports with owner_decl matching the regenerating decl.
4982 const list = export_list.items;
4983 var i: usize = 0;
4984 var new_len = list.len;
4985 while (i < new_len) {
4986 if (list[i].owner_decl == decl_index) {
4987 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4988 new_len -= 1;
4989 } else {
4990 i += 1;
4991 }
4992 }
4993 export_list.shrinkAndFree(mod.gpa, new_len);
4994 if (new_len == 0) {
4995 assert(mod.value_exports.swapRemove(value));
4996 }
4997 }
4998 },
4999 }
5000 if (mod.comp.bin_file) |lf| {
5001 try lf.deleteDeclExport(decl_index, exp.opts.name);
5002 }
5003 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
5004 failed_kv.value.destroy(mod.gpa);
4940/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
4941/// this `AnalUnit` will cause them to be re-created (or not).
4942pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
4943 const gpa = zcu.gpa;
4944
4945 const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
4946 .{ kv.value, 1 }
4947 else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
4948 .{ info.value.index, info.value.len }
4949 else
4950 return;
4951
4952 const exports = zcu.all_exports.items[exports_base..][0..exports_len];
4953
4954 // In an only-c build, we're guaranteed to never use incremental compilation, so there are
4955 // guaranteed not to be any exports in the output file that need deleting (since we only call
4956 // `updateExports` on flush).
4957 // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
4958 // within a single update.
4959 if (!build_options.only_c) {
4960 for (exports, exports_base..) |exp, export_idx| {
4961 if (zcu.comp.bin_file) |lf| {
4962 lf.deleteExport(exp.exported, exp.opts.name);
4963 }
4964 if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
4965 failed_kv.value.destroy(gpa);
4966 }
50054967 }
5006 mod.gpa.destroy(exp);
50074968 }
5008 export_owners.deinit(mod.gpa);
4969
4970 zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
4971 // This space will be reused eventually, so we need not propagate this error.
4972 // Just leak it for now, and let GC reclaim it later on.
4973 return;
4974 };
4975 for (exports_base..exports_base + exports_len) |export_idx| {
4976 zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
4977 }
50094978}
50104979
50114980pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air {
......@@ -5026,7 +4995,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
50264995 const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
50274996 defer decl_prog_node.end();
50284997
5029 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
4998 mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
50304999
50315000 var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
50325001 defer comptime_err_ret_trace.deinit();
......@@ -5262,6 +5231,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
52625231 };
52635232 }
52645233
5234 try sema.flushExports();
5235
52655236 return .{
52665237 .instructions = sema.air_instructions.toOwnedSlice(),
52675238 .extra = try sema.air_extra.toOwnedSlice(gpa),
......@@ -5392,33 +5363,89 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
53925363/// Called from `Compilation.update`, after everything is done, just before
53935364/// reporting compile errors. In this function we emit exported symbol collision
53945365/// errors and communicate exported symbols to the linker backend.
5395pub fn processExports(mod: *Module) !void {
5366pub fn processExports(zcu: *Zcu) !void {
5367 const gpa = zcu.gpa;
5368
5369 // First, construct a mapping of every exported value and Decl to the indices of all its different exports.
5370 var decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(u32)) = .{};
5371 var value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(u32)) = .{};
5372 defer {
5373 for (decl_exports.values()) |*exports| {
5374 exports.deinit(gpa);
5375 }
5376 decl_exports.deinit(gpa);
5377 for (value_exports.values()) |*exports| {
5378 exports.deinit(gpa);
5379 }
5380 value_exports.deinit(gpa);
5381 }
5382
5383 // We note as a heuristic:
5384 // * It is rare to export a value.
5385 // * It is rare for one Decl to be exported multiple times.
5386 // So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization.
5387 try decl_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count());
5388
5389 for (zcu.single_exports.values()) |export_idx| {
5390 const exp = zcu.all_exports.items[export_idx];
5391 const value_ptr, const found_existing = switch (exp.exported) {
5392 .decl_index => |i| gop: {
5393 const gop = try decl_exports.getOrPut(gpa, i);
5394 break :gop .{ gop.value_ptr, gop.found_existing };
5395 },
5396 .value => |i| gop: {
5397 const gop = try value_exports.getOrPut(gpa, i);
5398 break :gop .{ gop.value_ptr, gop.found_existing };
5399 },
5400 };
5401 if (!found_existing) value_ptr.* = .{};
5402 try value_ptr.append(gpa, export_idx);
5403 }
5404
5405 for (zcu.multi_exports.values()) |info| {
5406 for (zcu.all_exports.items[info.index..][0..info.len], info.index..) |exp, export_idx| {
5407 const value_ptr, const found_existing = switch (exp.exported) {
5408 .decl_index => |i| gop: {
5409 const gop = try decl_exports.getOrPut(gpa, i);
5410 break :gop .{ gop.value_ptr, gop.found_existing };
5411 },
5412 .value => |i| gop: {
5413 const gop = try value_exports.getOrPut(gpa, i);
5414 break :gop .{ gop.value_ptr, gop.found_existing };
5415 },
5416 };
5417 if (!found_existing) value_ptr.* = .{};
5418 try value_ptr.append(gpa, @intCast(export_idx));
5419 }
5420 }
5421
53965422 // Map symbol names to `Export` for name collision detection.
53975423 var symbol_exports: SymbolExports = .{};
5398 defer symbol_exports.deinit(mod.gpa);
5424 defer symbol_exports.deinit(gpa);
53995425
5400 for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
5426 for (decl_exports.keys(), decl_exports.values()) |exported_decl, exports_list| {
54015427 const exported: Exported = .{ .decl_index = exported_decl };
5402 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5428 try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
54035429 }
54045430
5405 for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
5431 for (value_exports.keys(), value_exports.values()) |exported_value, exports_list| {
54065432 const exported: Exported = .{ .value = exported_value };
5407 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5433 try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
54085434 }
54095435}
54105436
5411const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
5437const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
54125438
54135439fn processExportsInner(
54145440 zcu: *Zcu,
54155441 symbol_exports: *SymbolExports,
54165442 exported: Exported,
5417 exports: []const *Export,
5443 export_indices: []const u32,
54185444) error{OutOfMemory}!void {
54195445 const gpa = zcu.gpa;
54205446
5421 for (exports) |new_export| {
5447 for (export_indices) |export_idx| {
5448 const new_export = &zcu.all_exports.items[export_idx];
54225449 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
54235450 if (gop.found_existing) {
54245451 new_export.status = .failed_retryable;
......@@ -5428,40 +5455,41 @@ fn processExportsInner(
54285455 new_export.opts.name.fmt(&zcu.intern_pool),
54295456 });
54305457 errdefer msg.destroy(gpa);
5431 const other_export = gop.value_ptr.*;
5458 const other_export = zcu.all_exports.items[gop.value_ptr.*];
54325459 const other_src_loc = other_export.getSrcLoc(zcu);
54335460 try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
5434 zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5461 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
54355462 new_export.status = .failed;
54365463 } else {
5437 gop.value_ptr.* = new_export;
5464 gop.value_ptr.* = export_idx;
54385465 }
54395466 }
54405467 if (zcu.comp.bin_file) |lf| {
5441 try handleUpdateExports(zcu, exports, lf.updateExports(zcu, exported, exports));
5468 try handleUpdateExports(zcu, export_indices, lf.updateExports(zcu, exported, export_indices));
54425469 } else if (zcu.llvm_object) |llvm_object| {
54435470 if (build_options.only_c) unreachable;
5444 try handleUpdateExports(zcu, exports, llvm_object.updateExports(zcu, exported, exports));
5471 try handleUpdateExports(zcu, export_indices, llvm_object.updateExports(zcu, exported, export_indices));
54455472 }
54465473}
54475474
54485475fn handleUpdateExports(
54495476 zcu: *Zcu,
5450 exports: []const *Export,
5477 export_indices: []const u32,
54515478 result: link.File.UpdateExportsError!void,
54525479) Allocator.Error!void {
54535480 const gpa = zcu.gpa;
54545481 result catch |err| switch (err) {
54555482 error.OutOfMemory => return error.OutOfMemory,
54565483 error.AnalysisFail => {
5457 const new_export = exports[0];
5484 const export_idx = export_indices[0];
5485 const new_export = &zcu.all_exports.items[export_idx];
54585486 new_export.status = .failed_retryable;
54595487 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
54605488 const src_loc = new_export.getSrcLoc(zcu);
54615489 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
54625490 @errorName(err),
54635491 });
5464 zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5492 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
54655493 },
54665494 };
54675495}
......@@ -5627,16 +5655,13 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
56275655 .{@errorName(err)},
56285656 ));
56295657 decl.analysis = .codegen_failure;
5630 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
5658 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
56315659 },
56325660 };
56335661 } else if (zcu.llvm_object) |llvm_object| {
56345662 if (build_options.only_c) unreachable;
56355663 llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
56365664 error.OutOfMemory => return error.OutOfMemory,
5637 error.AnalysisFail => {
5638 decl.analysis = .codegen_failure;
5639 },
56405665 };
56415666 }
56425667}
......@@ -5684,14 +5709,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
56845709 }
56855710}
56865711
5687pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
5688 if (mod.decl_exports.get(decl_index)) |l| {
5689 return l.items;
5690 } else {
5691 return &[0]*Export{};
5692 }
5693}
5694
56955712pub const Feature = enum {
56965713 panic_fn,
56975714 panic_unwrap_error,
src/codegen/c.zig+2
......@@ -3081,6 +3081,8 @@ pub fn genDeclValue(
30813081}
30823082
30833083pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
3084 if (true) @panic("TODO jacobly");
3085
30843086 const tracy = trace(@src());
30853087 defer tracy.end();
30863088
src/codegen/llvm.zig+109-154
......@@ -848,10 +848,6 @@ pub const Object = struct {
848848 /// Note that the values are not added until `emit`, when all errors in
849849 /// the compilation are known.
850850 error_name_table: Builder.Variable.Index,
851 /// This map is usually very close to empty. It tracks only the cases when a
852 /// second extern Decl could not be emitted with the correct name due to a
853 /// name collision.
854 extern_collisions: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, void),
855851
856852 /// Memoizes a null `?usize` value.
857853 null_opt_usize: Builder.Constant,
......@@ -1011,7 +1007,6 @@ pub const Object = struct {
10111007 .named_enum_map = .{},
10121008 .type_map = .{},
10131009 .error_name_table = .none,
1014 .extern_collisions = .{},
10151010 .null_opt_usize = .no_init,
10161011 .struct_field_map = .{},
10171012 };
......@@ -1029,7 +1024,6 @@ pub const Object = struct {
10291024 self.anon_decl_map.deinit(gpa);
10301025 self.named_enum_map.deinit(gpa);
10311026 self.type_map.deinit(gpa);
1032 self.extern_collisions.deinit(gpa);
10331027 self.builder.deinit();
10341028 self.struct_field_map.deinit(gpa);
10351029 self.* = undefined;
......@@ -1121,61 +1115,6 @@ pub const Object = struct {
11211115 try object.builder.finishModuleAsm();
11221116 }
11231117
1124 fn resolveExportExternCollisions(object: *Object) !void {
1125 const mod = object.module;
1126
1127 // This map has externs with incorrect symbol names.
1128 for (object.extern_collisions.keys()) |decl_index| {
1129 const global = object.decl_map.get(decl_index) orelse continue;
1130 // Same logic as below but for externs instead of exports.
1131 const decl_name = object.builder.strtabStringIfExists(mod.declPtr(decl_index).name.toSlice(&mod.intern_pool)) orelse continue;
1132 const other_global = object.builder.getGlobal(decl_name) orelse continue;
1133 if (other_global.toConst().getBase(&object.builder) ==
1134 global.toConst().getBase(&object.builder)) continue;
1135
1136 try global.replace(other_global, &object.builder);
1137 }
1138 object.extern_collisions.clearRetainingCapacity();
1139
1140 for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
1141 const global = object.decl_map.get(decl_index) orelse continue;
1142 try resolveGlobalCollisions(object, global, export_list.items);
1143 }
1144
1145 for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
1146 const global = object.anon_decl_map.get(val) orelse continue;
1147 try resolveGlobalCollisions(object, global, export_list.items);
1148 }
1149 }
1150
1151 fn resolveGlobalCollisions(
1152 object: *Object,
1153 global: Builder.Global.Index,
1154 export_list: []const *Module.Export,
1155 ) !void {
1156 const mod = object.module;
1157 const global_base = global.toConst().getBase(&object.builder);
1158 for (export_list) |exp| {
1159 // Detect if the LLVM global has already been created as an extern. In such
1160 // case, we need to replace all uses of it with this exported global.
1161 const exp_name = object.builder.strtabStringIfExists(exp.opts.name.toSlice(&mod.intern_pool)) orelse continue;
1162
1163 const other_global = object.builder.getGlobal(exp_name) orelse continue;
1164 if (other_global.toConst().getBase(&object.builder) == global_base) continue;
1165
1166 try global.takeName(other_global, &object.builder);
1167 try other_global.replace(global, &object.builder);
1168 // Problem: now we need to replace in the decl_map that
1169 // the extern decl index points to this new global. However we don't
1170 // know the decl index.
1171 // Even if we did, a future incremental update to the extern would then
1172 // treat the LLVM global as an extern rather than an export, so it would
1173 // need a way to check that.
1174 // This is a TODO that needs to be solved when making
1175 // the LLVM backend support incremental compilation.
1176 }
1177 }
1178
11791118 pub const EmitOptions = struct {
11801119 pre_ir_path: ?[]const u8,
11811120 pre_bc_path: ?[]const u8,
......@@ -1193,7 +1132,6 @@ pub const Object = struct {
11931132
11941133 pub fn emit(self: *Object, options: EmitOptions) !void {
11951134 {
1196 try self.resolveExportExternCollisions();
11971135 try self.genErrorNameTable();
11981136 try self.genCmpLtErrorsLenFunction();
11991137 try self.genModuleLevelAssembly();
......@@ -1698,8 +1636,7 @@ pub const Object = struct {
16981636 const file = try o.getDebugFile(namespace.file_scope);
16991637
17001638 const line_number = decl.navSrcLine(zcu) + 1;
1701 const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
1702 !zcu.decl_exports.contains(decl_index);
1639 const is_internal_linkage = decl.val.getExternFunc(zcu) == null;
17031640 const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));
17041641
17051642 const subprogram = try o.builder.debugSubprogram(
......@@ -1760,8 +1697,6 @@ pub const Object = struct {
17601697 };
17611698
17621699 try fg.wip.finish();
1763
1764 try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
17651700 }
17661701
17671702 pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
......@@ -1781,66 +1716,25 @@ pub const Object = struct {
17811716 },
17821717 else => |e| return e,
17831718 };
1784 try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
17851719 }
17861720
17871721 pub fn updateExports(
17881722 self: *Object,
17891723 mod: *Module,
17901724 exported: Module.Exported,
1791 exports: []const *Module.Export,
1725 export_indices: []const u32,
17921726 ) link.File.UpdateExportsError!void {
17931727 const decl_index = switch (exported) {
17941728 .decl_index => |i| i,
1795 .value => |val| return updateExportedValue(self, mod, val, exports),
1729 .value => |val| return updateExportedValue(self, mod, val, export_indices),
17961730 };
1797 const gpa = mod.gpa;
17981731 const ip = &mod.intern_pool;
1799 // If the module does not already have the function, we ignore this function call
1800 // because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
1801 const global_index = self.decl_map.get(decl_index) orelse return;
1732 const global_index = self.decl_map.get(decl_index).?;
18021733 const decl = mod.declPtr(decl_index);
18031734 const comp = mod.comp;
1804 if (decl.isExtern(mod)) {
1805 const decl_name = decl_name: {
1806 if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) {
1807 if (decl.getOwnedExternFunc(mod).?.lib_name.toSlice(ip)) |lib_name| {
1808 if (!std.mem.eql(u8, lib_name, "c")) {
1809 break :decl_name try self.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
1810 }
1811 }
1812 }
1813 break :decl_name try self.builder.strtabString(decl.name.toSlice(ip));
1814 };
18151735
1816 if (self.builder.getGlobal(decl_name)) |other_global| {
1817 if (other_global != global_index) {
1818 try self.extern_collisions.put(gpa, decl_index, {});
1819 }
1820 }
1821
1822 try global_index.rename(decl_name, &self.builder);
1823 global_index.setLinkage(.external, &self.builder);
1824 global_index.setUnnamedAddr(.default, &self.builder);
1825 if (comp.config.dll_export_fns)
1826 global_index.setDllStorageClass(.default, &self.builder);
1827
1828 if (decl.val.getVariable(mod)) |decl_var| {
1829 global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
1830 if (decl_var.is_threadlocal) .generaldynamic else .default,
1831 &self.builder,
1832 );
1833 if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder);
1834 }
1835 } else if (exports.len != 0) {
1836 const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip));
1837 try global_index.rename(main_exp_name, &self.builder);
1838
1839 if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
1840 global_index.ptrConst(&self.builder).kind
1841 .variable.setThreadLocal(.generaldynamic, &self.builder);
1842
1843 return updateExportedGlobal(self, mod, global_index, exports);
1736 if (export_indices.len != 0) {
1737 return updateExportedGlobal(self, mod, global_index, export_indices);
18441738 } else {
18451739 const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
18461740 try global_index.rename(fqn, &self.builder);
......@@ -1848,17 +1742,6 @@ pub const Object = struct {
18481742 if (comp.config.dll_export_fns)
18491743 global_index.setDllStorageClass(.default, &self.builder);
18501744 global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
1851 if (decl.val.getVariable(mod)) |decl_var| {
1852 const decl_namespace = mod.namespacePtr(decl.src_namespace);
1853 const single_threaded = decl_namespace.file_scope.mod.single_threaded;
1854 global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
1855 if (decl_var.is_threadlocal and !single_threaded)
1856 .generaldynamic
1857 else
1858 .default,
1859 &self.builder,
1860 );
1861 }
18621745 }
18631746 }
18641747
......@@ -1866,11 +1749,11 @@ pub const Object = struct {
18661749 o: *Object,
18671750 mod: *Module,
18681751 exported_value: InternPool.Index,
1869 exports: []const *Module.Export,
1752 export_indices: []const u32,
18701753 ) link.File.UpdateExportsError!void {
18711754 const gpa = mod.gpa;
18721755 const ip = &mod.intern_pool;
1873 const main_exp_name = try o.builder.strtabString(exports[0].opts.name.toSlice(ip));
1756 const main_exp_name = try o.builder.strtabString(mod.all_exports.items[export_indices[0]].opts.name.toSlice(ip));
18741757 const global_index = i: {
18751758 const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
18761759 if (gop.found_existing) {
......@@ -1894,32 +1777,57 @@ pub const Object = struct {
18941777 try variable_index.setInitializer(init_val, &o.builder);
18951778 break :i global_index;
18961779 };
1897 return updateExportedGlobal(o, mod, global_index, exports);
1780 return updateExportedGlobal(o, mod, global_index, export_indices);
18981781 }
18991782
19001783 fn updateExportedGlobal(
19011784 o: *Object,
19021785 mod: *Module,
19031786 global_index: Builder.Global.Index,
1904 exports: []const *Module.Export,
1787 export_indices: []const u32,
19051788 ) link.File.UpdateExportsError!void {
19061789 const comp = mod.comp;
19071790 const ip = &mod.intern_pool;
1791 const first_export = mod.all_exports.items[export_indices[0]];
1792
1793 // We will rename this global to have a name matching `first_export`.
1794 // Successive exports become aliases.
1795 // If the first export name already exists, then there is a corresponding
1796 // extern global - we replace it with this global.
1797 const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip));
1798 if (o.builder.getGlobal(first_exp_name)) |other_global| replace: {
1799 if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) {
1800 break :replace; // this global already has the name we want
1801 }
1802 try global_index.takeName(other_global, &o.builder);
1803 try other_global.replace(global_index, &o.builder);
1804 // Problem: now we need to replace in the decl_map that
1805 // the extern decl index points to this new global. However we don't
1806 // know the decl index.
1807 // Even if we did, a future incremental update to the extern would then
1808 // treat the LLVM global as an extern rather than an export, so it would
1809 // need a way to check that.
1810 // This is a TODO that needs to be solved when making
1811 // the LLVM backend support incremental compilation.
1812 } else {
1813 try global_index.rename(first_exp_name, &o.builder);
1814 }
1815
19081816 global_index.setUnnamedAddr(.default, &o.builder);
19091817 if (comp.config.dll_export_fns)
19101818 global_index.setDllStorageClass(.dllexport, &o.builder);
1911 global_index.setLinkage(switch (exports[0].opts.linkage) {
1819 global_index.setLinkage(switch (first_export.opts.linkage) {
19121820 .internal => unreachable,
19131821 .strong => .external,
19141822 .weak => .weak_odr,
19151823 .link_once => .linkonce_odr,
19161824 }, &o.builder);
1917 global_index.setVisibility(switch (exports[0].opts.visibility) {
1825 global_index.setVisibility(switch (first_export.opts.visibility) {
19181826 .default => .default,
19191827 .hidden => .hidden,
19201828 .protected => .protected,
19211829 }, &o.builder);
1922 if (exports[0].opts.section.toSlice(ip)) |section|
1830 if (first_export.opts.section.toSlice(ip)) |section|
19231831 switch (global_index.ptrConst(&o.builder).kind) {
19241832 .variable => |impl_index| impl_index.setSection(
19251833 try o.builder.string(section),
......@@ -1936,7 +1844,8 @@ pub const Object = struct {
19361844 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
19371845 // Until then we iterate over existing aliases and make them point
19381846 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
1939 for (exports[1..]) |exp| {
1847 for (export_indices[1..]) |export_idx| {
1848 const exp = mod.all_exports.items[export_idx];
19401849 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
19411850 if (o.builder.getGlobal(exp_name)) |global| {
19421851 switch (global.ptrConst(&o.builder).kind) {
......@@ -1944,7 +1853,13 @@ pub const Object = struct {
19441853 alias.setAliasee(global_index.toConst(), &o.builder);
19451854 continue;
19461855 },
1947 .variable, .function => {},
1856 .variable, .function => {
1857 // This existing global is an `extern` corresponding to this export.
1858 // Replace it with the global being exported.
1859 // This existing global must be replaced with the alias.
1860 try global.rename(.empty, &o.builder);
1861 try global.replace(global_index, &o.builder);
1862 },
19481863 .replaced => unreachable,
19491864 }
19501865 }
......@@ -4762,36 +4677,77 @@ pub const DeclGen = struct {
47624677 else => try o.lowerValue(init_val),
47634678 }, &o.builder);
47644679
4680 if (decl.val.getVariable(zcu)) |decl_var| {
4681 const decl_namespace = zcu.namespacePtr(decl.src_namespace);
4682 const single_threaded = decl_namespace.file_scope.mod.single_threaded;
4683 variable_index.setThreadLocal(
4684 if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default,
4685 &o.builder,
4686 );
4687 }
4688
47654689 const line_number = decl.navSrcLine(zcu) + 1;
4766 const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
47674690
47684691 const namespace = zcu.namespacePtr(decl.src_namespace);
47694692 const owner_mod = namespace.file_scope.mod;
47704693
4771 if (owner_mod.strip) return;
4694 if (!owner_mod.strip) {
4695 const debug_file = try o.getDebugFile(namespace.file_scope);
4696
4697 const debug_global_var = try o.builder.debugGlobalVar(
4698 try o.builder.metadataString(decl.name.toSlice(ip)), // Name
4699 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
4700 debug_file, // File
4701 debug_file, // Scope
4702 line_number,
4703 try o.lowerDebugType(decl.typeOf(zcu)),
4704 variable_index,
4705 .{ .local = !decl.isExtern(zcu) },
4706 );
47724707
4773 const debug_file = try o.getDebugFile(namespace.file_scope);
4708 const debug_expression = try o.builder.debugExpression(&.{});
47744709
4775 const debug_global_var = try o.builder.debugGlobalVar(
4776 try o.builder.metadataString(decl.name.toSlice(ip)), // Name
4777 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
4778 debug_file, // File
4779 debug_file, // Scope
4780 line_number,
4781 try o.lowerDebugType(decl.typeOf(zcu)),
4782 variable_index,
4783 .{ .local = is_internal_linkage },
4784 );
4710 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
4711 debug_global_var,
4712 debug_expression,
4713 );
47854714
4786 const debug_expression = try o.builder.debugExpression(&.{});
4715 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
4716 try o.debug_globals.append(o.gpa, debug_global_var_expression);
4717 }
4718 }
47874719
4788 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
4789 debug_global_var,
4790 debug_expression,
4791 );
4720 if (decl.isExtern(zcu)) {
4721 const global_index = o.decl_map.get(decl_index).?;
47924722
4793 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
4794 try o.debug_globals.append(o.gpa, debug_global_var_expression);
4723 const decl_name = decl_name: {
4724 if (zcu.getTarget().isWasm() and decl.typeOf(zcu).zigTypeTag(zcu) == .Fn) {
4725 if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| {
4726 if (!std.mem.eql(u8, lib_name, "c")) {
4727 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
4728 }
4729 }
4730 }
4731 break :decl_name try o.builder.strtabString(decl.name.toSlice(ip));
4732 };
4733
4734 if (o.builder.getGlobal(decl_name)) |other_global| {
4735 if (other_global != global_index) {
4736 // Another global already has this name; just use it in place of this global.
4737 try global_index.replace(other_global, &o.builder);
4738 return;
4739 }
4740 }
4741
4742 try global_index.rename(decl_name, &o.builder);
4743 global_index.setLinkage(.external, &o.builder);
4744 global_index.setUnnamedAddr(.default, &o.builder);
4745 if (zcu.comp.config.dll_export_fns)
4746 global_index.setDllStorageClass(.default, &o.builder);
4747
4748 if (decl.val.getVariable(zcu)) |decl_var| {
4749 if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
4750 }
47954751 }
47964752 }
47974753};
......@@ -5193,7 +5149,6 @@ pub const FuncGen = struct {
51935149
51945150 const fqn = try decl.fullyQualifiedName(zcu);
51955151
5196 const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
51975152 const fn_ty = try zcu.funcType(.{
51985153 .param_types = &.{},
51995154 .return_type = .void_type,
......@@ -5211,7 +5166,7 @@ pub const FuncGen = struct {
52115166 .sp_flags = .{
52125167 .Optimized = owner_mod.optimize_mode != .Debug,
52135168 .Definition = true,
5214 .LocalToUnit = is_internal_linkage,
5169 .LocalToUnit = true, // TODO: we can't know this at this point, since the function could be exported later!
52155170 },
52165171 },
52175172 o.debug_compile_unit,
src/link.zig+6-6
......@@ -606,12 +606,12 @@ pub const File = struct {
606606 base: *File,
607607 module: *Module,
608608 exported: Module.Exported,
609 exports: []const *Module.Export,
609 export_indices: []const u32,
610610 ) UpdateExportsError!void {
611611 switch (base.tag) {
612612 inline else => |tag| {
613613 if (tag != .c and build_options.only_c) unreachable;
614 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, exports);
614 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, export_indices);
615615 },
616616 }
617617 }
......@@ -671,11 +671,11 @@ pub const File = struct {
671671 }
672672 }
673673
674 pub fn deleteDeclExport(
674 pub fn deleteExport(
675675 base: *File,
676 decl_index: InternPool.DeclIndex,
676 exported: Zcu.Exported,
677677 name: InternPool.NullTerminatedString,
678 ) !void {
678 ) void {
679679 if (build_options.only_c) @compileError("unreachable");
680680 switch (base.tag) {
681681 .plan9,
......@@ -685,7 +685,7 @@ pub const File = struct {
685685 => {},
686686
687687 inline else => |tag| {
688 return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteDeclExport(decl_index, name);
688 return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteExport(exported, name);
689689 },
690690 }
691691 }
src/link/C.zig+22-7
......@@ -183,6 +183,8 @@ pub fn updateFunc(
183183 air: Air,
184184 liveness: Liveness,
185185) !void {
186 if (true) @panic("TODO jacobly");
187
186188 const gpa = self.base.comp.gpa;
187189
188190 const func = zcu.funcInfo(func_index);
......@@ -250,6 +252,8 @@ pub fn updateFunc(
250252}
251253
252254fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
255 if (true) @panic("TODO jacobly");
256
253257 const gpa = self.base.comp.gpa;
254258 const anon_decl = self.anon_decls.keys()[i];
255259
......@@ -306,6 +310,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
306310}
307311
308312pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
313 if (true) @panic("TODO jacobly");
314
309315 const tracy = trace(@src());
310316 defer tracy.end();
311317
......@@ -390,6 +396,8 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
390396}
391397
392398pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
399 if (true) @panic("TODO jacobly");
400
393401 _ = arena; // Has the same lifetime as the call to Compilation.update.
394402
395403 const tracy = trace(@src());
......@@ -451,9 +459,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
451459 {
452460 var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
453461 defer export_names.deinit(gpa);
454 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.decl_exports.entries.len));
455 for (zcu.decl_exports.values()) |exports| for (exports.items) |@"export"|
456 try export_names.put(gpa, @"export".opts.name, {});
462 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
463 for (zcu.single_exports.values()) |export_idx| {
464 export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
465 }
466 for (zcu.multi_exports.values()) |info| {
467 try export_names.ensureUnusedCapacity(info.len);
468 for (zcu.all_exports.items[info.index..][0..info.len]) |export_idx| {
469 export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
470 }
471 }
457472
458473 for (self.anon_decls.values()) |*decl_block| {
459474 try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);
......@@ -781,10 +796,10 @@ pub fn updateExports(
781796 self: *C,
782797 zcu: *Zcu,
783798 exported: Zcu.Exported,
784 exports: []const *Zcu.Export,
799 export_indices: []const u32,
785800) !void {
786 _ = exports;
787 _ = exported;
788 _ = zcu;
789801 _ = self;
802 _ = zcu;
803 _ = exported;
804 _ = export_indices;
790805}
src/link/Coff.zig+18-17
......@@ -1162,9 +1162,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
11621162
11631163 try self.updateDeclCode(decl_index, code, .FUNCTION);
11641164
1165 // Since we updated the vaddr and the size, each corresponding export
1166 // symbol also needs to be updated.
1167 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1165 // Exports will be updated by `Zcu.processExports` after the update.
11681166}
11691167
11701168pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {
......@@ -1286,9 +1284,7 @@ pub fn updateDecl(
12861284
12871285 try self.updateDeclCode(decl_index, code, .NULL);
12881286
1289 // Since we updated the vaddr and the size, each corresponding export
1290 // symbol also needs to be updated.
1291 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1287 // Exports will be updated by `Zcu.processExports` after the update.
12921288}
12931289
12941290fn updateLazySymbolAtom(
......@@ -1509,7 +1505,7 @@ pub fn updateExports(
15091505 self: *Coff,
15101506 mod: *Module,
15111507 exported: Module.Exported,
1512 exports: []const *Module.Export,
1508 export_indices: []const u32,
15131509) link.File.UpdateExportsError!void {
15141510 if (build_options.skip_non_native and builtin.object_format != .coff) {
15151511 @panic("Attempted to compile for object format that was disabled by build configuration");
......@@ -1522,7 +1518,8 @@ pub fn updateExports(
15221518 if (comp.config.use_llvm) {
15231519 // Even in the case of LLVM, we need to notice certain exported symbols in order to
15241520 // detect the default subsystem.
1525 for (exports) |exp| {
1521 for (export_indices) |export_idx| {
1522 const exp = mod.all_exports.items[export_idx];
15261523 const exported_decl_index = switch (exp.exported) {
15271524 .decl_index => |i| i,
15281525 .value => continue,
......@@ -1552,7 +1549,7 @@ pub fn updateExports(
15521549 }
15531550 }
15541551
1555 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
1552 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
15561553
15571554 const gpa = comp.gpa;
15581555
......@@ -1562,7 +1559,7 @@ pub fn updateExports(
15621559 break :blk self.decls.getPtr(decl_index).?;
15631560 },
15641561 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1565 const first_exp = exports[0];
1562 const first_exp = mod.all_exports.items[export_indices[0]];
15661563 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
15671564 switch (res) {
15681565 .ok => {},
......@@ -1570,7 +1567,7 @@ pub fn updateExports(
15701567 // TODO maybe it's enough to return an error here and let Module.processExportsInner
15711568 // handle the error?
15721569 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1573 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1570 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
15741571 return;
15751572 },
15761573 }
......@@ -1580,12 +1577,13 @@ pub fn updateExports(
15801577 const atom_index = metadata.atom;
15811578 const atom = self.getAtom(atom_index);
15821579
1583 for (exports) |exp| {
1580 for (export_indices) |export_idx| {
1581 const exp = mod.all_exports.items[export_idx];
15841582 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
15851583
15861584 if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {
15871585 if (!mem.eql(u8, section_name, ".text")) {
1588 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1586 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
15891587 gpa,
15901588 exp.getSrcLoc(mod),
15911589 "Unimplemented: ExportOptions.section",
......@@ -1596,7 +1594,7 @@ pub fn updateExports(
15961594 }
15971595
15981596 if (exp.opts.linkage == .link_once) {
1599 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1597 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
16001598 gpa,
16011599 exp.getSrcLoc(mod),
16021600 "Unimplemented: GlobalLinkage.link_once",
......@@ -1641,13 +1639,16 @@ pub fn updateExports(
16411639 }
16421640}
16431641
1644pub fn deleteDeclExport(
1642pub fn deleteExport(
16451643 self: *Coff,
1646 decl_index: InternPool.DeclIndex,
1644 exported: Zcu.Exported,
16471645 name: InternPool.NullTerminatedString,
16481646) void {
16491647 if (self.llvm_object) |_| return;
1650 const metadata = self.decls.getPtr(decl_index) orelse return;
1648 const metadata = switch (exported) {
1649 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1650 .value => |value| self.anon_decls.getPtr(value) orelse return,
1651 };
16511652 const mod = self.base.comp.module.?;
16521653 const name_slice = name.toSlice(&mod.intern_pool);
16531654 const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
src/link/Elf.zig+6-6
......@@ -3011,13 +3011,13 @@ pub fn updateExports(
30113011 self: *Elf,
30123012 mod: *Module,
30133013 exported: Module.Exported,
3014 exports: []const *Module.Export,
3014 export_indices: []const u32,
30153015) link.File.UpdateExportsError!void {
30163016 if (build_options.skip_non_native and builtin.object_format != .elf) {
30173017 @panic("Attempted to compile for object format that was disabled by build configuration");
30183018 }
3019 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3020 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
3019 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
3020 return self.zigObjectPtr().?.updateExports(self, mod, exported, export_indices);
30213021}
30223022
30233023pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.DeclIndex) !void {
......@@ -3025,13 +3025,13 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.Dec
30253025 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
30263026}
30273027
3028pub fn deleteDeclExport(
3028pub fn deleteExport(
30293029 self: *Elf,
3030 decl_index: InternPool.DeclIndex,
3030 exported: Zcu.Exported,
30313031 name: InternPool.NullTerminatedString,
30323032) void {
30333033 if (self.llvm_object) |_| return;
3034 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
3034 return self.zigObjectPtr().?.deleteExport(self, exported, name);
30353035}
30363036
30373037fn addLinkerDefinedSymbols(self: *Elf) !void {
src/link/Elf/ZigObject.zig+15-15
......@@ -1115,9 +1115,7 @@ pub fn updateFunc(
11151115 );
11161116 }
11171117
1118 // Since we updated the vaddr and the size, each corresponding export
1119 // symbol also needs to be updated.
1120 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1118 // Exports will be updated by `Zcu.processExports` after the update.
11211119}
11221120
11231121pub fn updateDecl(
......@@ -1194,9 +1192,7 @@ pub fn updateDecl(
11941192 );
11951193 }
11961194
1197 // Since we updated the vaddr and the size, each corresponding export
1198 // symbol also needs to be updated.
1199 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1195 // Exports will be updated by `Zcu.processExports` after the update.
12001196}
12011197
12021198fn updateLazySymbol(
......@@ -1386,7 +1382,7 @@ pub fn updateExports(
13861382 elf_file: *Elf,
13871383 mod: *Module,
13881384 exported: Module.Exported,
1389 exports: []const *Module.Export,
1385 export_indices: []const u32,
13901386) link.File.UpdateExportsError!void {
13911387 const tracy = trace(@src());
13921388 defer tracy.end();
......@@ -1398,7 +1394,7 @@ pub fn updateExports(
13981394 break :blk self.decls.getPtr(decl_index).?;
13991395 },
14001396 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1401 const first_exp = exports[0];
1397 const first_exp = mod.all_exports.items[export_indices[0]];
14021398 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
14031399 switch (res) {
14041400 .ok => {},
......@@ -1406,7 +1402,7 @@ pub fn updateExports(
14061402 // TODO maybe it's enough to return an error here and let Module.processExportsInner
14071403 // handle the error?
14081404 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1409 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1405 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
14101406 return;
14111407 },
14121408 }
......@@ -1418,11 +1414,12 @@ pub fn updateExports(
14181414 const esym = self.local_esyms.items(.elf_sym)[esym_index];
14191415 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
14201416
1421 for (exports) |exp| {
1417 for (export_indices) |export_idx| {
1418 const exp = mod.all_exports.items[export_idx];
14221419 if (exp.opts.section.unwrap()) |section_name| {
14231420 if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
14241421 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1425 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1422 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
14261423 gpa,
14271424 exp.getSrcLoc(mod),
14281425 "Unimplemented: ExportOptions.section",
......@@ -1437,7 +1434,7 @@ pub fn updateExports(
14371434 .weak => elf.STB_WEAK,
14381435 .link_once => {
14391436 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1440 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1437 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
14411438 gpa,
14421439 exp.getSrcLoc(mod),
14431440 "Unimplemented: GlobalLinkage.LinkOnce",
......@@ -1487,13 +1484,16 @@ pub fn updateDeclLineNumber(
14871484 }
14881485}
14891486
1490pub fn deleteDeclExport(
1487pub fn deleteExport(
14911488 self: *ZigObject,
14921489 elf_file: *Elf,
1493 decl_index: InternPool.DeclIndex,
1490 exported: Zcu.Exported,
14941491 name: InternPool.NullTerminatedString,
14951492) void {
1496 const metadata = self.decls.getPtr(decl_index) orelse return;
1493 const metadata = switch (exported) {
1494 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1495 .value => |value| self.anon_decls.getPtr(value) orelse return,
1496 };
14971497 const mod = elf_file.base.comp.module.?;
14981498 const exp_name = name.toSlice(&mod.intern_pool);
14991499 const esym_index = metadata.@"export"(self, exp_name) orelse return;
src/link/MachO.zig+7-7
......@@ -3196,22 +3196,22 @@ pub fn updateExports(
31963196 self: *MachO,
31973197 mod: *Module,
31983198 exported: Module.Exported,
3199 exports: []const *Module.Export,
3199 export_indices: []const u32,
32003200) link.File.UpdateExportsError!void {
32013201 if (build_options.skip_non_native and builtin.object_format != .macho) {
32023202 @panic("Attempted to compile for object format that was disabled by build configuration");
32033203 }
3204 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3205 return self.getZigObject().?.updateExports(self, mod, exported, exports);
3204 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
3205 return self.getZigObject().?.updateExports(self, mod, exported, export_indices);
32063206}
32073207
3208pub fn deleteDeclExport(
3208pub fn deleteExport(
32093209 self: *MachO,
3210 decl_index: InternPool.DeclIndex,
3210 exported: Zcu.Exported,
32113211 name: InternPool.NullTerminatedString,
3212) Allocator.Error!void {
3212) void {
32133213 if (self.llvm_object) |_| return;
3214 return self.getZigObject().?.deleteDeclExport(self, decl_index, name);
3214 return self.getZigObject().?.deleteExport(self, exported, name);
32153215}
32163216
32173217pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
src/link/MachO/ZigObject.zig+15-15
......@@ -713,9 +713,7 @@ pub fn updateFunc(
713713 );
714714 }
715715
716 // Since we updated the vaddr and the size, each corresponding export
717 // symbol also needs to be updated.
718 return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
716 // Exports will be updated by `Zcu.processExports` after the update.
719717}
720718
721719pub fn updateDecl(
......@@ -790,9 +788,7 @@ pub fn updateDecl(
790788 );
791789 }
792790
793 // Since we updated the vaddr and the size, each corresponding export symbol also
794 // needs to be updated.
795 try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
791 // Exports will be updated by `Zcu.processExports` after the update.
796792}
797793
798794fn updateDeclCode(
......@@ -1187,7 +1183,7 @@ pub fn updateExports(
11871183 macho_file: *MachO,
11881184 mod: *Module,
11891185 exported: Module.Exported,
1190 exports: []const *Module.Export,
1186 export_indices: []const u32,
11911187) link.File.UpdateExportsError!void {
11921188 const tracy = trace(@src());
11931189 defer tracy.end();
......@@ -1199,7 +1195,7 @@ pub fn updateExports(
11991195 break :blk self.decls.getPtr(decl_index).?;
12001196 },
12011197 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1202 const first_exp = exports[0];
1198 const first_exp = mod.all_exports.items[export_indices[0]];
12031199 const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));
12041200 switch (res) {
12051201 .ok => {},
......@@ -1207,7 +1203,7 @@ pub fn updateExports(
12071203 // TODO maybe it's enough to return an error here and let Module.processExportsInner
12081204 // handle the error?
12091205 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1210 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1206 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
12111207 return;
12121208 },
12131209 }
......@@ -1218,11 +1214,12 @@ pub fn updateExports(
12181214 const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
12191215 const nlist = self.symtab.items(.nlist)[nlist_idx];
12201216
1221 for (exports) |exp| {
1217 for (export_indices) |export_idx| {
1218 const exp = mod.all_exports.items[export_idx];
12221219 if (exp.opts.section.unwrap()) |section_name| {
12231220 if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
12241221 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1225 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1222 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
12261223 gpa,
12271224 exp.getSrcLoc(mod),
12281225 "Unimplemented: ExportOptions.section",
......@@ -1232,7 +1229,7 @@ pub fn updateExports(
12321229 }
12331230 }
12341231 if (exp.opts.linkage == .link_once) {
1235 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
1232 try mod.failed_exports.putNoClobber(mod.gpa, export_idx, try Module.ErrorMsg.create(
12361233 gpa,
12371234 exp.getSrcLoc(mod),
12381235 "Unimplemented: GlobalLinkage.link_once",
......@@ -1364,15 +1361,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo
13641361 }
13651362}
13661363
1367pub fn deleteDeclExport(
1364pub fn deleteExport(
13681365 self: *ZigObject,
13691366 macho_file: *MachO,
1370 decl_index: InternPool.DeclIndex,
1367 exported: Zcu.Exported,
13711368 name: InternPool.NullTerminatedString,
13721369) void {
13731370 const mod = macho_file.base.comp.module.?;
13741371
1375 const metadata = self.decls.getPtr(decl_index) orelse return;
1372 const metadata = switch (exported) {
1373 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1374 .value => |value| self.anon_decls.getPtr(value) orelse return,
1375 };
13761376 const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
13771377
13781378 log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
src/link/NvPtx.zig+2-2
......@@ -96,12 +96,12 @@ pub fn updateExports(
9696 self: *NvPtx,
9797 module: *Module,
9898 exported: Module.Exported,
99 exports: []const *Module.Export,
99 export_indices: []const u32,
100100) !void {
101101 if (build_options.skip_non_native and builtin.object_format != .nvptx)
102102 @panic("Attempted to compile for object format that was disabled by build configuration");
103103
104 return self.llvm_object.updateExports(module, exported, exports);
104 return self.llvm_object.updateExports(module, exported, export_indices);
105105}
106106
107107pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {
src/link/Plan9.zig+44-22
......@@ -60,6 +60,9 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(
6060) = .{},
6161/// the code is modified when relocated, so that is why it is mutable
6262data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{},
63/// When `updateExports` is called, we store the export indices here, to be used
64/// during flush.
65decl_exports: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u32) = .{},
6366
6467/// Table of unnamed constants associated with a parent `Decl`.
6568/// We store them here so that we can free the constants whenever the `Decl`
......@@ -770,8 +773,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
770773 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
771774 }
772775 self.syms.items[atom.sym_index.?].value = off;
773 if (mod.decl_exports.get(decl_index)) |exports| {
774 try self.addDeclExports(mod, decl_index, exports.items);
776 if (self.decl_exports.get(decl_index)) |export_indices| {
777 try self.addDeclExports(mod, decl_index, export_indices);
775778 }
776779 }
777780 }
......@@ -836,8 +839,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
836839 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
837840 }
838841 self.syms.items[atom.sym_index.?].value = off;
839 if (mod.decl_exports.get(decl_index)) |exports| {
840 try self.addDeclExports(mod, decl_index, exports.items);
842 if (self.decl_exports.get(decl_index)) |export_indices| {
843 try self.addDeclExports(mod, decl_index, export_indices);
841844 }
842845 }
843846 // write the unnamed constants after the other data decls
......@@ -1007,20 +1010,21 @@ fn addDeclExports(
10071010 self: *Plan9,
10081011 mod: *Module,
10091012 decl_index: InternPool.DeclIndex,
1010 exports: []const *Module.Export,
1013 export_indices: []const u32,
10111014) !void {
10121015 const gpa = self.base.comp.gpa;
10131016 const metadata = self.decls.getPtr(decl_index).?;
10141017 const atom = self.getAtom(metadata.index);
10151018
1016 for (exports) |exp| {
1019 for (export_indices) |export_idx| {
1020 const exp = mod.all_exports.items[export_idx];
10171021 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
10181022 // plan9 does not support custom sections
10191023 if (exp.opts.section.unwrap()) |section_name| {
10201024 if (!section_name.eqlSlice(".text", &mod.intern_pool) and
10211025 !section_name.eqlSlice(".data", &mod.intern_pool))
10221026 {
1023 try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
1027 try mod.failed_exports.put(mod.gpa, export_idx, try Module.ErrorMsg.create(
10241028 gpa,
10251029 mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod),
10261030 "plan9 does not support extra sections",
......@@ -1152,15 +1156,23 @@ pub fn updateExports(
11521156 self: *Plan9,
11531157 module: *Module,
11541158 exported: Module.Exported,
1155 exports: []const *Module.Export,
1159 export_indices: []const u32,
11561160) !void {
1161 const gpa = self.base.comp.gpa;
11571162 switch (exported) {
11581163 .value => @panic("TODO: plan9 updateExports handling values"),
1159 .decl_index => |decl_index| _ = try self.seeDecl(decl_index),
1164 .decl_index => |decl_index| {
1165 _ = try self.seeDecl(decl_index);
1166 if (self.decl_exports.fetchSwapRemove(decl_index)) |kv| {
1167 gpa.free(kv.value);
1168 }
1169 try self.decl_exports.ensureUnusedCapacity(gpa, 1);
1170 const duped_indices = try gpa.dupe(u32, export_indices);
1171 self.decl_exports.putAssumeCapacityNoClobber(decl_index, duped_indices);
1172 },
11601173 }
1161 // we do all the things in flush
1174 // all proper work is done in flush
11621175 _ = module;
1163 _ = exports;
11641176}
11651177
11661178pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
......@@ -1290,6 +1302,10 @@ pub fn deinit(self: *Plan9) void {
12901302 gpa.free(self.syms.items[sym_index].name);
12911303 }
12921304 self.data_decl_table.deinit(gpa);
1305 for (self.decl_exports.values()) |export_indices| {
1306 gpa.free(export_indices);
1307 }
1308 self.decl_exports.deinit(gpa);
12931309 self.syms.deinit(gpa);
12941310 self.got_index_free_list.deinit(gpa);
12951311 self.syms_index_free_list.deinit(gpa);
......@@ -1395,10 +1411,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
13951411 const atom = self.getAtom(decl_metadata.index);
13961412 const sym = self.syms.items[atom.sym_index.?];
13971413 try self.writeSym(writer, sym);
1398 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
1399 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
1400 try self.writeSym(writer, self.syms.items[exp_i]);
1401 };
1414 if (self.decl_exports.get(decl_index)) |export_indices| {
1415 for (export_indices) |export_idx| {
1416 const exp = mod.all_exports.items[export_idx];
1417 if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
1418 try self.writeSym(writer, self.syms.items[exp_i]);
1419 }
1420 }
14021421 }
14031422 }
14041423 }
......@@ -1442,13 +1461,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
14421461 const atom = self.getAtom(decl_metadata.index);
14431462 const sym = self.syms.items[atom.sym_index.?];
14441463 try self.writeSym(writer, sym);
1445 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
1446 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
1447 const s = self.syms.items[exp_i];
1448 if (mem.eql(u8, s.name, "_start"))
1449 self.entry_val = s.value;
1450 try self.writeSym(writer, s);
1451 };
1464 if (self.decl_exports.get(decl_index)) |export_indices| {
1465 for (export_indices) |export_idx| {
1466 const exp = mod.all_exports.items[export_idx];
1467 if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
1468 const s = self.syms.items[exp_i];
1469 if (mem.eql(u8, s.name, "_start"))
1470 self.entry_val = s.value;
1471 try self.writeSym(writer, s);
1472 }
1473 }
14521474 }
14531475 }
14541476 }
src/link/SpirV.zig+3-2
......@@ -152,7 +152,7 @@ pub fn updateExports(
152152 self: *SpirV,
153153 mod: *Module,
154154 exported: Module.Exported,
155 exports: []const *Module.Export,
155 export_indices: []const u32,
156156) !void {
157157 const decl_index = switch (exported) {
158158 .decl_index => |i| i,
......@@ -177,7 +177,8 @@ pub fn updateExports(
177177 if ((!is_vulkan and execution_model == .Kernel) or
178178 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
179179 {
180 for (exports) |exp| {
180 for (export_indices) |export_idx| {
181 const exp = mod.all_exports.items[export_idx];
181182 try self.object.spv.declareEntryPoint(
182183 spv_decl_index,
183184 exp.opts.name.toSlice(&mod.intern_pool),
src/link/Wasm.zig+6-6
......@@ -1542,26 +1542,26 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
15421542 return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);
15431543}
15441544
1545pub fn deleteDeclExport(
1545pub fn deleteExport(
15461546 wasm: *Wasm,
1547 decl_index: InternPool.DeclIndex,
1547 exported: Zcu.Exported,
15481548 name: InternPool.NullTerminatedString,
15491549) void {
15501550 if (wasm.llvm_object) |_| return;
1551 return wasm.zigObjectPtr().?.deleteDeclExport(wasm, decl_index, name);
1551 return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);
15521552}
15531553
15541554pub fn updateExports(
15551555 wasm: *Wasm,
15561556 mod: *Module,
15571557 exported: Module.Exported,
1558 exports: []const *Module.Export,
1558 export_indices: []const u32,
15591559) !void {
15601560 if (build_options.skip_non_native and builtin.object_format != .wasm) {
15611561 @panic("Attempted to compile for object format that was disabled by build configuration");
15621562 }
1563 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
1564 return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, exports);
1563 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
1564 return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, export_indices);
15651565}
15661566
15671567pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
src/link/Wasm/ZigObject.zig+11-6
......@@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr(
833833 return target_symbol_index;
834834}
835835
836pub fn deleteDeclExport(
836pub fn deleteExport(
837837 zig_object: *ZigObject,
838838 wasm_file: *Wasm,
839 decl_index: InternPool.DeclIndex,
839 exported: Zcu.Exported,
840840 name: InternPool.NullTerminatedString,
841841) void {
842842 const mod = wasm_file.base.comp.module.?;
843 const decl_index = switch (exported) {
844 .decl_index => |decl_index| decl_index,
845 .value => @panic("TODO: implement Wasm linker code for exporting a constant value"),
846 };
843847 const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
844848 if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
845849 const sym = zig_object.symbol(sym_index);
......@@ -856,7 +860,7 @@ pub fn updateExports(
856860 wasm_file: *Wasm,
857861 mod: *Module,
858862 exported: Module.Exported,
859 exports: []const *Module.Export,
863 export_indices: []const u32,
860864) !void {
861865 const decl_index = switch (exported) {
862866 .decl_index => |i| i,
......@@ -873,9 +877,10 @@ pub fn updateExports(
873877 const gpa = mod.gpa;
874878 log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});
875879
876 for (exports) |exp| {
880 for (export_indices) |export_idx| {
881 const exp = mod.all_exports.items[export_idx];
877882 if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {
878 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
883 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
879884 gpa,
880885 decl.navSrcLoc(mod).upgrade(mod),
881886 "Unimplemented: ExportOptions.section '{s}'",
......@@ -908,7 +913,7 @@ pub fn updateExports(
908913 },
909914 .strong => {}, // symbols are strong by default
910915 .link_once => {
911 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
916 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
912917 gpa,
913918 decl.navSrcLoc(mod).upgrade(mod),
914919 "Unimplemented: LinkOnce",