| author | |
| committer | |
| log | 452ec646f90e43d516768d43cf8581d68a9ba776 |
| tree | a91487513afa81dca000e17e5553ecf324e8eb33 |
| parent | cc5dbff35fc8024cff0a1559de12ffbf7b809107 |
| parent | 30713514345f4416f7e68342be5555734e55410e |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36114
Reviewed-by: mlugg <mlugg@noreply.codeberg.org>3 files changed, 168 insertions(+), 139 deletions(-)
src/link/Coff.zig+2-2| ... | @@ -3602,13 +3602,13 @@ fn objectSectionMapIndex( | ... | @@ -3602,13 +3602,13 @@ fn objectSectionMapIndex( |
| 3602 | const parent_alignment = parent_ni.alignment(&coff.mf); | 3602 | const parent_alignment = parent_ni.alignment(&coff.mf); |
| 3603 | if (alignment.compare(.gt, parent_alignment)) { | 3603 | if (alignment.compare(.gt, parent_alignment)) { |
| 3604 | log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); | 3604 | log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); |
| 3605 | try parent_ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true }); | 3605 | try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true }); |
| 3606 | } | 3606 | } |
| 3607 | 3607 | ||
| 3608 | const old_alignment = sym.ni.alignment(&coff.mf); | 3608 | const old_alignment = sym.ni.alignment(&coff.mf); |
| 3609 | if (alignment.compare(.gt, old_alignment)) { | 3609 | if (alignment.compare(.gt, old_alignment)) { |
| 3610 | log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment }); | 3610 | log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment }); |
| 3611 | try sym.ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true }); | 3611 | try sym.ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true }); |
| 3612 | } | 3612 | } |
| 3613 | 3613 | ||
| 3614 | try coff.verifyParentSectionAttributes( | 3614 | try coff.verifyParentSectionAttributes( |
src/link/Elf2.zig+100-75| ... | @@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 4659 | const new_alignment: std.mem.Alignment = .fromByteUnits( | 4659 | const new_alignment: std.mem.Alignment = .fromByteUnits( |
| 4660 | std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), | 4660 | std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), |
| 4661 | ); | 4661 | ); |
| 4662 | try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{ .set_alignment = true }); | 4662 | try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{}); |
| 4663 | } | 4663 | } |
| 4664 | // ...and update the shdr as needed. | 4664 | // ...and update the shdr as needed. |
| 4665 | switch (elf.shdrPtr(existing_shndx)) { | 4665 | switch (elf.shdrPtr(existing_shndx)) { |
| ... | @@ -4796,7 +4796,7 @@ fn uavMapIndex( | ... | @@ -4796,7 +4796,7 @@ fn uavMapIndex( |
| 4796 | if (!uav_gop.found_existing) { | 4796 | if (!uav_gop.found_existing) { |
| 4797 | const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs | 4797 | const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs |
| 4798 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ | 4798 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| 4799 | .moved = true, // see assert at end of `flushUav` | 4799 | .moved = true, // see assert at end of `genUav` |
| 4800 | .alignment = resolved_align.toStdMem(), | 4800 | .alignment = resolved_align.toStdMem(), |
| 4801 | }); | 4801 | }); |
| 4802 | var name_buf: [32]u8 = undefined; | 4802 | var name_buf: [32]u8 = undefined; |
| ... | @@ -4822,7 +4822,7 @@ fn uavMapIndex( | ... | @@ -4822,7 +4822,7 @@ fn uavMapIndex( |
| 4822 | } else { | 4822 | } else { |
| 4823 | const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; | 4823 | const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; |
| 4824 | if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { | 4824 | if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { |
| 4825 | try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{ .set_alignment = true }); | 4825 | try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{}); |
| 4826 | } | 4826 | } |
| 4827 | } | 4827 | } |
| 4828 | return umi; | 4828 | return umi; |
| ... | @@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars | ... | @@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars |
| 5551 | // We have a copy relocation for this global, but the amount of space we | 5551 | // We have a copy relocation for this global, but the amount of space we |
| 5552 | // reserved for it could be too small or underaligned! | 5552 | // reserved for it could be too small or underaligned! |
| 5553 | try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); | 5553 | try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); |
| 5554 | try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{ .set_alignment = true }); | 5554 | try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{}); |
| 5555 | const global_ptr = elf.globalByName(name).?; | 5555 | const global_ptr = elf.globalByName(name).?; |
| 5556 | switch (elf.symPtr(global_ptr.symtab_index)) { | 5556 | switch (elf.symPtr(global_ptr.symtab_index)) { |
| 5557 | inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), | 5557 | inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), |
| ... | @@ -7005,22 +7005,27 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -7005,22 +7005,27 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 7005 | // called to apply the NAV's new relocations. | 7005 | // called to apply the NAV's new relocations. |
| 7006 | try ni.moved(gpa, &elf.mf); | 7006 | try ni.moved(gpa, &elf.mf); |
| 7007 | 7007 | ||
| 7008 | var nw: MappedFile.Node.Writer = undefined; | 7008 | { |
| 7009 | ni.writer(&elf.mf, gpa, &nw); | 7009 | var nw: MappedFile.Node.Writer = undefined; |
| 7010 | defer nw.deinit(); | 7010 | ni.writer(&elf.mf, gpa, &nw); |
| 7011 | codegen.generateSymbol( | 7011 | defer nw.deinit(); |
| 7012 | &elf.base, | 7012 | codegen.generateSymbol( |
| 7013 | pt, | 7013 | &elf.base, |
| 7014 | .fromInterned(nav.resolved.?.value), | 7014 | pt, |
| 7015 | &nw.interface, | 7015 | .fromInterned(nav.resolved.?.value), |
| 7016 | .{ .atom_index = Node.toAtom(ni) }, | 7016 | &nw.interface, |
| 7017 | ) catch |err| switch (err) { | 7017 | .{ .atom_index = Node.toAtom(ni) }, |
| 7018 | error.WriteFailed => return nw.err.?, | 7018 | ) catch |err| switch (err) { |
| 7019 | else => |e| return e, | 7019 | error.WriteFailed => return nw.err.?, |
| 7020 | }; | 7020 | else => |e| return e, |
| 7021 | switch (elf.symPtr(nmi.symbol(elf).index())) { | 7021 | }; |
| 7022 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 7022 | switch (elf.symPtr(nmi.symbol(elf).index())) { |
| 7023 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | ||
| 7024 | } | ||
| 7023 | } | 7025 | } |
| 7026 | |||
| 7027 | // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. | ||
| 7028 | try elf.genPending(pt); | ||
| 7024 | } | 7029 | } |
| 7025 | 7030 | ||
| 7026 | pub fn updateFunc( | 7031 | pub fn updateFunc( |
| ... | @@ -7056,29 +7061,34 @@ fn updateFuncInner( | ... | @@ -7056,29 +7061,34 @@ fn updateFuncInner( |
| 7056 | // called to apply the NAV's new relocations. | 7061 | // called to apply the NAV's new relocations. |
| 7057 | try ni.moved(gpa, &elf.mf); | 7062 | try ni.moved(gpa, &elf.mf); |
| 7058 | 7063 | ||
| 7059 | var nw: MappedFile.Node.Writer = undefined; | 7064 | { |
| 7060 | ni.writer(&elf.mf, gpa, &nw); | 7065 | var nw: MappedFile.Node.Writer = undefined; |
| 7061 | defer nw.deinit(); | 7066 | ni.writer(&elf.mf, gpa, &nw); |
| 7062 | codegen.emitFunction( | 7067 | defer nw.deinit(); |
| 7063 | &elf.base, | 7068 | codegen.emitFunction( |
| 7064 | pt, | 7069 | &elf.base, |
| 7065 | func_index, | 7070 | pt, |
| 7066 | Node.toAtom(ni), | 7071 | func_index, |
| 7067 | mir, | 7072 | Node.toAtom(ni), |
| 7068 | &nw.interface, | 7073 | mir, |
| 7069 | .none, | 7074 | &nw.interface, |
| 7070 | ) catch |err| switch (err) { | 7075 | .none, |
| 7071 | error.WriteFailed => return nw.err.?, | 7076 | ) catch |err| switch (err) { |
| 7072 | else => |e| return e, | 7077 | error.WriteFailed => return nw.err.?, |
| 7073 | }; | 7078 | else => |e| return e, |
| 7074 | switch (elf.symPtr(nmi.symbol(elf).index())) { | 7079 | }; |
| 7075 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 7080 | switch (elf.symPtr(nmi.symbol(elf).index())) { |
| 7081 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | ||
| 7082 | } | ||
| 7076 | } | 7083 | } |
| 7084 | |||
| 7085 | // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. | ||
| 7086 | try elf.genPending(pt); | ||
| 7077 | } | 7087 | } |
| 7078 | 7088 | ||
| 7079 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void { | 7089 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void { |
| 7080 | const diags = &elf.base.comp.link_diags; | 7090 | const diags = &elf.base.comp.link_diags; |
| 7081 | elf.flushLazy(pt, .{ | 7091 | elf.genLazy(pt, .{ |
| 7082 | .kind = .const_data, | 7092 | .kind = .const_data, |
| 7083 | .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), | 7093 | .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), |
| 7084 | }) catch |err| switch (err) { | 7094 | }) catch |err| switch (err) { |
| ... | @@ -7183,40 +7193,13 @@ fn updateDynamicTextrel(elf: *Elf) Error!void { | ... | @@ -7183,40 +7193,13 @@ fn updateDynamicTextrel(elf: *Elf) Error!void { |
| 7183 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { | 7193 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7184 | const comp = elf.base.comp; | 7194 | const comp = elf.base.comp; |
| 7185 | const diags = &comp.link_diags; | 7195 | const diags = &comp.link_diags; |
| 7196 | |||
| 7197 | assert(elf.pending_uavs.items.len == 0); | ||
| 7198 | for (&elf.lazy.values) |*lazy| { | ||
| 7199 | assert(lazy.pending_index == lazy.map.count()); | ||
| 7200 | } | ||
| 7201 | |||
| 7186 | task: { | 7202 | task: { |
| 7187 | while (elf.pending_uavs.pop()) |umi| { | ||
| 7188 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = umi }); | ||
| 7189 | defer sub_prog_node.end(); | ||
| 7190 | elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) { | ||
| 7191 | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), | ||
| 7192 | else => |e| return e, | ||
| 7193 | }; | ||
| 7194 | break :task; | ||
| 7195 | } | ||
| 7196 | var lazy_it = elf.lazy.iterator(); | ||
| 7197 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | ||
| 7198 | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; | ||
| 7199 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | ||
| 7200 | lazy.value.pending_index += 1; | ||
| 7201 | const kind = switch (lmr.kind) { | ||
| 7202 | .code => "code", | ||
| 7203 | .const_data => "data", | ||
| 7204 | }; | ||
| 7205 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 7206 | const sub_prog_node = elf.synth_prog_node.start( | ||
| 7207 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | ||
| 7208 | kind, | ||
| 7209 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), | ||
| 7210 | }) catch &name, | ||
| 7211 | 0, | ||
| 7212 | ); | ||
| 7213 | defer sub_prog_node.end(); | ||
| 7214 | elf.flushLazy(pt, lmr) catch |err| switch (err) { | ||
| 7215 | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), | ||
| 7216 | else => |e| return e, | ||
| 7217 | }; | ||
| 7218 | break :task; | ||
| 7219 | }; | ||
| 7220 | if (elf.input_section_pending_index < elf.input_sections.items.len) { | 7203 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 7221 | const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index); | 7204 | const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index); |
| 7222 | elf.input_section_pending_index += 1; | 7205 | elf.input_section_pending_index += 1; |
| ... | @@ -7315,8 +7298,6 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { | ... | @@ -7315,8 +7298,6 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7315 | } else elf.mf.update_prog_node.completeOne(); | 7298 | } else elf.mf.update_prog_node.completeOne(); |
| 7316 | } | 7299 | } |
| 7317 | } | 7300 | } |
| 7318 | if (elf.pending_uavs.items.len > 0) return true; | ||
| 7319 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | ||
| 7320 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; | 7301 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| 7321 | if (elf.changed_symtab_index.count() > 0) return true; | 7302 | if (elf.changed_symtab_index.count() > 0) return true; |
| 7322 | if (elf.mf.updates.items.len > 0) return true; | 7303 | if (elf.mf.updates.items.len > 0) return true; |
| ... | @@ -7351,7 +7332,43 @@ fn idleProgNode( | ... | @@ -7351,7 +7332,43 @@ fn idleProgNode( |
| 7351 | }, 0); | 7332 | }, 0); |
| 7352 | } | 7333 | } |
| 7353 | 7334 | ||
| 7354 | fn flushUav( | 7335 | fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { |
| 7336 | const zcu = elf.base.comp.zcu.?; | ||
| 7337 | pending: while (true) { | ||
| 7338 | if (elf.pending_uavs.pop()) |umi| { | ||
| 7339 | var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 7340 | const prog_name = std.mem.print(&prog_name_buf, "{f}", .{ | ||
| 7341 | Value.fromInterned(umi.uavValue(elf)).fmtValue(pt), | ||
| 7342 | }) catch &prog_name_buf; | ||
| 7343 | const prog_node = elf.const_prog_node.start(prog_name, 0); | ||
| 7344 | defer prog_node.end(); | ||
| 7345 | try elf.genUav(pt, umi); | ||
| 7346 | continue :pending; | ||
| 7347 | } | ||
| 7348 | var lazy_it = elf.lazy.iterator(); | ||
| 7349 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | ||
| 7350 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | ||
| 7351 | lazy.value.pending_index += 1; | ||
| 7352 | const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty); | ||
| 7353 | var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 7354 | const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) { | ||
| 7355 | .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, | ||
| 7356 | .error_set => switch (lmr.kind) { | ||
| 7357 | .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, | ||
| 7358 | .const_data => "@errorName", | ||
| 7359 | }, | ||
| 7360 | else => unreachable, | ||
| 7361 | }; | ||
| 7362 | const prog_node = elf.synth_prog_node.start(prog_name, 0); | ||
| 7363 | defer prog_node.end(); | ||
| 7364 | try elf.genLazy(pt, lmr); | ||
| 7365 | continue :pending; | ||
| 7366 | }; | ||
| 7367 | break; | ||
| 7368 | } | ||
| 7369 | } | ||
| 7370 | |||
| 7371 | fn genUav( | ||
| 7355 | elf: *Elf, | 7372 | elf: *Elf, |
| 7356 | pt: Zcu.PerThread, | 7373 | pt: Zcu.PerThread, |
| 7357 | umi: Node.UavMapIndex, | 7374 | umi: Node.UavMapIndex, |
| ... | @@ -7380,11 +7397,11 @@ fn flushUav( | ... | @@ -7380,11 +7397,11 @@ fn flushUav( |
| 7380 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 7397 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 7381 | } | 7398 | } |
| 7382 | // The UAV should already be considered to have moved, because it is created as moved and | 7399 | // The UAV should already be considered to have moved, because it is created as moved and |
| 7383 | // pending calls to `flushUav` always happen before pending calls to `flushMoved`. | 7400 | // pending calls to `genUav` always happen before pending calls to `flushMoved`. |
| 7384 | assert(ni.hasMoved(&elf.mf)); | 7401 | assert(ni.hasMoved(&elf.mf)); |
| 7385 | } | 7402 | } |
| 7386 | 7403 | ||
| 7387 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { | 7404 | fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { |
| 7388 | const zcu = pt.zcu; | 7405 | const zcu = pt.zcu; |
| 7389 | const gpa = zcu.gpa; | 7406 | const gpa = zcu.gpa; |
| 7390 | 7407 | ||
| ... | @@ -7497,6 +7514,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void { | ... | @@ -7497,6 +7514,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 7497 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { | 7514 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { |
| 7498 | const trace = tracy.trace(@src()); | 7515 | const trace = tracy.trace(@src()); |
| 7499 | defer trace.end(); | 7516 | defer trace.end(); |
| 7517 | |||
| 7518 | elf.mf.nodes_lock.lock(); | ||
| 7519 | defer elf.mf.nodes_lock.unlock(); | ||
| 7520 | |||
| 7500 | switch (elf.getNode(ni)) { | 7521 | switch (elf.getNode(ni)) { |
| 7501 | .file => unreachable, | 7522 | .file => unreachable, |
| 7502 | .ehdr, .shdr => elf.flushFileOffset(ni), | 7523 | .ehdr, .shdr => elf.flushFileOffset(ni), |
| ... | @@ -7662,6 +7683,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -7662,6 +7683,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7662 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { | 7683 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { |
| 7663 | const trace = tracy.trace(@src()); | 7684 | const trace = tracy.trace(@src()); |
| 7664 | defer trace.end(); | 7685 | defer trace.end(); |
| 7686 | |||
| 7687 | elf.mf.nodes_lock.lock(); | ||
| 7688 | defer elf.mf.nodes_lock.unlock(); | ||
| 7689 | |||
| 7665 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); | 7690 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 7666 | switch (elf.getNode(ni)) { | 7691 | switch (elf.getNode(ni)) { |
| 7667 | .file => {}, | 7692 | .file => {}, |
src/link/MappedFile.zig+66-62| ... | @@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I | ... | @@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I |
| 95 | .fallocate_punch_hole_unsupported = false, | 95 | .fallocate_punch_hole_unsupported = false, |
| 96 | }; | 96 | }; |
| 97 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | 97 | try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 98 | const root_ni = mf.addNode(gpa, .{ .add_node = .{ | 98 | const root_ni = try mf.addNode(gpa, .{ .add_node = .{ |
| 99 | .size = size, | 99 | .size = size, |
| 100 | .alignment = mf.flags.block_size, | 100 | .alignment = mf.flags.block_size, |
| 101 | .fixed = true, | 101 | .fixed = true, |
| 102 | } }) catch |err| switch (err) { | 102 | } }); |
| 103 | error.MappedFileIo => return mf.io_err.?, | ||
| 104 | else => |e| return e, | ||
| 105 | }; | ||
| 106 | assert(root_ni == Node.Index.root); | 103 | assert(root_ni == Node.Index.root); |
| 107 | try mf.ensureTotalCapacityInner(@intCast(size)); | 104 | try mf.ensureTotalCapacityInner(@intCast(size)); |
| 108 | return mf; | 105 | return mf; |
| ... | @@ -355,9 +352,7 @@ pub const Node = extern struct { | ... | @@ -355,9 +352,7 @@ pub const Node = extern struct { |
| 355 | 352 | ||
| 356 | pub const RealignNodeOptions = struct { | 353 | pub const RealignNodeOptions = struct { |
| 357 | /// Shift the node backwards if possible | 354 | /// Shift the node backwards if possible |
| 358 | try_backwards: bool = true, | 355 | try_backwards: bool = false, |
| 359 | /// If `set, persists `new_alignment` as the node's alignment for future operations. | ||
| 360 | set_alignment: bool = true, | ||
| 361 | }; | 356 | }; |
| 362 | 357 | ||
| 363 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. | 358 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. |
| ... | @@ -378,11 +373,7 @@ pub const Node = extern struct { | ... | @@ -378,11 +373,7 @@ pub const Node = extern struct { |
| 378 | return error.MappedFileIo; | 373 | return error.MappedFileIo; |
| 379 | }, | 374 | }, |
| 380 | }; | 375 | }; |
| 381 | var writers_it = mf.writers.first; | 376 | mf.updateWriters(); |
| 382 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { | ||
| 383 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); | ||
| 384 | w.interface.buffer = w.ni.slice(mf); | ||
| 385 | } | ||
| 386 | } | 377 | } |
| 387 | 378 | ||
| 388 | /// Shrink a node to `size`, exactly. | 379 | /// Shrink a node to `size`, exactly. |
| ... | @@ -398,11 +389,7 @@ pub const Node = extern struct { | ... | @@ -398,11 +389,7 @@ pub const Node = extern struct { |
| 398 | shift_next: bool, | 389 | shift_next: bool, |
| 399 | ) Error!void { | 390 | ) Error!void { |
| 400 | try mf.shrinkNode(gpa, ni, size, shift_next); | 391 | try mf.shrinkNode(gpa, ni, size, shift_next); |
| 401 | var writers_it = mf.writers.first; | 392 | mf.updateWriters(); |
| 402 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { | ||
| 403 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); | ||
| 404 | w.interface.buffer = w.ni.slice(mf); | ||
| 405 | } | ||
| 406 | } | 393 | } |
| 407 | 394 | ||
| 408 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { | 395 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { |
| ... | @@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 562 | next: Node.Index = .none, | 549 | next: Node.Index = .none, |
| 563 | offset: u64 = 0, | 550 | offset: u64 = 0, |
| 564 | add_node: AddNodeOptions, | 551 | add_node: AddNodeOptions, |
| 565 | }) Error!Node.Index { | 552 | }) (Allocator.Error || Io.Cancelable || IoError)!Node.Index { |
| 566 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | 553 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 567 | mf.nodes_lock.assertUnlocked(); | 554 | mf.nodes_lock.assertUnlocked(); |
| 568 | const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); | ||
| 569 | if (opts.parent != .none) { | ||
| 570 | const new_end = offset + opts.add_node.size; | ||
| 571 | switch (opts.next) { | ||
| 572 | .none => { | ||
| 573 | _, const parent_size = opts.parent.location(mf).resolve(mf); | ||
| 574 | if (new_end > parent_size) | ||
| 575 | try opts.parent.resize(mf, gpa, new_end); | ||
| 576 | }, | ||
| 577 | else => |next_ni| { | ||
| 578 | const next_offset, _ = next_ni.location(mf).resolve(mf); | ||
| 579 | if (new_end > next_offset) | ||
| 580 | try next_ni.realign(mf, gpa, opts.add_node.alignment, .{ | ||
| 581 | .try_backwards = false, | ||
| 582 | .set_alignment = false, | ||
| 583 | }); | ||
| 584 | }, | ||
| 585 | } | ||
| 586 | } | ||
| 587 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { | 555 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { |
| 588 | if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ | 556 | if (std.math.cast(u32, opts.offset)) |small_offset| break :location .{ .small, .{ |
| 589 | .small = .{ .offset = small_offset, .size = 0 }, | 557 | .small = .{ .offset = small_offset, .size = 0 }, |
| 590 | } }; | 558 | } }; |
| 591 | try mf.large.ensureUnusedCapacity(gpa, 2); | 559 | try mf.large.ensureUnusedCapacity(gpa, 2); |
| 592 | defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 }); | 560 | defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 }); |
| 593 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; | 561 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; |
| 594 | }; | 562 | }; |
| 595 | const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { | 563 | const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { |
| ... | @@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 616 | .last = .none, | 584 | .last = .none, |
| 617 | .flags = .{ | 585 | .flags = .{ |
| 618 | .location_tag = location_tag, | 586 | .location_tag = location_tag, |
| 619 | .alignment = opts.add_node.alignment, | 587 | .alignment = .@"1", |
| 620 | .fixed = opts.add_node.fixed, | 588 | .fixed = opts.add_node.fixed, |
| 621 | .moved = true, | 589 | .moved = true, |
| 622 | .resized = true, | 590 | .resized = true, |
| ... | @@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 627 | }; | 595 | }; |
| 628 | 596 | ||
| 629 | { | 597 | { |
| 630 | try free_ni.resize(mf, gpa, opts.add_node.size); | 598 | try mf.realignNode(gpa, free_ni, opts.add_node.alignment, .{}); |
| 599 | try mf.resizeNode(gpa, free_ni, opts.add_node.size); | ||
| 631 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | 600 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 632 | free_node.flags.moved = false; | 601 | free_node.flags.moved = false; |
| 633 | free_node.flags.resized = false; | 602 | free_node.flags.resized = false; |
| 634 | } | 603 | } |
| 635 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); | 604 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| 636 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); | 605 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); |
| 606 | mf.updateWriters(); | ||
| 637 | return free_ni; | 607 | return free_ni; |
| 638 | } | 608 | } |
| 639 | 609 | ||
| ... | @@ -658,7 +628,15 @@ pub fn addOnlyChildNode( | ... | @@ -658,7 +628,15 @@ pub fn addOnlyChildNode( |
| 658 | return mf.addNode(gpa, .{ | 628 | return mf.addNode(gpa, .{ |
| 659 | .parent = parent_ni, | 629 | .parent = parent_ni, |
| 660 | .add_node = opts, | 630 | .add_node = opts, |
| 661 | }); | 631 | }) catch |err| switch (err) { |
| 632 | error.OutOfMemory, | ||
| 633 | error.Canceled, | ||
| 634 | => |e| return e, | ||
| 635 | else => |e| { | ||
| 636 | mf.io_err = e; | ||
| 637 | return error.MappedFileIo; | ||
| 638 | }, | ||
| 639 | }; | ||
| 662 | } | 640 | } |
| 663 | 641 | ||
| 664 | pub fn addFirstChildNode( | 642 | pub fn addFirstChildNode( |
| ... | @@ -673,7 +651,15 @@ pub fn addFirstChildNode( | ... | @@ -673,7 +651,15 @@ pub fn addFirstChildNode( |
| 673 | .parent = parent_ni, | 651 | .parent = parent_ni, |
| 674 | .next = parent.first, | 652 | .next = parent.first, |
| 675 | .add_node = opts, | 653 | .add_node = opts, |
| 676 | }); | 654 | }) catch |err| switch (err) { |
| 655 | error.OutOfMemory, | ||
| 656 | error.Canceled, | ||
| 657 | => |e| return e, | ||
| 658 | else => |e| { | ||
| 659 | mf.io_err = e; | ||
| 660 | return error.MappedFileIo; | ||
| 661 | }, | ||
| 662 | }; | ||
| 677 | } | 663 | } |
| 678 | 664 | ||
| 679 | pub fn addLastChildNode( | 665 | pub fn addLastChildNode( |
| ... | @@ -695,7 +681,15 @@ pub fn addLastChildNode( | ... | @@ -695,7 +681,15 @@ pub fn addLastChildNode( |
| 695 | }, | 681 | }, |
| 696 | }, | 682 | }, |
| 697 | .add_node = opts, | 683 | .add_node = opts, |
| 698 | }); | 684 | }) catch |err| switch (err) { |
| 685 | error.OutOfMemory, | ||
| 686 | error.Canceled, | ||
| 687 | => |e| return e, | ||
| 688 | else => |e| { | ||
| 689 | mf.io_err = e; | ||
| 690 | return error.MappedFileIo; | ||
| 691 | }, | ||
| 692 | }; | ||
| 699 | } | 693 | } |
| 700 | 694 | ||
| 701 | pub fn addNodeAfter( | 695 | pub fn addNodeAfter( |
| ... | @@ -714,7 +708,15 @@ pub fn addNodeAfter( | ... | @@ -714,7 +708,15 @@ pub fn addNodeAfter( |
| 714 | .next = prev.next, | 708 | .next = prev.next, |
| 715 | .offset = prev_offset + prev_size, | 709 | .offset = prev_offset + prev_size, |
| 716 | .add_node = opts, | 710 | .add_node = opts, |
| 717 | }); | 711 | }) catch |err| switch (err) { |
| 712 | error.OutOfMemory, | ||
| 713 | error.Canceled, | ||
| 714 | => |e| return e, | ||
| 715 | else => |e| { | ||
| 716 | mf.io_err = e; | ||
| 717 | return error.MappedFileIo; | ||
| 718 | }, | ||
| 719 | }; | ||
| 718 | } | 720 | } |
| 719 | 721 | ||
| 720 | fn shrinkNode( | 722 | fn shrinkNode( |
| ... | @@ -1043,26 +1045,20 @@ fn realignNode( | ... | @@ -1043,26 +1045,20 @@ fn realignNode( |
| 1043 | new_alignment: std.mem.Alignment, | 1045 | new_alignment: std.mem.Alignment, |
| 1044 | opts: Node.Index.RealignNodeOptions, | 1046 | opts: Node.Index.RealignNodeOptions, |
| 1045 | ) (Allocator.Error || Io.Cancelable || IoError)!void { | 1047 | ) (Allocator.Error || Io.Cancelable || IoError)!void { |
| 1046 | assert(ni != Node.Index.root); // currently unsupported | ||
| 1047 | mf.nodes_lock.assertUnlocked(); | 1048 | mf.nodes_lock.assertUnlocked(); |
| 1048 | 1049 | ||
| 1049 | const node = ni.get(mf); | 1050 | const node = ni.get(mf); |
| 1050 | const old_offset, const size = node.location().resolve(mf); | 1051 | { |
| 1051 | 1052 | const prev_alignment = node.flags.alignment; | |
| 1052 | assert(new_alignment.compare(.gt, node.flags.alignment)); | 1053 | node.flags.alignment = new_alignment; |
| 1053 | 1054 | if (new_alignment.compare(.lte, prev_alignment)) return; | |
| 1054 | const prev_alignment = node.flags.alignment; | ||
| 1055 | node.flags.alignment = new_alignment; | ||
| 1056 | defer { | ||
| 1057 | // alignment needs to be temporarily set for the resizes below | ||
| 1058 | if (!opts.set_alignment) node.flags.alignment = prev_alignment; | ||
| 1059 | } | 1055 | } |
| 1060 | 1056 | ||
| 1061 | const new_size = node.flags.alignment.forward(@intCast(size)); | 1057 | const old_offset, const size = node.location().resolve(mf); |
| 1062 | if (new_alignment.check(@intCast(old_offset))) { | 1058 | if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size); |
| 1063 | if (new_size > size) try mf.resizeNode(gpa, ni, new_size); | 1059 | |
| 1064 | return; | 1060 | const new_size = new_alignment.forward(@intCast(size)); |
| 1065 | } | 1061 | if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size); |
| 1066 | 1062 | ||
| 1067 | _, const parent_size = node.parent.location(mf).resolve(mf); | 1063 | _, const parent_size = node.parent.location(mf).resolve(mf); |
| 1068 | const trailing_end = trailing_end: switch (node.next) { | 1064 | const trailing_end = trailing_end: switch (node.next) { |
| ... | @@ -1122,7 +1118,7 @@ fn realignNode( | ... | @@ -1122,7 +1118,7 @@ fn realignNode( |
| 1122 | 1118 | ||
| 1123 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); | 1119 | ni.setLocationAssumeCapacity(mf, forward_offset, new_size); |
| 1124 | } else { | 1120 | } else { |
| 1125 | const temp_size = node.flags.alignment.forward(@intCast(new_size + 1)); | 1121 | const temp_size = new_alignment.forward(@intCast(new_size + 1)); |
| 1126 | try mf.resizeNode(gpa, ni, temp_size); | 1122 | try mf.resizeNode(gpa, ni, temp_size); |
| 1127 | const new_offset, _ = ni.location(mf).resolve(mf); | 1123 | const new_offset, _ = ni.location(mf).resolve(mf); |
| 1128 | 1124 | ||
| ... | @@ -1148,6 +1144,14 @@ fn realignNode( | ... | @@ -1148,6 +1144,14 @@ fn realignNode( |
| 1148 | } | 1144 | } |
| 1149 | } | 1145 | } |
| 1150 | 1146 | ||
| 1147 | fn updateWriters(mf: *MappedFile) void { | ||
| 1148 | var writers_it = mf.writers.first; | ||
| 1149 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { | ||
| 1150 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); | ||
| 1151 | w.interface.buffer = w.ni.slice(mf); | ||
| 1152 | } | ||
| 1153 | } | ||
| 1154 | |||
| 1151 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void { | 1155 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void { |
| 1152 | // make a copy of this node at the new location | 1156 | // make a copy of this node at the new location |
| 1153 | try mf.copyRange(old_file_offset, new_file_offset, size); | 1157 | try mf.copyRange(old_file_offset, new_file_offset, size); |