| author | |
| committer | |
| log | 7e552dc1e9a8388f71cc32083deb9dd848e79808 |
| tree | b1c1086002c91be0e6c1195cc18966906a171ce3 |
| parent | bc8cd135987c7dc7419d034ba31178331d606cfa |
| signature |
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 | 117 | /// Backed by gpa. |
| 118 | 118 | comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{}, |
| 119 | 119 | |
| 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`. | |
| 122 | exports: std.ArrayListUnmanaged(Zcu.Export) = .{}, | |
| 123 | ||
| 120 | 124 | const MaybeComptimeAlloc = struct { |
| 121 | 125 | /// The runtime index of the `alloc` instruction. |
| 122 | 126 | runtime_index: Value.RuntimeIndex, |
| ... | ... | @@ -186,6 +190,7 @@ const build_options = @import("build_options"); |
| 186 | 190 | const Compilation = @import("Compilation.zig"); |
| 187 | 191 | const InternPool = @import("InternPool.zig"); |
| 188 | 192 | const Alignment = InternPool.Alignment; |
| 193 | const AnalUnit = InternPool.AnalUnit; | |
| 189 | 194 | const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; |
| 190 | 195 | |
| 191 | 196 | pub const default_branch_quota = 1000; |
| ... | ... | @@ -875,6 +880,7 @@ pub fn deinit(sema: *Sema) void { |
| 875 | 880 | sema.base_allocs.deinit(gpa); |
| 876 | 881 | sema.maybe_comptime_allocs.deinit(gpa); |
| 877 | 882 | sema.comptime_allocs.deinit(gpa); |
| 883 | sema.exports.deinit(gpa); | |
| 878 | 884 | sema.* = undefined; |
| 879 | 885 | } |
| 880 | 886 | |
| ... | ... | @@ -2735,12 +2741,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool { |
| 2735 | 2741 | if (!zcu.comp.debug_incremental) return false; |
| 2736 | 2742 | |
| 2737 | 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 | 2745 | const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or |
| 2740 | 2746 | zcu.potentially_outdated.swapRemove(decl_as_depender); |
| 2741 | 2747 | if (!was_outdated) return false; |
| 2742 | 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 | 2750 | zcu.intern_pool.remove(ty); |
| 2745 | 2751 | zcu.declPtr(decl_index).analysis = .dependency_failure; |
| 2746 | 2752 | try zcu.markDependeeOutdated(.{ .decl_val = decl_index }); |
| ... | ... | @@ -2834,7 +2840,7 @@ fn zirStructDecl( |
| 2834 | 2840 | if (sema.mod.comp.debug_incremental) { |
| 2835 | 2841 | try ip.addDependency( |
| 2836 | 2842 | sema.gpa, |
| 2837 | InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 2843 | AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 2838 | 2844 | .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) }, |
| 2839 | 2845 | ); |
| 2840 | 2846 | } |
| ... | ... | @@ -3068,7 +3074,7 @@ fn zirEnumDecl( |
| 3068 | 3074 | if (sema.mod.comp.debug_incremental) { |
| 3069 | 3075 | try mod.intern_pool.addDependency( |
| 3070 | 3076 | sema.gpa, |
| 3071 | InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3077 | AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3072 | 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 | 3340 | if (sema.mod.comp.debug_incremental) { |
| 3335 | 3341 | try mod.intern_pool.addDependency( |
| 3336 | 3342 | sema.gpa, |
| 3337 | InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3343 | AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3338 | 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 | 3428 | if (sema.mod.comp.debug_incremental) { |
| 3423 | 3429 | try ip.addDependency( |
| 3424 | 3430 | gpa, |
| 3425 | InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3431 | AnalUnit.wrap(.{ .decl = new_decl_index }), | |
| 3426 | 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 | 6429 | return sema.analyzeExport(block, src, options, decl_index); |
| 6424 | 6430 | } |
| 6425 | 6431 | |
| 6426 | try addExport(mod, .{ | |
| 6432 | try sema.exports.append(mod.gpa, .{ | |
| 6427 | 6433 | .opts = options, |
| 6428 | 6434 | .src = src, |
| 6429 | .owner_decl = sema.owner_decl_index, | |
| 6430 | 6435 | .exported = .{ .value = operand.toIntern() }, |
| 6431 | 6436 | .status = .in_progress, |
| 6432 | 6437 | }); |
| ... | ... | @@ -6469,46 +6474,14 @@ pub fn analyzeExport( |
| 6469 | 6474 | |
| 6470 | 6475 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); |
| 6471 | 6476 | |
| 6472 | try addExport(mod, .{ | |
| 6477 | try sema.exports.append(gpa, .{ | |
| 6473 | 6478 | .opts = options, |
| 6474 | 6479 | .src = src, |
| 6475 | .owner_decl = sema.owner_decl_index, | |
| 6476 | 6480 | .exported = .{ .decl_index = exported_decl_index }, |
| 6477 | 6481 | .status = .in_progress, |
| 6478 | 6482 | }); |
| 6479 | 6483 | } |
| 6480 | 6484 | |
| 6481 | fn 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 | ||
| 6512 | 6485 | fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 6513 | 6486 | const mod = sema.mod; |
| 6514 | 6487 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| ... | ... | @@ -8411,6 +8384,9 @@ fn instantiateGenericCall( |
| 8411 | 8384 | }); |
| 8412 | 8385 | sema.appendRefsAssumeCapacity(runtime_args.items); |
| 8413 | 8386 | |
| 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 | 8390 | if (ensure_result_used) { |
| 8415 | 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 | 35239 | const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); |
| 35264 | 35240 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); |
| 35265 | 35241 | } |
| 35242 | ||
| 35243 | try sema.flushExports(); | |
| 35266 | 35244 | } |
| 35267 | 35245 | |
| 35268 | 35246 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { |
| ... | ... | @@ -36225,6 +36203,8 @@ fn semaStructFields( |
| 36225 | 36203 | |
| 36226 | 36204 | struct_type.clearTypesWip(ip); |
| 36227 | 36205 | if (!any_inits) struct_type.setHaveFieldInits(ip); |
| 36206 | ||
| 36207 | try sema.flushExports(); | |
| 36228 | 36208 | } |
| 36229 | 36209 | |
| 36230 | 36210 | // This logic must be kept in sync with `semaStructFields` |
| ... | ... | @@ -36365,6 +36345,8 @@ fn semaStructFieldInits( |
| 36365 | 36345 | struct_type.field_inits.get(ip)[field_i] = default_val.toIntern(); |
| 36366 | 36346 | } |
| 36367 | 36347 | } |
| 36348 | ||
| 36349 | try sema.flushExports(); | |
| 36368 | 36350 | } |
| 36369 | 36351 | |
| 36370 | 36352 | fn 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 | 36720 | const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl)); |
| 36739 | 36721 | union_type.tagTypePtr(ip).* = enum_ty; |
| 36740 | 36722 | } |
| 36723 | ||
| 36724 | try sema.flushExports(); | |
| 36741 | 36725 | } |
| 36742 | 36726 | |
| 36743 | 36727 | fn 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 | 38346 | return; |
| 38363 | 38347 | } |
| 38364 | 38348 | |
| 38365 | const depender = InternPool.AnalUnit.wrap( | |
| 38349 | const depender = AnalUnit.wrap( | |
| 38366 | 38350 | if (sema.owner_func_index != .none) |
| 38367 | 38351 | .{ .func = sema.owner_func_index } |
| 38368 | 38352 | else |
| ... | ... | @@ -38494,6 +38478,52 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check: |
| 38494 | 38478 | } |
| 38495 | 38479 | } |
| 38496 | 38480 | |
| 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. | |
| 38484 | pub 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 | ||
| 38497 | 38527 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; |
| 38498 | 38528 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; |
| 38499 | 38529 |
src/Zcu.zig+160-143| ... | ... | @@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir; |
| 35 | 35 | const clang = @import("clang.zig"); |
| 36 | 36 | const InternPool = @import("InternPool.zig"); |
| 37 | 37 | const Alignment = InternPool.Alignment; |
| 38 | const AnalUnit = InternPool.AnalUnit; | |
| 38 | 39 | const BuiltinFn = std.zig.BuiltinFn; |
| 39 | 40 | const LlvmObject = @import("codegen/llvm.zig").Object; |
| 40 | 41 | |
| ... | ... | @@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined, |
| 71 | 72 | global_zir_cache: Compilation.Directory, |
| 72 | 73 | /// Used by AstGen worker to load and store ZIR cache. |
| 73 | 74 | local_zir_cache: Compilation.Directory, |
| 74 | /// It's rare for a decl to be exported, so we save memory by having a sparse | |
| 75 | /// map of Decl indexes to details about them being exported. | |
| 76 | /// The Export memory is owned by the `export_owners` table; the slice itself | |
| 77 | /// is owned by this table. The slice is guaranteed to not be empty. | |
| 78 | decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{}, | |
| 79 | /// Same as `decl_exports` but for exported constant values. | |
| 80 | value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{}, | |
| 81 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl | |
| 82 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that | |
| 83 | /// is performing the export of another Decl. | |
| 84 | /// This table owns the Export memory. | |
| 85 | export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{}, | |
| 75 | /// This is where all `Export` values are stored. Not all values here are necessarily valid exports; | |
| 76 | /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted. | |
| 77 | all_exports: ArrayListUnmanaged(Export) = .{}, | |
| 78 | /// This is a list of free indices in `all_exports`. These indices may be reused by exports from | |
| 79 | /// future semantic analysis. | |
| 80 | free_exports: ArrayListUnmanaged(u32) = .{}, | |
| 81 | /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of | |
| 82 | /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` | |
| 83 | /// whose analysis triggered the export. | |
| 84 | single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | |
| 85 | /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. | |
| 86 | /// The exports are `all_exports.items[index..][0..len]`. | |
| 87 | multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct { | |
| 88 | index: u32, | |
| 89 | len: u32, | |
| 90 | }) = .{}, | |
| 86 | 91 | /// The set of all the Zig source files in the Module. We keep track of this in order |
| 87 | 92 | /// to iterate over it and check which source files have been modified on the file system when |
| 88 | 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 | 131 | failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{}, |
| 127 | 132 | /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator. |
| 128 | 133 | failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{}, |
| 129 | /// Using a map here for consistency with the other fields here. | |
| 130 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. | |
| 131 | failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, | |
| 134 | /// Key is index into `all_exports`. | |
| 135 | failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{}, | |
| 132 | 136 | /// If a decl failed due to a cimport error, the corresponding Clang errors |
| 133 | 137 | /// are stored here. |
| 134 | 138 | cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{}, |
| ... | ... | @@ -140,14 +144,14 @@ global_error_set: GlobalErrorSet = .{}, |
| 140 | 144 | error_limit: ErrorInt, |
| 141 | 145 | |
| 142 | 146 | /// Value is the number of PO or outdated Decls which this AnalUnit depends on. |
| 143 | potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{}, | |
| 147 | potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | |
| 144 | 148 | /// Value is the number of PO or outdated Decls which this AnalUnit depends on. |
| 145 | 149 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. |
| 146 | outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{}, | |
| 150 | outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | |
| 147 | 151 | /// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0. |
| 148 | 152 | /// Such `AnalUnit`s are ready for immediate re-analysis. |
| 149 | 153 | /// See `findOutdatedToAnalyze` for details. |
| 150 | outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, void) = .{}, | |
| 154 | outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, | |
| 151 | 155 | /// This contains a set of Decls which may not be in `outdated`, but are the |
| 152 | 156 | /// root Decls of files which have updated source and thus must be re-analyzed. |
| 153 | 157 | /// 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 | 162 | /// failure was something like running out of disk space, and trying again may |
| 159 | 163 | /// succeed. On the next update, we will flush this list, marking all members of |
| 160 | 164 | /// it as outdated. |
| 161 | retryable_failures: std.ArrayListUnmanaged(InternPool.AnalUnit) = .{}, | |
| 165 | retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{}, | |
| 162 | 166 | |
| 163 | 167 | stage1_flags: packed struct { |
| 164 | 168 | have_winmain: bool = false, |
| ... | ... | @@ -267,8 +271,6 @@ pub const Exported = union(enum) { |
| 267 | 271 | pub const Export = struct { |
| 268 | 272 | opts: Options, |
| 269 | 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 | 274 | exported: Exported, |
| 273 | 275 | status: enum { |
| 274 | 276 | in_progress, |
| ... | ... | @@ -2507,20 +2509,10 @@ pub fn deinit(zcu: *Zcu) void { |
| 2507 | 2509 | |
| 2508 | 2510 | zcu.compile_log_decls.deinit(gpa); |
| 2509 | 2511 | |
| 2510 | for (zcu.decl_exports.values()) |*export_list| { | |
| 2511 | export_list.deinit(gpa); | |
| 2512 | } | |
| 2513 | zcu.decl_exports.deinit(gpa); | |
| 2514 | ||
| 2515 | for (zcu.value_exports.values()) |*export_list| { | |
| 2516 | export_list.deinit(gpa); | |
| 2517 | } | |
| 2518 | zcu.value_exports.deinit(gpa); | |
| 2519 | ||
| 2520 | for (zcu.export_owners.values()) |*value| { | |
| 2521 | freeExportList(gpa, value); | |
| 2522 | } | |
| 2523 | zcu.export_owners.deinit(gpa); | |
| 2512 | zcu.all_exports.deinit(gpa); | |
| 2513 | zcu.free_exports.deinit(gpa); | |
| 2514 | zcu.single_exports.deinit(gpa); | |
| 2515 | zcu.multi_exports.deinit(gpa); | |
| 2524 | 2516 | |
| 2525 | 2517 | zcu.global_error_set.deinit(gpa); |
| 2526 | 2518 | |
| ... | ... | @@ -2590,11 +2582,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 2590 | 2582 | return decl_index == namespace.decl_index; |
| 2591 | 2583 | } |
| 2592 | 2584 | |
| 2593 | fn 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 | 2585 | // TODO https://github.com/ziglang/zig/issues/8643 |
| 2599 | 2586 | const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; |
| 2600 | 2587 | const HackDataLayout = extern struct { |
| ... | ... | @@ -3139,7 +3126,7 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3139 | 3126 | |
| 3140 | 3127 | /// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may |
| 3141 | 3128 | /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES. |
| 3142 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.AnalUnit) !void { | |
| 3129 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void { | |
| 3143 | 3130 | var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) { |
| 3144 | 3131 | .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced |
| 3145 | 3132 | .func => |func_index| .{ .func_ies = func_index }, |
| ... | ... | @@ -3166,7 +3153,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP |
| 3166 | 3153 | } |
| 3167 | 3154 | } |
| 3168 | 3155 | |
| 3169 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit { | |
| 3156 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | |
| 3170 | 3157 | if (!zcu.comp.debug_incremental) return null; |
| 3171 | 3158 | |
| 3172 | 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 | 3184 | // `outdated`. This set will be small (number of files changed in this |
| 3198 | 3185 | // update), so it's alright for us to just iterate here. |
| 3199 | 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 | 3188 | if (zcu.outdated.contains(decl_depender)) { |
| 3202 | 3189 | // Since we didn't hit this in the first loop, this Decl must have |
| 3203 | 3190 | // pending dependencies, so is ineligible. |
| ... | ... | @@ -3271,7 +3258,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit { |
| 3271 | 3258 | chosen_decl_dependers, |
| 3272 | 3259 | }); |
| 3273 | 3260 | |
| 3274 | return InternPool.AnalUnit.wrap(.{ .decl = chosen_decl_idx.? }); | |
| 3261 | return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? }); | |
| 3275 | 3262 | } |
| 3276 | 3263 | |
| 3277 | 3264 | /// 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 | 3443 | // which tries to limit re-analysis to Decls whose previously listed |
| 3457 | 3444 | // dependencies are all up-to-date. |
| 3458 | 3445 | |
| 3459 | const decl_as_depender = InternPool.AnalUnit.wrap(.{ .decl = decl_index }); | |
| 3446 | const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index }); | |
| 3460 | 3447 | const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or |
| 3461 | 3448 | mod.potentially_outdated.swapRemove(decl_as_depender); |
| 3462 | 3449 | |
| ... | ... | @@ -3485,7 +3472,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3485 | 3472 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 3486 | 3473 | // prior to re-analysis. |
| 3487 | 3474 | if (build_options.only_c) unreachable; |
| 3488 | try mod.deleteDeclExports(decl_index); | |
| 3475 | mod.deleteUnitExports(AnalUnit.wrap(.{ .decl = decl_index })); | |
| 3489 | 3476 | } |
| 3490 | 3477 | |
| 3491 | 3478 | const sema_result: SemaDeclResult = blk: { |
| ... | ... | @@ -3522,7 +3509,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3522 | 3509 | else => |e| { |
| 3523 | 3510 | decl.analysis = .sema_failure; |
| 3524 | 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 | 3513 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 3527 | 3514 | mod.gpa, |
| 3528 | 3515 | decl.navSrcLoc(mod).upgrade(mod), |
| ... | ... | @@ -3581,7 +3568,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In |
| 3581 | 3568 | // that's the case, we should remove this function from the binary. |
| 3582 | 3569 | if (decl.val.ip_index != func_index) { |
| 3583 | 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 | 3572 | ip.remove(func_index); |
| 3586 | 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 | 3594 | .complete => {}, |
| 3608 | 3595 | } |
| 3609 | 3596 | |
| 3610 | const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index }); | |
| 3597 | const func_as_depender = AnalUnit.wrap(.{ .func = func_index }); | |
| 3611 | 3598 | const was_outdated = zcu.outdated.swapRemove(func_as_depender) or |
| 3612 | 3599 | zcu.potentially_outdated.swapRemove(func_as_depender); |
| 3613 | 3600 | |
| 3614 | 3601 | if (was_outdated) { |
| 3602 | if (build_options.only_c) unreachable; | |
| 3615 | 3603 | _ = zcu.outdated_ready.swapRemove(func_as_depender); |
| 3604 | zcu.deleteUnitExports(AnalUnit.wrap(.{ .func = func_index })); | |
| 3616 | 3605 | } |
| 3617 | 3606 | |
| 3618 | 3607 | switch (func.analysis(ip).state) { |
| ... | ... | @@ -3728,16 +3717,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In |
| 3728 | 3717 | .{@errorName(err)}, |
| 3729 | 3718 | )); |
| 3730 | 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 | 3723 | } else if (zcu.llvm_object) |llvm_object| { |
| 3735 | 3724 | if (build_options.only_c) unreachable; |
| 3736 | 3725 | llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { |
| 3737 | 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 | 3759 | |
| 3774 | 3760 | assert(decl.has_tv); |
| 3775 | 3761 | |
| 3776 | const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index }); | |
| 3762 | const func_as_depender = AnalUnit.wrap(.{ .func = func_index }); | |
| 3777 | 3763 | const is_outdated = mod.outdated.contains(func_as_depender) or |
| 3778 | 3764 | mod.potentially_outdated.contains(func_as_depender); |
| 3779 | 3765 | |
| ... | ... | @@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa |
| 3857 | 3843 | if (zcu.comp.debug_incremental) { |
| 3858 | 3844 | try ip.addDependency( |
| 3859 | 3845 | gpa, |
| 3860 | InternPool.AnalUnit.wrap(.{ .decl = decl_index }), | |
| 3846 | AnalUnit.wrap(.{ .decl = decl_index }), | |
| 3861 | 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 | 3892 | |
| 3907 | 3893 | if (type_outdated) { |
| 3908 | 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 | 3896 | zcu.intern_pool.remove(decl.val.toIntern()); |
| 3911 | 3897 | decl.val = undefined; |
| 3912 | 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 | 4083 | break :ip_index .none; |
| 4098 | 4084 | }; |
| 4099 | 4085 | |
| 4100 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index })); | |
| 4086 | mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .decl = decl_index })); | |
| 4101 | 4087 | |
| 4102 | 4088 | decl.analysis = .in_progress; |
| 4103 | 4089 | |
| ... | ... | @@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 4293 | 4279 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 4294 | 4280 | } |
| 4295 | 4281 | |
| 4282 | try sema.flushExports(); | |
| 4283 | ||
| 4296 | 4284 | return result; |
| 4297 | 4285 | } |
| 4298 | 4286 | |
| ... | ... | @@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult { |
| 4323 | 4311 | // with a new Decl. |
| 4324 | 4312 | // |
| 4325 | 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 | 4315 | zcu.intern_pool.remove(decl.val.toIntern()); |
| 4328 | 4316 | decl.analysis = .dependency_failure; |
| 4329 | 4317 | return .{ |
| ... | ... | @@ -4949,63 +4937,44 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo |
| 4949 | 4937 | } |
| 4950 | 4938 | } |
| 4951 | 4939 | |
| 4952 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of | |
| 4953 | /// this Decl will cause them to be re-created (or not). | |
| 4954 | fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { | |
| 4955 | var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value; | |
| 4956 | ||
| 4957 | for (export_owners.items) |exp| { | |
| 4958 | switch (exp.exported) { | |
| 4959 | .decl_index => |exported_decl_index| { | |
| 4960 | if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| { | |
| 4961 | // Remove exports with owner_decl matching the regenerating decl. | |
| 4962 | const list = export_list.items; | |
| 4963 | var i: usize = 0; | |
| 4964 | var new_len = list.len; | |
| 4965 | while (i < new_len) { | |
| 4966 | if (list[i].owner_decl == decl_index) { | |
| 4967 | mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]); | |
| 4968 | new_len -= 1; | |
| 4969 | } else { | |
| 4970 | i += 1; | |
| 4971 | } | |
| 4972 | } | |
| 4973 | export_list.shrinkAndFree(mod.gpa, new_len); | |
| 4974 | if (new_len == 0) { | |
| 4975 | assert(mod.decl_exports.swapRemove(exported_decl_index)); | |
| 4976 | } | |
| 4977 | } | |
| 4978 | }, | |
| 4979 | .value => |value| { | |
| 4980 | if (mod.value_exports.getPtr(value)) |export_list| { | |
| 4981 | // Remove exports with owner_decl matching the regenerating decl. | |
| 4982 | const list = export_list.items; | |
| 4983 | var i: usize = 0; | |
| 4984 | var new_len = list.len; | |
| 4985 | while (i < new_len) { | |
| 4986 | if (list[i].owner_decl == decl_index) { | |
| 4987 | mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]); | |
| 4988 | new_len -= 1; | |
| 4989 | } else { | |
| 4990 | i += 1; | |
| 4991 | } | |
| 4992 | } | |
| 4993 | export_list.shrinkAndFree(mod.gpa, new_len); | |
| 4994 | if (new_len == 0) { | |
| 4995 | assert(mod.value_exports.swapRemove(value)); | |
| 4996 | } | |
| 4997 | } | |
| 4998 | }, | |
| 4999 | } | |
| 5000 | if (mod.comp.bin_file) |lf| { | |
| 5001 | try lf.deleteDeclExport(decl_index, exp.opts.name); | |
| 5002 | } | |
| 5003 | if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { | |
| 5004 | failed_kv.value.destroy(mod.gpa); | |
| 4940 | /// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of | |
| 4941 | /// this `AnalUnit` will cause them to be re-created (or not). | |
| 4942 | pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { | |
| 4943 | const gpa = zcu.gpa; | |
| 4944 | ||
| 4945 | const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv| | |
| 4946 | .{ kv.value, 1 } | |
| 4947 | else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info| | |
| 4948 | .{ info.value.index, info.value.len } | |
| 4949 | else | |
| 4950 | return; | |
| 4951 | ||
| 4952 | const exports = zcu.all_exports.items[exports_base..][0..exports_len]; | |
| 4953 | ||
| 4954 | // In an only-c build, we're guaranteed to never use incremental compilation, so there are | |
| 4955 | // guaranteed not to be any exports in the output file that need deleting (since we only call | |
| 4956 | // `updateExports` on flush). | |
| 4957 | // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports | |
| 4958 | // within a single update. | |
| 4959 | if (!build_options.only_c) { | |
| 4960 | for (exports, exports_base..) |exp, export_idx| { | |
| 4961 | if (zcu.comp.bin_file) |lf| { | |
| 4962 | lf.deleteExport(exp.exported, exp.opts.name); | |
| 4963 | } | |
| 4964 | if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| { | |
| 4965 | failed_kv.value.destroy(gpa); | |
| 4966 | } | |
| 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 | } |
| 5010 | 4979 | |
| 5011 | 4980 | pub 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 | 4995 | const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); |
| 5027 | 4996 | defer decl_prog_node.end(); |
| 5028 | 4997 | |
| 5029 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index })); | |
| 4998 | mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index })); | |
| 5030 | 4999 | |
| 5031 | 5000 | var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa); |
| 5032 | 5001 | defer comptime_err_ret_trace.deinit(); |
| ... | ... | @@ -5262,6 +5231,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato |
| 5262 | 5231 | }; |
| 5263 | 5232 | } |
| 5264 | 5233 | |
| 5234 | try sema.flushExports(); | |
| 5235 | ||
| 5265 | 5236 | return .{ |
| 5266 | 5237 | .instructions = sema.air_instructions.toOwnedSlice(), |
| 5267 | 5238 | .extra = try sema.air_extra.toOwnedSlice(gpa), |
| ... | ... | @@ -5392,33 +5363,89 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void { |
| 5392 | 5363 | /// Called from `Compilation.update`, after everything is done, just before |
| 5393 | 5364 | /// reporting compile errors. In this function we emit exported symbol collision |
| 5394 | 5365 | /// errors and communicate exported symbols to the linker backend. |
| 5395 | pub fn processExports(mod: *Module) !void { | |
| 5366 | pub 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 | 5422 | // Map symbol names to `Export` for name collision detection. |
| 5397 | 5423 | var symbol_exports: SymbolExports = .{}; |
| 5398 | defer symbol_exports.deinit(mod.gpa); | |
| 5424 | defer symbol_exports.deinit(gpa); | |
| 5399 | 5425 | |
| 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 | 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 | } |
| 5404 | 5430 | |
| 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 | 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 | } |
| 5410 | 5436 | |
| 5411 | const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export); | |
| 5437 | const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32); | |
| 5412 | 5438 | |
| 5413 | 5439 | fn processExportsInner( |
| 5414 | 5440 | zcu: *Zcu, |
| 5415 | 5441 | symbol_exports: *SymbolExports, |
| 5416 | 5442 | exported: Exported, |
| 5417 | exports: []const *Export, | |
| 5443 | export_indices: []const u32, | |
| 5418 | 5444 | ) error{OutOfMemory}!void { |
| 5419 | 5445 | const gpa = zcu.gpa; |
| 5420 | 5446 | |
| 5421 | for (exports) |new_export| { | |
| 5447 | for (export_indices) |export_idx| { | |
| 5448 | const new_export = &zcu.all_exports.items[export_idx]; | |
| 5422 | 5449 | const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name); |
| 5423 | 5450 | if (gop.found_existing) { |
| 5424 | 5451 | new_export.status = .failed_retryable; |
| ... | ... | @@ -5428,40 +5455,41 @@ fn processExportsInner( |
| 5428 | 5455 | new_export.opts.name.fmt(&zcu.intern_pool), |
| 5429 | 5456 | }); |
| 5430 | 5457 | errdefer msg.destroy(gpa); |
| 5431 | const other_export = gop.value_ptr.*; | |
| 5458 | const other_export = zcu.all_exports.items[gop.value_ptr.*]; | |
| 5432 | 5459 | const other_src_loc = other_export.getSrcLoc(zcu); |
| 5433 | 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 | 5462 | new_export.status = .failed; |
| 5436 | 5463 | } else { |
| 5437 | gop.value_ptr.* = new_export; | |
| 5464 | gop.value_ptr.* = export_idx; | |
| 5438 | 5465 | } |
| 5439 | 5466 | } |
| 5440 | 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 | 5469 | } else if (zcu.llvm_object) |llvm_object| { |
| 5443 | 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 | } |
| 5447 | 5474 | |
| 5448 | 5475 | fn handleUpdateExports( |
| 5449 | 5476 | zcu: *Zcu, |
| 5450 | exports: []const *Export, | |
| 5477 | export_indices: []const u32, | |
| 5451 | 5478 | result: link.File.UpdateExportsError!void, |
| 5452 | 5479 | ) Allocator.Error!void { |
| 5453 | 5480 | const gpa = zcu.gpa; |
| 5454 | 5481 | result catch |err| switch (err) { |
| 5455 | 5482 | error.OutOfMemory => return error.OutOfMemory, |
| 5456 | 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 | 5486 | new_export.status = .failed_retryable; |
| 5459 | 5487 | try zcu.failed_exports.ensureUnusedCapacity(gpa, 1); |
| 5460 | 5488 | const src_loc = new_export.getSrcLoc(zcu); |
| 5461 | 5489 | const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{ |
| 5462 | 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 | 5655 | .{@errorName(err)}, |
| 5628 | 5656 | )); |
| 5629 | 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 | 5661 | } else if (zcu.llvm_object) |llvm_object| { |
| 5634 | 5662 | if (build_options.only_c) unreachable; |
| 5635 | 5663 | llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) { |
| 5636 | 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 | 5709 | } |
| 5685 | 5710 | } |
| 5686 | 5711 | |
| 5687 | pub 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 | ||
| 5695 | 5712 | pub const Feature = enum { |
| 5696 | 5713 | panic_fn, |
| 5697 | 5714 | panic_unwrap_error, |
src/codegen/c.zig+2| ... | ... | @@ -3081,6 +3081,8 @@ pub fn genDeclValue( |
| 3081 | 3081 | } |
| 3082 | 3082 | |
| 3083 | 3083 | pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 3084 | if (true) @panic("TODO jacobly"); | |
| 3085 | ||
| 3084 | 3086 | const tracy = trace(@src()); |
| 3085 | 3087 | defer tracy.end(); |
| 3086 | 3088 |
src/codegen/llvm.zig+109-154| ... | ... | @@ -848,10 +848,6 @@ pub const Object = struct { |
| 848 | 848 | /// Note that the values are not added until `emit`, when all errors in |
| 849 | 849 | /// the compilation are known. |
| 850 | 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), | |
| 855 | 851 | |
| 856 | 852 | /// Memoizes a null `?usize` value. |
| 857 | 853 | null_opt_usize: Builder.Constant, |
| ... | ... | @@ -1011,7 +1007,6 @@ pub const Object = struct { |
| 1011 | 1007 | .named_enum_map = .{}, |
| 1012 | 1008 | .type_map = .{}, |
| 1013 | 1009 | .error_name_table = .none, |
| 1014 | .extern_collisions = .{}, | |
| 1015 | 1010 | .null_opt_usize = .no_init, |
| 1016 | 1011 | .struct_field_map = .{}, |
| 1017 | 1012 | }; |
| ... | ... | @@ -1029,7 +1024,6 @@ pub const Object = struct { |
| 1029 | 1024 | self.anon_decl_map.deinit(gpa); |
| 1030 | 1025 | self.named_enum_map.deinit(gpa); |
| 1031 | 1026 | self.type_map.deinit(gpa); |
| 1032 | self.extern_collisions.deinit(gpa); | |
| 1033 | 1027 | self.builder.deinit(); |
| 1034 | 1028 | self.struct_field_map.deinit(gpa); |
| 1035 | 1029 | self.* = undefined; |
| ... | ... | @@ -1121,61 +1115,6 @@ pub const Object = struct { |
| 1121 | 1115 | try object.builder.finishModuleAsm(); |
| 1122 | 1116 | } |
| 1123 | 1117 | |
| 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 | 1118 | pub const EmitOptions = struct { |
| 1180 | 1119 | pre_ir_path: ?[]const u8, |
| 1181 | 1120 | pre_bc_path: ?[]const u8, |
| ... | ... | @@ -1193,7 +1132,6 @@ pub const Object = struct { |
| 1193 | 1132 | |
| 1194 | 1133 | pub fn emit(self: *Object, options: EmitOptions) !void { |
| 1195 | 1134 | { |
| 1196 | try self.resolveExportExternCollisions(); | |
| 1197 | 1135 | try self.genErrorNameTable(); |
| 1198 | 1136 | try self.genCmpLtErrorsLenFunction(); |
| 1199 | 1137 | try self.genModuleLevelAssembly(); |
| ... | ... | @@ -1698,8 +1636,7 @@ pub const Object = struct { |
| 1698 | 1636 | const file = try o.getDebugFile(namespace.file_scope); |
| 1699 | 1637 | |
| 1700 | 1638 | const line_number = decl.navSrcLine(zcu) + 1; |
| 1701 | const is_internal_linkage = decl.val.getExternFunc(zcu) == null and | |
| 1702 | !zcu.decl_exports.contains(decl_index); | |
| 1639 | const is_internal_linkage = decl.val.getExternFunc(zcu) == null; | |
| 1703 | 1640 | const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu)); |
| 1704 | 1641 | |
| 1705 | 1642 | const subprogram = try o.builder.debugSubprogram( |
| ... | ... | @@ -1760,8 +1697,6 @@ pub const Object = struct { |
| 1760 | 1697 | }; |
| 1761 | 1698 | |
| 1762 | 1699 | try fg.wip.finish(); |
| 1763 | ||
| 1764 | try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index)); | |
| 1765 | 1700 | } |
| 1766 | 1701 | |
| 1767 | 1702 | pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void { |
| ... | ... | @@ -1781,66 +1716,25 @@ pub const Object = struct { |
| 1781 | 1716 | }, |
| 1782 | 1717 | else => |e| return e, |
| 1783 | 1718 | }; |
| 1784 | try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index)); | |
| 1785 | 1719 | } |
| 1786 | 1720 | |
| 1787 | 1721 | pub fn updateExports( |
| 1788 | 1722 | self: *Object, |
| 1789 | 1723 | mod: *Module, |
| 1790 | 1724 | exported: Module.Exported, |
| 1791 | exports: []const *Module.Export, | |
| 1725 | export_indices: []const u32, | |
| 1792 | 1726 | ) link.File.UpdateExportsError!void { |
| 1793 | 1727 | const decl_index = switch (exported) { |
| 1794 | 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 | 1731 | const ip = &mod.intern_pool; |
| 1799 | // If the module does not already have the function, we ignore this function call | |
| 1800 | // because we call `updateExports` at the end of `updateFunc` and `updateDecl`. | |
| 1801 | const global_index = self.decl_map.get(decl_index) orelse return; | |
| 1732 | const global_index = self.decl_map.get(decl_index).?; | |
| 1802 | 1733 | const decl = mod.declPtr(decl_index); |
| 1803 | 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 | }; | |
| 1815 | 1735 | |
| 1816 | if (self.builder.getGlobal(decl_name)) |other_global| { | |
| 1817 | if (other_global != global_index) { | |
| 1818 | try self.extern_collisions.put(gpa, decl_index, {}); | |
| 1819 | } | |
| 1820 | } | |
| 1821 | ||
| 1822 | try global_index.rename(decl_name, &self.builder); | |
| 1823 | global_index.setLinkage(.external, &self.builder); | |
| 1824 | global_index.setUnnamedAddr(.default, &self.builder); | |
| 1825 | if (comp.config.dll_export_fns) | |
| 1826 | global_index.setDllStorageClass(.default, &self.builder); | |
| 1827 | ||
| 1828 | if (decl.val.getVariable(mod)) |decl_var| { | |
| 1829 | global_index.ptrConst(&self.builder).kind.variable.setThreadLocal( | |
| 1830 | if (decl_var.is_threadlocal) .generaldynamic else .default, | |
| 1831 | &self.builder, | |
| 1832 | ); | |
| 1833 | if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder); | |
| 1834 | } | |
| 1835 | } else if (exports.len != 0) { | |
| 1836 | const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip)); | |
| 1837 | try global_index.rename(main_exp_name, &self.builder); | |
| 1838 | ||
| 1839 | if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal) | |
| 1840 | global_index.ptrConst(&self.builder).kind | |
| 1841 | .variable.setThreadLocal(.generaldynamic, &self.builder); | |
| 1842 | ||
| 1843 | return updateExportedGlobal(self, mod, global_index, exports); | |
| 1736 | if (export_indices.len != 0) { | |
| 1737 | return updateExportedGlobal(self, mod, global_index, export_indices); | |
| 1844 | 1738 | } else { |
| 1845 | 1739 | const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip)); |
| 1846 | 1740 | try global_index.rename(fqn, &self.builder); |
| ... | ... | @@ -1848,17 +1742,6 @@ pub const Object = struct { |
| 1848 | 1742 | if (comp.config.dll_export_fns) |
| 1849 | 1743 | global_index.setDllStorageClass(.default, &self.builder); |
| 1850 | 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 | } |
| 1864 | 1747 | |
| ... | ... | @@ -1866,11 +1749,11 @@ pub const Object = struct { |
| 1866 | 1749 | o: *Object, |
| 1867 | 1750 | mod: *Module, |
| 1868 | 1751 | exported_value: InternPool.Index, |
| 1869 | exports: []const *Module.Export, | |
| 1752 | export_indices: []const u32, | |
| 1870 | 1753 | ) link.File.UpdateExportsError!void { |
| 1871 | 1754 | const gpa = mod.gpa; |
| 1872 | 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 | 1757 | const global_index = i: { |
| 1875 | 1758 | const gop = try o.anon_decl_map.getOrPut(gpa, exported_value); |
| 1876 | 1759 | if (gop.found_existing) { |
| ... | ... | @@ -1894,32 +1777,57 @@ pub const Object = struct { |
| 1894 | 1777 | try variable_index.setInitializer(init_val, &o.builder); |
| 1895 | 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 | } |
| 1899 | 1782 | |
| 1900 | 1783 | fn updateExportedGlobal( |
| 1901 | 1784 | o: *Object, |
| 1902 | 1785 | mod: *Module, |
| 1903 | 1786 | global_index: Builder.Global.Index, |
| 1904 | exports: []const *Module.Export, | |
| 1787 | export_indices: []const u32, | |
| 1905 | 1788 | ) link.File.UpdateExportsError!void { |
| 1906 | 1789 | const comp = mod.comp; |
| 1907 | 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 | 1816 | global_index.setUnnamedAddr(.default, &o.builder); |
| 1909 | 1817 | if (comp.config.dll_export_fns) |
| 1910 | 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 | 1820 | .internal => unreachable, |
| 1913 | 1821 | .strong => .external, |
| 1914 | 1822 | .weak => .weak_odr, |
| 1915 | 1823 | .link_once => .linkonce_odr, |
| 1916 | 1824 | }, &o.builder); |
| 1917 | global_index.setVisibility(switch (exports[0].opts.visibility) { | |
| 1825 | global_index.setVisibility(switch (first_export.opts.visibility) { | |
| 1918 | 1826 | .default => .default, |
| 1919 | 1827 | .hidden => .hidden, |
| 1920 | 1828 | .protected => .protected, |
| 1921 | 1829 | }, &o.builder); |
| 1922 | if (exports[0].opts.section.toSlice(ip)) |section| | |
| 1830 | if (first_export.opts.section.toSlice(ip)) |section| | |
| 1923 | 1831 | switch (global_index.ptrConst(&o.builder).kind) { |
| 1924 | 1832 | .variable => |impl_index| impl_index.setSection( |
| 1925 | 1833 | try o.builder.string(section), |
| ... | ... | @@ -1936,7 +1844,8 @@ pub const Object = struct { |
| 1936 | 1844 | // The planned solution to this is https://github.com/ziglang/zig/issues/13265 |
| 1937 | 1845 | // Until then we iterate over existing aliases and make them point |
| 1938 | 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 | 1849 | const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip)); |
| 1941 | 1850 | if (o.builder.getGlobal(exp_name)) |global| { |
| 1942 | 1851 | switch (global.ptrConst(&o.builder).kind) { |
| ... | ... | @@ -1944,7 +1853,13 @@ pub const Object = struct { |
| 1944 | 1853 | alias.setAliasee(global_index.toConst(), &o.builder); |
| 1945 | 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 | 1863 | .replaced => unreachable, |
| 1949 | 1864 | } |
| 1950 | 1865 | } |
| ... | ... | @@ -4762,36 +4677,77 @@ pub const DeclGen = struct { |
| 4762 | 4677 | else => try o.lowerValue(init_val), |
| 4763 | 4678 | }, &o.builder); |
| 4764 | 4679 | |
| 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 | 4689 | const line_number = decl.navSrcLine(zcu) + 1; |
| 4766 | const is_internal_linkage = !o.module.decl_exports.contains(decl_index); | |
| 4767 | 4690 | |
| 4768 | 4691 | const namespace = zcu.namespacePtr(decl.src_namespace); |
| 4769 | 4692 | const owner_mod = namespace.file_scope.mod; |
| 4770 | 4693 | |
| 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 | ); | |
| 4772 | 4707 | |
| 4773 | const debug_file = try o.getDebugFile(namespace.file_scope); | |
| 4708 | const debug_expression = try o.builder.debugExpression(&.{}); | |
| 4774 | 4709 | |
| 4775 | const debug_global_var = try o.builder.debugGlobalVar( | |
| 4776 | try o.builder.metadataString(decl.name.toSlice(ip)), // Name | |
| 4777 | try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name | |
| 4778 | debug_file, // File | |
| 4779 | debug_file, // Scope | |
| 4780 | line_number, | |
| 4781 | try o.lowerDebugType(decl.typeOf(zcu)), | |
| 4782 | variable_index, | |
| 4783 | .{ .local = is_internal_linkage }, | |
| 4784 | ); | |
| 4710 | const debug_global_var_expression = try o.builder.debugGlobalVarExpression( | |
| 4711 | debug_global_var, | |
| 4712 | debug_expression, | |
| 4713 | ); | |
| 4785 | 4714 | |
| 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 | } | |
| 4787 | 4719 | |
| 4788 | const debug_global_var_expression = try o.builder.debugGlobalVarExpression( | |
| 4789 | debug_global_var, | |
| 4790 | debug_expression, | |
| 4791 | ); | |
| 4720 | if (decl.isExtern(zcu)) { | |
| 4721 | const global_index = o.decl_map.get(decl_index).?; | |
| 4792 | 4722 | |
| 4793 | variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder); | |
| 4794 | try o.debug_globals.append(o.gpa, debug_global_var_expression); | |
| 4723 | const decl_name = decl_name: { | |
| 4724 | if (zcu.getTarget().isWasm() and decl.typeOf(zcu).zigTypeTag(zcu) == .Fn) { | |
| 4725 | if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| { | |
| 4726 | if (!std.mem.eql(u8, lib_name, "c")) { | |
| 4727 | break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name }); | |
| 4728 | } | |
| 4729 | } | |
| 4730 | } | |
| 4731 | break :decl_name try o.builder.strtabString(decl.name.toSlice(ip)); | |
| 4732 | }; | |
| 4733 | ||
| 4734 | if (o.builder.getGlobal(decl_name)) |other_global| { | |
| 4735 | if (other_global != global_index) { | |
| 4736 | // Another global already has this name; just use it in place of this global. | |
| 4737 | try global_index.replace(other_global, &o.builder); | |
| 4738 | return; | |
| 4739 | } | |
| 4740 | } | |
| 4741 | ||
| 4742 | try global_index.rename(decl_name, &o.builder); | |
| 4743 | global_index.setLinkage(.external, &o.builder); | |
| 4744 | global_index.setUnnamedAddr(.default, &o.builder); | |
| 4745 | if (zcu.comp.config.dll_export_fns) | |
| 4746 | global_index.setDllStorageClass(.default, &o.builder); | |
| 4747 | ||
| 4748 | if (decl.val.getVariable(zcu)) |decl_var| { | |
| 4749 | if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder); | |
| 4750 | } | |
| 4795 | 4751 | } |
| 4796 | 4752 | } |
| 4797 | 4753 | }; |
| ... | ... | @@ -5193,7 +5149,6 @@ pub const FuncGen = struct { |
| 5193 | 5149 | |
| 5194 | 5150 | const fqn = try decl.fullyQualifiedName(zcu); |
| 5195 | 5151 | |
| 5196 | const is_internal_linkage = !zcu.decl_exports.contains(decl_index); | |
| 5197 | 5152 | const fn_ty = try zcu.funcType(.{ |
| 5198 | 5153 | .param_types = &.{}, |
| 5199 | 5154 | .return_type = .void_type, |
| ... | ... | @@ -5211,7 +5166,7 @@ pub const FuncGen = struct { |
| 5211 | 5166 | .sp_flags = .{ |
| 5212 | 5167 | .Optimized = owner_mod.optimize_mode != .Debug, |
| 5213 | 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 | 5172 | o.debug_compile_unit, |
src/link.zig+6-6| ... | ... | @@ -606,12 +606,12 @@ pub const File = struct { |
| 606 | 606 | base: *File, |
| 607 | 607 | module: *Module, |
| 608 | 608 | exported: Module.Exported, |
| 609 | exports: []const *Module.Export, | |
| 609 | export_indices: []const u32, | |
| 610 | 610 | ) UpdateExportsError!void { |
| 611 | 611 | switch (base.tag) { |
| 612 | 612 | inline else => |tag| { |
| 613 | 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 | 671 | } |
| 672 | 672 | } |
| 673 | 673 | |
| 674 | pub fn deleteDeclExport( | |
| 674 | pub fn deleteExport( | |
| 675 | 675 | base: *File, |
| 676 | decl_index: InternPool.DeclIndex, | |
| 676 | exported: Zcu.Exported, | |
| 677 | 677 | name: InternPool.NullTerminatedString, |
| 678 | ) !void { | |
| 678 | ) void { | |
| 679 | 679 | if (build_options.only_c) @compileError("unreachable"); |
| 680 | 680 | switch (base.tag) { |
| 681 | 681 | .plan9, |
| ... | ... | @@ -685,7 +685,7 @@ pub const File = struct { |
| 685 | 685 | => {}, |
| 686 | 686 | |
| 687 | 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 | 183 | air: Air, |
| 184 | 184 | liveness: Liveness, |
| 185 | 185 | ) !void { |
| 186 | if (true) @panic("TODO jacobly"); | |
| 187 | ||
| 186 | 188 | const gpa = self.base.comp.gpa; |
| 187 | 189 | |
| 188 | 190 | const func = zcu.funcInfo(func_index); |
| ... | ... | @@ -250,6 +252,8 @@ pub fn updateFunc( |
| 250 | 252 | } |
| 251 | 253 | |
| 252 | 254 | fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void { |
| 255 | if (true) @panic("TODO jacobly"); | |
| 256 | ||
| 253 | 257 | const gpa = self.base.comp.gpa; |
| 254 | 258 | const anon_decl = self.anon_decls.keys()[i]; |
| 255 | 259 | |
| ... | ... | @@ -306,6 +310,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void { |
| 306 | 310 | } |
| 307 | 311 | |
| 308 | 312 | pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void { |
| 313 | if (true) @panic("TODO jacobly"); | |
| 314 | ||
| 309 | 315 | const tracy = trace(@src()); |
| 310 | 316 | defer tracy.end(); |
| 311 | 317 | |
| ... | ... | @@ -390,6 +396,8 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { |
| 390 | 396 | } |
| 391 | 397 | |
| 392 | 398 | pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void { |
| 399 | if (true) @panic("TODO jacobly"); | |
| 400 | ||
| 393 | 401 | _ = arena; // Has the same lifetime as the call to Compilation.update. |
| 394 | 402 | |
| 395 | 403 | const tracy = trace(@src()); |
| ... | ... | @@ -451,9 +459,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo |
| 451 | 459 | { |
| 452 | 460 | var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; |
| 453 | 461 | defer export_names.deinit(gpa); |
| 454 | try export_names.ensureTotalCapacity(gpa, @intCast(zcu.decl_exports.entries.len)); | |
| 455 | for (zcu.decl_exports.values()) |exports| for (exports.items) |@"export"| | |
| 456 | try export_names.put(gpa, @"export".opts.name, {}); | |
| 462 | try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count())); | |
| 463 | for (zcu.single_exports.values()) |export_idx| { | |
| 464 | export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {}); | |
| 465 | } | |
| 466 | for (zcu.multi_exports.values()) |info| { | |
| 467 | try export_names.ensureUnusedCapacity(info.len); | |
| 468 | for (zcu.all_exports.items[info.index..][0..info.len]) |export_idx| { | |
| 469 | export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {}); | |
| 470 | } | |
| 471 | } | |
| 457 | 472 | |
| 458 | 473 | for (self.anon_decls.values()) |*decl_block| { |
| 459 | 474 | try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none); |
| ... | ... | @@ -781,10 +796,10 @@ pub fn updateExports( |
| 781 | 796 | self: *C, |
| 782 | 797 | zcu: *Zcu, |
| 783 | 798 | exported: Zcu.Exported, |
| 784 | exports: []const *Zcu.Export, | |
| 799 | export_indices: []const u32, | |
| 785 | 800 | ) !void { |
| 786 | _ = exports; | |
| 787 | _ = exported; | |
| 788 | _ = zcu; | |
| 789 | 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 | 1162 | |
| 1163 | 1163 | try self.updateDeclCode(decl_index, code, .FUNCTION); |
| 1164 | 1164 | |
| 1165 | // Since we updated the vaddr and the size, each corresponding export | |
| 1166 | // symbol also needs to be updated. | |
| 1167 | return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 1165 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 1168 | 1166 | } |
| 1169 | 1167 | |
| 1170 | 1168 | pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 { |
| ... | ... | @@ -1286,9 +1284,7 @@ pub fn updateDecl( |
| 1286 | 1284 | |
| 1287 | 1285 | try self.updateDeclCode(decl_index, code, .NULL); |
| 1288 | 1286 | |
| 1289 | // Since we updated the vaddr and the size, each corresponding export | |
| 1290 | // symbol also needs to be updated. | |
| 1291 | return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 1287 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 1292 | 1288 | } |
| 1293 | 1289 | |
| 1294 | 1290 | fn updateLazySymbolAtom( |
| ... | ... | @@ -1509,7 +1505,7 @@ pub fn updateExports( |
| 1509 | 1505 | self: *Coff, |
| 1510 | 1506 | mod: *Module, |
| 1511 | 1507 | exported: Module.Exported, |
| 1512 | exports: []const *Module.Export, | |
| 1508 | export_indices: []const u32, | |
| 1513 | 1509 | ) link.File.UpdateExportsError!void { |
| 1514 | 1510 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1515 | 1511 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| ... | ... | @@ -1522,7 +1518,8 @@ pub fn updateExports( |
| 1522 | 1518 | if (comp.config.use_llvm) { |
| 1523 | 1519 | // Even in the case of LLVM, we need to notice certain exported symbols in order to |
| 1524 | 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 | 1523 | const exported_decl_index = switch (exp.exported) { |
| 1527 | 1524 | .decl_index => |i| i, |
| 1528 | 1525 | .value => continue, |
| ... | ... | @@ -1552,7 +1549,7 @@ pub fn updateExports( |
| 1552 | 1549 | } |
| 1553 | 1550 | } |
| 1554 | 1551 | |
| 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); | |
| 1556 | 1553 | |
| 1557 | 1554 | const gpa = comp.gpa; |
| 1558 | 1555 | |
| ... | ... | @@ -1562,7 +1559,7 @@ pub fn updateExports( |
| 1562 | 1559 | break :blk self.decls.getPtr(decl_index).?; |
| 1563 | 1560 | }, |
| 1564 | 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 | 1563 | const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod)); |
| 1567 | 1564 | switch (res) { |
| 1568 | 1565 | .ok => {}, |
| ... | ... | @@ -1570,7 +1567,7 @@ pub fn updateExports( |
| 1570 | 1567 | // TODO maybe it's enough to return an error here and let Module.processExportsInner |
| 1571 | 1568 | // handle the error? |
| 1572 | 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 | 1571 | return; |
| 1575 | 1572 | }, |
| 1576 | 1573 | } |
| ... | ... | @@ -1580,12 +1577,13 @@ pub fn updateExports( |
| 1580 | 1577 | const atom_index = metadata.atom; |
| 1581 | 1578 | const atom = self.getAtom(atom_index); |
| 1582 | 1579 | |
| 1583 | for (exports) |exp| { | |
| 1580 | for (export_indices) |export_idx| { | |
| 1581 | const exp = mod.all_exports.items[export_idx]; | |
| 1584 | 1582 | log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)}); |
| 1585 | 1583 | |
| 1586 | 1584 | if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| { |
| 1587 | 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 | 1587 | gpa, |
| 1590 | 1588 | exp.getSrcLoc(mod), |
| 1591 | 1589 | "Unimplemented: ExportOptions.section", |
| ... | ... | @@ -1596,7 +1594,7 @@ pub fn updateExports( |
| 1596 | 1594 | } |
| 1597 | 1595 | |
| 1598 | 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 | 1598 | gpa, |
| 1601 | 1599 | exp.getSrcLoc(mod), |
| 1602 | 1600 | "Unimplemented: GlobalLinkage.link_once", |
| ... | ... | @@ -1641,13 +1639,16 @@ pub fn updateExports( |
| 1641 | 1639 | } |
| 1642 | 1640 | } |
| 1643 | 1641 | |
| 1644 | pub fn deleteDeclExport( | |
| 1642 | pub fn deleteExport( | |
| 1645 | 1643 | self: *Coff, |
| 1646 | decl_index: InternPool.DeclIndex, | |
| 1644 | exported: Zcu.Exported, | |
| 1647 | 1645 | name: InternPool.NullTerminatedString, |
| 1648 | 1646 | ) void { |
| 1649 | 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 | 1652 | const mod = self.base.comp.module.?; |
| 1652 | 1653 | const name_slice = name.toSlice(&mod.intern_pool); |
| 1653 | 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 | 3011 | self: *Elf, |
| 3012 | 3012 | mod: *Module, |
| 3013 | 3013 | exported: Module.Exported, |
| 3014 | exports: []const *Module.Export, | |
| 3014 | export_indices: []const u32, | |
| 3015 | 3015 | ) link.File.UpdateExportsError!void { |
| 3016 | 3016 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 3017 | 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); | |
| 3020 | return self.zigObjectPtr().?.updateExports(self, mod, exported, exports); | |
| 3019 | if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices); | |
| 3020 | return self.zigObjectPtr().?.updateExports(self, mod, exported, export_indices); | |
| 3021 | 3021 | } |
| 3022 | 3022 | |
| 3023 | 3023 | pub 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 | 3025 | return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index); |
| 3026 | 3026 | } |
| 3027 | 3027 | |
| 3028 | pub fn deleteDeclExport( | |
| 3028 | pub fn deleteExport( | |
| 3029 | 3029 | self: *Elf, |
| 3030 | decl_index: InternPool.DeclIndex, | |
| 3030 | exported: Zcu.Exported, | |
| 3031 | 3031 | name: InternPool.NullTerminatedString, |
| 3032 | 3032 | ) void { |
| 3033 | 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 | } |
| 3036 | 3036 | |
| 3037 | 3037 | fn addLinkerDefinedSymbols(self: *Elf) !void { |
src/link/Elf/ZigObject.zig+15-15| ... | ... | @@ -1115,9 +1115,7 @@ pub fn updateFunc( |
| 1115 | 1115 | ); |
| 1116 | 1116 | } |
| 1117 | 1117 | |
| 1118 | // Since we updated the vaddr and the size, each corresponding export | |
| 1119 | // symbol also needs to be updated. | |
| 1120 | return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 1118 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 1121 | 1119 | } |
| 1122 | 1120 | |
| 1123 | 1121 | pub fn updateDecl( |
| ... | ... | @@ -1194,9 +1192,7 @@ pub fn updateDecl( |
| 1194 | 1192 | ); |
| 1195 | 1193 | } |
| 1196 | 1194 | |
| 1197 | // Since we updated the vaddr and the size, each corresponding export | |
| 1198 | // symbol also needs to be updated. | |
| 1199 | return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 1195 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 1200 | 1196 | } |
| 1201 | 1197 | |
| 1202 | 1198 | fn updateLazySymbol( |
| ... | ... | @@ -1386,7 +1382,7 @@ pub fn updateExports( |
| 1386 | 1382 | elf_file: *Elf, |
| 1387 | 1383 | mod: *Module, |
| 1388 | 1384 | exported: Module.Exported, |
| 1389 | exports: []const *Module.Export, | |
| 1385 | export_indices: []const u32, | |
| 1390 | 1386 | ) link.File.UpdateExportsError!void { |
| 1391 | 1387 | const tracy = trace(@src()); |
| 1392 | 1388 | defer tracy.end(); |
| ... | ... | @@ -1398,7 +1394,7 @@ pub fn updateExports( |
| 1398 | 1394 | break :blk self.decls.getPtr(decl_index).?; |
| 1399 | 1395 | }, |
| 1400 | 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 | 1398 | const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod)); |
| 1403 | 1399 | switch (res) { |
| 1404 | 1400 | .ok => {}, |
| ... | ... | @@ -1406,7 +1402,7 @@ pub fn updateExports( |
| 1406 | 1402 | // TODO maybe it's enough to return an error here and let Module.processExportsInner |
| 1407 | 1403 | // handle the error? |
| 1408 | 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 | 1406 | return; |
| 1411 | 1407 | }, |
| 1412 | 1408 | } |
| ... | ... | @@ -1418,11 +1414,12 @@ pub fn updateExports( |
| 1418 | 1414 | const esym = self.local_esyms.items(.elf_sym)[esym_index]; |
| 1419 | 1415 | const esym_shndx = self.local_esyms.items(.shndx)[esym_index]; |
| 1420 | 1416 | |
| 1421 | for (exports) |exp| { | |
| 1417 | for (export_indices) |export_idx| { | |
| 1418 | const exp = mod.all_exports.items[export_idx]; | |
| 1422 | 1419 | if (exp.opts.section.unwrap()) |section_name| { |
| 1423 | 1420 | if (!section_name.eqlSlice(".text", &mod.intern_pool)) { |
| 1424 | 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 | 1423 | gpa, |
| 1427 | 1424 | exp.getSrcLoc(mod), |
| 1428 | 1425 | "Unimplemented: ExportOptions.section", |
| ... | ... | @@ -1437,7 +1434,7 @@ pub fn updateExports( |
| 1437 | 1434 | .weak => elf.STB_WEAK, |
| 1438 | 1435 | .link_once => { |
| 1439 | 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 | 1438 | gpa, |
| 1442 | 1439 | exp.getSrcLoc(mod), |
| 1443 | 1440 | "Unimplemented: GlobalLinkage.LinkOnce", |
| ... | ... | @@ -1487,13 +1484,16 @@ pub fn updateDeclLineNumber( |
| 1487 | 1484 | } |
| 1488 | 1485 | } |
| 1489 | 1486 | |
| 1490 | pub fn deleteDeclExport( | |
| 1487 | pub fn deleteExport( | |
| 1491 | 1488 | self: *ZigObject, |
| 1492 | 1489 | elf_file: *Elf, |
| 1493 | decl_index: InternPool.DeclIndex, | |
| 1490 | exported: Zcu.Exported, | |
| 1494 | 1491 | name: InternPool.NullTerminatedString, |
| 1495 | 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 | 1497 | const mod = elf_file.base.comp.module.?; |
| 1498 | 1498 | const exp_name = name.toSlice(&mod.intern_pool); |
| 1499 | 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 | 3196 | self: *MachO, |
| 3197 | 3197 | mod: *Module, |
| 3198 | 3198 | exported: Module.Exported, |
| 3199 | exports: []const *Module.Export, | |
| 3199 | export_indices: []const u32, | |
| 3200 | 3200 | ) link.File.UpdateExportsError!void { |
| 3201 | 3201 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 3202 | 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); | |
| 3205 | return self.getZigObject().?.updateExports(self, mod, exported, exports); | |
| 3204 | if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices); | |
| 3205 | return self.getZigObject().?.updateExports(self, mod, exported, export_indices); | |
| 3206 | 3206 | } |
| 3207 | 3207 | |
| 3208 | pub fn deleteDeclExport( | |
| 3208 | pub fn deleteExport( | |
| 3209 | 3209 | self: *MachO, |
| 3210 | decl_index: InternPool.DeclIndex, | |
| 3210 | exported: Zcu.Exported, | |
| 3211 | 3211 | name: InternPool.NullTerminatedString, |
| 3212 | ) Allocator.Error!void { | |
| 3212 | ) void { | |
| 3213 | 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 | } |
| 3216 | 3216 | |
| 3217 | 3217 | pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void { |
src/link/MachO/ZigObject.zig+15-15| ... | ... | @@ -713,9 +713,7 @@ pub fn updateFunc( |
| 713 | 713 | ); |
| 714 | 714 | } |
| 715 | 715 | |
| 716 | // Since we updated the vaddr and the size, each corresponding export | |
| 717 | // symbol also needs to be updated. | |
| 718 | return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 716 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 719 | 717 | } |
| 720 | 718 | |
| 721 | 719 | pub fn updateDecl( |
| ... | ... | @@ -790,9 +788,7 @@ pub fn updateDecl( |
| 790 | 788 | ); |
| 791 | 789 | } |
| 792 | 790 | |
| 793 | // Since we updated the vaddr and the size, each corresponding export symbol also | |
| 794 | // needs to be updated. | |
| 795 | try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); | |
| 791 | // Exports will be updated by `Zcu.processExports` after the update. | |
| 796 | 792 | } |
| 797 | 793 | |
| 798 | 794 | fn updateDeclCode( |
| ... | ... | @@ -1187,7 +1183,7 @@ pub fn updateExports( |
| 1187 | 1183 | macho_file: *MachO, |
| 1188 | 1184 | mod: *Module, |
| 1189 | 1185 | exported: Module.Exported, |
| 1190 | exports: []const *Module.Export, | |
| 1186 | export_indices: []const u32, | |
| 1191 | 1187 | ) link.File.UpdateExportsError!void { |
| 1192 | 1188 | const tracy = trace(@src()); |
| 1193 | 1189 | defer tracy.end(); |
| ... | ... | @@ -1199,7 +1195,7 @@ pub fn updateExports( |
| 1199 | 1195 | break :blk self.decls.getPtr(decl_index).?; |
| 1200 | 1196 | }, |
| 1201 | 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 | 1199 | const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod)); |
| 1204 | 1200 | switch (res) { |
| 1205 | 1201 | .ok => {}, |
| ... | ... | @@ -1207,7 +1203,7 @@ pub fn updateExports( |
| 1207 | 1203 | // TODO maybe it's enough to return an error here and let Module.processExportsInner |
| 1208 | 1204 | // handle the error? |
| 1209 | 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 | 1207 | return; |
| 1212 | 1208 | }, |
| 1213 | 1209 | } |
| ... | ... | @@ -1218,11 +1214,12 @@ pub fn updateExports( |
| 1218 | 1214 | const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx; |
| 1219 | 1215 | const nlist = self.symtab.items(.nlist)[nlist_idx]; |
| 1220 | 1216 | |
| 1221 | for (exports) |exp| { | |
| 1217 | for (export_indices) |export_idx| { | |
| 1218 | const exp = mod.all_exports.items[export_idx]; | |
| 1222 | 1219 | if (exp.opts.section.unwrap()) |section_name| { |
| 1223 | 1220 | if (!section_name.eqlSlice("__text", &mod.intern_pool)) { |
| 1224 | 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 | 1223 | gpa, |
| 1227 | 1224 | exp.getSrcLoc(mod), |
| 1228 | 1225 | "Unimplemented: ExportOptions.section", |
| ... | ... | @@ -1232,7 +1229,7 @@ pub fn updateExports( |
| 1232 | 1229 | } |
| 1233 | 1230 | } |
| 1234 | 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 | 1233 | gpa, |
| 1237 | 1234 | exp.getSrcLoc(mod), |
| 1238 | 1235 | "Unimplemented: GlobalLinkage.link_once", |
| ... | ... | @@ -1364,15 +1361,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo |
| 1364 | 1361 | } |
| 1365 | 1362 | } |
| 1366 | 1363 | |
| 1367 | pub fn deleteDeclExport( | |
| 1364 | pub fn deleteExport( | |
| 1368 | 1365 | self: *ZigObject, |
| 1369 | 1366 | macho_file: *MachO, |
| 1370 | decl_index: InternPool.DeclIndex, | |
| 1367 | exported: Zcu.Exported, | |
| 1371 | 1368 | name: InternPool.NullTerminatedString, |
| 1372 | 1369 | ) void { |
| 1373 | 1370 | const mod = macho_file.base.comp.module.?; |
| 1374 | 1371 | |
| 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 | 1376 | const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return; |
| 1377 | 1377 | |
| 1378 | 1378 | log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)}); |
src/link/NvPtx.zig+2-2| ... | ... | @@ -96,12 +96,12 @@ pub fn updateExports( |
| 96 | 96 | self: *NvPtx, |
| 97 | 97 | module: *Module, |
| 98 | 98 | exported: Module.Exported, |
| 99 | exports: []const *Module.Export, | |
| 99 | export_indices: []const u32, | |
| 100 | 100 | ) !void { |
| 101 | 101 | if (build_options.skip_non_native and builtin.object_format != .nvptx) |
| 102 | 102 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 103 | 103 | |
| 104 | return self.llvm_object.updateExports(module, exported, exports); | |
| 104 | return self.llvm_object.updateExports(module, exported, export_indices); | |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | pub 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 | 60 | ) = .{}, |
| 61 | 61 | /// the code is modified when relocated, so that is why it is mutable |
| 62 | 62 | data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{}, |
| 63 | /// When `updateExports` is called, we store the export indices here, to be used | |
| 64 | /// during flush. | |
| 65 | decl_exports: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u32) = .{}, | |
| 63 | 66 | |
| 64 | 67 | /// Table of unnamed constants associated with a parent `Decl`. |
| 65 | 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 | 773 | mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); |
| 771 | 774 | } |
| 772 | 775 | self.syms.items[atom.sym_index.?].value = off; |
| 773 | if (mod.decl_exports.get(decl_index)) |exports| { | |
| 774 | try self.addDeclExports(mod, decl_index, exports.items); | |
| 776 | if (self.decl_exports.get(decl_index)) |export_indices| { | |
| 777 | try self.addDeclExports(mod, decl_index, export_indices); | |
| 775 | 778 | } |
| 776 | 779 | } |
| 777 | 780 | } |
| ... | ... | @@ -836,8 +839,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node) |
| 836 | 839 | mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); |
| 837 | 840 | } |
| 838 | 841 | self.syms.items[atom.sym_index.?].value = off; |
| 839 | if (mod.decl_exports.get(decl_index)) |exports| { | |
| 840 | try self.addDeclExports(mod, decl_index, exports.items); | |
| 842 | if (self.decl_exports.get(decl_index)) |export_indices| { | |
| 843 | try self.addDeclExports(mod, decl_index, export_indices); | |
| 841 | 844 | } |
| 842 | 845 | } |
| 843 | 846 | // write the unnamed constants after the other data decls |
| ... | ... | @@ -1007,20 +1010,21 @@ fn addDeclExports( |
| 1007 | 1010 | self: *Plan9, |
| 1008 | 1011 | mod: *Module, |
| 1009 | 1012 | decl_index: InternPool.DeclIndex, |
| 1010 | exports: []const *Module.Export, | |
| 1013 | export_indices: []const u32, | |
| 1011 | 1014 | ) !void { |
| 1012 | 1015 | const gpa = self.base.comp.gpa; |
| 1013 | 1016 | const metadata = self.decls.getPtr(decl_index).?; |
| 1014 | 1017 | const atom = self.getAtom(metadata.index); |
| 1015 | 1018 | |
| 1016 | for (exports) |exp| { | |
| 1019 | for (export_indices) |export_idx| { | |
| 1020 | const exp = mod.all_exports.items[export_idx]; | |
| 1017 | 1021 | const exp_name = exp.opts.name.toSlice(&mod.intern_pool); |
| 1018 | 1022 | // plan9 does not support custom sections |
| 1019 | 1023 | if (exp.opts.section.unwrap()) |section_name| { |
| 1020 | 1024 | if (!section_name.eqlSlice(".text", &mod.intern_pool) and |
| 1021 | 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 | 1028 | gpa, |
| 1025 | 1029 | mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod), |
| 1026 | 1030 | "plan9 does not support extra sections", |
| ... | ... | @@ -1152,15 +1156,23 @@ pub fn updateExports( |
| 1152 | 1156 | self: *Plan9, |
| 1153 | 1157 | module: *Module, |
| 1154 | 1158 | exported: Module.Exported, |
| 1155 | exports: []const *Module.Export, | |
| 1159 | export_indices: []const u32, | |
| 1156 | 1160 | ) !void { |
| 1161 | const gpa = self.base.comp.gpa; | |
| 1157 | 1162 | switch (exported) { |
| 1158 | 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 flush | |
| 1174 | // all proper work is done in flush | |
| 1162 | 1175 | _ = module; |
| 1163 | _ = exports; | |
| 1164 | 1176 | } |
| 1165 | 1177 | |
| 1166 | 1178 | pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index { |
| ... | ... | @@ -1290,6 +1302,10 @@ pub fn deinit(self: *Plan9) void { |
| 1290 | 1302 | gpa.free(self.syms.items[sym_index].name); |
| 1291 | 1303 | } |
| 1292 | 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 | 1309 | self.syms.deinit(gpa); |
| 1294 | 1310 | self.got_index_free_list.deinit(gpa); |
| 1295 | 1311 | self.syms_index_free_list.deinit(gpa); |
| ... | ... | @@ -1395,10 +1411,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1395 | 1411 | const atom = self.getAtom(decl_metadata.index); |
| 1396 | 1412 | const sym = self.syms.items[atom.sym_index.?]; |
| 1397 | 1413 | try self.writeSym(writer, sym); |
| 1398 | if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| { | |
| 1399 | for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| { | |
| 1400 | try self.writeSym(writer, self.syms.items[exp_i]); | |
| 1401 | }; | |
| 1414 | if (self.decl_exports.get(decl_index)) |export_indices| { | |
| 1415 | for (export_indices) |export_idx| { | |
| 1416 | const exp = mod.all_exports.items[export_idx]; | |
| 1417 | if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { | |
| 1418 | try self.writeSym(writer, self.syms.items[exp_i]); | |
| 1419 | } | |
| 1420 | } | |
| 1402 | 1421 | } |
| 1403 | 1422 | } |
| 1404 | 1423 | } |
| ... | ... | @@ -1442,13 +1461,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1442 | 1461 | const atom = self.getAtom(decl_metadata.index); |
| 1443 | 1462 | const sym = self.syms.items[atom.sym_index.?]; |
| 1444 | 1463 | try self.writeSym(writer, sym); |
| 1445 | if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| { | |
| 1446 | for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| { | |
| 1447 | const s = self.syms.items[exp_i]; | |
| 1448 | if (mem.eql(u8, s.name, "_start")) | |
| 1449 | self.entry_val = s.value; | |
| 1450 | try self.writeSym(writer, s); | |
| 1451 | }; | |
| 1464 | if (self.decl_exports.get(decl_index)) |export_indices| { | |
| 1465 | for (export_indices) |export_idx| { | |
| 1466 | const exp = mod.all_exports.items[export_idx]; | |
| 1467 | if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { | |
| 1468 | const s = self.syms.items[exp_i]; | |
| 1469 | if (mem.eql(u8, s.name, "_start")) | |
| 1470 | self.entry_val = s.value; | |
| 1471 | try self.writeSym(writer, s); | |
| 1472 | } | |
| 1473 | } | |
| 1452 | 1474 | } |
| 1453 | 1475 | } |
| 1454 | 1476 | } |
src/link/SpirV.zig+3-2| ... | ... | @@ -152,7 +152,7 @@ pub fn updateExports( |
| 152 | 152 | self: *SpirV, |
| 153 | 153 | mod: *Module, |
| 154 | 154 | exported: Module.Exported, |
| 155 | exports: []const *Module.Export, | |
| 155 | export_indices: []const u32, | |
| 156 | 156 | ) !void { |
| 157 | 157 | const decl_index = switch (exported) { |
| 158 | 158 | .decl_index => |i| i, |
| ... | ... | @@ -177,7 +177,8 @@ pub fn updateExports( |
| 177 | 177 | if ((!is_vulkan and execution_model == .Kernel) or |
| 178 | 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 | 182 | try self.object.spv.declareEntryPoint( |
| 182 | 183 | spv_decl_index, |
| 183 | 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 | 1542 | return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info); |
| 1543 | 1543 | } |
| 1544 | 1544 | |
| 1545 | pub fn deleteDeclExport( | |
| 1545 | pub fn deleteExport( | |
| 1546 | 1546 | wasm: *Wasm, |
| 1547 | decl_index: InternPool.DeclIndex, | |
| 1547 | exported: Zcu.Exported, | |
| 1548 | 1548 | name: InternPool.NullTerminatedString, |
| 1549 | 1549 | ) void { |
| 1550 | 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 | } |
| 1553 | 1553 | |
| 1554 | 1554 | pub fn updateExports( |
| 1555 | 1555 | wasm: *Wasm, |
| 1556 | 1556 | mod: *Module, |
| 1557 | 1557 | exported: Module.Exported, |
| 1558 | exports: []const *Module.Export, | |
| 1558 | export_indices: []const u32, | |
| 1559 | 1559 | ) !void { |
| 1560 | 1560 | if (build_options.skip_non_native and builtin.object_format != .wasm) { |
| 1561 | 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); | |
| 1564 | return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, exports); | |
| 1563 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices); | |
| 1564 | return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, export_indices); | |
| 1565 | 1565 | } |
| 1566 | 1566 | |
| 1567 | 1567 | pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { |
src/link/Wasm/ZigObject.zig+11-6| ... | ... | @@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr( |
| 833 | 833 | return target_symbol_index; |
| 834 | 834 | } |
| 835 | 835 | |
| 836 | pub fn deleteDeclExport( | |
| 836 | pub fn deleteExport( | |
| 837 | 837 | zig_object: *ZigObject, |
| 838 | 838 | wasm_file: *Wasm, |
| 839 | decl_index: InternPool.DeclIndex, | |
| 839 | exported: Zcu.Exported, | |
| 840 | 840 | name: InternPool.NullTerminatedString, |
| 841 | 841 | ) void { |
| 842 | 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 | 847 | const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return; |
| 844 | 848 | if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| { |
| 845 | 849 | const sym = zig_object.symbol(sym_index); |
| ... | ... | @@ -856,7 +860,7 @@ pub fn updateExports( |
| 856 | 860 | wasm_file: *Wasm, |
| 857 | 861 | mod: *Module, |
| 858 | 862 | exported: Module.Exported, |
| 859 | exports: []const *Module.Export, | |
| 863 | export_indices: []const u32, | |
| 860 | 864 | ) !void { |
| 861 | 865 | const decl_index = switch (exported) { |
| 862 | 866 | .decl_index => |i| i, |
| ... | ... | @@ -873,9 +877,10 @@ pub fn updateExports( |
| 873 | 877 | const gpa = mod.gpa; |
| 874 | 878 | log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)}); |
| 875 | 879 | |
| 876 | for (exports) |exp| { | |
| 880 | for (export_indices) |export_idx| { | |
| 881 | const exp = mod.all_exports.items[export_idx]; | |
| 877 | 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 | 884 | gpa, |
| 880 | 885 | decl.navSrcLoc(mod).upgrade(mod), |
| 881 | 886 | "Unimplemented: ExportOptions.section '{s}'", |
| ... | ... | @@ -908,7 +913,7 @@ pub fn updateExports( |
| 908 | 913 | }, |
| 909 | 914 | .strong => {}, // symbols are strong by default |
| 910 | 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 | 917 | gpa, |
| 913 | 918 | decl.navSrcLoc(mod).upgrade(mod), |
| 914 | 919 | "Unimplemented: LinkOnce", |