diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 5440147296..361fd96374 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1286,8 +1286,9 @@ fn genFunc(func: *CodeGen) InnerError!void { var prologue = std.ArrayList(Mir.Inst).init(func.gpa); defer prologue.deinit(); + const sp = @intFromEnum(func.bin_file.zigObjectPtr().?.stack_pointer_sym); // load stack pointer - try prologue.append(.{ .tag = .global_get, .data = .{ .label = 0 } }); + try prologue.append(.{ .tag = .global_get, .data = .{ .label = sp } }); // store stack pointer so we can restore it when we return from the function try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); // get the total stack size @@ -1303,7 +1304,7 @@ fn genFunc(func: *CodeGen) InnerError!void { try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.bottom_stack_value.local.value } }); // Store the current stack pointer value into the global stack pointer so other function calls will // start from this value instead and not overwrite the current stack. - try prologue.append(.{ .tag = .global_set, .data = .{ .label = 0 } }); + try prologue.append(.{ .tag = .global_set, .data = .{ .label = sp } }); // reserve space and insert all prologue instructions at the front of the instruction list // We insert them in reserve order as there is no insertSlice in multiArrayList. @@ -1502,7 +1503,7 @@ fn restoreStackPointer(func: *CodeGen) !void { try func.emitWValue(func.initial_stack_value); // save its value in the global stack pointer - try func.addLabel(.global_set, 0); + try func.addLabel(.global_set, @intFromEnum(func.bin_file.zigObjectPtr().?.stack_pointer_sym)); } /// From a given type, will create space on the virtual stack to store the value of such type. @@ -2205,7 +2206,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif const type_index = try func.bin_file.storeDeclType(extern_func.decl, func_type); try func.bin_file.addOrUpdateImport( mod.intern_pool.stringToSlice(ext_decl.name), - atom.getSymbolIndex().?, + atom.sym_index, mod.intern_pool.stringToSliceUnwrap(ext_decl.getOwnedExternFunc(mod).?.lib_name), type_index, ); @@ -2240,7 +2241,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif if (callee) |direct| { const atom_index = func.bin_file.zigObjectPtr().?.decls_map.get(direct).?.atom; - try func.addLabel(.call, func.bin_file.getAtom(atom_index).sym_index); + try func.addLabel(.call, @intFromEnum(func.bin_file.getAtom(atom_index).sym_index)); } else { // in this case we call a function pointer // so load its value onto the stack @@ -3158,7 +3159,7 @@ fn lowerAnonDeclRef( }, } const target_atom_index = func.bin_file.zigObjectPtr().?.anon_decls.get(decl_val).?; - const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?; + const target_sym_index = @intFromEnum(func.bin_file.getAtom(target_atom_index).sym_index); if (is_fn_body) { return WValue{ .function_index = target_sym_index }; } else if (offset == 0) { @@ -3189,7 +3190,7 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.Decl const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); const atom = func.bin_file.getAtom(atom_index); - const target_sym_index = atom.sym_index; + const target_sym_index = @intFromEnum(atom.sym_index); if (decl.ty.zigTypeTag(mod) == .Fn) { return WValue{ .function_index = target_sym_index }; } else if (offset == 0) { @@ -3711,7 +3712,7 @@ fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try func.resolveInst(un_op); const sym_index = try func.bin_file.getGlobalSymbol("__zig_errors_len", null); - const errors_len = WValue{ .memory = sym_index }; + const errors_len = WValue{ .memory = @intFromEnum(sym_index) }; try func.emitWValue(operand); const mod = func.bin_file.base.comp.module.?; @@ -7153,7 +7154,7 @@ fn callIntrinsic( args: []const WValue, ) InnerError!WValue { assert(param_types.len == args.len); - const symbol_index = func.bin_file.base.getGlobalSymbol(name, null) catch |err| { + const symbol_index = func.bin_file.getGlobalSymbol(name, null) catch |err| { return func.fail("Could not find or create global symbol '{s}'", .{@errorName(err)}); }; @@ -7181,7 +7182,7 @@ fn callIntrinsic( } // Actually call our intrinsic - try func.addLabel(.call, symbol_index); + try func.addLabel(.call, @intFromEnum(symbol_index)); if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { return WValue.none; @@ -7224,7 +7225,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { // check if we already generated code for this. if (func.bin_file.findGlobalSymbol(func_name)) |loc| { - return loc.index; + return @intFromEnum(loc.index); } const int_tag_ty = enum_ty.intTagType(mod); @@ -7364,7 +7365,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { const slice_ty = Type.slice_const_u8_sentinel_0; const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty.ip_index}, slice_ty, mod); - return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); + const sym_index = try func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); + return @intFromEnum(sym_index); } fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index a50c0bedfe..ce5f451a6f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -127,7 +127,7 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, /// This allows us to map multiple symbols to the same function. functions: std.AutoArrayHashMapUnmanaged( struct { file: File.Index, index: u32 }, - struct { func: std.wasm.Func, sym_index: u32 }, + struct { func: std.wasm.Func, sym_index: Symbol.Index }, ) = .{}, /// Output global section wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, @@ -208,13 +208,9 @@ pub const Segment = struct { } }; -pub const Export = struct { - sym_index: ?u32 = null, -}; - pub const SymbolLoc = struct { /// The index of the symbol within the specified file - index: u32, + index: Symbol.Index, /// The index of the object file where the symbol resides. file: File.Index, @@ -226,7 +222,7 @@ pub const SymbolLoc = struct { if (wasm_file.file(loc.file)) |obj_file| { return obj_file.symbol(loc.index); } - return &wasm_file.synthetic_symbols.items[loc.index]; + return &wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)]; } /// From a given location, returns the name of the symbol. @@ -237,7 +233,8 @@ pub const SymbolLoc = struct { if (wasm_file.file(loc.file)) |obj_file| { return obj_file.symbolName(loc.index); } - return wasm_file.string_table.get(wasm_file.synthetic_symbols.items[loc.index].name); + const sym = wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)]; + return wasm_file.string_table.get(sym.name); } /// From a given symbol location, returns the final location. @@ -272,7 +269,7 @@ pub const InitFuncLoc = struct { /// Turns the given `InitFuncLoc` into a `SymbolLoc` fn getSymbolLoc(loc: InitFuncLoc) SymbolLoc { - return .{ .file = loc.file, .index = loc.index }; + return .{ .file = loc.file, .index = @enumFromInt(loc.index) }; } /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`. @@ -566,7 +563,7 @@ pub fn createEmpty( var zig_object: ZigObject = .{ .index = index, .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}), - .stack_pointer_sym = undefined, + .stack_pointer_sym = .null, }; try zig_object.init(wasm); try wasm.files.append(gpa, .{ .zig_object = zig_object }); @@ -607,7 +604,7 @@ pub fn addOrUpdateImport( /// Name of the import name: []const u8, /// Symbol index that is external - symbol_index: u32, + symbol_index: Symbol.Index, /// Optional library name (i.e. `extern "c" fn foo() void` lib_name: ?[:0]const u8, /// The index of the type that represents the function signature @@ -627,7 +624,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol } fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { - const sym_index = @as(u32, @intCast(wasm.synthetic_symbols.items.len)); + const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); const loc: SymbolLoc = .{ .index = sym_index, .file = .null }; const gpa = wasm.base.comp.gpa; try wasm.synthetic_symbols.append(gpa, .{ @@ -670,9 +667,9 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { } /// Creates a new empty `Atom` and returns its `Atom.Index` -pub fn createAtom(wasm: *Wasm, sym_index: u32, file_index: File.Index) !Atom.Index { +pub fn createAtom(wasm: *Wasm, sym_index: Symbol.Index, file_index: File.Index) !Atom.Index { const gpa = wasm.base.comp.gpa; - const index: Atom.Index = @intCast(wasm.managed_atoms.items.len); + const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len); const atom = try wasm.managed_atoms.addOne(gpa); atom.* = .{ .file = file_index, .sym_index = sym_index }; try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index); @@ -681,11 +678,11 @@ pub fn createAtom(wasm: *Wasm, sym_index: u32, file_index: File.Index) !Atom.Ind } pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom { - return wasm.managed_atoms.items[index]; + return wasm.managed_atoms.items[@intFromEnum(index)]; } pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom { - return &wasm.managed_atoms.items[index]; + return &wasm.managed_atoms.items[@intFromEnum(index)]; } /// Parses an archive file and will then parse each object file @@ -757,7 +754,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()}); for (obj_file.symbols(), 0..) |symbol, i| { - const sym_index: u32 = @intCast(i); + const sym_index: Symbol.Index = @enumFromInt(i); const location: SymbolLoc = .{ .file = file_index, .index = sym_index }; const sym_name = obj_file.string(symbol.name); if (mem.eql(u8, sym_name, "__indirect_function_table")) { @@ -1489,7 +1486,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec /// such as an exported or imported symbol. /// If the symbol does not yet exist, creates a new one symbol instead /// and then returns the index to it. -pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 { +pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { _ = lib_name; return wasm.zigObjectPtr().?.getGlobalSymbol(wasm.base.comp.gpa, name); } @@ -1609,19 +1606,20 @@ fn allocateAtoms(wasm: *Wasm) !void { const sym = if (wasm.file(symbol_loc.file)) |obj_file| obj_file.symbol(symbol_loc.index).* else - wasm.synthetic_symbols.items[symbol_loc.index]; + wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)]; // Dead symbols must be unlinked from the linked-list to prevent them // from being emit into the binary. if (sym.isDead()) { - if (entry.value_ptr.* == atom_index and atom.prev != null) { + if (entry.value_ptr.* == atom_index and atom.prev != .null) { // When the atom is dead and is also the first atom retrieved from wasm.atoms(index) we update // the entry to point it to the previous atom to ensure we do not start with a dead symbol that // was removed and therefore do not emit any code at all. - entry.value_ptr.* = atom.prev.?; + entry.value_ptr.* = atom.prev; } - atom_index = atom.prev orelse break; - atom.prev = null; + if (atom.prev == .null) break; + atom_index = atom.prev; + atom.prev = .null; continue; } offset = @intCast(atom.alignment.forward(offset)); @@ -1633,7 +1631,8 @@ fn allocateAtoms(wasm: *Wasm) !void { atom.size, }); offset += atom.size; - atom_index = atom.prev orelse break; + if (atom.prev == .null) break; + atom_index = atom.prev; } segment.size = @intCast(segment.alignment.forward(offset)); } @@ -1738,7 +1737,7 @@ fn setupInitFunctions(wasm: *Wasm) !void { .file = file_index, .priority = init_func.priority, }); - try wasm.mark(.{ .index = init_func.symbol_index, .file = file_index }); + try wasm.mark(.{ .index = @enumFromInt(init_func.symbol_index), .file = file_index }); } } @@ -1844,7 +1843,7 @@ pub fn createFunction( func_ty: std.wasm.Type, function_body: *std.ArrayList(u8), relocations: *std.ArrayList(Relocation), -) !u32 { +) !Symbol.Index { return wasm.zigObjectPtr().?.createFunction(wasm, symbol_name, func_ty, function_body, relocations); } @@ -2324,11 +2323,11 @@ fn setupMemory(wasm: *Wasm) !void { /// From a given object's index and the index of the segment, returns the corresponding /// index of the segment within the final data section. When the segment does not yet /// exist, a new one will be initialized and appended. The new index will be returned in that case. -pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: u32) !u32 { +pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Symbol.Index) !u32 { const comp = wasm.base.comp; const gpa = comp.gpa; const obj_file = wasm.file(file_index).?; - const symbol = obj_file.symbols()[symbol_index]; + const symbol = obj_file.symbols()[@intFromEnum(symbol_index)]; const index: u32 = @intCast(wasm.segments.items.len); const shared_memory = comp.config.shared_memory; @@ -2889,8 +2888,8 @@ fn writeToFile( try binary_writer.writeAll(atom.code.items); current_offset += atom.size; - if (atom.prev) |prev| { - atom_index = prev; + if (atom.prev != .null) { + atom_index = atom.prev; } else { // also pad with zeroes when last atom to ensure // segments are aligned. @@ -2984,7 +2983,8 @@ fn writeToFile( while (true) { atom.resolveRelocs(wasm); try debug_bytes.appendSlice(atom.code.items); - atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; + if (atom.prev == .null) break; + atom = wasm.getAtomPtr(atom.prev); } try emitDebugSection(&binary_bytes, debug_bytes.items, item.name); debug_bytes.clearRetainingCapacity(); @@ -3853,7 +3853,7 @@ fn emitCodeRelocations( size_offset += getULEB128Size(atom.size); for (atom.relocs.items) |relocation| { count += 1; - const sym_loc: SymbolLoc = .{ .file = atom.file, .index = relocation.index }; + const sym_loc: SymbolLoc = .{ .file = atom.file, .index = @enumFromInt(relocation.index) }; const symbol_index = symbol_table.get(sym_loc).?; try leb.writeULEB128(writer, @intFromEnum(relocation.relocation_type)); const offset = atom.offset + relocation.offset + size_offset; @@ -3864,7 +3864,8 @@ fn emitCodeRelocations( } log.debug("Emit relocation: {}", .{relocation}); } - atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; + if (atom.prev == .null) break; + atom = wasm.getAtomPtr(atom.prev); } if (count == 0) return; var buf: [5]u8 = undefined; @@ -3900,7 +3901,7 @@ fn emitDataRelocations( size_offset += getULEB128Size(atom.size); for (atom.relocs.items) |relocation| { count += 1; - const sym_loc: SymbolLoc = .{ .file = atom.file, .index = relocation.index }; + const sym_loc: SymbolLoc = .{ .file = atom.file, .index = @enumFromInt(relocation.index) }; const symbol_index = symbol_table.get(sym_loc).?; try leb.writeULEB128(writer, @intFromEnum(relocation.relocation_type)); const offset = atom.offset + relocation.offset + size_offset; @@ -3911,7 +3912,8 @@ fn emitDataRelocations( } log.debug("Emit relocation: {}", .{relocation}); } - atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; + if (atom.prev == .null) break; + atom = wasm.getAtomPtr(atom.prev); } } if (count == 0) return; @@ -3969,7 +3971,8 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s /// /// When the symbol does not yet exist, it will create a new one instead. pub fn getErrorTableSymbol(wasm_file: *Wasm) !u32 { - return wasm_file.zigObjectPtr().?.getErrorTableSymbol(wasm_file); + const sym_index = try wasm_file.zigObjectPtr().?.getErrorTableSymbol(wasm_file); + return @intFromEnum(sym_index); } /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. @@ -4029,7 +4032,7 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void { const atom = wasm.getAtom(atom_index); for (atom.relocs.items) |reloc| { - const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file }; + const target_loc: SymbolLoc = .{ .index = @enumFromInt(reloc.index), .file = loc.file }; try wasm.mark(target_loc.finalLoc(wasm)); } } diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index ade66b687f..77d0790086 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -2,7 +2,7 @@ /// This is 'null' when the atom was generated by a synthetic linker symbol. file: FileIndex, /// symbol index of the symbol representing this atom -sym_index: u32, +sym_index: Symbol.Index, /// Size of the atom, used to calculate section sizes in the final binary size: u32 = 0, /// List of relocations belonging to this atom @@ -17,19 +17,19 @@ offset: u32 = 0, /// The original offset within the object file. This value is substracted from /// relocation offsets to determine where in the `data` to rewrite the value original_offset: u32 = 0, -/// Next atom in relation to this atom. -/// When null, this atom is the last atom -next: ?Atom.Index = null, /// Previous atom in relation to this atom. /// is null when this atom is the first in its order -prev: ?Atom.Index = null, +prev: Atom.Index = .null, /// Contains atoms local to a decl, all managed by this `Atom`. /// When the parent atom is being freed, it will also do so for all local atoms. locals: std.ArrayListUnmanaged(Atom.Index) = .{}, -/// Alias to an unsigned 32-bit integer. -// TODO: Make this a non-exhaustive enum. -pub const Index = u32; +/// Represents the index of an Atom where `null` is considered +/// an invalid atom. +pub const Index = enum(u32) { + null = std.math.maxInt(u32), + _, +}; /// Frees all resources owned by this `Atom`. pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void { @@ -50,7 +50,7 @@ pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptio _ = fmt; _ = options; try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{ - atom.sym_index, + @intFromEnum(atom.sym_index), atom.alignment, atom.size, atom.offset, @@ -62,11 +62,6 @@ pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { return .{ .file = atom.file, .index = atom.sym_index }; } -pub fn getSymbolIndex(atom: Atom) ?u32 { - if (atom.sym_index == 0) return null; - return atom.sym_index; -} - /// Resolves the relocations within the atom, writing the new value /// at the calculated offset. pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { @@ -80,7 +75,7 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { for (atom.relocs.items) |reloc| { const value = atom.relocationValue(reloc, wasm_bin); log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{ - (Wasm.SymbolLoc{ .file = atom.file, .index = reloc.index }).getName(wasm_bin), + (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(reloc.index) }).getName(wasm_bin), symbol_name, reloc.offset, value, @@ -119,7 +114,7 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { /// All values will be represented as a `u64` as all values can fit within it. /// The final value must be casted to the correct size. fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 { - const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin); + const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(relocation.index) }).finalLoc(wasm_bin); const symbol = target_loc.getSymbol(wasm_bin); if (relocation.relocation_type != .R_WASM_TYPE_INDEX_LEB and symbol.tag != .section and @@ -135,7 +130,7 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa .R_WASM_TABLE_INDEX_I64, .R_WASM_TABLE_INDEX_SLEB, .R_WASM_TABLE_INDEX_SLEB64, - => return wasm_bin.function_table.get(.{ .file = atom.file, .index = relocation.index }) orelse 0, + => return wasm_bin.function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0, .R_WASM_TYPE_INDEX_LEB => { const obj_file = wasm_bin.file(atom.file) orelse return relocation.index; const original_type = obj_file.funcTypes()[relocation.index]; @@ -195,6 +190,7 @@ fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 { } return null; } + const leb = std.leb; const log = std.log.scoped(.link); const mem = std.mem; diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 1c5640c526..297e71991d 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -907,10 +907,10 @@ fn assertEnd(reader: anytype) !void { } /// Parses an object file into atoms, for code and data sections -pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: u32) !Atom.Index { +pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: Symbol.Index) !Atom.Index { const comp = wasm.base.comp; const gpa = comp.gpa; - const symbol = &object.symtable[symbol_index]; + const symbol = &object.symtable[@intFromEnum(symbol_index)]; const relocatable_data: RelocatableData = switch (symbol.tag) { .function => object.relocatable_data.get(.code).?[symbol.index - object.imported_functions_count], .data => object.relocatable_data.get(.data).?[symbol.index], @@ -953,7 +953,7 @@ pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: u32) !Ato => { try wasm.function_table.put(gpa, .{ .file = object.index, - .index = reloc.index, + .index = @enumFromInt(reloc.index), }, 0); }, .R_WASM_GLOBAL_INDEX_I32, @@ -961,7 +961,7 @@ pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: u32) !Ato => { const sym = object.symtable[reloc.index]; if (sym.tag != .global) { - try wasm.got_symbols.append(gpa, .{ .file = object.index, .index = reloc.index }); + try wasm.got_symbols.append(gpa, .{ .file = object.index, .index = @enumFromInt(reloc.index) }); } }, else => {}, diff --git a/src/link/Wasm/Symbol.zig b/src/link/Wasm/Symbol.zig index 75c26ca10d..f913591fec 100644 --- a/src/link/Wasm/Symbol.zig +++ b/src/link/Wasm/Symbol.zig @@ -1,12 +1,8 @@ -//! Represents a wasm symbol. Containing all of its properties, +//! Represents a WebAssembly symbol. Containing all of its properties, //! as well as providing helper methods to determine its functionality //! and how it will/must be linked. //! The name of the symbol can be found by providing the offset, found //! on the `name` field, to a string table in the wasm binary or object file. -const Symbol = @This(); - -const std = @import("std"); -const types = @import("types.zig"); /// Bitfield containings flags for a symbol /// Can contain any of the flags defined in `Flag` @@ -24,6 +20,12 @@ tag: Tag, /// This differs from the offset of an `Atom` which is relative to the start of a segment. virtual_address: u32, +/// Represents a symbol index where `null` represents an invalid index. +pub const Index = enum(u32) { + null, + _, +}; + pub const Tag = enum { function, data, @@ -202,3 +204,7 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO .{ kind_fmt, binding, visible, symbol.index, symbol.name, undef }, ); } + +const std = @import("std"); +const types = @import("types.zig"); +const Symbol = @This(); diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 268448e41c..d47bb6b721 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -17,7 +17,7 @@ functions: std.ArrayListUnmanaged(std.wasm.Func) = .{}, /// List of indexes pointing to an entry within the `functions` list which has been removed. functions_free_list: std.ArrayListUnmanaged(u32) = .{}, /// Map of symbol locations, represented by its `types.Import`. -imports: std.AutoHashMapUnmanaged(u32, types.Import) = .{}, +imports: std.AutoHashMapUnmanaged(Symbol.Index, types.Import) = .{}, /// List of WebAssembly globals. globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, /// Mapping between an `Atom` and its type index representing the Wasm @@ -26,9 +26,9 @@ atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .{}, /// List of all symbols generated by Zig code. symbols: std.ArrayListUnmanaged(Symbol) = .{}, /// Map from symbol name offset to their index into the `symbols` list. -global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, +global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, /// List of symbol indexes which are free to be used. -symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, +symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, /// Extra metadata about the linking section, such as alignment of segments and their name. segment_info: std.ArrayListUnmanaged(types.Segment) = .{}, /// List of indexes which contain a free slot in the `segment_info` list. @@ -42,7 +42,7 @@ anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, /// During initializion, a symbol with corresponding atom will be created that is /// used to perform relocations to the pointer of this table. /// The actual table is populated during `flush`. -error_table_symbol: ?u32 = null, +error_table_symbol: Symbol.Index = .null, /// Amount of functions in the `import` sections. imported_functions_count: u32 = 0, /// Amount of globals in the `import` section. @@ -50,7 +50,7 @@ imported_globals_count: u32 = 0, /// Symbol index representing the stack pointer. This will be set upon initializion /// of a new `ZigObject`. Codegen will make calls into this to create relocations for /// this symbol each time the stack pointer is moved. -stack_pointer_sym: u32, +stack_pointer_sym: Symbol.Index, /// Debug information for the Zig module. dwarf: ?Dwarf = null, // Debug section atoms. These are only set when the current compilation @@ -83,10 +83,10 @@ debug_str_index: ?u32 = null, debug_abbrev_index: ?u32 = null, const DeclInfo = struct { - atom: Atom.Index = std.math.maxInt(Atom.Index), - exports: std.ArrayListUnmanaged(u32) = .{}, + atom: Atom.Index = .null, + exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, - fn @"export"(di: DeclInfo, zig_object: *const ZigObject, name: []const u8) ?u32 { + fn @"export"(di: DeclInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index { for (di.exports.items) |sym_index| { const sym_name_index = zig_object.symbol(sym_index).name; const sym_name = zig_object.string_table.getAssumeExists(sym_name_index); @@ -97,11 +97,11 @@ const DeclInfo = struct { return null; } - fn appendExport(di: *DeclInfo, gpa: std.mem.Allocator, sym_index: u32) !void { + fn appendExport(di: *DeclInfo, gpa: std.mem.Allocator, sym_index: Symbol.Index) !void { return di.exports.append(gpa, sym_index); } - fn deleteExport(di: *DeclInfo, sym_index: u32) void { + fn deleteExport(di: *DeclInfo, sym_index: Symbol.Index) void { for (di.exports.items, 0..) |idx, index| { if (idx == sym_index) { _ = di.exports.swapRemove(index); @@ -138,8 +138,8 @@ fn createStackPointer(zig_object: *ZigObject, wasm_file: *Wasm) !void { zig_object.stack_pointer_sym = sym_index; } -fn symbol(zig_object: *const ZigObject, index: u32) *Symbol { - return &zig_object.symbols.items[index]; +fn symbol(zig_object: *const ZigObject, index: Symbol.Index) *Symbol { + return &zig_object.symbols.items[@intFromEnum(index)]; } /// Frees and invalidates all memory of the incrementally compiled Zig module. @@ -192,7 +192,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void { /// Allocates a new symbol and returns its index. /// Will re-use slots when a symbol was freed at an earlier stage. -pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !u32 { +pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.Index { try zig_object.symbols.ensureUnusedCapacity(gpa, 1); const sym: Symbol = .{ .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls @@ -202,10 +202,10 @@ pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !u32 { .virtual_address = std.math.maxInt(u32), // will be set during atom allocation }; if (zig_object.symbols_free_list.popOrNull()) |index| { - zig_object.symbols.items[index] = sym; + zig_object.symbols.items[@intFromEnum(index)] = sym; return index; } - const index = @as(u32, @intCast(zig_object.symbols.items.len)); + const index: Symbol.Index = @enumFromInt(zig_object.symbols.items.len); zig_object.symbols.appendAssumeCapacity(sym); return index; } @@ -247,7 +247,7 @@ pub fn updateDecl( .{ .ty = decl.ty, .val = val }, &code_writer, .none, - .{ .parent_atom_index = atom.sym_index }, + .{ .parent_atom_index = @intFromEnum(atom.sym_index) }, ); const code = switch (res) { @@ -464,7 +464,7 @@ pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValu switch (try zig_object.lowerConst(wasm_file, name, tv, decl.srcLoc(mod))) { .ok => |atom_index| { try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); - return wasm_file.getAtom(atom_index).getSymbolIndex().?; + return @intFromEnum(wasm_file.getAtom(atom_index).sym_index); }, .fail => |em| { decl.analysis = .codegen_failure; @@ -494,7 +494,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty atom.alignment = tv.ty.abiAlignment(mod); const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name }); errdefer gpa.free(segment_name); - zig_object.symbols.items[sym_index] = .{ + zig_object.symbol(sym_index).* = .{ .name = try zig_object.string_table.insert(gpa, name), .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), .tag = .data, @@ -513,7 +513,7 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty &value_bytes, .none, .{ - .parent_atom_index = atom.sym_index, + .parent_atom_index = @intFromEnum(atom.sym_index), .addend = null, }, ); @@ -534,9 +534,9 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty /// 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(zig_object: *ZigObject, wasm_file: *Wasm) !u32 { - if (zig_object.error_table_symbol) |sym| { - return sym; +pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !Symbol.Index { + if (zig_object.error_table_symbol != .null) { + return zig_object.error_table_symbol; } // no error was referenced yet, so create a new symbol and atom for it @@ -561,7 +561,7 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !u32 { .virtual_address = undefined, }; - log.debug("Error name table was created with symbol index: ({d})", .{sym_index}); + log.debug("Error name table was created with symbol index: ({d})", .{@intFromEnum(sym_index)}); zig_object.error_table_symbol = sym_index; return sym_index; } @@ -571,9 +571,9 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !u32 { /// This creates a table that consists of pointers and length to each error name. /// The table is what is being pointed to within the runtime bodies that are generated. fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void { - const symbol_index = zig_object.error_table_symbol orelse return; + if (zig_object.error_table_symbol == .null) return; const gpa = wasm_file.base.comp.gpa; - const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = symbol_index }).?; + const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = zig_object.error_table_symbol }).?; // Rather than creating a symbol for each individual error name, // we create a symbol for the entire region of error names. We then calculate @@ -584,7 +584,7 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void { names_atom.alignment = .@"1"; const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names"); const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names"); - const names_symbol = &zig_object.symbols.items[names_sym_index]; + const names_symbol = zig_object.symbol(names_sym_index); names_symbol.* = .{ .name = sym_name, .tag = .data, @@ -611,7 +611,7 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void { try atom.code.writer(gpa).writeInt(u32, len - 1, .little); // create relocation to the error name try atom.relocs.append(gpa, .{ - .index = names_atom.sym_index, + .index = @intFromEnum(names_atom.sym_index), .relocation_type = .R_WASM_MEMORY_ADDR_I32, .offset = offset, .addend = @as(i32, @intCast(addend)), @@ -638,7 +638,7 @@ pub fn addOrUpdateImport( /// Name of the import name: []const u8, /// Symbol index that is external - symbol_index: u32, + symbol_index: Symbol.Index, /// Optional library name (i.e. `extern "c" fn foo() void` lib_name: ?[:0]const u8, /// The index of the type that represents the function signature @@ -647,7 +647,7 @@ pub fn addOrUpdateImport( type_index: ?u32, ) !void { const gpa = wasm_file.base.comp.gpa; - std.debug.assert(symbol_index != 0); + std.debug.assert(symbol_index != .null); // For the import name, we use the decl's name, rather than the fully qualified name // Also mangle the name when the lib name is set and not equal to "C" so imports with the same // name but different module can be resolved correctly. @@ -659,7 +659,7 @@ pub fn addOrUpdateImport( defer if (mangle_name) gpa.free(full_name); const decl_name_index = try zig_object.string_table.insert(gpa, full_name); - const sym: *Symbol = &zig_object.symbols.items[symbol_index]; + const sym: *Symbol = &zig_object.symbols.items[@intFromEnum(symbol_index)]; sym.setUndefined(true); sym.setGlobal(true); sym.name = decl_name_index; @@ -689,7 +689,7 @@ pub fn addOrUpdateImport( /// such as an exported or imported symbol. /// If the symbol does not yet exist, creates a new one symbol instead /// and then returns the index to it. -pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8) !u32 { +pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8) !Symbol.Index { const name_index = try zig_object.string_table.insert(gpa, name); const gop = try zig_object.global_syms.getOrPut(gpa, name_index); if (gop.found_existing) { @@ -707,12 +707,12 @@ pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []c sym.setUndefined(true); const sym_index = if (zig_object.symbols_free_list.popOrNull()) |index| index else blk: { - const index: u32 = @intCast(zig_object.symbols.items.len); + const index: Symbol.Index = @enumFromInt(zig_object.symbols.items.len); try zig_object.symbols.ensureUnusedCapacity(gpa, 1); zig_object.symbols.items.len += 1; break :blk index; }; - zig_object.symbols.items[sym_index] = sym; + zig_object.symbol(sym_index).* = sym; gop.value_ptr.* = sym_index; return sym_index; } @@ -731,10 +731,10 @@ pub fn getDeclVAddr( const decl = mod.declPtr(decl_index); const target_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index); - const target_symbol_index = wasm_file.getAtom(target_atom_index).sym_index; + const target_symbol_index = @intFromEnum(wasm_file.getAtom(target_atom_index).sym_index); std.debug.assert(reloc_info.parent_atom_index != 0); - const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = reloc_info.parent_atom_index }).?; + const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?; const atom = wasm_file.getAtomPtr(atom_index); const is_wasm32 = target.cpu.arch == .wasm32; if (decl.ty.zigTypeTag(mod) == .Fn) { @@ -769,9 +769,9 @@ pub fn getAnonDeclVAddr( const gpa = wasm_file.base.comp.gpa; const target = wasm_file.base.comp.root_mod.resolved_target.result; const atom_index = zig_object.anon_decls.get(decl_val).?; - const target_symbol_index = wasm_file.getAtom(atom_index).getSymbolIndex().?; + const target_symbol_index = @intFromEnum(wasm_file.getAtom(atom_index).sym_index); - const parent_atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = reloc_info.parent_atom_index }).?; + const parent_atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?; const parent_atom = wasm_file.getAtomPtr(parent_atom_index); const is_wasm32 = target.cpu.arch == .wasm32; const mod = wasm_file.base.comp.module.?; @@ -930,17 +930,7 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool // dwarf.freeDecl(decl_index); // } - if (atom.next) |next_atom_index| { - const next_atom = wasm_file.getAtomPtr(next_atom_index); - next_atom.prev = atom.prev; - atom.next = null; - } - if (atom.prev) |prev_index| { - const prev_atom = wasm_file.getAtomPtr(prev_index); - prev_atom.next = atom.next; - atom.prev = null; - } - + atom.prev = null; sym.tag = .dead; if (sym.isGlobal()) { std.debug.assert(zig_object.global_syms.remove(atom.sym_index)); @@ -998,7 +988,7 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void { // if not, allcoate a new atom. const atom_index = if (wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = sym_index })) |index| blk: { const atom = wasm_file.getAtomPtr(index); - atom.prev = null; + atom.prev = .null; atom.deinit(gpa); break :blk index; } else idx: { @@ -1022,7 +1012,7 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void { try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little); } -fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?u32 { +fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?Symbol.Index { const offset = zig_object.string_table.getOffset(name) orelse return null; return zig_object.global_syms.get(offset); } @@ -1121,7 +1111,7 @@ pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, decl_index: /// The symbols in ZigObject are already represented by an atom as we need to store its data. /// So rather than creating a new Atom and returning its index, we use this oppertunity to scan /// its relocations and create any GOT symbols or function table indexes it may require. -pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: u32) !Atom.Index { +pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symbol.Index) !Atom.Index { const gpa = wasm_file.base.comp.gpa; const loc: Wasm.SymbolLoc = .{ .file = zig_object.index, .index = index }; const atom_index = wasm_file.symbol_atom.get(loc).?; @@ -1129,6 +1119,7 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: u32) try wasm_file.appendAtomAtIndex(final_index, atom_index); const atom = wasm_file.getAtom(atom_index); for (atom.relocs.items) |reloc| { + const reloc_index: Symbol.Index = @enumFromInt(reloc.index); switch (reloc.relocation_type) { .R_WASM_TABLE_INDEX_I32, .R_WASM_TABLE_INDEX_I64, @@ -1137,17 +1128,17 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: u32) => { try wasm_file.function_table.put(gpa, .{ .file = zig_object.index, - .index = reloc.index, + .index = reloc_index, }, 0); }, .R_WASM_GLOBAL_INDEX_I32, .R_WASM_GLOBAL_INDEX_LEB, => { - const sym = zig_object.symbol(reloc.index); + const sym = zig_object.symbol(reloc_index); if (sym.tag != .global) { try wasm_file.got_symbols.append(gpa, .{ .file = zig_object.index, - .index = reloc.index, + .index = reloc_index, }); } }, @@ -1166,10 +1157,10 @@ pub fn createFunction( func_ty: std.wasm.Type, function_body: *std.ArrayList(u8), relocations: *std.ArrayList(types.Relocation), -) !u32 { +) !Symbol.Index { const gpa = wasm_file.base.comp.gpa; const sym_index = try zig_object.allocateSymbol(gpa); - const sym = &zig_object.symbols.items[sym_index]; + const sym = zig_object.symbol(sym_index); sym.tag = .function; sym.name = try zig_object.string_table.insert(gpa, symbol_name); const type_index = try zig_object.putOrGetFuncType(gpa, func_ty); diff --git a/src/link/Wasm/file.zig b/src/link/Wasm/file.zig index 1bb9805d83..e0ff121322 100644 --- a/src/link/Wasm/file.zig +++ b/src/link/Wasm/file.zig @@ -20,10 +20,10 @@ pub const File = union(enum) { }; } - pub fn symbol(file: File, index: u32) *Symbol { + pub fn symbol(file: File, index: Symbol.Index) *Symbol { return switch (file) { - .zig_object => |obj| &obj.symbols.items[index], - .object => |obj| &obj.symtable[index], + .zig_object => |obj| &obj.symbols.items[@intFromEnum(index)], + .object => |obj| &obj.symtable[@intFromEnum(index)], }; } @@ -34,20 +34,20 @@ pub const File = union(enum) { }; } - pub fn symbolName(file: File, index: u32) []const u8 { + pub fn symbolName(file: File, index: Symbol.Index) []const u8 { switch (file) { .zig_object => |obj| { - const sym = obj.symbols.items[index]; + const sym = obj.symbols.items[@intFromEnum(index)]; return obj.string_table.get(sym.name).?; }, .object => |obj| { - const sym = obj.symtable[index]; + const sym = obj.symtable[@intFromEnum(index)]; return obj.string_table.get(sym.name); }, } } - pub fn parseSymbolIntoAtom(file: File, wasm_file: *Wasm, index: u32) !AtomIndex { + pub fn parseSymbolIntoAtom(file: File, wasm_file: *Wasm, index: Symbol.Index) !AtomIndex { return switch (file) { inline else => |obj| obj.parseSymbolIntoAtom(wasm_file, index), }; @@ -55,10 +55,10 @@ pub const File = union(enum) { /// For a given symbol index, find its corresponding import. /// Asserts import exists. - pub fn import(file: File, symbol_index: u32) types.Import { + pub fn import(file: File, symbol_index: Symbol.Index) types.Import { return switch (file) { .zig_object => |obj| obj.imports.get(symbol_index).?, - .object => |obj| obj.findImport(obj.symtable[symbol_index]), + .object => |obj| obj.findImport(obj.symtable[@intFromEnum(symbol_index)]), }; } @@ -89,14 +89,14 @@ pub const File = union(enum) { }; } - pub fn function(file: File, sym_index: u32) std.wasm.Func { + pub fn function(file: File, sym_index: Symbol.Index) std.wasm.Func { switch (file) { .zig_object => |obj| { - const sym = obj.symbols.items[sym_index]; + const sym = obj.symbols.items[@intFromEnum(sym_index)]; return obj.functions.items[sym.index]; }, .object => |obj| { - const sym = obj.symtable[sym_index]; + const sym = obj.symtable[@intFromEnum(sym_index)]; return obj.functions[sym.index - obj.imported_functions_count]; }, }