diff options
| -rw-r--r-- | src/link/Wasm.zig | 325 | ||||
| -rw-r--r-- | src/link/Wasm/ZigObject.zig | 14 |
2 files changed, 32 insertions, 307 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 5f4277dfdd..a50c0bedfe 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -177,10 +177,6 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .{}, /// data of a symbol, such as its size, or its offset to perform a relocation. /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{}, -/// Maps a symbol's location to its export name, which may differ from the decl's name -/// which does the exporting. -/// Note: The value represents the offset into the string table, rather than the actual string. -export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, /// List of atom indexes of functions that are generated by the backend, /// rather than by the linker. @@ -1398,7 +1394,6 @@ pub fn deinit(wasm: *Wasm) void { wasm.undefs.deinit(gpa); wasm.discarded.deinit(gpa); wasm.symbol_atom.deinit(gpa); - wasm.export_names.deinit(gpa); wasm.atoms.deinit(gpa); wasm.managed_atoms.deinit(gpa); wasm.segments.deinit(gpa); @@ -2133,10 +2128,10 @@ fn setupExports(wasm: *Wasm) !void { if (!symbol.isExported(comp.config.rdynamic)) continue; const sym_name = sym_loc.getName(wasm); - const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { - if (sym_loc.file == .null) break :blk symbol.name; - break :blk try wasm.string_table.put(gpa, sym_name); - }; + const export_name = if (sym_loc.file == .null) + symbol.name + else + try wasm.string_table.put(gpa, sym_name); const exp: types.Export = if (symbol.tag == .data) exp: { const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); try wasm.wasm_globals.append(gpa, .{ @@ -2437,168 +2432,45 @@ fn appendDummySegment(wasm: *Wasm) !void { }); } -fn resetState(wasm: *Wasm) void { - const gpa = wasm.base.comp.gpa; - - for (wasm.segment_info.values()) |segment_info| { - gpa.free(segment_info.name); - } - - // TODO: Revisit - // var atom_it = wasm.decls.valueIterator(); - // while (atom_it.next()) |atom_index| { - // const atom = wasm.getAtomPtr(atom_index.*); - // atom.next = null; - // atom.prev = null; - - // for (atom.locals.items) |local_atom_index| { - // const local_atom = wasm.getAtomPtr(local_atom_index); - // local_atom.next = null; - // local_atom.prev = null; - // } - // } - - wasm.functions.clearRetainingCapacity(); - wasm.exports.clearRetainingCapacity(); - wasm.segments.clearRetainingCapacity(); - wasm.segment_info.clearRetainingCapacity(); - wasm.data_segments.clearRetainingCapacity(); - wasm.atoms.clearRetainingCapacity(); - wasm.symbol_atom.clearRetainingCapacity(); - wasm.code_section_index = null; - wasm.debug_info_index = null; - wasm.debug_line_index = null; - wasm.debug_loc_index = null; - wasm.debug_str_index = null; - wasm.debug_ranges_index = null; - wasm.debug_abbrev_index = null; - wasm.debug_pubnames_index = null; - wasm.debug_pubtypes_index = null; -} - pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { const comp = wasm.base.comp; const use_lld = build_options.have_llvm and comp.config.use_lld; - const use_llvm = comp.config.use_llvm; if (use_lld) { return wasm.linkWithLLD(arena, prog_node); - } else if (use_llvm) { - return wasm.linkWithZld(arena, prog_node); - } else { - return wasm.flushModule(arena, prog_node); } + return wasm.flushModule(arena, prog_node); } /// Uses the in-house linker to link one or multiple object -and archive files into a WebAssembly binary. -fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { +pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { const tracy = trace(@src()); defer tracy.end(); const comp = wasm.base.comp; - const shared_memory = comp.config.shared_memory; - const import_memory = comp.config.import_memory; + if (wasm.llvm_object) |llvm_object| { + try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); + const use_lld = build_options.have_llvm and comp.config.use_lld; + if (use_lld) return; + } + + var sub_prog_node = prog_node.start("Wasm Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path}); - const opt_zcu = comp.module; - const use_llvm = comp.config.use_llvm; - - // If there is no Zig code to compile, then we should skip flushing the output file because it - // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { - assert(use_llvm); // `linkWithZld` should never be called when the Wasm backend is used - try wasm.flushModule(arena, prog_node); - + const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: { if (fs.path.dirname(full_out_path)) |dirname| { - break :blk try fs.path.join(arena, &.{ dirname, wasm.base.zcu_object_sub_path.? }); + break :blk try fs.path.join(arena, &.{ dirname, path }); } else { - break :blk wasm.base.zcu_object_sub_path.?; + break :blk path; } } else null; - var sub_prog_node = prog_node.start("Wasm Flush", 0); - sub_prog_node.activate(); - defer sub_prog_node.end(); - - const compiler_rt_path: ?[]const u8 = blk: { - if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path; - if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path; - break :blk null; - }; - - const id_symlink_basename = "zld.id"; - - var man: Cache.Manifest = undefined; - defer if (!wasm.base.disable_lld_caching) man.deinit(); - var digest: [Cache.hex_digest_len]u8 = undefined; - - const objects = comp.objects; - - // NOTE: The following section must be maintained to be equal - // as the section defined in `linkWithLLD` - if (!wasm.base.disable_lld_caching) { - man = comp.cache_parent.obtain(); - - // We are about to obtain this lock, so here we give other processes a chance first. - wasm.base.releaseLock(); - - comptime assert(Compilation.link_hash_implementation_version == 12); - - for (objects) |obj| { - _ = try man.addFile(obj.path, null); - man.hash.add(obj.must_link); - } - for (comp.c_object_table.keys()) |key| { - _ = try man.addFile(key.status.success.object_path, null); - } - try man.addOptionalFile(module_obj_path); - try man.addOptionalFile(compiler_rt_path); - man.hash.addOptionalBytes(wasm.entry_name); - man.hash.add(wasm.base.stack_size); - man.hash.add(wasm.base.build_id); - man.hash.add(import_memory); - man.hash.add(shared_memory); - man.hash.add(wasm.import_table); - man.hash.add(wasm.export_table); - man.hash.addOptional(wasm.initial_memory); - man.hash.addOptional(wasm.max_memory); - man.hash.addOptional(wasm.global_base); - man.hash.addListOfBytes(wasm.export_symbol_names); - // strip does not need to go into the linker hash because it is part of the hash namespace - - // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. - _ = try man.hit(); - digest = man.final(); - - var prev_digest_buf: [digest.len]u8 = undefined; - const prev_digest: []u8 = Cache.readSmallFile( - directory.handle, - id_symlink_basename, - &prev_digest_buf, - ) catch |err| blk: { - log.debug("WASM LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); - // Handle this as a cache miss. - break :blk prev_digest_buf[0..0]; - }; - if (mem.eql(u8, prev_digest, &digest)) { - log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); - // Hot diggity dog! The output binary is already there. - wasm.base.lock = man.toOwnedLock(); - return; - } - log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); - - // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { - error.FileNotFound => {}, - else => |e| return e, - }; - } - // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList([]const u8).init(arena); - try positionals.ensureUnusedCapacity(objects.len); + try positionals.ensureUnusedCapacity(comp.objects.len); const target = comp.root_mod.resolved_target.result; const output_mode = comp.config.output_mode; @@ -2607,6 +2479,10 @@ fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) lin const link_libcpp = comp.config.link_libcpp; const wasi_exec_model = comp.config.wasi_exec_model; + if (wasm.zigObjectPtr()) |zig_object| { + try zig_object.flushModule(wasm); + } + // When the target os is WASI, we allow linking with WASI-LIBC if (target.os.tag == .wasi) { const is_exe_or_dyn_lib = output_mode == .Exe or @@ -2638,7 +2514,7 @@ fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) lin try positionals.append(path); } - for (objects) |object| { + for (comp.objects) |object| { try positionals.append(object.path); } @@ -2651,93 +2527,6 @@ fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) lin try wasm.parseInputFiles(positionals.items); - for (wasm.objects.items) |object_index| { - try wasm.resolveSymbolsInObject(object_index); - } - - var emit_features_count: u32 = 0; - var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; - try wasm.validateFeatures(&enabled_features, &emit_features_count); - try wasm.resolveSymbolsInArchives(); - try wasm.resolveLazySymbols(); - try wasm.checkUndefinedSymbols(); - - try wasm.setupInitFunctions(); - try wasm.setupStart(); - - try wasm.markReferences(); - try wasm.setupImports(); - try wasm.mergeSections(); - try wasm.mergeTypes(); - try wasm.allocateAtoms(); - try wasm.setupMemory(); - wasm.allocateVirtualAddresses(); - wasm.mapFunctionTable(); - try wasm.initializeCallCtorsFunction(); - try wasm.setupInitMemoryFunction(); - try wasm.setupTLSRelocationsFunction(); - try wasm.initializeTLSFunction(); - try wasm.setupStartSection(); - try wasm.setupExports(); - try wasm.writeToFile(enabled_features, emit_features_count, arena); - - if (!wasm.base.disable_lld_caching) { - // Update the file with the digest. If it fails we can continue; it only - // means that the next invocation will have an unnecessary cache miss. - Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { - log.warn("failed to save linking hash digest symlink: {s}", .{@errorName(err)}); - }; - // Again failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); - }; - // We hang on to this lock so that the output file path can be used without - // other processes clobbering it. - wasm.base.lock = man.toOwnedLock(); - } -} - -pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { - const tracy = trace(@src()); - defer tracy.end(); - - const comp = wasm.base.comp; - - if (wasm.llvm_object) |llvm_object| { - try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); - return; - } - - var sub_prog_node = prog_node.start("Wasm Flush", 0); - sub_prog_node.activate(); - defer sub_prog_node.end(); - - if (wasm.zigObjectPtr()) |zig_object| { - try zig_object.flushModule(wasm); - } - - // ensure the error names table is populated when an error name is referenced - // try wasm.populateErrorNameTable(); - - const objects = comp.objects; - - // Positional arguments to the linker such as object files and static archives. - var positionals = std.ArrayList([]const u8).init(arena); - try positionals.ensureUnusedCapacity(objects.len); - - for (objects) |object| { - positionals.appendAssumeCapacity(object.path); - } - - for (comp.c_object_table.keys()) |c_object| { - try positionals.append(c_object.status.success.object_path); - } - - if (comp.compiler_rt_lib) |lib| try positionals.append(lib.full_object_path); - if (comp.compiler_rt_obj) |obj| try positionals.append(obj.full_object_path); - - try wasm.parseInputFiles(positionals.items); - if (wasm.zig_object_index != .null) { try wasm.resolveSymbolsInObject(wasm.zig_object_index); } @@ -2752,73 +2541,11 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) try wasm.resolveLazySymbols(); try wasm.checkUndefinedSymbols(); - // When we finish/error we reset the state of the linker - // So we can rebuild the binary file on each incremental update - defer wasm.resetState(); try wasm.setupInitFunctions(); try wasm.setupStart(); + try wasm.markReferences(); - // try wasm.setupErrorsLen(); try wasm.setupImports(); - // if (comp.module) |mod| { - // var decl_it = wasm.decls.iterator(); - // while (decl_it.next()) |entry| { - // const decl = mod.declPtr(entry.key_ptr.*); - // if (decl.isExtern(mod)) continue; - // const atom_index = entry.value_ptr.*; - // const atom = wasm.getAtomPtr(atom_index); - // if (decl.ty.zigTypeTag(mod) == .Fn) { - // try wasm.parseAtom(atom_index, .function); - // } else if (decl.getOwnedVariable(mod)) |variable| { - // if (variable.is_const) { - // try wasm.parseAtom(atom_index, .{ .data = .read_only }); - // } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { - // // for safe build modes, we store the atom in the data segment, - // // whereas for unsafe build modes we store it in bss. - // const decl_namespace = mod.namespacePtr(decl.src_namespace); - // const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; - // const is_initialized = switch (optimize_mode) { - // .Debug, .ReleaseSafe => true, - // .ReleaseFast, .ReleaseSmall => false, - // }; - // try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); - // } else { - // // when the decl is all zeroes, we store the atom in the bss segment, - // // in all other cases it will be in the data segment. - // const is_zeroes = for (atom.code.items) |byte| { - // if (byte != 0) break false; - // } else true; - // try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized }); - // } - // } else { - // try wasm.parseAtom(atom_index, .{ .data = .read_only }); - // } - - // // also parse atoms for a decl's locals - // for (atom.locals.items) |local_atom_index| { - // try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); - // } - // } - // // parse anonymous declarations - // for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { - // const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); - // if (ty.zigTypeTag(mod) == .Fn) { - // try wasm.parseAtom(atom_index, .function); - // } else { - // try wasm.parseAtom(atom_index, .{ .data = .read_only }); - // } - // } - - // // also parse any backend-generated functions - // for (wasm.synthetic_functions.items) |atom_index| { - // try wasm.parseAtom(atom_index, .function); - // } - - // if (wasm.dwarf) |*dwarf| { - // try dwarf.flushModule(comp.module.?); - // } - // } - try wasm.mergeSections(); try wasm.mergeTypes(); try wasm.allocateAtoms(); @@ -4032,7 +3759,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: try leb.writeULEB128(writer, @intFromEnum(symbol.tag)); try leb.writeULEB128(writer, symbol.flags); - const sym_name = if (wasm.export_names.get(sym_loc)) |exp_name| wasm.string_table.get(exp_name) else sym_loc.getName(wasm); + const sym_name = sym_loc.getName(wasm); switch (symbol.tag) { .data => { try leb.writeULEB128(writer, @as(u32, @intCast(sym_name.len))); diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index e73bd466cc..268448e41c 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -670,17 +670,15 @@ pub fn addOrUpdateImport( if (type_index) |ty_index| { const gop = try zig_object.imports.getOrPut(gpa, symbol_index); - const module_name = if (lib_name) |l_name| blk: { - break :blk l_name; - } else wasm_file.host_name; + const module_name = if (lib_name) |l_name| l_name else wasm_file.host_name; if (!gop.found_existing) { - gop.value_ptr.* = .{ - .module_name = try zig_object.string_table.insert(gpa, module_name), - .name = try zig_object.string_table.insert(gpa, name), - .kind = .{ .function = ty_index }, - }; zig_object.imported_functions_count += 1; } + gop.value_ptr.* = .{ + .module_name = try zig_object.string_table.insert(gpa, module_name), + .name = try zig_object.string_table.insert(gpa, name), + .kind = .{ .function = ty_index }, + }; sym.tag = .function; } else { sym.tag = .data; |
