rewrite wasm/Emit.zig

mainly, rework how relocations works. This is the point at which symbol
indexes are known - not before. And don't emit unnecessary relocations!
They're only needed when emitting an object file.

Changes wasm linker to keep MIR around long-lived so that fixups can be
reapplied after linker garbage collection.

use labeled switch while we're at it
This commit is contained in:
Andrew Kelley 2024-12-05 23:46:46 -08:00
parent b9355edfb1
commit e521879e47
11 changed files with 1097 additions and 1140 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,10 +10,12 @@ const Mir = @This();
const InternPool = @import("../../InternPool.zig");
const Wasm = @import("../../link/Wasm.zig");
const builtin = @import("builtin");
const std = @import("std");
const assert = std.debug.assert;
/// A struct of array that represents each individual wasm
instructions: std.MultiArrayList(Inst).Slice,
instruction_tags: []const Inst.Tag,
instruction_datas: []const Inst.Data,
/// A slice of indexes where the meaning of the data is determined by the
/// `Inst.Tag` value.
extra: []const u32,
@ -28,13 +30,7 @@ pub const Inst = struct {
/// The position of a given MIR isntruction with the instruction list.
pub const Index = u32;
/// Contains all possible wasm opcodes the Zig compiler may emit
/// Rather than re-using std.wasm.Opcode, we only declare the opcodes
/// we need, and also use this possibility to document how to access
/// their payload.
///
/// Note: Uses its actual opcode value representation to easily convert
/// to and from its binary representation.
/// Some tags match wasm opcode values to facilitate trivial lowering.
pub const Tag = enum(u8) {
/// Uses `nop`
@"unreachable" = 0x00,
@ -46,19 +42,27 @@ pub const Inst = struct {
///
/// Type of the loop is given in data `block_type`
loop = 0x03,
/// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
/// memory address of an unnamed constant. When emitting an object
/// file, this adds a relocation.
///
/// Data is `ip_index`.
uav_ref,
/// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
/// memory address of an unnamed constant, offset by an integer value.
/// When emitting an object file, this adds a relocation.
///
/// Data is `payload` pointing to a `UavRefOff`.
uav_ref_off,
/// Inserts debug information about the current line and column
/// of the source code
///
/// Uses `payload` of which the payload type is `DbgLineColumn`
dbg_line = 0x06,
/// Emits epilogue begin debug information
/// Emits epilogue begin debug information. Marks the end of the function.
///
/// Uses `nop`
dbg_epilogue_begin = 0x07,
/// Emits prologue end debug information
///
/// Uses `nop`
dbg_prologue_end = 0x08,
/// Represents the end of a function body or an initialization expression
///
/// Payload is `nop`
@ -80,13 +84,13 @@ pub const Inst = struct {
///
/// Uses `nop`
@"return" = 0x0F,
/// Calls a function using `nav_index`.
call_nav,
/// Calls a function pointer by its function signature
/// and index into the function table.
///
/// Uses `label`
/// Uses `func_ty`
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.
@ -94,9 +98,11 @@ pub const Inst = struct {
/// The function is the auto-generated tag name function for the type
/// provided in `ip_index`.
call_tag_name,
/// Contains a symbol to a function pointer
/// uses `label`
/// Lowers to an i32_const containing the index of a function.
/// When emitting an object file, this adds a relocation.
/// Uses `ip_index`.
function_index,
/// Pops three values from the stack and pushes
/// the first or second value dependent on the third value.
/// Uses `tag`
@ -115,15 +121,11 @@ pub const Inst = struct {
///
/// Uses `label`
local_tee = 0x22,
/// Loads a (mutable) global at given index onto the stack
/// Pops a value from the stack and sets the stack pointer global.
/// The value must be the same type as the stack pointer global.
///
/// Uses `label`
global_get = 0x23,
/// Pops a value from the stack and sets the global at given index.
/// Note: Both types must be equal and global must be marked mutable.
///
/// Uses `label`.
global_set = 0x24,
/// Uses `tag` (no additional data).
global_set_sp,
/// Loads a 32-bit integer from memory (data section) onto the stack
/// Pops the value from the stack which represents the offset into memory.
///
@ -259,19 +261,19 @@ pub const Inst = struct {
/// Loads a 32-bit signed immediate value onto the stack
///
/// Uses `imm32`
i32_const = 0x41,
i32_const,
/// Loads a i64-bit signed immediate value onto the stack
///
/// uses `payload` of type `Imm64`
i64_const = 0x42,
i64_const,
/// Loads a 32-bit float value onto the stack.
///
/// Uses `float32`
f32_const = 0x43,
f32_const,
/// Loads a 64-bit float value onto the stack.
///
/// Uses `payload` of type `Float64`
f64_const = 0x44,
f64_const,
/// Uses `tag`
i32_eqz = 0x45,
/// Uses `tag`
@ -525,25 +527,19 @@ pub const Inst = struct {
///
/// The `data` field depends on the extension instruction and
/// may contain additional data.
misc_prefix = 0xFC,
misc_prefix,
/// The instruction consists of a simd opcode.
/// The actual simd-opcode is found at payload's index.
///
/// The `data` field depends on the simd instruction and
/// may contain additional data.
simd_prefix = 0xFD,
simd_prefix,
/// The instruction consists of an atomics opcode.
/// The actual atomics-opcode is found at payload's index.
///
/// The `data` field depends on the atomics instruction and
/// may contain additional data.
atomics_prefix = 0xFE,
/// Contains a symbol to a memory address
/// Uses `label`
///
/// Note: This uses `0xFF` as value as it is unused and not reserved
/// by the wasm specification, making it safe to use.
memory_address = 0xFF,
/// From a given wasm opcode, returns a MIR tag.
pub fn fromOpcode(opcode: std.wasm.Opcode) Tag {
@ -563,30 +559,38 @@ pub const Inst = struct {
/// Uses no additional data
tag: void,
/// Contains the result type of a block
///
/// Used by `block` and `loop`
block_type: u8,
/// Contains an u32 index into a wasm section entry, such as a local.
/// Note: This is not an index to another instruction.
///
/// Used by e.g. `local_get`, `local_set`, etc.
/// Label: Each structured control instruction introduces an implicit label.
/// Labels are targets for branch instructions that reference them with
/// label indices. Unlike with other index spaces, indexing of labels
/// is relative by nesting depth, that is, label 0 refers to the
/// innermost structured control instruction enclosing the referring
/// branch instruction, while increasing indices refer to those farther
/// out. Consequently, labels can only be referenced from within the
/// associated structured control instruction.
label: u32,
/// Local: The index space for locals is only accessible inside a function and
/// includes the parameters of that function, which precede the local
/// variables.
local: u32,
/// A 32-bit immediate value.
///
/// Used by `i32_const`
imm32: i32,
/// A 32-bit float value
///
/// Used by `f32_float`
float32: f32,
/// Index into `extra`. Meaning of what can be found there is context-dependent.
///
/// Used by e.g. `br_table`
payload: u32,
ip_index: InternPool.Index,
nav_index: InternPool.Nav.Index,
func_index: Wasm.FunctionIndex,
func_ty: Wasm.FunctionType.Index,
comptime {
switch (builtin.mode) {
.Debug, .ReleaseSafe => {},
.ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4),
}
}
};
};
@ -616,28 +620,19 @@ pub const JumpTable = struct {
length: u32,
};
/// Stores an unsigned 64bit integer
/// into a 32bit most significant bits field
/// and a 32bit least significant bits field.
///
/// This uses an unsigned integer rather than a signed integer
/// as we can easily store those into `extra`
pub const Imm64 = struct {
msb: u32,
lsb: u32,
pub fn fromU64(imm: u64) Imm64 {
pub fn init(full: u64) Imm64 {
return .{
.msb = @as(u32, @truncate(imm >> 32)),
.lsb = @as(u32, @truncate(imm)),
.msb = @truncate(full >> 32),
.lsb = @truncate(full),
};
}
pub fn toU64(self: Imm64) u64 {
var result: u64 = 0;
result |= @as(u64, self.msb) << 32;
result |= @as(u64, self.lsb);
return result;
pub fn toInt(i: Imm64) u64 {
return (@as(u64, i.msb) << 32) | @as(u64, i.lsb);
}
};
@ -645,23 +640,16 @@ pub const Float64 = struct {
msb: u32,
lsb: u32,
pub fn fromFloat64(float: f64) Float64 {
const tmp = @as(u64, @bitCast(float));
pub fn init(f: f64) Float64 {
const int: u64 = @bitCast(f);
return .{
.msb = @as(u32, @truncate(tmp >> 32)),
.lsb = @as(u32, @truncate(tmp)),
.msb = @truncate(int >> 32),
.lsb = @truncate(int),
};
}
pub fn toF64(self: Float64) f64 {
@as(f64, @bitCast(self.toU64()));
}
pub fn toU64(self: Float64) u64 {
var result: u64 = 0;
result |= @as(u64, self.msb) << 32;
result |= @as(u64, self.lsb);
return result;
pub fn toInt(f: Float64) u64 {
return (@as(u64, f.msb) << 32) | @as(u64, f.lsb);
}
};
@ -670,11 +658,9 @@ pub const MemArg = struct {
alignment: u32,
};
/// Represents a memory address, which holds both the pointer
/// or the parent pointer and the offset to it.
pub const Memory = struct {
pointer: u32,
offset: u32,
pub const UavRefOff = struct {
ip_index: InternPool.Index,
offset: i32,
};
/// Maps a source line with wasm bytecode

View File

@ -1040,7 +1040,7 @@ pub fn generateLazy(
emit.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?),
error.InvalidInstruction => return function.fail("failed to find a viable x86 instruction (Zig compiler bug)", .{}),
error.CannotEncode => return function.fail("failed to find encode x86 instruction (Zig compiler bug)", .{}),
error.CannotEncode => return function.fail("failed to encode x86 instruction (Zig compiler bug)", .{}),
else => |e| return function.fail("failed to emit MIR: {s}", .{@errorName(e)}),
};
}

View File

@ -1838,11 +1838,11 @@ pub const Object = struct {
o: *Object,
zcu: *Zcu,
exported_value: InternPool.Index,
export_indices: []const u32,
export_indices: []const Zcu.Export.Index,
) link.File.UpdateExportsError!void {
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const main_exp_name = try o.builder.strtabString(zcu.all_exports.items[export_indices[0]].opts.name.toSlice(ip));
const main_exp_name = try o.builder.strtabString(export_indices[0].ptr(zcu).opts.name.toSlice(ip));
const global_index = i: {
const gop = try o.uav_map.getOrPut(gpa, exported_value);
if (gop.found_existing) {
@ -1873,11 +1873,11 @@ pub const Object = struct {
o: *Object,
zcu: *Zcu,
global_index: Builder.Global.Index,
export_indices: []const u32,
export_indices: []const Zcu.Export.Index,
) link.File.UpdateExportsError!void {
const comp = zcu.comp;
const ip = &zcu.intern_pool;
const first_export = zcu.all_exports.items[export_indices[0]];
const first_export = export_indices[0].ptr(zcu);
// We will rename this global to have a name matching `first_export`.
// Successive exports become aliases.
@ -1934,7 +1934,7 @@ pub const Object = struct {
// 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 (export_indices[1..]) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
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) {

View File

@ -469,7 +469,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
defer export_names.deinit(gpa);
try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
for (zcu.single_exports.values()) |export_index| {
export_names.putAssumeCapacity(zcu.all_exports.items[export_index].opts.name, {});
export_names.putAssumeCapacity(export_index.ptr(zcu).opts.name, {});
}
for (zcu.multi_exports.values()) |info| {
try export_names.ensureUnusedCapacity(gpa, info.len);

View File

@ -1478,7 +1478,7 @@ pub fn updateExports(
coff: *Coff,
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 != .coff) {
@panic("Attempted to compile for object format that was disabled by build configuration");
@ -1493,7 +1493,7 @@ pub fn updateExports(
// Even in the case of LLVM, we need to notice certain exported symbols in order to
// detect the default subsystem.
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
const exported_nav_index = switch (exp.exported) {
.nav => |nav| nav,
.uav => continue,
@ -1536,7 +1536,7 @@ pub fn updateExports(
break :blk coff.navs.getPtr(nav).?;
},
.uav => |uav| coff.uavs.getPtr(uav) orelse blk: {
const first_exp = zcu.all_exports.items[export_indices[0]];
const first_exp = export_indices[0].ptr(zcu);
const res = try coff.lowerUav(pt, uav, .none, first_exp.src);
switch (res) {
.mcv => {},
@ -1555,7 +1555,7 @@ pub fn updateExports(
const atom = coff.getAtom(atom_index);
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
log.debug("adding new export '{}'", .{exp.opts.name.fmt(&zcu.intern_pool)});
if (exp.opts.section.toSlice(&zcu.intern_pool)) |section_name| {

View File

@ -1758,7 +1758,7 @@ pub fn updateExports(
break :blk self.navs.getPtr(nav).?;
},
.uav => |uav| self.uavs.getPtr(uav) orelse blk: {
const first_exp = zcu.all_exports.items[export_indices[0]];
const first_exp = export_indices[0].ptr(zcu);
const res = try self.lowerUav(elf_file, pt, uav, .none, first_exp.src);
switch (res) {
.mcv => {},
@ -1779,7 +1779,7 @@ pub fn updateExports(
const esym_shndx = self.symtab.items(.shndx)[esym_index];
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
if (exp.opts.section.unwrap()) |section_name| {
if (!section_name.eqlSlice(".text", &zcu.intern_pool)) {
try zcu.failed_exports.ensureUnusedCapacity(zcu.gpa, 1);

View File

@ -1259,7 +1259,7 @@ pub fn updateExports(
break :blk self.navs.getPtr(nav).?;
},
.uav => |uav| self.uavs.getPtr(uav) orelse blk: {
const first_exp = zcu.all_exports.items[export_indices[0]];
const first_exp = export_indices[0].ptr(zcu);
const res = try self.lowerUav(macho_file, pt, uav, .none, first_exp.src);
switch (res) {
.mcv => {},
@ -1279,7 +1279,7 @@ pub fn updateExports(
const nlist = self.symtab.items(.nlist)[nlist_idx];
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
if (exp.opts.section.unwrap()) |section_name| {
if (!section_name.eqlSlice("__text", &zcu.intern_pool)) {
try zcu.failed_exports.ensureUnusedCapacity(zcu.gpa, 1);

View File

@ -345,6 +345,7 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void
try a.writer().writeInt(u16, 1, .big);
// getting the full file path
// TODO don't call getcwd here, that is inappropriate
var buf: [std.fs.max_path_bytes]u8 = undefined;
const full_path = try std.fs.path.join(arena, &.{
file.mod.root.root_dir.path orelse try std.posix.getcwd(&buf),
@ -415,7 +416,7 @@ pub fn updateFunc(
};
defer dbg_info_output.dbg_line.deinit();
const res = try codegen.generateFunction(
try codegen.generateFunction(
&self.base,
pt,
zcu.navSrcLoc(func.owner_nav),
@ -425,10 +426,7 @@ pub fn updateFunc(
&code_buffer,
.{ .plan9 = &dbg_info_output },
);
const code = switch (res) {
.ok => try code_buffer.toOwnedSlice(),
.fail => |em| return zcu.failed_codegen.put(gpa, func.owner_nav, em),
};
const code = try code_buffer.toOwnedSlice();
self.getAtomPtr(atom_idx).code = .{
.code_ptr = null,
.other = .{ .nav_index = func.owner_nav },
@ -439,7 +437,9 @@ pub fn updateFunc(
.start_line = dbg_info_output.start_line.?,
.end_line = dbg_info_output.end_line,
};
try self.putFn(func.owner_nav, out);
// The awkward error handling here is due to putFn calling `std.posix.getcwd` which it should not do.
self.putFn(func.owner_nav, out) catch |err|
return zcu.codegenFail(func.owner_nav, "failed to put fn: {s}", .{@errorName(err)});
return self.updateFinish(pt, func.owner_nav);
}
@ -915,25 +915,25 @@ pub fn flushModule(
}
fn addNavExports(
self: *Plan9,
mod: *Zcu,
zcu: *Zcu,
nav_index: InternPool.Nav.Index,
export_indices: []const u32,
export_indices: []const Zcu.Export.Index,
) !void {
const gpa = self.base.comp.gpa;
const metadata = self.navs.getPtr(nav_index).?;
const atom = self.getAtom(metadata.index);
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const exp = export_idx.ptr(zcu);
const exp_name = exp.opts.name.toSlice(&zcu.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))
if (!section_name.eqlSlice(".text", &zcu.intern_pool) and
!section_name.eqlSlice(".data", &zcu.intern_pool))
{
try mod.failed_exports.put(mod.gpa, export_idx, try Zcu.ErrorMsg.create(
try zcu.failed_exports.put(zcu.gpa, export_idx, try Zcu.ErrorMsg.create(
gpa,
mod.navSrcLoc(nav_index),
zcu.navSrcLoc(nav_index),
"plan9 does not support extra sections",
.{},
));
@ -1252,7 +1252,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
try self.writeSym(writer, sym);
if (self.nav_exports.get(nav_index)) |export_indices| {
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
try self.writeSym(writer, self.syms.items[exp_i]);
}
@ -1291,7 +1291,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
try self.writeSym(writer, sym);
if (self.nav_exports.get(nav_index)) |export_indices| {
for (export_indices) |export_idx| {
const exp = zcu.all_exports.items[export_idx];
const exp = export_idx.ptr(zcu);
if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
const s = self.syms.items[exp_i];
if (mem.eql(u8, s.name, "_start"))

View File

@ -30,6 +30,7 @@ const log = std.log.scoped(.link);
const mem = std.mem;
const Air = @import("../Air.zig");
const Mir = @import("../arch/wasm/Mir.zig");
const CodeGen = @import("../arch/wasm/CodeGen.zig");
const Compilation = @import("../Compilation.zig");
const Dwarf = @import("Dwarf.zig");
@ -151,6 +152,7 @@ dump_argv_list: std.ArrayListUnmanaged([]const u8),
preloaded_strings: PreloadedStrings,
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Nav) = .empty,
zcu_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuFunc) = .empty,
nav_exports: std.AutoArrayHashMapUnmanaged(NavExport, Zcu.Export.Index) = .empty,
uav_exports: std.AutoArrayHashMapUnmanaged(UavExport, Zcu.Export.Index) = .empty,
imports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
@ -203,6 +205,13 @@ table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .
any_exports_updated: bool = true,
/// All MIR instructions for all Zcu functions.
mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
/// Corresponds to `mir_instructions`.
mir_extra: std.ArrayListUnmanaged(u32) = .empty,
/// All local types for all Zcu functions.
all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,
/// Index into `objects`.
pub const ObjectIndex = enum(u32) {
_,
@ -439,6 +448,24 @@ pub const Nav = extern struct {
};
};
pub const ZcuFunc = extern struct {
function: CodeGen.Function,
/// Index into `zcu_funcs`.
/// Note that swapRemove is sometimes performed on `zcu_funcs`.
pub const Index = enum(u32) {
_,
pub fn key(i: @This(), wasm: *const Wasm) *InternPool.Index {
return &wasm.zcu_funcs.keys()[@intFromEnum(i)];
}
pub fn value(i: @This(), wasm: *const Wasm) *ZcuFunc {
return &wasm.zcu_funcs.values()[@intFromEnum(i)];
}
};
};
pub const NavExport = extern struct {
name: String,
nav_index: InternPool.Nav.Index,
@ -932,7 +959,7 @@ pub const ValtypeList = enum(u32) {
}
pub fn slice(index: ValtypeList, wasm: *const Wasm) []const std.wasm.Valtype {
return @bitCast(String.slice(@enumFromInt(@intFromEnum(index)), wasm));
return @ptrCast(String.slice(@enumFromInt(@intFromEnum(index)), wasm));
}
};
@ -1430,12 +1457,17 @@ pub fn deinit(wasm: *Wasm) void {
if (wasm.llvm_object) |llvm_object| llvm_object.deinit();
wasm.navs.deinit(gpa);
wasm.zcu_funcs.deinit(gpa);
wasm.nav_exports.deinit(gpa);
wasm.uav_exports.deinit(gpa);
wasm.imports.deinit(gpa);
wasm.flush_buffer.deinit(gpa);
wasm.mir_instructions.deinit(gpa);
wasm.mir_extra.deinit(gpa);
wasm.all_zcu_locals.deinit(gpa);
if (wasm.dwarf) |*dwarf| dwarf.deinit();
wasm.object_function_imports.deinit(gpa);
@ -1474,49 +1506,11 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
}
if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = pt.zcu.funcInfo(func_index);
const nav_index = func.owner_nav;
const code_start: u32 = @intCast(wasm.string_bytes.items.len);
const relocs_start: u32 = @intCast(wasm.relocations.len);
wasm.string_bytes_lock.lock();
dev.check(.wasm_backend);
try CodeGen.generate(
&wasm.base,
pt,
zcu.navSrcLoc(nav_index),
func_index,
air,
liveness,
&wasm.string_bytes,
.none,
);
const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
const relocs_len: u32 = @intCast(wasm.relocations.len - relocs_start);
wasm.string_bytes_lock.unlock();
const code: Nav.Code = .{
.off = code_start,
.len = code_len,
};
const gop = try wasm.navs.getOrPut(gpa, nav_index);
if (gop.found_existing) {
@panic("TODO reuse these resources");
} else {
_ = wasm.imports.swapRemove(nav_index);
}
gop.value_ptr.* = .{
.code = code,
.relocs = .{
.off = relocs_start,
.len = relocs_len,
},
};
try wasm.zcu_funcs.put(pt.zcu.gpa, func_index, .{
.function = try CodeGen.function(wasm, pt, func_index, air, liveness),
});
}
// Generate code for the "Nav", storing it in memory to be later written to
@ -1642,8 +1636,8 @@ pub fn updateExports(
const exp = export_idx.ptr(zcu);
const name = try wasm.internString(exp.opts.name.toSlice(ip));
switch (exported) {
.nav => |nav_index| wasm.nav_exports.put(gpa, .{ .nav_index = nav_index, .name = name }, export_idx),
.uav => |uav_index| wasm.uav_exports.put(gpa, .{ .uav_index = uav_index, .name = name }, export_idx),
.nav => |nav_index| try wasm.nav_exports.put(gpa, .{ .nav_index = nav_index, .name = name }, export_idx),
.uav => |uav_index| try wasm.uav_exports.put(gpa, .{ .uav_index = uav_index, .name = name }, export_idx),
}
}
wasm.any_exports_updated = true;
@ -1713,9 +1707,9 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
continue;
}
}
try wasm.missing_exports.put(exp_name_interned, {});
try missing_exports.put(gpa, exp_name_interned, {});
}
wasm.missing_exports_init = try gpa.dupe(String, wasm.missing_exports.keys());
wasm.missing_exports_init = try gpa.dupe(String, missing_exports.keys());
}
if (wasm.entry_name.unwrap()) |entry_name| {
@ -2347,14 +2341,6 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
}
}
/// Returns the symbol index of the error name table.
///
/// When the symbol does not yet exist, it will create a new one instead.
pub fn getErrorTableSymbol(wasm: *Wasm, pt: Zcu.PerThread) !u32 {
const sym_index = try wasm.zig_object.?.getErrorTableSymbol(wasm, pt);
return @intFromEnum(sym_index);
}
fn defaultEntrySymbolName(
preloaded_strings: *const PreloadedStrings,
wasi_exec_model: std.builtin.WasiExecModel,