compiler: add type safety for export indices
This commit is contained in:
10
src/Sema.zig
10
src/Sema.zig
@@ -38298,7 +38298,7 @@ pub fn flushExports(sema: *Sema) !void {
|
||||
// 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(sema.owner)) |export_idx| {
|
||||
try sema.exports.append(gpa, zcu.all_exports.items[export_idx]);
|
||||
try sema.exports.append(gpa, export_idx.ptr(zcu).*);
|
||||
} else if (zcu.multi_exports.get(sema.owner)) |info| {
|
||||
try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
|
||||
}
|
||||
@@ -38307,12 +38307,12 @@ pub fn flushExports(sema: *Sema) !void {
|
||||
// `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: {
|
||||
const export_idx: Zcu.Export.Index = zcu.free_exports.popOrNull() orelse idx: {
|
||||
_ = try zcu.all_exports.addOne(gpa);
|
||||
break :idx zcu.all_exports.items.len - 1;
|
||||
break :idx @enumFromInt(zcu.all_exports.items.len - 1);
|
||||
};
|
||||
zcu.all_exports.items[export_idx] = sema.exports.items[0];
|
||||
zcu.single_exports.putAssumeCapacityNoClobber(sema.owner, @intCast(export_idx));
|
||||
export_idx.ptr(zcu).* = sema.exports.items[0];
|
||||
zcu.single_exports.putAssumeCapacityNoClobber(sema.owner, export_idx);
|
||||
} else {
|
||||
try zcu.multi_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const exports_base = zcu.all_exports.items.len;
|
||||
|
||||
24
src/Zcu.zig
24
src/Zcu.zig
@@ -79,11 +79,11 @@ local_zir_cache: Compilation.Directory,
|
||||
all_exports: std.ArrayListUnmanaged(Export) = .empty,
|
||||
/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
|
||||
/// future semantic analysis.
|
||||
free_exports: std.ArrayListUnmanaged(u32) = .empty,
|
||||
free_exports: std.ArrayListUnmanaged(Export.Index) = .empty,
|
||||
/// 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) = .empty,
|
||||
single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, Export.Index) = .empty,
|
||||
/// 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 {
|
||||
@@ -145,8 +145,7 @@ compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
|
||||
failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .empty,
|
||||
/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
|
||||
failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .empty,
|
||||
/// Key is index into `all_exports`.
|
||||
failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .empty,
|
||||
failed_exports: std.AutoArrayHashMapUnmanaged(Export.Index, *ErrorMsg) = .empty,
|
||||
/// If analysis failed due to a cimport error, the corresponding Clang errors
|
||||
/// are stored here.
|
||||
cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .empty,
|
||||
@@ -3101,7 +3100,7 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
|
||||
.{ kv.value, 1 }
|
||||
.{ @intFromEnum(kv.value), 1 }
|
||||
else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
|
||||
.{ info.value.index, info.value.len }
|
||||
else
|
||||
@@ -3115,11 +3114,12 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
// This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
|
||||
// within a single update.
|
||||
if (dev.env.supports(.incremental)) {
|
||||
for (exports, exports_base..) |exp, export_idx| {
|
||||
for (exports, exports_base..) |exp, export_index_usize| {
|
||||
const export_idx: Export.Index = @enumFromInt(export_index_usize);
|
||||
if (zcu.comp.bin_file) |lf| {
|
||||
lf.deleteExport(exp.exported, exp.opts.name);
|
||||
}
|
||||
if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
|
||||
if (zcu.failed_exports.fetchSwapRemove(export_idx)) |failed_kv| {
|
||||
failed_kv.value.destroy(gpa);
|
||||
}
|
||||
}
|
||||
@@ -3131,7 +3131,7 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
return;
|
||||
};
|
||||
for (exports_base..exports_base + exports_len) |export_idx| {
|
||||
zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
|
||||
zcu.free_exports.appendAssumeCapacity(@enumFromInt(export_idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3277,7 +3277,7 @@ fn lockAndClearFileCompileError(zcu: *Zcu, file: *File) void {
|
||||
|
||||
pub fn handleUpdateExports(
|
||||
zcu: *Zcu,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Export.Index,
|
||||
result: link.File.UpdateExportsError!void,
|
||||
) Allocator.Error!void {
|
||||
const gpa = zcu.gpa;
|
||||
@@ -3285,12 +3285,10 @@ pub fn handleUpdateExports(
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => {
|
||||
const export_idx = export_indices[0];
|
||||
const new_export = &zcu.all_exports.items[export_idx];
|
||||
const new_export = export_idx.ptr(zcu);
|
||||
new_export.status = .failed_retryable;
|
||||
try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{
|
||||
@errorName(err),
|
||||
});
|
||||
const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{@errorName(err)});
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2815,8 +2815,8 @@ pub fn processExports(pt: Zcu.PerThread) !void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
// First, construct a mapping of every exported value and Nav to the indices of all its different exports.
|
||||
var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(u32)) = .empty;
|
||||
var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(u32)) = .empty;
|
||||
var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty;
|
||||
var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty;
|
||||
defer {
|
||||
for (nav_exports.values()) |*exports| {
|
||||
exports.deinit(gpa);
|
||||
@@ -2835,7 +2835,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
|
||||
try nav_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 exp = export_idx.ptr(zcu);
|
||||
const value_ptr, const found_existing = switch (exp.exported) {
|
||||
.nav => |nav| gop: {
|
||||
const gop = try nav_exports.getOrPut(gpa, nav);
|
||||
@@ -2863,7 +2863,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
|
||||
},
|
||||
};
|
||||
if (!found_existing) value_ptr.* = .{};
|
||||
try value_ptr.append(gpa, @intCast(export_idx));
|
||||
try value_ptr.append(gpa, @enumFromInt(export_idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2882,20 +2882,20 @@ pub fn processExports(pt: Zcu.PerThread) !void {
|
||||
}
|
||||
}
|
||||
|
||||
const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
|
||||
const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Zcu.Export.Index);
|
||||
|
||||
fn processExportsInner(
|
||||
pt: Zcu.PerThread,
|
||||
symbol_exports: *SymbolExports,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) error{OutOfMemory}!void {
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
for (export_indices) |export_idx| {
|
||||
const new_export = &zcu.all_exports.items[export_idx];
|
||||
const new_export = export_idx.ptr(zcu);
|
||||
const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
|
||||
if (gop.found_existing) {
|
||||
new_export.status = .failed_retryable;
|
||||
@@ -2904,7 +2904,7 @@ fn processExportsInner(
|
||||
new_export.opts.name.fmt(ip),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
const other_export = zcu.all_exports.items[gop.value_ptr.*];
|
||||
const other_export = gop.value_ptr.ptr(zcu);
|
||||
try zcu.errNote(other_export.src, msg, "other symbol here", .{});
|
||||
zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
|
||||
new_export.status = .failed;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const leb = std.leb;
|
||||
@@ -631,7 +630,7 @@ blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, struct {
|
||||
/// Maps `loop` instructions to their label. `br` to here repeats the loop.
|
||||
loops: std.AutoHashMapUnmanaged(Air.Inst.Index, u32) = .empty,
|
||||
/// `bytes` contains the wasm bytecode belonging to the 'code' section.
|
||||
code: *ArrayList(u8),
|
||||
code: *std.ArrayListUnmanaged(u8),
|
||||
/// The index the next local generated will have
|
||||
/// NOTE: arguments share the index with locals therefore the first variable
|
||||
/// will have the index that comes after the last argument's index
|
||||
@@ -639,8 +638,6 @@ local_index: u32 = 0,
|
||||
/// The index of the current argument.
|
||||
/// Used to track which argument is being referenced in `airArg`.
|
||||
arg_index: u32 = 0,
|
||||
/// If codegen fails, an error messages will be allocated and saved in `err_msg`
|
||||
err_msg: *Zcu.ErrorMsg,
|
||||
/// List of all locals' types generated throughout this declaration
|
||||
/// used to emit locals count at start of 'code' section.
|
||||
locals: std.ArrayListUnmanaged(u8),
|
||||
@@ -732,10 +729,9 @@ pub fn deinit(func: *CodeGen) void {
|
||||
func.* = undefined;
|
||||
}
|
||||
|
||||
/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
|
||||
fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
|
||||
func.err_msg = try Zcu.ErrorMsg.create(func.gpa, func.src_loc, fmt, args);
|
||||
return error.CodegenFail;
|
||||
fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
|
||||
const msg = try Zcu.ErrorMsg.create(func.gpa, func.src_loc, fmt, args);
|
||||
return func.pt.zcu.codegenFailMsg(func.owner_nav, msg);
|
||||
}
|
||||
|
||||
/// Resolves the `WValue` for the given instruction `inst`
|
||||
@@ -1173,9 +1169,9 @@ pub fn generate(
|
||||
func_index: InternPool.Index,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
code: *std.ArrayList(u8),
|
||||
code: *std.ArrayListUnmanaged(u8),
|
||||
debug_output: link.File.DebugInfoOutput,
|
||||
) codegen.CodeGenError!codegen.Result {
|
||||
) codegen.CodeGenError!void {
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const func = zcu.funcInfo(func_index);
|
||||
@@ -1189,7 +1185,6 @@ pub fn generate(
|
||||
.code = code,
|
||||
.owner_nav = func.owner_nav,
|
||||
.src_loc = src_loc,
|
||||
.err_msg = undefined,
|
||||
.locals = .{},
|
||||
.target = target,
|
||||
.bin_file = bin_file.cast(.wasm).?,
|
||||
@@ -1199,11 +1194,9 @@ pub fn generate(
|
||||
defer code_gen.deinit();
|
||||
|
||||
genFunc(&code_gen) catch |err| switch (err) {
|
||||
error.CodegenFail => return codegen.Result{ .fail = code_gen.err_msg },
|
||||
else => |e| return e,
|
||||
error.CodegenFail => return error.CodegenFail,
|
||||
else => |e| return code_gen.fail("failed to generate function: {s}", .{@errorName(e)}),
|
||||
};
|
||||
|
||||
return codegen.Result.ok;
|
||||
}
|
||||
|
||||
fn genFunc(func: *CodeGen) InnerError!void {
|
||||
|
||||
@@ -80,15 +80,15 @@ pub const Inst = struct {
|
||||
///
|
||||
/// Uses `nop`
|
||||
@"return" = 0x0F,
|
||||
/// Calls a function using `nav_index`.
|
||||
call_nav,
|
||||
/// Calls a function using `func_index`.
|
||||
call_func,
|
||||
/// Calls a function pointer by its function signature
|
||||
/// and index into the function table.
|
||||
///
|
||||
/// Uses `label`
|
||||
call_indirect = 0x11,
|
||||
/// Calls a function using `nav_index`.
|
||||
call_nav,
|
||||
/// Calls a function using `func_index`.
|
||||
call_func,
|
||||
/// Calls a function by its index.
|
||||
///
|
||||
/// The function is the auto-generated tag name function for the type
|
||||
|
||||
@@ -3052,12 +3052,12 @@ pub fn genDeclValue(
|
||||
try w.writeAll(";\n");
|
||||
}
|
||||
|
||||
pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const u32) !void {
|
||||
pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void {
|
||||
const zcu = dg.pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const fwd = dg.fwdDeclWriter();
|
||||
|
||||
const main_name = zcu.all_exports.items[export_indices[0]].opts.name;
|
||||
const main_name = export_indices[0].ptr(zcu).opts.name;
|
||||
try fwd.writeAll("#define ");
|
||||
switch (exported) {
|
||||
.nav => |nav| try dg.renderNavName(fwd, nav),
|
||||
@@ -3069,7 +3069,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
|
||||
|
||||
const exported_val = exported.getValue(zcu);
|
||||
if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| {
|
||||
const @"export" = &zcu.all_exports.items[export_index];
|
||||
const @"export" = export_index.ptr(zcu);
|
||||
try fwd.writeAll("zig_extern ");
|
||||
if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
|
||||
try dg.renderFunctionSignature(
|
||||
@@ -3091,7 +3091,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
|
||||
else => true,
|
||||
};
|
||||
for (export_indices) |export_index| {
|
||||
const @"export" = &zcu.all_exports.items[export_index];
|
||||
const @"export" = export_index.ptr(zcu);
|
||||
try fwd.writeAll("zig_extern ");
|
||||
if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
|
||||
const extern_name = @"export".opts.name.toSlice(ip);
|
||||
|
||||
@@ -1810,7 +1810,7 @@ pub const Object = struct {
|
||||
self: *Object,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) link.File.UpdateExportsError!void {
|
||||
assert(std.meta.eql(pt, self.pt));
|
||||
const zcu = pt.zcu;
|
||||
|
||||
@@ -817,7 +817,7 @@ pub const File = struct {
|
||||
base: *File,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) UpdateExportsError!void {
|
||||
switch (base.tag) {
|
||||
inline else => |tag| {
|
||||
|
||||
@@ -840,7 +840,7 @@ pub fn updateExports(
|
||||
self: *C,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
@@ -2393,7 +2393,7 @@ pub fn updateExports(
|
||||
self: *Elf,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) 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");
|
||||
|
||||
@@ -1745,7 +1745,7 @@ pub fn updateExports(
|
||||
elf_file: *Elf,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@@ -3056,7 +3056,7 @@ pub fn updateExports(
|
||||
self: *MachO,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) 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");
|
||||
|
||||
@@ -1246,7 +1246,7 @@ pub fn updateExports(
|
||||
macho_file: *MachO,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@@ -100,7 +100,7 @@ pub fn updateExports(
|
||||
self: *NvPtx,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !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");
|
||||
|
||||
@@ -60,7 +60,7 @@ fn_nav_table: std.AutoArrayHashMapUnmanaged(
|
||||
data_nav_table: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u8) = .empty,
|
||||
/// When `updateExports` is called, we store the export indices here, to be used
|
||||
/// during flush.
|
||||
nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u32) = .empty,
|
||||
nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []Zcu.Export.Index) = .empty,
|
||||
|
||||
lazy_syms: LazySymbolTable = .{},
|
||||
|
||||
@@ -1007,7 +1007,7 @@ pub fn updateExports(
|
||||
self: *Plan9,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
switch (exported) {
|
||||
@@ -1018,7 +1018,7 @@ pub fn updateExports(
|
||||
gpa.free(kv.value);
|
||||
}
|
||||
try self.nav_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const duped_indices = try gpa.dupe(u32, export_indices);
|
||||
const duped_indices = try gpa.dupe(Zcu.Export.Index, export_indices);
|
||||
self.nav_exports.putAssumeCapacityNoClobber(nav, duped_indices);
|
||||
},
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ pub fn updateExports(
|
||||
self: *SpirV,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
@@ -190,7 +190,7 @@ pub fn updateExports(
|
||||
};
|
||||
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = zcu.all_exports.items[export_idx];
|
||||
const exp = export_idx.ptr(zcu);
|
||||
try self.object.spv.declareEntryPoint(
|
||||
spv_decl_index,
|
||||
exp.opts.name.toSlice(ip),
|
||||
|
||||
@@ -56,6 +56,10 @@ base: link.File,
|
||||
/// string_table entries for them. Alternately those sites could be moved to
|
||||
/// use a different byte array for this purpose.
|
||||
string_bytes: std.ArrayListUnmanaged(u8),
|
||||
/// Sometimes we have logic that wants to borrow string bytes to store
|
||||
/// arbitrary things in there. In this case it is not allowed to intern new
|
||||
/// strings during this time. This safety lock is used to detect misuses.
|
||||
string_bytes_lock: std.debug.SafetyLock = .{},
|
||||
/// Omitted when serializing linker state.
|
||||
string_table: String.Table,
|
||||
/// Symbol name of the entry function to export
|
||||
@@ -202,6 +206,10 @@ any_exports_updated: bool = true,
|
||||
/// Index into `objects`.
|
||||
pub const ObjectIndex = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: ObjectIndex, wasm: *const Wasm) *Object {
|
||||
return &wasm.objects.items[@intFromEnum(index)];
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `functions`.
|
||||
@@ -269,12 +277,26 @@ pub const SourceLocation = enum(u32) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unpack(sl: SourceLocation, wasm: *const Wasm) Unpacked {
|
||||
return switch (sl) {
|
||||
.zig_object_nofile => .zig_object_nofile,
|
||||
.none => .none,
|
||||
_ => {
|
||||
const i = @intFromEnum(sl);
|
||||
if (i < wasm.objects.items.len) return .{ .object_index = @enumFromInt(i) };
|
||||
const sl_index = i - wasm.objects.items.len;
|
||||
_ = sl_index;
|
||||
@panic("TODO");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {
|
||||
const diags = &wasm.base.comp.link_diags;
|
||||
switch (sl.unpack(wasm)) {
|
||||
.none => unreachable,
|
||||
.zig_object_nofile => diags.addError("zig compilation unit: " ++ f, args),
|
||||
.object_index => |i| diags.addError("{}: " ++ f, .{wasm.objects.items[i].path} ++ args),
|
||||
.object_index => |i| diags.addError("{}: " ++ f, .{i.ptr(wasm).path} ++ args),
|
||||
.source_location_index => @panic("TODO"),
|
||||
}
|
||||
}
|
||||
@@ -520,6 +542,10 @@ pub const FunctionImport = extern struct {
|
||||
/// Index into `object_function_imports`.
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: FunctionImport.Index, wasm: *const Wasm) *FunctionImport {
|
||||
return &wasm.object_function_imports.items[@intFromEnum(index)];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -543,7 +569,8 @@ pub const GlobalImport = extern struct {
|
||||
source_location: SourceLocation,
|
||||
resolution: Resolution,
|
||||
|
||||
/// Represents a synthetic global, or a global from an object.
|
||||
/// Represents a synthetic global, a global from an object, or a global
|
||||
/// from the Zcu.
|
||||
pub const Resolution = enum(u32) {
|
||||
unresolved,
|
||||
__heap_base,
|
||||
@@ -556,6 +583,68 @@ pub const GlobalImport = extern struct {
|
||||
// Next, index into `object_globals`.
|
||||
// Next, index into `navs`.
|
||||
_,
|
||||
|
||||
const first_object_global = @intFromEnum(Resolution.__zig_error_name_table) + 1;
|
||||
|
||||
pub const Unpacked = union(enum) {
|
||||
unresolved,
|
||||
__heap_base,
|
||||
__heap_end,
|
||||
__stack_pointer,
|
||||
__tls_align,
|
||||
__tls_base,
|
||||
__tls_size,
|
||||
__zig_error_name_table,
|
||||
object_global: ObjectGlobalIndex,
|
||||
nav: Nav.Index,
|
||||
};
|
||||
|
||||
pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
|
||||
return switch (r) {
|
||||
.unresolved => .unresolved,
|
||||
.__wasm_apply_global_tls_relocs => .__wasm_apply_global_tls_relocs,
|
||||
.__wasm_call_ctors => .__wasm_call_ctors,
|
||||
.__wasm_init_memory => .__wasm_init_memory,
|
||||
.__wasm_init_tls => .__wasm_init_tls,
|
||||
.__zig_error_names => .__zig_error_names,
|
||||
_ => {
|
||||
const i: u32 = @intFromEnum(r);
|
||||
const object_global_index = i - first_object_global;
|
||||
if (object_global_index < wasm.object_globals.items.len)
|
||||
return .{ .object_global = @enumFromInt(object_global_index) };
|
||||
const nav_index = object_global_index - wasm.object_globals.items.len;
|
||||
return .{ .nav = @enumFromInt(nav_index) };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Resolution {
|
||||
return switch (unpacked) {
|
||||
.unresolved => .unresolved,
|
||||
.__heap_base => .__heap_base,
|
||||
.__heap_end => .__heap_end,
|
||||
.__stack_pointer => .__stack_pointer,
|
||||
.__tls_align => .__tls_align,
|
||||
.__tls_base => .__tls_base,
|
||||
.__tls_size => .__tls_size,
|
||||
.__zig_error_name_table => .__zig_error_name_table,
|
||||
.object_global => |i| @enumFromInt(first_object_global + @intFromEnum(i)),
|
||||
.nav => |i| @enumFromInt(first_object_global + wasm.object_globals.items.len + @intFromEnum(i)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
|
||||
return pack(wasm, .{ .nav = @enumFromInt(wasm.navs.getIndex(ip_nav).?) });
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `object_global_imports`.
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: Index, wasm: *const Wasm) *GlobalImport {
|
||||
return &wasm.object_global_imports.items[@intFromEnum(index)];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -634,20 +723,6 @@ pub const ObjectSectionIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// Index into `object_function_imports`.
|
||||
pub const ObjectFunctionImportIndex = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: ObjectFunctionImportIndex, wasm: *const Wasm) *FunctionImport {
|
||||
return &wasm.object_function_imports.items[@intFromEnum(index)];
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `object_global_imports`.
|
||||
pub const ObjectGlobalImportIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// Index into `object_table_imports`.
|
||||
pub const ObjectTableImportIndex = enum(u32) {
|
||||
_,
|
||||
@@ -861,11 +936,35 @@ pub const ValtypeList = enum(u32) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `imports`.
|
||||
pub const ZcuImportIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// 0. Index into `object_function_imports`.
|
||||
/// 1. Index into `imports`.
|
||||
pub const FunctionImportId = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const Unpacked = union(enum) {
|
||||
object_function_import: FunctionImport.Index,
|
||||
zcu_import: ZcuImportIndex,
|
||||
};
|
||||
|
||||
pub fn pack(unpacked: Unpacked, wasm: *const Wasm) FunctionImportId {
|
||||
return switch (unpacked) {
|
||||
.object_function_import => |i| @enumFromInt(@intFromEnum(i)),
|
||||
.zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_function_imports.entries.len),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unpack(id: FunctionImportId, wasm: *const Wasm) Unpacked {
|
||||
const i = @intFromEnum(id);
|
||||
if (i < wasm.object_function_imports.entries.len) return .{ .object_function_import = @enumFromInt(i) };
|
||||
const zcu_import_i = i - wasm.object_function_imports.entries.len;
|
||||
return .{ .zcu_import = @enumFromInt(zcu_import_i) };
|
||||
}
|
||||
|
||||
/// This function is allowed O(N) lookup because it is only called during
|
||||
/// diagnostic generation.
|
||||
pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
|
||||
@@ -873,10 +972,10 @@ pub const FunctionImportId = enum(u32) {
|
||||
.object_function_import => |obj_func_index| {
|
||||
// TODO binary search
|
||||
for (wasm.objects.items, 0..) |o, i| {
|
||||
if (o.function_imports.off <= obj_func_index and
|
||||
o.function_imports.off + o.function_imports.len > obj_func_index)
|
||||
if (o.function_imports.off <= @intFromEnum(obj_func_index) and
|
||||
o.function_imports.off + o.function_imports.len > @intFromEnum(obj_func_index))
|
||||
{
|
||||
return .pack(wasm, .{ .object_index = @enumFromInt(i) });
|
||||
return .pack(.{ .object_index = @enumFromInt(i) }, wasm);
|
||||
}
|
||||
} else unreachable;
|
||||
},
|
||||
@@ -890,17 +989,36 @@ pub const FunctionImportId = enum(u32) {
|
||||
pub const GlobalImportId = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const Unpacked = union(enum) {
|
||||
object_global_import: GlobalImport.Index,
|
||||
zcu_import: ZcuImportIndex,
|
||||
};
|
||||
|
||||
pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
|
||||
return switch (unpacked) {
|
||||
.object_global_import => |i| @enumFromInt(@intFromEnum(i)),
|
||||
.zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_global_imports.entries.len),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked {
|
||||
const i = @intFromEnum(id);
|
||||
if (i < wasm.object_global_imports.entries.len) return .{ .object_global_import = @enumFromInt(i) };
|
||||
const zcu_import_i = i - wasm.object_global_imports.entries.len;
|
||||
return .{ .zcu_import = @enumFromInt(zcu_import_i) };
|
||||
}
|
||||
|
||||
/// This function is allowed O(N) lookup because it is only called during
|
||||
/// diagnostic generation.
|
||||
pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
|
||||
switch (id.unpack(wasm)) {
|
||||
.object_global_import => |obj_func_index| {
|
||||
.object_global_import => |obj_global_index| {
|
||||
// TODO binary search
|
||||
for (wasm.objects.items, 0..) |o, i| {
|
||||
if (o.global_imports.off <= obj_func_index and
|
||||
o.global_imports.off + o.global_imports.len > obj_func_index)
|
||||
if (o.global_imports.off <= @intFromEnum(obj_global_index) and
|
||||
o.global_imports.off + o.global_imports.len > @intFromEnum(obj_global_index))
|
||||
{
|
||||
return .pack(wasm, .{ .object_index = @enumFromInt(i) });
|
||||
return .pack(.{ .object_index = @enumFromInt(i) }, wasm);
|
||||
}
|
||||
} else unreachable;
|
||||
},
|
||||
@@ -1330,23 +1448,13 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
wasm.object_memories.deinit(gpa);
|
||||
|
||||
wasm.object_data_segments.deinit(gpa);
|
||||
wasm.object_relocatable_codes.deinit(gpa);
|
||||
wasm.object_custom_segments.deinit(gpa);
|
||||
wasm.object_symbols.deinit(gpa);
|
||||
wasm.object_named_segments.deinit(gpa);
|
||||
wasm.object_init_funcs.deinit(gpa);
|
||||
wasm.object_comdats.deinit(gpa);
|
||||
wasm.object_relocations.deinit(gpa);
|
||||
wasm.object_relocations_table.deinit(gpa);
|
||||
wasm.object_comdat_symbols.deinit(gpa);
|
||||
wasm.objects.deinit(gpa);
|
||||
|
||||
wasm.synthetic_symbols.deinit(gpa);
|
||||
wasm.undefs.deinit(gpa);
|
||||
wasm.discarded.deinit(gpa);
|
||||
wasm.segments.deinit(gpa);
|
||||
wasm.segment_info.deinit(gpa);
|
||||
|
||||
wasm.func_types.deinit(gpa);
|
||||
wasm.function_exports.deinit(gpa);
|
||||
wasm.function_imports.deinit(gpa);
|
||||
@@ -1354,8 +1462,6 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
wasm.globals.deinit(gpa);
|
||||
wasm.global_imports.deinit(gpa);
|
||||
wasm.table_imports.deinit(gpa);
|
||||
wasm.output_globals.deinit(gpa);
|
||||
wasm.exports.deinit(gpa);
|
||||
|
||||
wasm.string_bytes.deinit(gpa);
|
||||
wasm.string_table.deinit(gpa);
|
||||
@@ -1374,12 +1480,11 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
|
||||
const nav_index = func.owner_nav;
|
||||
|
||||
const code_start: u32 = @intCast(wasm.string_bytes.items.len);
|
||||
const relocs_start: u32 = @intCast(wasm.relocations.items.len);
|
||||
const relocs_start: u32 = @intCast(wasm.relocations.len);
|
||||
wasm.string_bytes_lock.lock();
|
||||
|
||||
const wasm_codegen = @import("../../arch/wasm/CodeGen.zig");
|
||||
dev.check(.wasm_backend);
|
||||
const result = try wasm_codegen.generate(
|
||||
try CodeGen.generate(
|
||||
&wasm.base,
|
||||
pt,
|
||||
zcu.navSrcLoc(nav_index),
|
||||
@@ -1391,18 +1496,12 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
|
||||
);
|
||||
|
||||
const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
|
||||
const relocs_len: u32 = @intCast(wasm.relocations.items.len - relocs_start);
|
||||
const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);
|
||||
wasm.string_bytes_lock.unlock();
|
||||
|
||||
const code: Nav.Code = switch (result) {
|
||||
.ok => .{
|
||||
.off = code_start,
|
||||
.len = code_len,
|
||||
},
|
||||
.fail => |em| {
|
||||
try pt.zcu.failed_codegen.put(gpa, nav_index, em);
|
||||
return;
|
||||
},
|
||||
const code: Nav.Code = .{
|
||||
.off = code_start,
|
||||
.len = code_len,
|
||||
};
|
||||
|
||||
const gop = try wasm.navs.getOrPut(gpa, nav_index);
|
||||
@@ -1445,24 +1544,22 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
|
||||
|
||||
if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
|
||||
_ = wasm.imports.swapRemove(nav_index);
|
||||
if (wasm.navs.swapRemove(nav_index)) |old| {
|
||||
_ = old;
|
||||
if (wasm.navs.swapRemove(nav_index)) {
|
||||
@panic("TODO reclaim resources");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_extern) {
|
||||
try wasm.imports.put(nav_index, {});
|
||||
if (wasm.navs.swapRemove(nav_index)) |old| {
|
||||
_ = old;
|
||||
try wasm.imports.put(gpa, nav_index, {});
|
||||
if (wasm.navs.swapRemove(nav_index)) {
|
||||
@panic("TODO reclaim resources");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const code_start: u32 = @intCast(wasm.string_bytes.items.len);
|
||||
const relocs_start: u32 = @intCast(wasm.relocations.items.len);
|
||||
const relocs_start: u32 = @intCast(wasm.relocations.len);
|
||||
wasm.string_bytes_lock.lock();
|
||||
|
||||
const res = try codegen.generateSymbol(
|
||||
@@ -1475,7 +1572,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
|
||||
);
|
||||
|
||||
const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
|
||||
const relocs_len: u32 = @intCast(wasm.relocations.items.len - relocs_start);
|
||||
const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);
|
||||
wasm.string_bytes_lock.unlock();
|
||||
|
||||
const code: Nav.Code = switch (res) {
|
||||
@@ -1531,7 +1628,7 @@ pub fn updateExports(
|
||||
wasm: *Wasm,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const u32,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !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");
|
||||
@@ -1668,7 +1765,7 @@ fn markFunction(
|
||||
wasm: *Wasm,
|
||||
name: String,
|
||||
import: *FunctionImport,
|
||||
func_index: ObjectFunctionImportIndex,
|
||||
func_index: FunctionImport.Index,
|
||||
) error{OutOfMemory}!void {
|
||||
if (import.flags.alive) return;
|
||||
import.flags.alive = true;
|
||||
@@ -1712,7 +1809,7 @@ fn markGlobal(
|
||||
wasm: *Wasm,
|
||||
name: String,
|
||||
import: *GlobalImport,
|
||||
global_index: ObjectGlobalImportIndex,
|
||||
global_index: GlobalImport.Index,
|
||||
) !void {
|
||||
if (import.flags.alive) return;
|
||||
import.flags.alive = true;
|
||||
|
||||
@@ -137,13 +137,12 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
|
||||
|
||||
// Merge and order the data segments. Depends on garbage collection so that
|
||||
// unused segments can be omitted.
|
||||
try f.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len);
|
||||
try f.data_segments.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len);
|
||||
for (wasm.object_data_segments.items, 0..) |*ds, i| {
|
||||
if (!ds.flags.alive) continue;
|
||||
const data_segment_index: Wasm.DataSegment.Index = @enumFromInt(i);
|
||||
any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !isBss(wasm, ds.name));
|
||||
f.data_segments.putAssumeCapacityNoClobber(@intCast(i), .{
|
||||
.offset = undefined,
|
||||
});
|
||||
f.data_segments.putAssumeCapacityNoClobber(data_segment_index, .{ .offset = undefined });
|
||||
}
|
||||
|
||||
try wasm.functions.ensureUnusedCapacity(gpa, 3);
|
||||
@@ -1082,8 +1081,8 @@ fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)
|
||||
// try writeCustomSectionHeader(binary_bytes.items, header_offset, size);
|
||||
//}
|
||||
|
||||
fn isBss(wasm: *Wasm, name: String) bool {
|
||||
const s = name.slice(wasm);
|
||||
fn isBss(wasm: *Wasm, optional_name: Wasm.OptionalString) bool {
|
||||
const s = optional_name.slice(wasm) orelse return false;
|
||||
return mem.eql(u8, s, ".bss") or mem.startsWith(u8, s, ".bss.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user