mirror of
https://github.com/ziglang/zig.git
synced 2025-01-25 11:21:02 +00:00
Zcu: rework exports
This commit reworks our representation of exported Decls and values in Zcu to be memory-optimized and trivially serialized. All exports are now stored in the `all_exports` array on `Zcu`. An `AnalUnit` which performs an export (either through an `export` annotation or by containing an analyzed `@export`) gains an entry into `single_exports` if it performs only one export, or `multi_exports` if it performs multiple. We no longer store a persistent mapping from a `Decl`/value to all exports of that entity; this state is not necessary for the majority of the pipeline. Instead, we construct it in `Zcu.processExports`, just before flush. This does not affect the algorithmic complexity of `processExports`, since this function already iterates all exports in the `Zcu`. The elimination of `decl_exports` and `value_exports` led to a few non-trivial backend changes. The LLVM backend has been wrangled into a more reasonable state in general regarding exports and externs. The C backend is currently disabled in this commit, because its support for `export` was quite broken, and that was exposed by this work -- I'm hoping @jacobly0 will be able to pick this up!
This commit is contained in:
parent
bc8cd13598
commit
7e552dc1e9
114
src/Sema.zig
114
src/Sema.zig
@ -117,6 +117,10 @@ maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAll
|
||||
/// Backed by gpa.
|
||||
comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{},
|
||||
|
||||
/// A list of exports performed by this analysis. After this `Sema` terminates,
|
||||
/// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`.
|
||||
exports: std.ArrayListUnmanaged(Zcu.Export) = .{},
|
||||
|
||||
const MaybeComptimeAlloc = struct {
|
||||
/// The runtime index of the `alloc` instruction.
|
||||
runtime_index: Value.RuntimeIndex,
|
||||
@ -186,6 +190,7 @@ const build_options = @import("build_options");
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const InternPool = @import("InternPool.zig");
|
||||
const Alignment = InternPool.Alignment;
|
||||
const AnalUnit = InternPool.AnalUnit;
|
||||
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
|
||||
|
||||
pub const default_branch_quota = 1000;
|
||||
@ -875,6 +880,7 @@ pub fn deinit(sema: *Sema) void {
|
||||
sema.base_allocs.deinit(gpa);
|
||||
sema.maybe_comptime_allocs.deinit(gpa);
|
||||
sema.comptime_allocs.deinit(gpa);
|
||||
sema.exports.deinit(gpa);
|
||||
sema.* = undefined;
|
||||
}
|
||||
|
||||
@ -2735,12 +2741,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
|
||||
if (!zcu.comp.debug_incremental) return false;
|
||||
|
||||
const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
|
||||
const decl_as_depender = InternPool.AnalUnit.wrap(.{ .decl = decl_index });
|
||||
const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
|
||||
const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
|
||||
zcu.potentially_outdated.swapRemove(decl_as_depender);
|
||||
if (!was_outdated) return false;
|
||||
_ = zcu.outdated_ready.swapRemove(decl_as_depender);
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
zcu.intern_pool.remove(ty);
|
||||
zcu.declPtr(decl_index).analysis = .dependency_failure;
|
||||
try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
|
||||
@ -2834,7 +2840,7 @@ fn zirStructDecl(
|
||||
if (sema.mod.comp.debug_incremental) {
|
||||
try ip.addDependency(
|
||||
sema.gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
.{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
|
||||
);
|
||||
}
|
||||
@ -3068,7 +3074,7 @@ fn zirEnumDecl(
|
||||
if (sema.mod.comp.debug_incremental) {
|
||||
try mod.intern_pool.addDependency(
|
||||
sema.gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
.{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
|
||||
);
|
||||
}
|
||||
@ -3334,7 +3340,7 @@ fn zirUnionDecl(
|
||||
if (sema.mod.comp.debug_incremental) {
|
||||
try mod.intern_pool.addDependency(
|
||||
sema.gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
.{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
|
||||
);
|
||||
}
|
||||
@ -3422,7 +3428,7 @@ fn zirOpaqueDecl(
|
||||
if (sema.mod.comp.debug_incremental) {
|
||||
try ip.addDependency(
|
||||
gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
AnalUnit.wrap(.{ .decl = new_decl_index }),
|
||||
.{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
|
||||
);
|
||||
}
|
||||
@ -6423,10 +6429,9 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
return sema.analyzeExport(block, src, options, decl_index);
|
||||
}
|
||||
|
||||
try addExport(mod, .{
|
||||
try sema.exports.append(mod.gpa, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.owner_decl = sema.owner_decl_index,
|
||||
.exported = .{ .value = operand.toIntern() },
|
||||
.status = .in_progress,
|
||||
});
|
||||
@ -6469,46 +6474,14 @@ pub fn analyzeExport(
|
||||
|
||||
try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
|
||||
|
||||
try addExport(mod, .{
|
||||
try sema.exports.append(gpa, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.owner_decl = sema.owner_decl_index,
|
||||
.exported = .{ .decl_index = exported_decl_index },
|
||||
.status = .in_progress,
|
||||
});
|
||||
}
|
||||
|
||||
fn addExport(mod: *Module, export_init: Module.Export) error{OutOfMemory}!void {
|
||||
const gpa = mod.gpa;
|
||||
|
||||
try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
|
||||
try mod.value_exports.ensureUnusedCapacity(gpa, 1);
|
||||
try mod.export_owners.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const new_export = try gpa.create(Module.Export);
|
||||
errdefer gpa.destroy(new_export);
|
||||
|
||||
new_export.* = export_init;
|
||||
|
||||
const eo_gop = mod.export_owners.getOrPutAssumeCapacity(export_init.owner_decl);
|
||||
if (!eo_gop.found_existing) eo_gop.value_ptr.* = .{};
|
||||
try eo_gop.value_ptr.append(gpa, new_export);
|
||||
errdefer _ = eo_gop.value_ptr.pop();
|
||||
|
||||
switch (export_init.exported) {
|
||||
.decl_index => |decl_index| {
|
||||
const de_gop = mod.decl_exports.getOrPutAssumeCapacity(decl_index);
|
||||
if (!de_gop.found_existing) de_gop.value_ptr.* = .{};
|
||||
try de_gop.value_ptr.append(gpa, new_export);
|
||||
},
|
||||
.value => |value| {
|
||||
const ve_gop = mod.value_exports.getOrPutAssumeCapacity(value);
|
||||
if (!ve_gop.found_existing) ve_gop.value_ptr.* = .{};
|
||||
try ve_gop.value_ptr.append(gpa, new_export);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
|
||||
const mod = sema.mod;
|
||||
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
@ -8411,6 +8384,9 @@ fn instantiateGenericCall(
|
||||
});
|
||||
sema.appendRefsAssumeCapacity(runtime_args.items);
|
||||
|
||||
// `child_sema` is owned by us, so just take its exports.
|
||||
try sema.exports.appendSlice(sema.gpa, child_sema.exports.items);
|
||||
|
||||
if (ensure_result_used) {
|
||||
try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
|
||||
}
|
||||
@ -35263,6 +35239,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
|
||||
const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
|
||||
struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
|
||||
}
|
||||
|
||||
try sema.flushExports();
|
||||
}
|
||||
|
||||
fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
|
||||
@ -36225,6 +36203,8 @@ fn semaStructFields(
|
||||
|
||||
struct_type.clearTypesWip(ip);
|
||||
if (!any_inits) struct_type.setHaveFieldInits(ip);
|
||||
|
||||
try sema.flushExports();
|
||||
}
|
||||
|
||||
// This logic must be kept in sync with `semaStructFields`
|
||||
@ -36365,6 +36345,8 @@ fn semaStructFieldInits(
|
||||
struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
|
||||
}
|
||||
}
|
||||
|
||||
try sema.flushExports();
|
||||
}
|
||||
|
||||
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
|
||||
const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
|
||||
union_type.tagTypePtr(ip).* = enum_ty;
|
||||
}
|
||||
|
||||
try sema.flushExports();
|
||||
}
|
||||
|
||||
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 {
|
||||
return;
|
||||
}
|
||||
|
||||
const depender = InternPool.AnalUnit.wrap(
|
||||
const depender = AnalUnit.wrap(
|
||||
if (sema.owner_func_index != .none)
|
||||
.{ .func = sema.owner_func_index }
|
||||
else
|
||||
@ -38494,6 +38478,52 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check:
|
||||
}
|
||||
}
|
||||
|
||||
/// This should be called exactly once, at the end of a `Sema`'s lifetime.
|
||||
/// It takes the exports stored in `sema.export` and flushes them to the `Zcu`
|
||||
/// to be processed by the linker after the update.
|
||||
pub fn flushExports(sema: *Sema) !void {
|
||||
if (sema.exports.items.len == 0) return;
|
||||
|
||||
const zcu = sema.mod;
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const unit: AnalUnit = if (sema.owner_func_index != .none)
|
||||
AnalUnit.wrap(.{ .func = sema.owner_func_index })
|
||||
else
|
||||
AnalUnit.wrap(.{ .decl = sema.owner_decl_index });
|
||||
|
||||
// There may be existing exports. For instance, a struct may export
|
||||
// things during both field type resolution and field default resolution.
|
||||
//
|
||||
// So, pick up and delete any existing exports. This strategy performs
|
||||
// redundant work, but that's okay, because this case is exceedingly rare.
|
||||
if (zcu.single_exports.get(unit)) |export_idx| {
|
||||
try sema.exports.append(gpa, zcu.all_exports.items[export_idx]);
|
||||
} else if (zcu.multi_exports.get(unit)) |info| {
|
||||
try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
|
||||
}
|
||||
zcu.deleteUnitExports(unit);
|
||||
|
||||
// `sema.exports` is completed; store the data into the `Zcu`.
|
||||
if (sema.exports.items.len == 1) {
|
||||
try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const export_idx = zcu.free_exports.popOrNull() orelse idx: {
|
||||
_ = try zcu.all_exports.addOne(gpa);
|
||||
break :idx zcu.all_exports.items.len - 1;
|
||||
};
|
||||
zcu.all_exports.items[export_idx] = sema.exports.items[0];
|
||||
zcu.single_exports.putAssumeCapacityNoClobber(unit, @intCast(export_idx));
|
||||
} else {
|
||||
try zcu.multi_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const exports_base = zcu.all_exports.items.len;
|
||||
try zcu.all_exports.appendSlice(gpa, sema.exports.items);
|
||||
zcu.multi_exports.putAssumeCapacityNoClobber(unit, .{
|
||||
.index = @intCast(exports_base),
|
||||
.len = @intCast(sema.exports.items.len),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
|
||||
pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
|
||||
|
||||
|
307
src/Zcu.zig
307
src/Zcu.zig
@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir;
|
||||
const clang = @import("clang.zig");
|
||||
const InternPool = @import("InternPool.zig");
|
||||
const Alignment = InternPool.Alignment;
|
||||
const AnalUnit = InternPool.AnalUnit;
|
||||
const BuiltinFn = std.zig.BuiltinFn;
|
||||
const LlvmObject = @import("codegen/llvm.zig").Object;
|
||||
|
||||
@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined,
|
||||
global_zir_cache: Compilation.Directory,
|
||||
/// Used by AstGen worker to load and store ZIR cache.
|
||||
local_zir_cache: Compilation.Directory,
|
||||
/// It's rare for a decl to be exported, so we save memory by having a sparse
|
||||
/// map of Decl indexes to details about them being exported.
|
||||
/// The Export memory is owned by the `export_owners` table; the slice itself
|
||||
/// is owned by this table. The slice is guaranteed to not be empty.
|
||||
decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
|
||||
/// Same as `decl_exports` but for exported constant values.
|
||||
value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
|
||||
/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
|
||||
/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
|
||||
/// is performing the export of another Decl.
|
||||
/// This table owns the Export memory.
|
||||
export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
|
||||
/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
|
||||
/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
|
||||
all_exports: ArrayListUnmanaged(Export) = .{},
|
||||
/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
|
||||
/// future semantic analysis.
|
||||
free_exports: ArrayListUnmanaged(u32) = .{},
|
||||
/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
|
||||
/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
|
||||
/// whose analysis triggered the export.
|
||||
single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
|
||||
/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
|
||||
/// The exports are `all_exports.items[index..][0..len]`.
|
||||
multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
|
||||
index: u32,
|
||||
len: u32,
|
||||
}) = .{},
|
||||
/// The set of all the Zig source files in the Module. We keep track of this in order
|
||||
/// to iterate over it and check which source files have been modified on the file system when
|
||||
/// an update is requested, as well as to cache `@import` results.
|
||||
@ -126,9 +131,8 @@ compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
|
||||
failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
|
||||
/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
|
||||
failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
|
||||
/// Using a map here for consistency with the other fields here.
|
||||
/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
|
||||
failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
|
||||
/// Key is index into `all_exports`.
|
||||
failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{},
|
||||
/// If a decl failed due to a cimport error, the corresponding Clang errors
|
||||
/// are stored here.
|
||||
cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},
|
||||
@ -140,14 +144,14 @@ global_error_set: GlobalErrorSet = .{},
|
||||
error_limit: ErrorInt,
|
||||
|
||||
/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
|
||||
potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{},
|
||||
potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
|
||||
/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
|
||||
/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
|
||||
outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, u32) = .{},
|
||||
outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
|
||||
/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
|
||||
/// Such `AnalUnit`s are ready for immediate re-analysis.
|
||||
/// See `findOutdatedToAnalyze` for details.
|
||||
outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, void) = .{},
|
||||
outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
|
||||
/// This contains a set of Decls which may not be in `outdated`, but are the
|
||||
/// root Decls of files which have updated source and thus must be re-analyzed.
|
||||
/// 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) = .{},
|
||||
/// failure was something like running out of disk space, and trying again may
|
||||
/// succeed. On the next update, we will flush this list, marking all members of
|
||||
/// it as outdated.
|
||||
retryable_failures: std.ArrayListUnmanaged(InternPool.AnalUnit) = .{},
|
||||
retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{},
|
||||
|
||||
stage1_flags: packed struct {
|
||||
have_winmain: bool = false,
|
||||
@ -267,8 +271,6 @@ pub const Exported = union(enum) {
|
||||
pub const Export = struct {
|
||||
opts: Options,
|
||||
src: LazySrcLoc,
|
||||
/// The Decl that performs the export. Note that this is *not* the Decl being exported.
|
||||
owner_decl: Decl.Index,
|
||||
exported: Exported,
|
||||
status: enum {
|
||||
in_progress,
|
||||
@ -2507,20 +2509,10 @@ pub fn deinit(zcu: *Zcu) void {
|
||||
|
||||
zcu.compile_log_decls.deinit(gpa);
|
||||
|
||||
for (zcu.decl_exports.values()) |*export_list| {
|
||||
export_list.deinit(gpa);
|
||||
}
|
||||
zcu.decl_exports.deinit(gpa);
|
||||
|
||||
for (zcu.value_exports.values()) |*export_list| {
|
||||
export_list.deinit(gpa);
|
||||
}
|
||||
zcu.value_exports.deinit(gpa);
|
||||
|
||||
for (zcu.export_owners.values()) |*value| {
|
||||
freeExportList(gpa, value);
|
||||
}
|
||||
zcu.export_owners.deinit(gpa);
|
||||
zcu.all_exports.deinit(gpa);
|
||||
zcu.free_exports.deinit(gpa);
|
||||
zcu.single_exports.deinit(gpa);
|
||||
zcu.multi_exports.deinit(gpa);
|
||||
|
||||
zcu.global_error_set.deinit(gpa);
|
||||
|
||||
@ -2590,11 +2582,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
|
||||
return decl_index == namespace.decl_index;
|
||||
}
|
||||
|
||||
fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void {
|
||||
for (export_list.items) |exp| gpa.destroy(exp);
|
||||
export_list.deinit(gpa);
|
||||
}
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/8643
|
||||
const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
|
||||
const HackDataLayout = extern struct {
|
||||
@ -3139,7 +3126,7 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
|
||||
|
||||
/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
|
||||
/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
|
||||
fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.AnalUnit) !void {
|
||||
fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
|
||||
var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
|
||||
.decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
|
||||
.func => |func_index| .{ .func_ies = func_index },
|
||||
@ -3166,7 +3153,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP
|
||||
}
|
||||
}
|
||||
|
||||
pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
|
||||
pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
if (!zcu.comp.debug_incremental) return null;
|
||||
|
||||
if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
|
||||
@ -3197,7 +3184,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
|
||||
// `outdated`. This set will be small (number of files changed in this
|
||||
// update), so it's alright for us to just iterate here.
|
||||
for (zcu.outdated_file_root.keys()) |file_decl| {
|
||||
const decl_depender = InternPool.AnalUnit.wrap(.{ .decl = file_decl });
|
||||
const decl_depender = AnalUnit.wrap(.{ .decl = file_decl });
|
||||
if (zcu.outdated.contains(decl_depender)) {
|
||||
// Since we didn't hit this in the first loop, this Decl must have
|
||||
// pending dependencies, so is ineligible.
|
||||
@ -3271,7 +3258,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalUnit {
|
||||
chosen_decl_dependers,
|
||||
});
|
||||
|
||||
return InternPool.AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
|
||||
return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
// which tries to limit re-analysis to Decls whose previously listed
|
||||
// dependencies are all up-to-date.
|
||||
|
||||
const decl_as_depender = InternPool.AnalUnit.wrap(.{ .decl = decl_index });
|
||||
const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
|
||||
const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
|
||||
mod.potentially_outdated.swapRemove(decl_as_depender);
|
||||
|
||||
@ -3485,7 +3472,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
|
||||
// The exports this Decl performs will be re-discovered, so we remove them here
|
||||
// prior to re-analysis.
|
||||
if (build_options.only_c) unreachable;
|
||||
try mod.deleteDeclExports(decl_index);
|
||||
mod.deleteUnitExports(AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
}
|
||||
|
||||
const sema_result: SemaDeclResult = blk: {
|
||||
@ -3522,7 +3509,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
|
||||
else => |e| {
|
||||
decl.analysis = .sema_failure;
|
||||
try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
|
||||
try mod.retryable_failures.append(mod.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
try mod.retryable_failures.append(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
|
||||
mod.gpa,
|
||||
decl.navSrcLoc(mod).upgrade(mod),
|
||||
@ -3581,7 +3568,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
|
||||
// that's the case, we should remove this function from the binary.
|
||||
if (decl.val.ip_index != func_index) {
|
||||
try zcu.markDependeeOutdated(.{ .func_ies = func_index });
|
||||
ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
|
||||
ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
|
||||
ip.remove(func_index);
|
||||
@panic("TODO: remove orphaned function from binary");
|
||||
}
|
||||
@ -3607,12 +3594,14 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
|
||||
.complete => {},
|
||||
}
|
||||
|
||||
const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index });
|
||||
const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
|
||||
const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
|
||||
zcu.potentially_outdated.swapRemove(func_as_depender);
|
||||
|
||||
if (was_outdated) {
|
||||
if (build_options.only_c) unreachable;
|
||||
_ = zcu.outdated_ready.swapRemove(func_as_depender);
|
||||
zcu.deleteUnitExports(AnalUnit.wrap(.{ .func = func_index }));
|
||||
}
|
||||
|
||||
switch (func.analysis(ip).state) {
|
||||
@ -3728,16 +3717,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
|
||||
.{@errorName(err)},
|
||||
));
|
||||
func.analysis(ip).state = .codegen_failure;
|
||||
try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
|
||||
try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
|
||||
},
|
||||
};
|
||||
} else if (zcu.llvm_object) |llvm_object| {
|
||||
if (build_options.only_c) unreachable;
|
||||
llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => {
|
||||
func.analysis(ip).state = .codegen_failure;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -3773,7 +3759,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
|
||||
|
||||
assert(decl.has_tv);
|
||||
|
||||
const func_as_depender = InternPool.AnalUnit.wrap(.{ .func = func_index });
|
||||
const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
|
||||
const is_outdated = mod.outdated.contains(func_as_depender) or
|
||||
mod.potentially_outdated.contains(func_as_depender);
|
||||
|
||||
@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
|
||||
if (zcu.comp.debug_incremental) {
|
||||
try ip.addDependency(
|
||||
gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
|
||||
AnalUnit.wrap(.{ .decl = decl_index }),
|
||||
.{ .src_hash = tracked_inst },
|
||||
);
|
||||
}
|
||||
@ -3906,7 +3892,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
|
||||
|
||||
if (type_outdated) {
|
||||
// Invalidate the existing type, reusing the decl and namespace.
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = file.root_decl.unwrap().? }));
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = file.root_decl.unwrap().? }));
|
||||
zcu.intern_pool.remove(decl.val.toIntern());
|
||||
decl.val = undefined;
|
||||
_ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
|
||||
@ -4097,7 +4083,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
|
||||
break :ip_index .none;
|
||||
};
|
||||
|
||||
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
|
||||
decl.analysis = .in_progress;
|
||||
|
||||
@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
|
||||
try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
|
||||
}
|
||||
|
||||
try sema.flushExports();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
|
||||
// with a new Decl.
|
||||
//
|
||||
// Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
zcu.intern_pool.remove(decl.val.toIntern());
|
||||
decl.analysis = .dependency_failure;
|
||||
return .{
|
||||
@ -4949,63 +4937,44 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete all the Export objects that are caused by this Decl. Re-analysis of
|
||||
/// this Decl will cause them to be re-created (or not).
|
||||
fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
|
||||
var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
|
||||
/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
|
||||
/// this `AnalUnit` will cause them to be re-created (or not).
|
||||
pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
for (export_owners.items) |exp| {
|
||||
switch (exp.exported) {
|
||||
.decl_index => |exported_decl_index| {
|
||||
if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
|
||||
// Remove exports with owner_decl matching the regenerating decl.
|
||||
const list = export_list.items;
|
||||
var i: usize = 0;
|
||||
var new_len = list.len;
|
||||
while (i < new_len) {
|
||||
if (list[i].owner_decl == decl_index) {
|
||||
mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
|
||||
new_len -= 1;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
export_list.shrinkAndFree(mod.gpa, new_len);
|
||||
if (new_len == 0) {
|
||||
assert(mod.decl_exports.swapRemove(exported_decl_index));
|
||||
}
|
||||
}
|
||||
},
|
||||
.value => |value| {
|
||||
if (mod.value_exports.getPtr(value)) |export_list| {
|
||||
// Remove exports with owner_decl matching the regenerating decl.
|
||||
const list = export_list.items;
|
||||
var i: usize = 0;
|
||||
var new_len = list.len;
|
||||
while (i < new_len) {
|
||||
if (list[i].owner_decl == decl_index) {
|
||||
mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
|
||||
new_len -= 1;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
export_list.shrinkAndFree(mod.gpa, new_len);
|
||||
if (new_len == 0) {
|
||||
assert(mod.value_exports.swapRemove(value));
|
||||
}
|
||||
}
|
||||
},
|
||||
const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
|
||||
.{ kv.value, 1 }
|
||||
else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
|
||||
.{ info.value.index, info.value.len }
|
||||
else
|
||||
return;
|
||||
|
||||
const exports = zcu.all_exports.items[exports_base..][0..exports_len];
|
||||
|
||||
// In an only-c build, we're guaranteed to never use incremental compilation, so there are
|
||||
// guaranteed not to be any exports in the output file that need deleting (since we only call
|
||||
// `updateExports` on flush).
|
||||
// This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
|
||||
// within a single update.
|
||||
if (!build_options.only_c) {
|
||||
for (exports, exports_base..) |exp, export_idx| {
|
||||
if (zcu.comp.bin_file) |lf| {
|
||||
lf.deleteExport(exp.exported, exp.opts.name);
|
||||
}
|
||||
if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
|
||||
failed_kv.value.destroy(gpa);
|
||||
}
|
||||
}
|
||||
if (mod.comp.bin_file) |lf| {
|
||||
try lf.deleteDeclExport(decl_index, exp.opts.name);
|
||||
}
|
||||
if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
|
||||
failed_kv.value.destroy(mod.gpa);
|
||||
}
|
||||
mod.gpa.destroy(exp);
|
||||
}
|
||||
export_owners.deinit(mod.gpa);
|
||||
|
||||
zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
|
||||
// This space will be reused eventually, so we need not propagate this error.
|
||||
// Just leak it for now, and let GC reclaim it later on.
|
||||
return;
|
||||
};
|
||||
for (exports_base..exports_base + exports_len) |export_idx| {
|
||||
zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
|
||||
defer decl_prog_node.end();
|
||||
|
||||
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
|
||||
mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
|
||||
|
||||
var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
|
||||
defer comptime_err_ret_trace.deinit();
|
||||
@ -5262,6 +5231,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
|
||||
};
|
||||
}
|
||||
|
||||
try sema.flushExports();
|
||||
|
||||
return .{
|
||||
.instructions = sema.air_instructions.toOwnedSlice(),
|
||||
.extra = try sema.air_extra.toOwnedSlice(gpa),
|
||||
@ -5392,33 +5363,89 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
|
||||
/// Called from `Compilation.update`, after everything is done, just before
|
||||
/// reporting compile errors. In this function we emit exported symbol collision
|
||||
/// errors and communicate exported symbols to the linker backend.
|
||||
pub fn processExports(mod: *Module) !void {
|
||||
// Map symbol names to `Export` for name collision detection.
|
||||
var symbol_exports: SymbolExports = .{};
|
||||
defer symbol_exports.deinit(mod.gpa);
|
||||
pub fn processExports(zcu: *Zcu) !void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
|
||||
const exported: Exported = .{ .decl_index = exported_decl };
|
||||
try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
|
||||
// First, construct a mapping of every exported value and Decl to the indices of all its different exports.
|
||||
var decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(u32)) = .{};
|
||||
var value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(u32)) = .{};
|
||||
defer {
|
||||
for (decl_exports.values()) |*exports| {
|
||||
exports.deinit(gpa);
|
||||
}
|
||||
decl_exports.deinit(gpa);
|
||||
for (value_exports.values()) |*exports| {
|
||||
exports.deinit(gpa);
|
||||
}
|
||||
value_exports.deinit(gpa);
|
||||
}
|
||||
|
||||
for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
|
||||
// We note as a heuristic:
|
||||
// * It is rare to export a value.
|
||||
// * It is rare for one Decl to be exported multiple times.
|
||||
// So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization.
|
||||
try decl_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count());
|
||||
|
||||
for (zcu.single_exports.values()) |export_idx| {
|
||||
const exp = zcu.all_exports.items[export_idx];
|
||||
const value_ptr, const found_existing = switch (exp.exported) {
|
||||
.decl_index => |i| gop: {
|
||||
const gop = try decl_exports.getOrPut(gpa, i);
|
||||
break :gop .{ gop.value_ptr, gop.found_existing };
|
||||
},
|
||||
.value => |i| gop: {
|
||||
const gop = try value_exports.getOrPut(gpa, i);
|
||||
break :gop .{ gop.value_ptr, gop.found_existing };
|
||||
},
|
||||
};
|
||||
if (!found_existing) value_ptr.* = .{};
|
||||
try value_ptr.append(gpa, export_idx);
|
||||
}
|
||||
|
||||
for (zcu.multi_exports.values()) |info| {
|
||||
for (zcu.all_exports.items[info.index..][0..info.len], info.index..) |exp, export_idx| {
|
||||
const value_ptr, const found_existing = switch (exp.exported) {
|
||||
.decl_index => |i| gop: {
|
||||
const gop = try decl_exports.getOrPut(gpa, i);
|
||||
break :gop .{ gop.value_ptr, gop.found_existing };
|
||||
},
|
||||
.value => |i| gop: {
|
||||
const gop = try value_exports.getOrPut(gpa, i);
|
||||
break :gop .{ gop.value_ptr, gop.found_existing };
|
||||
},
|
||||
};
|
||||
if (!found_existing) value_ptr.* = .{};
|
||||
try value_ptr.append(gpa, @intCast(export_idx));
|
||||
}
|
||||
}
|
||||
|
||||
// Map symbol names to `Export` for name collision detection.
|
||||
var symbol_exports: SymbolExports = .{};
|
||||
defer symbol_exports.deinit(gpa);
|
||||
|
||||
for (decl_exports.keys(), decl_exports.values()) |exported_decl, exports_list| {
|
||||
const exported: Exported = .{ .decl_index = exported_decl };
|
||||
try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
|
||||
}
|
||||
|
||||
for (value_exports.keys(), value_exports.values()) |exported_value, exports_list| {
|
||||
const exported: Exported = .{ .value = exported_value };
|
||||
try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
|
||||
try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
|
||||
}
|
||||
}
|
||||
|
||||
const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
|
||||
const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
|
||||
|
||||
fn processExportsInner(
|
||||
zcu: *Zcu,
|
||||
symbol_exports: *SymbolExports,
|
||||
exported: Exported,
|
||||
exports: []const *Export,
|
||||
export_indices: []const u32,
|
||||
) error{OutOfMemory}!void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
for (exports) |new_export| {
|
||||
for (export_indices) |export_idx| {
|
||||
const new_export = &zcu.all_exports.items[export_idx];
|
||||
const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
|
||||
if (gop.found_existing) {
|
||||
new_export.status = .failed_retryable;
|
||||
@ -5428,40 +5455,41 @@ fn processExportsInner(
|
||||
new_export.opts.name.fmt(&zcu.intern_pool),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
const other_export = gop.value_ptr.*;
|
||||
const other_export = zcu.all_exports.items[gop.value_ptr.*];
|
||||
const other_src_loc = other_export.getSrcLoc(zcu);
|
||||
try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
|
||||
new_export.status = .failed;
|
||||
} else {
|
||||
gop.value_ptr.* = new_export;
|
||||
gop.value_ptr.* = export_idx;
|
||||
}
|
||||
}
|
||||
if (zcu.comp.bin_file) |lf| {
|
||||
try handleUpdateExports(zcu, exports, lf.updateExports(zcu, exported, exports));
|
||||
try handleUpdateExports(zcu, export_indices, lf.updateExports(zcu, exported, export_indices));
|
||||
} else if (zcu.llvm_object) |llvm_object| {
|
||||
if (build_options.only_c) unreachable;
|
||||
try handleUpdateExports(zcu, exports, llvm_object.updateExports(zcu, exported, exports));
|
||||
try handleUpdateExports(zcu, export_indices, llvm_object.updateExports(zcu, exported, export_indices));
|
||||
}
|
||||
}
|
||||
|
||||
fn handleUpdateExports(
|
||||
zcu: *Zcu,
|
||||
exports: []const *Export,
|
||||
export_indices: []const u32,
|
||||
result: link.File.UpdateExportsError!void,
|
||||
) Allocator.Error!void {
|
||||
const gpa = zcu.gpa;
|
||||
result catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => {
|
||||
const new_export = exports[0];
|
||||
const export_idx = export_indices[0];
|
||||
const new_export = &zcu.all_exports.items[export_idx];
|
||||
new_export.status = .failed_retryable;
|
||||
try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const src_loc = new_export.getSrcLoc(zcu);
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
|
||||
@errorName(err),
|
||||
});
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -5627,16 +5655,13 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
|
||||
.{@errorName(err)},
|
||||
));
|
||||
decl.analysis = .codegen_failure;
|
||||
try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
|
||||
},
|
||||
};
|
||||
} else if (zcu.llvm_object) |llvm_object| {
|
||||
if (build_options.only_c) unreachable;
|
||||
llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => {
|
||||
decl.analysis = .codegen_failure;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -5684,14 +5709,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
|
||||
if (mod.decl_exports.get(decl_index)) |l| {
|
||||
return l.items;
|
||||
} else {
|
||||
return &[0]*Export{};
|
||||
}
|
||||
}
|
||||
|
||||
pub const Feature = enum {
|
||||
panic_fn,
|
||||
panic_unwrap_error,
|
||||
|
@ -3081,6 +3081,8 @@ pub fn genDeclValue(
|
||||
}
|
||||
|
||||
pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
|
||||
if (true) @panic("TODO jacobly");
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
|
@ -848,10 +848,6 @@ pub const Object = struct {
|
||||
/// Note that the values are not added until `emit`, when all errors in
|
||||
/// the compilation are known.
|
||||
error_name_table: Builder.Variable.Index,
|
||||
/// This map is usually very close to empty. It tracks only the cases when a
|
||||
/// second extern Decl could not be emitted with the correct name due to a
|
||||
/// name collision.
|
||||
extern_collisions: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, void),
|
||||
|
||||
/// Memoizes a null `?usize` value.
|
||||
null_opt_usize: Builder.Constant,
|
||||
@ -1011,7 +1007,6 @@ pub const Object = struct {
|
||||
.named_enum_map = .{},
|
||||
.type_map = .{},
|
||||
.error_name_table = .none,
|
||||
.extern_collisions = .{},
|
||||
.null_opt_usize = .no_init,
|
||||
.struct_field_map = .{},
|
||||
};
|
||||
@ -1029,7 +1024,6 @@ pub const Object = struct {
|
||||
self.anon_decl_map.deinit(gpa);
|
||||
self.named_enum_map.deinit(gpa);
|
||||
self.type_map.deinit(gpa);
|
||||
self.extern_collisions.deinit(gpa);
|
||||
self.builder.deinit();
|
||||
self.struct_field_map.deinit(gpa);
|
||||
self.* = undefined;
|
||||
@ -1121,61 +1115,6 @@ pub const Object = struct {
|
||||
try object.builder.finishModuleAsm();
|
||||
}
|
||||
|
||||
fn resolveExportExternCollisions(object: *Object) !void {
|
||||
const mod = object.module;
|
||||
|
||||
// This map has externs with incorrect symbol names.
|
||||
for (object.extern_collisions.keys()) |decl_index| {
|
||||
const global = object.decl_map.get(decl_index) orelse continue;
|
||||
// Same logic as below but for externs instead of exports.
|
||||
const decl_name = object.builder.strtabStringIfExists(mod.declPtr(decl_index).name.toSlice(&mod.intern_pool)) orelse continue;
|
||||
const other_global = object.builder.getGlobal(decl_name) orelse continue;
|
||||
if (other_global.toConst().getBase(&object.builder) ==
|
||||
global.toConst().getBase(&object.builder)) continue;
|
||||
|
||||
try global.replace(other_global, &object.builder);
|
||||
}
|
||||
object.extern_collisions.clearRetainingCapacity();
|
||||
|
||||
for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
|
||||
const global = object.decl_map.get(decl_index) orelse continue;
|
||||
try resolveGlobalCollisions(object, global, export_list.items);
|
||||
}
|
||||
|
||||
for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
|
||||
const global = object.anon_decl_map.get(val) orelse continue;
|
||||
try resolveGlobalCollisions(object, global, export_list.items);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveGlobalCollisions(
|
||||
object: *Object,
|
||||
global: Builder.Global.Index,
|
||||
export_list: []const *Module.Export,
|
||||
) !void {
|
||||
const mod = object.module;
|
||||
const global_base = global.toConst().getBase(&object.builder);
|
||||
for (export_list) |exp| {
|
||||
// Detect if the LLVM global has already been created as an extern. In such
|
||||
// case, we need to replace all uses of it with this exported global.
|
||||
const exp_name = object.builder.strtabStringIfExists(exp.opts.name.toSlice(&mod.intern_pool)) orelse continue;
|
||||
|
||||
const other_global = object.builder.getGlobal(exp_name) orelse continue;
|
||||
if (other_global.toConst().getBase(&object.builder) == global_base) continue;
|
||||
|
||||
try global.takeName(other_global, &object.builder);
|
||||
try other_global.replace(global, &object.builder);
|
||||
// Problem: now we need to replace in the decl_map that
|
||||
// the extern decl index points to this new global. However we don't
|
||||
// know the decl index.
|
||||
// Even if we did, a future incremental update to the extern would then
|
||||
// treat the LLVM global as an extern rather than an export, so it would
|
||||
// need a way to check that.
|
||||
// This is a TODO that needs to be solved when making
|
||||
// the LLVM backend support incremental compilation.
|
||||
}
|
||||
}
|
||||
|
||||
pub const EmitOptions = struct {
|
||||
pre_ir_path: ?[]const u8,
|
||||
pre_bc_path: ?[]const u8,
|
||||
@ -1193,7 +1132,6 @@ pub const Object = struct {
|
||||
|
||||
pub fn emit(self: *Object, options: EmitOptions) !void {
|
||||
{
|
||||
try self.resolveExportExternCollisions();
|
||||
try self.genErrorNameTable();
|
||||
try self.genCmpLtErrorsLenFunction();
|
||||
try self.genModuleLevelAssembly();
|
||||
@ -1698,8 +1636,7 @@ pub const Object = struct {
|
||||
const file = try o.getDebugFile(namespace.file_scope);
|
||||
|
||||
const line_number = decl.navSrcLine(zcu) + 1;
|
||||
const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
|
||||
!zcu.decl_exports.contains(decl_index);
|
||||
const is_internal_linkage = decl.val.getExternFunc(zcu) == null;
|
||||
const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));
|
||||
|
||||
const subprogram = try o.builder.debugSubprogram(
|
||||
@ -1760,8 +1697,6 @@ pub const Object = struct {
|
||||
};
|
||||
|
||||
try fg.wip.finish();
|
||||
|
||||
try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
|
||||
@ -1781,66 +1716,25 @@ pub const Object = struct {
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
self: *Object,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| return updateExportedValue(self, mod, val, exports),
|
||||
.value => |val| return updateExportedValue(self, mod, val, export_indices),
|
||||
};
|
||||
const gpa = mod.gpa;
|
||||
const ip = &mod.intern_pool;
|
||||
// If the module does not already have the function, we ignore this function call
|
||||
// because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
|
||||
const global_index = self.decl_map.get(decl_index) orelse return;
|
||||
const global_index = self.decl_map.get(decl_index).?;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const comp = mod.comp;
|
||||
if (decl.isExtern(mod)) {
|
||||
const decl_name = decl_name: {
|
||||
if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) {
|
||||
if (decl.getOwnedExternFunc(mod).?.lib_name.toSlice(ip)) |lib_name| {
|
||||
if (!std.mem.eql(u8, lib_name, "c")) {
|
||||
break :decl_name try self.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
|
||||
}
|
||||
}
|
||||
}
|
||||
break :decl_name try self.builder.strtabString(decl.name.toSlice(ip));
|
||||
};
|
||||
|
||||
if (self.builder.getGlobal(decl_name)) |other_global| {
|
||||
if (other_global != global_index) {
|
||||
try self.extern_collisions.put(gpa, decl_index, {});
|
||||
}
|
||||
}
|
||||
|
||||
try global_index.rename(decl_name, &self.builder);
|
||||
global_index.setLinkage(.external, &self.builder);
|
||||
global_index.setUnnamedAddr(.default, &self.builder);
|
||||
if (comp.config.dll_export_fns)
|
||||
global_index.setDllStorageClass(.default, &self.builder);
|
||||
|
||||
if (decl.val.getVariable(mod)) |decl_var| {
|
||||
global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
|
||||
if (decl_var.is_threadlocal) .generaldynamic else .default,
|
||||
&self.builder,
|
||||
);
|
||||
if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder);
|
||||
}
|
||||
} else if (exports.len != 0) {
|
||||
const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip));
|
||||
try global_index.rename(main_exp_name, &self.builder);
|
||||
|
||||
if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
|
||||
global_index.ptrConst(&self.builder).kind
|
||||
.variable.setThreadLocal(.generaldynamic, &self.builder);
|
||||
|
||||
return updateExportedGlobal(self, mod, global_index, exports);
|
||||
if (export_indices.len != 0) {
|
||||
return updateExportedGlobal(self, mod, global_index, export_indices);
|
||||
} else {
|
||||
const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
|
||||
try global_index.rename(fqn, &self.builder);
|
||||
@ -1848,17 +1742,6 @@ pub const Object = struct {
|
||||
if (comp.config.dll_export_fns)
|
||||
global_index.setDllStorageClass(.default, &self.builder);
|
||||
global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
|
||||
if (decl.val.getVariable(mod)) |decl_var| {
|
||||
const decl_namespace = mod.namespacePtr(decl.src_namespace);
|
||||
const single_threaded = decl_namespace.file_scope.mod.single_threaded;
|
||||
global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
|
||||
if (decl_var.is_threadlocal and !single_threaded)
|
||||
.generaldynamic
|
||||
else
|
||||
.default,
|
||||
&self.builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1866,11 +1749,11 @@ pub const Object = struct {
|
||||
o: *Object,
|
||||
mod: *Module,
|
||||
exported_value: InternPool.Index,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const gpa = mod.gpa;
|
||||
const ip = &mod.intern_pool;
|
||||
const main_exp_name = try o.builder.strtabString(exports[0].opts.name.toSlice(ip));
|
||||
const main_exp_name = try o.builder.strtabString(mod.all_exports.items[export_indices[0]].opts.name.toSlice(ip));
|
||||
const global_index = i: {
|
||||
const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
|
||||
if (gop.found_existing) {
|
||||
@ -1894,32 +1777,57 @@ pub const Object = struct {
|
||||
try variable_index.setInitializer(init_val, &o.builder);
|
||||
break :i global_index;
|
||||
};
|
||||
return updateExportedGlobal(o, mod, global_index, exports);
|
||||
return updateExportedGlobal(o, mod, global_index, export_indices);
|
||||
}
|
||||
|
||||
fn updateExportedGlobal(
|
||||
o: *Object,
|
||||
mod: *Module,
|
||||
global_index: Builder.Global.Index,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const comp = mod.comp;
|
||||
const ip = &mod.intern_pool;
|
||||
const first_export = mod.all_exports.items[export_indices[0]];
|
||||
|
||||
// We will rename this global to have a name matching `first_export`.
|
||||
// Successive exports become aliases.
|
||||
// If the first export name already exists, then there is a corresponding
|
||||
// extern global - we replace it with this global.
|
||||
const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip));
|
||||
if (o.builder.getGlobal(first_exp_name)) |other_global| replace: {
|
||||
if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) {
|
||||
break :replace; // this global already has the name we want
|
||||
}
|
||||
try global_index.takeName(other_global, &o.builder);
|
||||
try other_global.replace(global_index, &o.builder);
|
||||
// Problem: now we need to replace in the decl_map that
|
||||
// the extern decl index points to this new global. However we don't
|
||||
// know the decl index.
|
||||
// Even if we did, a future incremental update to the extern would then
|
||||
// treat the LLVM global as an extern rather than an export, so it would
|
||||
// need a way to check that.
|
||||
// This is a TODO that needs to be solved when making
|
||||
// the LLVM backend support incremental compilation.
|
||||
} else {
|
||||
try global_index.rename(first_exp_name, &o.builder);
|
||||
}
|
||||
|
||||
global_index.setUnnamedAddr(.default, &o.builder);
|
||||
if (comp.config.dll_export_fns)
|
||||
global_index.setDllStorageClass(.dllexport, &o.builder);
|
||||
global_index.setLinkage(switch (exports[0].opts.linkage) {
|
||||
global_index.setLinkage(switch (first_export.opts.linkage) {
|
||||
.internal => unreachable,
|
||||
.strong => .external,
|
||||
.weak => .weak_odr,
|
||||
.link_once => .linkonce_odr,
|
||||
}, &o.builder);
|
||||
global_index.setVisibility(switch (exports[0].opts.visibility) {
|
||||
global_index.setVisibility(switch (first_export.opts.visibility) {
|
||||
.default => .default,
|
||||
.hidden => .hidden,
|
||||
.protected => .protected,
|
||||
}, &o.builder);
|
||||
if (exports[0].opts.section.toSlice(ip)) |section|
|
||||
if (first_export.opts.section.toSlice(ip)) |section|
|
||||
switch (global_index.ptrConst(&o.builder).kind) {
|
||||
.variable => |impl_index| impl_index.setSection(
|
||||
try o.builder.string(section),
|
||||
@ -1936,7 +1844,8 @@ pub const Object = struct {
|
||||
// The planned solution to this is https://github.com/ziglang/zig/issues/13265
|
||||
// Until then we iterate over existing aliases and make them point
|
||||
// to the correct decl, or otherwise add a new alias. Old aliases are leaked.
|
||||
for (exports[1..]) |exp| {
|
||||
for (export_indices[1..]) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
|
||||
if (o.builder.getGlobal(exp_name)) |global| {
|
||||
switch (global.ptrConst(&o.builder).kind) {
|
||||
@ -1944,7 +1853,13 @@ pub const Object = struct {
|
||||
alias.setAliasee(global_index.toConst(), &o.builder);
|
||||
continue;
|
||||
},
|
||||
.variable, .function => {},
|
||||
.variable, .function => {
|
||||
// This existing global is an `extern` corresponding to this export.
|
||||
// Replace it with the global being exported.
|
||||
// This existing global must be replaced with the alias.
|
||||
try global.rename(.empty, &o.builder);
|
||||
try global.replace(global_index, &o.builder);
|
||||
},
|
||||
.replaced => unreachable,
|
||||
}
|
||||
}
|
||||
@ -4762,36 +4677,77 @@ pub const DeclGen = struct {
|
||||
else => try o.lowerValue(init_val),
|
||||
}, &o.builder);
|
||||
|
||||
if (decl.val.getVariable(zcu)) |decl_var| {
|
||||
const decl_namespace = zcu.namespacePtr(decl.src_namespace);
|
||||
const single_threaded = decl_namespace.file_scope.mod.single_threaded;
|
||||
variable_index.setThreadLocal(
|
||||
if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default,
|
||||
&o.builder,
|
||||
);
|
||||
}
|
||||
|
||||
const line_number = decl.navSrcLine(zcu) + 1;
|
||||
const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
|
||||
|
||||
const namespace = zcu.namespacePtr(decl.src_namespace);
|
||||
const owner_mod = namespace.file_scope.mod;
|
||||
|
||||
if (owner_mod.strip) return;
|
||||
if (!owner_mod.strip) {
|
||||
const debug_file = try o.getDebugFile(namespace.file_scope);
|
||||
|
||||
const debug_file = try o.getDebugFile(namespace.file_scope);
|
||||
const debug_global_var = try o.builder.debugGlobalVar(
|
||||
try o.builder.metadataString(decl.name.toSlice(ip)), // Name
|
||||
try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
|
||||
debug_file, // File
|
||||
debug_file, // Scope
|
||||
line_number,
|
||||
try o.lowerDebugType(decl.typeOf(zcu)),
|
||||
variable_index,
|
||||
.{ .local = !decl.isExtern(zcu) },
|
||||
);
|
||||
|
||||
const debug_global_var = try o.builder.debugGlobalVar(
|
||||
try o.builder.metadataString(decl.name.toSlice(ip)), // Name
|
||||
try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
|
||||
debug_file, // File
|
||||
debug_file, // Scope
|
||||
line_number,
|
||||
try o.lowerDebugType(decl.typeOf(zcu)),
|
||||
variable_index,
|
||||
.{ .local = is_internal_linkage },
|
||||
);
|
||||
const debug_expression = try o.builder.debugExpression(&.{});
|
||||
|
||||
const debug_expression = try o.builder.debugExpression(&.{});
|
||||
const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
|
||||
debug_global_var,
|
||||
debug_expression,
|
||||
);
|
||||
|
||||
const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
|
||||
debug_global_var,
|
||||
debug_expression,
|
||||
);
|
||||
variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
|
||||
try o.debug_globals.append(o.gpa, debug_global_var_expression);
|
||||
}
|
||||
}
|
||||
|
||||
variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
|
||||
try o.debug_globals.append(o.gpa, debug_global_var_expression);
|
||||
if (decl.isExtern(zcu)) {
|
||||
const global_index = o.decl_map.get(decl_index).?;
|
||||
|
||||
const decl_name = decl_name: {
|
||||
if (zcu.getTarget().isWasm() and decl.typeOf(zcu).zigTypeTag(zcu) == .Fn) {
|
||||
if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| {
|
||||
if (!std.mem.eql(u8, lib_name, "c")) {
|
||||
break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
|
||||
}
|
||||
}
|
||||
}
|
||||
break :decl_name try o.builder.strtabString(decl.name.toSlice(ip));
|
||||
};
|
||||
|
||||
if (o.builder.getGlobal(decl_name)) |other_global| {
|
||||
if (other_global != global_index) {
|
||||
// Another global already has this name; just use it in place of this global.
|
||||
try global_index.replace(other_global, &o.builder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try global_index.rename(decl_name, &o.builder);
|
||||
global_index.setLinkage(.external, &o.builder);
|
||||
global_index.setUnnamedAddr(.default, &o.builder);
|
||||
if (zcu.comp.config.dll_export_fns)
|
||||
global_index.setDllStorageClass(.default, &o.builder);
|
||||
|
||||
if (decl.val.getVariable(zcu)) |decl_var| {
|
||||
if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -5193,7 +5149,6 @@ pub const FuncGen = struct {
|
||||
|
||||
const fqn = try decl.fullyQualifiedName(zcu);
|
||||
|
||||
const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
|
||||
const fn_ty = try zcu.funcType(.{
|
||||
.param_types = &.{},
|
||||
.return_type = .void_type,
|
||||
@ -5211,7 +5166,7 @@ pub const FuncGen = struct {
|
||||
.sp_flags = .{
|
||||
.Optimized = owner_mod.optimize_mode != .Debug,
|
||||
.Definition = true,
|
||||
.LocalToUnit = is_internal_linkage,
|
||||
.LocalToUnit = true, // TODO: we can't know this at this point, since the function could be exported later!
|
||||
},
|
||||
},
|
||||
o.debug_compile_unit,
|
||||
|
12
src/link.zig
12
src/link.zig
@ -606,12 +606,12 @@ pub const File = struct {
|
||||
base: *File,
|
||||
module: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) UpdateExportsError!void {
|
||||
switch (base.tag) {
|
||||
inline else => |tag| {
|
||||
if (tag != .c and build_options.only_c) unreachable;
|
||||
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, exports);
|
||||
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, export_indices);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -671,11 +671,11 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
base: *File,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) !void {
|
||||
) void {
|
||||
if (build_options.only_c) @compileError("unreachable");
|
||||
switch (base.tag) {
|
||||
.plan9,
|
||||
@ -685,7 +685,7 @@ pub const File = struct {
|
||||
=> {},
|
||||
|
||||
inline else => |tag| {
|
||||
return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteDeclExport(decl_index, name);
|
||||
return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteExport(exported, name);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +183,8 @@ pub fn updateFunc(
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
) !void {
|
||||
if (true) @panic("TODO jacobly");
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
const func = zcu.funcInfo(func_index);
|
||||
@ -250,6 +252,8 @@ pub fn updateFunc(
|
||||
}
|
||||
|
||||
fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
|
||||
if (true) @panic("TODO jacobly");
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const anon_decl = self.anon_decls.keys()[i];
|
||||
|
||||
@ -306,6 +310,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
|
||||
if (true) @panic("TODO jacobly");
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -390,6 +396,8 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
|
||||
if (true) @panic("TODO jacobly");
|
||||
|
||||
_ = arena; // Has the same lifetime as the call to Compilation.update.
|
||||
|
||||
const tracy = trace(@src());
|
||||
@ -451,9 +459,16 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
|
||||
{
|
||||
var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
|
||||
defer export_names.deinit(gpa);
|
||||
try export_names.ensureTotalCapacity(gpa, @intCast(zcu.decl_exports.entries.len));
|
||||
for (zcu.decl_exports.values()) |exports| for (exports.items) |@"export"|
|
||||
try export_names.put(gpa, @"export".opts.name, {});
|
||||
try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
|
||||
for (zcu.single_exports.values()) |export_idx| {
|
||||
export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
|
||||
}
|
||||
for (zcu.multi_exports.values()) |info| {
|
||||
try export_names.ensureUnusedCapacity(info.len);
|
||||
for (zcu.all_exports.items[info.index..][0..info.len]) |export_idx| {
|
||||
export_names.putAssumeCapacity(gpa, zcu.all_exports.items[export_idx].opts.name, {});
|
||||
}
|
||||
}
|
||||
|
||||
for (self.anon_decls.values()) |*decl_block| {
|
||||
try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);
|
||||
@ -781,10 +796,10 @@ pub fn updateExports(
|
||||
self: *C,
|
||||
zcu: *Zcu,
|
||||
exported: Zcu.Exported,
|
||||
exports: []const *Zcu.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
_ = exports;
|
||||
_ = exported;
|
||||
_ = zcu;
|
||||
_ = self;
|
||||
_ = zcu;
|
||||
_ = exported;
|
||||
_ = export_indices;
|
||||
}
|
||||
|
@ -1162,9 +1162,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
|
||||
|
||||
try self.updateDeclCode(decl_index, code, .FUNCTION);
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {
|
||||
@ -1286,9 +1284,7 @@ pub fn updateDecl(
|
||||
|
||||
try self.updateDeclCode(decl_index, code, .NULL);
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
fn updateLazySymbolAtom(
|
||||
@ -1509,7 +1505,7 @@ pub fn updateExports(
|
||||
self: *Coff,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .coff) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
@ -1522,7 +1518,8 @@ pub fn updateExports(
|
||||
if (comp.config.use_llvm) {
|
||||
// Even in the case of LLVM, we need to notice certain exported symbols in order to
|
||||
// detect the default subsystem.
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
const exported_decl_index = switch (exp.exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => continue,
|
||||
@ -1552,7 +1549,7 @@ pub fn updateExports(
|
||||
}
|
||||
}
|
||||
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
|
||||
|
||||
const gpa = comp.gpa;
|
||||
|
||||
@ -1562,7 +1559,7 @@ pub fn updateExports(
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const first_exp = mod.all_exports.items[export_indices[0]];
|
||||
const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
@ -1570,7 +1567,7 @@ pub fn updateExports(
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
@ -1580,12 +1577,13 @@ pub fn updateExports(
|
||||
const atom_index = metadata.atom;
|
||||
const atom = self.getAtom(atom_index);
|
||||
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
|
||||
|
||||
if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {
|
||||
if (!mem.eql(u8, section_name, ".text")) {
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
@ -1596,7 +1594,7 @@ pub fn updateExports(
|
||||
}
|
||||
|
||||
if (exp.opts.linkage == .link_once) {
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.link_once",
|
||||
@ -1641,13 +1639,16 @@ pub fn updateExports(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
self: *Coff,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
if (self.llvm_object) |_| return;
|
||||
const metadata = self.decls.getPtr(decl_index) orelse return;
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse return,
|
||||
};
|
||||
const mod = self.base.comp.module.?;
|
||||
const name_slice = name.toSlice(&mod.intern_pool);
|
||||
const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
|
||||
|
@ -3011,13 +3011,13 @@ pub fn updateExports(
|
||||
self: *Elf,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .elf) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
|
||||
return self.zigObjectPtr().?.updateExports(self, mod, exported, export_indices);
|
||||
}
|
||||
|
||||
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
|
||||
return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
self: *Elf,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
if (self.llvm_object) |_| return;
|
||||
return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
|
||||
return self.zigObjectPtr().?.deleteExport(self, exported, name);
|
||||
}
|
||||
|
||||
fn addLinkerDefinedSymbols(self: *Elf) !void {
|
||||
|
@ -1115,9 +1115,7 @@ pub fn updateFunc(
|
||||
);
|
||||
}
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
pub fn updateDecl(
|
||||
@ -1194,9 +1192,7 @@ pub fn updateDecl(
|
||||
);
|
||||
}
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
fn updateLazySymbol(
|
||||
@ -1386,7 +1382,7 @@ pub fn updateExports(
|
||||
elf_file: *Elf,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -1398,7 +1394,7 @@ pub fn updateExports(
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const first_exp = mod.all_exports.items[export_indices[0]];
|
||||
const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
@ -1406,7 +1402,7 @@ pub fn updateExports(
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
@ -1418,11 +1414,12 @@ pub fn updateExports(
|
||||
const esym = self.local_esyms.items(.elf_sym)[esym_index];
|
||||
const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
|
||||
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
if (exp.opts.section.unwrap()) |section_name| {
|
||||
if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
@ -1437,7 +1434,7 @@ pub fn updateExports(
|
||||
.weak => elf.STB_WEAK,
|
||||
.link_once => {
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
@ -1487,13 +1484,16 @@ pub fn updateDeclLineNumber(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
self: *ZigObject,
|
||||
elf_file: *Elf,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
const metadata = self.decls.getPtr(decl_index) orelse return;
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse return,
|
||||
};
|
||||
const mod = elf_file.base.comp.module.?;
|
||||
const exp_name = name.toSlice(&mod.intern_pool);
|
||||
const esym_index = metadata.@"export"(self, exp_name) orelse return;
|
||||
|
@ -3196,22 +3196,22 @@ pub fn updateExports(
|
||||
self: *MachO,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .macho) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
return self.getZigObject().?.updateExports(self, mod, exported, exports);
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
|
||||
return self.getZigObject().?.updateExports(self, mod, exported, export_indices);
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
self: *MachO,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) Allocator.Error!void {
|
||||
) void {
|
||||
if (self.llvm_object) |_| return;
|
||||
return self.getZigObject().?.deleteDeclExport(self, decl_index, name);
|
||||
return self.getZigObject().?.deleteExport(self, exported, name);
|
||||
}
|
||||
|
||||
pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
|
||||
|
@ -713,9 +713,7 @@ pub fn updateFunc(
|
||||
);
|
||||
}
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
pub fn updateDecl(
|
||||
@ -790,9 +788,7 @@ pub fn updateDecl(
|
||||
);
|
||||
}
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export symbol also
|
||||
// needs to be updated.
|
||||
try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
// Exports will be updated by `Zcu.processExports` after the update.
|
||||
}
|
||||
|
||||
fn updateDeclCode(
|
||||
@ -1187,7 +1183,7 @@ pub fn updateExports(
|
||||
macho_file: *MachO,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -1199,7 +1195,7 @@ pub fn updateExports(
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const first_exp = mod.all_exports.items[export_indices[0]];
|
||||
const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
@ -1207,7 +1203,7 @@ pub fn updateExports(
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
@ -1218,11 +1214,12 @@ pub fn updateExports(
|
||||
const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
|
||||
const nlist = self.symtab.items(.nlist)[nlist_idx];
|
||||
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
if (exp.opts.section.unwrap()) |section_name| {
|
||||
if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
@ -1232,7 +1229,7 @@ pub fn updateExports(
|
||||
}
|
||||
}
|
||||
if (exp.opts.linkage == .link_once) {
|
||||
try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.putNoClobber(mod.gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.link_once",
|
||||
@ -1364,15 +1361,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
self: *ZigObject,
|
||||
macho_file: *MachO,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
const mod = macho_file.base.comp.module.?;
|
||||
|
||||
const metadata = self.decls.getPtr(decl_index) orelse return;
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse return,
|
||||
};
|
||||
const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
|
||||
|
||||
log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
|
||||
|
@ -96,12 +96,12 @@ pub fn updateExports(
|
||||
self: *NvPtx,
|
||||
module: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .nvptx)
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
|
||||
return self.llvm_object.updateExports(module, exported, exports);
|
||||
return self.llvm_object.updateExports(module, exported, export_indices);
|
||||
}
|
||||
|
||||
pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {
|
||||
|
@ -60,6 +60,9 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(
|
||||
) = .{},
|
||||
/// the code is modified when relocated, so that is why it is mutable
|
||||
data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{},
|
||||
/// When `updateExports` is called, we store the export indices here, to be used
|
||||
/// during flush.
|
||||
decl_exports: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u32) = .{},
|
||||
|
||||
/// Table of unnamed constants associated with a parent `Decl`.
|
||||
/// 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)
|
||||
mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
|
||||
}
|
||||
self.syms.items[atom.sym_index.?].value = off;
|
||||
if (mod.decl_exports.get(decl_index)) |exports| {
|
||||
try self.addDeclExports(mod, decl_index, exports.items);
|
||||
if (self.decl_exports.get(decl_index)) |export_indices| {
|
||||
try self.addDeclExports(mod, decl_index, export_indices);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -836,8 +839,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
|
||||
mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
|
||||
}
|
||||
self.syms.items[atom.sym_index.?].value = off;
|
||||
if (mod.decl_exports.get(decl_index)) |exports| {
|
||||
try self.addDeclExports(mod, decl_index, exports.items);
|
||||
if (self.decl_exports.get(decl_index)) |export_indices| {
|
||||
try self.addDeclExports(mod, decl_index, export_indices);
|
||||
}
|
||||
}
|
||||
// write the unnamed constants after the other data decls
|
||||
@ -1007,20 +1010,21 @@ fn addDeclExports(
|
||||
self: *Plan9,
|
||||
mod: *Module,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
const metadata = self.decls.getPtr(decl_index).?;
|
||||
const atom = self.getAtom(metadata.index);
|
||||
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
|
||||
// plan9 does not support custom sections
|
||||
if (exp.opts.section.unwrap()) |section_name| {
|
||||
if (!section_name.eqlSlice(".text", &mod.intern_pool) and
|
||||
!section_name.eqlSlice(".data", &mod.intern_pool))
|
||||
{
|
||||
try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.put(mod.gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod),
|
||||
"plan9 does not support extra sections",
|
||||
@ -1152,15 +1156,23 @@ pub fn updateExports(
|
||||
self: *Plan9,
|
||||
module: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
switch (exported) {
|
||||
.value => @panic("TODO: plan9 updateExports handling values"),
|
||||
.decl_index => |decl_index| _ = try self.seeDecl(decl_index),
|
||||
.decl_index => |decl_index| {
|
||||
_ = try self.seeDecl(decl_index);
|
||||
if (self.decl_exports.fetchSwapRemove(decl_index)) |kv| {
|
||||
gpa.free(kv.value);
|
||||
}
|
||||
try self.decl_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const duped_indices = try gpa.dupe(u32, export_indices);
|
||||
self.decl_exports.putAssumeCapacityNoClobber(decl_index, duped_indices);
|
||||
},
|
||||
}
|
||||
// we do all the things in flush
|
||||
// all proper work is done in flush
|
||||
_ = module;
|
||||
_ = exports;
|
||||
}
|
||||
|
||||
pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
|
||||
@ -1290,6 +1302,10 @@ pub fn deinit(self: *Plan9) void {
|
||||
gpa.free(self.syms.items[sym_index].name);
|
||||
}
|
||||
self.data_decl_table.deinit(gpa);
|
||||
for (self.decl_exports.values()) |export_indices| {
|
||||
gpa.free(export_indices);
|
||||
}
|
||||
self.decl_exports.deinit(gpa);
|
||||
self.syms.deinit(gpa);
|
||||
self.got_index_free_list.deinit(gpa);
|
||||
self.syms_index_free_list.deinit(gpa);
|
||||
@ -1395,10 +1411,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
|
||||
const atom = self.getAtom(decl_metadata.index);
|
||||
const sym = self.syms.items[atom.sym_index.?];
|
||||
try self.writeSym(writer, sym);
|
||||
if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
|
||||
for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
|
||||
try self.writeSym(writer, self.syms.items[exp_i]);
|
||||
};
|
||||
if (self.decl_exports.get(decl_index)) |export_indices| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
|
||||
try self.writeSym(writer, self.syms.items[exp_i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1442,13 +1461,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
|
||||
const atom = self.getAtom(decl_metadata.index);
|
||||
const sym = self.syms.items[atom.sym_index.?];
|
||||
try self.writeSym(writer, sym);
|
||||
if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
|
||||
for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
|
||||
const s = self.syms.items[exp_i];
|
||||
if (mem.eql(u8, s.name, "_start"))
|
||||
self.entry_val = s.value;
|
||||
try self.writeSym(writer, s);
|
||||
};
|
||||
if (self.decl_exports.get(decl_index)) |export_indices| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
|
||||
const s = self.syms.items[exp_i];
|
||||
if (mem.eql(u8, s.name, "_start"))
|
||||
self.entry_val = s.value;
|
||||
try self.writeSym(writer, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ pub fn updateExports(
|
||||
self: *SpirV,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
@ -177,7 +177,8 @@ pub fn updateExports(
|
||||
if ((!is_vulkan and execution_model == .Kernel) or
|
||||
(is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
|
||||
{
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
try self.object.spv.declareEntryPoint(
|
||||
spv_decl_index,
|
||||
exp.opts.name.toSlice(&mod.intern_pool),
|
||||
|
@ -1542,26 +1542,26 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
|
||||
return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
wasm: *Wasm,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
if (wasm.llvm_object) |_| return;
|
||||
return wasm.zigObjectPtr().?.deleteDeclExport(wasm, decl_index, name);
|
||||
return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
wasm: *Wasm,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .wasm) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, exports);
|
||||
if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
|
||||
return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, export_indices);
|
||||
}
|
||||
|
||||
pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
|
||||
|
@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr(
|
||||
return target_symbol_index;
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(
|
||||
pub fn deleteExport(
|
||||
zig_object: *ZigObject,
|
||||
wasm_file: *Wasm,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
const mod = wasm_file.base.comp.module.?;
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |decl_index| decl_index,
|
||||
.value => @panic("TODO: implement Wasm linker code for exporting a constant value"),
|
||||
};
|
||||
const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
|
||||
if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
@ -856,7 +860,7 @@ pub fn updateExports(
|
||||
wasm_file: *Wasm,
|
||||
mod: *Module,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
export_indices: []const u32,
|
||||
) !void {
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
@ -873,9 +877,10 @@ pub fn updateExports(
|
||||
const gpa = mod.gpa;
|
||||
log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});
|
||||
|
||||
for (exports) |exp| {
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = mod.all_exports.items[export_idx];
|
||||
if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.navSrcLoc(mod).upgrade(mod),
|
||||
"Unimplemented: ExportOptions.section '{s}'",
|
||||
@ -908,7 +913,7 @@ pub fn updateExports(
|
||||
},
|
||||
.strong => {}, // symbols are strong by default
|
||||
.link_once => {
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.navSrcLoc(mod).upgrade(mod),
|
||||
"Unimplemented: LinkOnce",
|
||||
|
Loading…
Reference in New Issue
Block a user