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 {...@@ -459,6 +459,7 @@ pub const File = struct {
459 return index;459 return index;
460 }460 }
461461
462 /// See https://github.com/ziglang/zig/issues/7699
462 pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {463 pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
463 if (is_windows) {464 if (is_windows) {
464 // TODO improve this to use ReadFileScatter465 // TODO improve this to use ReadFileScatter
...@@ -479,6 +480,7 @@ pub const File = struct {...@@ -479,6 +480,7 @@ pub const File = struct {
479 /// is not an error condition.480 /// is not an error condition.
480 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in481 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
481 /// order to handle partial reads from the underlying OS layer.482 /// order to handle partial reads from the underlying OS layer.
483 /// See https://github.com/ziglang/zig/issues/7699
482 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {484 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
483 if (iovecs.len == 0) return;485 if (iovecs.len == 0) return;
484486
...@@ -500,6 +502,7 @@ pub const File = struct {...@@ -500,6 +502,7 @@ pub const File = struct {
500 }502 }
501 }503 }
502504
505 /// See https://github.com/ziglang/zig/issues/7699
503 pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {506 pub fn preadv(self: File, iovecs: []const os.iovec, offset: u64) PReadError!usize {
504 if (is_windows) {507 if (is_windows) {
505 // TODO improve this to use ReadFileScatter508 // TODO improve this to use ReadFileScatter
...@@ -520,6 +523,7 @@ pub const File = struct {...@@ -520,6 +523,7 @@ pub const File = struct {
520 /// is not an error condition.523 /// is not an error condition.
521 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in524 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
522 /// order to handle partial reads from the underlying OS layer.525 /// order to handle partial reads from the underlying OS layer.
526 /// See https://github.com/ziglang/zig/issues/7699
523 pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {527 pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
524 if (iovecs.len == 0) return;528 if (iovecs.len == 0) return;
525529
...@@ -582,6 +586,7 @@ pub const File = struct {...@@ -582,6 +586,7 @@ pub const File = struct {
582 }586 }
583 }587 }
584588
589 /// See https://github.com/ziglang/zig/issues/7699
585 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {590 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
586 if (is_windows) {591 if (is_windows) {
587 // TODO improve this to use WriteFileScatter592 // TODO improve this to use WriteFileScatter
...@@ -599,6 +604,7 @@ pub const File = struct {...@@ -599,6 +604,7 @@ pub const File = struct {
599604
600 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in605 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
601 /// order to handle partial writes from the underlying OS layer.606 /// order to handle partial writes from the underlying OS layer.
607 /// See https://github.com/ziglang/zig/issues/7699
602 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {608 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
603 if (iovecs.len == 0) return;609 if (iovecs.len == 0) return;
604610
...@@ -615,6 +621,7 @@ pub const File = struct {...@@ -615,6 +621,7 @@ pub const File = struct {
615 }621 }
616 }622 }
617623
624 /// See https://github.com/ziglang/zig/issues/7699
618 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!usize {625 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!usize {
619 if (is_windows) {626 if (is_windows) {
620 // TODO improve this to use WriteFileScatter627 // TODO improve this to use WriteFileScatter
...@@ -632,6 +639,7 @@ pub const File = struct {...@@ -632,6 +639,7 @@ pub const File = struct {
632639
633 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in640 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
634 /// order to handle partial writes from the underlying OS layer.641 /// order to handle partial writes from the underlying OS layer.
642 /// See https://github.com/ziglang/zig/issues/7699
635 pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!void {643 pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!void {
636 if (iovecs.len == 0) return;644 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...@@ -41,13 +41,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
41 if (options.use_lld) return error.LLDHasNoCBackend;41 if (options.use_lld) return error.LLDHasNoCBackend;
4242
43 const file = try options.emit.?.directory.handle.createFile(sub_path, .{43 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
44 .truncate = true,44 // Truncation is done on `flush`.
45 .truncate = false,
45 .mode = link.determineMode(options),46 .mode = link.determineMode(options),
46 });47 });
47 errdefer file.close();48 errdefer file.close();
4849
49 try file.writeAll(zig_h);
50
51 var c_file = try allocator.create(C);50 var c_file = try allocator.create(C);
52 errdefer allocator.destroy(c_file);51 errdefer allocator.destroy(c_file);
5352
...@@ -133,40 +132,61 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -133,40 +132,61 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
133 const tracy = trace(@src());132 const tracy = trace(@src());
134 defer tracy.end();133 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.138 // We collect a list of buffers to write, and write them all at once with pwritev 😎
139 // TODO: use writev139 var all_buffers = std.ArrayList(std.os.iovec_const).init(comp.gpa);
140 try file.seekTo(zig_h.len);140 defer all_buffers.deinit();
141 try file.setEndPos(zig_h.len);
142141
143 var buffered_writer = std.io.bufferedWriter(file.writer());142 // This is at least enough until we get to the function bodies without error handling.
144 const writer = buffered_writer.writer();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
148 // Forward decls and non-functions first.153 // Forward decls and non-functions first.
149 // TODO: use writev
150 for (module.decl_table.items()) |kv| {154 for (module.decl_table.items()) |kv| {
151 const decl = kv.value;155 const decl = kv.value;
152 const decl_tv = decl.typed_value.most_recent.typed_value;156 const decl_tv = decl.typed_value.most_recent.typed_value;
153 if (decl_tv.val.castTag(.function)) |_| {157 const buf = buf: {
154 try writer.writeAll(decl.fn_link.c.fwd_decl.items);158 if (decl_tv.val.castTag(.function)) |_| {
155 } else {159 fn_count += 1;
156 try writer.writeAll(decl.link.c.code.items);160 break :buf decl.fn_link.c.fwd_decl.items;
157 }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;
158 }170 }
159171
160 // Now the function bodies.172 // Now the function bodies.
173 try all_buffers.ensureCapacity(all_buffers.items.len + fn_count);
161 for (module.decl_table.items()) |kv| {174 for (module.decl_table.items()) |kv| {
162 const decl = kv.value;175 const decl = kv.value;
163 const decl_tv = decl.typed_value.most_recent.typed_value;176 const decl_tv = decl.typed_value.most_recent.typed_value;
164 if (decl_tv.val.castTag(.function)) |_| {177 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;
166 }184 }
167 }185 }
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);
170}190}
171191
172pub fn updateDeclExports(192pub fn updateDeclExports(