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...@@ -117,6 +117,10 @@ maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAll
117/// Backed by gpa.117/// Backed by gpa.
118comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{},118comptime_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
120const MaybeComptimeAlloc = struct {124const MaybeComptimeAlloc = struct {
121 /// The runtime index of the `alloc` instruction.125 /// The runtime index of the `alloc` instruction.
122 runtime_index: Value.RuntimeIndex,126 runtime_index: Value.RuntimeIndex,
...@@ -186,6 +190,7 @@ const build_options = @import("build_options");...@@ -186,6 +190,7 @@ const build_options = @import("build_options");
186const Compilation = @import("Compilation.zig");190const Compilation = @import("Compilation.zig");
187const InternPool = @import("InternPool.zig");191const InternPool = @import("InternPool.zig");
188const Alignment = InternPool.Alignment;192const Alignment = InternPool.Alignment;
193const AnalUnit = InternPool.AnalUnit;
189const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;194const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
190195
191pub const default_branch_quota = 1000;196pub const default_branch_quota = 1000;
...@@ -875,6 +880,7 @@ pub fn deinit(sema: *Sema) void {...@@ -875,6 +880,7 @@ pub fn deinit(sema: *Sema) void {
875 sema.base_allocs.deinit(gpa);880 sema.base_allocs.deinit(gpa);
876 sema.maybe_comptime_allocs.deinit(gpa);881 sema.maybe_comptime_allocs.deinit(gpa);
877 sema.comptime_allocs.deinit(gpa);882 sema.comptime_allocs.deinit(gpa);
883 sema.exports.deinit(gpa);
878 sema.* = undefined;884 sema.* = undefined;
879}885}
880886
...@@ -2735,12 +2741,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {...@@ -2735,12 +2741,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
2735 if (!zcu.comp.debug_incremental) return false;2741 if (!zcu.comp.debug_incremental) return false;
27362742
2737 const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);2743 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 });
2739 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or2745 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
2740 zcu.potentially_outdated.swapRemove(decl_as_depender);2746 zcu.potentially_outdated.swapRemove(decl_as_depender);
2741 if (!was_outdated) return false;2747 if (!was_outdated) return false;
2742 _ = zcu.outdated_ready.swapRemove(decl_as_depender);2748 _ = 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 }));
2744 zcu.intern_pool.remove(ty);2750 zcu.intern_pool.remove(ty);
2745 zcu.declPtr(decl_index).analysis = .dependency_failure;2751 zcu.declPtr(decl_index).analysis = .dependency_failure;
2746 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });2752 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
...@@ -2834,7 +2840,7 @@ fn zirStructDecl(...@@ -2834,7 +2840,7 @@ fn zirStructDecl(
2834 if (sema.mod.comp.debug_incremental) {2840 if (sema.mod.comp.debug_incremental) {
2835 try ip.addDependency(2841 try ip.addDependency(
2836 sema.gpa,2842 sema.gpa,
2837 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),2843 AnalUnit.wrap(.{ .decl = new_decl_index }),
2838 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },2844 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2839 );2845 );
2840 }2846 }
...@@ -3068,7 +3074,7 @@ fn zirEnumDecl(...@@ -3068,7 +3074,7 @@ fn zirEnumDecl(
3068 if (sema.mod.comp.debug_incremental) {3074 if (sema.mod.comp.debug_incremental) {
3069 try mod.intern_pool.addDependency(3075 try mod.intern_pool.addDependency(
3070 sema.gpa,3076 sema.gpa,
3071 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),3077 AnalUnit.wrap(.{ .decl = new_decl_index }),
3072 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },3078 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3073 );3079 );
3074 }3080 }
...@@ -3334,7 +3340,7 @@ fn zirUnionDecl(...@@ -3334,7 +3340,7 @@ fn zirUnionDecl(
3334 if (sema.mod.comp.debug_incremental) {3340 if (sema.mod.comp.debug_incremental) {
3335 try mod.intern_pool.addDependency(3341 try mod.intern_pool.addDependency(
3336 sema.gpa,3342 sema.gpa,
3337 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),3343 AnalUnit.wrap(.{ .decl = new_decl_index }),
3338 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },3344 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3339 );3345 );
3340 }3346 }
...@@ -3422,7 +3428,7 @@ fn zirOpaqueDecl(...@@ -3422,7 +3428,7 @@ fn zirOpaqueDecl(
3422 if (sema.mod.comp.debug_incremental) {3428 if (sema.mod.comp.debug_incremental) {
3423 try ip.addDependency(3429 try ip.addDependency(
3424 gpa,3430 gpa,
3425 InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),3431 AnalUnit.wrap(.{ .decl = new_decl_index }),
3426 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },3432 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
3427 );3433 );
3428 }3434 }
...@@ -6423,10 +6429,9 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6423,10 +6429,9 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6423 return sema.analyzeExport(block, src, options, decl_index);6429 return sema.analyzeExport(block, src, options, decl_index);
6424 }6430 }
64256431
6426 try addExport(mod, .{6432 try sema.exports.append(mod.gpa, .{
6427 .opts = options,6433 .opts = options,
6428 .src = src,6434 .src = src,
6429 .owner_decl = sema.owner_decl_index,
6430 .exported = .{ .value = operand.toIntern() },6435 .exported = .{ .value = operand.toIntern() },
6431 .status = .in_progress,6436 .status = .in_progress,
6432 });6437 });
...@@ -6469,46 +6474,14 @@ pub fn analyzeExport(...@@ -6469,46 +6474,14 @@ pub fn analyzeExport(
64696474
6470 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);6475 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
64716476
6472 try addExport(mod, .{6477 try sema.exports.append(gpa, .{
6473 .opts = options,6478 .opts = options,
6474 .src = src,6479 .src = src,
6475 .owner_decl = sema.owner_decl_index,
6476 .exported = .{ .decl_index = exported_decl_index },6480 .exported = .{ .decl_index = exported_decl_index },
6477 .status = .in_progress,6481 .status = .in_progress,
6478 });6482 });
6479}6483}
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
6512fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {6485fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
6513 const mod = sema.mod;6486 const mod = sema.mod;
6514 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;6487 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
...@@ -8411,6 +8384,9 @@ fn instantiateGenericCall(...@@ -8411,6 +8384,9 @@ fn instantiateGenericCall(
8411 });8384 });
8412 sema.appendRefsAssumeCapacity(runtime_args.items);8385 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
8414 if (ensure_result_used) {8390 if (ensure_result_used) {
8415 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);8391 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
8416 }8392 }
...@@ -35263,6 +35239,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co...@@ -35263,6 +35239,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
35263 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));35239 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
35264 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();35240 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
35265 }35241 }
35242
35243 try sema.flushExports();
35266}35244}
3526735245
35268fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {35246fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
...@@ -36225,6 +36203,8 @@ fn semaStructFields(...@@ -36225,6 +36203,8 @@ fn semaStructFields(
3622536203
36226 struct_type.clearTypesWip(ip);36204 struct_type.clearTypesWip(ip);
36227 if (!any_inits) struct_type.setHaveFieldInits(ip);36205 if (!any_inits) struct_type.setHaveFieldInits(ip);
36206
36207 try sema.flushExports();
36228}36208}
3622936209
36230// This logic must be kept in sync with `semaStructFields`36210// This logic must be kept in sync with `semaStructFields`
...@@ -36365,6 +36345,8 @@ fn semaStructFieldInits(...@@ -36365,6 +36345,8 @@ fn semaStructFieldInits(
36365 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();36345 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
36366 }36346 }
36367 }36347 }
36348
36349 try sema.flushExports();
36368}36350}
3636936351
36370fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {36352fn 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...@@ -36738,6 +36720,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
36738 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));36720 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
36739 union_type.tagTypePtr(ip).* = enum_ty;36721 union_type.tagTypePtr(ip).* = enum_ty;
36740 }36722 }
36723
36724 try sema.flushExports();
36741}36725}
3674236726
36743fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value {36727fn 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 {...@@ -38362,7 +38346,7 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
38362 return;38346 return;
38363 }38347 }
3836438348
38365 const depender = InternPool.AnalUnit.wrap(38349 const depender = AnalUnit.wrap(
38366 if (sema.owner_func_index != .none)38350 if (sema.owner_func_index != .none)
38367 .{ .func = sema.owner_func_index }38351 .{ .func = sema.owner_func_index }
38368 else38352 else
...@@ -38494,6 +38478,52 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check:...@@ -38494,6 +38478,52 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check:
38494 }38478 }
38495}38479}
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
38497pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;38527pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
38498pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;38528pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
3849938529
src/Zcu.zig+160-143
...@@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir;...@@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir;
35const clang = @import("clang.zig");35const clang = @import("clang.zig");
36const InternPool = @import("InternPool.zig");36const InternPool = @import("InternPool.zig");
37const Alignment = InternPool.Alignment;37const Alignment = InternPool.Alignment;
38const AnalUnit = InternPool.AnalUnit;
38const BuiltinFn = std.zig.BuiltinFn;39const BuiltinFn = std.zig.BuiltinFn;
39const LlvmObject = @import("codegen/llvm.zig").Object;40const LlvmObject = @import("codegen/llvm.zig").Object;
4041
...@@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined,...@@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined,
71global_zir_cache: Compilation.Directory,72global_zir_cache: Compilation.Directory,
72/// Used by AstGen worker to load and store ZIR cache.73/// Used by AstGen worker to load and store ZIR cache.
73local_zir_cache: Compilation.Directory,74local_zir_cache: Compilation.Directory,
74/// It's rare for a decl to be exported, so we save memory by having a sparse75/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
75/// map of Decl indexes to details about them being exported.76/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
76/// The Export memory is owned by the `export_owners` table; the slice itself77all_exports: ArrayListUnmanaged(Export) = .{},
77/// is owned by this table. The slice is guaranteed to not be empty.78/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
78decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},79/// future semantic analysis.
79/// Same as `decl_exports` but for exported constant values.80free_exports: ArrayListUnmanaged(u32) = .{},
80value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},81/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
81/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl82/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
82/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that83/// whose analysis triggered the export.
83/// is performing the export of another Decl.84single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
84/// This table owns the Export memory.85/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
85export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},86/// The exports are `all_exports.items[index..][0..len]`.
87multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
88 index: u32,
89 len: u32,
90}) = .{},
86/// The set of all the Zig source files in the Module. We keep track of this in order91/// The set of all the Zig source files in the Module. We keep track of this in order
87/// to iterate over it and check which source files have been modified on the file system when92/// to iterate over it and check which source files have been modified on the file system when
88/// an update is requested, as well as to cache `@import` results.93/// an update is requested, as well as to cache `@import` results.
...@@ -126,9 +131,8 @@ compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {...@@ -126,9 +131,8 @@ compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
126failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},131failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
127/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.132/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
128failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},133failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
129/// Using a map here for consistency with the other fields here.134/// Key is index into `all_exports`.
130/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.135failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{},
131failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
132/// If a decl failed due to a cimport error, the corresponding Clang errors136/// If a decl failed due to a cimport error, the corresponding Clang errors
133/// are stored here.137/// are stored here.
134cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},138cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},
...@@ -140,14 +144,14 @@ global_error_set: GlobalErrorSet = .{},...@@ -140,14 +144,14 @@ global_error_set: GlobalErrorSet = .{},
140error_limit: ErrorInt,144error_limit: ErrorInt,
141145
142/// Value is the number of PO or outdated Decls which this AnalUnit depends on.146/// 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) = .{},
144/// Value is the number of PO or outdated Decls which this AnalUnit depends on.148/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
145/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.149/// 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) = .{},
147/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.151/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
148/// Such `AnalUnit`s are ready for immediate re-analysis.152/// Such `AnalUnit`s are ready for immediate re-analysis.
149/// See `findOutdatedToAnalyze` for details.153/// See `findOutdatedToAnalyze` for details.
150outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, void) = .{},154outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
151/// This contains a set of Decls which may not be in `outdated`, but are the155/// This contains a set of Decls which may not be in `outdated`, but are the
152/// root Decls of files which have updated source and thus must be re-analyzed.156/// root Decls of files which have updated source and thus must be re-analyzed.
153/// If such a Decl is only in this set, the struct type index may be preserved157/// 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) = .{},...@@ -158,7 +162,7 @@ outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
158/// failure was something like running out of disk space, and trying again may162/// failure was something like running out of disk space, and trying again may
159/// succeed. On the next update, we will flush this list, marking all members of163/// succeed. On the next update, we will flush this list, marking all members of
160/// it as outdated.164/// it as outdated.
161retryable_failures: std.ArrayListUnmanaged(InternPool.AnalUnit) = .{},165retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{},
162166
163stage1_flags: packed struct {167stage1_flags: packed struct {
164 have_winmain: bool = false,168 have_winmain: bool = false,
...@@ -267,8 +271,6 @@ pub const Exported = union(enum) {...@@ -267,8 +271,6 @@ pub const Exported = union(enum) {
267pub const Export = struct {271pub const Export = struct {
268 opts: Options,272 opts: Options,
269 src: LazySrcLoc,273 src: LazySrcLoc,
270 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
271 owner_decl: Decl.Index,
272 exported: Exported,274 exported: Exported,
273 status: enum {275 status: enum {
274 in_progress,276 in_progress,
...@@ -2507,20 +2509,10 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2507,20 +2509,10 @@ pub fn deinit(zcu: *Zcu) void {
25072509
2508 zcu.compile_log_decls.deinit(gpa);2510 zcu.compile_log_decls.deinit(gpa);
25092511
2510 for (zcu.decl_exports.values()) |*export_list| {2512 zcu.all_exports.deinit(gpa);
2511 export_list.deinit(gpa);2513 zcu.free_exports.deinit(gpa);
2512 }2514 zcu.single_exports.deinit(gpa);
2513 zcu.decl_exports.deinit(gpa);2515 zcu.multi_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);
25242516
2525 zcu.global_error_set.deinit(gpa);2517 zcu.global_error_set.deinit(gpa);
25262518
...@@ -2590,11 +2582,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {...@@ -2590,11 +2582,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
2590 return decl_index == namespace.decl_index;2582 return decl_index == namespace.decl_index;
2591}2583}
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
2598// TODO https://github.com/ziglang/zig/issues/86432585// TODO https://github.com/ziglang/zig/issues/8643
2599const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;2586const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
2600const HackDataLayout = extern struct {2587const HackDataLayout = extern struct {
...@@ -3139,7 +3126,7 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -3139,7 +3126,7 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
31393126
3140/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may3127/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
3141/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.3128/// 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 {
3143 var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {3130 var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
3144 .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced3131 .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
3145 .func => |func_index| .{ .func_ies = func_index },3132 .func => |func_index| .{ .func_ies = func_index },
...@@ -3166,7 +3153,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP...@@ -3166,7 +3153,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP
3166 }3153 }
3167}3154}
31683155
3169pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {3156pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
3170 if (!zcu.comp.debug_incremental) return null;3157 if (!zcu.comp.debug_incremental) return null;
31713158
3172 if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {3159 if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
...@@ -3197,7 +3184,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {...@@ -3197,7 +3184,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
3197 // `outdated`. This set will be small (number of files changed in this3184 // `outdated`. This set will be small (number of files changed in this
3198 // update), so it's alright for us to just iterate here.3185 // update), so it's alright for us to just iterate here.
3199 for (zcu.outdated_file_root.keys()) |file_decl| {3186 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 });
3201 if (zcu.outdated.contains(decl_depender)) {3188 if (zcu.outdated.contains(decl_depender)) {
3202 // Since we didn't hit this in the first loop, this Decl must have3189 // Since we didn't hit this in the first loop, this Decl must have
3203 // pending dependencies, so is ineligible.3190 // pending dependencies, so is ineligible.
...@@ -3271,7 +3258,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {...@@ -3271,7 +3258,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
3271 chosen_decl_dependers,3258 chosen_decl_dependers,
3272 });3259 });
32733260
3274 return InternPool.AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });3261 return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
3275}3262}
32763263
3277/// During an incremental update, before semantic analysis, call this to flush all values from3264/// 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 {...@@ -3456,7 +3443,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3456 // which tries to limit re-analysis to Decls whose previously listed3443 // which tries to limit re-analysis to Decls whose previously listed
3457 // dependencies are all up-to-date.3444 // 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 });
3460 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or3447 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
3461 mod.potentially_outdated.swapRemove(decl_as_depender);3448 mod.potentially_outdated.swapRemove(decl_as_depender);
34623449
...@@ -3485,7 +3472,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3485,7 +3472,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3485 // The exports this Decl performs will be re-discovered, so we remove them here3472 // The exports this Decl performs will be re-discovered, so we remove them here
3486 // prior to re-analysis.3473 // prior to re-analysis.
3487 if (build_options.only_c) unreachable;3474 if (build_options.only_c) unreachable;
3488 try mod.deleteDeclExports(decl_index);3475 mod.deleteUnitExports(AnalUnit.wrap(.{ .decl = decl_index }));
3489 }3476 }
34903477
3491 const sema_result: SemaDeclResult = blk: {3478 const sema_result: SemaDeclResult = blk: {
...@@ -3522,7 +3509,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3522,7 +3509,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3522 else => |e| {3509 else => |e| {
3523 decl.analysis = .sema_failure;3510 decl.analysis = .sema_failure;
3524 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);3511 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 }));
3526 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(3513 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
3527 mod.gpa,3514 mod.gpa,
3528 decl.navSrcLoc(mod).upgrade(mod),3515 decl.navSrcLoc(mod).upgrade(mod),
...@@ -3581,7 +3568,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In...@@ -3581,7 +3568,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
3581 // that's the case, we should remove this function from the binary.3568 // that's the case, we should remove this function from the binary.
3582 if (decl.val.ip_index != func_index) {3569 if (decl.val.ip_index != func_index) {
3583 try zcu.markDependeeOutdated(.{ .func_ies = func_index });3570 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 }));
3585 ip.remove(func_index);3572 ip.remove(func_index);
3586 @panic("TODO: remove orphaned function from binary");3573 @panic("TODO: remove orphaned function from binary");
3587 }3574 }
...@@ -3607,12 +3594,14 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In...@@ -3607,12 +3594,14 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
3607 .complete => {},3594 .complete => {},
3608 }3595 }
36093596
3610 const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index });3597 const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
3611 const was_outdated = zcu.outdated.swapRemove(func_as_depender) or3598 const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
3612 zcu.potentially_outdated.swapRemove(func_as_depender);3599 zcu.potentially_outdated.swapRemove(func_as_depender);
36133600
3614 if (was_outdated) {3601 if (was_outdated) {
3602 if (build_options.only_c) unreachable;
3615 _ = zcu.outdated_ready.swapRemove(func_as_depender);3603 _ = zcu.outdated_ready.swapRemove(func_as_depender);
3604 zcu.deleteUnitExports(AnalUnit.wrap(.{ .func = func_index }));
3616 }3605 }
36173606
3618 switch (func.analysis(ip).state) {3607 switch (func.analysis(ip).state) {
...@@ -3728,16 +3717,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In...@@ -3728,16 +3717,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
3728 .{@errorName(err)},3717 .{@errorName(err)},
3729 ));3718 ));
3730 func.analysis(ip).state = .codegen_failure;3719 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 }));
3732 },3721 },
3733 };3722 };
3734 } else if (zcu.llvm_object) |llvm_object| {3723 } else if (zcu.llvm_object) |llvm_object| {
3735 if (build_options.only_c) unreachable;3724 if (build_options.only_c) unreachable;
3736 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {3725 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
3737 error.OutOfMemory => return error.OutOfMemory,3726 error.OutOfMemory => return error.OutOfMemory,
3738 error.AnalysisFail => {
3739 func.analysis(ip).state = .codegen_failure;
3740 },
3741 };3727 };
3742 }3728 }
3743}3729}
...@@ -3773,7 +3759,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)...@@ -3773,7 +3759,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
37733759
3774 assert(decl.has_tv);3760 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 });
3777 const is_outdated = mod.outdated.contains(func_as_depender) or3763 const is_outdated = mod.outdated.contains(func_as_depender) or
3778 mod.potentially_outdated.contains(func_as_depender);3764 mod.potentially_outdated.contains(func_as_depender);
37793765
...@@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa...@@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
3857 if (zcu.comp.debug_incremental) {3843 if (zcu.comp.debug_incremental) {
3858 try ip.addDependency(3844 try ip.addDependency(
3859 gpa,3845 gpa,
3860 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),3846 AnalUnit.wrap(.{ .decl = decl_index }),
3861 .{ .src_hash = tracked_inst },3847 .{ .src_hash = tracked_inst },
3862 );3848 );
3863 }3849 }
...@@ -3906,7 +3892,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {...@@ -3906,7 +3892,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
39063892
3907 if (type_outdated) {3893 if (type_outdated) {
3908 // Invalidate the existing type, reusing the decl and namespace.3894 // 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().? }));
3910 zcu.intern_pool.remove(decl.val.toIntern());3896 zcu.intern_pool.remove(decl.val.toIntern());
3911 decl.val = undefined;3897 decl.val = undefined;
3912 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);3898 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
...@@ -4097,7 +4083,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -4097,7 +4083,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
4097 break :ip_index .none;4083 break :ip_index .none;
4098 };4084 };
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
4102 decl.analysis = .in_progress;4088 decl.analysis = .in_progress;
41034089
...@@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
4293 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);4279 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
4294 }4280 }
42954281
4282 try sema.flushExports();
4283
4296 return result;4284 return result;
4297}4285}
42984286
...@@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {...@@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
4323 // with a new Decl.4311 // with a new Decl.
4324 //4312 //
4325 // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.4313 // 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 }));
4327 zcu.intern_pool.remove(decl.val.toIntern());4315 zcu.intern_pool.remove(decl.val.toIntern());
4328 decl.analysis = .dependency_failure;4316 decl.analysis = .dependency_failure;
4329 return .{4317 return .{
...@@ -4949,63 +4937,44 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo...@@ -4949,63 +4937,44 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo
4949 }4937 }
4950}4938}
49514939
4952/// Delete all the Export objects that are caused by this Decl. Re-analysis of4940/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
4953/// this Decl will cause them to be re-created (or not).4941/// this `AnalUnit` will cause them to be re-created (or not).
4954fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {4942pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
4955 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;4943 const gpa = zcu.gpa;
49564944
4957 for (export_owners.items) |exp| {4945 const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
4958 switch (exp.exported) {4946 .{ kv.value, 1 }
4959 .decl_index => |exported_decl_index| {4947 else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
4960 if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {4948 .{ info.value.index, info.value.len }
4961 // Remove exports with owner_decl matching the regenerating decl.4949 else
4962 const list = export_list.items;4950 return;
4963 var i: usize = 0;4951
4964 var new_len = list.len;4952 const exports = zcu.all_exports.items[exports_base..][0..exports_len];
4965 while (i < new_len) {4953
4966 if (list[i].owner_decl == decl_index) {4954 // In an only-c build, we're guaranteed to never use incremental compilation, so there are
4967 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);4955 // guaranteed not to be any exports in the output file that need deleting (since we only call
4968 new_len -= 1;4956 // `updateExports` on flush).
4969 } else {4957 // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
4970 i += 1;4958 // within a single update.
4971 }4959 if (!build_options.only_c) {
4972 }4960 for (exports, exports_base..) |exp, export_idx| {
4973 export_list.shrinkAndFree(mod.gpa, new_len);4961 if (zcu.comp.bin_file) |lf| {
4974 if (new_len == 0) {4962 lf.deleteExport(exp.exported, exp.opts.name);
4975 assert(mod.decl_exports.swapRemove(exported_decl_index));4963 }
4976 }4964 if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
4977 }4965 failed_kv.value.destroy(gpa);
4978 },4966 }
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);
5005 }4967 }
5006 mod.gpa.destroy(exp);
5007 }4968 }
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 }
5009}4978}
50104979
5011pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air {4980pub 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...@@ -5026,7 +4995,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
5026 const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);4995 const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
5027 defer decl_prog_node.end();4996 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
5031 var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);5000 var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
5032 defer comptime_err_ret_trace.deinit();5001 defer comptime_err_ret_trace.deinit();
...@@ -5262,6 +5231,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -5262,6 +5231,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
5262 };5231 };
5263 }5232 }
52645233
5234 try sema.flushExports();
5235
5265 return .{5236 return .{
5266 .instructions = sema.air_instructions.toOwnedSlice(),5237 .instructions = sema.air_instructions.toOwnedSlice(),
5267 .extra = try sema.air_extra.toOwnedSlice(gpa),5238 .extra = try sema.air_extra.toOwnedSlice(gpa),
...@@ -5392,33 +5363,89 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {...@@ -5392,33 +5363,89 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
5392/// Called from `Compilation.update`, after everything is done, just before5363/// Called from `Compilation.update`, after everything is done, just before
5393/// reporting compile errors. In this function we emit exported symbol collision5364/// reporting compile errors. In this function we emit exported symbol collision
5394/// errors and communicate exported symbols to the linker backend.5365/// 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
5396 // Map symbol names to `Export` for name collision detection.5422 // Map symbol names to `Export` for name collision detection.
5397 var symbol_exports: SymbolExports = .{};5423 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| {
5401 const exported: Exported = .{ .decl_index = exported_decl };5427 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);
5403 }5429 }
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| {
5406 const exported: Exported = .{ .value = exported_value };5432 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);
5408 }5434 }
5409}5435}
54105436
5411const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);5437const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
54125438
5413fn processExportsInner(5439fn processExportsInner(
5414 zcu: *Zcu,5440 zcu: *Zcu,
5415 symbol_exports: *SymbolExports,5441 symbol_exports: *SymbolExports,
5416 exported: Exported,5442 exported: Exported,
5417 exports: []const *Export,5443 export_indices: []const u32,
5418) error{OutOfMemory}!void {5444) error{OutOfMemory}!void {
5419 const gpa = zcu.gpa;5445 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];
5422 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);5449 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
5423 if (gop.found_existing) {5450 if (gop.found_existing) {
5424 new_export.status = .failed_retryable;5451 new_export.status = .failed_retryable;
...@@ -5428,40 +5455,41 @@ fn processExportsInner(...@@ -5428,40 +5455,41 @@ fn processExportsInner(
5428 new_export.opts.name.fmt(&zcu.intern_pool),5455 new_export.opts.name.fmt(&zcu.intern_pool),
5429 });5456 });
5430 errdefer msg.destroy(gpa);5457 errdefer msg.destroy(gpa);
5431 const other_export = gop.value_ptr.*;5458 const other_export = zcu.all_exports.items[gop.value_ptr.*];
5432 const other_src_loc = other_export.getSrcLoc(zcu);5459 const other_src_loc = other_export.getSrcLoc(zcu);
5433 try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});5460 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);
5435 new_export.status = .failed;5462 new_export.status = .failed;
5436 } else {5463 } else {
5437 gop.value_ptr.* = new_export;5464 gop.value_ptr.* = export_idx;
5438 }5465 }
5439 }5466 }
5440 if (zcu.comp.bin_file) |lf| {5467 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));
5442 } else if (zcu.llvm_object) |llvm_object| {5469 } else if (zcu.llvm_object) |llvm_object| {
5443 if (build_options.only_c) unreachable;5470 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));
5445 }5472 }
5446}5473}
54475474
5448fn handleUpdateExports(5475fn handleUpdateExports(
5449 zcu: *Zcu,5476 zcu: *Zcu,
5450 exports: []const *Export,5477 export_indices: []const u32,
5451 result: link.File.UpdateExportsError!void,5478 result: link.File.UpdateExportsError!void,
5452) Allocator.Error!void {5479) Allocator.Error!void {
5453 const gpa = zcu.gpa;5480 const gpa = zcu.gpa;
5454 result catch |err| switch (err) {5481 result catch |err| switch (err) {
5455 error.OutOfMemory => return error.OutOfMemory,5482 error.OutOfMemory => return error.OutOfMemory,
5456 error.AnalysisFail => {5483 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];
5458 new_export.status = .failed_retryable;5486 new_export.status = .failed_retryable;
5459 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);5487 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
5460 const src_loc = new_export.getSrcLoc(zcu);5488 const src_loc = new_export.getSrcLoc(zcu);
5461 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{5489 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
5462 @errorName(err),5490 @errorName(err),
5463 });5491 });
5464 zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);5492 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
5465 },5493 },
5466 };5494 };
5467}5495}
...@@ -5627,16 +5655,13 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {...@@ -5627,16 +5655,13 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
5627 .{@errorName(err)},5655 .{@errorName(err)},
5628 ));5656 ));
5629 decl.analysis = .codegen_failure;5657 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 }));
5631 },5659 },
5632 };5660 };
5633 } else if (zcu.llvm_object) |llvm_object| {5661 } else if (zcu.llvm_object) |llvm_object| {
5634 if (build_options.only_c) unreachable;5662 if (build_options.only_c) unreachable;
5635 llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {5663 llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
5636 error.OutOfMemory => return error.OutOfMemory,5664 error.OutOfMemory => return error.OutOfMemory,
5637 error.AnalysisFail => {
5638 decl.analysis = .codegen_failure;
5639 },
5640 };5665 };
5641 }5666 }
5642}5667}
...@@ -5684,14 +5709,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u...@@ -5684,14 +5709,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
5684 }5709 }
5685}5710}
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
5695pub const Feature = enum {5712pub const Feature = enum {
5696 panic_fn,5713 panic_fn,
5697 panic_unwrap_error,5714 panic_unwrap_error,
src/codegen/c.zig+2
...@@ -3081,6 +3081,8 @@ pub fn genDeclValue(...@@ -3081,6 +3081,8 @@ pub fn genDeclValue(
3081}3081}
30823082
3083pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {3083pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
3084 if (true) @panic("TODO jacobly");
3085
3084 const tracy = trace(@src());3086 const tracy = trace(@src());
3085 defer tracy.end();3087 defer tracy.end();
30863088
src/codegen/llvm.zig+109-154
...@@ -848,10 +848,6 @@ pub const Object = struct {...@@ -848,10 +848,6 @@ pub const Object = struct {
848 /// Note that the values are not added until `emit`, when all errors in848 /// Note that the values are not added until `emit`, when all errors in
849 /// the compilation are known.849 /// the compilation are known.
850 error_name_table: Builder.Variable.Index,850 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
856 /// Memoizes a null `?usize` value.852 /// Memoizes a null `?usize` value.
857 null_opt_usize: Builder.Constant,853 null_opt_usize: Builder.Constant,
...@@ -1011,7 +1007,6 @@ pub const Object = struct {...@@ -1011,7 +1007,6 @@ pub const Object = struct {
1011 .named_enum_map = .{},1007 .named_enum_map = .{},
1012 .type_map = .{},1008 .type_map = .{},
1013 .error_name_table = .none,1009 .error_name_table = .none,
1014 .extern_collisions = .{},
1015 .null_opt_usize = .no_init,1010 .null_opt_usize = .no_init,
1016 .struct_field_map = .{},1011 .struct_field_map = .{},
1017 };1012 };
...@@ -1029,7 +1024,6 @@ pub const Object = struct {...@@ -1029,7 +1024,6 @@ pub const Object = struct {
1029 self.anon_decl_map.deinit(gpa);1024 self.anon_decl_map.deinit(gpa);
1030 self.named_enum_map.deinit(gpa);1025 self.named_enum_map.deinit(gpa);
1031 self.type_map.deinit(gpa);1026 self.type_map.deinit(gpa);
1032 self.extern_collisions.deinit(gpa);
1033 self.builder.deinit();1027 self.builder.deinit();
1034 self.struct_field_map.deinit(gpa);1028 self.struct_field_map.deinit(gpa);
1035 self.* = undefined;1029 self.* = undefined;
...@@ -1121,61 +1115,6 @@ pub const Object = struct {...@@ -1121,61 +1115,6 @@ pub const Object = struct {
1121 try object.builder.finishModuleAsm();1115 try object.builder.finishModuleAsm();
1122 }1116 }
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
1179 pub const EmitOptions = struct {1118 pub const EmitOptions = struct {
1180 pre_ir_path: ?[]const u8,1119 pre_ir_path: ?[]const u8,
1181 pre_bc_path: ?[]const u8,1120 pre_bc_path: ?[]const u8,
...@@ -1193,7 +1132,6 @@ pub const Object = struct {...@@ -1193,7 +1132,6 @@ pub const Object = struct {
11931132
1194 pub fn emit(self: *Object, options: EmitOptions) !void {1133 pub fn emit(self: *Object, options: EmitOptions) !void {
1195 {1134 {
1196 try self.resolveExportExternCollisions();
1197 try self.genErrorNameTable();1135 try self.genErrorNameTable();
1198 try self.genCmpLtErrorsLenFunction();1136 try self.genCmpLtErrorsLenFunction();
1199 try self.genModuleLevelAssembly();1137 try self.genModuleLevelAssembly();
...@@ -1698,8 +1636,7 @@ pub const Object = struct {...@@ -1698,8 +1636,7 @@ pub const Object = struct {
1698 const file = try o.getDebugFile(namespace.file_scope);1636 const file = try o.getDebugFile(namespace.file_scope);
16991637
1700 const line_number = decl.navSrcLine(zcu) + 1;1638 const line_number = decl.navSrcLine(zcu) + 1;
1701 const is_internal_linkage = decl.val.getExternFunc(zcu) == null and1639 const is_internal_linkage = decl.val.getExternFunc(zcu) == null;
1702 !zcu.decl_exports.contains(decl_index);
1703 const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));1640 const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));
17041641
1705 const subprogram = try o.builder.debugSubprogram(1642 const subprogram = try o.builder.debugSubprogram(
...@@ -1760,8 +1697,6 @@ pub const Object = struct {...@@ -1760,8 +1697,6 @@ pub const Object = struct {
1760 };1697 };
17611698
1762 try fg.wip.finish();1699 try fg.wip.finish();
1763
1764 try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
1765 }1700 }
17661701
1767 pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {1702 pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
...@@ -1781,66 +1716,25 @@ pub const Object = struct {...@@ -1781,66 +1716,25 @@ pub const Object = struct {
1781 },1716 },
1782 else => |e| return e,1717 else => |e| return e,
1783 };1718 };
1784 try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
1785 }1719 }
17861720
1787 pub fn updateExports(1721 pub fn updateExports(
1788 self: *Object,1722 self: *Object,
1789 mod: *Module,1723 mod: *Module,
1790 exported: Module.Exported,1724 exported: Module.Exported,
1791 exports: []const *Module.Export,1725 export_indices: []const u32,
1792 ) link.File.UpdateExportsError!void {1726 ) link.File.UpdateExportsError!void {
1793 const decl_index = switch (exported) {1727 const decl_index = switch (exported) {
1794 .decl_index => |i| i,1728 .decl_index => |i| i,
1795 .value => |val| return updateExportedValue(self, mod, val, exports),1729 .value => |val| return updateExportedValue(self, mod, val, export_indices),
1796 };1730 };
1797 const gpa = mod.gpa;
1798 const ip = &mod.intern_pool;1731 const ip = &mod.intern_pool;
1799 // If the module does not already have the function, we ignore this function call1732 const global_index = self.decl_map.get(decl_index).?;
1800 // because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
1801 const global_index = self.decl_map.get(decl_index) orelse return;
1802 const decl = mod.declPtr(decl_index);1733 const decl = mod.declPtr(decl_index);
1803 const comp = mod.comp;1734 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| {1736 if (export_indices.len != 0) {
1817 if (other_global != global_index) {1737 return updateExportedGlobal(self, mod, global_index, export_indices);
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);
1844 } else {1738 } else {
1845 const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));1739 const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
1846 try global_index.rename(fqn, &self.builder);1740 try global_index.rename(fqn, &self.builder);
...@@ -1848,17 +1742,6 @@ pub const Object = struct {...@@ -1848,17 +1742,6 @@ pub const Object = struct {
1848 if (comp.config.dll_export_fns)1742 if (comp.config.dll_export_fns)
1849 global_index.setDllStorageClass(.default, &self.builder);1743 global_index.setDllStorageClass(.default, &self.builder);
1850 global_index.setUnnamedAddr(.unnamed_addr, &self.builder);1744 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 }
1862 }1745 }
1863 }1746 }
18641747
...@@ -1866,11 +1749,11 @@ pub const Object = struct {...@@ -1866,11 +1749,11 @@ pub const Object = struct {
1866 o: *Object,1749 o: *Object,
1867 mod: *Module,1750 mod: *Module,
1868 exported_value: InternPool.Index,1751 exported_value: InternPool.Index,
1869 exports: []const *Module.Export,1752 export_indices: []const u32,
1870 ) link.File.UpdateExportsError!void {1753 ) link.File.UpdateExportsError!void {
1871 const gpa = mod.gpa;1754 const gpa = mod.gpa;
1872 const ip = &mod.intern_pool;1755 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));
1874 const global_index = i: {1757 const global_index = i: {
1875 const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);1758 const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
1876 if (gop.found_existing) {1759 if (gop.found_existing) {
...@@ -1894,32 +1777,57 @@ pub const Object = struct {...@@ -1894,32 +1777,57 @@ pub const Object = struct {
1894 try variable_index.setInitializer(init_val, &o.builder);1777 try variable_index.setInitializer(init_val, &o.builder);
1895 break :i global_index;1778 break :i global_index;
1896 };1779 };
1897 return updateExportedGlobal(o, mod, global_index, exports);1780 return updateExportedGlobal(o, mod, global_index, export_indices);
1898 }1781 }
18991782
1900 fn updateExportedGlobal(1783 fn updateExportedGlobal(
1901 o: *Object,1784 o: *Object,
1902 mod: *Module,1785 mod: *Module,
1903 global_index: Builder.Global.Index,1786 global_index: Builder.Global.Index,
1904 exports: []const *Module.Export,1787 export_indices: []const u32,
1905 ) link.File.UpdateExportsError!void {1788 ) link.File.UpdateExportsError!void {
1906 const comp = mod.comp;1789 const comp = mod.comp;
1907 const ip = &mod.intern_pool;1790 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
1908 global_index.setUnnamedAddr(.default, &o.builder);1816 global_index.setUnnamedAddr(.default, &o.builder);
1909 if (comp.config.dll_export_fns)1817 if (comp.config.dll_export_fns)
1910 global_index.setDllStorageClass(.dllexport, &o.builder);1818 global_index.setDllStorageClass(.dllexport, &o.builder);
1911 global_index.setLinkage(switch (exports[0].opts.linkage) {1819 global_index.setLinkage(switch (first_export.opts.linkage) {
1912 .internal => unreachable,1820 .internal => unreachable,
1913 .strong => .external,1821 .strong => .external,
1914 .weak => .weak_odr,1822 .weak => .weak_odr,
1915 .link_once => .linkonce_odr,1823 .link_once => .linkonce_odr,
1916 }, &o.builder);1824 }, &o.builder);
1917 global_index.setVisibility(switch (exports[0].opts.visibility) {1825 global_index.setVisibility(switch (first_export.opts.visibility) {
1918 .default => .default,1826 .default => .default,
1919 .hidden => .hidden,1827 .hidden => .hidden,
1920 .protected => .protected,1828 .protected => .protected,
1921 }, &o.builder);1829 }, &o.builder);
1922 if (exports[0].opts.section.toSlice(ip)) |section|1830 if (first_export.opts.section.toSlice(ip)) |section|
1923 switch (global_index.ptrConst(&o.builder).kind) {1831 switch (global_index.ptrConst(&o.builder).kind) {
1924 .variable => |impl_index| impl_index.setSection(1832 .variable => |impl_index| impl_index.setSection(
1925 try o.builder.string(section),1833 try o.builder.string(section),
...@@ -1936,7 +1844,8 @@ pub const Object = struct {...@@ -1936,7 +1844,8 @@ pub const Object = struct {
1936 // The planned solution to this is https://github.com/ziglang/zig/issues/132651844 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
1937 // Until then we iterate over existing aliases and make them point1845 // Until then we iterate over existing aliases and make them point
1938 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.1846 // 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];
1940 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));1849 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
1941 if (o.builder.getGlobal(exp_name)) |global| {1850 if (o.builder.getGlobal(exp_name)) |global| {
1942 switch (global.ptrConst(&o.builder).kind) {1851 switch (global.ptrConst(&o.builder).kind) {
...@@ -1944,7 +1853,13 @@ pub const Object = struct {...@@ -1944,7 +1853,13 @@ pub const Object = struct {
1944 alias.setAliasee(global_index.toConst(), &o.builder);1853 alias.setAliasee(global_index.toConst(), &o.builder);
1945 continue;1854 continue;
1946 },1855 },
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 },
1948 .replaced => unreachable,1863 .replaced => unreachable,
1949 }1864 }
1950 }1865 }
...@@ -4762,36 +4677,77 @@ pub const DeclGen = struct {...@@ -4762,36 +4677,77 @@ pub const DeclGen = struct {
4762 else => try o.lowerValue(init_val),4677 else => try o.lowerValue(init_val),
4763 }, &o.builder);4678 }, &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
4765 const line_number = decl.navSrcLine(zcu) + 1;4689 const line_number = decl.navSrcLine(zcu) + 1;
4766 const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
47674690
4768 const namespace = zcu.namespacePtr(decl.src_namespace);4691 const namespace = zcu.namespacePtr(decl.src_namespace);
4769 const owner_mod = namespace.file_scope.mod;4692 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(4710 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
4776 try o.builder.metadataString(decl.name.toSlice(ip)), // Name4711 debug_global_var,
4777 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name4712 debug_expression,
4778 debug_file, // File4713 );
4779 debug_file, // Scope
4780 line_number,
4781 try o.lowerDebugType(decl.typeOf(zcu)),
4782 variable_index,
4783 .{ .local = is_internal_linkage },
4784 );
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(4720 if (decl.isExtern(zcu)) {
4789 debug_global_var,4721 const global_index = o.decl_map.get(decl_index).?;
4790 debug_expression,
4791 );
47924722
4793 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);4723 const decl_name = decl_name: {
4794 try o.debug_globals.append(o.gpa, debug_global_var_expression);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 }
4795 }4751 }
4796 }4752 }
4797};4753};
...@@ -5193,7 +5149,6 @@ pub const FuncGen = struct {...@@ -5193,7 +5149,6 @@ pub const FuncGen = struct {
51935149
5194 const fqn = try decl.fullyQualifiedName(zcu);5150 const fqn = try decl.fullyQualifiedName(zcu);
51955151
5196 const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
5197 const fn_ty = try zcu.funcType(.{5152 const fn_ty = try zcu.funcType(.{
5198 .param_types = &.{},5153 .param_types = &.{},
5199 .return_type = .void_type,5154 .return_type = .void_type,
...@@ -5211,7 +5166,7 @@ pub const FuncGen = struct {...@@ -5211,7 +5166,7 @@ pub const FuncGen = struct {
5211 .sp_flags = .{5166 .sp_flags = .{
5212 .Optimized = owner_mod.optimize_mode != .Debug,5167 .Optimized = owner_mod.optimize_mode != .Debug,
5213 .Definition = true,5168 .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!
5215 },5170 },
5216 },5171 },
5217 o.debug_compile_unit,5172 o.debug_compile_unit,
src/link.zig+6-6
...@@ -606,12 +606,12 @@ pub const File = struct {...@@ -606,12 +606,12 @@ pub const File = struct {
606 base: *File,606 base: *File,
607 module: *Module,607 module: *Module,
608 exported: Module.Exported,608 exported: Module.Exported,
609 exports: []const *Module.Export,609 export_indices: []const u32,
610 ) UpdateExportsError!void {610 ) UpdateExportsError!void {
611 switch (base.tag) {611 switch (base.tag) {
612 inline else => |tag| {612 inline else => |tag| {
613 if (tag != .c and build_options.only_c) unreachable;613 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);
615 },615 },
616 }616 }
617 }617 }
...@@ -671,11 +671,11 @@ pub const File = struct {...@@ -671,11 +671,11 @@ pub const File = struct {
671 }671 }
672 }672 }
673673
674 pub fn deleteDeclExport(674 pub fn deleteExport(
675 base: *File,675 base: *File,
676 decl_index: InternPool.DeclIndex,676 exported: Zcu.Exported,
677 name: InternPool.NullTerminatedString,677 name: InternPool.NullTerminatedString,
678 ) !void {678 ) void {
679 if (build_options.only_c) @compileError("unreachable");679 if (build_options.only_c) @compileError("unreachable");
680 switch (base.tag) {680 switch (base.tag) {
681 .plan9,681 .plan9,
...@@ -685,7 +685,7 @@ pub const File = struct {...@@ -685,7 +685,7 @@ pub const File = struct {
685 => {},685 => {},
686686
687 inline else => |tag| {687 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);
689 },689 },
690 }690 }
691 }691 }
src/link/C.zig+22-7
...@@ -183,6 +183,8 @@ pub fn updateFunc(...@@ -183,6 +183,8 @@ pub fn updateFunc(
183 air: Air,183 air: Air,
184 liveness: Liveness,184 liveness: Liveness,
185) !void {185) !void {
186 if (true) @panic("TODO jacobly");
187
186 const gpa = self.base.comp.gpa;188 const gpa = self.base.comp.gpa;
187189
188 const func = zcu.funcInfo(func_index);190 const func = zcu.funcInfo(func_index);
...@@ -250,6 +252,8 @@ pub fn updateFunc(...@@ -250,6 +252,8 @@ pub fn updateFunc(
250}252}
251253
252fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {254fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
255 if (true) @panic("TODO jacobly");
256
253 const gpa = self.base.comp.gpa;257 const gpa = self.base.comp.gpa;
254 const anon_decl = self.anon_decls.keys()[i];258 const anon_decl = self.anon_decls.keys()[i];
255259
...@@ -306,6 +310,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {...@@ -306,6 +310,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
306}310}
307311
308pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {312pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
313 if (true) @panic("TODO jacobly");
314
309 const tracy = trace(@src());315 const tracy = trace(@src());
310 defer tracy.end();316 defer tracy.end();
311317
...@@ -390,6 +396,8 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {...@@ -390,6 +396,8 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
390}396}
391397
392pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {398pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
399 if (true) @panic("TODO jacobly");
400
393 _ = arena; // Has the same lifetime as the call to Compilation.update.401 _ = arena; // Has the same lifetime as the call to Compilation.update.
394402
395 const tracy = trace(@src());403 const tracy = trace(@src());
...@@ -451,9 +459,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo...@@ -451,9 +459,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
451 {459 {
452 var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};460 var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
453 defer export_names.deinit(gpa);461 defer export_names.deinit(gpa);
454 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.decl_exports.entries.len));462 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
455 for (zcu.decl_exports.values()) |exports| for (exports.items) |@"export"|463 for (zcu.single_exports.values()) |export_idx| {
456 try export_names.put(gpa, @"export".opts.name, {});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
458 for (self.anon_decls.values()) |*decl_block| {473 for (self.anon_decls.values()) |*decl_block| {
459 try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);474 try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);
...@@ -781,10 +796,10 @@ pub fn updateExports(...@@ -781,10 +796,10 @@ pub fn updateExports(
781 self: *C,796 self: *C,
782 zcu: *Zcu,797 zcu: *Zcu,
783 exported: Zcu.Exported,798 exported: Zcu.Exported,
784 exports: []const *Zcu.Export,799 export_indices: []const u32,
785) !void {800) !void {
786 _ = exports;
787 _ = exported;
788 _ = zcu;
789 _ = self;801 _ = self;
802 _ = zcu;
803 _ = exported;
804 _ = export_indices;
790}805}
src/link/Coff.zig+18-17
...@@ -1162,9 +1162,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:...@@ -1162,9 +1162,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
11621162
1163 try self.updateDeclCode(decl_index, code, .FUNCTION);1163 try self.updateDeclCode(decl_index, code, .FUNCTION);
11641164
1165 // Since we updated the vaddr and the size, each corresponding export1165 // Exports will be updated by `Zcu.processExports` after the update.
1166 // symbol also needs to be updated.
1167 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1168}1166}
11691167
1170pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {1168pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {
...@@ -1286,9 +1284,7 @@ pub fn updateDecl(...@@ -1286,9 +1284,7 @@ pub fn updateDecl(
12861284
1287 try self.updateDeclCode(decl_index, code, .NULL);1285 try self.updateDeclCode(decl_index, code, .NULL);
12881286
1289 // Since we updated the vaddr and the size, each corresponding export1287 // Exports will be updated by `Zcu.processExports` after the update.
1290 // symbol also needs to be updated.
1291 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1292}1288}
12931289
1294fn updateLazySymbolAtom(1290fn updateLazySymbolAtom(
...@@ -1509,7 +1505,7 @@ pub fn updateExports(...@@ -1509,7 +1505,7 @@ pub fn updateExports(
1509 self: *Coff,1505 self: *Coff,
1510 mod: *Module,1506 mod: *Module,
1511 exported: Module.Exported,1507 exported: Module.Exported,
1512 exports: []const *Module.Export,1508 export_indices: []const u32,
1513) link.File.UpdateExportsError!void {1509) link.File.UpdateExportsError!void {
1514 if (build_options.skip_non_native and builtin.object_format != .coff) {1510 if (build_options.skip_non_native and builtin.object_format != .coff) {
1515 @panic("Attempted to compile for object format that was disabled by build configuration");1511 @panic("Attempted to compile for object format that was disabled by build configuration");
...@@ -1522,7 +1518,8 @@ pub fn updateExports(...@@ -1522,7 +1518,8 @@ pub fn updateExports(
1522 if (comp.config.use_llvm) {1518 if (comp.config.use_llvm) {
1523 // Even in the case of LLVM, we need to notice certain exported symbols in order to1519 // Even in the case of LLVM, we need to notice certain exported symbols in order to
1524 // detect the default subsystem.1520 // detect the default subsystem.
1525 for (exports) |exp| {1521 for (export_indices) |export_idx| {
1522 const exp = mod.all_exports.items[export_idx];
1526 const exported_decl_index = switch (exp.exported) {1523 const exported_decl_index = switch (exp.exported) {
1527 .decl_index => |i| i,1524 .decl_index => |i| i,
1528 .value => continue,1525 .value => continue,
...@@ -1552,7 +1549,7 @@ pub fn updateExports(...@@ -1552,7 +1549,7 @@ pub fn updateExports(
1552 }1549 }
1553 }1550 }
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
1557 const gpa = comp.gpa;1554 const gpa = comp.gpa;
15581555
...@@ -1562,7 +1559,7 @@ pub fn updateExports(...@@ -1562,7 +1559,7 @@ pub fn updateExports(
1562 break :blk self.decls.getPtr(decl_index).?;1559 break :blk self.decls.getPtr(decl_index).?;
1563 },1560 },
1564 .value => |value| self.anon_decls.getPtr(value) orelse blk: {1561 .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]];
1566 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));1563 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
1567 switch (res) {1564 switch (res) {
1568 .ok => {},1565 .ok => {},
...@@ -1570,7 +1567,7 @@ pub fn updateExports(...@@ -1570,7 +1567,7 @@ pub fn updateExports(
1570 // TODO maybe it's enough to return an error here and let Module.processExportsInner1567 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1571 // handle the error?1568 // handle the error?
1572 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1569 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);
1574 return;1571 return;
1575 },1572 },
1576 }1573 }
...@@ -1580,12 +1577,13 @@ pub fn updateExports(...@@ -1580,12 +1577,13 @@ pub fn updateExports(
1580 const atom_index = metadata.atom;1577 const atom_index = metadata.atom;
1581 const atom = self.getAtom(atom_index);1578 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];
1584 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});1582 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
15851583
1586 if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {1584 if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {
1587 if (!mem.eql(u8, section_name, ".text")) {1585 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(
1589 gpa,1587 gpa,
1590 exp.getSrcLoc(mod),1588 exp.getSrcLoc(mod),
1591 "Unimplemented: ExportOptions.section",1589 "Unimplemented: ExportOptions.section",
...@@ -1596,7 +1594,7 @@ pub fn updateExports(...@@ -1596,7 +1594,7 @@ pub fn updateExports(
1596 }1594 }
15971595
1598 if (exp.opts.linkage == .link_once) {1596 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(
1600 gpa,1598 gpa,
1601 exp.getSrcLoc(mod),1599 exp.getSrcLoc(mod),
1602 "Unimplemented: GlobalLinkage.link_once",1600 "Unimplemented: GlobalLinkage.link_once",
...@@ -1641,13 +1639,16 @@ pub fn updateExports(...@@ -1641,13 +1639,16 @@ pub fn updateExports(
1641 }1639 }
1642}1640}
16431641
1644pub fn deleteDeclExport(1642pub fn deleteExport(
1645 self: *Coff,1643 self: *Coff,
1646 decl_index: InternPool.DeclIndex,1644 exported: Zcu.Exported,
1647 name: InternPool.NullTerminatedString,1645 name: InternPool.NullTerminatedString,
1648) void {1646) void {
1649 if (self.llvm_object) |_| return;1647 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 };
1651 const mod = self.base.comp.module.?;1652 const mod = self.base.comp.module.?;
1652 const name_slice = name.toSlice(&mod.intern_pool);1653 const name_slice = name.toSlice(&mod.intern_pool);
1653 const sym_index = metadata.getExportPtr(self, name_slice) orelse return;1654 const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
src/link/Elf.zig+6-6
...@@ -3011,13 +3011,13 @@ pub fn updateExports(...@@ -3011,13 +3011,13 @@ pub fn updateExports(
3011 self: *Elf,3011 self: *Elf,
3012 mod: *Module,3012 mod: *Module,
3013 exported: Module.Exported,3013 exported: Module.Exported,
3014 exports: []const *Module.Export,3014 export_indices: []const u32,
3015) link.File.UpdateExportsError!void {3015) link.File.UpdateExportsError!void {
3016 if (build_options.skip_non_native and builtin.object_format != .elf) {3016 if (build_options.skip_non_native and builtin.object_format != .elf) {
3017 @panic("Attempted to compile for object format that was disabled by build configuration");3017 @panic("Attempted to compile for object format that was disabled by build configuration");
3018 }3018 }
3019 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(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, exports);3020 return self.zigObjectPtr().?.updateExports(self, mod, exported, export_indices);
3021}3021}
30223022
3023pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.DeclIndex) !void {3023pub 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...@@ -3025,13 +3025,13 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.Dec
3025 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);3025 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
3026}3026}
30273027
3028pub fn deleteDeclExport(3028pub fn deleteExport(
3029 self: *Elf,3029 self: *Elf,
3030 decl_index: InternPool.DeclIndex,3030 exported: Zcu.Exported,
3031 name: InternPool.NullTerminatedString,3031 name: InternPool.NullTerminatedString,
3032) void {3032) void {
3033 if (self.llvm_object) |_| return;3033 if (self.llvm_object) |_| return;
3034 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);3034 return self.zigObjectPtr().?.deleteExport(self, exported, name);
3035}3035}
30363036
3037fn addLinkerDefinedSymbols(self: *Elf) !void {3037fn addLinkerDefinedSymbols(self: *Elf) !void {
src/link/Elf/ZigObject.zig+15-15
...@@ -1115,9 +1115,7 @@ pub fn updateFunc(...@@ -1115,9 +1115,7 @@ pub fn updateFunc(
1115 );1115 );
1116 }1116 }
11171117
1118 // Since we updated the vaddr and the size, each corresponding export1118 // Exports will be updated by `Zcu.processExports` after the update.
1119 // symbol also needs to be updated.
1120 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1121}1119}
11221120
1123pub fn updateDecl(1121pub fn updateDecl(
...@@ -1194,9 +1192,7 @@ pub fn updateDecl(...@@ -1194,9 +1192,7 @@ pub fn updateDecl(
1194 );1192 );
1195 }1193 }
11961194
1197 // Since we updated the vaddr and the size, each corresponding export1195 // Exports will be updated by `Zcu.processExports` after the update.
1198 // symbol also needs to be updated.
1199 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1200}1196}
12011197
1202fn updateLazySymbol(1198fn updateLazySymbol(
...@@ -1386,7 +1382,7 @@ pub fn updateExports(...@@ -1386,7 +1382,7 @@ pub fn updateExports(
1386 elf_file: *Elf,1382 elf_file: *Elf,
1387 mod: *Module,1383 mod: *Module,
1388 exported: Module.Exported,1384 exported: Module.Exported,
1389 exports: []const *Module.Export,1385 export_indices: []const u32,
1390) link.File.UpdateExportsError!void {1386) link.File.UpdateExportsError!void {
1391 const tracy = trace(@src());1387 const tracy = trace(@src());
1392 defer tracy.end();1388 defer tracy.end();
...@@ -1398,7 +1394,7 @@ pub fn updateExports(...@@ -1398,7 +1394,7 @@ pub fn updateExports(
1398 break :blk self.decls.getPtr(decl_index).?;1394 break :blk self.decls.getPtr(decl_index).?;
1399 },1395 },
1400 .value => |value| self.anon_decls.getPtr(value) orelse blk: {1396 .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]];
1402 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));1398 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
1403 switch (res) {1399 switch (res) {
1404 .ok => {},1400 .ok => {},
...@@ -1406,7 +1402,7 @@ pub fn updateExports(...@@ -1406,7 +1402,7 @@ pub fn updateExports(
1406 // TODO maybe it's enough to return an error here and let Module.processExportsInner1402 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1407 // handle the error?1403 // handle the error?
1408 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1404 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);
1410 return;1406 return;
1411 },1407 },
1412 }1408 }
...@@ -1418,11 +1414,12 @@ pub fn updateExports(...@@ -1418,11 +1414,12 @@ pub fn updateExports(
1418 const esym = self.local_esyms.items(.elf_sym)[esym_index];1414 const esym = self.local_esyms.items(.elf_sym)[esym_index];
1419 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];1415 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];
1422 if (exp.opts.section.unwrap()) |section_name| {1419 if (exp.opts.section.unwrap()) |section_name| {
1423 if (!section_name.eqlSlice(".text", &mod.intern_pool)) {1420 if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
1424 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1421 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(
1426 gpa,1423 gpa,
1427 exp.getSrcLoc(mod),1424 exp.getSrcLoc(mod),
1428 "Unimplemented: ExportOptions.section",1425 "Unimplemented: ExportOptions.section",
...@@ -1437,7 +1434,7 @@ pub fn updateExports(...@@ -1437,7 +1434,7 @@ pub fn updateExports(
1437 .weak => elf.STB_WEAK,1434 .weak => elf.STB_WEAK,
1438 .link_once => {1435 .link_once => {
1439 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1436 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(
1441 gpa,1438 gpa,
1442 exp.getSrcLoc(mod),1439 exp.getSrcLoc(mod),
1443 "Unimplemented: GlobalLinkage.LinkOnce",1440 "Unimplemented: GlobalLinkage.LinkOnce",
...@@ -1487,13 +1484,16 @@ pub fn updateDeclLineNumber(...@@ -1487,13 +1484,16 @@ pub fn updateDeclLineNumber(
1487 }1484 }
1488}1485}
14891486
1490pub fn deleteDeclExport(1487pub fn deleteExport(
1491 self: *ZigObject,1488 self: *ZigObject,
1492 elf_file: *Elf,1489 elf_file: *Elf,
1493 decl_index: InternPool.DeclIndex,1490 exported: Zcu.Exported,
1494 name: InternPool.NullTerminatedString,1491 name: InternPool.NullTerminatedString,
1495) void {1492) 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 };
1497 const mod = elf_file.base.comp.module.?;1497 const mod = elf_file.base.comp.module.?;
1498 const exp_name = name.toSlice(&mod.intern_pool);1498 const exp_name = name.toSlice(&mod.intern_pool);
1499 const esym_index = metadata.@"export"(self, exp_name) orelse return;1499 const esym_index = metadata.@"export"(self, exp_name) orelse return;
src/link/MachO.zig+7-7
...@@ -3196,22 +3196,22 @@ pub fn updateExports(...@@ -3196,22 +3196,22 @@ pub fn updateExports(
3196 self: *MachO,3196 self: *MachO,
3197 mod: *Module,3197 mod: *Module,
3198 exported: Module.Exported,3198 exported: Module.Exported,
3199 exports: []const *Module.Export,3199 export_indices: []const u32,
3200) link.File.UpdateExportsError!void {3200) link.File.UpdateExportsError!void {
3201 if (build_options.skip_non_native and builtin.object_format != .macho) {3201 if (build_options.skip_non_native and builtin.object_format != .macho) {
3202 @panic("Attempted to compile for object format that was disabled by build configuration");3202 @panic("Attempted to compile for object format that was disabled by build configuration");
3203 }3203 }
3204 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(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, exports);3205 return self.getZigObject().?.updateExports(self, mod, exported, export_indices);
3206}3206}
32073207
3208pub fn deleteDeclExport(3208pub fn deleteExport(
3209 self: *MachO,3209 self: *MachO,
3210 decl_index: InternPool.DeclIndex,3210 exported: Zcu.Exported,
3211 name: InternPool.NullTerminatedString,3211 name: InternPool.NullTerminatedString,
3212) Allocator.Error!void {3212) void {
3213 if (self.llvm_object) |_| return;3213 if (self.llvm_object) |_| return;
3214 return self.getZigObject().?.deleteDeclExport(self, decl_index, name);3214 return self.getZigObject().?.deleteExport(self, exported, name);
3215}3215}
32163216
3217pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {3217pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
src/link/MachO/ZigObject.zig+15-15
...@@ -713,9 +713,7 @@ pub fn updateFunc(...@@ -713,9 +713,7 @@ pub fn updateFunc(
713 );713 );
714 }714 }
715715
716 // Since we updated the vaddr and the size, each corresponding export716 // Exports will be updated by `Zcu.processExports` after the update.
717 // symbol also needs to be updated.
718 return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
719}717}
720718
721pub fn updateDecl(719pub fn updateDecl(
...@@ -790,9 +788,7 @@ pub fn updateDecl(...@@ -790,9 +788,7 @@ pub fn updateDecl(
790 );788 );
791 }789 }
792790
793 // Since we updated the vaddr and the size, each corresponding export symbol also791 // Exports will be updated by `Zcu.processExports` after the update.
794 // needs to be updated.
795 try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
796}792}
797793
798fn updateDeclCode(794fn updateDeclCode(
...@@ -1187,7 +1183,7 @@ pub fn updateExports(...@@ -1187,7 +1183,7 @@ pub fn updateExports(
1187 macho_file: *MachO,1183 macho_file: *MachO,
1188 mod: *Module,1184 mod: *Module,
1189 exported: Module.Exported,1185 exported: Module.Exported,
1190 exports: []const *Module.Export,1186 export_indices: []const u32,
1191) link.File.UpdateExportsError!void {1187) link.File.UpdateExportsError!void {
1192 const tracy = trace(@src());1188 const tracy = trace(@src());
1193 defer tracy.end();1189 defer tracy.end();
...@@ -1199,7 +1195,7 @@ pub fn updateExports(...@@ -1199,7 +1195,7 @@ pub fn updateExports(
1199 break :blk self.decls.getPtr(decl_index).?;1195 break :blk self.decls.getPtr(decl_index).?;
1200 },1196 },
1201 .value => |value| self.anon_decls.getPtr(value) orelse blk: {1197 .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]];
1203 const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));1199 const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));
1204 switch (res) {1200 switch (res) {
1205 .ok => {},1201 .ok => {},
...@@ -1207,7 +1203,7 @@ pub fn updateExports(...@@ -1207,7 +1203,7 @@ pub fn updateExports(
1207 // TODO maybe it's enough to return an error here and let Module.processExportsInner1203 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1208 // handle the error?1204 // handle the error?
1209 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1205 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);
1211 return;1207 return;
1212 },1208 },
1213 }1209 }
...@@ -1218,11 +1214,12 @@ pub fn updateExports(...@@ -1218,11 +1214,12 @@ pub fn updateExports(
1218 const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;1214 const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
1219 const nlist = self.symtab.items(.nlist)[nlist_idx];1215 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];
1222 if (exp.opts.section.unwrap()) |section_name| {1219 if (exp.opts.section.unwrap()) |section_name| {
1223 if (!section_name.eqlSlice("__text", &mod.intern_pool)) {1220 if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
1224 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);1221 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(
1226 gpa,1223 gpa,
1227 exp.getSrcLoc(mod),1224 exp.getSrcLoc(mod),
1228 "Unimplemented: ExportOptions.section",1225 "Unimplemented: ExportOptions.section",
...@@ -1232,7 +1229,7 @@ pub fn updateExports(...@@ -1232,7 +1229,7 @@ pub fn updateExports(
1232 }1229 }
1233 }1230 }
1234 if (exp.opts.linkage == .link_once) {1231 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(
1236 gpa,1233 gpa,
1237 exp.getSrcLoc(mod),1234 exp.getSrcLoc(mod),
1238 "Unimplemented: GlobalLinkage.link_once",1235 "Unimplemented: GlobalLinkage.link_once",
...@@ -1364,15 +1361,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo...@@ -1364,15 +1361,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo
1364 }1361 }
1365}1362}
13661363
1367pub fn deleteDeclExport(1364pub fn deleteExport(
1368 self: *ZigObject,1365 self: *ZigObject,
1369 macho_file: *MachO,1366 macho_file: *MachO,
1370 decl_index: InternPool.DeclIndex,1367 exported: Zcu.Exported,
1371 name: InternPool.NullTerminatedString,1368 name: InternPool.NullTerminatedString,
1372) void {1369) void {
1373 const mod = macho_file.base.comp.module.?;1370 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 };
1376 const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;1376 const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
13771377
1378 log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});1378 log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
src/link/NvPtx.zig+2-2
...@@ -96,12 +96,12 @@ pub fn updateExports(...@@ -96,12 +96,12 @@ pub fn updateExports(
96 self: *NvPtx,96 self: *NvPtx,
97 module: *Module,97 module: *Module,
98 exported: Module.Exported,98 exported: Module.Exported,
99 exports: []const *Module.Export,99 export_indices: []const u32,
100) !void {100) !void {
101 if (build_options.skip_non_native and builtin.object_format != .nvptx)101 if (build_options.skip_non_native and builtin.object_format != .nvptx)
102 @panic("Attempted to compile for object format that was disabled by build configuration");102 @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);
105}105}
106106
107pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {107pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {
src/link/Plan9.zig+44-22
...@@ -60,6 +60,9 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(...@@ -60,6 +60,9 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(
60) = .{},60) = .{},
61/// the code is modified when relocated, so that is why it is mutable61/// the code is modified when relocated, so that is why it is mutable
62data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{},62data_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
64/// Table of unnamed constants associated with a parent `Decl`.67/// Table of unnamed constants associated with a parent `Decl`.
65/// We store them here so that we can free the constants whenever the `Decl`68/// 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)...@@ -770,8 +773,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
770 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());773 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
771 }774 }
772 self.syms.items[atom.sym_index.?].value = off;775 self.syms.items[atom.sym_index.?].value = off;
773 if (mod.decl_exports.get(decl_index)) |exports| {776 if (self.decl_exports.get(decl_index)) |export_indices| {
774 try self.addDeclExports(mod, decl_index, exports.items);777 try self.addDeclExports(mod, decl_index, export_indices);
775 }778 }
776 }779 }
777 }780 }
...@@ -836,8 +839,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)...@@ -836,8 +839,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
836 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());839 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
837 }840 }
838 self.syms.items[atom.sym_index.?].value = off;841 self.syms.items[atom.sym_index.?].value = off;
839 if (mod.decl_exports.get(decl_index)) |exports| {842 if (self.decl_exports.get(decl_index)) |export_indices| {
840 try self.addDeclExports(mod, decl_index, exports.items);843 try self.addDeclExports(mod, decl_index, export_indices);
841 }844 }
842 }845 }
843 // write the unnamed constants after the other data decls846 // write the unnamed constants after the other data decls
...@@ -1007,20 +1010,21 @@ fn addDeclExports(...@@ -1007,20 +1010,21 @@ fn addDeclExports(
1007 self: *Plan9,1010 self: *Plan9,
1008 mod: *Module,1011 mod: *Module,
1009 decl_index: InternPool.DeclIndex,1012 decl_index: InternPool.DeclIndex,
1010 exports: []const *Module.Export,1013 export_indices: []const u32,
1011) !void {1014) !void {
1012 const gpa = self.base.comp.gpa;1015 const gpa = self.base.comp.gpa;
1013 const metadata = self.decls.getPtr(decl_index).?;1016 const metadata = self.decls.getPtr(decl_index).?;
1014 const atom = self.getAtom(metadata.index);1017 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];
1017 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);1021 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
1018 // plan9 does not support custom sections1022 // plan9 does not support custom sections
1019 if (exp.opts.section.unwrap()) |section_name| {1023 if (exp.opts.section.unwrap()) |section_name| {
1020 if (!section_name.eqlSlice(".text", &mod.intern_pool) and1024 if (!section_name.eqlSlice(".text", &mod.intern_pool) and
1021 !section_name.eqlSlice(".data", &mod.intern_pool))1025 !section_name.eqlSlice(".data", &mod.intern_pool))
1022 {1026 {
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(
1024 gpa,1028 gpa,
1025 mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod),1029 mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod),
1026 "plan9 does not support extra sections",1030 "plan9 does not support extra sections",
...@@ -1152,15 +1156,23 @@ pub fn updateExports(...@@ -1152,15 +1156,23 @@ pub fn updateExports(
1152 self: *Plan9,1156 self: *Plan9,
1153 module: *Module,1157 module: *Module,
1154 exported: Module.Exported,1158 exported: Module.Exported,
1155 exports: []const *Module.Export,1159 export_indices: []const u32,
1156) !void {1160) !void {
1161 const gpa = self.base.comp.gpa;
1157 switch (exported) {1162 switch (exported) {
1158 .value => @panic("TODO: plan9 updateExports handling values"),1163 .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 },
1160 }1173 }
1161 // we do all the things in flush1174 // all proper work is done in flush
1162 _ = module;1175 _ = module;
1163 _ = exports;
1164}1176}
11651177
1166pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {1178pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
...@@ -1290,6 +1302,10 @@ pub fn deinit(self: *Plan9) void {...@@ -1290,6 +1302,10 @@ pub fn deinit(self: *Plan9) void {
1290 gpa.free(self.syms.items[sym_index].name);1302 gpa.free(self.syms.items[sym_index].name);
1291 }1303 }
1292 self.data_decl_table.deinit(gpa);1304 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);
1293 self.syms.deinit(gpa);1309 self.syms.deinit(gpa);
1294 self.got_index_free_list.deinit(gpa);1310 self.got_index_free_list.deinit(gpa);
1295 self.syms_index_free_list.deinit(gpa);1311 self.syms_index_free_list.deinit(gpa);
...@@ -1395,10 +1411,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -1395,10 +1411,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
1395 const atom = self.getAtom(decl_metadata.index);1411 const atom = self.getAtom(decl_metadata.index);
1396 const sym = self.syms.items[atom.sym_index.?];1412 const sym = self.syms.items[atom.sym_index.?];
1397 try self.writeSym(writer, sym);1413 try self.writeSym(writer, sym);
1398 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {1414 if (self.decl_exports.get(decl_index)) |export_indices| {
1399 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {1415 for (export_indices) |export_idx| {
1400 try self.writeSym(writer, self.syms.items[exp_i]);1416 const exp = mod.all_exports.items[export_idx];
1401 };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 }
1402 }1421 }
1403 }1422 }
1404 }1423 }
...@@ -1442,13 +1461,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -1442,13 +1461,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
1442 const atom = self.getAtom(decl_metadata.index);1461 const atom = self.getAtom(decl_metadata.index);
1443 const sym = self.syms.items[atom.sym_index.?];1462 const sym = self.syms.items[atom.sym_index.?];
1444 try self.writeSym(writer, sym);1463 try self.writeSym(writer, sym);
1445 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {1464 if (self.decl_exports.get(decl_index)) |export_indices| {
1446 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {1465 for (export_indices) |export_idx| {
1447 const s = self.syms.items[exp_i];1466 const exp = mod.all_exports.items[export_idx];
1448 if (mem.eql(u8, s.name, "_start"))1467 if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
1449 self.entry_val = s.value;1468 const s = self.syms.items[exp_i];
1450 try self.writeSym(writer, s);1469 if (mem.eql(u8, s.name, "_start"))
1451 };1470 self.entry_val = s.value;
1471 try self.writeSym(writer, s);
1472 }
1473 }
1452 }1474 }
1453 }1475 }
1454 }1476 }
src/link/SpirV.zig+3-2
...@@ -152,7 +152,7 @@ pub fn updateExports(...@@ -152,7 +152,7 @@ pub fn updateExports(
152 self: *SpirV,152 self: *SpirV,
153 mod: *Module,153 mod: *Module,
154 exported: Module.Exported,154 exported: Module.Exported,
155 exports: []const *Module.Export,155 export_indices: []const u32,
156) !void {156) !void {
157 const decl_index = switch (exported) {157 const decl_index = switch (exported) {
158 .decl_index => |i| i,158 .decl_index => |i| i,
...@@ -177,7 +177,8 @@ pub fn updateExports(...@@ -177,7 +177,8 @@ pub fn updateExports(
177 if ((!is_vulkan and execution_model == .Kernel) or177 if ((!is_vulkan and execution_model == .Kernel) or
178 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))178 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
179 {179 {
180 for (exports) |exp| {180 for (export_indices) |export_idx| {
181 const exp = mod.all_exports.items[export_idx];
181 try self.object.spv.declareEntryPoint(182 try self.object.spv.declareEntryPoint(
182 spv_decl_index,183 spv_decl_index,
183 exp.opts.name.toSlice(&mod.intern_pool),184 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...@@ -1542,26 +1542,26 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
1542 return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);1542 return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);
1543}1543}
15441544
1545pub fn deleteDeclExport(1545pub fn deleteExport(
1546 wasm: *Wasm,1546 wasm: *Wasm,
1547 decl_index: InternPool.DeclIndex,1547 exported: Zcu.Exported,
1548 name: InternPool.NullTerminatedString,1548 name: InternPool.NullTerminatedString,
1549) void {1549) void {
1550 if (wasm.llvm_object) |_| return;1550 if (wasm.llvm_object) |_| return;
1551 return wasm.zigObjectPtr().?.deleteDeclExport(wasm, decl_index, name);1551 return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);
1552}1552}
15531553
1554pub fn updateExports(1554pub fn updateExports(
1555 wasm: *Wasm,1555 wasm: *Wasm,
1556 mod: *Module,1556 mod: *Module,
1557 exported: Module.Exported,1557 exported: Module.Exported,
1558 exports: []const *Module.Export,1558 export_indices: []const u32,
1559) !void {1559) !void {
1560 if (build_options.skip_non_native and builtin.object_format != .wasm) {1560 if (build_options.skip_non_native and builtin.object_format != .wasm) {
1561 @panic("Attempted to compile for object format that was disabled by build configuration");1561 @panic("Attempted to compile for object format that was disabled by build configuration");
1562 }1562 }
1563 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(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, exports);1564 return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, export_indices);
1565}1565}
15661566
1567pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {1567pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
src/link/Wasm/ZigObject.zig+11-6
...@@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr(...@@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr(
833 return target_symbol_index;833 return target_symbol_index;
834}834}
835835
836pub fn deleteDeclExport(836pub fn deleteExport(
837 zig_object: *ZigObject,837 zig_object: *ZigObject,
838 wasm_file: *Wasm,838 wasm_file: *Wasm,
839 decl_index: InternPool.DeclIndex,839 exported: Zcu.Exported,
840 name: InternPool.NullTerminatedString,840 name: InternPool.NullTerminatedString,
841) void {841) void {
842 const mod = wasm_file.base.comp.module.?;842 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 };
843 const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;847 const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
844 if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {848 if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
845 const sym = zig_object.symbol(sym_index);849 const sym = zig_object.symbol(sym_index);
...@@ -856,7 +860,7 @@ pub fn updateExports(...@@ -856,7 +860,7 @@ pub fn updateExports(
856 wasm_file: *Wasm,860 wasm_file: *Wasm,
857 mod: *Module,861 mod: *Module,
858 exported: Module.Exported,862 exported: Module.Exported,
859 exports: []const *Module.Export,863 export_indices: []const u32,
860) !void {864) !void {
861 const decl_index = switch (exported) {865 const decl_index = switch (exported) {
862 .decl_index => |i| i,866 .decl_index => |i| i,
...@@ -873,9 +877,10 @@ pub fn updateExports(...@@ -873,9 +877,10 @@ pub fn updateExports(
873 const gpa = mod.gpa;877 const gpa = mod.gpa;
874 log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});878 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];
877 if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {882 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(
879 gpa,884 gpa,
880 decl.navSrcLoc(mod).upgrade(mod),885 decl.navSrcLoc(mod).upgrade(mod),
881 "Unimplemented: ExportOptions.section '{s}'",886 "Unimplemented: ExportOptions.section '{s}'",
...@@ -908,7 +913,7 @@ pub fn updateExports(...@@ -908,7 +913,7 @@ pub fn updateExports(
908 },913 },
909 .strong => {}, // symbols are strong by default914 .strong => {}, // symbols are strong by default
910 .link_once => {915 .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(
912 gpa,917 gpa,
913 decl.navSrcLoc(mod).upgrade(mod),918 decl.navSrcLoc(mod).upgrade(mod),
914 "Unimplemented: LinkOnce",919 "Unimplemented: LinkOnce",