authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-05 13:04:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-05 17:41:14-07:00
loge1811f72eb1bae11934dfd423baa5b26efd99afd
treece10147303417f00af370e9fdbdfd616e98c6f88
parent7b8cede61fc20c137aca4e02425536bfc9a5a400

stage2: link.C: use pwritev


2 files changed, 47 insertions(+), 19 deletions(-)

lib/std/fs/file.zig+8
......@@ -459,6 +459,7 @@ pub const File = struct {
459459 return index;
460460 }
461461
462 /// See https://github.com/ziglang/zig/issues/7699
462463 pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
463464 if (is_windows) {
464465 // TODO improve this to use ReadFileScatter
......@@ -479,6 +480,7 @@ pub const File = struct {
479480 /// is not an error condition.
480481 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
481482 /// order to handle partial reads from the underlying OS layer.
483 /// See https://github.com/ziglang/zig/issues/7699
482484 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
483485 if (iovecs.len == 0) return;
484486
......@@ -500,6 +502,7 @@ pub const File = struct {
500502 }
501503 }
502504
505 /// See https://github.com/ziglang/zig/issues/7699
503506 pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {
504507 if (is_windows) {
505508 // TODO improve this to use ReadFileScatter
......@@ -520,6 +523,7 @@ pub const File = struct {
520523 /// is not an error condition.
521524 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
522525 /// order to handle partial reads from the underlying OS layer.
526 /// See https://github.com/ziglang/zig/issues/7699
523527 pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
524528 if (iovecs.len == 0) return;
525529
......@@ -582,6 +586,7 @@ pub const File = struct {
582586 }
583587 }
584588
589 /// See https://github.com/ziglang/zig/issues/7699
585590 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
586591 if (is_windows) {
587592 // TODO improve this to use WriteFileScatter
......@@ -599,6 +604,7 @@ pub const File = struct {
599604
600605 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
601606 /// order to handle partial writes from the underlying OS layer.
607 /// See https://github.com/ziglang/zig/issues/7699
602608 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
603609 if (iovecs.len == 0) return;
604610
......@@ -615,6 +621,7 @@ pub const File = struct {
615621 }
616622 }
617623
624 /// See https://github.com/ziglang/zig/issues/7699
618625 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!usize {
619626 if (is_windows) {
620627 // TODO improve this to use WriteFileScatter
......@@ -632,6 +639,7 @@ pub const File = struct {
632639
633640 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
634641 /// order to handle partial writes from the underlying OS layer.
642 /// See https://github.com/ziglang/zig/issues/7699
635643 pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!void {
636644 if (iovecs.len == 0) return;
637645
src/link/C.zig+39-19
......@@ -41,13 +41,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
4141 if (options.use_lld) return error.LLDHasNoCBackend;
4242
4343 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
44 .truncate = true,
44 // Truncation is done on `flush`.
45 .truncate = false,
4546 .mode = link.determineMode(options),
4647 });
4748 errdefer file.close();
4849
49 try file.writeAll(zig_h);
50
5150 var c_file = try allocator.create(C);
5251 errdefer allocator.destroy(c_file);
5352
......@@ -133,40 +132,61 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
133132 const tracy = trace(@src());
134133 defer tracy.end();
135134
136 const file = self.base.file.?;
135 const module = self.base.options.module orelse
136 return error.LinkingWithoutZigSourceUnimplemented;
137137
138 // The header is written upon opening; here we truncate and seek to after the header.
139 // TODO: use writev
140 try file.seekTo(zig_h.len);
141 try file.setEndPos(zig_h.len);
138 // We collect a list of buffers to write, and write them all at once with pwritev 😎
139 var all_buffers = std.ArrayList(std.os.iovec_const).init(comp.gpa);
140 defer all_buffers.deinit();
142141
143 var buffered_writer = std.io.bufferedWriter(file.writer());
144 const writer = buffered_writer.writer();
142 // This is at least enough until we get to the function bodies without error handling.
143 try all_buffers.ensureCapacity(module.decl_table.count() + 1);
144
145 var file_size: u64 = zig_h.len;
146 all_buffers.appendAssumeCapacity(.{
147 .iov_base = zig_h,
148 .iov_len = zig_h.len,
149 });
145150
146 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
151 var fn_count: usize = 0;
147152
148153 // Forward decls and non-functions first.
149 // TODO: use writev
150154 for (module.decl_table.items()) |kv| {
151155 const decl = kv.value;
152156 const decl_tv = decl.typed_value.most_recent.typed_value;
153 if (decl_tv.val.castTag(.function)) |_| {
154 try writer.writeAll(decl.fn_link.c.fwd_decl.items);
155 } else {
156 try writer.writeAll(decl.link.c.code.items);
157 }
157 const buf = buf: {
158 if (decl_tv.val.castTag(.function)) |_| {
159 fn_count += 1;
160 break :buf decl.fn_link.c.fwd_decl.items;
161 } else {
162 break :buf decl.link.c.code.items;
163 }
164 };
165 all_buffers.appendAssumeCapacity(.{
166 .iov_base = buf.ptr,
167 .iov_len = buf.len,
168 });
169 file_size += buf.len;
158170 }
159171
160172 // Now the function bodies.
173 try all_buffers.ensureCapacity(all_buffers.items.len + fn_count);
161174 for (module.decl_table.items()) |kv| {
162175 const decl = kv.value;
163176 const decl_tv = decl.typed_value.most_recent.typed_value;
164177 if (decl_tv.val.castTag(.function)) |_| {
165 try writer.writeAll(decl.link.c.code.items);
178 const buf = decl.link.c.code.items;
179 all_buffers.appendAssumeCapacity(.{
180 .iov_base = buf.ptr,
181 .iov_len = buf.len,
182 });
183 file_size += buf.len;
166184 }
167185 }
168186
169 try buffered_writer.flush();
187 const file = self.base.file.?;
188 try file.setEndPos(file_size);
189 try file.pwritevAll(all_buffers.items, 0);
170190}
171191
172192pub fn updateDeclExports(