mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
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:
parent
b9355edfb1
commit
e521879e47
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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)}),
|
||||
};
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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| {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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"))
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user