| author | |
| committer | |
| log | b36c07a95a6cf9b2cc120133b44cbd0673e6823a |
| tree | 2c2bf8ff9137d51b80ae56dc70ef9375b8c13583 |
| parent | b220be7a33a9835a1ec7a033e472830290332d57 |
| parent | 4b6740e19d57454f3c4eac0c2e9a92ce08e7ec04 |
| signature |
65 files changed, 3020 insertions(+), 994 deletions(-)
doc/langref.html.in+4-4| ... | @@ -7455,6 +7455,10 @@ fn add(a: i32, b: i32) i32 { return a + b; } | ... | @@ -7455,6 +7455,10 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 7455 | Attempting to convert a number which is out of range of the destination type results in | 7455 | Attempting to convert a number which is out of range of the destination type results in |
| 7456 | safety-protected {#link|Undefined Behavior#}. | 7456 | safety-protected {#link|Undefined Behavior#}. |
| 7457 | </p> | 7457 | </p> |
| 7458 | <p> | ||
| 7459 | If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, | ||
| 7460 | then this is semantically equivalent to {#link|Type Coercion#}. | ||
| 7461 | </p> | ||
| 7458 | {#header_close#} | 7462 | {#header_close#} |
| 7459 | 7463 | ||
| 7460 | {#header_open|@intToEnum#} | 7464 | {#header_open|@intToEnum#} |
| ... | @@ -8206,10 +8210,6 @@ test "integer truncation" { | ... | @@ -8206,10 +8210,6 @@ test "integer truncation" { |
| 8206 | This function always truncates the significant bits of the integer, regardless | 8210 | This function always truncates the significant bits of the integer, regardless |
| 8207 | of endianness on the target platform. | 8211 | of endianness on the target platform. |
| 8208 | </p> | 8212 | </p> |
| 8209 | <p> | ||
| 8210 | If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, | ||
| 8211 | then this is semantically equivalent to {#link|Type Coercion#}. | ||
| 8212 | </p> | ||
| 8213 | {#header_close#} | 8213 | {#header_close#} |
| 8214 | 8214 | ||
| 8215 | {#header_open|@Type#} | 8215 | {#header_open|@Type#} |
lib/std/array_list.zig+17| ... | @@ -40,6 +40,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -40,6 +40,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 40 | .allocator = allocator, | 40 | .allocator = allocator, |
| 41 | }; | 41 | }; |
| 42 | } | 42 | } |
| 43 | |||
| 44 | /// Initialize with capacity to hold at least num elements. | ||
| 45 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | ||
| 46 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | ||
| 47 | var self = Self.init(allocator); | ||
| 48 | try self.ensureCapacity(num); | ||
| 49 | return self; | ||
| 50 | } | ||
| 43 | 51 | ||
| 44 | /// Release all allocated memory. | 52 | /// Release all allocated memory. |
| 45 | pub fn deinit(self: Self) void { | 53 | pub fn deinit(self: Self) void { |
| ... | @@ -271,6 +279,15 @@ test "std.ArrayList.init" { | ... | @@ -271,6 +279,15 @@ test "std.ArrayList.init" { |
| 271 | testing.expect(list.capacity() == 0); | 279 | testing.expect(list.capacity() == 0); |
| 272 | } | 280 | } |
| 273 | 281 | ||
| 282 | test "std.ArrayList.initCapacity" { | ||
| 283 | var bytes: [1024]u8 = undefined; | ||
| 284 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; | ||
| 285 | var list = try ArrayList(i8).initCapacity(allocator, 200); | ||
| 286 | defer list.deinit(); | ||
| 287 | testing.expect(list.count() == 0); | ||
| 288 | testing.expect(list.capacity() >= 200); | ||
| 289 | } | ||
| 290 | |||
| 274 | test "std.ArrayList.basic" { | 291 | test "std.ArrayList.basic" { |
| 275 | var bytes: [1024]u8 = undefined; | 292 | var bytes: [1024]u8 = undefined; |
| 276 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; | 293 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; |
lib/std/buffer.zig+35-1| ... | @@ -16,13 +16,22 @@ pub const Buffer = struct { | ... | @@ -16,13 +16,22 @@ pub const Buffer = struct { |
| 16 | mem.copy(u8, self.list.items, m); | 16 | mem.copy(u8, self.list.items, m); |
| 17 | return self; | 17 | return self; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | /// Initialize memory to size bytes of undefined values. | ||
| 20 | /// Must deinitialize with deinit. | 21 | /// Must deinitialize with deinit. |
| 21 | pub fn initSize(allocator: *Allocator, size: usize) !Buffer { | 22 | pub fn initSize(allocator: *Allocator, size: usize) !Buffer { |
| 22 | var self = initNull(allocator); | 23 | var self = initNull(allocator); |
| 23 | try self.resize(size); | 24 | try self.resize(size); |
| 24 | return self; | 25 | return self; |
| 25 | } | 26 | } |
| 27 | |||
| 28 | /// Initialize with capacity to hold at least num bytes. | ||
| 29 | /// Must deinitialize with deinit. | ||
| 30 | pub fn initCapacity(allocator: *Allocator, num: usize) !Buffer { | ||
| 31 | var self = Buffer{ .list = try ArrayList(u8).initCapacity(allocator, num + 1) }; | ||
| 32 | self.list.appendAssumeCapacity(0); | ||
| 33 | return self; | ||
| 34 | } | ||
| 26 | 35 | ||
| 27 | /// Must deinitialize with deinit. | 36 | /// Must deinitialize with deinit. |
| 28 | /// None of the other operations are valid until you do one of these: | 37 | /// None of the other operations are valid until you do one of these: |
| ... | @@ -98,6 +107,13 @@ pub const Buffer = struct { | ... | @@ -98,6 +107,13 @@ pub const Buffer = struct { |
| 98 | pub fn len(self: Buffer) usize { | 107 | pub fn len(self: Buffer) usize { |
| 99 | return self.list.len - 1; | 108 | return self.list.len - 1; |
| 100 | } | 109 | } |
| 110 | |||
| 111 | pub fn capacity(self: Buffer) usize { | ||
| 112 | return if (self.list.items.len > 0) | ||
| 113 | self.list.items.len - 1 | ||
| 114 | else | ||
| 115 | 0; | ||
| 116 | } | ||
| 101 | 117 | ||
| 102 | pub fn append(self: *Buffer, m: []const u8) !void { | 118 | pub fn append(self: *Buffer, m: []const u8) !void { |
| 103 | const old_len = self.len(); | 119 | const old_len = self.len(); |
| ... | @@ -151,3 +167,21 @@ test "simple Buffer" { | ... | @@ -151,3 +167,21 @@ test "simple Buffer" { |
| 151 | try buf2.resize(4); | 167 | try buf2.resize(4); |
| 152 | testing.expect(buf.startsWith(buf2.toSlice())); | 168 | testing.expect(buf.startsWith(buf2.toSlice())); |
| 153 | } | 169 | } |
| 170 | |||
| 171 | test "Buffer.initSize" { | ||
| 172 | var buf = try Buffer.initSize(debug.global_allocator, 3); | ||
| 173 | testing.expect(buf.len() == 3); | ||
| 174 | try buf.append("hello"); | ||
| 175 | testing.expect(mem.eql(u8, buf.toSliceConst()[3..], "hello")); | ||
| 176 | } | ||
| 177 | |||
| 178 | test "Buffer.initCapacity" { | ||
| 179 | var buf = try Buffer.initCapacity(debug.global_allocator, 10); | ||
| 180 | testing.expect(buf.len() == 0); | ||
| 181 | testing.expect(buf.capacity() >= 10); | ||
| 182 | const old_cap = buf.capacity(); | ||
| 183 | try buf.append("hello"); | ||
| 184 | testing.expect(buf.len() == 5); | ||
| 185 | testing.expect(buf.capacity() == old_cap); | ||
| 186 | testing.expect(mem.eql(u8, buf.toSliceConst(), "hello")); | ||
| 187 | } |
lib/std/build.zig+23-9| ... | @@ -2062,14 +2062,28 @@ pub const RunStep = struct { | ... | @@ -2062,14 +2062,28 @@ pub const RunStep = struct { |
| 2062 | } | 2062 | } |
| 2063 | 2063 | ||
| 2064 | pub fn addPathDir(self: *RunStep, search_path: []const u8) void { | 2064 | pub fn addPathDir(self: *RunStep, search_path: []const u8) void { |
| 2065 | const PATH = if (builtin.os == .windows) "Path" else "PATH"; | ||
| 2066 | const env_map = self.getEnvMap(); | 2065 | const env_map = self.getEnvMap(); |
| 2067 | const prev_path = env_map.get(PATH) orelse { | 2066 | |
| 2068 | env_map.set(PATH, search_path) catch unreachable; | 2067 | var key: []const u8 = undefined; |
| 2069 | return; | 2068 | var prev_path: ?[]const u8 = undefined; |
| 2070 | }; | 2069 | if (builtin.os == .windows) { |
| 2071 | const new_path = self.builder.fmt("{}" ++ &[1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path); | 2070 | key = "Path"; |
| 2072 | env_map.set(PATH, new_path) catch unreachable; | 2071 | prev_path = env_map.get(key); |
| 2072 | if (prev_path == null) { | ||
| 2073 | key = "PATH"; | ||
| 2074 | prev_path = env_map.get(key); | ||
| 2075 | } | ||
| 2076 | } else { | ||
| 2077 | key = "PATH"; | ||
| 2078 | prev_path = env_map.get(key); | ||
| 2079 | } | ||
| 2080 | |||
| 2081 | if (prev_path) |pp| { | ||
| 2082 | const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", pp, search_path); | ||
| 2083 | env_map.set(key, new_path) catch unreachable; | ||
| 2084 | } else { | ||
| 2085 | env_map.set(key, search_path) catch unreachable; | ||
| 2086 | } | ||
| 2073 | } | 2087 | } |
| 2074 | 2088 | ||
| 2075 | pub fn getEnvMap(self: *RunStep) *BufMap { | 2089 | pub fn getEnvMap(self: *RunStep) *BufMap { |
| ... | @@ -2178,7 +2192,7 @@ const InstallArtifactStep = struct { | ... | @@ -2178,7 +2192,7 @@ const InstallArtifactStep = struct { |
| 2178 | 2192 | ||
| 2179 | const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); | 2193 | const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); |
| 2180 | try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); | 2194 | try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); |
| 2181 | if (self.artifact.isDynamicLibrary()) { | 2195 | if (self.artifact.isDynamicLibrary() and self.artifact.target.wantSharedLibSymLinks()) { |
| 2182 | try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename); | 2196 | try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename); |
| 2183 | } | 2197 | } |
| 2184 | if (self.pdb_dir) |pdb_dir| { | 2198 | if (self.pdb_dir) |pdb_dir| { |
| ... | @@ -2405,7 +2419,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { | ... | @@ -2405,7 +2419,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { |
| 2405 | const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" }); | 2419 | const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" }); |
| 2406 | defer allocator.free(path_file); | 2420 | defer allocator.free(path_file); |
| 2407 | 2421 | ||
| 2408 | const file = fs.File.openRead(path_file) catch return null; | 2422 | const file = fs.cwd().openFile(path_file, .{}) catch return null; |
| 2409 | defer file.close(); | 2423 | defer file.close(); |
| 2410 | 2424 | ||
| 2411 | const size = @intCast(usize, try file.getEndPos()); | 2425 | const size = @intCast(usize, try file.getEndPos()); |
lib/std/c.zig+1| ... | @@ -220,6 +220,7 @@ pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int; | ... | @@ -220,6 +220,7 @@ pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int; |
| 220 | 220 | ||
| 221 | pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{}; | 221 | pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{}; |
| 222 | pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int; | 222 | pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int; |
| 223 | pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) c_int; | ||
| 223 | pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int; | 224 | pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int; |
| 224 | pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int; | 225 | pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int; |
| 225 | 226 |
lib/std/debug.zig+8-2| ... | @@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1131 | } | 1131 | } |
| 1132 | 1132 | ||
| 1133 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { | 1133 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { |
| 1134 | var f = try File.openRead(line_info.file_name); | 1134 | var f = try fs.cwd().openFile(line_info.file_name, .{}); |
| 1135 | defer f.close(); | 1135 | defer f.close(); |
| 1136 | // TODO fstat and make sure that the file has the correct size | 1136 | // TODO fstat and make sure that the file has the correct size |
| 1137 | 1137 | ||
| ... | @@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u | ... | @@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 2089 | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); | 2089 | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); |
| 2090 | 2090 | ||
| 2091 | gop.kv.value = MachOFile{ | 2091 | gop.kv.value = MachOFile{ |
| 2092 | .bytes = try std.fs.Dir.cwd().readFileAllocAligned( | 2092 | .bytes = try std.fs.cwd().readFileAllocAligned( |
| 2093 | di.ofiles.allocator, | 2093 | di.ofiles.allocator, |
| 2094 | ofile_path, | 2094 | ofile_path, |
| 2095 | maxInt(usize), | 2095 | maxInt(usize), |
| ... | @@ -2417,6 +2417,12 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con | ... | @@ -2417,6 +2417,12 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con |
| 2417 | std.debug.warn("Segmentation fault at address 0x{x}\n", addr); | 2417 | std.debug.warn("Segmentation fault at address 0x{x}\n", addr); |
| 2418 | 2418 | ||
| 2419 | switch (builtin.arch) { | 2419 | switch (builtin.arch) { |
| 2420 | .i386 => { | ||
| 2421 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); | ||
| 2422 | const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_EIP]); | ||
| 2423 | const bp = @intCast(usize, ctx.mcontext.gregs[os.REG_EBP]); | ||
| 2424 | dumpStackTraceFromBase(bp, ip); | ||
| 2425 | }, | ||
| 2420 | .x86_64 => { | 2426 | .x86_64 => { |
| 2421 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); | 2427 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| 2422 | const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]); | 2428 | const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]); |
lib/std/event/channel.zig+30-3| ... | @@ -54,6 +54,10 @@ pub fn Channel(comptime T: type) type { | ... | @@ -54,6 +54,10 @@ pub fn Channel(comptime T: type) type { |
| 54 | /// For a zero length buffer, use `[0]T{}`. | 54 | /// For a zero length buffer, use `[0]T{}`. |
| 55 | /// TODO https://github.com/ziglang/zig/issues/2765 | 55 | /// TODO https://github.com/ziglang/zig/issues/2765 |
| 56 | pub fn init(self: *SelfChannel, buffer: []T) void { | 56 | pub fn init(self: *SelfChannel, buffer: []T) void { |
| 57 | // The ring buffer implementation only works with power of 2 buffer sizes | ||
| 58 | // because of relying on subtracting across zero. For example (0 -% 1) % 10 == 5 | ||
| 59 | assert(buffer.len == 0 or @popCount(usize, buffer.len) == 1); | ||
| 60 | |||
| 57 | self.* = SelfChannel{ | 61 | self.* = SelfChannel{ |
| 58 | .buffer_len = 0, | 62 | .buffer_len = 0, |
| 59 | .buffer_nodes = buffer, | 63 | .buffer_nodes = buffer, |
| ... | @@ -184,11 +188,11 @@ pub fn Channel(comptime T: type) type { | ... | @@ -184,11 +188,11 @@ pub fn Channel(comptime T: type) type { |
| 184 | const get_node = &self.getters.get().?.data; | 188 | const get_node = &self.getters.get().?.data; |
| 185 | switch (get_node.data) { | 189 | switch (get_node.data) { |
| 186 | GetNode.Data.Normal => |info| { | 190 | GetNode.Data.Normal => |info| { |
| 187 | info.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len]; | 191 | info.ptr.* = self.buffer_nodes[(self.buffer_index -% self.buffer_len) % self.buffer_nodes.len]; |
| 188 | }, | 192 | }, |
| 189 | GetNode.Data.OrNull => |info| { | 193 | GetNode.Data.OrNull => |info| { |
| 190 | _ = self.or_null_queue.remove(info.or_null); | 194 | _ = self.or_null_queue.remove(info.or_null); |
| 191 | info.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len]; | 195 | info.ptr.* = self.buffer_nodes[(self.buffer_index -% self.buffer_len) % self.buffer_nodes.len]; |
| 192 | }, | 196 | }, |
| 193 | } | 197 | } |
| 194 | global_event_loop.onNextTick(get_node.tick_node); | 198 | global_event_loop.onNextTick(get_node.tick_node); |
| ... | @@ -222,7 +226,7 @@ pub fn Channel(comptime T: type) type { | ... | @@ -222,7 +226,7 @@ pub fn Channel(comptime T: type) type { |
| 222 | while (self.buffer_len != self.buffer_nodes.len and put_count != 0) { | 226 | while (self.buffer_len != self.buffer_nodes.len and put_count != 0) { |
| 223 | const put_node = &self.putters.get().?.data; | 227 | const put_node = &self.putters.get().?.data; |
| 224 | 228 | ||
| 225 | self.buffer_nodes[self.buffer_index] = put_node.data; | 229 | self.buffer_nodes[self.buffer_index % self.buffer_nodes.len] = put_node.data; |
| 226 | global_event_loop.onNextTick(put_node.tick_node); | 230 | global_event_loop.onNextTick(put_node.tick_node); |
| 227 | self.buffer_index +%= 1; | 231 | self.buffer_index +%= 1; |
| 228 | self.buffer_len += 1; | 232 | self.buffer_len += 1; |
| ... | @@ -283,6 +287,29 @@ test "std.event.Channel" { | ... | @@ -283,6 +287,29 @@ test "std.event.Channel" { |
| 283 | await putter; | 287 | await putter; |
| 284 | } | 288 | } |
| 285 | 289 | ||
| 290 | test "std.event.Channel wraparound" { | ||
| 291 | |||
| 292 | // TODO provide a way to run tests in evented I/O mode | ||
| 293 | if (!std.io.is_async) return error.SkipZigTest; | ||
| 294 | |||
| 295 | const channel_size = 2; | ||
| 296 | |||
| 297 | var buf : [channel_size]i32 = undefined; | ||
| 298 | var channel: Channel(i32) = undefined; | ||
| 299 | channel.init(&buf); | ||
| 300 | defer channel.deinit(); | ||
| 301 | |||
| 302 | // add items to channel and pull them out until | ||
| 303 | // the buffer wraps around, make sure it doesn't crash. | ||
| 304 | var result : i32 = undefined; | ||
| 305 | channel.put(5); | ||
| 306 | testing.expectEqual(@as(i32, 5), channel.get()); | ||
| 307 | channel.put(6); | ||
| 308 | testing.expectEqual(@as(i32, 6), channel.get()); | ||
| 309 | channel.put(7); | ||
| 310 | testing.expectEqual(@as(i32, 7), channel.get()); | ||
| 311 | } | ||
| 312 | |||
| 286 | async fn testChannelGetter(channel: *Channel(i32)) void { | 313 | async fn testChannelGetter(channel: *Channel(i32)) void { |
| 287 | const value1 = channel.get(); | 314 | const value1 = channel.get(); |
| 288 | testing.expect(value1 == 1234); | 315 | testing.expect(value1 == 1234); |
lib/std/event/fs.zig+15-13| ... | @@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type { | ... | @@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type { |
| 735 | allocator: *Allocator, | 735 | allocator: *Allocator, |
| 736 | 736 | ||
| 737 | const OsData = switch (builtin.os) { | 737 | const OsData = switch (builtin.os) { |
| 738 | .macosx, .freebsd, .netbsd, .dragonfly => struct { | 738 | // TODO https://github.com/ziglang/zig/issues/3778 |
| 739 | file_table: FileTable, | 739 | .macosx, .freebsd, .netbsd, .dragonfly => KqOsData, |
| 740 | table_lock: event.Lock, | ||
| 741 | |||
| 742 | const FileTable = std.StringHashMap(*Put); | ||
| 743 | const Put = struct { | ||
| 744 | putter_frame: @Frame(kqPutEvents), | ||
| 745 | cancelled: bool = false, | ||
| 746 | value: V, | ||
| 747 | }; | ||
| 748 | }, | ||
| 749 | |||
| 750 | .linux => LinuxOsData, | 740 | .linux => LinuxOsData, |
| 751 | .windows => WindowsOsData, | 741 | .windows => WindowsOsData, |
| 752 | 742 | ||
| 753 | else => @compileError("Unsupported OS"), | 743 | else => @compileError("Unsupported OS"), |
| 754 | }; | 744 | }; |
| 755 | 745 | ||
| 746 | const KqOsData = struct { | ||
| 747 | file_table: FileTable, | ||
| 748 | table_lock: event.Lock, | ||
| 749 | |||
| 750 | const FileTable = std.StringHashMap(*Put); | ||
| 751 | const Put = struct { | ||
| 752 | putter_frame: @Frame(kqPutEvents), | ||
| 753 | cancelled: bool = false, | ||
| 754 | value: V, | ||
| 755 | }; | ||
| 756 | }; | ||
| 757 | |||
| 756 | const WindowsOsData = struct { | 758 | const WindowsOsData = struct { |
| 757 | table_lock: event.Lock, | 759 | table_lock: event.Lock, |
| 758 | dir_table: DirTable, | 760 | dir_table: DirTable, |
| ... | @@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type { | ... | @@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type { |
| 1291 | os.linux.EINVAL => unreachable, | 1293 | os.linux.EINVAL => unreachable, |
| 1292 | os.linux.EFAULT => unreachable, | 1294 | os.linux.EFAULT => unreachable, |
| 1293 | os.linux.EAGAIN => { | 1295 | os.linux.EAGAIN => { |
| 1294 | global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN); | 1296 | global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN | os.EPOLLONESHOT); |
| 1295 | }, | 1297 | }, |
| 1296 | else => unreachable, | 1298 | else => unreachable, |
| 1297 | } | 1299 | } |
lib/std/fs.zig+229-49| ... | @@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File; | ... | @@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File; |
| 13 | 13 | ||
| 14 | pub const symLink = os.symlink; | 14 | pub const symLink = os.symlink; |
| 15 | pub const symLinkC = os.symlinkC; | 15 | pub const symLinkC = os.symlinkC; |
| 16 | pub const deleteFile = os.unlink; | ||
| 17 | pub const deleteFileC = os.unlinkC; | ||
| 18 | pub const rename = os.rename; | 16 | pub const rename = os.rename; |
| 19 | pub const renameC = os.renameC; | 17 | pub const renameC = os.renameC; |
| 20 | pub const renameW = os.renameW; | 18 | pub const renameW = os.renameW; |
| ... | @@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { | ... | @@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { |
| 88 | /// If any of the directories do not exist for dest_path, they are created. | 86 | /// If any of the directories do not exist for dest_path, they are created. |
| 89 | /// TODO https://github.com/ziglang/zig/issues/2885 | 87 | /// TODO https://github.com/ziglang/zig/issues/2885 |
| 90 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { | 88 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { |
| 91 | var src_file = try File.openRead(source_path); | 89 | const my_cwd = cwd(); |
| 90 | |||
| 91 | var src_file = try my_cwd.openFile(source_path, .{}); | ||
| 92 | defer src_file.close(); | 92 | defer src_file.close(); |
| 93 | 93 | ||
| 94 | const src_stat = try src_file.stat(); | 94 | const src_stat = try src_file.stat(); |
| 95 | check_dest_stat: { | 95 | check_dest_stat: { |
| 96 | const dest_stat = blk: { | 96 | const dest_stat = blk: { |
| 97 | var dest_file = File.openRead(dest_path) catch |err| switch (err) { | 97 | var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) { |
| 98 | error.FileNotFound => break :check_dest_stat, | 98 | error.FileNotFound => break :check_dest_stat, |
| 99 | else => |e| return e, | 99 | else => |e| return e, |
| 100 | }; | 100 | }; |
| ... | @@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil | ... | @@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil |
| 157 | /// in the same directory as dest_path. | 157 | /// in the same directory as dest_path. |
| 158 | /// Destination file will have the same mode as the source file. | 158 | /// Destination file will have the same mode as the source file. |
| 159 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | 159 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { |
| 160 | var in_file = try File.openRead(source_path); | 160 | var in_file = try cwd().openFile(source_path, .{}); |
| 161 | defer in_file.close(); | 161 | defer in_file.close(); |
| 162 | 162 | ||
| 163 | const mode = try in_file.mode(); | 163 | const mode = try in_file.mode(); |
| ... | @@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | ... | @@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { |
| 180 | /// merged and readily available, | 180 | /// merged and readily available, |
| 181 | /// there is a possibility of power loss or application termination leaving temporary files present | 181 | /// there is a possibility of power loss or application termination leaving temporary files present |
| 182 | pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { | 182 | pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { |
| 183 | var in_file = try File.openRead(source_path); | 183 | var in_file = try cwd().openFile(source_path, .{}); |
| 184 | defer in_file.close(); | 184 | defer in_file.close(); |
| 185 | 185 | ||
| 186 | var atomic_file = try AtomicFile.init(dest_path, mode); | 186 | var atomic_file = try AtomicFile.init(dest_path, mode); |
| ... | @@ -206,8 +206,6 @@ pub const AtomicFile = struct { | ... | @@ -206,8 +206,6 @@ pub const AtomicFile = struct { |
| 206 | 206 | ||
| 207 | /// dest_path must remain valid for the lifetime of AtomicFile | 207 | /// dest_path must remain valid for the lifetime of AtomicFile |
| 208 | /// call finish to atomically replace dest_path with contents | 208 | /// call finish to atomically replace dest_path with contents |
| 209 | /// TODO once we have null terminated pointers, use the | ||
| 210 | /// openWriteNoClobberN function | ||
| 211 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { | 209 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { |
| 212 | const dirname = path.dirname(dest_path); | 210 | const dirname = path.dirname(dest_path); |
| 213 | var rand_buf: [12]u8 = undefined; | 211 | var rand_buf: [12]u8 = undefined; |
| ... | @@ -224,15 +222,19 @@ pub const AtomicFile = struct { | ... | @@ -224,15 +222,19 @@ pub const AtomicFile = struct { |
| 224 | 222 | ||
| 225 | tmp_path_buf[tmp_path_len] = 0; | 223 | tmp_path_buf[tmp_path_len] = 0; |
| 226 | 224 | ||
| 225 | const my_cwd = cwd(); | ||
| 226 | |||
| 227 | while (true) { | 227 | while (true) { |
| 228 | try crypto.randomBytes(rand_buf[0..]); | 228 | try crypto.randomBytes(rand_buf[0..]); |
| 229 | b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], &rand_buf); | 229 | b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], &rand_buf); |
| 230 | 230 | ||
| 231 | const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) { | 231 | // TODO https://github.com/ziglang/zig/issues/3770 to clean up this @ptrCast |
| 232 | const file = my_cwd.createFileC( | ||
| 233 | @ptrCast([*:0]u8, &tmp_path_buf), | ||
| 234 | .{ .mode = mode, .exclusive = true }, | ||
| 235 | ) catch |err| switch (err) { | ||
| 232 | error.PathAlreadyExists => continue, | 236 | error.PathAlreadyExists => continue, |
| 233 | // TODO zig should figure out that this error set does not include PathAlreadyExists since | 237 | else => |e| return e, |
| 234 | // it is handled in the above switch | ||
| 235 | else => return err, | ||
| 236 | }; | 238 | }; |
| 237 | 239 | ||
| 238 | return AtomicFile{ | 240 | return AtomicFile{ |
| ... | @@ -248,7 +250,7 @@ pub const AtomicFile = struct { | ... | @@ -248,7 +250,7 @@ pub const AtomicFile = struct { |
| 248 | pub fn deinit(self: *AtomicFile) void { | 250 | pub fn deinit(self: *AtomicFile) void { |
| 249 | if (!self.finished) { | 251 | if (!self.finished) { |
| 250 | self.file.close(); | 252 | self.file.close(); |
| 251 | deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; | 253 | cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; |
| 252 | self.finished = true; | 254 | self.finished = true; |
| 253 | } | 255 | } |
| 254 | } | 256 | } |
| ... | @@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void { | ... | @@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 350 | CannotDeleteRootDirectory, | 352 | CannotDeleteRootDirectory, |
| 351 | }.CannotDeleteRootDirectory; | 353 | }.CannotDeleteRootDirectory; |
| 352 | 354 | ||
| 353 | var dir = try Dir.cwd().openDirList(dirname); | 355 | var dir = try cwd().openDirList(dirname); |
| 354 | defer dir.close(); | 356 | defer dir.close(); |
| 355 | 357 | ||
| 356 | return dir.deleteTree(path.basename(full_path)); | 358 | return dir.deleteTree(path.basename(full_path)); |
| 357 | } else { | 359 | } else { |
| 358 | return Dir.cwd().deleteTree(full_path); | 360 | return cwd().deleteTree(full_path); |
| 359 | } | 361 | } |
| 360 | } | 362 | } |
| 361 | 363 | ||
| ... | @@ -657,17 +659,6 @@ pub const Dir = struct { | ... | @@ -657,17 +659,6 @@ pub const Dir = struct { |
| 657 | } | 659 | } |
| 658 | } | 660 | } |
| 659 | 661 | ||
| 660 | /// Returns an handle to the current working directory that is open for traversal. | ||
| 661 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. | ||
| 662 | /// On POSIX targets, this function is comptime-callable. | ||
| 663 | pub fn cwd() Dir { | ||
| 664 | if (builtin.os == .windows) { | ||
| 665 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; | ||
| 666 | } else { | ||
| 667 | return Dir{ .fd = os.AT_FDCWD }; | ||
| 668 | } | ||
| 669 | } | ||
| 670 | |||
| 671 | pub const OpenError = error{ | 662 | pub const OpenError = error{ |
| 672 | FileNotFound, | 663 | FileNotFound, |
| 673 | NotDir, | 664 | NotDir, |
| ... | @@ -683,12 +674,12 @@ pub const Dir = struct { | ... | @@ -683,12 +674,12 @@ pub const Dir = struct { |
| 683 | DeviceBusy, | 674 | DeviceBusy, |
| 684 | } || os.UnexpectedError; | 675 | } || os.UnexpectedError; |
| 685 | 676 | ||
| 686 | /// Deprecated; call `Dir.cwd().openDirList` directly. | 677 | /// Deprecated; call `cwd().openDirList` directly. |
| 687 | pub fn open(dir_path: []const u8) OpenError!Dir { | 678 | pub fn open(dir_path: []const u8) OpenError!Dir { |
| 688 | return cwd().openDirList(dir_path); | 679 | return cwd().openDirList(dir_path); |
| 689 | } | 680 | } |
| 690 | 681 | ||
| 691 | /// Deprecated; call `Dir.cwd().openDirListC` directly. | 682 | /// Deprecated; call `cwd().openDirListC` directly. |
| 692 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { | 683 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { |
| 693 | return cwd().openDirListC(dir_path_c); | 684 | return cwd().openDirListC(dir_path_c); |
| 694 | } | 685 | } |
| ... | @@ -698,29 +689,110 @@ pub const Dir = struct { | ... | @@ -698,29 +689,110 @@ pub const Dir = struct { |
| 698 | self.* = undefined; | 689 | self.* = undefined; |
| 699 | } | 690 | } |
| 700 | 691 | ||
| 701 | /// Call `File.close` on the result when done. | 692 | /// Opens a file for reading or writing, without attempting to create a new file. |
| 702 | pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File { | 693 | /// Call `File.close` to release the resource. |
| 694 | /// Asserts that the path parameter has no null bytes. | ||
| 695 | pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 696 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 703 | if (builtin.os == .windows) { | 697 | if (builtin.os == .windows) { |
| 704 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 698 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 705 | return self.openReadW(&path_w); | 699 | return self.openFileW(&path_w, flags); |
| 706 | } | 700 | } |
| 707 | const path_c = try os.toPosixPath(sub_path); | 701 | const path_c = try os.toPosixPath(sub_path); |
| 708 | return self.openReadC(&path_c); | 702 | return self.openFileC(&path_c, flags); |
| 709 | } | 703 | } |
| 710 | 704 | ||
| 711 | /// Call `File.close` on the result when done. | 705 | /// Same as `openFile` but the path parameter is null-terminated. |
| 712 | pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { | 706 | pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { |
| 713 | if (builtin.os == .windows) { | 707 | if (builtin.os == .windows) { |
| 714 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path); | 708 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path); |
| 715 | return self.openReadW(&path_w); | 709 | return self.openFileW(&path_w, flags); |
| 716 | } | 710 | } |
| 717 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 711 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 718 | const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC; | 712 | const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) |
| 719 | const fd = try os.openatC(self.fd, sub_path, flags, 0); | 713 | @as(u32, os.O_RDWR) |
| 720 | return File.openHandle(fd); | 714 | else if (flags.write) |
| 715 | @as(u32, os.O_WRONLY) | ||
| 716 | else | ||
| 717 | @as(u32, os.O_RDONLY); | ||
| 718 | const fd = try os.openatC(self.fd, sub_path, os_flags, 0); | ||
| 719 | return File{ .handle = fd }; | ||
| 720 | } | ||
| 721 | |||
| 722 | /// Same as `openFile` but Windows-only and the path parameter is | ||
| 723 | /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded. | ||
| 724 | pub fn openFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | ||
| 725 | const w = os.windows; | ||
| 726 | const access_mask = w.SYNCHRONIZE | | ||
| 727 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | | ||
| 728 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); | ||
| 729 | return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN); | ||
| 721 | } | 730 | } |
| 722 | 731 | ||
| 723 | pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File { | 732 | /// Creates, opens, or overwrites a file with write access. |
| 733 | /// Call `File.close` on the result when done. | ||
| 734 | /// Asserts that the path parameter has no null bytes. | ||
| 735 | pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 736 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 737 | if (builtin.os == .windows) { | ||
| 738 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); | ||
| 739 | return self.createFileW(&path_w, flags); | ||
| 740 | } | ||
| 741 | const path_c = try os.toPosixPath(sub_path); | ||
| 742 | return self.createFileC(&path_c, flags); | ||
| 743 | } | ||
| 744 | |||
| 745 | /// Same as `createFile` but the path parameter is null-terminated. | ||
| 746 | pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 747 | if (builtin.os == .windows) { | ||
| 748 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | ||
| 749 | return self.createFileW(&path_w, flags); | ||
| 750 | } | ||
| 751 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | ||
| 752 | const os_flags = O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | ||
| 753 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | | ||
| 754 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | | ||
| 755 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); | ||
| 756 | const fd = try os.openatC(self.fd, sub_path_c, os_flags, flags.mode); | ||
| 757 | return File{ .handle = fd }; | ||
| 758 | } | ||
| 759 | |||
| 760 | /// Same as `createFile` but Windows-only and the path parameter is | ||
| 761 | /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded. | ||
| 762 | pub fn createFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | ||
| 763 | const w = os.windows; | ||
| 764 | const access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | | ||
| 765 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0); | ||
| 766 | const creation = if (flags.exclusive) | ||
| 767 | @as(u32, w.FILE_CREATE) | ||
| 768 | else if (flags.truncate) | ||
| 769 | @as(u32, w.FILE_OVERWRITE_IF) | ||
| 770 | else | ||
| 771 | @as(u32, w.FILE_OPEN_IF); | ||
| 772 | return self.openFileWindows(sub_path_w, access_mask, creation); | ||
| 773 | } | ||
| 774 | |||
| 775 | /// Deprecated; call `openFile` directly. | ||
| 776 | pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File { | ||
| 777 | return self.openFile(sub_path, .{}); | ||
| 778 | } | ||
| 779 | |||
| 780 | /// Deprecated; call `openFileC` directly. | ||
| 781 | pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { | ||
| 782 | return self.openFileC(sub_path, .{}); | ||
| 783 | } | ||
| 784 | |||
| 785 | /// Deprecated; call `openFileW` directly. | ||
| 786 | pub fn openReadW(self: Dir, sub_path: [*:0]const u16) File.OpenError!File { | ||
| 787 | return self.openFileW(sub_path, .{}); | ||
| 788 | } | ||
| 789 | |||
| 790 | pub fn openFileWindows( | ||
| 791 | self: Dir, | ||
| 792 | sub_path_w: [*:0]const u16, | ||
| 793 | access_mask: os.windows.ACCESS_MASK, | ||
| 794 | creation: os.windows.ULONG, | ||
| 795 | ) File.OpenError!File { | ||
| 724 | const w = os.windows; | 796 | const w = os.windows; |
| 725 | 797 | ||
| 726 | var result = File{ .handle = undefined }; | 798 | var result = File{ .handle = undefined }; |
| ... | @@ -750,13 +822,13 @@ pub const Dir = struct { | ... | @@ -750,13 +822,13 @@ pub const Dir = struct { |
| 750 | var io: w.IO_STATUS_BLOCK = undefined; | 822 | var io: w.IO_STATUS_BLOCK = undefined; |
| 751 | const rc = w.ntdll.NtCreateFile( | 823 | const rc = w.ntdll.NtCreateFile( |
| 752 | &result.handle, | 824 | &result.handle, |
| 753 | w.GENERIC_READ | w.SYNCHRONIZE, | 825 | access_mask, |
| 754 | &attr, | 826 | &attr, |
| 755 | &io, | 827 | &io, |
| 756 | null, | 828 | null, |
| 757 | w.FILE_ATTRIBUTE_NORMAL, | 829 | w.FILE_ATTRIBUTE_NORMAL, |
| 758 | w.FILE_SHARE_READ, | 830 | w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, |
| 759 | w.FILE_OPEN, | 831 | creation, |
| 760 | w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT, | 832 | w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT, |
| 761 | null, | 833 | null, |
| 762 | 0, | 834 | 0, |
| ... | @@ -771,6 +843,7 @@ pub const Dir = struct { | ... | @@ -771,6 +843,7 @@ pub const Dir = struct { |
| 771 | w.STATUS.ACCESS_DENIED => return error.AccessDenied, | 843 | w.STATUS.ACCESS_DENIED => return error.AccessDenied, |
| 772 | w.STATUS.PIPE_BUSY => return error.PipeBusy, | 844 | w.STATUS.PIPE_BUSY => return error.PipeBusy, |
| 773 | w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable, | 845 | w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable, |
| 846 | w.STATUS.OBJECT_NAME_COLLISION => return error.PathAlreadyExists, | ||
| 774 | else => return w.unexpectedStatus(rc), | 847 | else => return w.unexpectedStatus(rc), |
| 775 | } | 848 | } |
| 776 | } | 849 | } |
| ... | @@ -790,7 +863,10 @@ pub const Dir = struct { | ... | @@ -790,7 +863,10 @@ pub const Dir = struct { |
| 790 | /// list the contents of a directory, open it with `openDirList`. | 863 | /// list the contents of a directory, open it with `openDirList`. |
| 791 | /// | 864 | /// |
| 792 | /// Call `close` on the result when done. | 865 | /// Call `close` on the result when done. |
| 866 | /// | ||
| 867 | /// Asserts that the path parameter has no null bytes. | ||
| 793 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { | 868 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 869 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 794 | if (builtin.os == .windows) { | 870 | if (builtin.os == .windows) { |
| 795 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 871 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 796 | return self.openDirTraverseW(&sub_path_w); | 872 | return self.openDirTraverseW(&sub_path_w); |
| ... | @@ -805,7 +881,10 @@ pub const Dir = struct { | ... | @@ -805,7 +881,10 @@ pub const Dir = struct { |
| 805 | /// same and may be more efficient. | 881 | /// same and may be more efficient. |
| 806 | /// | 882 | /// |
| 807 | /// Call `close` on the result when done. | 883 | /// Call `close` on the result when done. |
| 884 | /// | ||
| 885 | /// Asserts that the path parameter has no null bytes. | ||
| 808 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { | 886 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 887 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 809 | if (builtin.os == .windows) { | 888 | if (builtin.os == .windows) { |
| 810 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 889 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 811 | return self.openDirListW(&sub_path_w); | 890 | return self.openDirListW(&sub_path_w); |
| ... | @@ -920,9 +999,12 @@ pub const Dir = struct { | ... | @@ -920,9 +999,12 @@ pub const Dir = struct { |
| 920 | pub const DeleteFileError = os.UnlinkError; | 999 | pub const DeleteFileError = os.UnlinkError; |
| 921 | 1000 | ||
| 922 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 1001 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 1002 | /// Asserts that the path parameter has no null bytes. | ||
| 923 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { | 1003 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { |
| 924 | const sub_path_c = try os.toPosixPath(sub_path); | 1004 | os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) { |
| 925 | return self.deleteFileC(&sub_path_c); | 1005 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR |
| 1006 | else => |e| return e, | ||
| 1007 | }; | ||
| 926 | } | 1008 | } |
| 927 | 1009 | ||
| 928 | /// Same as `deleteFile` except the parameter is null-terminated. | 1010 | /// Same as `deleteFile` except the parameter is null-terminated. |
| ... | @@ -933,6 +1015,14 @@ pub const Dir = struct { | ... | @@ -933,6 +1015,14 @@ pub const Dir = struct { |
| 933 | }; | 1015 | }; |
| 934 | } | 1016 | } |
| 935 | 1017 | ||
| 1018 | /// Same as `deleteFile` except the parameter is WTF-16 encoded. | ||
| 1019 | pub fn deleteFileW(self: Dir, sub_path_w: [*:0]const u16) DeleteFileError!void { | ||
| 1020 | os.unlinkatW(self.fd, sub_path_w, 0) catch |err| switch (err) { | ||
| 1021 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | ||
| 1022 | else => |e| return e, | ||
| 1023 | }; | ||
| 1024 | } | ||
| 1025 | |||
| 936 | pub const DeleteDirError = error{ | 1026 | pub const DeleteDirError = error{ |
| 937 | DirNotEmpty, | 1027 | DirNotEmpty, |
| 938 | FileNotFound, | 1028 | FileNotFound, |
| ... | @@ -951,7 +1041,9 @@ pub const Dir = struct { | ... | @@ -951,7 +1041,9 @@ pub const Dir = struct { |
| 951 | 1041 | ||
| 952 | /// Returns `error.DirNotEmpty` if the directory is not empty. | 1042 | /// Returns `error.DirNotEmpty` if the directory is not empty. |
| 953 | /// To delete a directory recursively, see `deleteTree`. | 1043 | /// To delete a directory recursively, see `deleteTree`. |
| 1044 | /// Asserts that the path parameter has no null bytes. | ||
| 954 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { | 1045 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { |
| 1046 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 955 | if (builtin.os == .windows) { | 1047 | if (builtin.os == .windows) { |
| 956 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 1048 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 957 | return self.deleteDirW(&sub_path_w); | 1049 | return self.deleteDirW(&sub_path_w); |
| ... | @@ -979,7 +1071,9 @@ pub const Dir = struct { | ... | @@ -979,7 +1071,9 @@ pub const Dir = struct { |
| 979 | 1071 | ||
| 980 | /// Read value of a symbolic link. | 1072 | /// Read value of a symbolic link. |
| 981 | /// The return value is a slice of `buffer`, from index `0`. | 1073 | /// The return value is a slice of `buffer`, from index `0`. |
| 1074 | /// Asserts that the path parameter has no null bytes. | ||
| 982 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1075 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1076 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 983 | const sub_path_c = try os.toPosixPath(sub_path); | 1077 | const sub_path_c = try os.toPosixPath(sub_path); |
| 984 | return self.readLinkC(&sub_path_c, buffer); | 1078 | return self.readLinkC(&sub_path_c, buffer); |
| 985 | } | 1079 | } |
| ... | @@ -1190,8 +1284,94 @@ pub const Dir = struct { | ... | @@ -1190,8 +1284,94 @@ pub const Dir = struct { |
| 1190 | } | 1284 | } |
| 1191 | } | 1285 | } |
| 1192 | } | 1286 | } |
| 1287 | |||
| 1288 | /// Writes content to the file system, creating a new file if it does not exist, truncating | ||
| 1289 | /// if it already exists. | ||
| 1290 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { | ||
| 1291 | var file = try self.createFile(sub_path, .{}); | ||
| 1292 | defer file.close(); | ||
| 1293 | try file.write(data); | ||
| 1294 | } | ||
| 1193 | }; | 1295 | }; |
| 1194 | 1296 | ||
| 1297 | /// Returns an handle to the current working directory that is open for traversal. | ||
| 1298 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. | ||
| 1299 | /// On POSIX targets, this function is comptime-callable. | ||
| 1300 | pub fn cwd() Dir { | ||
| 1301 | if (builtin.os == .windows) { | ||
| 1302 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; | ||
| 1303 | } else { | ||
| 1304 | return Dir{ .fd = os.AT_FDCWD }; | ||
| 1305 | } | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | /// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path. | ||
| 1309 | /// Call `File.close` to release the resource. | ||
| 1310 | /// Asserts that the path is absolute. See `Dir.openFile` for a function that | ||
| 1311 | /// operates on both absolute and relative paths. | ||
| 1312 | /// Asserts that the path parameter has no null bytes. See `openFileAbsoluteC` for a function | ||
| 1313 | /// that accepts a null-terminated path. | ||
| 1314 | pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 1315 | assert(path.isAbsolute(absolute_path)); | ||
| 1316 | return cwd().openFile(absolute_path, flags); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /// Same as `openFileAbsolute` but the path parameter is null-terminated. | ||
| 1320 | pub fn openFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 1321 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1322 | return cwd().openFileC(absolute_path_c, flags); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | /// Same as `openFileAbsolute` but the path parameter is WTF-16 encoded. | ||
| 1326 | pub fn openFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | ||
| 1327 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1328 | return cwd().openFileW(absolute_path_w, flags); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | /// Creates, opens, or overwrites a file with write access, based on an absolute path. | ||
| 1332 | /// Call `File.close` to release the resource. | ||
| 1333 | /// Asserts that the path is absolute. See `Dir.createFile` for a function that | ||
| 1334 | /// operates on both absolute and relative paths. | ||
| 1335 | /// Asserts that the path parameter has no null bytes. See `createFileAbsoluteC` for a function | ||
| 1336 | /// that accepts a null-terminated path. | ||
| 1337 | pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 1338 | assert(path.isAbsolute(absolute_path)); | ||
| 1339 | return cwd().createFile(absolute_path, flags); | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | /// Same as `createFileAbsolute` but the path parameter is null-terminated. | ||
| 1343 | pub fn createFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 1344 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1345 | return cwd().createFileC(absolute_path_c, flags); | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | /// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded. | ||
| 1349 | pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | ||
| 1350 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1351 | return cwd().createFileW(absolute_path_w, flags); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | /// Delete a file name and possibly the file it refers to, based on an absolute path. | ||
| 1355 | /// Asserts that the path is absolute. See `Dir.deleteFile` for a function that | ||
| 1356 | /// operates on both absolute and relative paths. | ||
| 1357 | /// Asserts that the path parameter has no null bytes. | ||
| 1358 | pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void { | ||
| 1359 | assert(path.isAbsolute(absolute_path)); | ||
| 1360 | return cwd().deleteFile(absolute_path); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | /// Same as `deleteFileAbsolute` except the parameter is null-terminated. | ||
| 1364 | pub fn deleteFileAbsoluteC(absolute_path_c: [*:0]const u8) DeleteFileError!void { | ||
| 1365 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1366 | return cwd().deleteFileC(absolute_path_c); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. | ||
| 1370 | pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void { | ||
| 1371 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1372 | return cwd().deleteFileW(absolute_path_w); | ||
| 1373 | } | ||
| 1374 | |||
| 1195 | pub const Walker = struct { | 1375 | pub const Walker = struct { |
| 1196 | stack: std.ArrayList(StackItem), | 1376 | stack: std.ArrayList(StackItem), |
| 1197 | name_buffer: std.Buffer, | 1377 | name_buffer: std.Buffer, |
| ... | @@ -1264,7 +1444,7 @@ pub const Walker = struct { | ... | @@ -1264,7 +1444,7 @@ pub const Walker = struct { |
| 1264 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | 1444 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1265 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); | 1445 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1266 | 1446 | ||
| 1267 | var dir = try Dir.cwd().openDirList(dir_path); | 1447 | var dir = try cwd().openDirList(dir_path); |
| 1268 | errdefer dir.close(); | 1448 | errdefer dir.close(); |
| 1269 | 1449 | ||
| 1270 | var name_buffer = try std.Buffer.init(allocator, dir_path); | 1450 | var name_buffer = try std.Buffer.init(allocator, dir_path); |
| ... | @@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE | ... | @@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE |
| 1298 | 1478 | ||
| 1299 | pub fn openSelfExe() OpenSelfExeError!File { | 1479 | pub fn openSelfExe() OpenSelfExeError!File { |
| 1300 | if (builtin.os == .linux) { | 1480 | if (builtin.os == .linux) { |
| 1301 | return File.openReadC("/proc/self/exe"); | 1481 | return openFileAbsoluteC("/proc/self/exe", .{}); |
| 1302 | } | 1482 | } |
| 1303 | if (builtin.os == .windows) { | 1483 | if (builtin.os == .windows) { |
| 1304 | const wide_slice = selfExePathW(); | 1484 | const wide_slice = selfExePathW(); |
| 1305 | const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); | 1485 | const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); |
| 1306 | return Dir.cwd().openReadW(&prefixed_path_w); | 1486 | return cwd().openReadW(&prefixed_path_w); |
| 1307 | } | 1487 | } |
| 1308 | var buf: [MAX_PATH_BYTES]u8 = undefined; | 1488 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1309 | const self_exe_path = try selfExePath(&buf); | 1489 | const self_exe_path = try selfExePath(&buf); |
| 1310 | buf[self_exe_path.len] = 0; | 1490 | buf[self_exe_path.len] = 0; |
| 1311 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 1491 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 1312 | return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr)); | 1492 | return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{}); |
| 1313 | } | 1493 | } |
| 1314 | 1494 | ||
| 1315 | test "openSelfExe" { | 1495 | test "openSelfExe" { |
lib/std/fs/file.zig+56-73| ... | @@ -25,105 +25,87 @@ pub const File = struct { | ... | @@ -25,105 +25,87 @@ pub const File = struct { |
| 25 | 25 | ||
| 26 | pub const OpenError = windows.CreateFileError || os.OpenError; | 26 | pub const OpenError = windows.CreateFileError || os.OpenError; |
| 27 | 27 | ||
| 28 | /// Deprecated; call `std.fs.Dir.openRead` directly. | 28 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| 29 | pub const OpenFlags = struct { | ||
| 30 | read: bool = true, | ||
| 31 | write: bool = false, | ||
| 32 | }; | ||
| 33 | |||
| 34 | /// TODO https://github.com/ziglang/zig/issues/3802 | ||
| 35 | pub const CreateFlags = struct { | ||
| 36 | /// Whether the file will be created with read access. | ||
| 37 | read: bool = false, | ||
| 38 | |||
| 39 | /// If the file already exists, and is a regular file, and the access | ||
| 40 | /// mode allows writing, it will be truncated to length 0. | ||
| 41 | truncate: bool = true, | ||
| 42 | |||
| 43 | /// Ensures that this open call creates the file, otherwise causes | ||
| 44 | /// `error.FileAlreadyExists` to be returned. | ||
| 45 | exclusive: bool = false, | ||
| 46 | |||
| 47 | /// For POSIX systems this is the file system mode the file will | ||
| 48 | /// be created with. | ||
| 49 | mode: Mode = default_mode, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /// Deprecated; call `std.fs.Dir.openFile` directly. | ||
| 29 | pub fn openRead(path: []const u8) OpenError!File { | 53 | pub fn openRead(path: []const u8) OpenError!File { |
| 30 | return std.fs.Dir.cwd().openRead(path); | 54 | return std.fs.cwd().openFile(path, .{}); |
| 31 | } | 55 | } |
| 32 | 56 | ||
| 33 | /// Deprecated; call `std.fs.Dir.openReadC` directly. | 57 | /// Deprecated; call `std.fs.Dir.openFileC` directly. |
| 34 | pub fn openReadC(path_c: [*:0]const u8) OpenError!File { | 58 | pub fn openReadC(path_c: [*:0]const u8) OpenError!File { |
| 35 | return std.fs.Dir.cwd().openReadC(path_c); | 59 | return std.fs.cwd().openFileC(path_c, .{}); |
| 36 | } | 60 | } |
| 37 | 61 | ||
| 38 | /// Deprecated; call `std.fs.Dir.openReadW` directly. | 62 | /// Deprecated; call `std.fs.Dir.openFileW` directly. |
| 39 | pub fn openReadW(path_w: [*]const u16) OpenError!File { | 63 | pub fn openReadW(path_w: [*]const u16) OpenError!File { |
| 40 | return std.fs.Dir.cwd().openReadW(path_w); | 64 | return std.fs.cwd().openFileW(path_w, .{}); |
| 41 | } | 65 | } |
| 42 | 66 | ||
| 43 | /// Calls `openWriteMode` with `default_mode` for the mode. | 67 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 44 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 45 | pub fn openWrite(path: []const u8) OpenError!File { | 68 | pub fn openWrite(path: []const u8) OpenError!File { |
| 46 | return openWriteMode(path, default_mode); | 69 | return std.fs.cwd().createFile(path, .{}); |
| 47 | } | 70 | } |
| 48 | 71 | ||
| 49 | /// If the path does not exist it will be created. | 72 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 50 | /// If a file already exists in the destination it will be truncated. | ||
| 51 | /// Call close to clean up. | ||
| 52 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 53 | pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { | 73 | pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { |
| 54 | if (builtin.os == .windows) { | 74 | return std.fs.cwd().createFile(path, .{ .mode = file_mode }); |
| 55 | const path_w = try windows.sliceToPrefixedFileW(path); | ||
| 56 | return openWriteModeW(&path_w, file_mode); | ||
| 57 | } | ||
| 58 | const path_c = try os.toPosixPath(path); | ||
| 59 | return openWriteModeC(&path_c, file_mode); | ||
| 60 | } | 75 | } |
| 61 | 76 | ||
| 62 | /// Same as `openWriteMode` except `path` is null-terminated. | 77 | /// Deprecated; call `std.fs.Dir.createFileC` directly. |
| 63 | /// TODO: deprecate this and move it to `std.fs.Dir`. | 78 | pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { |
| 64 | pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File { | 79 | return std.fs.cwd().createFileC(path_c, .{ .mode = file_mode }); |
| 65 | if (builtin.os == .windows) { | ||
| 66 | const path_w = try windows.cStrToPrefixedFileW(path); | ||
| 67 | return openWriteModeW(&path_w, file_mode); | ||
| 68 | } | ||
| 69 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | ||
| 70 | const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC; | ||
| 71 | const fd = try os.openC(path, flags, file_mode); | ||
| 72 | return openHandle(fd); | ||
| 73 | } | 80 | } |
| 74 | 81 | ||
| 75 | /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded | 82 | /// Deprecated; call `std.fs.Dir.createFileW` directly. |
| 76 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 77 | pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { | 83 | pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 78 | const handle = try windows.CreateFileW( | 84 | return std.fs.cwd().createFileW(path_w, .{ .mode = file_mode }); |
| 79 | path_w, | ||
| 80 | windows.GENERIC_WRITE, | ||
| 81 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | ||
| 82 | null, | ||
| 83 | windows.CREATE_ALWAYS, | ||
| 84 | windows.FILE_ATTRIBUTE_NORMAL, | ||
| 85 | null, | ||
| 86 | ); | ||
| 87 | return openHandle(handle); | ||
| 88 | } | 85 | } |
| 89 | 86 | ||
| 90 | /// If the path does not exist it will be created. | 87 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 91 | /// If a file already exists in the destination this returns OpenError.PathAlreadyExists | ||
| 92 | /// Call close to clean up. | ||
| 93 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 94 | pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { | 88 | pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { |
| 95 | if (builtin.os == .windows) { | 89 | return std.fs.cwd().createFile(path, .{ |
| 96 | const path_w = try windows.sliceToPrefixedFileW(path); | 90 | .mode = file_mode, |
| 97 | return openWriteNoClobberW(&path_w, file_mode); | 91 | .exclusive = true, |
| 98 | } | 92 | }); |
| 99 | const path_c = try os.toPosixPath(path); | ||
| 100 | return openWriteNoClobberC(&path_c, file_mode); | ||
| 101 | } | 93 | } |
| 102 | 94 | ||
| 103 | /// TODO: deprecate this and move it to `std.fs.Dir`. | 95 | /// Deprecated; call `std.fs.Dir.createFileC` directly. |
| 104 | pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File { | 96 | pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { |
| 105 | if (builtin.os == .windows) { | 97 | return std.fs.cwd().createFileC(path_c, .{ |
| 106 | const path_w = try windows.cStrToPrefixedFileW(path); | 98 | .mode = file_mode, |
| 107 | return openWriteNoClobberW(&path_w, file_mode); | 99 | .exclusive = true, |
| 108 | } | 100 | }); |
| 109 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | ||
| 110 | const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL; | ||
| 111 | const fd = try os.openC(path, flags, file_mode); | ||
| 112 | return openHandle(fd); | ||
| 113 | } | 101 | } |
| 114 | 102 | ||
| 115 | /// TODO: deprecate this and move it to `std.fs.Dir`. | 103 | /// Deprecated; call `std.fs.Dir.createFileW` directly. |
| 116 | pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { | 104 | pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 117 | const handle = try windows.CreateFileW( | 105 | return std.fs.cwd().createFileW(path_w, .{ |
| 118 | path_w, | 106 | .mode = file_mode, |
| 119 | windows.GENERIC_WRITE, | 107 | .exclusive = true, |
| 120 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | 108 | }); |
| 121 | null, | ||
| 122 | windows.CREATE_NEW, | ||
| 123 | windows.FILE_ATTRIBUTE_NORMAL, | ||
| 124 | null, | ||
| 125 | ); | ||
| 126 | return openHandle(handle); | ||
| 127 | } | 109 | } |
| 128 | 110 | ||
| 129 | pub fn openHandle(handle: os.fd_t) File { | 111 | pub fn openHandle(handle: os.fd_t) File { |
| ... | @@ -246,6 +228,7 @@ pub const File = struct { | ... | @@ -246,6 +228,7 @@ pub const File = struct { |
| 246 | windows.STATUS.SUCCESS => {}, | 228 | windows.STATUS.SUCCESS => {}, |
| 247 | windows.STATUS.BUFFER_OVERFLOW => {}, | 229 | windows.STATUS.BUFFER_OVERFLOW => {}, |
| 248 | windows.STATUS.INVALID_PARAMETER => unreachable, | 230 | windows.STATUS.INVALID_PARAMETER => unreachable, |
| 231 | windows.STATUS.ACCESS_DENIED => return error.AccessDenied, | ||
| 249 | else => return windows.unexpectedStatus(rc), | 232 | else => return windows.unexpectedStatus(rc), |
| 250 | } | 233 | } |
| 251 | return Stat{ | 234 | return Stat{ |
lib/std/fs/path.zig+32-1| ... | @@ -130,6 +130,14 @@ test "join" { | ... | @@ -130,6 +130,14 @@ test "join" { |
| 130 | testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c"); | 130 | testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c"); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | pub fn isAbsoluteC(path_c: [*:0]const u8) bool { | ||
| 134 | if (builtin.os == .windows) { | ||
| 135 | return isAbsoluteWindowsC(path_c); | ||
| 136 | } else { | ||
| 137 | return isAbsolutePosixC(path_c); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 133 | pub fn isAbsolute(path: []const u8) bool { | 141 | pub fn isAbsolute(path: []const u8) bool { |
| 134 | if (builtin.os == .windows) { | 142 | if (builtin.os == .windows) { |
| 135 | return isAbsoluteWindows(path); | 143 | return isAbsoluteWindows(path); |
| ... | @@ -138,7 +146,7 @@ pub fn isAbsolute(path: []const u8) bool { | ... | @@ -138,7 +146,7 @@ pub fn isAbsolute(path: []const u8) bool { |
| 138 | } | 146 | } |
| 139 | } | 147 | } |
| 140 | 148 | ||
| 141 | pub fn isAbsoluteW(path_w: [*]const u16) bool { | 149 | pub fn isAbsoluteW(path_w: [*:0]const u16) bool { |
| 142 | if (path_w[0] == '/') | 150 | if (path_w[0] == '/') |
| 143 | return true; | 151 | return true; |
| 144 | 152 | ||
| ... | @@ -176,10 +184,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool { | ... | @@ -176,10 +184,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool { |
| 176 | return false; | 184 | return false; |
| 177 | } | 185 | } |
| 178 | 186 | ||
| 187 | pub fn isAbsoluteWindowsC(path_c: [*:0]const u8) bool { | ||
| 188 | if (path_c[0] == '/') | ||
| 189 | return true; | ||
| 190 | |||
| 191 | if (path_c[0] == '\\') { | ||
| 192 | return true; | ||
| 193 | } | ||
| 194 | if (path_c[0] == 0 or path_c[1] == 0 or path_c[2] == 0) { | ||
| 195 | return false; | ||
| 196 | } | ||
| 197 | if (path_c[1] == ':') { | ||
| 198 | if (path_c[2] == '/') | ||
| 199 | return true; | ||
| 200 | if (path_c[2] == '\\') | ||
| 201 | return true; | ||
| 202 | } | ||
| 203 | return false; | ||
| 204 | } | ||
| 205 | |||
| 179 | pub fn isAbsolutePosix(path: []const u8) bool { | 206 | pub fn isAbsolutePosix(path: []const u8) bool { |
| 180 | return path[0] == sep_posix; | 207 | return path[0] == sep_posix; |
| 181 | } | 208 | } |
| 182 | 209 | ||
| 210 | pub fn isAbsolutePosixC(path_c: [*:0]const u8) bool { | ||
| 211 | return path_c[0] == sep_posix; | ||
| 212 | } | ||
| 213 | |||
| 183 | test "isAbsoluteWindows" { | 214 | test "isAbsoluteWindows" { |
| 184 | testIsAbsoluteWindows("/", true); | 215 | testIsAbsoluteWindows("/", true); |
| 185 | testIsAbsoluteWindows("//", true); | 216 | testIsAbsoluteWindows("//", true); |
lib/std/io.zig+4-7| ... | @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream; | ... | @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream; |
| 61 | pub const InStream = @import("io/in_stream.zig").InStream; | 61 | pub const InStream = @import("io/in_stream.zig").InStream; |
| 62 | pub const OutStream = @import("io/out_stream.zig").OutStream; | 62 | pub const OutStream = @import("io/out_stream.zig").OutStream; |
| 63 | 63 | ||
| 64 | /// TODO move this to `std.fs` and add a version to `std.fs.Dir`. | 64 | /// Deprecated; use `std.fs.Dir.writeFile`. |
| 65 | pub fn writeFile(path: []const u8, data: []const u8) !void { | 65 | pub fn writeFile(path: []const u8, data: []const u8) !void { |
| 66 | var file = try File.openWrite(path); | 66 | return fs.cwd().writeFile(path, data); |
| 67 | defer file.close(); | ||
| 68 | try file.write(data); | ||
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | /// On success, caller owns returned buffer. | 69 | /// Deprecated; use `std.fs.Dir.readFileAlloc`. |
| 72 | /// This function is deprecated; use `std.fs.Dir.readFileAlloc`. | ||
| 73 | pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 { | 70 | pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 { |
| 74 | return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize)); | 71 | return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize)); |
| 75 | } | 72 | } |
| 76 | 73 | ||
| 77 | pub fn BufferedInStream(comptime Error: type) type { | 74 | pub fn BufferedInStream(comptime Error: type) type { |
lib/std/io/test.zig+15-13| ... | @@ -14,12 +14,14 @@ test "write a file, read it, then delete it" { | ... | @@ -14,12 +14,14 @@ test "write a file, read it, then delete it" { |
| 14 | var raw_bytes: [200 * 1024]u8 = undefined; | 14 | var raw_bytes: [200 * 1024]u8 = undefined; |
| 15 | var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator; | 15 | var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator; |
| 16 | 16 | ||
| 17 | const cwd = fs.cwd(); | ||
| 18 | |||
| 17 | var data: [1024]u8 = undefined; | 19 | var data: [1024]u8 = undefined; |
| 18 | var prng = DefaultPrng.init(1234); | 20 | var prng = DefaultPrng.init(1234); |
| 19 | prng.random.bytes(data[0..]); | 21 | prng.random.bytes(data[0..]); |
| 20 | const tmp_file_name = "temp_test_file.txt"; | 22 | const tmp_file_name = "temp_test_file.txt"; |
| 21 | { | 23 | { |
| 22 | var file = try File.openWrite(tmp_file_name); | 24 | var file = try cwd.createFile(tmp_file_name, .{}); |
| 23 | defer file.close(); | 25 | defer file.close(); |
| 24 | 26 | ||
| 25 | var file_out_stream = file.outStream(); | 27 | var file_out_stream = file.outStream(); |
| ... | @@ -32,8 +34,8 @@ test "write a file, read it, then delete it" { | ... | @@ -32,8 +34,8 @@ test "write a file, read it, then delete it" { |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | { | 36 | { |
| 35 | // make sure openWriteNoClobber doesn't harm the file | 37 | // Make sure the exclusive flag is honored. |
| 36 | if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| { | 38 | if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| { |
| 37 | unreachable; | 39 | unreachable; |
| 38 | } else |err| { | 40 | } else |err| { |
| 39 | std.debug.assert(err == File.OpenError.PathAlreadyExists); | 41 | std.debug.assert(err == File.OpenError.PathAlreadyExists); |
| ... | @@ -41,7 +43,7 @@ test "write a file, read it, then delete it" { | ... | @@ -41,7 +43,7 @@ test "write a file, read it, then delete it" { |
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | { | 45 | { |
| 44 | var file = try File.openRead(tmp_file_name); | 46 | var file = try cwd.openFile(tmp_file_name, .{}); |
| 45 | defer file.close(); | 47 | defer file.close(); |
| 46 | 48 | ||
| 47 | const file_size = try file.getEndPos(); | 49 | const file_size = try file.getEndPos(); |
| ... | @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" { | ... | @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" { |
| 58 | expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data)); | 60 | expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data)); |
| 59 | expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); | 61 | expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); |
| 60 | } | 62 | } |
| 61 | try fs.deleteFile(tmp_file_name); | 63 | try cwd.deleteFile(tmp_file_name); |
| 62 | } | 64 | } |
| 63 | 65 | ||
| 64 | test "BufferOutStream" { | 66 | test "BufferOutStream" { |
| ... | @@ -274,7 +276,7 @@ test "BitOutStream" { | ... | @@ -274,7 +276,7 @@ test "BitOutStream" { |
| 274 | test "BitStreams with File Stream" { | 276 | test "BitStreams with File Stream" { |
| 275 | const tmp_file_name = "temp_test_file.txt"; | 277 | const tmp_file_name = "temp_test_file.txt"; |
| 276 | { | 278 | { |
| 277 | var file = try File.openWrite(tmp_file_name); | 279 | var file = try fs.cwd().createFile(tmp_file_name, .{}); |
| 278 | defer file.close(); | 280 | defer file.close(); |
| 279 | 281 | ||
| 280 | var file_out = file.outStream(); | 282 | var file_out = file.outStream(); |
| ... | @@ -291,7 +293,7 @@ test "BitStreams with File Stream" { | ... | @@ -291,7 +293,7 @@ test "BitStreams with File Stream" { |
| 291 | try bit_stream.flushBits(); | 293 | try bit_stream.flushBits(); |
| 292 | } | 294 | } |
| 293 | { | 295 | { |
| 294 | var file = try File.openRead(tmp_file_name); | 296 | var file = try fs.cwd().openFile(tmp_file_name, .{}); |
| 295 | defer file.close(); | 297 | defer file.close(); |
| 296 | 298 | ||
| 297 | var file_in = file.inStream(); | 299 | var file_in = file.inStream(); |
| ... | @@ -316,7 +318,7 @@ test "BitStreams with File Stream" { | ... | @@ -316,7 +318,7 @@ test "BitStreams with File Stream" { |
| 316 | 318 | ||
| 317 | expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); | 319 | expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); |
| 318 | } | 320 | } |
| 319 | try fs.deleteFile(tmp_file_name); | 321 | try fs.cwd().deleteFile(tmp_file_name); |
| 320 | } | 322 | } |
| 321 | 323 | ||
| 322 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { | 324 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { |
| ... | @@ -599,7 +601,7 @@ test "c out stream" { | ... | @@ -599,7 +601,7 @@ test "c out stream" { |
| 599 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | 601 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; |
| 600 | defer { | 602 | defer { |
| 601 | _ = std.c.fclose(out_file); | 603 | _ = std.c.fclose(out_file); |
| 602 | fs.deleteFileC(filename) catch {}; | 604 | fs.cwd().deleteFileC(filename) catch {}; |
| 603 | } | 605 | } |
| 604 | 606 | ||
| 605 | const out_stream = &io.COutStream.init(out_file).stream; | 607 | const out_stream = &io.COutStream.init(out_file).stream; |
| ... | @@ -608,10 +610,10 @@ test "c out stream" { | ... | @@ -608,10 +610,10 @@ test "c out stream" { |
| 608 | 610 | ||
| 609 | test "File seek ops" { | 611 | test "File seek ops" { |
| 610 | const tmp_file_name = "temp_test_file.txt"; | 612 | const tmp_file_name = "temp_test_file.txt"; |
| 611 | var file = try File.openWrite(tmp_file_name); | 613 | var file = try fs.cwd().createFile(tmp_file_name, .{}); |
| 612 | defer { | 614 | defer { |
| 613 | file.close(); | 615 | file.close(); |
| 614 | fs.deleteFile(tmp_file_name) catch {}; | 616 | fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 615 | } | 617 | } |
| 616 | 618 | ||
| 617 | try file.write(&([_]u8{0x55} ** 8192)); | 619 | try file.write(&([_]u8{0x55} ** 8192)); |
| ... | @@ -632,10 +634,10 @@ test "File seek ops" { | ... | @@ -632,10 +634,10 @@ test "File seek ops" { |
| 632 | 634 | ||
| 633 | test "updateTimes" { | 635 | test "updateTimes" { |
| 634 | const tmp_file_name = "just_a_temporary_file.txt"; | 636 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 635 | var file = try File.openWrite(tmp_file_name); | 637 | var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true }); |
| 636 | defer { | 638 | defer { |
| 637 | file.close(); | 639 | file.close(); |
| 638 | std.fs.deleteFile(tmp_file_name) catch {}; | 640 | std.fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 639 | } | 641 | } |
| 640 | var stat_old = try file.stat(); | 642 | var stat_old = try file.stat(); |
| 641 | // Set atime and mtime to 5s before | 643 | // Set atime and mtime to 5s before |
lib/std/math.zig-12| ... | @@ -25,18 +25,6 @@ pub const ln2 = 0.693147180559945309417232121458176568; | ... | @@ -25,18 +25,6 @@ pub const ln2 = 0.693147180559945309417232121458176568; |
| 25 | /// ln(10) | 25 | /// ln(10) |
| 26 | pub const ln10 = 2.302585092994045684017991454684364208; | 26 | pub const ln10 = 2.302585092994045684017991454684364208; |
| 27 | 27 | ||
| 28 | /// π/2 | ||
| 29 | pub const pi_2 = 1.570796326794896619231321691639751442; | ||
| 30 | |||
| 31 | /// π/4 | ||
| 32 | pub const pi_4 = 0.785398163397448309615660845819875721; | ||
| 33 | |||
| 34 | /// 1/π | ||
| 35 | pub const one_pi = 0.318309886183790671537767526745028724; | ||
| 36 | |||
| 37 | /// 2/π | ||
| 38 | pub const two_pi = 0.636619772367581343075535053490057448; | ||
| 39 | |||
| 40 | /// 2/sqrt(π) | 28 | /// 2/sqrt(π) |
| 41 | pub const two_sqrtpi = 1.128379167095512573896158903121545172; | 29 | pub const two_sqrtpi = 1.128379167095512573896158903121545172; |
| 42 | 30 |
lib/std/mutex.zig+85-47| ... | @@ -1,13 +1,12 @@ | ... | @@ -1,13 +1,12 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const SpinLock = std.SpinLock; | 4 | const ResetEvent = std.ResetEvent; |
| 5 | const ThreadParker = std.ThreadParker; | ||
| 6 | 5 | ||
| 7 | /// Lock may be held only once. If the same thread | 6 | /// Lock may be held only once. If the same thread |
| 8 | /// tries to acquire the same mutex twice, it deadlocks. | 7 | /// tries to acquire the same mutex twice, it deadlocks. |
| 9 | /// This type supports static initialization and is based off of Golang 1.13 runtime.lock_futex: | 8 | /// This type supports static initialization and is based off of Webkit's WTF Lock (via rust parking_lot) |
| 10 | /// https://github.com/golang/go/blob/master/src/runtime/lock_futex.go | 9 | /// https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs |
| 11 | /// When an application is built in single threaded release mode, all the functions are | 10 | /// When an application is built in single threaded release mode, all the functions are |
| 12 | /// no-ops. In single threaded debug mode, there is deadlock detection. | 11 | /// no-ops. In single threaded debug mode, there is deadlock detection. |
| 13 | pub const Mutex = if (builtin.single_threaded) | 12 | pub const Mutex = if (builtin.single_threaded) |
| ... | @@ -39,80 +38,119 @@ pub const Mutex = if (builtin.single_threaded) | ... | @@ -39,80 +38,119 @@ pub const Mutex = if (builtin.single_threaded) |
| 39 | } | 38 | } |
| 40 | else | 39 | else |
| 41 | struct { | 40 | struct { |
| 42 | state: State, // TODO: make this an enum | 41 | state: usize, |
| 43 | parker: ThreadParker, | ||
| 44 | 42 | ||
| 45 | const State = enum(u32) { | 43 | const MUTEX_LOCK: usize = 1 << 0; |
| 46 | Unlocked, | 44 | const QUEUE_LOCK: usize = 1 << 1; |
| 47 | Sleeping, | 45 | const QUEUE_MASK: usize = ~(MUTEX_LOCK | QUEUE_LOCK); |
| 48 | Locked, | 46 | const QueueNode = std.atomic.Stack(ResetEvent).Node; |
| 49 | }; | ||
| 50 | 47 | ||
| 51 | /// number of iterations to spin yielding the cpu | 48 | /// number of iterations to spin yielding the cpu |
| 52 | const SPIN_CPU = 4; | 49 | const SPIN_CPU = 4; |
| 53 | 50 | ||
| 54 | /// number of iterations to perform in the cpu yield loop | 51 | /// number of iterations to spin in the cpu yield loop |
| 55 | const SPIN_CPU_COUNT = 30; | 52 | const SPIN_CPU_COUNT = 30; |
| 56 | 53 | ||
| 57 | /// number of iterations to spin yielding the thread | 54 | /// number of iterations to spin yielding the thread |
| 58 | const SPIN_THREAD = 1; | 55 | const SPIN_THREAD = 1; |
| 59 | 56 | ||
| 60 | pub fn init() Mutex { | 57 | pub fn init() Mutex { |
| 61 | return Mutex{ | 58 | return Mutex{ .state = 0 }; |
| 62 | .state = .Unlocked, | ||
| 63 | .parker = ThreadParker.init(), | ||
| 64 | }; | ||
| 65 | } | 59 | } |
| 66 | 60 | ||
| 67 | pub fn deinit(self: *Mutex) void { | 61 | pub fn deinit(self: *Mutex) void { |
| 68 | self.parker.deinit(); | 62 | self.* = undefined; |
| 69 | } | 63 | } |
| 70 | 64 | ||
| 71 | pub const Held = struct { | 65 | pub const Held = struct { |
| 72 | mutex: *Mutex, | 66 | mutex: *Mutex, |
| 73 | 67 | ||
| 74 | pub fn release(self: Held) void { | 68 | pub fn release(self: Held) void { |
| 75 | switch (@atomicRmw(State, &self.mutex.state, .Xchg, .Unlocked, .Release)) { | 69 | // since MUTEX_LOCK is the first bit, we can use (.Sub) instead of (.And, ~MUTEX_LOCK). |
| 76 | .Locked => {}, | 70 | // this is because .Sub may be implemented more efficiently than the latter |
| 77 | .Sleeping => self.mutex.parker.unpark(@ptrCast(*const u32, &self.mutex.state)), | 71 | // (e.g. `lock xadd` vs `cmpxchg` loop on x86) |
| 78 | .Unlocked => unreachable, // unlocking an unlocked mutex | 72 | const state = @atomicRmw(usize, &self.mutex.state, .Sub, MUTEX_LOCK, .Release); |
| 79 | else => unreachable, // should never be anything else | 73 | if ((state & QUEUE_MASK) != 0 and (state & QUEUE_LOCK) == 0) { |
| 74 | self.mutex.releaseSlow(state); | ||
| 80 | } | 75 | } |
| 81 | } | 76 | } |
| 82 | }; | 77 | }; |
| 83 | 78 | ||
| 84 | pub fn acquire(self: *Mutex) Held { | 79 | pub fn acquire(self: *Mutex) Held { |
| 85 | // Try and speculatively grab the lock. | 80 | // fast path close to SpinLock fast path |
| 86 | // If it fails, the state is either Locked or Sleeping | 81 | if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic)) |current_state| { |
| 87 | // depending on if theres a thread stuck sleeping below. | 82 | self.acquireSlow(current_state); |
| 88 | var state = @atomicRmw(State, &self.state, .Xchg, .Locked, .Acquire); | 83 | } |
| 89 | if (state == .Unlocked) | 84 | return Held{ .mutex = self }; |
| 90 | return Held{ .mutex = self }; | 85 | } |
| 91 | 86 | ||
| 87 | fn acquireSlow(self: *Mutex, current_state: usize) void { | ||
| 88 | var spin: usize = 0; | ||
| 89 | var state = current_state; | ||
| 92 | while (true) { | 90 | while (true) { |
| 93 | // try and acquire the lock using cpu spinning on failure | 91 | |
| 94 | var spin: usize = 0; | 92 | // try and acquire the lock if unlocked |
| 95 | while (spin < SPIN_CPU) : (spin += 1) { | 93 | if ((state & MUTEX_LOCK) == 0) { |
| 96 | var value = @atomicLoad(State, &self.state, .Monotonic); | 94 | state = @cmpxchgWeak(usize, &self.state, state, state | MUTEX_LOCK, .Acquire, .Monotonic) orelse return; |
| 97 | while (value == .Unlocked) | 95 | continue; |
| 98 | value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self }; | 96 | } |
| 99 | SpinLock.yield(SPIN_CPU_COUNT); | 97 | |
| 98 | // spin only if the waiting queue isn't empty and when it hasn't spun too much already | ||
| 99 | if ((state & QUEUE_MASK) == 0 and spin < SPIN_CPU + SPIN_THREAD) { | ||
| 100 | if (spin < SPIN_CPU) { | ||
| 101 | std.SpinLock.yield(SPIN_CPU_COUNT); | ||
| 102 | } else { | ||
| 103 | std.os.sched_yield() catch std.time.sleep(0); | ||
| 104 | } | ||
| 105 | state = @atomicLoad(usize, &self.state, .Monotonic); | ||
| 106 | continue; | ||
| 100 | } | 107 | } |
| 101 | 108 | ||
| 102 | // try and acquire the lock using thread rescheduling on failure | 109 | // thread should block, try and add this event to the waiting queue |
| 103 | spin = 0; | 110 | var node = QueueNode{ |
| 104 | while (spin < SPIN_THREAD) : (spin += 1) { | 111 | .next = @intToPtr(?*QueueNode, state & QUEUE_MASK), |
| 105 | var value = @atomicLoad(State, &self.state, .Monotonic); | 112 | .data = ResetEvent.init(), |
| 106 | while (value == .Unlocked) | 113 | }; |
| 107 | value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self }; | 114 | defer node.data.deinit(); |
| 108 | std.os.sched_yield() catch std.time.sleep(1); | 115 | const new_state = @ptrToInt(&node) | (state & ~QUEUE_MASK); |
| 116 | state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse { | ||
| 117 | // node is in the queue, wait until a `held.release()` wakes us up. | ||
| 118 | _ = node.data.wait(null) catch unreachable; | ||
| 119 | spin = 0; | ||
| 120 | state = @atomicLoad(usize, &self.state, .Monotonic); | ||
| 121 | continue; | ||
| 122 | }; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | fn releaseSlow(self: *Mutex, current_state: usize) void { | ||
| 127 | // grab the QUEUE_LOCK in order to signal a waiting queue node's event. | ||
| 128 | var state = current_state; | ||
| 129 | while (true) { | ||
| 130 | if ((state & QUEUE_LOCK) != 0 or (state & QUEUE_MASK) == 0) | ||
| 131 | return; | ||
| 132 | state = @cmpxchgWeak(usize, &self.state, state, state | QUEUE_LOCK, .Acquire, .Monotonic) orelse break; | ||
| 133 | } | ||
| 134 | |||
| 135 | while (true) { | ||
| 136 | // barrier needed to observe incoming state changes | ||
| 137 | defer @fence(.Acquire); | ||
| 138 | |||
| 139 | // the mutex is currently locked. try to unset the QUEUE_LOCK and let the locker wake up the next node. | ||
| 140 | // avoids waking up multiple sleeping threads which try to acquire the lock again which increases contention. | ||
| 141 | if ((state & MUTEX_LOCK) != 0) { | ||
| 142 | state = @cmpxchgWeak(usize, &self.state, state, state & ~QUEUE_LOCK, .Release, .Monotonic) orelse return; | ||
| 143 | continue; | ||
| 109 | } | 144 | } |
| 110 | 145 | ||
| 111 | // failed to acquire the lock, go to sleep until woken up by `Held.release()` | 146 | // try to pop the top node on the waiting queue stack to wake it up |
| 112 | if (@atomicRmw(State, &self.state, .Xchg, .Sleeping, .Acquire) == .Unlocked) | 147 | // while at the same time unsetting the QUEUE_LOCK. |
| 113 | return Held{ .mutex = self }; | 148 | const node = @intToPtr(*QueueNode, state & QUEUE_MASK); |
| 114 | state = .Sleeping; | 149 | const new_state = @ptrToInt(node.next) | (state & MUTEX_LOCK); |
| 115 | self.parker.park(@ptrCast(*const u32, &self.state), @enumToInt(State.Sleeping)); | 150 | state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse { |
| 151 | _ = node.data.set(false); | ||
| 152 | return; | ||
| 153 | }; | ||
| 116 | } | 154 | } |
| 117 | } | 155 | } |
| 118 | }; | 156 | }; |
lib/std/net.zig+2-2| ... | @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( | ... | @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( |
| 812 | family: os.sa_family_t, | 812 | family: os.sa_family_t, |
| 813 | port: u16, | 813 | port: u16, |
| 814 | ) !void { | 814 | ) !void { |
| 815 | const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) { | 815 | const file = fs.openFileAbsoluteC("/etc/hosts", .{}) catch |err| switch (err) { |
| 816 | error.FileNotFound, | 816 | error.FileNotFound, |
| 817 | error.NotDir, | 817 | error.NotDir, |
| 818 | error.AccessDenied, | 818 | error.AccessDenied, |
| ... | @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { | ... | @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1006 | }; | 1006 | }; |
| 1007 | errdefer rc.deinit(); | 1007 | errdefer rc.deinit(); |
| 1008 | 1008 | ||
| 1009 | const file = fs.File.openReadC("/etc/resolv.conf") catch |err| switch (err) { | 1009 | const file = fs.openFileAbsoluteC("/etc/resolv.conf", .{}) catch |err| switch (err) { |
| 1010 | error.FileNotFound, | 1010 | error.FileNotFound, |
| 1011 | error.NotDir, | 1011 | error.NotDir, |
| 1012 | error.AccessDenied, | 1012 | error.AccessDenied, |
lib/std/os.zig+13-6| ... | @@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e | ... | @@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 798 | path_buf[search_path.len] = '/'; | 798 | path_buf[search_path.len] = '/'; |
| 799 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); | 799 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); |
| 800 | path_buf[search_path.len + file_slice.len + 1] = 0; | 800 | path_buf[search_path.len + file_slice.len + 1] = 0; |
| 801 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 801 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 802 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); | 802 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); |
| 803 | switch (err) { | 803 | switch (err) { |
| 804 | error.AccessDenied => seen_eacces = true, | 804 | error.AccessDenied => seen_eacces = true, |
| ... | @@ -834,7 +834,7 @@ pub fn execvpe( | ... | @@ -834,7 +834,7 @@ pub fn execvpe( |
| 834 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); | 834 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); |
| 835 | arg_buf[arg.len] = 0; | 835 | arg_buf[arg.len] = 0; |
| 836 | 836 | ||
| 837 | // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731 | 837 | // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 838 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); | 838 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); |
| 839 | } | 839 | } |
| 840 | argv_buf[argv_slice.len] = null; | 840 | argv_buf[argv_slice.len] = null; |
| ... | @@ -842,7 +842,7 @@ pub fn execvpe( | ... | @@ -842,7 +842,7 @@ pub fn execvpe( |
| 842 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); | 842 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); |
| 843 | defer freeNullDelimitedEnvMap(allocator, envp_buf); | 843 | defer freeNullDelimitedEnvMap(allocator, envp_buf); |
| 844 | 844 | ||
| 845 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 845 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 846 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); | 846 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); |
| 847 | 847 | ||
| 848 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); | 848 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); |
| ... | @@ -863,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. | ... | @@ -863,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 863 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); | 863 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); |
| 864 | env_buf[env_buf.len - 1] = 0; | 864 | env_buf[env_buf.len - 1] = 0; |
| 865 | 865 | ||
| 866 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 866 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 867 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); | 867 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); |
| 868 | } | 868 | } |
| 869 | assert(i == envp_count); | 869 | assert(i == envp_count); |
| 870 | } | 870 | } |
| 871 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 871 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 872 | assert(envp_buf[envp_count] == null); | 872 | assert(envp_buf[envp_count] == null); |
| 873 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; | 873 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; |
| 874 | } | 874 | } |
| ... | @@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{ | ... | @@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{ |
| 1087 | }; | 1087 | }; |
| 1088 | 1088 | ||
| 1089 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 1089 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 1090 | /// Asserts that the path parameter has no null bytes. | ||
| 1090 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { | 1091 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { |
| 1092 | if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0); | ||
| 1091 | if (builtin.os == .windows) { | 1093 | if (builtin.os == .windows) { |
| 1092 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 1094 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); |
| 1093 | return unlinkatW(dirfd, &file_path_w, flags); | 1095 | return unlinkatW(dirfd, &file_path_w, flags); |
| ... | @@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 { | ... | @@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 { |
| 2026 | } | 2028 | } |
| 2027 | } | 2029 | } |
| 2028 | 2030 | ||
| 2029 | pub const FStatError = error{SystemResources} || UnexpectedError; | 2031 | pub const FStatError = error{ |
| 2032 | SystemResources, | ||
| 2033 | AccessDenied, | ||
| 2034 | } || UnexpectedError; | ||
| 2030 | 2035 | ||
| 2031 | pub fn fstat(fd: fd_t) FStatError!Stat { | 2036 | pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2032 | var stat: Stat = undefined; | 2037 | var stat: Stat = undefined; |
| ... | @@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { | ... | @@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2036 | EINVAL => unreachable, | 2041 | EINVAL => unreachable, |
| 2037 | EBADF => unreachable, // Always a race condition. | 2042 | EBADF => unreachable, // Always a race condition. |
| 2038 | ENOMEM => return error.SystemResources, | 2043 | ENOMEM => return error.SystemResources, |
| 2044 | EACCES => return error.AccessDenied, | ||
| 2039 | else => |err| return unexpectedErrno(err), | 2045 | else => |err| return unexpectedErrno(err), |
| 2040 | } | 2046 | } |
| 2041 | } | 2047 | } |
| ... | @@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { | ... | @@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2045 | EINVAL => unreachable, | 2051 | EINVAL => unreachable, |
| 2046 | EBADF => unreachable, // Always a race condition. | 2052 | EBADF => unreachable, // Always a race condition. |
| 2047 | ENOMEM => return error.SystemResources, | 2053 | ENOMEM => return error.SystemResources, |
| 2054 | EACCES => return error.AccessDenied, | ||
| 2048 | else => |err| return unexpectedErrno(err), | 2055 | else => |err| return unexpectedErrno(err), |
| 2049 | } | 2056 | } |
| 2050 | } | 2057 | } |
lib/std/os/bits/linux.zig+1| ... | @@ -9,6 +9,7 @@ pub usingnamespace switch (builtin.arch) { | ... | @@ -9,6 +9,7 @@ pub usingnamespace switch (builtin.arch) { |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | pub usingnamespace switch (builtin.arch) { | 11 | pub usingnamespace switch (builtin.arch) { |
| 12 | .i386 => @import("linux/i386.zig"), | ||
| 12 | .x86_64 => @import("linux/x86_64.zig"), | 13 | .x86_64 => @import("linux/x86_64.zig"), |
| 13 | .aarch64 => @import("linux/arm64.zig"), | 14 | .aarch64 => @import("linux/arm64.zig"), |
| 14 | .arm => @import("linux/arm-eabi.zig"), | 15 | .arm => @import("linux/arm-eabi.zig"), |
lib/std/os/bits/linux/arm-eabi.zig-1| ... | @@ -466,7 +466,6 @@ pub const MAP_LOCKED = 0x2000; | ... | @@ -466,7 +466,6 @@ pub const MAP_LOCKED = 0x2000; |
| 466 | /// don't check for reservations | 466 | /// don't check for reservations |
| 467 | pub const MAP_NORESERVE = 0x4000; | 467 | pub const MAP_NORESERVE = 0x4000; |
| 468 | 468 | ||
| 469 | pub const VDSO_USEFUL = true; | ||
| 470 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; | 469 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; |
| 471 | pub const VDSO_CGT_VER = "LINUX_2.6"; | 470 | pub const VDSO_CGT_VER = "LINUX_2.6"; |
| 472 | 471 |
lib/std/os/bits/linux/arm64.zig-1| ... | @@ -358,7 +358,6 @@ pub const MAP_LOCKED = 0x2000; | ... | @@ -358,7 +358,6 @@ pub const MAP_LOCKED = 0x2000; |
| 358 | /// don't check for reservations | 358 | /// don't check for reservations |
| 359 | pub const MAP_NORESERVE = 0x4000; | 359 | pub const MAP_NORESERVE = 0x4000; |
| 360 | 360 | ||
| 361 | pub const VDSO_USEFUL = true; | ||
| 362 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; | 361 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; |
| 363 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; | 362 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; |
| 364 | 363 |
lib/std/os/bits/linux/i386.zig created+642| ... | @@ -0,0 +1,642 @@ | ||
| 1 | // i386-specific declarations that are intended to be imported into the POSIX namespace. | ||
| 2 | // This does include Linux-only APIs. | ||
| 3 | |||
| 4 | const std = @import("../../../std.zig"); | ||
| 5 | const linux = std.os.linux; | ||
| 6 | const socklen_t = linux.socklen_t; | ||
| 7 | const iovec = linux.iovec; | ||
| 8 | const iovec_const = linux.iovec_const; | ||
| 9 | const uid_t = linux.uid_t; | ||
| 10 | const gid_t = linux.gid_t; | ||
| 11 | const stack_t = linux.stack_t; | ||
| 12 | const sigset_t = linux.sigset_t; | ||
| 13 | |||
| 14 | pub const SYS_restart_syscall = 0; | ||
| 15 | pub const SYS_exit = 1; | ||
| 16 | pub const SYS_fork = 2; | ||
| 17 | pub const SYS_read = 3; | ||
| 18 | pub const SYS_write = 4; | ||
| 19 | pub const SYS_open = 5; | ||
| 20 | pub const SYS_close = 6; | ||
| 21 | pub const SYS_waitpid = 7; | ||
| 22 | pub const SYS_creat = 8; | ||
| 23 | pub const SYS_link = 9; | ||
| 24 | pub const SYS_unlink = 10; | ||
| 25 | pub const SYS_execve = 11; | ||
| 26 | pub const SYS_chdir = 12; | ||
| 27 | pub const SYS_time = 13; | ||
| 28 | pub const SYS_mknod = 14; | ||
| 29 | pub const SYS_chmod = 15; | ||
| 30 | pub const SYS_lchown = 16; | ||
| 31 | pub const SYS_break = 17; | ||
| 32 | pub const SYS_oldstat = 18; | ||
| 33 | pub const SYS_lseek = 19; | ||
| 34 | pub const SYS_getpid = 20; | ||
| 35 | pub const SYS_mount = 21; | ||
| 36 | pub const SYS_umount = 22; | ||
| 37 | pub const SYS_setuid = 23; | ||
| 38 | pub const SYS_getuid = 24; | ||
| 39 | pub const SYS_stime = 25; | ||
| 40 | pub const SYS_ptrace = 26; | ||
| 41 | pub const SYS_alarm = 27; | ||
| 42 | pub const SYS_oldfstat = 28; | ||
| 43 | pub const SYS_pause = 29; | ||
| 44 | pub const SYS_utime = 30; | ||
| 45 | pub const SYS_stty = 31; | ||
| 46 | pub const SYS_gtty = 32; | ||
| 47 | pub const SYS_access = 33; | ||
| 48 | pub const SYS_nice = 34; | ||
| 49 | pub const SYS_ftime = 35; | ||
| 50 | pub const SYS_sync = 36; | ||
| 51 | pub const SYS_kill = 37; | ||
| 52 | pub const SYS_rename = 38; | ||
| 53 | pub const SYS_mkdir = 39; | ||
| 54 | pub const SYS_rmdir = 40; | ||
| 55 | pub const SYS_dup = 41; | ||
| 56 | pub const SYS_pipe = 42; | ||
| 57 | pub const SYS_times = 43; | ||
| 58 | pub const SYS_prof = 44; | ||
| 59 | pub const SYS_brk = 45; | ||
| 60 | pub const SYS_setgid = 46; | ||
| 61 | pub const SYS_getgid = 47; | ||
| 62 | pub const SYS_signal = 48; | ||
| 63 | pub const SYS_geteuid = 49; | ||
| 64 | pub const SYS_getegid = 50; | ||
| 65 | pub const SYS_acct = 51; | ||
| 66 | pub const SYS_umount2 = 52; | ||
| 67 | pub const SYS_lock = 53; | ||
| 68 | pub const SYS_ioctl = 54; | ||
| 69 | pub const SYS_fcntl = 55; | ||
| 70 | pub const SYS_mpx = 56; | ||
| 71 | pub const SYS_setpgid = 57; | ||
| 72 | pub const SYS_ulimit = 58; | ||
| 73 | pub const SYS_oldolduname = 59; | ||
| 74 | pub const SYS_umask = 60; | ||
| 75 | pub const SYS_chroot = 61; | ||
| 76 | pub const SYS_ustat = 62; | ||
| 77 | pub const SYS_dup2 = 63; | ||
| 78 | pub const SYS_getppid = 64; | ||
| 79 | pub const SYS_getpgrp = 65; | ||
| 80 | pub const SYS_setsid = 66; | ||
| 81 | pub const SYS_sigaction = 67; | ||
| 82 | pub const SYS_sgetmask = 68; | ||
| 83 | pub const SYS_ssetmask = 69; | ||
| 84 | pub const SYS_setreuid = 70; | ||
| 85 | pub const SYS_setregid = 71; | ||
| 86 | pub const SYS_sigsuspend = 72; | ||
| 87 | pub const SYS_sigpending = 73; | ||
| 88 | pub const SYS_sethostname = 74; | ||
| 89 | pub const SYS_setrlimit = 75; | ||
| 90 | pub const SYS_getrlimit = 76; | ||
| 91 | pub const SYS_getrusage = 77; | ||
| 92 | pub const SYS_gettimeofday = 78; | ||
| 93 | pub const SYS_settimeofday = 79; | ||
| 94 | pub const SYS_getgroups = 80; | ||
| 95 | pub const SYS_setgroups = 81; | ||
| 96 | pub const SYS_select = 82; | ||
| 97 | pub const SYS_symlink = 83; | ||
| 98 | pub const SYS_oldlstat = 84; | ||
| 99 | pub const SYS_readlink = 85; | ||
| 100 | pub const SYS_uselib = 86; | ||
| 101 | pub const SYS_swapon = 87; | ||
| 102 | pub const SYS_reboot = 88; | ||
| 103 | pub const SYS_readdir = 89; | ||
| 104 | pub const SYS_mmap = 90; | ||
| 105 | pub const SYS_munmap = 91; | ||
| 106 | pub const SYS_truncate = 92; | ||
| 107 | pub const SYS_ftruncate = 93; | ||
| 108 | pub const SYS_fchmod = 94; | ||
| 109 | pub const SYS_fchown = 95; | ||
| 110 | pub const SYS_getpriority = 96; | ||
| 111 | pub const SYS_setpriority = 97; | ||
| 112 | pub const SYS_profil = 98; | ||
| 113 | pub const SYS_statfs = 99; | ||
| 114 | pub const SYS_fstatfs = 100; | ||
| 115 | pub const SYS_ioperm = 101; | ||
| 116 | pub const SYS_socketcall = 102; | ||
| 117 | pub const SYS_syslog = 103; | ||
| 118 | pub const SYS_setitimer = 104; | ||
| 119 | pub const SYS_getitimer = 105; | ||
| 120 | pub const SYS_stat = 106; | ||
| 121 | pub const SYS_lstat = 107; | ||
| 122 | pub const SYS_fstat = 108; | ||
| 123 | pub const SYS_olduname = 109; | ||
| 124 | pub const SYS_iopl = 110; | ||
| 125 | pub const SYS_vhangup = 111; | ||
| 126 | pub const SYS_idle = 112; | ||
| 127 | pub const SYS_vm86old = 113; | ||
| 128 | pub const SYS_wait4 = 114; | ||
| 129 | pub const SYS_swapoff = 115; | ||
| 130 | pub const SYS_sysinfo = 116; | ||
| 131 | pub const SYS_ipc = 117; | ||
| 132 | pub const SYS_fsync = 118; | ||
| 133 | pub const SYS_sigreturn = 119; | ||
| 134 | pub const SYS_clone = 120; | ||
| 135 | pub const SYS_setdomainname = 121; | ||
| 136 | pub const SYS_uname = 122; | ||
| 137 | pub const SYS_modify_ldt = 123; | ||
| 138 | pub const SYS_adjtimex = 124; | ||
| 139 | pub const SYS_mprotect = 125; | ||
| 140 | pub const SYS_sigprocmask = 126; | ||
| 141 | pub const SYS_create_module = 127; | ||
| 142 | pub const SYS_init_module = 128; | ||
| 143 | pub const SYS_delete_module = 129; | ||
| 144 | pub const SYS_get_kernel_syms = 130; | ||
| 145 | pub const SYS_quotactl = 131; | ||
| 146 | pub const SYS_getpgid = 132; | ||
| 147 | pub const SYS_fchdir = 133; | ||
| 148 | pub const SYS_bdflush = 134; | ||
| 149 | pub const SYS_sysfs = 135; | ||
| 150 | pub const SYS_personality = 136; | ||
| 151 | pub const SYS_afs_syscall = 137; | ||
| 152 | pub const SYS_setfsuid = 138; | ||
| 153 | pub const SYS_setfsgid = 139; | ||
| 154 | pub const SYS__llseek = 140; | ||
| 155 | pub const SYS_getdents = 141; | ||
| 156 | pub const SYS__newselect = 142; | ||
| 157 | pub const SYS_flock = 143; | ||
| 158 | pub const SYS_msync = 144; | ||
| 159 | pub const SYS_readv = 145; | ||
| 160 | pub const SYS_writev = 146; | ||
| 161 | pub const SYS_getsid = 147; | ||
| 162 | pub const SYS_fdatasync = 148; | ||
| 163 | pub const SYS__sysctl = 149; | ||
| 164 | pub const SYS_mlock = 150; | ||
| 165 | pub const SYS_munlock = 151; | ||
| 166 | pub const SYS_mlockall = 152; | ||
| 167 | pub const SYS_munlockall = 153; | ||
| 168 | pub const SYS_sched_setparam = 154; | ||
| 169 | pub const SYS_sched_getparam = 155; | ||
| 170 | pub const SYS_sched_setscheduler = 156; | ||
| 171 | pub const SYS_sched_getscheduler = 157; | ||
| 172 | pub const SYS_sched_yield = 158; | ||
| 173 | pub const SYS_sched_get_priority_max = 159; | ||
| 174 | pub const SYS_sched_get_priority_min = 160; | ||
| 175 | pub const SYS_sched_rr_get_interval = 161; | ||
| 176 | pub const SYS_nanosleep = 162; | ||
| 177 | pub const SYS_mremap = 163; | ||
| 178 | pub const SYS_setresuid = 164; | ||
| 179 | pub const SYS_getresuid = 165; | ||
| 180 | pub const SYS_vm86 = 166; | ||
| 181 | pub const SYS_query_module = 167; | ||
| 182 | pub const SYS_poll = 168; | ||
| 183 | pub const SYS_nfsservctl = 169; | ||
| 184 | pub const SYS_setresgid = 170; | ||
| 185 | pub const SYS_getresgid = 171; | ||
| 186 | pub const SYS_prctl = 172; | ||
| 187 | pub const SYS_rt_sigreturn = 173; | ||
| 188 | pub const SYS_rt_sigaction = 174; | ||
| 189 | pub const SYS_rt_sigprocmask = 175; | ||
| 190 | pub const SYS_rt_sigpending = 176; | ||
| 191 | pub const SYS_rt_sigtimedwait = 177; | ||
| 192 | pub const SYS_rt_sigqueueinfo = 178; | ||
| 193 | pub const SYS_rt_sigsuspend = 179; | ||
| 194 | pub const SYS_pread64 = 180; | ||
| 195 | pub const SYS_pwrite64 = 181; | ||
| 196 | pub const SYS_chown = 182; | ||
| 197 | pub const SYS_getcwd = 183; | ||
| 198 | pub const SYS_capget = 184; | ||
| 199 | pub const SYS_capset = 185; | ||
| 200 | pub const SYS_sigaltstack = 186; | ||
| 201 | pub const SYS_sendfile = 187; | ||
| 202 | pub const SYS_getpmsg = 188; | ||
| 203 | pub const SYS_putpmsg = 189; | ||
| 204 | pub const SYS_vfork = 190; | ||
| 205 | pub const SYS_ugetrlimit = 191; | ||
| 206 | pub const SYS_mmap2 = 192; | ||
| 207 | pub const SYS_truncate64 = 193; | ||
| 208 | pub const SYS_ftruncate64 = 194; | ||
| 209 | pub const SYS_stat64 = 195; | ||
| 210 | pub const SYS_lstat64 = 196; | ||
| 211 | pub const SYS_fstat64 = 197; | ||
| 212 | pub const SYS_lchown32 = 198; | ||
| 213 | pub const SYS_getuid32 = 199; | ||
| 214 | pub const SYS_getgid32 = 200; | ||
| 215 | pub const SYS_geteuid32 = 201; | ||
| 216 | pub const SYS_getegid32 = 202; | ||
| 217 | pub const SYS_setreuid32 = 203; | ||
| 218 | pub const SYS_setregid32 = 204; | ||
| 219 | pub const SYS_getgroups32 = 205; | ||
| 220 | pub const SYS_setgroups32 = 206; | ||
| 221 | pub const SYS_fchown32 = 207; | ||
| 222 | pub const SYS_setresuid32 = 208; | ||
| 223 | pub const SYS_getresuid32 = 209; | ||
| 224 | pub const SYS_setresgid32 = 210; | ||
| 225 | pub const SYS_getresgid32 = 211; | ||
| 226 | pub const SYS_chown32 = 212; | ||
| 227 | pub const SYS_setuid32 = 213; | ||
| 228 | pub const SYS_setgid32 = 214; | ||
| 229 | pub const SYS_setfsuid32 = 215; | ||
| 230 | pub const SYS_setfsgid32 = 216; | ||
| 231 | pub const SYS_pivot_root = 217; | ||
| 232 | pub const SYS_mincore = 218; | ||
| 233 | pub const SYS_madvise = 219; | ||
| 234 | pub const SYS_getdents64 = 220; | ||
| 235 | pub const SYS_fcntl64 = 221; | ||
| 236 | pub const SYS_gettid = 224; | ||
| 237 | pub const SYS_readahead = 225; | ||
| 238 | pub const SYS_setxattr = 226; | ||
| 239 | pub const SYS_lsetxattr = 227; | ||
| 240 | pub const SYS_fsetxattr = 228; | ||
| 241 | pub const SYS_getxattr = 229; | ||
| 242 | pub const SYS_lgetxattr = 230; | ||
| 243 | pub const SYS_fgetxattr = 231; | ||
| 244 | pub const SYS_listxattr = 232; | ||
| 245 | pub const SYS_llistxattr = 233; | ||
| 246 | pub const SYS_flistxattr = 234; | ||
| 247 | pub const SYS_removexattr = 235; | ||
| 248 | pub const SYS_lremovexattr = 236; | ||
| 249 | pub const SYS_fremovexattr = 237; | ||
| 250 | pub const SYS_tkill = 238; | ||
| 251 | pub const SYS_sendfile64 = 239; | ||
| 252 | pub const SYS_futex = 240; | ||
| 253 | pub const SYS_sched_setaffinity = 241; | ||
| 254 | pub const SYS_sched_getaffinity = 242; | ||
| 255 | pub const SYS_set_thread_area = 243; | ||
| 256 | pub const SYS_get_thread_area = 244; | ||
| 257 | pub const SYS_io_setup = 245; | ||
| 258 | pub const SYS_io_destroy = 246; | ||
| 259 | pub const SYS_io_getevents = 247; | ||
| 260 | pub const SYS_io_submit = 248; | ||
| 261 | pub const SYS_io_cancel = 249; | ||
| 262 | pub const SYS_fadvise64 = 250; | ||
| 263 | pub const SYS_exit_group = 252; | ||
| 264 | pub const SYS_lookup_dcookie = 253; | ||
| 265 | pub const SYS_epoll_create = 254; | ||
| 266 | pub const SYS_epoll_ctl = 255; | ||
| 267 | pub const SYS_epoll_wait = 256; | ||
| 268 | pub const SYS_remap_file_pages = 257; | ||
| 269 | pub const SYS_set_tid_address = 258; | ||
| 270 | pub const SYS_timer_create = 259; | ||
| 271 | pub const SYS_timer_settime = SYS_timer_create + 1; | ||
| 272 | pub const SYS_timer_gettime = SYS_timer_create + 2; | ||
| 273 | pub const SYS_timer_getoverrun = SYS_timer_create + 3; | ||
| 274 | pub const SYS_timer_delete = SYS_timer_create + 4; | ||
| 275 | pub const SYS_clock_settime = SYS_timer_create + 5; | ||
| 276 | pub const SYS_clock_gettime = SYS_timer_create + 6; | ||
| 277 | pub const SYS_clock_getres = SYS_timer_create + 7; | ||
| 278 | pub const SYS_clock_nanosleep = SYS_timer_create + 8; | ||
| 279 | pub const SYS_statfs64 = 268; | ||
| 280 | pub const SYS_fstatfs64 = 269; | ||
| 281 | pub const SYS_tgkill = 270; | ||
| 282 | pub const SYS_utimes = 271; | ||
| 283 | pub const SYS_fadvise64_64 = 272; | ||
| 284 | pub const SYS_vserver = 273; | ||
| 285 | pub const SYS_mbind = 274; | ||
| 286 | pub const SYS_get_mempolicy = 275; | ||
| 287 | pub const SYS_set_mempolicy = 276; | ||
| 288 | pub const SYS_mq_open = 277; | ||
| 289 | pub const SYS_mq_unlink = SYS_mq_open + 1; | ||
| 290 | pub const SYS_mq_timedsend = SYS_mq_open + 2; | ||
| 291 | pub const SYS_mq_timedreceive = SYS_mq_open + 3; | ||
| 292 | pub const SYS_mq_notify = SYS_mq_open + 4; | ||
| 293 | pub const SYS_mq_getsetattr = SYS_mq_open + 5; | ||
| 294 | pub const SYS_kexec_load = 283; | ||
| 295 | pub const SYS_waitid = 284; | ||
| 296 | pub const SYS_add_key = 286; | ||
| 297 | pub const SYS_request_key = 287; | ||
| 298 | pub const SYS_keyctl = 288; | ||
| 299 | pub const SYS_ioprio_set = 289; | ||
| 300 | pub const SYS_ioprio_get = 290; | ||
| 301 | pub const SYS_inotify_init = 291; | ||
| 302 | pub const SYS_inotify_add_watch = 292; | ||
| 303 | pub const SYS_inotify_rm_watch = 293; | ||
| 304 | pub const SYS_migrate_pages = 294; | ||
| 305 | pub const SYS_openat = 295; | ||
| 306 | pub const SYS_mkdirat = 296; | ||
| 307 | pub const SYS_mknodat = 297; | ||
| 308 | pub const SYS_fchownat = 298; | ||
| 309 | pub const SYS_futimesat = 299; | ||
| 310 | pub const SYS_fstatat64 = 300; | ||
| 311 | pub const SYS_unlinkat = 301; | ||
| 312 | pub const SYS_renameat = 302; | ||
| 313 | pub const SYS_linkat = 303; | ||
| 314 | pub const SYS_symlinkat = 304; | ||
| 315 | pub const SYS_readlinkat = 305; | ||
| 316 | pub const SYS_fchmodat = 306; | ||
| 317 | pub const SYS_faccessat = 307; | ||
| 318 | pub const SYS_pselect6 = 308; | ||
| 319 | pub const SYS_ppoll = 309; | ||
| 320 | pub const SYS_unshare = 310; | ||
| 321 | pub const SYS_set_robust_list = 311; | ||
| 322 | pub const SYS_get_robust_list = 312; | ||
| 323 | pub const SYS_splice = 313; | ||
| 324 | pub const SYS_sync_file_range = 314; | ||
| 325 | pub const SYS_tee = 315; | ||
| 326 | pub const SYS_vmsplice = 316; | ||
| 327 | pub const SYS_move_pages = 317; | ||
| 328 | pub const SYS_getcpu = 318; | ||
| 329 | pub const SYS_epoll_pwait = 319; | ||
| 330 | pub const SYS_utimensat = 320; | ||
| 331 | pub const SYS_signalfd = 321; | ||
| 332 | pub const SYS_timerfd_create = 322; | ||
| 333 | pub const SYS_eventfd = 323; | ||
| 334 | pub const SYS_fallocate = 324; | ||
| 335 | pub const SYS_timerfd_settime = 325; | ||
| 336 | pub const SYS_timerfd_gettime = 326; | ||
| 337 | pub const SYS_signalfd4 = 327; | ||
| 338 | pub const SYS_eventfd2 = 328; | ||
| 339 | pub const SYS_epoll_create1 = 329; | ||
| 340 | pub const SYS_dup3 = 330; | ||
| 341 | pub const SYS_pipe2 = 331; | ||
| 342 | pub const SYS_inotify_init1 = 332; | ||
| 343 | pub const SYS_preadv = 333; | ||
| 344 | pub const SYS_pwritev = 334; | ||
| 345 | pub const SYS_rt_tgsigqueueinfo = 335; | ||
| 346 | pub const SYS_perf_event_open = 336; | ||
| 347 | pub const SYS_recvmmsg = 337; | ||
| 348 | pub const SYS_fanotify_init = 338; | ||
| 349 | pub const SYS_fanotify_mark = 339; | ||
| 350 | pub const SYS_prlimit64 = 340; | ||
| 351 | pub const SYS_name_to_handle_at = 341; | ||
| 352 | pub const SYS_open_by_handle_at = 342; | ||
| 353 | pub const SYS_clock_adjtime = 343; | ||
| 354 | pub const SYS_syncfs = 344; | ||
| 355 | pub const SYS_sendmmsg = 345; | ||
| 356 | pub const SYS_setns = 346; | ||
| 357 | pub const SYS_process_vm_readv = 347; | ||
| 358 | pub const SYS_process_vm_writev = 348; | ||
| 359 | pub const SYS_kcmp = 349; | ||
| 360 | pub const SYS_finit_module = 350; | ||
| 361 | pub const SYS_sched_setattr = 351; | ||
| 362 | pub const SYS_sched_getattr = 352; | ||
| 363 | pub const SYS_renameat2 = 353; | ||
| 364 | pub const SYS_seccomp = 354; | ||
| 365 | pub const SYS_getrandom = 355; | ||
| 366 | pub const SYS_memfd_create = 356; | ||
| 367 | pub const SYS_bpf = 357; | ||
| 368 | pub const SYS_execveat = 358; | ||
| 369 | pub const SYS_socket = 359; | ||
| 370 | pub const SYS_socketpair = 360; | ||
| 371 | pub const SYS_bind = 361; | ||
| 372 | pub const SYS_connect = 362; | ||
| 373 | pub const SYS_listen = 363; | ||
| 374 | pub const SYS_accept4 = 364; | ||
| 375 | pub const SYS_getsockopt = 365; | ||
| 376 | pub const SYS_setsockopt = 366; | ||
| 377 | pub const SYS_getsockname = 367; | ||
| 378 | pub const SYS_getpeername = 368; | ||
| 379 | pub const SYS_sendto = 369; | ||
| 380 | pub const SYS_sendmsg = 370; | ||
| 381 | pub const SYS_recvfrom = 371; | ||
| 382 | pub const SYS_recvmsg = 372; | ||
| 383 | pub const SYS_shutdown = 373; | ||
| 384 | pub const SYS_userfaultfd = 374; | ||
| 385 | pub const SYS_membarrier = 375; | ||
| 386 | pub const SYS_mlock2 = 376; | ||
| 387 | pub const SYS_copy_file_range = 377; | ||
| 388 | pub const SYS_preadv2 = 378; | ||
| 389 | pub const SYS_pwritev2 = 379; | ||
| 390 | pub const SYS_pkey_mprotect = 380; | ||
| 391 | pub const SYS_pkey_alloc = 381; | ||
| 392 | pub const SYS_pkey_free = 382; | ||
| 393 | pub const SYS_statx = 383; | ||
| 394 | pub const SYS_arch_prctl = 384; | ||
| 395 | pub const SYS_io_pgetevents = 385; | ||
| 396 | pub const SYS_rseq = 386; | ||
| 397 | pub const SYS_semget = 393; | ||
| 398 | pub const SYS_semctl = 394; | ||
| 399 | pub const SYS_shmget = 395; | ||
| 400 | pub const SYS_shmctl = 396; | ||
| 401 | pub const SYS_shmat = 397; | ||
| 402 | pub const SYS_shmdt = 398; | ||
| 403 | pub const SYS_msgget = 399; | ||
| 404 | pub const SYS_msgsnd = 400; | ||
| 405 | pub const SYS_msgrcv = 401; | ||
| 406 | pub const SYS_msgctl = 402; | ||
| 407 | pub const SYS_clock_gettime64 = 403; | ||
| 408 | pub const SYS_clock_settime64 = 404; | ||
| 409 | pub const SYS_clock_adjtime64 = 405; | ||
| 410 | pub const SYS_clock_getres_time64 = 406; | ||
| 411 | pub const SYS_clock_nanosleep_time64 = 407; | ||
| 412 | pub const SYS_timer_gettime64 = 408; | ||
| 413 | pub const SYS_timer_settime64 = 409; | ||
| 414 | pub const SYS_timerfd_gettime64 = 410; | ||
| 415 | pub const SYS_timerfd_settime64 = 411; | ||
| 416 | pub const SYS_utimensat_time64 = 412; | ||
| 417 | pub const SYS_pselect6_time64 = 413; | ||
| 418 | pub const SYS_ppoll_time64 = 414; | ||
| 419 | pub const SYS_io_pgetevents_time64 = 416; | ||
| 420 | pub const SYS_recvmmsg_time64 = 417; | ||
| 421 | pub const SYS_mq_timedsend_time64 = 418; | ||
| 422 | pub const SYS_mq_timedreceive_time64 = 419; | ||
| 423 | pub const SYS_semtimedop_time64 = 420; | ||
| 424 | pub const SYS_rt_sigtimedwait_time64 = 421; | ||
| 425 | pub const SYS_futex_time64 = 422; | ||
| 426 | pub const SYS_sched_rr_get_interval_time64 = 423; | ||
| 427 | pub const SYS_pidfd_send_signal = 424; | ||
| 428 | pub const SYS_io_uring_setup = 425; | ||
| 429 | pub const SYS_io_uring_enter = 426; | ||
| 430 | pub const SYS_io_uring_register = 427; | ||
| 431 | pub const SYS_open_tree = 428; | ||
| 432 | pub const SYS_move_mount = 429; | ||
| 433 | pub const SYS_fsopen = 430; | ||
| 434 | pub const SYS_fsconfig = 431; | ||
| 435 | pub const SYS_fsmount = 432; | ||
| 436 | pub const SYS_fspick = 433; | ||
| 437 | |||
| 438 | pub const O_CREAT = 0o100; | ||
| 439 | pub const O_EXCL = 0o200; | ||
| 440 | pub const O_NOCTTY = 0o400; | ||
| 441 | pub const O_TRUNC = 0o1000; | ||
| 442 | pub const O_APPEND = 0o2000; | ||
| 443 | pub const O_NONBLOCK = 0o4000; | ||
| 444 | pub const O_DSYNC = 0o10000; | ||
| 445 | pub const O_SYNC = 0o4010000; | ||
| 446 | pub const O_RSYNC = 0o4010000; | ||
| 447 | pub const O_DIRECTORY = 0o200000; | ||
| 448 | pub const O_NOFOLLOW = 0o400000; | ||
| 449 | pub const O_CLOEXEC = 0o2000000; | ||
| 450 | |||
| 451 | pub const O_ASYNC = 0o20000; | ||
| 452 | pub const O_DIRECT = 0o40000; | ||
| 453 | pub const O_LARGEFILE = 0o100000; | ||
| 454 | pub const O_NOATIME = 0o1000000; | ||
| 455 | pub const O_PATH = 0o10000000; | ||
| 456 | pub const O_TMPFILE = 0o20200000; | ||
| 457 | pub const O_NDELAY = O_NONBLOCK; | ||
| 458 | |||
| 459 | pub const F_DUPFD = 0; | ||
| 460 | pub const F_GETFD = 1; | ||
| 461 | pub const F_SETFD = 2; | ||
| 462 | pub const F_GETFL = 3; | ||
| 463 | pub const F_SETFL = 4; | ||
| 464 | |||
| 465 | pub const F_SETOWN = 8; | ||
| 466 | pub const F_GETOWN = 9; | ||
| 467 | pub const F_SETSIG = 10; | ||
| 468 | pub const F_GETSIG = 11; | ||
| 469 | |||
| 470 | pub const F_GETLK = 12; | ||
| 471 | pub const F_SETLK = 13; | ||
| 472 | pub const F_SETLKW = 14; | ||
| 473 | |||
| 474 | pub const F_SETOWN_EX = 15; | ||
| 475 | pub const F_GETOWN_EX = 16; | ||
| 476 | |||
| 477 | pub const F_GETOWNER_UIDS = 17; | ||
| 478 | |||
| 479 | pub const MAP_NORESERVE = 0x4000; | ||
| 480 | pub const MAP_GROWSDOWN = 0x0100; | ||
| 481 | pub const MAP_DENYWRITE = 0x0800; | ||
| 482 | pub const MAP_EXECUTABLE = 0x1000; | ||
| 483 | pub const MAP_LOCKED = 0x2000; | ||
| 484 | pub const MAP_32BIT = 0x40; | ||
| 485 | |||
| 486 | pub const MMAP2_UNIT = 4096; | ||
| 487 | |||
| 488 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; | ||
| 489 | pub const VDSO_CGT_VER = "LINUX_2.6"; | ||
| 490 | |||
| 491 | pub const msghdr = extern struct { | ||
| 492 | msg_name: ?*sockaddr, | ||
| 493 | msg_namelen: socklen_t, | ||
| 494 | msg_iov: [*]iovec, | ||
| 495 | msg_iovlen: i32, | ||
| 496 | msg_control: ?*c_void, | ||
| 497 | msg_controllen: socklen_t, | ||
| 498 | msg_flags: i32, | ||
| 499 | }; | ||
| 500 | |||
| 501 | pub const msghdr_const = extern struct { | ||
| 502 | msg_name: ?*const sockaddr, | ||
| 503 | msg_namelen: socklen_t, | ||
| 504 | msg_iov: [*]iovec_const, | ||
| 505 | msg_iovlen: i32, | ||
| 506 | msg_control: ?*c_void, | ||
| 507 | msg_controllen: socklen_t, | ||
| 508 | msg_flags: i32, | ||
| 509 | }; | ||
| 510 | |||
| 511 | pub const blksize_t = i32; | ||
| 512 | pub const nlink_t = u32; | ||
| 513 | pub const time_t = isize; | ||
| 514 | pub const mode_t = u32; | ||
| 515 | pub const off_t = i64; | ||
| 516 | pub const ino_t = u64; | ||
| 517 | pub const dev_t = u64; | ||
| 518 | pub const blkcnt_t = i64; | ||
| 519 | |||
| 520 | /// Renamed to Stat to not conflict with the stat function. | ||
| 521 | /// atime, mtime, and ctime have functions to return `timespec`, | ||
| 522 | /// because although this is a POSIX API, the layout and names of | ||
| 523 | /// the structs are inconsistent across operating systems, and | ||
| 524 | /// in C, macros are used to hide the differences. Here we use | ||
| 525 | /// methods to accomplish this. | ||
| 526 | pub const Stat = extern struct { | ||
| 527 | dev: dev_t, | ||
| 528 | __dev_padding: u32, | ||
| 529 | __ino_truncated: u32, | ||
| 530 | mode: mode_t, | ||
| 531 | nlink: nlink_t, | ||
| 532 | uid: uid_t, | ||
| 533 | gid: gid_t, | ||
| 534 | rdev: dev_t, | ||
| 535 | __rdev_padding: u32, | ||
| 536 | size: off_t, | ||
| 537 | blksize: blksize_t, | ||
| 538 | blocks: blkcnt_t, | ||
| 539 | atim: timespec, | ||
| 540 | mtim: timespec, | ||
| 541 | ctim: timespec, | ||
| 542 | ino: ino_t, | ||
| 543 | |||
| 544 | pub fn atime(self: Stat) timespec { | ||
| 545 | return self.atim; | ||
| 546 | } | ||
| 547 | |||
| 548 | pub fn mtime(self: Stat) timespec { | ||
| 549 | return self.mtim; | ||
| 550 | } | ||
| 551 | |||
| 552 | pub fn ctime(self: Stat) timespec { | ||
| 553 | return self.ctim; | ||
| 554 | } | ||
| 555 | }; | ||
| 556 | |||
| 557 | pub const timespec = extern struct { | ||
| 558 | tv_sec: i32, | ||
| 559 | tv_nsec: i32, | ||
| 560 | }; | ||
| 561 | |||
| 562 | pub const timeval = extern struct { | ||
| 563 | tv_sec: i32, | ||
| 564 | tv_usec: i32, | ||
| 565 | }; | ||
| 566 | |||
| 567 | pub const timezone = extern struct { | ||
| 568 | tz_minuteswest: i32, | ||
| 569 | tz_dsttime: i32, | ||
| 570 | }; | ||
| 571 | |||
| 572 | pub const mcontext_t = extern struct { | ||
| 573 | gregs: [19]usize, | ||
| 574 | fpregs: [*]u8, | ||
| 575 | oldmask: usize, | ||
| 576 | cr2: usize, | ||
| 577 | }; | ||
| 578 | |||
| 579 | pub const REG_GS = 0; | ||
| 580 | pub const REG_FS = 1; | ||
| 581 | pub const REG_ES = 2; | ||
| 582 | pub const REG_DS = 3; | ||
| 583 | pub const REG_EDI = 4; | ||
| 584 | pub const REG_ESI = 5; | ||
| 585 | pub const REG_EBP = 6; | ||
| 586 | pub const REG_ESP = 7; | ||
| 587 | pub const REG_EBX = 8; | ||
| 588 | pub const REG_EDX = 9; | ||
| 589 | pub const REG_ECX = 10; | ||
| 590 | pub const REG_EAX = 11; | ||
| 591 | pub const REG_TRAPNO = 12; | ||
| 592 | pub const REG_ERR = 13; | ||
| 593 | pub const REG_EIP = 14; | ||
| 594 | pub const REG_CS = 15; | ||
| 595 | pub const REG_EFL = 16; | ||
| 596 | pub const REG_UESP = 17; | ||
| 597 | pub const REG_SS = 18; | ||
| 598 | |||
| 599 | pub const ucontext_t = extern struct { | ||
| 600 | flags: usize, | ||
| 601 | link: *ucontext_t, | ||
| 602 | stack: stack_t, | ||
| 603 | mcontext: mcontext_t, | ||
| 604 | sigmask: sigset_t, | ||
| 605 | regspace: [64]u64, | ||
| 606 | }; | ||
| 607 | |||
| 608 | pub const Elf_Symndx = u32; | ||
| 609 | |||
| 610 | pub const user_desc = packed struct { | ||
| 611 | entry_number: u32, | ||
| 612 | base_addr: u32, | ||
| 613 | limit: u32, | ||
| 614 | seg_32bit: u1, | ||
| 615 | contents: u2, | ||
| 616 | read_exec_only: u1, | ||
| 617 | limit_in_pages: u1, | ||
| 618 | seg_not_present: u1, | ||
| 619 | useable: u1, | ||
| 620 | }; | ||
| 621 | |||
| 622 | // socketcall() call numbers | ||
| 623 | pub const SC_socket = 1; | ||
| 624 | pub const SC_bind = 2; | ||
| 625 | pub const SC_connect = 3; | ||
| 626 | pub const SC_listen = 4; | ||
| 627 | pub const SC_accept = 5; | ||
| 628 | pub const SC_getsockname = 6; | ||
| 629 | pub const SC_getpeername = 7; | ||
| 630 | pub const SC_socketpair = 8; | ||
| 631 | pub const SC_send = 9; | ||
| 632 | pub const SC_recv = 10; | ||
| 633 | pub const SC_sendto = 11; | ||
| 634 | pub const SC_recvfrom = 12; | ||
| 635 | pub const SC_shutdown = 13; | ||
| 636 | pub const SC_setsockopt = 14; | ||
| 637 | pub const SC_getsockopt = 15; | ||
| 638 | pub const SC_sendmsg = 16; | ||
| 639 | pub const SC_recvmsg = 17; | ||
| 640 | pub const SC_accept4 = 18; | ||
| 641 | pub const SC_recvmmsg = 19; | ||
| 642 | pub const SC_sendmmsg = 20; | ||
lib/std/os/bits/linux/mipsel.zig-1| ... | @@ -454,7 +454,6 @@ pub const SO_PEERSEC = 30; | ... | @@ -454,7 +454,6 @@ pub const SO_PEERSEC = 30; |
| 454 | pub const SO_SNDBUFFORCE = 31; | 454 | pub const SO_SNDBUFFORCE = 31; |
| 455 | pub const SO_RCVBUFFORCE = 33; | 455 | pub const SO_RCVBUFFORCE = 33; |
| 456 | 456 | ||
| 457 | pub const VDSO_USEFUL = true; | ||
| 458 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; | 457 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; |
| 459 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; | 458 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; |
| 460 | 459 |
lib/std/os/bits/linux/x86_64.zig-1| ... | @@ -420,7 +420,6 @@ pub const MAP_LOCKED = 0x2000; | ... | @@ -420,7 +420,6 @@ pub const MAP_LOCKED = 0x2000; |
| 420 | /// don't check for reservations | 420 | /// don't check for reservations |
| 421 | pub const MAP_NORESERVE = 0x4000; | 421 | pub const MAP_NORESERVE = 0x4000; |
| 422 | 422 | ||
| 423 | pub const VDSO_USEFUL = true; | ||
| 424 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; | 423 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; |
| 425 | pub const VDSO_CGT_VER = "LINUX_2.6"; | 424 | pub const VDSO_CGT_VER = "LINUX_2.6"; |
| 426 | pub const VDSO_GETCPU_SYM = "__vdso_getcpu"; | 425 | pub const VDSO_GETCPU_SYM = "__vdso_getcpu"; |
lib/std/os/linux.zig+49| ... | @@ -14,6 +14,7 @@ const vdso = @import("linux/vdso.zig"); | ... | @@ -14,6 +14,7 @@ const vdso = @import("linux/vdso.zig"); |
| 14 | const dl = @import("../dynamic_library.zig"); | 14 | const dl = @import("../dynamic_library.zig"); |
| 15 | 15 | ||
| 16 | pub usingnamespace switch (builtin.arch) { | 16 | pub usingnamespace switch (builtin.arch) { |
| 17 | .i386 => @import("linux/i386.zig"), | ||
| 17 | .x86_64 => @import("linux/x86_64.zig"), | 18 | .x86_64 => @import("linux/x86_64.zig"), |
| 18 | .aarch64 => @import("linux/arm64.zig"), | 19 | .aarch64 => @import("linux/arm64.zig"), |
| 19 | .arm => @import("linux/arm-eabi.zig"), | 20 | .arm => @import("linux/arm-eabi.zig"), |
| ... | @@ -743,26 +744,44 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool { | ... | @@ -743,26 +744,44 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool { |
| 743 | } | 744 | } |
| 744 | 745 | ||
| 745 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 746 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 747 | if (builtin.arch == .i386) { | ||
| 748 | return socketcall(SC_getsockname, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); | ||
| 749 | } | ||
| 746 | return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); | 750 | return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); |
| 747 | } | 751 | } |
| 748 | 752 | ||
| 749 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 753 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 754 | if (builtin.arch == .i386) { | ||
| 755 | return socketcall(SC_getpeername, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); | ||
| 756 | } | ||
| 750 | return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); | 757 | return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); |
| 751 | } | 758 | } |
| 752 | 759 | ||
| 753 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { | 760 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { |
| 761 | if (builtin.arch == .i386) { | ||
| 762 | return socketcall(SC_socket, &[3]usize{ domain, socket_type, protocol }); | ||
| 763 | } | ||
| 754 | return syscall3(SYS_socket, domain, socket_type, protocol); | 764 | return syscall3(SYS_socket, domain, socket_type, protocol); |
| 755 | } | 765 | } |
| 756 | 766 | ||
| 757 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { | 767 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { |
| 768 | if (builtin.arch == .i386) { | ||
| 769 | return socketcall(SC_setsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen) }); | ||
| 770 | } | ||
| 758 | return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); | 771 | return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); |
| 759 | } | 772 | } |
| 760 | 773 | ||
| 761 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { | 774 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { |
| 775 | if (builtin.arch == .i386) { | ||
| 776 | return socketcall(SC_getsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen) }); | ||
| 777 | } | ||
| 762 | return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | 778 | return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); |
| 763 | } | 779 | } |
| 764 | 780 | ||
| 765 | pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { | 781 | pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { |
| 782 | if (builtin.arch == .i386) { | ||
| 783 | return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); | ||
| 784 | } | ||
| 766 | return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); | 785 | return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); |
| 767 | } | 786 | } |
| 768 | 787 | ||
| ... | @@ -807,42 +826,72 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize | ... | @@ -807,42 +826,72 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize |
| 807 | } | 826 | } |
| 808 | 827 | ||
| 809 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { | 828 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { |
| 829 | if (builtin.arch == .i386) { | ||
| 830 | return socketcall(SC_connect, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len }); | ||
| 831 | } | ||
| 810 | return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len); | 832 | return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len); |
| 811 | } | 833 | } |
| 812 | 834 | ||
| 813 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { | 835 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { |
| 836 | if (builtin.arch == .i386) { | ||
| 837 | return socketcall(SC_recvmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); | ||
| 838 | } | ||
| 814 | return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); | 839 | return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); |
| 815 | } | 840 | } |
| 816 | 841 | ||
| 817 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { | 842 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { |
| 843 | if (builtin.arch == .i386) { | ||
| 844 | return socketcall(SC_recvfrom, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen) }); | ||
| 845 | } | ||
| 818 | return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | 846 | return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); |
| 819 | } | 847 | } |
| 820 | 848 | ||
| 821 | pub fn shutdown(fd: i32, how: i32) usize { | 849 | pub fn shutdown(fd: i32, how: i32) usize { |
| 850 | if (builtin.arch == .i386) { | ||
| 851 | return socketcall(SC_shutdown, &[2]usize{ @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)) }); | ||
| 852 | } | ||
| 822 | return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how))); | 853 | return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how))); |
| 823 | } | 854 | } |
| 824 | 855 | ||
| 825 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { | 856 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { |
| 857 | if (builtin.arch == .i386) { | ||
| 858 | return socketcall(SC_bind, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len) }); | ||
| 859 | } | ||
| 826 | return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len)); | 860 | return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len)); |
| 827 | } | 861 | } |
| 828 | 862 | ||
| 829 | pub fn listen(fd: i32, backlog: u32) usize { | 863 | pub fn listen(fd: i32, backlog: u32) usize { |
| 864 | if (builtin.arch == .i386) { | ||
| 865 | return socketcall(SC_listen, &[2]usize{ @bitCast(usize, @as(isize, fd)), backlog }); | ||
| 866 | } | ||
| 830 | return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog); | 867 | return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog); |
| 831 | } | 868 | } |
| 832 | 869 | ||
| 833 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { | 870 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { |
| 871 | if (builtin.arch == .i386) { | ||
| 872 | return socketcall(SC_sendto, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen) }); | ||
| 873 | } | ||
| 834 | return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); | 874 | return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); |
| 835 | } | 875 | } |
| 836 | 876 | ||
| 837 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { | 877 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { |
| 878 | if (builtin.arch == .i386) { | ||
| 879 | return socketcall(SC_socketpair, &[4]usize{ @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]) }); | ||
| 880 | } | ||
| 838 | return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); | 881 | return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); |
| 839 | } | 882 | } |
| 840 | 883 | ||
| 841 | pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 884 | pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 885 | if (builtin.arch == .i386) { | ||
| 886 | return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 }); | ||
| 887 | } | ||
| 842 | return accept4(fd, addr, len, 0); | 888 | return accept4(fd, addr, len, 0); |
| 843 | } | 889 | } |
| 844 | 890 | ||
| 845 | pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { | 891 | pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { |
| 892 | if (builtin.arch == .i386) { | ||
| 893 | return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags }); | ||
| 894 | } | ||
| 846 | return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags); | 895 | return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags); |
| 847 | } | 896 | } |
| 848 | 897 |
lib/std/os/linux/i386.zig created+119| ... | @@ -0,0 +1,119 @@ | ||
| 1 | usingnamespace @import("../bits.zig"); | ||
| 2 | |||
| 3 | pub fn syscall0(number: usize) usize { | ||
| 4 | return asm volatile ("int $0x80" | ||
| 5 | : [ret] "={eax}" (-> usize) | ||
| 6 | : [number] "{eax}" (number) | ||
| 7 | : "memory" | ||
| 8 | ); | ||
| 9 | } | ||
| 10 | |||
| 11 | pub fn syscall1(number: usize, arg1: usize) usize { | ||
| 12 | return asm volatile ("int $0x80" | ||
| 13 | : [ret] "={eax}" (-> usize) | ||
| 14 | : [number] "{eax}" (number), | ||
| 15 | [arg1] "{ebx}" (arg1) | ||
| 16 | : "memory" | ||
| 17 | ); | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize { | ||
| 21 | return asm volatile ("int $0x80" | ||
| 22 | : [ret] "={eax}" (-> usize) | ||
| 23 | : [number] "{eax}" (number), | ||
| 24 | [arg1] "{ebx}" (arg1), | ||
| 25 | [arg2] "{ecx}" (arg2) | ||
| 26 | : "memory" | ||
| 27 | ); | ||
| 28 | } | ||
| 29 | |||
| 30 | pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize { | ||
| 31 | return asm volatile ("int $0x80" | ||
| 32 | : [ret] "={eax}" (-> usize) | ||
| 33 | : [number] "{eax}" (number), | ||
| 34 | [arg1] "{ebx}" (arg1), | ||
| 35 | [arg2] "{ecx}" (arg2), | ||
| 36 | [arg3] "{edx}" (arg3) | ||
| 37 | : "memory" | ||
| 38 | ); | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { | ||
| 42 | return asm volatile ("int $0x80" | ||
| 43 | : [ret] "={eax}" (-> usize) | ||
| 44 | : [number] "{eax}" (number), | ||
| 45 | [arg1] "{ebx}" (arg1), | ||
| 46 | [arg2] "{ecx}" (arg2), | ||
| 47 | [arg3] "{edx}" (arg3), | ||
| 48 | [arg4] "{esi}" (arg4) | ||
| 49 | : "memory" | ||
| 50 | ); | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { | ||
| 54 | return asm volatile ("int $0x80" | ||
| 55 | : [ret] "={eax}" (-> usize) | ||
| 56 | : [number] "{eax}" (number), | ||
| 57 | [arg1] "{ebx}" (arg1), | ||
| 58 | [arg2] "{ecx}" (arg2), | ||
| 59 | [arg3] "{edx}" (arg3), | ||
| 60 | [arg4] "{esi}" (arg4), | ||
| 61 | [arg5] "{edi}" (arg5) | ||
| 62 | : "memory" | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn syscall6( | ||
| 67 | number: usize, | ||
| 68 | arg1: usize, | ||
| 69 | arg2: usize, | ||
| 70 | arg3: usize, | ||
| 71 | arg4: usize, | ||
| 72 | arg5: usize, | ||
| 73 | arg6: usize, | ||
| 74 | ) usize { | ||
| 75 | return asm volatile ( | ||
| 76 | \\ push %%ebp | ||
| 77 | \\ mov %[arg6], %%ebp | ||
| 78 | \\ int $0x80 | ||
| 79 | \\ pop %%ebp | ||
| 80 | : [ret] "={eax}" (-> usize) | ||
| 81 | : [number] "{eax}" (number), | ||
| 82 | [arg1] "{ebx}" (arg1), | ||
| 83 | [arg2] "{ecx}" (arg2), | ||
| 84 | [arg3] "{edx}" (arg3), | ||
| 85 | [arg4] "{esi}" (arg4), | ||
| 86 | [arg5] "{edi}" (arg5), | ||
| 87 | [arg6] "rm" (arg6) | ||
| 88 | : "memory" | ||
| 89 | ); | ||
| 90 | } | ||
| 91 | |||
| 92 | pub fn socketcall(call: usize, args: [*]usize) usize { | ||
| 93 | return asm volatile ("int $0x80" | ||
| 94 | : [ret] "={eax}" (-> usize) | ||
| 95 | : [number] "{eax}" (@as(usize, SYS_socketcall)), | ||
| 96 | [arg1] "{ebx}" (call), | ||
| 97 | [arg2] "{ecx}" (@ptrToInt(args)) | ||
| 98 | : "memory" | ||
| 99 | ); | ||
| 100 | } | ||
| 101 | |||
| 102 | /// This matches the libc clone function. | ||
| 103 | pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | ||
| 104 | |||
| 105 | pub nakedcc fn restore() void { | ||
| 106 | return asm volatile ("int $0x80" | ||
| 107 | : | ||
| 108 | : [number] "{eax}" (@as(usize, SYS_sigreturn)) | ||
| 109 | : "memory" | ||
| 110 | ); | ||
| 111 | } | ||
| 112 | |||
| 113 | pub nakedcc fn restore_rt() void { | ||
| 114 | return asm volatile ("int $0x80" | ||
| 115 | : | ||
| 116 | : [number] "{eax}" (@as(usize, SYS_rt_sigreturn)) | ||
| 117 | : "memory" | ||
| 118 | ); | ||
| 119 | } | ||
lib/std/os/linux/test.zig+3-4| ... | @@ -4,6 +4,7 @@ const linux = std.os.linux; | ... | @@ -4,6 +4,7 @@ const linux = std.os.linux; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const elf = std.elf; | 5 | const elf = std.elf; |
| 6 | const expect = std.testing.expect; | 6 | const expect = std.testing.expect; |
| 7 | const fs = std.fs; | ||
| 7 | 8 | ||
| 8 | test "getpid" { | 9 | test "getpid" { |
| 9 | expect(linux.getpid() != 0); | 10 | expect(linux.getpid() != 0); |
| ... | @@ -45,14 +46,12 @@ test "timer" { | ... | @@ -45,14 +46,12 @@ test "timer" { |
| 45 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); | 46 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | const File = std.fs.File; | ||
| 49 | |||
| 50 | test "statx" { | 49 | test "statx" { |
| 51 | const tmp_file_name = "just_a_temporary_file.txt"; | 50 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 52 | var file = try File.openWrite(tmp_file_name); | 51 | var file = try fs.cwd().createFile(tmp_file_name, .{}); |
| 53 | defer { | 52 | defer { |
| 54 | file.close(); | 53 | file.close(); |
| 55 | std.fs.deleteFile(tmp_file_name) catch {}; | 54 | fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | var statx_buf: linux.Statx = undefined; | 57 | var statx_buf: linux.Statx = undefined; |
lib/std/os/linux/tls.zig+27| ... | @@ -109,12 +109,38 @@ const TLSImage = struct { | ... | @@ -109,12 +109,38 @@ const TLSImage = struct { |
| 109 | tcb_offset: usize, | 109 | tcb_offset: usize, |
| 110 | dtv_offset: usize, | 110 | dtv_offset: usize, |
| 111 | data_offset: usize, | 111 | data_offset: usize, |
| 112 | // Only used on the i386 architecture | ||
| 113 | gdt_entry_number: usize, | ||
| 112 | }; | 114 | }; |
| 113 | 115 | ||
| 114 | pub var tls_image: ?TLSImage = null; | 116 | pub var tls_image: ?TLSImage = null; |
| 115 | 117 | ||
| 116 | pub fn setThreadPointer(addr: usize) void { | 118 | pub fn setThreadPointer(addr: usize) void { |
| 117 | switch (builtin.arch) { | 119 | switch (builtin.arch) { |
| 120 | .i386 => { | ||
| 121 | var user_desc = std.os.linux.user_desc{ | ||
| 122 | .entry_number = tls_image.?.gdt_entry_number, | ||
| 123 | .base_addr = addr, | ||
| 124 | .limit = 0xfffff, | ||
| 125 | .seg_32bit = 1, | ||
| 126 | .contents = 0, // Data | ||
| 127 | .read_exec_only = 0, | ||
| 128 | .limit_in_pages = 1, | ||
| 129 | .seg_not_present = 0, | ||
| 130 | .useable = 1, | ||
| 131 | }; | ||
| 132 | const rc = std.os.linux.syscall1(std.os.linux.SYS_set_thread_area, @ptrToInt(&user_desc)); | ||
| 133 | assert(rc == 0); | ||
| 134 | |||
| 135 | const gdt_entry_number = user_desc.entry_number; | ||
| 136 | // We have to keep track of our slot as it's also needed for clone() | ||
| 137 | tls_image.?.gdt_entry_number = gdt_entry_number; | ||
| 138 | // Update the %gs selector | ||
| 139 | asm volatile ("movl %[gs_val], %%gs" | ||
| 140 | : | ||
| 141 | : [gs_val] "r" (gdt_entry_number << 3 | 3) | ||
| 142 | ); | ||
| 143 | }, | ||
| 118 | .x86_64 => { | 144 | .x86_64 => { |
| 119 | const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, std.os.linux.ARCH_SET_FS, addr); | 145 | const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, std.os.linux.ARCH_SET_FS, addr); |
| 120 | assert(rc == 0); | 146 | assert(rc == 0); |
| ... | @@ -238,6 +264,7 @@ pub fn initTLS() ?*elf.Phdr { | ... | @@ -238,6 +264,7 @@ pub fn initTLS() ?*elf.Phdr { |
| 238 | .tcb_offset = tcb_offset, | 264 | .tcb_offset = tcb_offset, |
| 239 | .dtv_offset = dtv_offset, | 265 | .dtv_offset = dtv_offset, |
| 240 | .data_offset = data_offset, | 266 | .data_offset = data_offset, |
| 267 | .gdt_entry_number = @bitCast(usize, @as(isize, -1)), | ||
| 241 | }; | 268 | }; |
| 242 | } | 269 | } |
| 243 | 270 |
lib/std/os/test.zig+2-2| ... | @@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" { | ... | @@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" { |
| 20 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); | 20 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); |
| 21 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); | 21 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); |
| 22 | try fs.deleteTree("os_test_tmp"); | 22 | try fs.deleteTree("os_test_tmp"); |
| 23 | if (fs.Dir.cwd().openDirTraverse("os_test_tmp")) |dir| { | 23 | if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { |
| 24 | @panic("expected error"); | 24 | @panic("expected error"); |
| 25 | } else |err| { | 25 | } else |err| { |
| 26 | expect(err == error.FileNotFound); | 26 | expect(err == error.FileNotFound); |
| ... | @@ -111,7 +111,7 @@ test "AtomicFile" { | ... | @@ -111,7 +111,7 @@ test "AtomicFile" { |
| 111 | const content = try io.readFileAlloc(allocator, test_out_file); | 111 | const content = try io.readFileAlloc(allocator, test_out_file); |
| 112 | expect(mem.eql(u8, content, test_content)); | 112 | expect(mem.eql(u8, content, test_content)); |
| 113 | 113 | ||
| 114 | try fs.deleteFile(test_out_file); | 114 | try fs.cwd().deleteFile(test_out_file); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | test "thread local storage" { | 117 | test "thread local storage" { |
lib/std/os/wasi.zig+2-2| ... | @@ -12,8 +12,8 @@ comptime { | ... | @@ -12,8 +12,8 @@ comptime { |
| 12 | assert(@alignOf(u16) == 2); | 12 | assert(@alignOf(u16) == 2); |
| 13 | assert(@alignOf(i32) == 4); | 13 | assert(@alignOf(i32) == 4); |
| 14 | assert(@alignOf(u32) == 4); | 14 | assert(@alignOf(u32) == 4); |
| 15 | assert(@alignOf(i64) == 8); | 15 | // assert(@alignOf(i64) == 8); |
| 16 | assert(@alignOf(u64) == 8); | 16 | // assert(@alignOf(u64) == 8); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | pub const iovec_t = iovec; | 19 | pub const iovec_t = iovec; |
lib/std/parker.zig deleted-180| ... | @@ -1,180 +0,0 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const time = std.time; | ||
| 4 | const testing = std.testing; | ||
| 5 | const assert = std.debug.assert; | ||
| 6 | const SpinLock = std.SpinLock; | ||
| 7 | const linux = std.os.linux; | ||
| 8 | const windows = std.os.windows; | ||
| 9 | |||
| 10 | pub const ThreadParker = switch (builtin.os) { | ||
| 11 | .linux => if (builtin.link_libc) PosixParker else LinuxParker, | ||
| 12 | .windows => WindowsParker, | ||
| 13 | else => if (builtin.link_libc) PosixParker else SpinParker, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const SpinParker = struct { | ||
| 17 | pub fn init() SpinParker { | ||
| 18 | return SpinParker{}; | ||
| 19 | } | ||
| 20 | pub fn deinit(self: *SpinParker) void {} | ||
| 21 | |||
| 22 | pub fn unpark(self: *SpinParker, ptr: *const u32) void {} | ||
| 23 | |||
| 24 | pub fn park(self: *SpinParker, ptr: *const u32, expected: u32) void { | ||
| 25 | var backoff = SpinLock.Backoff.init(); | ||
| 26 | while (@atomicLoad(u32, ptr, .Acquire) == expected) | ||
| 27 | backoff.yield(); | ||
| 28 | } | ||
| 29 | }; | ||
| 30 | |||
| 31 | const LinuxParker = struct { | ||
| 32 | pub fn init() LinuxParker { | ||
| 33 | return LinuxParker{}; | ||
| 34 | } | ||
| 35 | pub fn deinit(self: *LinuxParker) void {} | ||
| 36 | |||
| 37 | pub fn unpark(self: *LinuxParker, ptr: *const u32) void { | ||
| 38 | const rc = linux.futex_wake(@ptrCast(*const i32, ptr), linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); | ||
| 39 | assert(linux.getErrno(rc) == 0); | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn park(self: *LinuxParker, ptr: *const u32, expected: u32) void { | ||
| 43 | const value = @intCast(i32, expected); | ||
| 44 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { | ||
| 45 | const rc = linux.futex_wait(@ptrCast(*const i32, ptr), linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, value, null); | ||
| 46 | switch (linux.getErrno(rc)) { | ||
| 47 | 0, linux.EAGAIN => return, | ||
| 48 | linux.EINTR => continue, | ||
| 49 | linux.EINVAL => unreachable, | ||
| 50 | else => continue, | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | |||
| 56 | const WindowsParker = struct { | ||
| 57 | waiters: u32, | ||
| 58 | |||
| 59 | pub fn init() WindowsParker { | ||
| 60 | return WindowsParker{ .waiters = 0 }; | ||
| 61 | } | ||
| 62 | pub fn deinit(self: *WindowsParker) void {} | ||
| 63 | |||
| 64 | pub fn unpark(self: *WindowsParker, ptr: *const u32) void { | ||
| 65 | const key = @ptrCast(*const c_void, ptr); | ||
| 66 | const handle = getEventHandle() orelse return; | ||
| 67 | |||
| 68 | var waiting = @atomicLoad(u32, &self.waiters, .Monotonic); | ||
| 69 | while (waiting != 0) { | ||
| 70 | waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse { | ||
| 71 | const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null); | ||
| 72 | assert(rc == 0); | ||
| 73 | return; | ||
| 74 | }; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void { | ||
| 79 | var spin = SpinLock.Backoff.init(); | ||
| 80 | const ev_handle = getEventHandle(); | ||
| 81 | const key = @ptrCast(*const c_void, ptr); | ||
| 82 | |||
| 83 | while (@atomicLoad(u32, ptr, .Monotonic) == expected) { | ||
| 84 | if (ev_handle) |handle| { | ||
| 85 | _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release); | ||
| 86 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null); | ||
| 87 | assert(rc == 0); | ||
| 88 | } else { | ||
| 89 | spin.yield(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | var event_handle = std.lazyInit(windows.HANDLE); | ||
| 95 | |||
| 96 | fn getEventHandle() ?windows.HANDLE { | ||
| 97 | if (event_handle.get()) |handle_ptr| | ||
| 98 | return handle_ptr.*; | ||
| 99 | defer event_handle.resolve(); | ||
| 100 | |||
| 101 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; | ||
| 102 | if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0) | ||
| 103 | return null; | ||
| 104 | return event_handle.data; | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | |||
| 108 | const PosixParker = struct { | ||
| 109 | cond: c.pthread_cond_t, | ||
| 110 | mutex: c.pthread_mutex_t, | ||
| 111 | |||
| 112 | const c = std.c; | ||
| 113 | |||
| 114 | pub fn init() PosixParker { | ||
| 115 | return PosixParker{ | ||
| 116 | .cond = c.PTHREAD_COND_INITIALIZER, | ||
| 117 | .mutex = c.PTHREAD_MUTEX_INITIALIZER, | ||
| 118 | }; | ||
| 119 | } | ||
| 120 | |||
| 121 | pub fn deinit(self: *PosixParker) void { | ||
| 122 | // On dragonfly, the destroy functions return EINVAL if they were initialized statically. | ||
| 123 | const retm = c.pthread_mutex_destroy(&self.mutex); | ||
| 124 | assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0)); | ||
| 125 | const retc = c.pthread_cond_destroy(&self.cond); | ||
| 126 | assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0)); | ||
| 127 | } | ||
| 128 | |||
| 129 | pub fn unpark(self: *PosixParker, ptr: *const u32) void { | ||
| 130 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 131 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 132 | assert(c.pthread_cond_signal(&self.cond) == 0); | ||
| 133 | } | ||
| 134 | |||
| 135 | pub fn park(self: *PosixParker, ptr: *const u32, expected: u32) void { | ||
| 136 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 137 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 138 | while (@atomicLoad(u32, ptr, .Acquire) == expected) | ||
| 139 | assert(c.pthread_cond_wait(&self.cond, &self.mutex) == 0); | ||
| 140 | } | ||
| 141 | }; | ||
| 142 | |||
| 143 | test "std.ThreadParker" { | ||
| 144 | if (builtin.single_threaded) | ||
| 145 | return error.SkipZigTest; | ||
| 146 | |||
| 147 | const Context = struct { | ||
| 148 | parker: ThreadParker, | ||
| 149 | data: u32, | ||
| 150 | |||
| 151 | fn receiver(self: *@This()) void { | ||
| 152 | self.parker.park(&self.data, 0); // receives 1 | ||
| 153 | assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2 | ||
| 154 | self.parker.unpark(&self.data); // wakes up waiters on 2 | ||
| 155 | self.parker.park(&self.data, 2); // receives 3 | ||
| 156 | assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4 | ||
| 157 | self.parker.unpark(&self.data); // wakes up waiters on 4 | ||
| 158 | } | ||
| 159 | |||
| 160 | fn sender(self: *@This()) void { | ||
| 161 | assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1 | ||
| 162 | self.parker.unpark(&self.data); // wakes up waiters on 1 | ||
| 163 | self.parker.park(&self.data, 1); // receives 2 | ||
| 164 | assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3 | ||
| 165 | self.parker.unpark(&self.data); // wakes up waiters on 3 | ||
| 166 | self.parker.park(&self.data, 3); // receives 4 | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | |||
| 170 | var context = Context{ | ||
| 171 | .parker = ThreadParker.init(), | ||
| 172 | .data = 0, | ||
| 173 | }; | ||
| 174 | defer context.parker.deinit(); | ||
| 175 | |||
| 176 | var receiver = try std.Thread.spawn(&context, Context.receiver); | ||
| 177 | defer receiver.wait(); | ||
| 178 | |||
| 179 | context.sender(); | ||
| 180 | } | ||
lib/std/pdb.zig+2-1| ... | @@ -6,6 +6,7 @@ const mem = std.mem; | ... | @@ -6,6 +6,7 @@ const mem = std.mem; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | const coff = std.coff; | 8 | const coff = std.coff; |
| 9 | const fs = std.fs; | ||
| 9 | const File = std.fs.File; | 10 | const File = std.fs.File; |
| 10 | 11 | ||
| 11 | const ArrayList = std.ArrayList; | 12 | const ArrayList = std.ArrayList; |
| ... | @@ -469,7 +470,7 @@ pub const Pdb = struct { | ... | @@ -469,7 +470,7 @@ pub const Pdb = struct { |
| 469 | msf: Msf, | 470 | msf: Msf, |
| 470 | 471 | ||
| 471 | pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void { | 472 | pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void { |
| 472 | self.in_file = try File.openRead(file_name); | 473 | self.in_file = try fs.cwd().openFile(file_name, .{}); |
| 473 | self.allocator = coff_ptr.allocator; | 474 | self.allocator = coff_ptr.allocator; |
| 474 | self.coff = coff_ptr; | 475 | self.coff = coff_ptr; |
| 475 | 476 |
lib/std/reset_event.zig created+433| ... | @@ -0,0 +1,433 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const testing = std.testing; | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | const Backoff = std.SpinLock.Backoff; | ||
| 6 | const c = std.c; | ||
| 7 | const os = std.os; | ||
| 8 | const time = std.time; | ||
| 9 | const linux = os.linux; | ||
| 10 | const windows = os.windows; | ||
| 11 | |||
| 12 | /// A resource object which supports blocking until signaled. | ||
| 13 | /// Once finished, the `deinit()` method should be called for correctness. | ||
| 14 | pub const ResetEvent = struct { | ||
| 15 | os_event: OsEvent, | ||
| 16 | |||
| 17 | pub fn init() ResetEvent { | ||
| 18 | return ResetEvent{ .os_event = OsEvent.init() }; | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn deinit(self: *ResetEvent) void { | ||
| 22 | self.os_event.deinit(); | ||
| 23 | self.* = undefined; | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Returns whether or not the event is currenetly set | ||
| 27 | pub fn isSet(self: *ResetEvent) bool { | ||
| 28 | return self.os_event.isSet(); | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Sets the event if not already set and | ||
| 32 | /// wakes up AT LEAST one thread waiting the event. | ||
| 33 | /// Returns whether or not a thread was woken up. | ||
| 34 | pub fn set(self: *ResetEvent, auto_reset: bool) bool { | ||
| 35 | return self.os_event.set(auto_reset); | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Resets the event to its original, unset state. | ||
| 39 | /// Returns whether or not the event was currently set before un-setting. | ||
| 40 | pub fn reset(self: *ResetEvent) bool { | ||
| 41 | return self.os_event.reset(); | ||
| 42 | } | ||
| 43 | |||
| 44 | const WaitError = error{ | ||
| 45 | /// The thread blocked longer than the maximum time specified. | ||
| 46 | TimedOut, | ||
| 47 | }; | ||
| 48 | |||
| 49 | /// Wait for the event to be set by blocking the current thread. | ||
| 50 | /// Optionally provided timeout in nanoseconds which throws an | ||
| 51 | /// `error.TimedOut` if the thread blocked AT LEAST longer than specified. | ||
| 52 | /// Returns whether or not the thread blocked from the event being unset at the time of calling. | ||
| 53 | pub fn wait(self: *ResetEvent, timeout_ns: ?u64) WaitError!bool { | ||
| 54 | return self.os_event.wait(timeout_ns); | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | |||
| 58 | const OsEvent = if (builtin.single_threaded) DebugEvent else switch (builtin.os) { | ||
| 59 | .windows => WindowsEvent, | ||
| 60 | .linux => if (builtin.link_libc) PosixEvent else LinuxEvent, | ||
| 61 | else => if (builtin.link_libc) PosixEvent else SpinEvent, | ||
| 62 | }; | ||
| 63 | |||
| 64 | const DebugEvent = struct { | ||
| 65 | is_set: @typeOf(set_init), | ||
| 66 | |||
| 67 | const set_init = if (std.debug.runtime_safety) false else {}; | ||
| 68 | |||
| 69 | pub fn init() DebugEvent { | ||
| 70 | return DebugEvent{ .is_set = set_init }; | ||
| 71 | } | ||
| 72 | |||
| 73 | pub fn deinit(self: *DebugEvent) void { | ||
| 74 | self.* = undefined; | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn isSet(self: *DebugEvent) bool { | ||
| 78 | if (!std.debug.runtime_safety) | ||
| 79 | return true; | ||
| 80 | return self.is_set; | ||
| 81 | } | ||
| 82 | |||
| 83 | pub fn set(self: *DebugEvent, auto_reset: bool) bool { | ||
| 84 | if (std.debug.runtime_safety) | ||
| 85 | self.is_set = !auto_reset; | ||
| 86 | return false; | ||
| 87 | } | ||
| 88 | |||
| 89 | pub fn reset(self: *DebugEvent) bool { | ||
| 90 | if (!std.debug.runtime_safety) | ||
| 91 | return false; | ||
| 92 | const was_set = self.is_set; | ||
| 93 | self.is_set = false; | ||
| 94 | return was_set; | ||
| 95 | } | ||
| 96 | |||
| 97 | pub fn wait(self: *DebugEvent, timeout: ?u64) ResetEvent.WaitError!bool { | ||
| 98 | if (std.debug.runtime_safety and !self.is_set) | ||
| 99 | @panic("deadlock detected"); | ||
| 100 | return ResetEvent.WaitError.TimedOut; | ||
| 101 | } | ||
| 102 | }; | ||
| 103 | |||
| 104 | fn AtomicEvent(comptime FutexImpl: type) type { | ||
| 105 | return struct { | ||
| 106 | state: u32, | ||
| 107 | |||
| 108 | const IS_SET: u32 = 1 << 0; | ||
| 109 | const WAIT_MASK = ~IS_SET; | ||
| 110 | |||
| 111 | pub const Self = @This(); | ||
| 112 | pub const Futex = FutexImpl; | ||
| 113 | |||
| 114 | pub fn init() Self { | ||
| 115 | return Self{ .state = 0 }; | ||
| 116 | } | ||
| 117 | |||
| 118 | pub fn deinit(self: *Self) void { | ||
| 119 | self.* = undefined; | ||
| 120 | } | ||
| 121 | |||
| 122 | pub fn isSet(self: *const Self) bool { | ||
| 123 | const state = @atomicLoad(u32, &self.state, .Acquire); | ||
| 124 | return (state & IS_SET) != 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | pub fn reset(self: *Self) bool { | ||
| 128 | const old_state = @atomicRmw(u32, &self.state, .Xchg, 0, .Monotonic); | ||
| 129 | return (old_state & IS_SET) != 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | pub fn set(self: *Self, auto_reset: bool) bool { | ||
| 133 | const new_state = if (auto_reset) 0 else IS_SET; | ||
| 134 | const old_state = @atomicRmw(u32, &self.state, .Xchg, new_state, .Release); | ||
| 135 | if ((old_state & WAIT_MASK) == 0) { | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | Futex.wake(&self.state); | ||
| 140 | return true; | ||
| 141 | } | ||
| 142 | |||
| 143 | pub fn wait(self: *Self, timeout: ?u64) ResetEvent.WaitError!bool { | ||
| 144 | var dummy_value: u32 = undefined; | ||
| 145 | const wait_token = @truncate(u32, @ptrToInt(&dummy_value)); | ||
| 146 | |||
| 147 | var state = @atomicLoad(u32, &self.state, .Monotonic); | ||
| 148 | while (true) { | ||
| 149 | if ((state & IS_SET) != 0) | ||
| 150 | return false; | ||
| 151 | state = @cmpxchgWeak(u32, &self.state, state, wait_token, .Acquire, .Monotonic) orelse break; | ||
| 152 | } | ||
| 153 | |||
| 154 | try Futex.wait(&self.state, wait_token, timeout); | ||
| 155 | return true; | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | } | ||
| 159 | |||
| 160 | const SpinEvent = AtomicEvent(struct { | ||
| 161 | fn wake(ptr: *const u32) void {} | ||
| 162 | |||
| 163 | fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void { | ||
| 164 | // TODO: handle platforms where time.Timer.start() fails | ||
| 165 | var spin = Backoff.init(); | ||
| 166 | var timer = if (timeout == null) null else time.Timer.start() catch unreachable; | ||
| 167 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { | ||
| 168 | spin.yield(); | ||
| 169 | if (timeout) |timeout_ns| { | ||
| 170 | if (timer.?.read() > timeout_ns) | ||
| 171 | return ResetEvent.WaitError.TimedOut; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | }); | ||
| 176 | |||
| 177 | const LinuxEvent = AtomicEvent(struct { | ||
| 178 | fn wake(ptr: *const u32) void { | ||
| 179 | const key = @ptrCast(*const i32, ptr); | ||
| 180 | const rc = linux.futex_wake(key, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); | ||
| 181 | assert(linux.getErrno(rc) == 0); | ||
| 182 | } | ||
| 183 | |||
| 184 | fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void { | ||
| 185 | var ts: linux.timespec = undefined; | ||
| 186 | var ts_ptr: ?*linux.timespec = null; | ||
| 187 | if (timeout) |timeout_ns| { | ||
| 188 | ts_ptr = &ts; | ||
| 189 | ts.tv_sec = @intCast(isize, timeout_ns / time.ns_per_s); | ||
| 190 | ts.tv_nsec = @intCast(isize, timeout_ns % time.ns_per_s); | ||
| 191 | } | ||
| 192 | |||
| 193 | const key = @ptrCast(*const i32, ptr); | ||
| 194 | const key_expect = @bitCast(i32, expected); | ||
| 195 | while (@atomicLoad(i32, key, .Acquire) == key_expect) { | ||
| 196 | const rc = linux.futex_wait(key, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, key_expect, ts_ptr); | ||
| 197 | switch (linux.getErrno(rc)) { | ||
| 198 | 0, linux.EAGAIN => break, | ||
| 199 | linux.EINTR => continue, | ||
| 200 | linux.ETIMEDOUT => return ResetEvent.WaitError.TimedOut, | ||
| 201 | else => unreachable, | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | }); | ||
| 206 | |||
| 207 | const WindowsEvent = AtomicEvent(struct { | ||
| 208 | fn wake(ptr: *const u32) void { | ||
| 209 | if (getEventHandle()) |handle| { | ||
| 210 | const key = @ptrCast(*const c_void, ptr); | ||
| 211 | const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null); | ||
| 212 | assert(rc == 0); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void { | ||
| 217 | // fallback to spinlock if NT Keyed Events arent available | ||
| 218 | const handle = getEventHandle() orelse { | ||
| 219 | return SpinEvent.Futex.wait(ptr, expected, timeout); | ||
| 220 | }; | ||
| 221 | |||
| 222 | // NT uses timeouts in units of 100ns with negative value being relative | ||
| 223 | var timeout_ptr: ?*windows.LARGE_INTEGER = null; | ||
| 224 | var timeout_value: windows.LARGE_INTEGER = undefined; | ||
| 225 | if (timeout) |timeout_ns| { | ||
| 226 | timeout_ptr = &timeout_value; | ||
| 227 | timeout_value = -@intCast(windows.LARGE_INTEGER, timeout_ns / 100); | ||
| 228 | } | ||
| 229 | |||
| 230 | // NtWaitForKeyedEvent doesnt have spurious wake-ups | ||
| 231 | if (@atomicLoad(u32, ptr, .Acquire) == expected) { | ||
| 232 | const key = @ptrCast(*const c_void, ptr); | ||
| 233 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, timeout_ptr); | ||
| 234 | switch (rc) { | ||
| 235 | 0 => {}, | ||
| 236 | windows.WAIT_TIMEOUT => return ResetEvent.WaitError.TimedOut, | ||
| 237 | else => unreachable, | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | var keyed_state = State.Uninitialized; | ||
| 243 | var keyed_handle: ?windows.HANDLE = null; | ||
| 244 | |||
| 245 | const State = enum(u8) { | ||
| 246 | Uninitialized, | ||
| 247 | Intializing, | ||
| 248 | Initialized, | ||
| 249 | }; | ||
| 250 | |||
| 251 | fn getEventHandle() ?windows.HANDLE { | ||
| 252 | var spin = Backoff.init(); | ||
| 253 | var state = @atomicLoad(State, &keyed_state, .Monotonic); | ||
| 254 | |||
| 255 | while (true) { | ||
| 256 | switch (state) { | ||
| 257 | .Initialized => { | ||
| 258 | return keyed_handle; | ||
| 259 | }, | ||
| 260 | .Intializing => { | ||
| 261 | spin.yield(); | ||
| 262 | state = @atomicLoad(State, &keyed_state, .Acquire); | ||
| 263 | }, | ||
| 264 | .Uninitialized => state = @cmpxchgWeak(State, &keyed_state, state, .Intializing, .Acquire, .Monotonic) orelse { | ||
| 265 | var handle: windows.HANDLE = undefined; | ||
| 266 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; | ||
| 267 | if (windows.ntdll.NtCreateKeyedEvent(&handle, access_mask, null, 0) == 0) | ||
| 268 | keyed_handle = handle; | ||
| 269 | @atomicStore(State, &keyed_state, .Initialized, .Release); | ||
| 270 | return keyed_handle; | ||
| 271 | }, | ||
| 272 | } | ||
| 273 | } | ||
| 274 | } | ||
| 275 | }); | ||
| 276 | |||
| 277 | const PosixEvent = struct { | ||
| 278 | state: u32, | ||
| 279 | cond: c.pthread_cond_t, | ||
| 280 | mutex: c.pthread_mutex_t, | ||
| 281 | |||
| 282 | const IS_SET: u32 = 1; | ||
| 283 | |||
| 284 | pub fn init() PosixEvent { | ||
| 285 | return PosixEvent{ | ||
| 286 | .state = .0, | ||
| 287 | .cond = c.PTHREAD_COND_INITIALIZER, | ||
| 288 | .mutex = c.PTHREAD_MUTEX_INITIALIZER, | ||
| 289 | }; | ||
| 290 | } | ||
| 291 | |||
| 292 | pub fn deinit(self: *PosixEvent) void { | ||
| 293 | // On dragonfly, the destroy functions return EINVAL if they were initialized statically. | ||
| 294 | const retm = c.pthread_mutex_destroy(&self.mutex); | ||
| 295 | assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0)); | ||
| 296 | const retc = c.pthread_cond_destroy(&self.cond); | ||
| 297 | assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0)); | ||
| 298 | } | ||
| 299 | |||
| 300 | pub fn isSet(self: *PosixEvent) bool { | ||
| 301 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 302 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 303 | |||
| 304 | return self.state == IS_SET; | ||
| 305 | } | ||
| 306 | |||
| 307 | pub fn reset(self: *PosixEvent) bool { | ||
| 308 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 309 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 310 | |||
| 311 | const was_set = self.state == IS_SET; | ||
| 312 | self.state = 0; | ||
| 313 | return was_set; | ||
| 314 | } | ||
| 315 | |||
| 316 | pub fn set(self: *PosixEvent, auto_reset: bool) bool { | ||
| 317 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 318 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 319 | |||
| 320 | const had_waiter = self.state > IS_SET; | ||
| 321 | self.state = if (auto_reset) 0 else IS_SET; | ||
| 322 | if (had_waiter) { | ||
| 323 | assert(c.pthread_cond_signal(&self.cond) == 0); | ||
| 324 | } | ||
| 325 | return had_waiter; | ||
| 326 | } | ||
| 327 | |||
| 328 | pub fn wait(self: *PosixEvent, timeout: ?u64) ResetEvent.WaitError!bool { | ||
| 329 | assert(c.pthread_mutex_lock(&self.mutex) == 0); | ||
| 330 | defer assert(c.pthread_mutex_unlock(&self.mutex) == 0); | ||
| 331 | |||
| 332 | if (self.state == IS_SET) | ||
| 333 | return false; | ||
| 334 | |||
| 335 | var ts: os.timespec = undefined; | ||
| 336 | if (timeout) |timeout_ns| { | ||
| 337 | var timeout_abs = timeout_ns; | ||
| 338 | if (comptime std.Target.current.isDarwin()) { | ||
| 339 | var tv: os.darwin.timeval = undefined; | ||
| 340 | assert(os.darwin.gettimeofday(&tv, null) == 0); | ||
| 341 | timeout_abs += @intCast(u64, tv.tv_sec) * time.second; | ||
| 342 | timeout_abs += @intCast(u64, tv.tv_usec) * time.microsecond; | ||
| 343 | } else { | ||
| 344 | os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable; | ||
| 345 | timeout_abs += @intCast(u64, ts.tv_sec) * time.second; | ||
| 346 | timeout_abs += @intCast(u64, ts.tv_nsec); | ||
| 347 | } | ||
| 348 | ts.tv_sec = @intCast(@typeOf(ts.tv_sec), @divFloor(timeout_abs, time.second)); | ||
| 349 | ts.tv_nsec = @intCast(@typeOf(ts.tv_nsec), @mod(timeout_abs, time.second)); | ||
| 350 | } | ||
| 351 | |||
| 352 | var dummy_value: u32 = undefined; | ||
| 353 | var wait_token = @truncate(u32, @ptrToInt(&dummy_value)); | ||
| 354 | self.state = wait_token; | ||
| 355 | |||
| 356 | while (self.state == wait_token) { | ||
| 357 | const rc = switch (timeout == null) { | ||
| 358 | true => c.pthread_cond_wait(&self.cond, &self.mutex), | ||
| 359 | else => c.pthread_cond_timedwait(&self.cond, &self.mutex, &ts), | ||
| 360 | }; | ||
| 361 | // TODO: rc appears to be the positive error code making os.errno() always return 0 on linux | ||
| 362 | switch (std.math.max(@as(c_int, os.errno(rc)), rc)) { | ||
| 363 | 0 => {}, | ||
| 364 | os.ETIMEDOUT => return ResetEvent.WaitError.TimedOut, | ||
| 365 | os.EINVAL => unreachable, | ||
| 366 | os.EPERM => unreachable, | ||
| 367 | else => unreachable, | ||
| 368 | } | ||
| 369 | } | ||
| 370 | return true; | ||
| 371 | } | ||
| 372 | }; | ||
| 373 | |||
| 374 | test "std.ResetEvent" { | ||
| 375 | // TODO | ||
| 376 | if (builtin.single_threaded) | ||
| 377 | return error.SkipZigTest; | ||
| 378 | |||
| 379 | var event = ResetEvent.init(); | ||
| 380 | defer event.deinit(); | ||
| 381 | |||
| 382 | // test event setting | ||
| 383 | testing.expect(event.isSet() == false); | ||
| 384 | testing.expect(event.set(false) == false); | ||
| 385 | testing.expect(event.isSet() == true); | ||
| 386 | |||
| 387 | // test event resetting | ||
| 388 | testing.expect(event.reset() == true); | ||
| 389 | testing.expect(event.isSet() == false); | ||
| 390 | testing.expect(event.reset() == false); | ||
| 391 | |||
| 392 | // test cross thread signaling | ||
| 393 | const Context = struct { | ||
| 394 | event: ResetEvent, | ||
| 395 | value: u128, | ||
| 396 | |||
| 397 | fn receiver(self: *@This()) void { | ||
| 398 | // wait for the sender to notify us with updated value | ||
| 399 | assert(self.value == 0); | ||
| 400 | assert((self.event.wait(1 * time.second) catch unreachable) == true); | ||
| 401 | assert(self.value == 1); | ||
| 402 | |||
| 403 | // wait for sender to sleep, then notify it of new value | ||
| 404 | time.sleep(50 * time.millisecond); | ||
| 405 | self.value = 2; | ||
| 406 | assert(self.event.set(false) == true); | ||
| 407 | } | ||
| 408 | |||
| 409 | fn sender(self: *@This()) !void { | ||
| 410 | // wait for the receiver() to start wait()'ing | ||
| 411 | time.sleep(50 * time.millisecond); | ||
| 412 | |||
| 413 | // update value to 1 and notify the receiver() | ||
| 414 | assert(self.value == 0); | ||
| 415 | self.value = 1; | ||
| 416 | assert(self.event.set(true) == true); | ||
| 417 | |||
| 418 | // wait for the receiver to update the value & notify us | ||
| 419 | assert((try self.event.wait(1 * time.second)) == true); | ||
| 420 | assert(self.value == 2); | ||
| 421 | } | ||
| 422 | }; | ||
| 423 | |||
| 424 | _ = event.reset(); | ||
| 425 | var context = Context{ | ||
| 426 | .event = event, | ||
| 427 | .value = 0, | ||
| 428 | }; | ||
| 429 | |||
| 430 | var receiver = try std.Thread.spawn(&context, Context.receiver); | ||
| 431 | defer receiver.wait(); | ||
| 432 | try context.sender(); | ||
| 433 | } | ||
| \ No newline at end of file | |||
lib/std/special/c.zig+43| ... | @@ -197,6 +197,49 @@ extern fn __stack_chk_fail() noreturn { | ... | @@ -197,6 +197,49 @@ extern fn __stack_chk_fail() noreturn { |
| 197 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. | 197 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. |
| 198 | nakedcc fn clone() void { | 198 | nakedcc fn clone() void { |
| 199 | switch (builtin.arch) { | 199 | switch (builtin.arch) { |
| 200 | .i386 => { | ||
| 201 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | ||
| 202 | // +8, +12, +16, +20, +24, +28, +32 | ||
| 203 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) | ||
| 204 | // eax, ebx, ecx, edx, esi, edi | ||
| 205 | asm volatile ( | ||
| 206 | \\ push %%ebp | ||
| 207 | \\ mov %%esp,%%ebp | ||
| 208 | \\ push %%ebx | ||
| 209 | \\ push %%esi | ||
| 210 | \\ push %%edi | ||
| 211 | \\ // Setup the arguments | ||
| 212 | \\ mov 16(%%ebp),%%ebx | ||
| 213 | \\ mov 12(%%ebp),%%ecx | ||
| 214 | \\ and $-16,%%ecx | ||
| 215 | \\ sub $20,%%ecx | ||
| 216 | \\ mov 20(%%ebp),%%eax | ||
| 217 | \\ mov %%eax,4(%%ecx) | ||
| 218 | \\ mov 8(%%ebp),%%eax | ||
| 219 | \\ mov %%eax,0(%%ecx) | ||
| 220 | \\ mov 24(%%ebp),%%edx | ||
| 221 | \\ mov 28(%%ebp),%%esi | ||
| 222 | \\ mov 32(%%ebp),%%edi | ||
| 223 | \\ mov $120,%%eax | ||
| 224 | \\ int $128 | ||
| 225 | \\ test %%eax,%%eax | ||
| 226 | \\ jnz 1f | ||
| 227 | \\ pop %%eax | ||
| 228 | \\ xor %%ebp,%%ebp | ||
| 229 | \\ call *%%eax | ||
| 230 | \\ mov %%eax,%%ebx | ||
| 231 | \\ xor %%eax,%%eax | ||
| 232 | \\ inc %%eax | ||
| 233 | \\ int $128 | ||
| 234 | \\ hlt | ||
| 235 | \\1: | ||
| 236 | \\ pop %%edi | ||
| 237 | \\ pop %%esi | ||
| 238 | \\ pop %%ebx | ||
| 239 | \\ pop %%ebp | ||
| 240 | \\ ret | ||
| 241 | ); | ||
| 242 | }, | ||
| 200 | .x86_64 => { | 243 | .x86_64 => { |
| 201 | asm volatile ( | 244 | asm volatile ( |
| 202 | \\ xor %%eax,%%eax | 245 | \\ xor %%eax,%%eax |
lib/std/std.zig+1-1| ... | @@ -16,6 +16,7 @@ pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; | ... | @@ -16,6 +16,7 @@ pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; |
| 16 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; | 16 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; |
| 17 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; | 17 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 18 | pub const Progress = @import("progress.zig").Progress; | 18 | pub const Progress = @import("progress.zig").Progress; |
| 19 | pub const ResetEvent = @import("reset_event.zig").ResetEvent; | ||
| 19 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; | 20 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 20 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; | 21 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; |
| 21 | pub const SpinLock = @import("spinlock.zig").SpinLock; | 22 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| ... | @@ -23,7 +24,6 @@ pub const StringHashMap = @import("hash_map.zig").StringHashMap; | ... | @@ -23,7 +24,6 @@ pub const StringHashMap = @import("hash_map.zig").StringHashMap; |
| 23 | pub const TailQueue = @import("linked_list.zig").TailQueue; | 24 | pub const TailQueue = @import("linked_list.zig").TailQueue; |
| 24 | pub const Target = @import("target.zig").Target; | 25 | pub const Target = @import("target.zig").Target; |
| 25 | pub const Thread = @import("thread.zig").Thread; | 26 | pub const Thread = @import("thread.zig").Thread; |
| 26 | pub const ThreadParker = @import("parker.zig").ThreadParker; | ||
| 27 | 27 | ||
| 28 | pub const atomic = @import("atomic.zig"); | 28 | pub const atomic = @import("atomic.zig"); |
| 29 | pub const base64 = @import("base64.zig"); | 29 | pub const base64 = @import("base64.zig"); |
lib/std/testing.zig+33-1| ... | @@ -89,7 +89,26 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { | ... | @@ -89,7 +89,26 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { |
| 89 | if (union_info.tag_type == null) { | 89 | if (union_info.tag_type == null) { |
| 90 | @compileError("Unable to compare untagged union values"); | 90 | @compileError("Unable to compare untagged union values"); |
| 91 | } | 91 | } |
| 92 | @compileError("TODO implement testing.expectEqual for tagged unions"); | 92 | |
| 93 | const TagType = @TagType(@typeOf(expected)); | ||
| 94 | |||
| 95 | const expectedTag = @as(TagType, expected); | ||
| 96 | const actualTag = @as(TagType, actual); | ||
| 97 | |||
| 98 | expectEqual(expectedTag, actualTag); | ||
| 99 | |||
| 100 | // we only reach this loop if the tags are equal | ||
| 101 | inline for (std.meta.fields(@typeOf(actual))) |fld| { | ||
| 102 | if (std.mem.eql(u8, fld.name, @tagName(actualTag))) { | ||
| 103 | expectEqual(@field(expected, fld.name), @field(actual, fld.name)); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | // we iterate over *all* union fields | ||
| 109 | // => we should never get here as the loop above is | ||
| 110 | // including all possible values. | ||
| 111 | unreachable; | ||
| 93 | }, | 112 | }, |
| 94 | 113 | ||
| 95 | .Optional => { | 114 | .Optional => { |
| ... | @@ -124,6 +143,19 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { | ... | @@ -124,6 +143,19 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { |
| 124 | } | 143 | } |
| 125 | } | 144 | } |
| 126 | 145 | ||
| 146 | test "expectEqual.union(enum)" | ||
| 147 | { | ||
| 148 | const T = union(enum) { | ||
| 149 | a: i32, | ||
| 150 | b: f32, | ||
| 151 | }; | ||
| 152 | |||
| 153 | const a10 = T { .a = 10 }; | ||
| 154 | const a20 = T { .a = 20 }; | ||
| 155 | |||
| 156 | expectEqual(a10, a10); | ||
| 157 | } | ||
| 158 | |||
| 127 | /// This function is intended to be used only in tests. When the two slices are not | 159 | /// This function is intended to be used only in tests. When the two slices are not |
| 128 | /// equal, prints diagnostics to stderr to show exactly how they are not equal, | 160 | /// equal, prints diagnostics to stderr to show exactly how they are not equal, |
| 129 | /// then aborts. | 161 | /// then aborts. |
lib/std/thread.zig+29-2| ... | @@ -314,11 +314,38 @@ pub const Thread = struct { | ... | @@ -314,11 +314,38 @@ pub const Thread = struct { |
| 314 | os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID | | 314 | os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID | |
| 315 | os.CLONE_DETACHED; | 315 | os.CLONE_DETACHED; |
| 316 | var newtls: usize = undefined; | 316 | var newtls: usize = undefined; |
| 317 | // This structure is only needed when targeting i386 | ||
| 318 | var user_desc: if (builtin.arch == .i386) os.linux.user_desc else void = undefined; | ||
| 319 | |||
| 317 | if (os.linux.tls.tls_image) |tls_img| { | 320 | if (os.linux.tls.tls_image) |tls_img| { |
| 318 | newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset); | 321 | if (builtin.arch == .i386) { |
| 322 | user_desc = os.linux.user_desc{ | ||
| 323 | .entry_number = tls_img.gdt_entry_number, | ||
| 324 | .base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset), | ||
| 325 | .limit = 0xfffff, | ||
| 326 | .seg_32bit = 1, | ||
| 327 | .contents = 0, // Data | ||
| 328 | .read_exec_only = 0, | ||
| 329 | .limit_in_pages = 1, | ||
| 330 | .seg_not_present = 0, | ||
| 331 | .useable = 1, | ||
| 332 | }; | ||
| 333 | newtls = @ptrToInt(&user_desc); | ||
| 334 | } else { | ||
| 335 | newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset); | ||
| 336 | } | ||
| 319 | flags |= os.CLONE_SETTLS; | 337 | flags |= os.CLONE_SETTLS; |
| 320 | } | 338 | } |
| 321 | const rc = os.linux.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); | 339 | |
| 340 | const rc = os.linux.clone( | ||
| 341 | MainFuncs.linuxThreadMain, | ||
| 342 | mmap_addr + stack_end_offset, | ||
| 343 | flags, | ||
| 344 | arg, | ||
| 345 | &thread_ptr.data.handle, | ||
| 346 | newtls, | ||
| 347 | &thread_ptr.data.handle, | ||
| 348 | ); | ||
| 322 | switch (os.errno(rc)) { | 349 | switch (os.errno(rc)) { |
| 323 | 0 => return thread_ptr, | 350 | 0 => return thread_ptr, |
| 324 | os.EAGAIN => return error.ThreadQuotaExceeded, | 351 | os.EAGAIN => return error.ThreadQuotaExceeded, |
src-self-hosted/codegen.zig+15-15| ... | @@ -25,10 +25,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -25,10 +25,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 25 | 25 | ||
| 26 | const context = llvm_handle.node.data; | 26 | const context = llvm_handle.node.data; |
| 27 | 27 | ||
| 28 | const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory; | 28 | const module = llvm.ModuleCreateWithNameInContext(comp.name.toSliceConst(), context) orelse return error.OutOfMemory; |
| 29 | defer llvm.DisposeModule(module); | 29 | defer llvm.DisposeModule(module); |
| 30 | 30 | ||
| 31 | llvm.SetTarget(module, comp.llvm_triple.ptr()); | 31 | llvm.SetTarget(module, comp.llvm_triple.toSliceConst()); |
| 32 | llvm.SetDataLayout(module, comp.target_layout_str); | 32 | llvm.SetDataLayout(module, comp.target_layout_str); |
| 33 | 33 | ||
| 34 | if (util.getObjectFormat(comp.target) == .coff) { | 34 | if (util.getObjectFormat(comp.target) == .coff) { |
| ... | @@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 48 | const producer = try std.Buffer.allocPrint( | 48 | const producer = try std.Buffer.allocPrint( |
| 49 | &code.arena.allocator, | 49 | &code.arena.allocator, |
| 50 | "zig {}.{}.{}", | 50 | "zig {}.{}.{}", |
| 51 | u32(c.ZIG_VERSION_MAJOR), | 51 | @as(u32, c.ZIG_VERSION_MAJOR), |
| 52 | u32(c.ZIG_VERSION_MINOR), | 52 | @as(u32, c.ZIG_VERSION_MINOR), |
| 53 | u32(c.ZIG_VERSION_PATCH), | 53 | @as(u32, c.ZIG_VERSION_PATCH), |
| 54 | ); | 54 | ); |
| 55 | const flags = ""; | 55 | const flags = ""; |
| 56 | const runtime_version = 0; | 56 | const runtime_version = 0; |
| 57 | const compile_unit_file = llvm.CreateFile( | 57 | const compile_unit_file = llvm.CreateFile( |
| 58 | dibuilder, | 58 | dibuilder, |
| 59 | comp.name.ptr(), | 59 | comp.name.toSliceConst(), |
| 60 | comp.root_package.root_src_dir.ptr(), | 60 | comp.root_package.root_src_dir.toSliceConst(), |
| 61 | ) orelse return error.OutOfMemory; | 61 | ) orelse return error.OutOfMemory; |
| 62 | const is_optimized = comp.build_mode != .Debug; | 62 | const is_optimized = comp.build_mode != .Debug; |
| 63 | const compile_unit = llvm.CreateCompileUnit( | 63 | const compile_unit = llvm.CreateCompileUnit( |
| 64 | dibuilder, | 64 | dibuilder, |
| 65 | DW.LANG_C99, | 65 | DW.LANG_C99, |
| 66 | compile_unit_file, | 66 | compile_unit_file, |
| 67 | producer.ptr(), | 67 | producer.toSliceConst(), |
| 68 | is_optimized, | 68 | is_optimized, |
| 69 | flags, | 69 | flags, |
| 70 | runtime_version, | 70 | runtime_version, |
| ... | @@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 99 | 99 | ||
| 100 | // verify the llvm module when safety is on | 100 | // verify the llvm module when safety is on |
| 101 | if (std.debug.runtime_safety) { | 101 | if (std.debug.runtime_safety) { |
| 102 | var error_ptr: ?[*]u8 = null; | 102 | var error_ptr: ?[*:0]u8 = null; |
| 103 | _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); | 103 | _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| ... | @@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 108 | const is_small = comp.build_mode == .ReleaseSmall; | 108 | const is_small = comp.build_mode == .ReleaseSmall; |
| 109 | const is_debug = comp.build_mode == .Debug; | 109 | const is_debug = comp.build_mode == .Debug; |
| 110 | 110 | ||
| 111 | var err_msg: [*]u8 = undefined; | 111 | var err_msg: [*:0]u8 = undefined; |
| 112 | // TODO integrate this with evented I/O | 112 | // TODO integrate this with evented I/O |
| 113 | if (llvm.TargetMachineEmitToFile( | 113 | if (llvm.TargetMachineEmitToFile( |
| 114 | comp.target_machine, | 114 | comp.target_machine, |
| 115 | module, | 115 | module, |
| 116 | output_path.ptr(), | 116 | output_path.toSliceConst(), |
| 117 | llvm.EmitBinary, | 117 | llvm.EmitBinary, |
| 118 | &err_msg, | 118 | &err_msg, |
| 119 | is_debug, | 119 | is_debug, |
| ... | @@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) |
| 154 | const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context); | 154 | const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context); |
| 155 | const llvm_fn = llvm.AddFunction( | 155 | const llvm_fn = llvm.AddFunction( |
| 156 | ofile.module, | 156 | ofile.module, |
| 157 | fn_val.symbol_name.ptr(), | 157 | fn_val.symbol_name.toSliceConst(), |
| 158 | llvm_fn_type, | 158 | llvm_fn_type, |
| 159 | ) orelse return error.OutOfMemory; | 159 | ) orelse return error.OutOfMemory; |
| 160 | 160 | ||
| ... | @@ -379,7 +379,7 @@ fn renderLoadUntyped( | ... | @@ -379,7 +379,7 @@ fn renderLoadUntyped( |
| 379 | ptr: *llvm.Value, | 379 | ptr: *llvm.Value, |
| 380 | alignment: Type.Pointer.Align, | 380 | alignment: Type.Pointer.Align, |
| 381 | vol: Type.Pointer.Vol, | 381 | vol: Type.Pointer.Vol, |
| 382 | name: [*]const u8, | 382 | name: [*:0]const u8, |
| 383 | ) !*llvm.Value { | 383 | ) !*llvm.Value { |
| 384 | const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; | 384 | const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; |
| 385 | switch (vol) { | 385 | switch (vol) { |
| ... | @@ -390,7 +390,7 @@ fn renderLoadUntyped( | ... | @@ -390,7 +390,7 @@ fn renderLoadUntyped( |
| 390 | return result; | 390 | return result; |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value { | 393 | fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*:0]const u8) !*llvm.Value { |
| 394 | return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); | 394 | return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); |
| 395 | } | 395 | } |
| 396 | 396 | ||
| ... | @@ -438,7 +438,7 @@ pub fn renderAlloca( | ... | @@ -438,7 +438,7 @@ pub fn renderAlloca( |
| 438 | ) !*llvm.Value { | 438 | ) !*llvm.Value { |
| 439 | const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); | 439 | const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); |
| 440 | const name_with_null = try std.cstr.addNullByte(ofile.arena, name); | 440 | const name_with_null = try std.cstr.addNullByte(ofile.arena, name); |
| 441 | const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory; | 441 | const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, @ptrCast([*:0]const u8, name_with_null.ptr)) orelse return error.OutOfMemory; |
| 442 | llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type)); | 442 | llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type)); |
| 443 | return result; | 443 | return result; |
| 444 | } | 444 | } |
src-self-hosted/compilation.zig+127-151| ... | @@ -93,7 +93,7 @@ pub const ZigCompiler = struct { | ... | @@ -93,7 +93,7 @@ pub const ZigCompiler = struct { |
| 93 | return LlvmHandle{ .node = node }; | 93 | return LlvmHandle{ .node = node }; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | pub async fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { | 96 | pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { |
| 97 | if (self.native_libc.start()) |ptr| return ptr; | 97 | if (self.native_libc.start()) |ptr| return ptr; |
| 98 | try self.native_libc.data.findNative(self.allocator); | 98 | try self.native_libc.data.findNative(self.allocator); |
| 99 | self.native_libc.resolve(); | 99 | self.native_libc.resolve(); |
| ... | @@ -133,62 +133,62 @@ pub const Compilation = struct { | ... | @@ -133,62 +133,62 @@ pub const Compilation = struct { |
| 133 | zig_std_dir: []const u8, | 133 | zig_std_dir: []const u8, |
| 134 | 134 | ||
| 135 | /// lazily created when we need it | 135 | /// lazily created when we need it |
| 136 | tmp_dir: event.Future(BuildError![]u8), | 136 | tmp_dir: event.Future(BuildError![]u8) = event.Future(BuildError![]u8).init(), |
| 137 | 137 | ||
| 138 | version_major: u32, | 138 | version_major: u32 = 0, |
| 139 | version_minor: u32, | 139 | version_minor: u32 = 0, |
| 140 | version_patch: u32, | 140 | version_patch: u32 = 0, |
| 141 | 141 | ||
| 142 | linker_script: ?[]const u8, | 142 | linker_script: ?[]const u8 = null, |
| 143 | out_h_path: ?[]const u8, | 143 | out_h_path: ?[]const u8 = null, |
| 144 | 144 | ||
| 145 | is_test: bool, | 145 | is_test: bool = false, |
| 146 | each_lib_rpath: bool, | 146 | each_lib_rpath: bool = false, |
| 147 | strip: bool, | 147 | strip: bool = false, |
| 148 | is_static: bool, | 148 | is_static: bool, |
| 149 | linker_rdynamic: bool, | 149 | linker_rdynamic: bool = false, |
| 150 | 150 | ||
| 151 | clang_argv: []const []const u8, | 151 | clang_argv: []const []const u8 = [_][]const u8{}, |
| 152 | lib_dirs: []const []const u8, | 152 | lib_dirs: []const []const u8 = [_][]const u8{}, |
| 153 | rpath_list: []const []const u8, | 153 | rpath_list: []const []const u8 = [_][]const u8{}, |
| 154 | assembly_files: []const []const u8, | 154 | assembly_files: []const []const u8 = [_][]const u8{}, |
| 155 | 155 | ||
| 156 | /// paths that are explicitly provided by the user to link against | 156 | /// paths that are explicitly provided by the user to link against |
| 157 | link_objects: []const []const u8, | 157 | link_objects: []const []const u8 = [_][]const u8{}, |
| 158 | 158 | ||
| 159 | /// functions that have their own objects that we need to link | 159 | /// functions that have their own objects that we need to link |
| 160 | /// it uses an optional pointer so that tombstone removals are possible | 160 | /// it uses an optional pointer so that tombstone removals are possible |
| 161 | fn_link_set: event.Locked(FnLinkSet), | 161 | fn_link_set: event.Locked(FnLinkSet) = event.Locked(FnLinkSet).init(FnLinkSet.init()), |
| 162 | 162 | ||
| 163 | pub const FnLinkSet = std.TailQueue(?*Value.Fn); | 163 | pub const FnLinkSet = std.TailQueue(?*Value.Fn); |
| 164 | 164 | ||
| 165 | windows_subsystem_windows: bool, | 165 | windows_subsystem_windows: bool = false, |
| 166 | windows_subsystem_console: bool, | 166 | windows_subsystem_console: bool = false, |
| 167 | 167 | ||
| 168 | link_libs_list: ArrayList(*LinkLib), | 168 | link_libs_list: ArrayList(*LinkLib), |
| 169 | libc_link_lib: ?*LinkLib, | 169 | libc_link_lib: ?*LinkLib = null, |
| 170 | 170 | ||
| 171 | err_color: errmsg.Color, | 171 | err_color: errmsg.Color = .Auto, |
| 172 | 172 | ||
| 173 | verbose_tokenize: bool, | 173 | verbose_tokenize: bool = false, |
| 174 | verbose_ast_tree: bool, | 174 | verbose_ast_tree: bool = false, |
| 175 | verbose_ast_fmt: bool, | 175 | verbose_ast_fmt: bool = false, |
| 176 | verbose_cimport: bool, | 176 | verbose_cimport: bool = false, |
| 177 | verbose_ir: bool, | 177 | verbose_ir: bool = false, |
| 178 | verbose_llvm_ir: bool, | 178 | verbose_llvm_ir: bool = false, |
| 179 | verbose_link: bool, | 179 | verbose_link: bool = false, |
| 180 | 180 | ||
| 181 | darwin_frameworks: []const []const u8, | 181 | darwin_frameworks: []const []const u8 = [_][]const u8{}, |
| 182 | darwin_version_min: DarwinVersionMin, | 182 | darwin_version_min: DarwinVersionMin = .None, |
| 183 | 183 | ||
| 184 | test_filters: []const []const u8, | 184 | test_filters: []const []const u8 = [_][]const u8{}, |
| 185 | test_name_prefix: ?[]const u8, | 185 | test_name_prefix: ?[]const u8 = null, |
| 186 | 186 | ||
| 187 | emit_file_type: Emit, | 187 | emit_file_type: Emit = .Binary, |
| 188 | 188 | ||
| 189 | kind: Kind, | 189 | kind: Kind, |
| 190 | 190 | ||
| 191 | link_out_file: ?[]const u8, | 191 | link_out_file: ?[]const u8 = null, |
| 192 | events: *event.Channel(Event), | 192 | events: *event.Channel(Event), |
| 193 | 193 | ||
| 194 | exported_symbol_names: event.Locked(Decl.Table), | 194 | exported_symbol_names: event.Locked(Decl.Table), |
| ... | @@ -213,7 +213,7 @@ pub const Compilation = struct { | ... | @@ -213,7 +213,7 @@ pub const Compilation = struct { |
| 213 | 213 | ||
| 214 | target_machine: *llvm.TargetMachine, | 214 | target_machine: *llvm.TargetMachine, |
| 215 | target_data_ref: *llvm.TargetData, | 215 | target_data_ref: *llvm.TargetData, |
| 216 | target_layout_str: [*]u8, | 216 | target_layout_str: [*:0]u8, |
| 217 | target_ptr_bits: u32, | 217 | target_ptr_bits: u32, |
| 218 | 218 | ||
| 219 | /// for allocating things which have the same lifetime as this Compilation | 219 | /// for allocating things which have the same lifetime as this Compilation |
| ... | @@ -222,16 +222,16 @@ pub const Compilation = struct { | ... | @@ -222,16 +222,16 @@ pub const Compilation = struct { |
| 222 | root_package: *Package, | 222 | root_package: *Package, |
| 223 | std_package: *Package, | 223 | std_package: *Package, |
| 224 | 224 | ||
| 225 | override_libc: ?*LibCInstallation, | 225 | override_libc: ?*LibCInstallation = null, |
| 226 | 226 | ||
| 227 | /// need to wait on this group before deinitializing | 227 | /// need to wait on this group before deinitializing |
| 228 | deinit_group: event.Group(void), | 228 | deinit_group: event.Group(void), |
| 229 | 229 | ||
| 230 | // destroy_frame: @Frame(createAsync), | 230 | destroy_frame: *@Frame(createAsync), |
| 231 | // main_loop_frame: @Frame(Compilation.mainLoop), | 231 | main_loop_frame: *@Frame(Compilation.mainLoop), |
| 232 | main_loop_future: event.Future(void), | 232 | main_loop_future: event.Future(void) = event.Future(void).init(), |
| 233 | 233 | ||
| 234 | have_err_ret_tracing: bool, | 234 | have_err_ret_tracing: bool = false, |
| 235 | 235 | ||
| 236 | /// not locked because it is read-only | 236 | /// not locked because it is read-only |
| 237 | primitive_type_table: TypeTable, | 237 | primitive_type_table: TypeTable, |
| ... | @@ -243,7 +243,9 @@ pub const Compilation = struct { | ... | @@ -243,7 +243,9 @@ pub const Compilation = struct { |
| 243 | 243 | ||
| 244 | c_int_types: [CInt.list.len]*Type.Int, | 244 | c_int_types: [CInt.list.len]*Type.Int, |
| 245 | 245 | ||
| 246 | // fs_watch: *fs.Watch(*Scope.Root), | 246 | fs_watch: *fs.Watch(*Scope.Root), |
| 247 | |||
| 248 | cancelled: bool = false, | ||
| 247 | 249 | ||
| 248 | const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql); | 250 | const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql); |
| 249 | const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql); | 251 | const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql); |
| ... | @@ -348,7 +350,9 @@ pub const Compilation = struct { | ... | @@ -348,7 +350,9 @@ pub const Compilation = struct { |
| 348 | zig_lib_dir: []const u8, | 350 | zig_lib_dir: []const u8, |
| 349 | ) !*Compilation { | 351 | ) !*Compilation { |
| 350 | var optional_comp: ?*Compilation = null; | 352 | var optional_comp: ?*Compilation = null; |
| 351 | var frame = async createAsync( | 353 | var frame = try zig_compiler.allocator.create(@Frame(createAsync)); |
| 354 | errdefer zig_compiler.allocator.destroy(frame); | ||
| 355 | frame.* = async createAsync( | ||
| 352 | &optional_comp, | 356 | &optional_comp, |
| 353 | zig_compiler, | 357 | zig_compiler, |
| 354 | name, | 358 | name, |
| ... | @@ -359,11 +363,11 @@ pub const Compilation = struct { | ... | @@ -359,11 +363,11 @@ pub const Compilation = struct { |
| 359 | is_static, | 363 | is_static, |
| 360 | zig_lib_dir, | 364 | zig_lib_dir, |
| 361 | ); | 365 | ); |
| 366 | // TODO causes segfault | ||
| 367 | // return optional_comp orelse if (await frame) |_| unreachable else |err| err; | ||
| 362 | if (optional_comp) |comp| { | 368 | if (optional_comp) |comp| { |
| 363 | return comp; | 369 | return comp; |
| 364 | } else { | 370 | } else if (await frame) |_| unreachable else |err| return err; |
| 365 | if (await frame) |_| unreachable else |err| return err; | ||
| 366 | } | ||
| 367 | } | 371 | } |
| 368 | 372 | ||
| 369 | async fn createAsync( | 373 | async fn createAsync( |
| ... | @@ -389,50 +393,13 @@ pub const Compilation = struct { | ... | @@ -389,50 +393,13 @@ pub const Compilation = struct { |
| 389 | .build_mode = build_mode, | 393 | .build_mode = build_mode, |
| 390 | .zig_lib_dir = zig_lib_dir, | 394 | .zig_lib_dir = zig_lib_dir, |
| 391 | .zig_std_dir = undefined, | 395 | .zig_std_dir = undefined, |
| 392 | .tmp_dir = event.Future(BuildError![]u8).init(), | 396 | .destroy_frame = @frame(), |
| 393 | // .destroy_frame = @frame(), | 397 | .main_loop_frame = undefined, |
| 394 | // .main_loop_frame = undefined, | ||
| 395 | .main_loop_future = event.Future(void).init(), | ||
| 396 | 398 | ||
| 397 | .name = undefined, | 399 | .name = undefined, |
| 398 | .llvm_triple = undefined, | 400 | .llvm_triple = undefined, |
| 399 | |||
| 400 | .version_major = 0, | ||
| 401 | .version_minor = 0, | ||
| 402 | .version_patch = 0, | ||
| 403 | |||
| 404 | .verbose_tokenize = false, | ||
| 405 | .verbose_ast_tree = false, | ||
| 406 | .verbose_ast_fmt = false, | ||
| 407 | .verbose_cimport = false, | ||
| 408 | .verbose_ir = false, | ||
| 409 | .verbose_llvm_ir = false, | ||
| 410 | .verbose_link = false, | ||
| 411 | |||
| 412 | .linker_script = null, | ||
| 413 | .out_h_path = null, | ||
| 414 | .is_test = false, | ||
| 415 | .each_lib_rpath = false, | ||
| 416 | .strip = false, | ||
| 417 | .is_static = is_static, | 401 | .is_static = is_static, |
| 418 | .linker_rdynamic = false, | ||
| 419 | .clang_argv = &[_][]const u8{}, | ||
| 420 | .lib_dirs = &[_][]const u8{}, | ||
| 421 | .rpath_list = &[_][]const u8{}, | ||
| 422 | .assembly_files = &[_][]const u8{}, | ||
| 423 | .link_objects = &[_][]const u8{}, | ||
| 424 | .fn_link_set = event.Locked(FnLinkSet).init(FnLinkSet.init()), | ||
| 425 | .windows_subsystem_windows = false, | ||
| 426 | .windows_subsystem_console = false, | ||
| 427 | .link_libs_list = undefined, | 402 | .link_libs_list = undefined, |
| 428 | .libc_link_lib = null, | ||
| 429 | .err_color = errmsg.Color.Auto, | ||
| 430 | .darwin_frameworks = &[_][]const u8{}, | ||
| 431 | .darwin_version_min = DarwinVersionMin.None, | ||
| 432 | .test_filters = &[_][]const u8{}, | ||
| 433 | .test_name_prefix = null, | ||
| 434 | .emit_file_type = Emit.Binary, | ||
| 435 | .link_out_file = null, | ||
| 436 | .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)), | 403 | .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)), |
| 437 | .prelink_group = event.Group(BuildError!void).init(allocator), | 404 | .prelink_group = event.Group(BuildError!void).init(allocator), |
| 438 | .deinit_group = event.Group(void).init(allocator), | 405 | .deinit_group = event.Group(void).init(allocator), |
| ... | @@ -462,11 +429,9 @@ pub const Compilation = struct { | ... | @@ -462,11 +429,9 @@ pub const Compilation = struct { |
| 462 | .root_package = undefined, | 429 | .root_package = undefined, |
| 463 | .std_package = undefined, | 430 | .std_package = undefined, |
| 464 | 431 | ||
| 465 | .override_libc = null, | ||
| 466 | .have_err_ret_tracing = false, | ||
| 467 | .primitive_type_table = undefined, | 432 | .primitive_type_table = undefined, |
| 468 | 433 | ||
| 469 | // .fs_watch = undefined, | 434 | .fs_watch = undefined, |
| 470 | }; | 435 | }; |
| 471 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); | 436 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); |
| 472 | comp.primitive_type_table = TypeTable.init(comp.arena()); | 437 | comp.primitive_type_table = TypeTable.init(comp.arena()); |
| ... | @@ -538,13 +503,16 @@ pub const Compilation = struct { | ... | @@ -538,13 +503,16 @@ pub const Compilation = struct { |
| 538 | comp.root_package = try Package.create(comp.arena(), ".", ""); | 503 | comp.root_package = try Package.create(comp.arena(), ".", ""); |
| 539 | } | 504 | } |
| 540 | 505 | ||
| 541 | // comp.fs_watch = try fs.Watch(*Scope.Root).create(16); | 506 | comp.fs_watch = try fs.Watch(*Scope.Root).init(allocator, 16); |
| 542 | // defer comp.fs_watch.destroy(); | 507 | defer comp.fs_watch.deinit(); |
| 543 | 508 | ||
| 544 | try comp.initTypes(); | 509 | try comp.initTypes(); |
| 545 | defer comp.primitive_type_table.deinit(); | 510 | defer comp.primitive_type_table.deinit(); |
| 546 | 511 | ||
| 547 | // comp.main_loop_frame = async comp.mainLoop(); | 512 | comp.main_loop_frame = try allocator.create(@Frame(mainLoop)); |
| 513 | defer allocator.destroy(comp.main_loop_frame); | ||
| 514 | |||
| 515 | comp.main_loop_frame.* = async comp.mainLoop(); | ||
| 548 | // Set this to indicate that initialization completed successfully. | 516 | // Set this to indicate that initialization completed successfully. |
| 549 | // from here on out we must not return an error. | 517 | // from here on out we must not return an error. |
| 550 | // This must occur before the first suspend/await. | 518 | // This must occur before the first suspend/await. |
| ... | @@ -563,7 +531,7 @@ pub const Compilation = struct { | ... | @@ -563,7 +531,7 @@ pub const Compilation = struct { |
| 563 | } | 531 | } |
| 564 | 532 | ||
| 565 | /// it does ref the result because it could be an arbitrary integer size | 533 | /// it does ref the result because it could be an arbitrary integer size |
| 566 | pub async fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type { | 534 | pub fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type { |
| 567 | if (name.len >= 2) { | 535 | if (name.len >= 2) { |
| 568 | switch (name[0]) { | 536 | switch (name[0]) { |
| 569 | 'i', 'u' => blk: { | 537 | 'i', 'u' => blk: { |
| ... | @@ -757,8 +725,11 @@ pub const Compilation = struct { | ... | @@ -757,8 +725,11 @@ pub const Compilation = struct { |
| 757 | } | 725 | } |
| 758 | 726 | ||
| 759 | pub fn destroy(self: *Compilation) void { | 727 | pub fn destroy(self: *Compilation) void { |
| 760 | // await self.main_loop_frame; | 728 | const allocator = self.gpa(); |
| 761 | // resume self.destroy_frame; | 729 | self.cancelled = true; |
| 730 | await self.main_loop_frame; | ||
| 731 | resume self.destroy_frame; | ||
| 732 | allocator.destroy(self.destroy_frame); | ||
| 762 | } | 733 | } |
| 763 | 734 | ||
| 764 | fn start(self: *Compilation) void { | 735 | fn start(self: *Compilation) void { |
| ... | @@ -771,7 +742,7 @@ pub const Compilation = struct { | ... | @@ -771,7 +742,7 @@ pub const Compilation = struct { |
| 771 | 742 | ||
| 772 | var build_result = self.initialCompile(); | 743 | var build_result = self.initialCompile(); |
| 773 | 744 | ||
| 774 | while (true) { | 745 | while (!self.cancelled) { |
| 775 | const link_result = if (build_result) blk: { | 746 | const link_result = if (build_result) blk: { |
| 776 | break :blk self.maybeLink(); | 747 | break :blk self.maybeLink(); |
| 777 | } else |err| err; | 748 | } else |err| err; |
| ... | @@ -799,47 +770,47 @@ pub const Compilation = struct { | ... | @@ -799,47 +770,47 @@ pub const Compilation = struct { |
| 799 | self.events.put(Event{ .Error = err }); | 770 | self.events.put(Event{ .Error = err }); |
| 800 | } | 771 | } |
| 801 | 772 | ||
| 802 | // // First, get an item from the watch channel, waiting on the channel. | 773 | // First, get an item from the watch channel, waiting on the channel. |
| 803 | // var group = event.Group(BuildError!void).init(self.gpa()); | 774 | var group = event.Group(BuildError!void).init(self.gpa()); |
| 804 | // { | 775 | { |
| 805 | // const ev = (self.fs_watch.channel.get()) catch |err| { | 776 | const ev = (self.fs_watch.channel.get()) catch |err| { |
| 806 | // build_result = err; | 777 | build_result = err; |
| 807 | // continue; | 778 | continue; |
| 808 | // }; | 779 | }; |
| 809 | // const root_scope = ev.data; | 780 | const root_scope = ev.data; |
| 810 | // group.call(rebuildFile, self, root_scope) catch |err| { | 781 | group.call(rebuildFile, self, root_scope) catch |err| { |
| 811 | // build_result = err; | 782 | build_result = err; |
| 812 | // continue; | 783 | continue; |
| 813 | // }; | 784 | }; |
| 814 | // } | 785 | } |
| 815 | // // Next, get all the items from the channel that are buffered up. | 786 | // Next, get all the items from the channel that are buffered up. |
| 816 | // while (self.fs_watch.channel.getOrNull()) |ev_or_err| { | 787 | while (self.fs_watch.channel.getOrNull()) |ev_or_err| { |
| 817 | // if (ev_or_err) |ev| { | 788 | if (ev_or_err) |ev| { |
| 818 | // const root_scope = ev.data; | 789 | const root_scope = ev.data; |
| 819 | // group.call(rebuildFile, self, root_scope) catch |err| { | 790 | group.call(rebuildFile, self, root_scope) catch |err| { |
| 820 | // build_result = err; | 791 | build_result = err; |
| 821 | // continue; | 792 | continue; |
| 822 | // }; | 793 | }; |
| 823 | // } else |err| { | 794 | } else |err| { |
| 824 | // build_result = err; | 795 | build_result = err; |
| 825 | // continue; | 796 | continue; |
| 826 | // } | 797 | } |
| 827 | // } | 798 | } |
| 828 | // build_result = group.wait(); | 799 | build_result = group.wait(); |
| 829 | } | 800 | } |
| 830 | } | 801 | } |
| 831 | 802 | ||
| 832 | async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) !void { | 803 | async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) BuildError!void { |
| 833 | const tree_scope = blk: { | 804 | const tree_scope = blk: { |
| 834 | const source_code = ""; | 805 | const source_code = fs.readFile( |
| 835 | // const source_code = fs.readFile( | 806 | self.gpa(), |
| 836 | // root_scope.realpath, | 807 | root_scope.realpath, |
| 837 | // max_src_size, | 808 | max_src_size, |
| 838 | // ) catch |err| { | 809 | ) catch |err| { |
| 839 | // try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err)); | 810 | try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err)); |
| 840 | // return; | 811 | return; |
| 841 | // }; | 812 | }; |
| 842 | // errdefer self.gpa().free(source_code); | 813 | errdefer self.gpa().free(source_code); |
| 843 | 814 | ||
| 844 | const tree = try std.zig.parse(self.gpa(), source_code); | 815 | const tree = try std.zig.parse(self.gpa(), source_code); |
| 845 | errdefer { | 816 | errdefer { |
| ... | @@ -877,7 +848,7 @@ pub const Compilation = struct { | ... | @@ -877,7 +848,7 @@ pub const Compilation = struct { |
| 877 | try decl_group.wait(); | 848 | try decl_group.wait(); |
| 878 | } | 849 | } |
| 879 | 850 | ||
| 880 | async fn rebuildChangedDecls( | 851 | fn rebuildChangedDecls( |
| 881 | self: *Compilation, | 852 | self: *Compilation, |
| 882 | group: *event.Group(BuildError!void), | 853 | group: *event.Group(BuildError!void), |
| 883 | locked_table: *Decl.Table, | 854 | locked_table: *Decl.Table, |
| ... | @@ -966,7 +937,7 @@ pub const Compilation = struct { | ... | @@ -966,7 +937,7 @@ pub const Compilation = struct { |
| 966 | } | 937 | } |
| 967 | } | 938 | } |
| 968 | 939 | ||
| 969 | async fn initialCompile(self: *Compilation) !void { | 940 | fn initialCompile(self: *Compilation) !void { |
| 970 | if (self.root_src_path) |root_src_path| { | 941 | if (self.root_src_path) |root_src_path| { |
| 971 | const root_scope = blk: { | 942 | const root_scope = blk: { |
| 972 | // TODO async/await std.fs.realpath | 943 | // TODO async/await std.fs.realpath |
| ... | @@ -985,7 +956,7 @@ pub const Compilation = struct { | ... | @@ -985,7 +956,7 @@ pub const Compilation = struct { |
| 985 | } | 956 | } |
| 986 | } | 957 | } |
| 987 | 958 | ||
| 988 | async fn maybeLink(self: *Compilation) !void { | 959 | fn maybeLink(self: *Compilation) !void { |
| 989 | (self.prelink_group.wait()) catch |err| switch (err) { | 960 | (self.prelink_group.wait()) catch |err| switch (err) { |
| 990 | error.SemanticAnalysisFailed => {}, | 961 | error.SemanticAnalysisFailed => {}, |
| 991 | else => return err, | 962 | else => return err, |
| ... | @@ -1169,11 +1140,10 @@ pub const Compilation = struct { | ... | @@ -1169,11 +1140,10 @@ pub const Compilation = struct { |
| 1169 | return link_lib; | 1140 | return link_lib; |
| 1170 | } | 1141 | } |
| 1171 | 1142 | ||
| 1172 | /// cancels itself so no need to await or cancel the promise. | ||
| 1173 | async fn startFindingNativeLibC(self: *Compilation) void { | 1143 | async fn startFindingNativeLibC(self: *Compilation) void { |
| 1174 | std.event.Loop.instance.?.yield(); | 1144 | event.Loop.startCpuBoundOperation(); |
| 1175 | // we don't care if it fails, we're just trying to kick off the future resolution | 1145 | // we don't care if it fails, we're just trying to kick off the future resolution |
| 1176 | _ = (self.zig_compiler.getNativeLibC()) catch return; | 1146 | _ = self.zig_compiler.getNativeLibC() catch return; |
| 1177 | } | 1147 | } |
| 1178 | 1148 | ||
| 1179 | /// General Purpose Allocator. Must free when done. | 1149 | /// General Purpose Allocator. Must free when done. |
| ... | @@ -1188,7 +1158,7 @@ pub const Compilation = struct { | ... | @@ -1188,7 +1158,7 @@ pub const Compilation = struct { |
| 1188 | 1158 | ||
| 1189 | /// If the temporary directory for this compilation has not been created, it creates it. | 1159 | /// If the temporary directory for this compilation has not been created, it creates it. |
| 1190 | /// Then it creates a random file name in that dir and returns it. | 1160 | /// Then it creates a random file name in that dir and returns it. |
| 1191 | pub async fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer { | 1161 | pub fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer { |
| 1192 | const tmp_dir = try self.getTmpDir(); | 1162 | const tmp_dir = try self.getTmpDir(); |
| 1193 | const file_prefix = self.getRandomFileName(); | 1163 | const file_prefix = self.getRandomFileName(); |
| 1194 | 1164 | ||
| ... | @@ -1204,14 +1174,14 @@ pub const Compilation = struct { | ... | @@ -1204,14 +1174,14 @@ pub const Compilation = struct { |
| 1204 | /// If the temporary directory for this Compilation has not been created, creates it. | 1174 | /// If the temporary directory for this Compilation has not been created, creates it. |
| 1205 | /// Then returns it. The directory is unique to this Compilation and cleaned up when | 1175 | /// Then returns it. The directory is unique to this Compilation and cleaned up when |
| 1206 | /// the Compilation deinitializes. | 1176 | /// the Compilation deinitializes. |
| 1207 | async fn getTmpDir(self: *Compilation) ![]const u8 { | 1177 | fn getTmpDir(self: *Compilation) ![]const u8 { |
| 1208 | if (self.tmp_dir.start()) |ptr| return ptr.*; | 1178 | if (self.tmp_dir.start()) |ptr| return ptr.*; |
| 1209 | self.tmp_dir.data = self.getTmpDirImpl(); | 1179 | self.tmp_dir.data = self.getTmpDirImpl(); |
| 1210 | self.tmp_dir.resolve(); | 1180 | self.tmp_dir.resolve(); |
| 1211 | return self.tmp_dir.data; | 1181 | return self.tmp_dir.data; |
| 1212 | } | 1182 | } |
| 1213 | 1183 | ||
| 1214 | async fn getTmpDirImpl(self: *Compilation) ![]u8 { | 1184 | fn getTmpDirImpl(self: *Compilation) ![]u8 { |
| 1215 | const comp_dir_name = self.getRandomFileName(); | 1185 | const comp_dir_name = self.getRandomFileName(); |
| 1216 | const zig_dir_path = try getZigDir(self.gpa()); | 1186 | const zig_dir_path = try getZigDir(self.gpa()); |
| 1217 | defer self.gpa().free(zig_dir_path); | 1187 | defer self.gpa().free(zig_dir_path); |
| ... | @@ -1221,7 +1191,7 @@ pub const Compilation = struct { | ... | @@ -1221,7 +1191,7 @@ pub const Compilation = struct { |
| 1221 | return tmp_dir; | 1191 | return tmp_dir; |
| 1222 | } | 1192 | } |
| 1223 | 1193 | ||
| 1224 | async fn getRandomFileName(self: *Compilation) [12]u8 { | 1194 | fn getRandomFileName(self: *Compilation) [12]u8 { |
| 1225 | // here we replace the standard +/ with -_ so that it can be used in a file name | 1195 | // here we replace the standard +/ with -_ so that it can be used in a file name |
| 1226 | const b64_fs_encoder = std.base64.Base64Encoder.init( | 1196 | const b64_fs_encoder = std.base64.Base64Encoder.init( |
| 1227 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", | 1197 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", |
| ... | @@ -1247,20 +1217,23 @@ pub const Compilation = struct { | ... | @@ -1247,20 +1217,23 @@ pub const Compilation = struct { |
| 1247 | } | 1217 | } |
| 1248 | 1218 | ||
| 1249 | /// Returns a value which has been ref()'d once | 1219 | /// Returns a value which has been ref()'d once |
| 1250 | async fn analyzeConstValue( | 1220 | fn analyzeConstValue( |
| 1251 | comp: *Compilation, | 1221 | comp: *Compilation, |
| 1252 | tree_scope: *Scope.AstTree, | 1222 | tree_scope: *Scope.AstTree, |
| 1253 | scope: *Scope, | 1223 | scope: *Scope, |
| 1254 | node: *ast.Node, | 1224 | node: *ast.Node, |
| 1255 | expected_type: *Type, | 1225 | expected_type: *Type, |
| 1256 | ) !*Value { | 1226 | ) !*Value { |
| 1257 | const analyzed_code = try comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type); | 1227 | var frame = try comp.gpa().create(@Frame(genAndAnalyzeCode)); |
| 1228 | defer comp.gpa().destroy(frame); | ||
| 1229 | frame.* = async comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type); | ||
| 1230 | const analyzed_code = try await frame; | ||
| 1258 | defer analyzed_code.destroy(comp.gpa()); | 1231 | defer analyzed_code.destroy(comp.gpa()); |
| 1259 | 1232 | ||
| 1260 | return analyzed_code.getCompTimeResult(comp); | 1233 | return analyzed_code.getCompTimeResult(comp); |
| 1261 | } | 1234 | } |
| 1262 | 1235 | ||
| 1263 | async fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type { | 1236 | fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type { |
| 1264 | const meta_type = &Type.MetaType.get(comp).base; | 1237 | const meta_type = &Type.MetaType.get(comp).base; |
| 1265 | defer meta_type.base.deref(comp); | 1238 | defer meta_type.base.deref(comp); |
| 1266 | 1239 | ||
| ... | @@ -1291,7 +1264,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib | ... | @@ -1291,7 +1264,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib |
| 1291 | } | 1264 | } |
| 1292 | 1265 | ||
| 1293 | /// The function that actually does the generation. | 1266 | /// The function that actually does the generation. |
| 1294 | async fn generateDecl(comp: *Compilation, decl: *Decl) !void { | 1267 | fn generateDecl(comp: *Compilation, decl: *Decl) !void { |
| 1295 | switch (decl.id) { | 1268 | switch (decl.id) { |
| 1296 | .Var => @panic("TODO"), | 1269 | .Var => @panic("TODO"), |
| 1297 | .Fn => { | 1270 | .Fn => { |
| ... | @@ -1302,7 +1275,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void { | ... | @@ -1302,7 +1275,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void { |
| 1302 | } | 1275 | } |
| 1303 | } | 1276 | } |
| 1304 | 1277 | ||
| 1305 | async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | 1278 | fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1306 | const tree_scope = fn_decl.base.tree_scope; | 1279 | const tree_scope = fn_decl.base.tree_scope; |
| 1307 | 1280 | ||
| 1308 | const body_node = fn_decl.fn_proto.body_node orelse return generateDeclFnProto(comp, fn_decl); | 1281 | const body_node = fn_decl.fn_proto.body_node orelse return generateDeclFnProto(comp, fn_decl); |
| ... | @@ -1319,7 +1292,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -1319,7 +1292,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1319 | 1292 | ||
| 1320 | // The Decl.Fn owns the initial 1 reference count | 1293 | // The Decl.Fn owns the initial 1 reference count |
| 1321 | const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); | 1294 | const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); |
| 1322 | fn_decl.value = Decl.Fn.Val{ .Fn = fn_val }; | 1295 | fn_decl.value = .{ .Fn = fn_val }; |
| 1323 | symbol_name_consumed = true; | 1296 | symbol_name_consumed = true; |
| 1324 | 1297 | ||
| 1325 | // Define local parameter variables | 1298 | // Define local parameter variables |
| ... | @@ -1354,12 +1327,15 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -1354,12 +1327,15 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1354 | try fn_type.non_key.Normal.variable_list.append(var_scope); | 1327 | try fn_type.non_key.Normal.variable_list.append(var_scope); |
| 1355 | } | 1328 | } |
| 1356 | 1329 | ||
| 1357 | const analyzed_code = try comp.genAndAnalyzeCode( | 1330 | var frame = try comp.gpa().create(@Frame(Compilation.genAndAnalyzeCode)); |
| 1331 | defer comp.gpa().destroy(frame); | ||
| 1332 | frame.* = async comp.genAndAnalyzeCode( | ||
| 1358 | tree_scope, | 1333 | tree_scope, |
| 1359 | fn_val.child_scope, | 1334 | fn_val.child_scope, |
| 1360 | body_node, | 1335 | body_node, |
| 1361 | fn_type.key.data.Normal.return_type, | 1336 | fn_type.key.data.Normal.return_type, |
| 1362 | ); | 1337 | ); |
| 1338 | const analyzed_code = try await frame; | ||
| 1363 | errdefer analyzed_code.destroy(comp.gpa()); | 1339 | errdefer analyzed_code.destroy(comp.gpa()); |
| 1364 | 1340 | ||
| 1365 | assert(fn_val.block_scope != null); | 1341 | assert(fn_val.block_scope != null); |
| ... | @@ -1386,7 +1362,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 { | ... | @@ -1386,7 +1362,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 { |
| 1386 | return std.fs.getAppDataDir(allocator, "zig"); | 1362 | return std.fs.getAppDataDir(allocator, "zig"); |
| 1387 | } | 1363 | } |
| 1388 | 1364 | ||
| 1389 | async fn analyzeFnType( | 1365 | fn analyzeFnType( |
| 1390 | comp: *Compilation, | 1366 | comp: *Compilation, |
| 1391 | tree_scope: *Scope.AstTree, | 1367 | tree_scope: *Scope.AstTree, |
| 1392 | scope: *Scope, | 1368 | scope: *Scope, |
| ... | @@ -1448,7 +1424,7 @@ async fn analyzeFnType( | ... | @@ -1448,7 +1424,7 @@ async fn analyzeFnType( |
| 1448 | return fn_type; | 1424 | return fn_type; |
| 1449 | } | 1425 | } |
| 1450 | 1426 | ||
| 1451 | async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { | 1427 | fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1452 | const fn_type = try analyzeFnType( | 1428 | const fn_type = try analyzeFnType( |
| 1453 | comp, | 1429 | comp, |
| 1454 | fn_decl.base.tree_scope, | 1430 | fn_decl.base.tree_scope, |
| ... | @@ -1463,6 +1439,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -1463,6 +1439,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1463 | 1439 | ||
| 1464 | // The Decl.Fn owns the initial 1 reference count | 1440 | // The Decl.Fn owns the initial 1 reference count |
| 1465 | const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name); | 1441 | const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name); |
| 1466 | fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val }; | 1442 | fn_decl.value = .{ .FnProto = fn_proto_val }; |
| 1467 | symbol_name_consumed = true; | 1443 | symbol_name_consumed = true; |
| 1468 | } | 1444 | } |
src-self-hosted/decl.zig+3-6| ... | @@ -69,15 +69,12 @@ pub const Decl = struct { | ... | @@ -69,15 +69,12 @@ pub const Decl = struct { |
| 69 | 69 | ||
| 70 | pub const Fn = struct { | 70 | pub const Fn = struct { |
| 71 | base: Decl, | 71 | base: Decl, |
| 72 | value: Val, | 72 | value: union(enum) { |
| 73 | fn_proto: *ast.Node.FnProto, | ||
| 74 | |||
| 75 | // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous | ||
| 76 | pub const Val = union(enum) { | ||
| 77 | Unresolved, | 73 | Unresolved, |
| 78 | Fn: *Value.Fn, | 74 | Fn: *Value.Fn, |
| 79 | FnProto: *Value.FnProto, | 75 | FnProto: *Value.FnProto, |
| 80 | }; | 76 | }, |
| 77 | fn_proto: *ast.Node.FnProto, | ||
| 81 | 78 | ||
| 82 | pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 { | 79 | pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 { |
| 83 | return if (self.fn_proto.extern_export_inline_token) |tok_index| x: { | 80 | return if (self.fn_proto.extern_export_inline_token) |tok_index| x: { |
src-self-hosted/ir.zig+38-30| ... | @@ -110,7 +110,7 @@ pub const Inst = struct { | ... | @@ -110,7 +110,7 @@ pub const Inst = struct { |
| 110 | unreachable; | 110 | unreachable; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst { | 113 | pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst { |
| 114 | switch (base.id) { | 114 | switch (base.id) { |
| 115 | .Return => return @fieldParentPtr(Return, "base", base).analyze(ira), | 115 | .Return => return @fieldParentPtr(Return, "base", base).analyze(ira), |
| 116 | .Const => return @fieldParentPtr(Const, "base", base).analyze(ira), | 116 | .Const => return @fieldParentPtr(Const, "base", base).analyze(ira), |
| ... | @@ -422,7 +422,7 @@ pub const Inst = struct { | ... | @@ -422,7 +422,7 @@ pub const Inst = struct { |
| 422 | return false; | 422 | return false; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst { | 425 | pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst { |
| 426 | const target = try self.params.target.getAsParam(); | 426 | const target = try self.params.target.getAsParam(); |
| 427 | 427 | ||
| 428 | if (ira.getCompTimeValOrNullUndefOk(target)) |val| { | 428 | if (ira.getCompTimeValOrNullUndefOk(target)) |val| { |
| ... | @@ -472,7 +472,7 @@ pub const Inst = struct { | ... | @@ -472,7 +472,7 @@ pub const Inst = struct { |
| 472 | return false; | 472 | return false; |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst { | 475 | pub fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst { |
| 476 | (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) { | 476 | (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) { |
| 477 | error.OutOfMemory => return error.OutOfMemory, | 477 | error.OutOfMemory => return error.OutOfMemory, |
| 478 | else => return error.SemanticAnalysisFailed, | 478 | else => return error.SemanticAnalysisFailed, |
| ... | @@ -516,7 +516,7 @@ pub const Inst = struct { | ... | @@ -516,7 +516,7 @@ pub const Inst = struct { |
| 516 | return false; | 516 | return false; |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst { | 519 | pub fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst { |
| 520 | switch (self.params.var_scope.data) { | 520 | switch (self.params.var_scope.data) { |
| 521 | .Const => @panic("TODO"), | 521 | .Const => @panic("TODO"), |
| 522 | .Param => |param| { | 522 | .Param => |param| { |
| ... | @@ -563,7 +563,7 @@ pub const Inst = struct { | ... | @@ -563,7 +563,7 @@ pub const Inst = struct { |
| 563 | return false; | 563 | return false; |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst { | 566 | pub fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst { |
| 567 | const target = try self.params.target.getAsParam(); | 567 | const target = try self.params.target.getAsParam(); |
| 568 | const target_type = target.getKnownType(); | 568 | const target_type = target.getKnownType(); |
| 569 | if (target_type.id != .Pointer) { | 569 | if (target_type.id != .Pointer) { |
| ... | @@ -645,7 +645,7 @@ pub const Inst = struct { | ... | @@ -645,7 +645,7 @@ pub const Inst = struct { |
| 645 | return false; | 645 | return false; |
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst { | 648 | pub fn analyze(self: *const PtrType, ira: *Analyze) !*Inst { |
| 649 | const child_type = try self.params.child_type.getAsConstType(ira); | 649 | const child_type = try self.params.child_type.getAsConstType(ira); |
| 650 | // if (child_type->id == TypeTableEntryIdUnreachable) { | 650 | // if (child_type->id == TypeTableEntryIdUnreachable) { |
| 651 | // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); | 651 | // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); |
| ... | @@ -658,7 +658,7 @@ pub const Inst = struct { | ... | @@ -658,7 +658,7 @@ pub const Inst = struct { |
| 658 | const amt = try align_inst.getAsConstAlign(ira); | 658 | const amt = try align_inst.getAsConstAlign(ira); |
| 659 | break :blk Type.Pointer.Align{ .Override = amt }; | 659 | break :blk Type.Pointer.Align{ .Override = amt }; |
| 660 | } else blk: { | 660 | } else blk: { |
| 661 | break :blk Type.Pointer.Align{ .Abi = {} }; | 661 | break :blk .Abi; |
| 662 | }; | 662 | }; |
| 663 | const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{ | 663 | const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{ |
| 664 | .child_type = child_type, | 664 | .child_type = child_type, |
| ... | @@ -927,7 +927,7 @@ pub const Variable = struct { | ... | @@ -927,7 +927,7 @@ pub const Variable = struct { |
| 927 | 927 | ||
| 928 | pub const BasicBlock = struct { | 928 | pub const BasicBlock = struct { |
| 929 | ref_count: usize, | 929 | ref_count: usize, |
| 930 | name_hint: [*]const u8, // must be a C string literal | 930 | name_hint: [*:0]const u8, |
| 931 | debug_id: usize, | 931 | debug_id: usize, |
| 932 | scope: *Scope, | 932 | scope: *Scope, |
| 933 | instruction_list: std.ArrayList(*Inst), | 933 | instruction_list: std.ArrayList(*Inst), |
| ... | @@ -1051,7 +1051,7 @@ pub const Builder = struct { | ... | @@ -1051,7 +1051,7 @@ pub const Builder = struct { |
| 1051 | } | 1051 | } |
| 1052 | 1052 | ||
| 1053 | /// No need to clean up resources thanks to the arena allocator. | 1053 | /// No need to clean up resources thanks to the arena allocator. |
| 1054 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { | 1054 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*:0]const u8) !*BasicBlock { |
| 1055 | const basic_block = try self.arena().create(BasicBlock); | 1055 | const basic_block = try self.arena().create(BasicBlock); |
| 1056 | basic_block.* = BasicBlock{ | 1056 | basic_block.* = BasicBlock{ |
| 1057 | .ref_count = 0, | 1057 | .ref_count = 0, |
| ... | @@ -1078,6 +1078,14 @@ pub const Builder = struct { | ... | @@ -1078,6 +1078,14 @@ pub const Builder = struct { |
| 1078 | self.current_basic_block = basic_block; | 1078 | self.current_basic_block = basic_block; |
| 1079 | } | 1079 | } |
| 1080 | 1080 | ||
| 1081 | pub fn genNodeRecursive(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst { | ||
| 1082 | const alloc = irb.comp.gpa(); | ||
| 1083 | var frame = try alloc.create(@Frame(genNode)); | ||
| 1084 | defer alloc.destroy(frame); | ||
| 1085 | frame.* = async irb.genNode(node, scope, lval); | ||
| 1086 | return await frame; | ||
| 1087 | } | ||
| 1088 | |||
| 1081 | pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst { | 1089 | pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst { |
| 1082 | switch (node.id) { | 1090 | switch (node.id) { |
| 1083 | .Root => unreachable, | 1091 | .Root => unreachable, |
| ... | @@ -1157,7 +1165,7 @@ pub const Builder = struct { | ... | @@ -1157,7 +1165,7 @@ pub const Builder = struct { |
| 1157 | }, | 1165 | }, |
| 1158 | .GroupedExpression => { | 1166 | .GroupedExpression => { |
| 1159 | const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node); | 1167 | const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node); |
| 1160 | return irb.genNode(grouped_expr.expr, scope, lval); | 1168 | return irb.genNodeRecursive(grouped_expr.expr, scope, lval); |
| 1161 | }, | 1169 | }, |
| 1162 | .BuiltinCall => return error.Unimplemented, | 1170 | .BuiltinCall => return error.Unimplemented, |
| 1163 | .ErrorSetDecl => return error.Unimplemented, | 1171 | .ErrorSetDecl => return error.Unimplemented, |
| ... | @@ -1186,14 +1194,14 @@ pub const Builder = struct { | ... | @@ -1186,14 +1194,14 @@ pub const Builder = struct { |
| 1186 | } | 1194 | } |
| 1187 | } | 1195 | } |
| 1188 | 1196 | ||
| 1189 | async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst { | 1197 | fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst { |
| 1190 | const fn_ref = try irb.genNode(suffix_op.lhs, scope, .None); | 1198 | const fn_ref = try irb.genNodeRecursive(suffix_op.lhs.node, scope, .None); |
| 1191 | 1199 | ||
| 1192 | const args = try irb.arena().alloc(*Inst, call.params.len); | 1200 | const args = try irb.arena().alloc(*Inst, call.params.len); |
| 1193 | var it = call.params.iterator(0); | 1201 | var it = call.params.iterator(0); |
| 1194 | var i: usize = 0; | 1202 | var i: usize = 0; |
| 1195 | while (it.next()) |arg_node_ptr| : (i += 1) { | 1203 | while (it.next()) |arg_node_ptr| : (i += 1) { |
| 1196 | args[i] = try irb.genNode(arg_node_ptr.*, scope, .None); | 1204 | args[i] = try irb.genNodeRecursive(arg_node_ptr.*, scope, .None); |
| 1197 | } | 1205 | } |
| 1198 | 1206 | ||
| 1199 | //bool is_async = node->data.fn_call_expr.is_async; | 1207 | //bool is_async = node->data.fn_call_expr.is_async; |
| ... | @@ -1214,7 +1222,7 @@ pub const Builder = struct { | ... | @@ -1214,7 +1222,7 @@ pub const Builder = struct { |
| 1214 | //return ir_lval_wrap(irb, scope, fn_call, lval); | 1222 | //return ir_lval_wrap(irb, scope, fn_call, lval); |
| 1215 | } | 1223 | } |
| 1216 | 1224 | ||
| 1217 | async fn genPtrType( | 1225 | fn genPtrType( |
| 1218 | irb: *Builder, | 1226 | irb: *Builder, |
| 1219 | prefix_op: *ast.Node.PrefixOp, | 1227 | prefix_op: *ast.Node.PrefixOp, |
| 1220 | ptr_info: ast.Node.PrefixOp.PtrInfo, | 1228 | ptr_info: ast.Node.PrefixOp.PtrInfo, |
| ... | @@ -1238,7 +1246,7 @@ pub const Builder = struct { | ... | @@ -1238,7 +1246,7 @@ pub const Builder = struct { |
| 1238 | //} else { | 1246 | //} else { |
| 1239 | // align_value = nullptr; | 1247 | // align_value = nullptr; |
| 1240 | //} | 1248 | //} |
| 1241 | const child_type = try irb.genNode(prefix_op.rhs, scope, .None); | 1249 | const child_type = try irb.genNodeRecursive(prefix_op.rhs, scope, .None); |
| 1242 | 1250 | ||
| 1243 | //uint32_t bit_offset_start = 0; | 1251 | //uint32_t bit_offset_start = 0; |
| 1244 | //if (node->data.pointer_type.bit_offset_start != nullptr) { | 1252 | //if (node->data.pointer_type.bit_offset_start != nullptr) { |
| ... | @@ -1307,9 +1315,9 @@ pub const Builder = struct { | ... | @@ -1307,9 +1315,9 @@ pub const Builder = struct { |
| 1307 | var rest: []const u8 = undefined; | 1315 | var rest: []const u8 = undefined; |
| 1308 | if (int_token.len >= 3 and int_token[0] == '0') { | 1316 | if (int_token.len >= 3 and int_token[0] == '0') { |
| 1309 | base = switch (int_token[1]) { | 1317 | base = switch (int_token[1]) { |
| 1310 | 'b' => u8(2), | 1318 | 'b' => 2, |
| 1311 | 'o' => u8(8), | 1319 | 'o' => 8, |
| 1312 | 'x' => u8(16), | 1320 | 'x' => 16, |
| 1313 | else => unreachable, | 1321 | else => unreachable, |
| 1314 | }; | 1322 | }; |
| 1315 | rest = int_token[2..]; | 1323 | rest = int_token[2..]; |
| ... | @@ -1339,7 +1347,7 @@ pub const Builder = struct { | ... | @@ -1339,7 +1347,7 @@ pub const Builder = struct { |
| 1339 | return inst; | 1347 | return inst; |
| 1340 | } | 1348 | } |
| 1341 | 1349 | ||
| 1342 | pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst { | 1350 | pub fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst { |
| 1343 | const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token); | 1351 | const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token); |
| 1344 | const src_span = Span.token(str_lit.token); | 1352 | const src_span = Span.token(str_lit.token); |
| 1345 | 1353 | ||
| ... | @@ -1389,7 +1397,7 @@ pub const Builder = struct { | ... | @@ -1389,7 +1397,7 @@ pub const Builder = struct { |
| 1389 | } | 1397 | } |
| 1390 | } | 1398 | } |
| 1391 | 1399 | ||
| 1392 | pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { | 1400 | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { |
| 1393 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); | 1401 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); |
| 1394 | 1402 | ||
| 1395 | const outer_block_scope = &block_scope.base; | 1403 | const outer_block_scope = &block_scope.base; |
| ... | @@ -1437,7 +1445,7 @@ pub const Builder = struct { | ... | @@ -1437,7 +1445,7 @@ pub const Builder = struct { |
| 1437 | child_scope = &defer_child_scope.base; | 1445 | child_scope = &defer_child_scope.base; |
| 1438 | continue; | 1446 | continue; |
| 1439 | } | 1447 | } |
| 1440 | const statement_value = try irb.genNode(statement_node, child_scope, .None); | 1448 | const statement_value = try irb.genNodeRecursive(statement_node, child_scope, .None); |
| 1441 | 1449 | ||
| 1442 | is_continuation_unreachable = statement_value.isNoReturn(); | 1450 | is_continuation_unreachable = statement_value.isNoReturn(); |
| 1443 | if (is_continuation_unreachable) { | 1451 | if (is_continuation_unreachable) { |
| ... | @@ -1499,7 +1507,7 @@ pub const Builder = struct { | ... | @@ -1499,7 +1507,7 @@ pub const Builder = struct { |
| 1499 | return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true); | 1507 | return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true); |
| 1500 | } | 1508 | } |
| 1501 | 1509 | ||
| 1502 | pub async fn genControlFlowExpr( | 1510 | pub fn genControlFlowExpr( |
| 1503 | irb: *Builder, | 1511 | irb: *Builder, |
| 1504 | control_flow_expr: *ast.Node.ControlFlowExpression, | 1512 | control_flow_expr: *ast.Node.ControlFlowExpression, |
| 1505 | scope: *Scope, | 1513 | scope: *Scope, |
| ... | @@ -1533,7 +1541,7 @@ pub const Builder = struct { | ... | @@ -1533,7 +1541,7 @@ pub const Builder = struct { |
| 1533 | 1541 | ||
| 1534 | const outer_scope = irb.begin_scope.?; | 1542 | const outer_scope = irb.begin_scope.?; |
| 1535 | const return_value = if (control_flow_expr.rhs) |rhs| blk: { | 1543 | const return_value = if (control_flow_expr.rhs) |rhs| blk: { |
| 1536 | break :blk try irb.genNode(rhs, scope, .None); | 1544 | break :blk try irb.genNodeRecursive(rhs, scope, .None); |
| 1537 | } else blk: { | 1545 | } else blk: { |
| 1538 | break :blk try irb.buildConstVoid(scope, src_span, true); | 1546 | break :blk try irb.buildConstVoid(scope, src_span, true); |
| 1539 | }; | 1547 | }; |
| ... | @@ -1596,7 +1604,7 @@ pub const Builder = struct { | ... | @@ -1596,7 +1604,7 @@ pub const Builder = struct { |
| 1596 | } | 1604 | } |
| 1597 | } | 1605 | } |
| 1598 | 1606 | ||
| 1599 | pub async fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst { | 1607 | pub fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst { |
| 1600 | const src_span = Span.token(identifier.token); | 1608 | const src_span = Span.token(identifier.token); |
| 1601 | const name = irb.code.tree_scope.tree.tokenSlice(identifier.token); | 1609 | const name = irb.code.tree_scope.tree.tokenSlice(identifier.token); |
| 1602 | 1610 | ||
| ... | @@ -1694,7 +1702,7 @@ pub const Builder = struct { | ... | @@ -1694,7 +1702,7 @@ pub const Builder = struct { |
| 1694 | return result; | 1702 | return result; |
| 1695 | } | 1703 | } |
| 1696 | 1704 | ||
| 1697 | async fn genDefersForBlock( | 1705 | fn genDefersForBlock( |
| 1698 | irb: *Builder, | 1706 | irb: *Builder, |
| 1699 | inner_scope: *Scope, | 1707 | inner_scope: *Scope, |
| 1700 | outer_scope: *Scope, | 1708 | outer_scope: *Scope, |
| ... | @@ -1712,7 +1720,7 @@ pub const Builder = struct { | ... | @@ -1712,7 +1720,7 @@ pub const Builder = struct { |
| 1712 | }; | 1720 | }; |
| 1713 | if (generate) { | 1721 | if (generate) { |
| 1714 | const defer_expr_scope = defer_scope.defer_expr_scope; | 1722 | const defer_expr_scope = defer_scope.defer_expr_scope; |
| 1715 | const instruction = try irb.genNode( | 1723 | const instruction = try irb.genNodeRecursive( |
| 1716 | defer_expr_scope.expr_node, | 1724 | defer_expr_scope.expr_node, |
| 1717 | &defer_expr_scope.base, | 1725 | &defer_expr_scope.base, |
| 1718 | .None, | 1726 | .None, |
| ... | @@ -1797,7 +1805,7 @@ pub const Builder = struct { | ... | @@ -1797,7 +1805,7 @@ pub const Builder = struct { |
| 1797 | // Look at the params and ref() other instructions | 1805 | // Look at the params and ref() other instructions |
| 1798 | comptime var i = 0; | 1806 | comptime var i = 0; |
| 1799 | inline while (i < @memberCount(I.Params)) : (i += 1) { | 1807 | inline while (i < @memberCount(I.Params)) : (i += 1) { |
| 1800 | const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i))); | 1808 | const FieldType = comptime @typeOf(@field(@as(I.Params, undefined), @memberName(I.Params, i))); |
| 1801 | switch (FieldType) { | 1809 | switch (FieldType) { |
| 1802 | *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self), | 1810 | *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self), |
| 1803 | *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self), | 1811 | *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self), |
| ... | @@ -1909,7 +1917,7 @@ pub const Builder = struct { | ... | @@ -1909,7 +1917,7 @@ pub const Builder = struct { |
| 1909 | VarScope: *Scope.Var, | 1917 | VarScope: *Scope.Var, |
| 1910 | }; | 1918 | }; |
| 1911 | 1919 | ||
| 1912 | async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident { | 1920 | fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident { |
| 1913 | var s = scope; | 1921 | var s = scope; |
| 1914 | while (true) { | 1922 | while (true) { |
| 1915 | switch (s.id) { | 1923 | switch (s.id) { |
| ... | @@ -2519,7 +2527,7 @@ const Analyze = struct { | ... | @@ -2519,7 +2527,7 @@ const Analyze = struct { |
| 2519 | } | 2527 | } |
| 2520 | }; | 2528 | }; |
| 2521 | 2529 | ||
| 2522 | pub async fn gen( | 2530 | pub fn gen( |
| 2523 | comp: *Compilation, | 2531 | comp: *Compilation, |
| 2524 | body_node: *ast.Node, | 2532 | body_node: *ast.Node, |
| 2525 | tree_scope: *Scope.AstTree, | 2533 | tree_scope: *Scope.AstTree, |
| ... | @@ -2541,7 +2549,7 @@ pub async fn gen( | ... | @@ -2541,7 +2549,7 @@ pub async fn gen( |
| 2541 | return irb.finish(); | 2549 | return irb.finish(); |
| 2542 | } | 2550 | } |
| 2543 | 2551 | ||
| 2544 | pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code { | 2552 | pub fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code { |
| 2545 | const old_entry_bb = old_code.basic_block_list.at(0); | 2553 | const old_entry_bb = old_code.basic_block_list.at(0); |
| 2546 | 2554 | ||
| 2547 | var ira = try Analyze.init(comp, old_code.tree_scope, expected_type); | 2555 | var ira = try Analyze.init(comp, old_code.tree_scope, expected_type); |
src-self-hosted/libc_installation.zig+3-3| ... | @@ -143,7 +143,7 @@ pub const LibCInstallation = struct { | ... | @@ -143,7 +143,7 @@ pub const LibCInstallation = struct { |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | /// Finds the default, native libc. | 145 | /// Finds the default, native libc. |
| 146 | pub async fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { | 146 | pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { |
| 147 | self.initEmpty(); | 147 | self.initEmpty(); |
| 148 | var group = event.Group(FindError!void).init(allocator); | 148 | var group = event.Group(FindError!void).init(allocator); |
| 149 | errdefer group.wait() catch {}; | 149 | errdefer group.wait() catch {}; |
| ... | @@ -393,14 +393,14 @@ pub const LibCInstallation = struct { | ... | @@ -393,14 +393,14 @@ pub const LibCInstallation = struct { |
| 393 | }; | 393 | }; |
| 394 | 394 | ||
| 395 | /// caller owns returned memory | 395 | /// caller owns returned memory |
| 396 | async fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { | 396 | fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { |
| 397 | const cc_exe = std.os.getenv("CC") orelse "cc"; | 397 | const cc_exe = std.os.getenv("CC") orelse "cc"; |
| 398 | const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file); | 398 | const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file); |
| 399 | defer allocator.free(arg1); | 399 | defer allocator.free(arg1); |
| 400 | const argv = [_][]const u8{ cc_exe, arg1 }; | 400 | const argv = [_][]const u8{ cc_exe, arg1 }; |
| 401 | 401 | ||
| 402 | // TODO This simulates evented I/O for the child process exec | 402 | // TODO This simulates evented I/O for the child process exec |
| 403 | std.event.Loop.instance.?.yield(); | 403 | event.Loop.startCpuBoundOperation(); |
| 404 | const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); | 404 | const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); |
| 405 | const exec_result = if (std.debug.runtime_safety) blk: { | 405 | const exec_result = if (std.debug.runtime_safety) blk: { |
| 406 | break :blk errorable_result catch unreachable; | 406 | break :blk errorable_result catch unreachable; |
src-self-hosted/link.zig+33-35| ... | @@ -11,7 +11,7 @@ const util = @import("util.zig"); | ... | @@ -11,7 +11,7 @@ const util = @import("util.zig"); |
| 11 | const Context = struct { | 11 | const Context = struct { |
| 12 | comp: *Compilation, | 12 | comp: *Compilation, |
| 13 | arena: std.heap.ArenaAllocator, | 13 | arena: std.heap.ArenaAllocator, |
| 14 | args: std.ArrayList([*]const u8), | 14 | args: std.ArrayList([*:0]const u8), |
| 15 | link_in_crt: bool, | 15 | link_in_crt: bool, |
| 16 | 16 | ||
| 17 | link_err: error{OutOfMemory}!void, | 17 | link_err: error{OutOfMemory}!void, |
| ... | @@ -21,7 +21,7 @@ const Context = struct { | ... | @@ -21,7 +21,7 @@ const Context = struct { |
| 21 | out_file_path: std.Buffer, | 21 | out_file_path: std.Buffer, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | pub async fn link(comp: *Compilation) !void { | 24 | pub fn link(comp: *Compilation) !void { |
| 25 | var ctx = Context{ | 25 | var ctx = Context{ |
| 26 | .comp = comp, | 26 | .comp = comp, |
| 27 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), | 27 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| ... | @@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void { | ... | @@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void { |
| 33 | .out_file_path = undefined, | 33 | .out_file_path = undefined, |
| 34 | }; | 34 | }; |
| 35 | defer ctx.arena.deinit(); | 35 | defer ctx.arena.deinit(); |
| 36 | ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator); | 36 | ctx.args = std.ArrayList([*:0]const u8).init(&ctx.arena.allocator); |
| 37 | ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator); | 37 | ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator); |
| 38 | 38 | ||
| 39 | if (comp.link_out_file) |out_file| { | 39 | if (comp.link_out_file) |out_file| { |
| ... | @@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void { | ... | @@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void { |
| 58 | try ctx.args.append("lld"); | 58 | try ctx.args.append("lld"); |
| 59 | 59 | ||
| 60 | if (comp.haveLibC()) { | 60 | if (comp.haveLibC()) { |
| 61 | ctx.libc = ctx.comp.override_libc orelse blk: { | 61 | // TODO https://github.com/ziglang/zig/issues/3190 |
| 62 | var libc = ctx.comp.override_libc orelse blk: { | ||
| 62 | switch (comp.target) { | 63 | switch (comp.target) { |
| 63 | Target.Native => { | 64 | Target.Native => { |
| 64 | break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; | 65 | break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; |
| ... | @@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void { | ... | @@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void { |
| 66 | else => return error.LibCRequiredButNotProvidedOrFound, | 67 | else => return error.LibCRequiredButNotProvidedOrFound, |
| 67 | } | 68 | } |
| 68 | }; | 69 | }; |
| 70 | ctx.libc = libc; | ||
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | try constructLinkerArgs(&ctx); | 73 | try constructLinkerArgs(&ctx); |
| ... | @@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 171 | //} | 173 | //} |
| 172 | 174 | ||
| 173 | try ctx.args.append("-o"); | 175 | try ctx.args.append("-o"); |
| 174 | try ctx.args.append(ctx.out_file_path.ptr()); | 176 | try ctx.args.append(ctx.out_file_path.toSliceConst()); |
| 175 | 177 | ||
| 176 | if (ctx.link_in_crt) { | 178 | if (ctx.link_in_crt) { |
| 177 | const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; | 179 | const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; |
| ... | @@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 214 | 216 | ||
| 215 | if (ctx.comp.haveLibC()) { | 217 | if (ctx.comp.haveLibC()) { |
| 216 | try ctx.args.append("-L"); | 218 | try ctx.args.append("-L"); |
| 217 | try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr); | 219 | // TODO addNullByte should probably return [:0]u8 |
| 220 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr)); | ||
| 218 | 221 | ||
| 219 | try ctx.args.append("-L"); | 222 | try ctx.args.append("-L"); |
| 220 | try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr); | 223 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); |
| 221 | 224 | ||
| 222 | if (!ctx.comp.is_static) { | 225 | if (!ctx.comp.is_static) { |
| 223 | const dl = blk: { | 226 | const dl = blk: { |
| ... | @@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 226 | return error.LibCMissingDynamicLinker; | 229 | return error.LibCMissingDynamicLinker; |
| 227 | }; | 230 | }; |
| 228 | try ctx.args.append("-dynamic-linker"); | 231 | try ctx.args.append("-dynamic-linker"); |
| 229 | try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr); | 232 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); |
| 230 | } | 233 | } |
| 231 | } | 234 | } |
| 232 | 235 | ||
| ... | @@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 238 | // .o files | 241 | // .o files |
| 239 | for (ctx.comp.link_objects) |link_object| { | 242 | for (ctx.comp.link_objects) |link_object| { |
| 240 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); | 243 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); |
| 241 | try ctx.args.append(link_obj_with_null.ptr); | 244 | try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); |
| 242 | } | 245 | } |
| 243 | try addFnObjects(ctx); | 246 | try addFnObjects(ctx); |
| 244 | 247 | ||
| ... | @@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 313 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { | 316 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { |
| 314 | const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename }); | 317 | const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename }); |
| 315 | const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path); | 318 | const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path); |
| 316 | try ctx.args.append(full_path_with_null.ptr); | 319 | try ctx.args.append(@ptrCast([*:0]const u8, full_path_with_null.ptr)); |
| 317 | } | 320 | } |
| 318 | 321 | ||
| 319 | fn constructLinkerArgsCoff(ctx: *Context) !void { | 322 | fn constructLinkerArgsCoff(ctx: *Context) !void { |
| ... | @@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { | ... | @@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 339 | const is_library = ctx.comp.kind == .Lib; | 342 | const is_library = ctx.comp.kind == .Lib; |
| 340 | 343 | ||
| 341 | const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst()); | 344 | const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst()); |
| 342 | try ctx.args.append(out_arg.ptr); | 345 | try ctx.args.append(@ptrCast([*:0]const u8, out_arg.ptr)); |
| 343 | 346 | ||
| 344 | if (ctx.comp.haveLibC()) { | 347 | if (ctx.comp.haveLibC()) { |
| 345 | try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr); | 348 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr)); |
| 346 | try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr); | 349 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr)); |
| 347 | try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr); | 350 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr)); |
| 348 | } | 351 | } |
| 349 | 352 | ||
| 350 | if (ctx.link_in_crt) { | 353 | if (ctx.link_in_crt) { |
| ... | @@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { | ... | @@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 353 | 356 | ||
| 354 | if (ctx.comp.is_static) { | 357 | if (ctx.comp.is_static) { |
| 355 | const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str); | 358 | const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str); |
| 356 | try ctx.args.append(cmt_lib_name.ptr); | 359 | try ctx.args.append(@ptrCast([*:0]const u8, cmt_lib_name.ptr)); |
| 357 | } else { | 360 | } else { |
| 358 | const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str); | 361 | const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str); |
| 359 | try ctx.args.append(msvcrt_lib_name.ptr); | 362 | try ctx.args.append(@ptrCast([*:0]const u8, msvcrt_lib_name.ptr)); |
| 360 | } | 363 | } |
| 361 | 364 | ||
| 362 | const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str); | 365 | const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str); |
| 363 | try ctx.args.append(vcruntime_lib_name.ptr); | 366 | try ctx.args.append(@ptrCast([*:0]const u8, vcruntime_lib_name.ptr)); |
| 364 | 367 | ||
| 365 | const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str); | 368 | const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str); |
| 366 | try ctx.args.append(crt_lib_name.ptr); | 369 | try ctx.args.append(@ptrCast([*:0]const u8, crt_lib_name.ptr)); |
| 367 | 370 | ||
| 368 | // Visual C++ 2015 Conformance Changes | 371 | // Visual C++ 2015 Conformance Changes |
| 369 | // https://msdn.microsoft.com/en-us/library/bb531344.aspx | 372 | // https://msdn.microsoft.com/en-us/library/bb531344.aspx |
| ... | @@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { | ... | @@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 395 | 398 | ||
| 396 | for (ctx.comp.link_objects) |link_object| { | 399 | for (ctx.comp.link_objects) |link_object| { |
| 397 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); | 400 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); |
| 398 | try ctx.args.append(link_obj_with_null.ptr); | 401 | try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); |
| 399 | } | 402 | } |
| 400 | try addFnObjects(ctx); | 403 | try addFnObjects(ctx); |
| 401 | 404 | ||
| ... | @@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 504 | //} | 507 | //} |
| 505 | 508 | ||
| 506 | try ctx.args.append("-arch"); | 509 | try ctx.args.append("-arch"); |
| 507 | const darwin_arch_str = try std.cstr.addNullByte( | 510 | try ctx.args.append(util.getDarwinArchString(ctx.comp.target)); |
| 508 | &ctx.arena.allocator, | ||
| 509 | ctx.comp.target.getDarwinArchString(), | ||
| 510 | ); | ||
| 511 | try ctx.args.append(darwin_arch_str.ptr); | ||
| 512 | 511 | ||
| 513 | const platform = try DarwinPlatform.get(ctx.comp); | 512 | const platform = try DarwinPlatform.get(ctx.comp); |
| 514 | switch (platform.kind) { | 513 | switch (platform.kind) { |
| ... | @@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 517 | .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"), | 516 | .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"), |
| 518 | } | 517 | } |
| 519 | const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro); | 518 | const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro); |
| 520 | try ctx.args.append(ver_str.ptr); | 519 | try ctx.args.append(@ptrCast([*:0]const u8, ver_str.ptr)); |
| 521 | 520 | ||
| 522 | if (ctx.comp.kind == .Exe) { | 521 | if (ctx.comp.kind == .Exe) { |
| 523 | if (ctx.comp.is_static) { | 522 | if (ctx.comp.is_static) { |
| ... | @@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 528 | } | 527 | } |
| 529 | 528 | ||
| 530 | try ctx.args.append("-o"); | 529 | try ctx.args.append("-o"); |
| 531 | try ctx.args.append(ctx.out_file_path.ptr()); | 530 | try ctx.args.append(ctx.out_file_path.toSliceConst()); |
| 532 | 531 | ||
| 533 | //for (size_t i = 0; i < g->rpath_list.length; i += 1) { | 532 | //for (size_t i = 0; i < g->rpath_list.length; i += 1) { |
| 534 | // Buf *rpath = g->rpath_list.at(i); | 533 | // Buf *rpath = g->rpath_list.at(i); |
| ... | @@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 572 | 571 | ||
| 573 | for (ctx.comp.link_objects) |link_object| { | 572 | for (ctx.comp.link_objects) |link_object| { |
| 574 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); | 573 | const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); |
| 575 | try ctx.args.append(link_obj_with_null.ptr); | 574 | try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); |
| 576 | } | 575 | } |
| 577 | try addFnObjects(ctx); | 576 | try addFnObjects(ctx); |
| 578 | 577 | ||
| ... | @@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 593 | } else { | 592 | } else { |
| 594 | if (mem.indexOfScalar(u8, lib.name, '/') == null) { | 593 | if (mem.indexOfScalar(u8, lib.name, '/') == null) { |
| 595 | const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name); | 594 | const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name); |
| 596 | try ctx.args.append(arg.ptr); | 595 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); |
| 597 | } else { | 596 | } else { |
| 598 | const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); | 597 | const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); |
| 599 | try ctx.args.append(arg.ptr); | 598 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); |
| 600 | } | 599 | } |
| 601 | } | 600 | } |
| 602 | } | 601 | } |
| ... | @@ -626,20 +625,19 @@ fn constructLinkerArgsWasm(ctx: *Context) void { | ... | @@ -626,20 +625,19 @@ fn constructLinkerArgsWasm(ctx: *Context) void { |
| 626 | } | 625 | } |
| 627 | 626 | ||
| 628 | fn addFnObjects(ctx: *Context) !void { | 627 | fn addFnObjects(ctx: *Context) !void { |
| 629 | // at this point it's guaranteed nobody else has this lock, so we circumvent it | 628 | const held = ctx.comp.fn_link_set.acquire(); |
| 630 | // and avoid having to be an async function | 629 | defer held.release(); |
| 631 | const fn_link_set = &ctx.comp.fn_link_set.private_data; | ||
| 632 | 630 | ||
| 633 | var it = fn_link_set.first; | 631 | var it = held.value.first; |
| 634 | while (it) |node| { | 632 | while (it) |node| { |
| 635 | const fn_val = node.data orelse { | 633 | const fn_val = node.data orelse { |
| 636 | // handle the tombstone. See Value.Fn.destroy. | 634 | // handle the tombstone. See Value.Fn.destroy. |
| 637 | it = node.next; | 635 | it = node.next; |
| 638 | fn_link_set.remove(node); | 636 | held.value.remove(node); |
| 639 | ctx.comp.gpa().destroy(node); | 637 | ctx.comp.gpa().destroy(node); |
| 640 | continue; | 638 | continue; |
| 641 | }; | 639 | }; |
| 642 | try ctx.args.append(fn_val.containing_object.ptr()); | 640 | try ctx.args.append(fn_val.containing_object.toSliceConst()); |
| 643 | it = node.next; | 641 | it = node.next; |
| 644 | } | 642 | } |
| 645 | } | 643 | } |
src-self-hosted/llvm.zig+1-1| ... | @@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal; | ... | @@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal; |
| 86 | extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value; | 86 | extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value; |
| 87 | 87 | ||
| 88 | pub const ConstStringInContext = LLVMConstStringInContext; | 88 | pub const ConstStringInContext = LLVMConstStringInContext; |
| 89 | extern fn LLVMConstStringInContext(C: *Context, Str: [*:0]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; | 89 | extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; |
| 90 | 90 | ||
| 91 | pub const ConstInt = LLVMConstInt; | 91 | pub const ConstInt = LLVMConstInt; |
| 92 | extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; | 92 | extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; |
src-self-hosted/main.zig+64-73| ... | @@ -49,14 +49,15 @@ const usage = | ... | @@ -49,14 +49,15 @@ const usage = |
| 49 | 49 | ||
| 50 | const Command = struct { | 50 | const Command = struct { |
| 51 | name: []const u8, | 51 | name: []const u8, |
| 52 | exec: fn (*Allocator, []const []const u8) anyerror!void, | 52 | exec: async fn (*Allocator, []const []const u8) anyerror!void, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | pub fn main() !void { | 55 | pub fn main() !void { |
| 56 | // This allocator needs to be thread-safe because we use it for the event.Loop | 56 | // This allocator needs to be thread-safe because we use it for the event.Loop |
| 57 | // which multiplexes async functions onto kernel threads. | 57 | // which multiplexes async functions onto kernel threads. |
| 58 | // libc allocator is guaranteed to have this property. | 58 | // libc allocator is guaranteed to have this property. |
| 59 | const allocator = std.heap.c_allocator; | 59 | // TODO https://github.com/ziglang/zig/issues/3783 |
| 60 | const allocator = std.heap.page_allocator; | ||
| 60 | 61 | ||
| 61 | stdout = &std.io.getStdOut().outStream().stream; | 62 | stdout = &std.io.getStdOut().outStream().stream; |
| 62 | 63 | ||
| ... | @@ -118,14 +119,18 @@ pub fn main() !void { | ... | @@ -118,14 +119,18 @@ pub fn main() !void { |
| 118 | }, | 119 | }, |
| 119 | }; | 120 | }; |
| 120 | 121 | ||
| 121 | for (commands) |command| { | 122 | inline for (commands) |command| { |
| 122 | if (mem.eql(u8, command.name, args[1])) { | 123 | if (mem.eql(u8, command.name, args[1])) { |
| 123 | return command.exec(allocator, args[2..]); | 124 | var frame = try allocator.create(@Frame(command.exec)); |
| 125 | defer allocator.destroy(frame); | ||
| 126 | frame.* = async command.exec(allocator, args[2..]); | ||
| 127 | return await frame; | ||
| 124 | } | 128 | } |
| 125 | } | 129 | } |
| 126 | 130 | ||
| 127 | try stderr.print("unknown command: {}\n\n", args[1]); | 131 | try stderr.print("unknown command: {}\n\n", args[1]); |
| 128 | try stderr.write(usage); | 132 | try stderr.write(usage); |
| 133 | process.argsFree(allocator, args); | ||
| 129 | process.exit(1); | 134 | process.exit(1); |
| 130 | } | 135 | } |
| 131 | 136 | ||
| ... | @@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 461 | comp.link_objects = link_objects; | 466 | comp.link_objects = link_objects; |
| 462 | 467 | ||
| 463 | comp.start(); | 468 | comp.start(); |
| 464 | const frame = async processBuildEvents(comp, color); | 469 | processBuildEvents(comp, color); |
| 465 | } | 470 | } |
| 466 | 471 | ||
| 467 | async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { | 472 | fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 468 | var count: usize = 0; | 473 | var count: usize = 0; |
| 469 | while (true) { | 474 | while (!comp.cancelled) { |
| 470 | // TODO directly awaiting async should guarantee memory allocation elision | ||
| 471 | const build_event = comp.events.get(); | 475 | const build_event = comp.events.get(); |
| 472 | count += 1; | 476 | count += 1; |
| 473 | 477 | ||
| ... | @@ -545,7 +549,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil | ... | @@ -545,7 +549,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil |
| 545 | "Try running `zig libc` to see an example for the native target.\n", | 549 | "Try running `zig libc` to see an example for the native target.\n", |
| 546 | libc_paths_file, | 550 | libc_paths_file, |
| 547 | @errorName(err), | 551 | @errorName(err), |
| 548 | ) catch process.exit(1); | 552 | ) catch {}; |
| 549 | process.exit(1); | 553 | process.exit(1); |
| 550 | }; | 554 | }; |
| 551 | } | 555 | } |
| ... | @@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 567 | var zig_compiler = try ZigCompiler.init(allocator); | 571 | var zig_compiler = try ZigCompiler.init(allocator); |
| 568 | defer zig_compiler.deinit(); | 572 | defer zig_compiler.deinit(); |
| 569 | 573 | ||
| 570 | const frame = async findLibCAsync(&zig_compiler); | ||
| 571 | } | ||
| 572 | |||
| 573 | async fn findLibCAsync(zig_compiler: *ZigCompiler) void { | ||
| 574 | const libc = zig_compiler.getNativeLibC() catch |err| { | 574 | const libc = zig_compiler.getNativeLibC() catch |err| { |
| 575 | stderr.print("unable to find libc: {}\n", @errorName(err)) catch process.exit(1); | 575 | stderr.print("unable to find libc: {}\n", @errorName(err)) catch {}; |
| 576 | process.exit(1); | 576 | process.exit(1); |
| 577 | }; | 577 | }; |
| 578 | libc.render(stdout) catch process.exit(1); | 578 | libc.render(stdout) catch process.exit(1); |
| ... | @@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 644 | process.exit(1); | 644 | process.exit(1); |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | return asyncFmtMain( | 647 | var fmt = Fmt{ |
| 648 | allocator, | 648 | .allocator = allocator, |
| 649 | &flags, | 649 | .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)), |
| 650 | color, | 650 | .any_error = false, |
| 651 | ); | 651 | .color = color, |
| 652 | }; | ||
| 653 | |||
| 654 | const check_mode = flags.present("check"); | ||
| 655 | |||
| 656 | var group = event.Group(FmtError!void).init(allocator); | ||
| 657 | for (flags.positionals.toSliceConst()) |file_path| { | ||
| 658 | try group.call(fmtPath, &fmt, file_path, check_mode); | ||
| 659 | } | ||
| 660 | try group.wait(); | ||
| 661 | if (fmt.any_error) { | ||
| 662 | process.exit(1); | ||
| 663 | } | ||
| 652 | } | 664 | } |
| 653 | 665 | ||
| 654 | const FmtError = error{ | 666 | const FmtError = error{ |
| ... | @@ -673,30 +685,6 @@ const FmtError = error{ | ... | @@ -673,30 +685,6 @@ const FmtError = error{ |
| 673 | CurrentWorkingDirectoryUnlinked, | 685 | CurrentWorkingDirectoryUnlinked, |
| 674 | } || fs.File.OpenError; | 686 | } || fs.File.OpenError; |
| 675 | 687 | ||
| 676 | async fn asyncFmtMain( | ||
| 677 | allocator: *Allocator, | ||
| 678 | flags: *const Args, | ||
| 679 | color: errmsg.Color, | ||
| 680 | ) FmtError!void { | ||
| 681 | var fmt = Fmt{ | ||
| 682 | .allocator = allocator, | ||
| 683 | .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)), | ||
| 684 | .any_error = false, | ||
| 685 | .color = color, | ||
| 686 | }; | ||
| 687 | |||
| 688 | const check_mode = flags.present("check"); | ||
| 689 | |||
| 690 | var group = event.Group(FmtError!void).init(allocator); | ||
| 691 | for (flags.positionals.toSliceConst()) |file_path| { | ||
| 692 | try group.call(fmtPath, &fmt, file_path, check_mode); | ||
| 693 | } | ||
| 694 | try group.wait(); | ||
| 695 | if (fmt.any_error) { | ||
| 696 | process.exit(1); | ||
| 697 | } | ||
| 698 | } | ||
| 699 | |||
| 700 | async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { | 688 | async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { |
| 701 | const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); | 689 | const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); |
| 702 | defer fmt.allocator.free(file_path); | 690 | defer fmt.allocator.free(file_path); |
| ... | @@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro | ... | @@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 708 | if (try held.value.put(file_path, {})) |_| return; | 696 | if (try held.value.put(file_path, {})) |_| return; |
| 709 | } | 697 | } |
| 710 | 698 | ||
| 711 | const source_code = ""; | 699 | const source_code = event.fs.readFile( |
| 712 | // const source_code = event.fs.readFile( | 700 | fmt.allocator, |
| 713 | // file_path, | 701 | file_path, |
| 714 | // max_src_size, | 702 | max_src_size, |
| 715 | // ) catch |err| switch (err) { | 703 | ) catch |err| switch (err) { |
| 716 | // error.IsDir, error.AccessDenied => { | 704 | error.IsDir, error.AccessDenied => { |
| 717 | // // TODO make event based (and dir.next()) | 705 | var dir = try fs.cwd().openDirList(file_path); |
| 718 | // var dir = try fs.Dir.cwd().openDirList(file_path); | 706 | defer dir.close(); |
| 719 | // defer dir.close(); | 707 | |
| 720 | 708 | var group = event.Group(FmtError!void).init(fmt.allocator); | |
| 721 | // var group = event.Group(FmtError!void).init(fmt.allocator); | 709 | var it = dir.iterate(); |
| 722 | // while (try dir.next()) |entry| { | 710 | while (try it.next()) |entry| { |
| 723 | // if (entry.kind == fs.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) { | 711 | if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { |
| 724 | // const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name }); | 712 | const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name }); |
| 725 | // try group.call(fmtPath, fmt, full_path, check_mode); | 713 | @panic("TODO https://github.com/ziglang/zig/issues/3777"); |
| 726 | // } | 714 | // try group.call(fmtPath, fmt, full_path, check_mode); |
| 727 | // } | 715 | } |
| 728 | // return group.wait(); | 716 | } |
| 729 | // }, | 717 | return group.wait(); |
| 730 | // else => { | 718 | }, |
| 731 | // // TODO lock stderr printing | 719 | else => { |
| 732 | // try stderr.print("unable to open '{}': {}\n", file_path, err); | 720 | // TODO lock stderr printing |
| 733 | // fmt.any_error = true; | 721 | try stderr.print("unable to open '{}': {}\n", file_path, err); |
| 734 | // return; | 722 | fmt.any_error = true; |
| 735 | // }, | 723 | return; |
| 736 | // }; | 724 | }, |
| 737 | // defer fmt.allocator.free(source_code); | 725 | }; |
| 726 | defer fmt.allocator.free(source_code); | ||
| 738 | 727 | ||
| 739 | const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { | 728 | const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { |
| 740 | try stderr.print("error parsing file '{}': {}\n", file_path, err); | 729 | try stderr.print("error parsing file '{}': {}\n", file_path, err); |
| ... | @@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { |
| 867 | .exec = cmdInternalBuildInfo, | 856 | .exec = cmdInternalBuildInfo, |
| 868 | }}; | 857 | }}; |
| 869 | 858 | ||
| 870 | for (sub_commands) |sub_command| { | 859 | inline for (sub_commands) |sub_command| { |
| 871 | if (mem.eql(u8, sub_command.name, args[0])) { | 860 | if (mem.eql(u8, sub_command.name, args[0])) { |
| 872 | try sub_command.exec(allocator, args[1..]); | 861 | var frame = try allocator.create(@Frame(sub_command.exec)); |
| 873 | return; | 862 | defer allocator.destroy(frame); |
| 863 | frame.* = async sub_command.exec(allocator, args[1..]); | ||
| 864 | return await frame; | ||
| 874 | } | 865 | } |
| 875 | } | 866 | } |
| 876 | 867 |
src-self-hosted/stage1.zig+4-4| ... | @@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void | ... | @@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void |
| 279 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { | 279 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { |
| 280 | error.IsDir, error.AccessDenied => { | 280 | error.IsDir, error.AccessDenied => { |
| 281 | // TODO make event based (and dir.next()) | 281 | // TODO make event based (and dir.next()) |
| 282 | var dir = try fs.Dir.cwd().openDirList(file_path); | 282 | var dir = try fs.cwd().openDirList(file_path); |
| 283 | defer dir.close(); | 283 | defer dir.close(); |
| 284 | 284 | ||
| 285 | var dir_it = dir.iterate(); | 285 | var dir_it = dir.iterate(); |
| ... | @@ -427,11 +427,11 @@ export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextRes | ... | @@ -427,11 +427,11 @@ export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextRes |
| 427 | }; | 427 | }; |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | export const stage2_DepTokenizer = extern struct { | 430 | const stage2_DepTokenizer = extern struct { |
| 431 | handle: *DepTokenizer, | 431 | handle: *DepTokenizer, |
| 432 | }; | 432 | }; |
| 433 | 433 | ||
| 434 | export const stage2_DepNextResult = extern struct { | 434 | const stage2_DepNextResult = extern struct { |
| 435 | type_id: TypeId, | 435 | type_id: TypeId, |
| 436 | 436 | ||
| 437 | // when type_id == error --> error text | 437 | // when type_id == error --> error text |
| ... | @@ -440,7 +440,7 @@ export const stage2_DepNextResult = extern struct { | ... | @@ -440,7 +440,7 @@ export const stage2_DepNextResult = extern struct { |
| 440 | // when type_id == prereq --> prereq pathname | 440 | // when type_id == prereq --> prereq pathname |
| 441 | textz: [*]const u8, | 441 | textz: [*]const u8, |
| 442 | 442 | ||
| 443 | export const TypeId = extern enum { | 443 | const TypeId = extern enum { |
| 444 | error_, | 444 | error_, |
| 445 | null_, | 445 | null_, |
| 446 | target, | 446 | target, |
src-self-hosted/test.zig+11-13| ... | @@ -26,7 +26,8 @@ test "stage2" { | ... | @@ -26,7 +26,8 @@ test "stage2" { |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | const file1 = "1.zig"; | 28 | const file1 = "1.zig"; |
| 29 | const allocator = std.heap.c_allocator; | 29 | // TODO https://github.com/ziglang/zig/issues/3783 |
| 30 | const allocator = std.heap.page_allocator; | ||
| 30 | 31 | ||
| 31 | pub const TestContext = struct { | 32 | pub const TestContext = struct { |
| 32 | zig_compiler: ZigCompiler, | 33 | zig_compiler: ZigCompiler, |
| ... | @@ -94,8 +95,8 @@ pub const TestContext = struct { | ... | @@ -94,8 +95,8 @@ pub const TestContext = struct { |
| 94 | &self.zig_compiler, | 95 | &self.zig_compiler, |
| 95 | "test", | 96 | "test", |
| 96 | file1_path, | 97 | file1_path, |
| 97 | Target.Native, | 98 | .Native, |
| 98 | Compilation.Kind.Obj, | 99 | .Obj, |
| 99 | .Debug, | 100 | .Debug, |
| 100 | true, // is_static | 101 | true, // is_static |
| 101 | self.zig_lib_dir, | 102 | self.zig_lib_dir, |
| ... | @@ -116,7 +117,7 @@ pub const TestContext = struct { | ... | @@ -116,7 +117,7 @@ pub const TestContext = struct { |
| 116 | const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr()); | 117 | const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr()); |
| 117 | const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 }); | 118 | const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 }); |
| 118 | 119 | ||
| 119 | const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{.Native = {}}).exeFileExt()); | 120 | const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{ .Native = {} }).exeFileExt()); |
| 120 | if (std.fs.path.dirname(file1_path)) |dirname| { | 121 | if (std.fs.path.dirname(file1_path)) |dirname| { |
| 121 | try std.fs.makePath(allocator, dirname); | 122 | try std.fs.makePath(allocator, dirname); |
| 122 | } | 123 | } |
| ... | @@ -128,8 +129,8 @@ pub const TestContext = struct { | ... | @@ -128,8 +129,8 @@ pub const TestContext = struct { |
| 128 | &self.zig_compiler, | 129 | &self.zig_compiler, |
| 129 | "test", | 130 | "test", |
| 130 | file1_path, | 131 | file1_path, |
| 131 | Target.Native, | 132 | .Native, |
| 132 | Compilation.Kind.Exe, | 133 | .Exe, |
| 133 | .Debug, | 134 | .Debug, |
| 134 | false, | 135 | false, |
| 135 | self.zig_lib_dir, | 136 | self.zig_lib_dir, |
| ... | @@ -148,15 +149,12 @@ pub const TestContext = struct { | ... | @@ -148,15 +149,12 @@ pub const TestContext = struct { |
| 148 | exe_file: []const u8, | 149 | exe_file: []const u8, |
| 149 | expected_output: []const u8, | 150 | expected_output: []const u8, |
| 150 | ) anyerror!void { | 151 | ) anyerror!void { |
| 151 | // TODO this should not be necessary | ||
| 152 | const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file); | ||
| 153 | |||
| 154 | defer comp.destroy(); | 152 | defer comp.destroy(); |
| 155 | const build_event = comp.events.get(); | 153 | const build_event = comp.events.get(); |
| 156 | 154 | ||
| 157 | switch (build_event) { | 155 | switch (build_event) { |
| 158 | .Ok => { | 156 | .Ok => { |
| 159 | const argv = [_][]const u8{exe_file_2}; | 157 | const argv = [_][]const u8{exe_file}; |
| 160 | // TODO use event loop | 158 | // TODO use event loop |
| 161 | const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024); | 159 | const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024); |
| 162 | switch (child.term) { | 160 | switch (child.term) { |
| ... | @@ -173,13 +171,13 @@ pub const TestContext = struct { | ... | @@ -173,13 +171,13 @@ pub const TestContext = struct { |
| 173 | return error.OutputMismatch; | 171 | return error.OutputMismatch; |
| 174 | } | 172 | } |
| 175 | }, | 173 | }, |
| 176 | Compilation.Event.Error => |err| return err, | 174 | .Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err, |
| 177 | Compilation.Event.Fail => |msgs| { | 175 | .Fail => |msgs| { |
| 178 | const stderr = std.io.getStdErr(); | 176 | const stderr = std.io.getStdErr(); |
| 179 | try stderr.write("build incorrectly failed:\n"); | 177 | try stderr.write("build incorrectly failed:\n"); |
| 180 | for (msgs) |msg| { | 178 | for (msgs) |msg| { |
| 181 | defer msg.destroy(); | 179 | defer msg.destroy(); |
| 182 | try msg.printToFile(stderr, errmsg.Color.Auto); | 180 | try msg.printToFile(stderr, .Auto); |
| 183 | } | 181 | } |
| 184 | }, | 182 | }, |
| 185 | } | 183 | } |
src-self-hosted/type.zig+14-12| ... | @@ -53,7 +53,7 @@ pub const Type = struct { | ... | @@ -53,7 +53,7 @@ pub const Type = struct { |
| 53 | base: *Type, | 53 | base: *Type, |
| 54 | allocator: *Allocator, | 54 | allocator: *Allocator, |
| 55 | llvm_context: *llvm.Context, | 55 | llvm_context: *llvm.Context, |
| 56 | ) (error{OutOfMemory}!*llvm.Type) { | 56 | ) error{OutOfMemory}!*llvm.Type { |
| 57 | switch (base.id) { | 57 | switch (base.id) { |
| 58 | .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), | 58 | .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), |
| 59 | .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), | 59 | .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), |
| ... | @@ -184,7 +184,7 @@ pub const Type = struct { | ... | @@ -184,7 +184,7 @@ pub const Type = struct { |
| 184 | 184 | ||
| 185 | /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead. | 185 | /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead. |
| 186 | /// Otherwise, this one will grab one from the pool and then release it. | 186 | /// Otherwise, this one will grab one from the pool and then release it. |
| 187 | pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 { | 187 | pub fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 { |
| 188 | if (base.abi_alignment.start()) |ptr| return ptr.*; | 188 | if (base.abi_alignment.start()) |ptr| return ptr.*; |
| 189 | 189 | ||
| 190 | { | 190 | { |
| ... | @@ -200,7 +200,7 @@ pub const Type = struct { | ... | @@ -200,7 +200,7 @@ pub const Type = struct { |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /// If you have an llvm conext handy, you can use it here. | 202 | /// If you have an llvm conext handy, you can use it here. |
| 203 | pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { | 203 | pub fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { |
| 204 | if (base.abi_alignment.start()) |ptr| return ptr.*; | 204 | if (base.abi_alignment.start()) |ptr| return ptr.*; |
| 205 | 205 | ||
| 206 | base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context); | 206 | base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context); |
| ... | @@ -209,7 +209,7 @@ pub const Type = struct { | ... | @@ -209,7 +209,7 @@ pub const Type = struct { |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | /// Lower level function that does the work. See getAbiAlignment. | 211 | /// Lower level function that does the work. See getAbiAlignment. |
| 212 | async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { | 212 | fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { |
| 213 | const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); | 213 | const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); |
| 214 | return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); | 214 | return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); |
| 215 | } | 215 | } |
| ... | @@ -367,7 +367,7 @@ pub const Type = struct { | ... | @@ -367,7 +367,7 @@ pub const Type = struct { |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | /// takes ownership of key.Normal.params on success | 369 | /// takes ownership of key.Normal.params on success |
| 370 | pub async fn get(comp: *Compilation, key: Key) !*Fn { | 370 | pub fn get(comp: *Compilation, key: Key) !*Fn { |
| 371 | { | 371 | { |
| 372 | const held = comp.fn_type_table.acquire(); | 372 | const held = comp.fn_type_table.acquire(); |
| 373 | defer held.release(); | 373 | defer held.release(); |
| ... | @@ -564,7 +564,7 @@ pub const Type = struct { | ... | @@ -564,7 +564,7 @@ pub const Type = struct { |
| 564 | return comp.u8_type; | 564 | return comp.u8_type; |
| 565 | } | 565 | } |
| 566 | 566 | ||
| 567 | pub async fn get(comp: *Compilation, key: Key) !*Int { | 567 | pub fn get(comp: *Compilation, key: Key) !*Int { |
| 568 | { | 568 | { |
| 569 | const held = comp.int_type_table.acquire(); | 569 | const held = comp.int_type_table.acquire(); |
| 570 | defer held.release(); | 570 | defer held.release(); |
| ... | @@ -606,7 +606,7 @@ pub const Type = struct { | ... | @@ -606,7 +606,7 @@ pub const Type = struct { |
| 606 | comp.registerGarbage(Int, &self.garbage_node); | 606 | comp.registerGarbage(Int, &self.garbage_node); |
| 607 | } | 607 | } |
| 608 | 608 | ||
| 609 | pub async fn gcDestroy(self: *Int, comp: *Compilation) void { | 609 | pub fn gcDestroy(self: *Int, comp: *Compilation) void { |
| 610 | { | 610 | { |
| 611 | const held = comp.int_type_table.acquire(); | 611 | const held = comp.int_type_table.acquire(); |
| 612 | defer held.release(); | 612 | defer held.release(); |
| ... | @@ -700,7 +700,7 @@ pub const Type = struct { | ... | @@ -700,7 +700,7 @@ pub const Type = struct { |
| 700 | comp.registerGarbage(Pointer, &self.garbage_node); | 700 | comp.registerGarbage(Pointer, &self.garbage_node); |
| 701 | } | 701 | } |
| 702 | 702 | ||
| 703 | pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void { | 703 | pub fn gcDestroy(self: *Pointer, comp: *Compilation) void { |
| 704 | { | 704 | { |
| 705 | const held = comp.ptr_type_table.acquire(); | 705 | const held = comp.ptr_type_table.acquire(); |
| 706 | defer held.release(); | 706 | defer held.release(); |
| ... | @@ -711,14 +711,14 @@ pub const Type = struct { | ... | @@ -711,14 +711,14 @@ pub const Type = struct { |
| 711 | comp.gpa().destroy(self); | 711 | comp.gpa().destroy(self); |
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 { | 714 | pub fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 { |
| 715 | switch (self.key.alignment) { | 715 | switch (self.key.alignment) { |
| 716 | .Abi => return self.key.child_type.getAbiAlignment(comp), | 716 | .Abi => return self.key.child_type.getAbiAlignment(comp), |
| 717 | .Override => |alignment| return alignment, | 717 | .Override => |alignment| return alignment, |
| 718 | } | 718 | } |
| 719 | } | 719 | } |
| 720 | 720 | ||
| 721 | pub async fn get( | 721 | pub fn get( |
| 722 | comp: *Compilation, | 722 | comp: *Compilation, |
| 723 | key: Key, | 723 | key: Key, |
| 724 | ) !*Pointer { | 724 | ) !*Pointer { |
| ... | @@ -726,8 +726,10 @@ pub const Type = struct { | ... | @@ -726,8 +726,10 @@ pub const Type = struct { |
| 726 | switch (key.alignment) { | 726 | switch (key.alignment) { |
| 727 | .Abi => {}, | 727 | .Abi => {}, |
| 728 | .Override => |alignment| { | 728 | .Override => |alignment| { |
| 729 | // TODO https://github.com/ziglang/zig/issues/3190 | ||
| 730 | var align_spill = alignment; | ||
| 729 | const abi_align = try key.child_type.getAbiAlignment(comp); | 731 | const abi_align = try key.child_type.getAbiAlignment(comp); |
| 730 | if (abi_align == alignment) { | 732 | if (abi_align == align_spill) { |
| 731 | normal_key.alignment = .Abi; | 733 | normal_key.alignment = .Abi; |
| 732 | } | 734 | } |
| 733 | }, | 735 | }, |
| ... | @@ -828,7 +830,7 @@ pub const Type = struct { | ... | @@ -828,7 +830,7 @@ pub const Type = struct { |
| 828 | comp.gpa().destroy(self); | 830 | comp.gpa().destroy(self); |
| 829 | } | 831 | } |
| 830 | 832 | ||
| 831 | pub async fn get(comp: *Compilation, key: Key) !*Array { | 833 | pub fn get(comp: *Compilation, key: Key) !*Array { |
| 832 | key.elem_type.base.ref(); | 834 | key.elem_type.base.ref(); |
| 833 | errdefer key.elem_type.base.deref(comp); | 835 | errdefer key.elem_type.base.deref(comp); |
| 834 | 836 |
src-self-hosted/util.zig+12-11| ... | @@ -32,21 +32,21 @@ pub fn getFloatAbi(self: Target) FloatAbi { | ... | @@ -32,21 +32,21 @@ pub fn getFloatAbi(self: Target) FloatAbi { |
| 32 | }; | 32 | }; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | pub fn getObjectFormat(self: Target) Target.ObjectFormat { | 35 | pub fn getObjectFormat(target: Target) Target.ObjectFormat { |
| 36 | return switch (self) { | 36 | switch (target) { |
| 37 | .Native => @import("builtin").object_format, | 37 | .Native => return @import("builtin").object_format, |
| 38 | .Cross => { | 38 | .Cross => blk: { |
| 39 | if (target.isWindows() or target.isUefi()) { | 39 | if (target.isWindows() or target.isUefi()) { |
| 40 | break .coff; | 40 | return .coff; |
| 41 | } else if (target.isDarwin()) { | 41 | } else if (target.isDarwin()) { |
| 42 | break .macho; | 42 | return .macho; |
| 43 | } | 43 | } |
| 44 | if (target.isWasm()) { | 44 | if (target.isWasm()) { |
| 45 | break .wasm; | 45 | return .wasm; |
| 46 | } | 46 | } |
| 47 | break .elf; | 47 | return .elf; |
| 48 | }, | 48 | }, |
| 49 | }; | 49 | } |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { | 52 | pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { |
| ... | @@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { | ... | @@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { |
| 156 | } | 156 | } |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | pub fn getDarwinArchString(self: Target) []const u8 { | 159 | pub fn getDarwinArchString(self: Target) [:0]const u8 { |
| 160 | const arch = self.getArch(); | 160 | const arch = self.getArch(); |
| 161 | switch (arch) { | 161 | switch (arch) { |
| 162 | .aarch64 => return "arm64", | 162 | .aarch64 => return "arm64", |
| ... | @@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 { | ... | @@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 { |
| 166 | .powerpc => return "ppc", | 166 | .powerpc => return "ppc", |
| 167 | .powerpc64 => return "ppc64", | 167 | .powerpc64 => return "ppc64", |
| 168 | .powerpc64le => return "ppc64le", | 168 | .powerpc64le => return "ppc64le", |
| 169 | else => return @tagName(arch), | 169 | // @tagName should be able to return sentinel terminated slice |
| 170 | else => @panic("TODO https://github.com/ziglang/zig/issues/3779"), //return @tagName(arch), | ||
| 170 | } | 171 | } |
| 171 | } | 172 | } |
| 172 | 173 |
src-self-hosted/value.zig+7-7| ... | @@ -156,7 +156,7 @@ pub const Value = struct { | ... | @@ -156,7 +156,7 @@ pub const Value = struct { |
| 156 | const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); | 156 | const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); |
| 157 | const llvm_fn = llvm.AddFunction( | 157 | const llvm_fn = llvm.AddFunction( |
| 158 | ofile.module, | 158 | ofile.module, |
| 159 | self.symbol_name.ptr(), | 159 | self.symbol_name.toSliceConst(), |
| 160 | llvm_fn_type, | 160 | llvm_fn_type, |
| 161 | ) orelse return error.OutOfMemory; | 161 | ) orelse return error.OutOfMemory; |
| 162 | 162 | ||
| ... | @@ -241,7 +241,7 @@ pub const Value = struct { | ... | @@ -241,7 +241,7 @@ pub const Value = struct { |
| 241 | const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); | 241 | const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); |
| 242 | const llvm_fn = llvm.AddFunction( | 242 | const llvm_fn = llvm.AddFunction( |
| 243 | ofile.module, | 243 | ofile.module, |
| 244 | self.symbol_name.ptr(), | 244 | self.symbol_name.toSliceConst(), |
| 245 | llvm_fn_type, | 245 | llvm_fn_type, |
| 246 | ) orelse return error.OutOfMemory; | 246 | ) orelse return error.OutOfMemory; |
| 247 | 247 | ||
| ... | @@ -334,7 +334,7 @@ pub const Value = struct { | ... | @@ -334,7 +334,7 @@ pub const Value = struct { |
| 334 | field_index: usize, | 334 | field_index: usize, |
| 335 | }; | 335 | }; |
| 336 | 336 | ||
| 337 | pub async fn createArrayElemPtr( | 337 | pub fn createArrayElemPtr( |
| 338 | comp: *Compilation, | 338 | comp: *Compilation, |
| 339 | array_val: *Array, | 339 | array_val: *Array, |
| 340 | mut: Type.Pointer.Mut, | 340 | mut: Type.Pointer.Mut, |
| ... | @@ -350,7 +350,7 @@ pub const Value = struct { | ... | @@ -350,7 +350,7 @@ pub const Value = struct { |
| 350 | .mut = mut, | 350 | .mut = mut, |
| 351 | .vol = Type.Pointer.Vol.Non, | 351 | .vol = Type.Pointer.Vol.Non, |
| 352 | .size = size, | 352 | .size = size, |
| 353 | .alignment = Type.Pointer.Align.Abi, | 353 | .alignment = .Abi, |
| 354 | }); | 354 | }); |
| 355 | var ptr_type_consumed = false; | 355 | var ptr_type_consumed = false; |
| 356 | errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); | 356 | errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); |
| ... | @@ -390,13 +390,13 @@ pub const Value = struct { | ... | @@ -390,13 +390,13 @@ pub const Value = struct { |
| 390 | const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; | 390 | const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; |
| 391 | const ptr_bit_count = ofile.comp.target_ptr_bits; | 391 | const ptr_bit_count = ofile.comp.target_ptr_bits; |
| 392 | const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; | 392 | const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; |
| 393 | const indices = [_]*llvm.Value{ | 393 | var indices = [_]*llvm.Value{ |
| 394 | llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, | 394 | llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, |
| 395 | llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, | 395 | llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, |
| 396 | }; | 396 | }; |
| 397 | return llvm.ConstInBoundsGEP( | 397 | return llvm.ConstInBoundsGEP( |
| 398 | array_llvm_value, | 398 | array_llvm_value, |
| 399 | &indices, | 399 | @ptrCast([*]*llvm.Value, &indices), |
| 400 | @intCast(c_uint, indices.len), | 400 | @intCast(c_uint, indices.len), |
| 401 | ) orelse return error.OutOfMemory; | 401 | ) orelse return error.OutOfMemory; |
| 402 | }, | 402 | }, |
| ... | @@ -423,7 +423,7 @@ pub const Value = struct { | ... | @@ -423,7 +423,7 @@ pub const Value = struct { |
| 423 | }; | 423 | }; |
| 424 | 424 | ||
| 425 | /// Takes ownership of buffer | 425 | /// Takes ownership of buffer |
| 426 | pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array { | 426 | pub fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array { |
| 427 | const u8_type = Type.Int.get_u8(comp); | 427 | const u8_type = Type.Int.get_u8(comp); |
| 428 | defer u8_type.base.base.deref(comp); | 428 | defer u8_type.base.base.deref(comp); |
| 429 | 429 |
src/all_types.hpp+3-1| ... | @@ -1565,7 +1565,7 @@ struct ZigFn { | ... | @@ -1565,7 +1565,7 @@ struct ZigFn { |
| 1565 | // in the case of async functions this is the implicit return type according to the | 1565 | // in the case of async functions this is the implicit return type according to the |
| 1566 | // zig source code, not according to zig ir | 1566 | // zig source code, not according to zig ir |
| 1567 | ZigType *src_implicit_return_type; | 1567 | ZigType *src_implicit_return_type; |
| 1568 | IrExecutable ir_executable; | 1568 | IrExecutable *ir_executable; |
| 1569 | IrExecutable analyzed_executable; | 1569 | IrExecutable analyzed_executable; |
| 1570 | size_t prealloc_bbc; | 1570 | size_t prealloc_bbc; |
| 1571 | size_t prealloc_backward_branch_quota; | 1571 | size_t prealloc_backward_branch_quota; |
| ... | @@ -2204,6 +2204,8 @@ struct ZigVar { | ... | @@ -2204,6 +2204,8 @@ struct ZigVar { |
| 2204 | bool src_is_const; | 2204 | bool src_is_const; |
| 2205 | bool gen_is_const; | 2205 | bool gen_is_const; |
| 2206 | bool is_thread_local; | 2206 | bool is_thread_local; |
| 2207 | bool is_comptime_memoized; | ||
| 2208 | bool is_comptime_memoized_value; | ||
| 2207 | }; | 2209 | }; |
| 2208 | 2210 | ||
| 2209 | struct ErrorTableEntry { | 2211 | struct ErrorTableEntry { |
src/analyze.cpp+32-9| ... | @@ -3275,14 +3275,15 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i | ... | @@ -3275,14 +3275,15 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i |
| 3275 | } | 3275 | } |
| 3276 | 3276 | ||
| 3277 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { | 3277 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { |
| 3278 | ZigFn *fn_entry = allocate<ZigFn>(1); | 3278 | ZigFn *fn_entry = allocate<ZigFn>(1, "ZigFn"); |
| 3279 | fn_entry->ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1"); | ||
| 3279 | 3280 | ||
| 3280 | fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota; | 3281 | fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota; |
| 3281 | 3282 | ||
| 3282 | fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; | 3283 | fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; |
| 3283 | fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; | 3284 | fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; |
| 3284 | fn_entry->analyzed_executable.fn_entry = fn_entry; | 3285 | fn_entry->analyzed_executable.fn_entry = fn_entry; |
| 3285 | fn_entry->ir_executable.fn_entry = fn_entry; | 3286 | fn_entry->ir_executable->fn_entry = fn_entry; |
| 3286 | fn_entry->fn_inline = inline_value; | 3287 | fn_entry->fn_inline = inline_value; |
| 3287 | 3288 | ||
| 3288 | return fn_entry; | 3289 | return fn_entry; |
| ... | @@ -3792,6 +3793,16 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3792,6 +3793,16 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3792 | return variable_entry; | 3793 | return variable_entry; |
| 3793 | } | 3794 | } |
| 3794 | 3795 | ||
| 3796 | static void validate_export_var_type(CodeGen *g, ZigType* type, AstNode *source_node) { | ||
| 3797 | switch (type->id) { | ||
| 3798 | case ZigTypeIdMetaType: | ||
| 3799 | add_node_error(g, source_node, buf_sprintf("cannot export variable of type 'type'")); | ||
| 3800 | break; | ||
| 3801 | default: | ||
| 3802 | break; | ||
| 3803 | } | ||
| 3804 | } | ||
| 3805 | |||
| 3795 | static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { | 3806 | static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { |
| 3796 | AstNode *source_node = tld_var->base.source_node; | 3807 | AstNode *source_node = tld_var->base.source_node; |
| 3797 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; | 3808 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; |
| ... | @@ -3881,6 +3892,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { | ... | @@ -3881,6 +3892,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { |
| 3881 | } | 3892 | } |
| 3882 | 3893 | ||
| 3883 | if (is_export) { | 3894 | if (is_export) { |
| 3895 | validate_export_var_type(g, type, source_node); | ||
| 3884 | add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong); | 3896 | add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong); |
| 3885 | } | 3897 | } |
| 3886 | 3898 | ||
| ... | @@ -4599,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { | ... | @@ -4599,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { |
| 4599 | assert(!fn_type->data.fn.is_generic); | 4611 | assert(!fn_type->data.fn.is_generic); |
| 4600 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 4612 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 4601 | 4613 | ||
| 4602 | ZigType *block_return_type = ir_analyze(g, &fn->ir_executable, | 4614 | ZigType *block_return_type = ir_analyze(g, fn->ir_executable, |
| 4603 | &fn->analyzed_executable, fn_type_id->return_type, return_type_node); | 4615 | &fn->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 4604 | fn->src_implicit_return_type = block_return_type; | 4616 | fn->src_implicit_return_type = block_return_type; |
| 4605 | 4617 | ||
| ... | @@ -4695,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -4695,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 4695 | assert(!fn_type->data.fn.is_generic); | 4707 | assert(!fn_type->data.fn.is_generic); |
| 4696 | 4708 | ||
| 4697 | ir_gen_fn(g, fn_table_entry); | 4709 | ir_gen_fn(g, fn_table_entry); |
| 4698 | if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) { | 4710 | if (fn_table_entry->ir_executable->first_err_trace_msg != nullptr) { |
| 4699 | fn_table_entry->anal_state = FnAnalStateInvalid; | 4711 | fn_table_entry->anal_state = FnAnalStateInvalid; |
| 4700 | return; | 4712 | return; |
| 4701 | } | 4713 | } |
| ... | @@ -4703,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -4703,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 4703 | fprintf(stderr, "\n"); | 4715 | fprintf(stderr, "\n"); |
| 4704 | ast_render(stderr, fn_table_entry->body_node, 4); | 4716 | ast_render(stderr, fn_table_entry->body_node, 4); |
| 4705 | fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); | 4717 | fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); |
| 4706 | ir_print(g, stderr, &fn_table_entry->ir_executable, 4, IrPassSrc); | 4718 | ir_print(g, stderr, fn_table_entry->ir_executable, 4, IrPassSrc); |
| 4707 | fprintf(stderr, "}\n"); | 4719 | fprintf(stderr, "}\n"); |
| 4708 | } | 4720 | } |
| 4709 | 4721 | ||
| ... | @@ -6442,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { | ... | @@ -6442,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 6442 | } | 6454 | } |
| 6443 | 6455 | ||
| 6444 | bool ir_get_var_is_comptime(ZigVar *var) { | 6456 | bool ir_get_var_is_comptime(ZigVar *var) { |
| 6457 | if (var->is_comptime_memoized) | ||
| 6458 | return var->is_comptime_memoized_value; | ||
| 6459 | |||
| 6460 | var->is_comptime_memoized = true; | ||
| 6461 | |||
| 6445 | // The is_comptime field can be left null, which means not comptime. | 6462 | // The is_comptime field can be left null, which means not comptime. |
| 6446 | if (var->is_comptime == nullptr) | 6463 | if (var->is_comptime == nullptr) { |
| 6447 | return false; | 6464 | var->is_comptime_memoized_value = false; |
| 6465 | return var->is_comptime_memoized_value; | ||
| 6466 | } | ||
| 6448 | // When the is_comptime field references an instruction that has to get analyzed, this | 6467 | // When the is_comptime field references an instruction that has to get analyzed, this |
| 6449 | // is the value. | 6468 | // is the value. |
| 6450 | if (var->is_comptime->child != nullptr) { | 6469 | if (var->is_comptime->child != nullptr) { |
| 6451 | assert(var->is_comptime->child->value->type->id == ZigTypeIdBool); | 6470 | assert(var->is_comptime->child->value->type->id == ZigTypeIdBool); |
| 6452 | return var->is_comptime->child->value->data.x_bool; | 6471 | var->is_comptime_memoized_value = var->is_comptime->child->value->data.x_bool; |
| 6472 | var->is_comptime = nullptr; | ||
| 6473 | return var->is_comptime_memoized_value; | ||
| 6453 | } | 6474 | } |
| 6454 | // As an optimization, is_comptime values which are constant are allowed | 6475 | // As an optimization, is_comptime values which are constant are allowed |
| 6455 | // to be omitted from analysis. In this case, there is no child instruction | 6476 | // to be omitted from analysis. In this case, there is no child instruction |
| 6456 | // and we simply look at the unanalyzed const parent instruction. | 6477 | // and we simply look at the unanalyzed const parent instruction. |
| 6457 | assert(var->is_comptime->value->type->id == ZigTypeIdBool); | 6478 | assert(var->is_comptime->value->type->id == ZigTypeIdBool); |
| 6458 | return var->is_comptime->value->data.x_bool; | 6479 | var->is_comptime_memoized_value = var->is_comptime->value->data.x_bool; |
| 6480 | var->is_comptime = nullptr; | ||
| 6481 | return var->is_comptime_memoized_value; | ||
| 6459 | } | 6482 | } |
| 6460 | 6483 | ||
| 6461 | bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { | 6484 | bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { |
src/codegen.cpp+174-127| ... | @@ -9563,7 +9563,11 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e | ... | @@ -9563,7 +9563,11 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e |
| 9563 | case ZigTypeIdVoid: | 9563 | case ZigTypeIdVoid: |
| 9564 | case ZigTypeIdUnreachable: | 9564 | case ZigTypeIdUnreachable: |
| 9565 | case ZigTypeIdBool: | 9565 | case ZigTypeIdBool: |
| 9566 | g->c_want_stdbool = true; | ||
| 9567 | return; | ||
| 9566 | case ZigTypeIdInt: | 9568 | case ZigTypeIdInt: |
| 9569 | g->c_want_stdint = true; | ||
| 9570 | return; | ||
| 9567 | case ZigTypeIdFloat: | 9571 | case ZigTypeIdFloat: |
| 9568 | return; | 9572 | return; |
| 9569 | case ZigTypeIdOpaque: | 9573 | case ZigTypeIdOpaque: |
| ... | @@ -9644,7 +9648,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu | ... | @@ -9644,7 +9648,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu |
| 9644 | break; | 9648 | break; |
| 9645 | case ZigTypeIdBool: | 9649 | case ZigTypeIdBool: |
| 9646 | buf_init_from_str(out_buf, "bool"); | 9650 | buf_init_from_str(out_buf, "bool"); |
| 9647 | g->c_want_stdbool = true; | ||
| 9648 | break; | 9651 | break; |
| 9649 | case ZigTypeIdUnreachable: | 9652 | case ZigTypeIdUnreachable: |
| 9650 | buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void"); | 9653 | buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void"); |
| ... | @@ -9668,7 +9671,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu | ... | @@ -9668,7 +9671,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu |
| 9668 | } | 9671 | } |
| 9669 | break; | 9672 | break; |
| 9670 | case ZigTypeIdInt: | 9673 | case ZigTypeIdInt: |
| 9671 | g->c_want_stdint = true; | ||
| 9672 | buf_resize(out_buf, 0); | 9674 | buf_resize(out_buf, 0); |
| 9673 | buf_appendf(out_buf, "%sint%" PRIu32 "_t", | 9675 | buf_appendf(out_buf, "%sint%" PRIu32 "_t", |
| 9674 | type_entry->data.integral.is_signed ? "" : "u", | 9676 | type_entry->data.integral.is_signed ? "" : "u", |
| ... | @@ -9780,113 +9782,7 @@ static Buf *preprocessor_mangle(Buf *src) { | ... | @@ -9780,113 +9782,7 @@ static Buf *preprocessor_mangle(Buf *src) { |
| 9780 | return result; | 9782 | return result; |
| 9781 | } | 9783 | } |
| 9782 | 9784 | ||
| 9783 | static void gen_h_file(CodeGen *g) { | 9785 | static void gen_h_file_types(CodeGen* g, GenH* gen_h, Buf* out_buf) { |
| 9784 | GenH gen_h_data = {0}; | ||
| 9785 | GenH *gen_h = &gen_h_data; | ||
| 9786 | |||
| 9787 | assert(!g->is_test_build); | ||
| 9788 | assert(!g->disable_gen_h); | ||
| 9789 | |||
| 9790 | Buf *out_h_path = buf_sprintf("%s" OS_SEP "%s.h", buf_ptr(g->output_dir), buf_ptr(g->root_out_name)); | ||
| 9791 | |||
| 9792 | FILE *out_h = fopen(buf_ptr(out_h_path), "wb"); | ||
| 9793 | if (!out_h) | ||
| 9794 | zig_panic("unable to open %s: %s\n", buf_ptr(out_h_path), strerror(errno)); | ||
| 9795 | |||
| 9796 | Buf *export_macro = nullptr; | ||
| 9797 | if (g->is_dynamic) { | ||
| 9798 | export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name))); | ||
| 9799 | buf_upcase(export_macro); | ||
| 9800 | } | ||
| 9801 | |||
| 9802 | Buf *extern_c_macro = preprocessor_mangle(buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name))); | ||
| 9803 | buf_upcase(extern_c_macro); | ||
| 9804 | |||
| 9805 | Buf h_buf = BUF_INIT; | ||
| 9806 | buf_resize(&h_buf, 0); | ||
| 9807 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { | ||
| 9808 | ZigFn *fn_table_entry = g->fn_defs.at(fn_def_i); | ||
| 9809 | |||
| 9810 | if (fn_table_entry->export_list.length == 0) | ||
| 9811 | continue; | ||
| 9812 | |||
| 9813 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | ||
| 9814 | |||
| 9815 | Buf return_type_c = BUF_INIT; | ||
| 9816 | get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c); | ||
| 9817 | |||
| 9818 | Buf *symbol_name; | ||
| 9819 | if (fn_table_entry->export_list.length == 0) { | ||
| 9820 | symbol_name = &fn_table_entry->symbol_name; | ||
| 9821 | } else { | ||
| 9822 | GlobalExport *fn_export = &fn_table_entry->export_list.items[0]; | ||
| 9823 | symbol_name = &fn_export->name; | ||
| 9824 | } | ||
| 9825 | |||
| 9826 | buf_appendf(&h_buf, "%s %s %s(", | ||
| 9827 | buf_ptr(g->is_dynamic ? export_macro : extern_c_macro), | ||
| 9828 | buf_ptr(&return_type_c), | ||
| 9829 | buf_ptr(symbol_name)); | ||
| 9830 | |||
| 9831 | Buf param_type_c = BUF_INIT; | ||
| 9832 | if (fn_type_id->param_count > 0) { | ||
| 9833 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | ||
| 9834 | FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i]; | ||
| 9835 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, param_i); | ||
| 9836 | Buf *param_name = param_decl_node->data.param_decl.name; | ||
| 9837 | |||
| 9838 | const char *comma_str = (param_i == 0) ? "" : ", "; | ||
| 9839 | const char *restrict_str = param_info->is_noalias ? "restrict" : ""; | ||
| 9840 | get_c_type(g, gen_h, param_info->type, &param_type_c); | ||
| 9841 | |||
| 9842 | if (param_info->type->id == ZigTypeIdArray) { | ||
| 9843 | // Arrays decay to pointers | ||
| 9844 | buf_appendf(&h_buf, "%s%s%s %s[]", comma_str, buf_ptr(&param_type_c), | ||
| 9845 | restrict_str, buf_ptr(param_name)); | ||
| 9846 | } else { | ||
| 9847 | buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c), | ||
| 9848 | restrict_str, buf_ptr(param_name)); | ||
| 9849 | } | ||
| 9850 | } | ||
| 9851 | buf_appendf(&h_buf, ")"); | ||
| 9852 | } else { | ||
| 9853 | buf_appendf(&h_buf, "void)"); | ||
| 9854 | } | ||
| 9855 | |||
| 9856 | buf_appendf(&h_buf, ";\n"); | ||
| 9857 | |||
| 9858 | } | ||
| 9859 | |||
| 9860 | Buf *ifdef_dance_name = preprocessor_mangle(buf_sprintf("%s_H", buf_ptr(g->root_out_name))); | ||
| 9861 | buf_upcase(ifdef_dance_name); | ||
| 9862 | |||
| 9863 | fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); | ||
| 9864 | fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name)); | ||
| 9865 | |||
| 9866 | if (g->c_want_stdbool) | ||
| 9867 | fprintf(out_h, "#include <stdbool.h>\n"); | ||
| 9868 | if (g->c_want_stdint) | ||
| 9869 | fprintf(out_h, "#include <stdint.h>\n"); | ||
| 9870 | |||
| 9871 | fprintf(out_h, "\n"); | ||
| 9872 | |||
| 9873 | fprintf(out_h, "#ifdef __cplusplus\n"); | ||
| 9874 | fprintf(out_h, "#define %s extern \"C\"\n", buf_ptr(extern_c_macro)); | ||
| 9875 | fprintf(out_h, "#else\n"); | ||
| 9876 | fprintf(out_h, "#define %s\n", buf_ptr(extern_c_macro)); | ||
| 9877 | fprintf(out_h, "#endif\n"); | ||
| 9878 | fprintf(out_h, "\n"); | ||
| 9879 | |||
| 9880 | if (g->is_dynamic) { | ||
| 9881 | fprintf(out_h, "#if defined(_WIN32)\n"); | ||
| 9882 | fprintf(out_h, "#define %s %s __declspec(dllimport)\n", buf_ptr(export_macro), buf_ptr(extern_c_macro)); | ||
| 9883 | fprintf(out_h, "#else\n"); | ||
| 9884 | fprintf(out_h, "#define %s %s __attribute__((visibility (\"default\")))\n", | ||
| 9885 | buf_ptr(export_macro), buf_ptr(extern_c_macro)); | ||
| 9886 | fprintf(out_h, "#endif\n"); | ||
| 9887 | fprintf(out_h, "\n"); | ||
| 9888 | } | ||
| 9889 | |||
| 9890 | for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) { | 9786 | for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) { |
| 9891 | ZigType *type_entry = gen_h->types_to_declare.at(type_i); | 9787 | ZigType *type_entry = gen_h->types_to_declare.at(type_i); |
| 9892 | switch (type_entry->id) { | 9788 | switch (type_entry->id) { |
| ... | @@ -9917,25 +9813,25 @@ static void gen_h_file(CodeGen *g) { | ... | @@ -9917,25 +9813,25 @@ static void gen_h_file(CodeGen *g) { |
| 9917 | 9813 | ||
| 9918 | case ZigTypeIdEnum: | 9814 | case ZigTypeIdEnum: |
| 9919 | if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { | 9815 | if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { |
| 9920 | fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry))); | 9816 | buf_appendf(out_buf, "enum %s {\n", buf_ptr(type_h_name(type_entry))); |
| 9921 | for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) { | 9817 | for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) { |
| 9922 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i]; | 9818 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i]; |
| 9923 | Buf *value_buf = buf_alloc(); | 9819 | Buf *value_buf = buf_alloc(); |
| 9924 | bigint_append_buf(value_buf, &enum_field->value, 10); | 9820 | bigint_append_buf(value_buf, &enum_field->value, 10); |
| 9925 | fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf)); | 9821 | buf_appendf(out_buf, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf)); |
| 9926 | if (field_i != type_entry->data.enumeration.src_field_count - 1) { | 9822 | if (field_i != type_entry->data.enumeration.src_field_count - 1) { |
| 9927 | fprintf(out_h, ","); | 9823 | buf_appendf(out_buf, ","); |
| 9928 | } | 9824 | } |
| 9929 | fprintf(out_h, "\n"); | 9825 | buf_appendf(out_buf, "\n"); |
| 9930 | } | 9826 | } |
| 9931 | fprintf(out_h, "};\n\n"); | 9827 | buf_appendf(out_buf, "};\n\n"); |
| 9932 | } else { | 9828 | } else { |
| 9933 | fprintf(out_h, "enum %s;\n", buf_ptr(type_h_name(type_entry))); | 9829 | buf_appendf(out_buf, "enum %s;\n\n", buf_ptr(type_h_name(type_entry))); |
| 9934 | } | 9830 | } |
| 9935 | break; | 9831 | break; |
| 9936 | case ZigTypeIdStruct: | 9832 | case ZigTypeIdStruct: |
| 9937 | if (type_entry->data.structure.layout == ContainerLayoutExtern) { | 9833 | if (type_entry->data.structure.layout == ContainerLayoutExtern) { |
| 9938 | fprintf(out_h, "struct %s {\n", buf_ptr(type_h_name(type_entry))); | 9834 | buf_appendf(out_buf, "struct %s {\n", buf_ptr(type_h_name(type_entry))); |
| 9939 | for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) { | 9835 | for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) { |
| 9940 | TypeStructField *struct_field = type_entry->data.structure.fields[field_i]; | 9836 | TypeStructField *struct_field = type_entry->data.structure.fields[field_i]; |
| 9941 | 9837 | ||
| ... | @@ -9943,43 +9839,194 @@ static void gen_h_file(CodeGen *g) { | ... | @@ -9943,43 +9839,194 @@ static void gen_h_file(CodeGen *g) { |
| 9943 | get_c_type(g, gen_h, struct_field->type_entry, type_name_buf); | 9839 | get_c_type(g, gen_h, struct_field->type_entry, type_name_buf); |
| 9944 | 9840 | ||
| 9945 | if (struct_field->type_entry->id == ZigTypeIdArray) { | 9841 | if (struct_field->type_entry->id == ZigTypeIdArray) { |
| 9946 | fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf), | 9842 | buf_appendf(out_buf, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf), |
| 9947 | buf_ptr(struct_field->name), | 9843 | buf_ptr(struct_field->name), |
| 9948 | struct_field->type_entry->data.array.len); | 9844 | struct_field->type_entry->data.array.len); |
| 9949 | } else { | 9845 | } else { |
| 9950 | fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name)); | 9846 | buf_appendf(out_buf, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name)); |
| 9951 | } | 9847 | } |
| 9952 | 9848 | ||
| 9953 | } | 9849 | } |
| 9954 | fprintf(out_h, "};\n\n"); | 9850 | buf_appendf(out_buf, "};\n\n"); |
| 9955 | } else { | 9851 | } else { |
| 9956 | fprintf(out_h, "struct %s;\n", buf_ptr(type_h_name(type_entry))); | 9852 | buf_appendf(out_buf, "struct %s;\n\n", buf_ptr(type_h_name(type_entry))); |
| 9957 | } | 9853 | } |
| 9958 | break; | 9854 | break; |
| 9959 | case ZigTypeIdUnion: | 9855 | case ZigTypeIdUnion: |
| 9960 | if (type_entry->data.unionation.layout == ContainerLayoutExtern) { | 9856 | if (type_entry->data.unionation.layout == ContainerLayoutExtern) { |
| 9961 | fprintf(out_h, "union %s {\n", buf_ptr(type_h_name(type_entry))); | 9857 | buf_appendf(out_buf, "union %s {\n", buf_ptr(type_h_name(type_entry))); |
| 9962 | for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) { | 9858 | for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) { |
| 9963 | TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i]; | 9859 | TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i]; |
| 9964 | 9860 | ||
| 9965 | Buf *type_name_buf = buf_alloc(); | 9861 | Buf *type_name_buf = buf_alloc(); |
| 9966 | get_c_type(g, gen_h, union_field->type_entry, type_name_buf); | 9862 | get_c_type(g, gen_h, union_field->type_entry, type_name_buf); |
| 9967 | fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name)); | 9863 | buf_appendf(out_buf, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name)); |
| 9968 | } | 9864 | } |
| 9969 | fprintf(out_h, "};\n\n"); | 9865 | buf_appendf(out_buf, "};\n\n"); |
| 9970 | } else { | 9866 | } else { |
| 9971 | fprintf(out_h, "union %s;\n", buf_ptr(type_h_name(type_entry))); | 9867 | buf_appendf(out_buf, "union %s;\n\n", buf_ptr(type_h_name(type_entry))); |
| 9972 | } | 9868 | } |
| 9973 | break; | 9869 | break; |
| 9974 | case ZigTypeIdOpaque: | 9870 | case ZigTypeIdOpaque: |
| 9975 | fprintf(out_h, "struct %s;\n\n", buf_ptr(type_h_name(type_entry))); | 9871 | buf_appendf(out_buf, "struct %s;\n\n", buf_ptr(type_h_name(type_entry))); |
| 9976 | break; | 9872 | break; |
| 9977 | } | 9873 | } |
| 9978 | } | 9874 | } |
| 9875 | } | ||
| 9876 | |||
| 9877 | static void gen_h_file_functions(CodeGen* g, GenH* gen_h, Buf* out_buf, Buf* export_macro) { | ||
| 9878 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { | ||
| 9879 | ZigFn *fn_table_entry = g->fn_defs.at(fn_def_i); | ||
| 9880 | |||
| 9881 | if (fn_table_entry->export_list.length == 0) | ||
| 9882 | continue; | ||
| 9883 | |||
| 9884 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | ||
| 9885 | |||
| 9886 | Buf return_type_c = BUF_INIT; | ||
| 9887 | get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c); | ||
| 9888 | |||
| 9889 | Buf *symbol_name; | ||
| 9890 | if (fn_table_entry->export_list.length == 0) { | ||
| 9891 | symbol_name = &fn_table_entry->symbol_name; | ||
| 9892 | } else { | ||
| 9893 | GlobalExport *fn_export = &fn_table_entry->export_list.items[0]; | ||
| 9894 | symbol_name = &fn_export->name; | ||
| 9895 | } | ||
| 9896 | |||
| 9897 | if (export_macro != nullptr) { | ||
| 9898 | buf_appendf(out_buf, "%s %s %s(", | ||
| 9899 | buf_ptr(export_macro), | ||
| 9900 | buf_ptr(&return_type_c), | ||
| 9901 | buf_ptr(symbol_name)); | ||
| 9902 | } else { | ||
| 9903 | buf_appendf(out_buf, "%s %s(", | ||
| 9904 | buf_ptr(&return_type_c), | ||
| 9905 | buf_ptr(symbol_name)); | ||
| 9906 | } | ||
| 9907 | |||
| 9908 | Buf param_type_c = BUF_INIT; | ||
| 9909 | if (fn_type_id->param_count > 0) { | ||
| 9910 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | ||
| 9911 | FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i]; | ||
| 9912 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, param_i); | ||
| 9913 | Buf *param_name = param_decl_node->data.param_decl.name; | ||
| 9914 | |||
| 9915 | const char *comma_str = (param_i == 0) ? "" : ", "; | ||
| 9916 | const char *restrict_str = param_info->is_noalias ? "restrict" : ""; | ||
| 9917 | get_c_type(g, gen_h, param_info->type, &param_type_c); | ||
| 9918 | |||
| 9919 | if (param_info->type->id == ZigTypeIdArray) { | ||
| 9920 | // Arrays decay to pointers | ||
| 9921 | buf_appendf(out_buf, "%s%s%s %s[]", comma_str, buf_ptr(&param_type_c), | ||
| 9922 | restrict_str, buf_ptr(param_name)); | ||
| 9923 | } else { | ||
| 9924 | buf_appendf(out_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c), | ||
| 9925 | restrict_str, buf_ptr(param_name)); | ||
| 9926 | } | ||
| 9927 | } | ||
| 9928 | buf_appendf(out_buf, ")"); | ||
| 9929 | } else { | ||
| 9930 | buf_appendf(out_buf, "void)"); | ||
| 9931 | } | ||
| 9932 | |||
| 9933 | buf_appendf(out_buf, ";\n"); | ||
| 9934 | } | ||
| 9935 | } | ||
| 9936 | |||
| 9937 | static void gen_h_file_variables(CodeGen* g, GenH* gen_h, Buf* h_buf, Buf* export_macro) { | ||
| 9938 | for (size_t exp_var_i = 0; exp_var_i < g->global_vars.length; exp_var_i += 1) { | ||
| 9939 | ZigVar* var = g->global_vars.at(exp_var_i)->var; | ||
| 9940 | if (var->export_list.length == 0) | ||
| 9941 | continue; | ||
| 9942 | |||
| 9943 | Buf var_type_c = BUF_INIT; | ||
| 9944 | get_c_type(g, gen_h, var->var_type, &var_type_c); | ||
| 9945 | |||
| 9946 | if (export_macro != nullptr) { | ||
| 9947 | buf_appendf(h_buf, "extern %s %s %s;\n", | ||
| 9948 | buf_ptr(export_macro), | ||
| 9949 | buf_ptr(&var_type_c), | ||
| 9950 | var->name); | ||
| 9951 | } else { | ||
| 9952 | buf_appendf(h_buf, "extern %s %s;\n", | ||
| 9953 | buf_ptr(&var_type_c), | ||
| 9954 | var->name); | ||
| 9955 | } | ||
| 9956 | } | ||
| 9957 | } | ||
| 9958 | |||
| 9959 | static void gen_h_file(CodeGen *g) { | ||
| 9960 | GenH gen_h_data = {0}; | ||
| 9961 | GenH *gen_h = &gen_h_data; | ||
| 9962 | |||
| 9963 | assert(!g->is_test_build); | ||
| 9964 | assert(!g->disable_gen_h); | ||
| 9965 | |||
| 9966 | Buf *out_h_path = buf_sprintf("%s" OS_SEP "%s.h", buf_ptr(g->output_dir), buf_ptr(g->root_out_name)); | ||
| 9967 | |||
| 9968 | FILE *out_h = fopen(buf_ptr(out_h_path), "wb"); | ||
| 9969 | if (!out_h) | ||
| 9970 | zig_panic("unable to open %s: %s\n", buf_ptr(out_h_path), strerror(errno)); | ||
| 9971 | |||
| 9972 | Buf *export_macro = nullptr; | ||
| 9973 | if (g->is_dynamic) { | ||
| 9974 | export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name))); | ||
| 9975 | buf_upcase(export_macro); | ||
| 9976 | } | ||
| 9977 | |||
| 9978 | Buf fns_buf = BUF_INIT; | ||
| 9979 | buf_resize(&fns_buf, 0); | ||
| 9980 | gen_h_file_functions(g, gen_h, &fns_buf, export_macro); | ||
| 9981 | |||
| 9982 | Buf vars_buf = BUF_INIT; | ||
| 9983 | buf_resize(&vars_buf, 0); | ||
| 9984 | gen_h_file_variables(g, gen_h, &vars_buf, export_macro); | ||
| 9985 | |||
| 9986 | // Types will be populated by exported functions and variables so it has to run last. | ||
| 9987 | Buf types_buf = BUF_INIT; | ||
| 9988 | buf_resize(&types_buf, 0); | ||
| 9989 | gen_h_file_types(g, gen_h, &types_buf); | ||
| 9990 | |||
| 9991 | Buf *ifdef_dance_name = preprocessor_mangle(buf_sprintf("%s_H", buf_ptr(g->root_out_name))); | ||
| 9992 | buf_upcase(ifdef_dance_name); | ||
| 9993 | |||
| 9994 | fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); | ||
| 9995 | fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name)); | ||
| 9996 | |||
| 9997 | if (g->c_want_stdbool) | ||
| 9998 | fprintf(out_h, "#include <stdbool.h>\n"); | ||
| 9999 | if (g->c_want_stdint) | ||
| 10000 | fprintf(out_h, "#include <stdint.h>\n"); | ||
| 10001 | |||
| 10002 | fprintf(out_h, "\n"); | ||
| 10003 | |||
| 10004 | if (g->is_dynamic) { | ||
| 10005 | fprintf(out_h, "#if defined(_WIN32)\n"); | ||
| 10006 | fprintf(out_h, "#define %s __declspec(dllimport)\n", buf_ptr(export_macro)); | ||
| 10007 | fprintf(out_h, "#else\n"); | ||
| 10008 | fprintf(out_h, "#define %s __attribute__((visibility (\"default\")))\n", | ||
| 10009 | buf_ptr(export_macro)); | ||
| 10010 | fprintf(out_h, "#endif\n"); | ||
| 10011 | fprintf(out_h, "\n"); | ||
| 10012 | } | ||
| 10013 | |||
| 10014 | fprintf(out_h, "%s", buf_ptr(&types_buf)); | ||
| 10015 | |||
| 10016 | fprintf(out_h, "#ifdef __cplusplus\n"); | ||
| 10017 | fprintf(out_h, "extern \"C\" {\n"); | ||
| 10018 | fprintf(out_h, "#endif\n"); | ||
| 10019 | fprintf(out_h, "\n"); | ||
| 10020 | |||
| 10021 | fprintf(out_h, "%s\n", buf_ptr(&fns_buf)); | ||
| 10022 | |||
| 10023 | fprintf(out_h, "#ifdef __cplusplus\n"); | ||
| 10024 | fprintf(out_h, "} // extern \"C\"\n"); | ||
| 10025 | fprintf(out_h, "#endif\n\n"); | ||
| 9979 | 10026 | ||
| 9980 | fprintf(out_h, "%s", buf_ptr(&h_buf)); | 10027 | fprintf(out_h, "%s\n", buf_ptr(&vars_buf)); |
| 9981 | 10028 | ||
| 9982 | fprintf(out_h, "\n#endif\n"); | 10029 | fprintf(out_h, "#endif // %s\n", buf_ptr(ifdef_dance_name)); |
| 9983 | 10030 | ||
| 9984 | if (fclose(out_h)) | 10031 | if (fclose(out_h)) |
| 9985 | zig_panic("unable to close h file: %s", strerror(errno)); | 10032 | zig_panic("unable to close h file: %s", strerror(errno)); |
src/ir.cpp+456-30| ... | @@ -41,6 +41,7 @@ struct IrAnalyze { | ... | @@ -41,6 +41,7 @@ struct IrAnalyze { |
| 41 | ZigList<IrInstruction *> src_implicit_return_type_list; | 41 | ZigList<IrInstruction *> src_implicit_return_type_list; |
| 42 | ZigList<IrSuspendPosition> resume_stack; | 42 | ZigList<IrSuspendPosition> resume_stack; |
| 43 | IrBasicBlock *const_predecessor_bb; | 43 | IrBasicBlock *const_predecessor_bb; |
| 44 | size_t ref_count; | ||
| 44 | 45 | ||
| 45 | // For the purpose of using in a debugger | 46 | // For the purpose of using in a debugger |
| 46 | void dump(); | 47 | void dump(); |
| ... | @@ -74,6 +75,7 @@ enum ConstCastResultId { | ... | @@ -74,6 +75,7 @@ enum ConstCastResultId { |
| 74 | ConstCastResultIdPtrLens, | 75 | ConstCastResultIdPtrLens, |
| 75 | ConstCastResultIdCV, | 76 | ConstCastResultIdCV, |
| 76 | ConstCastResultIdPtrSentinel, | 77 | ConstCastResultIdPtrSentinel, |
| 78 | ConstCastResultIdIntShorten, | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | struct ConstCastOnly; | 81 | struct ConstCastOnly; |
| ... | @@ -100,6 +102,7 @@ struct ConstCastBadAllowsZero; | ... | @@ -100,6 +102,7 @@ struct ConstCastBadAllowsZero; |
| 100 | struct ConstCastBadNullTermArrays; | 102 | struct ConstCastBadNullTermArrays; |
| 101 | struct ConstCastBadCV; | 103 | struct ConstCastBadCV; |
| 102 | struct ConstCastPtrSentinel; | 104 | struct ConstCastPtrSentinel; |
| 105 | struct ConstCastIntShorten; | ||
| 103 | 106 | ||
| 104 | struct ConstCastOnly { | 107 | struct ConstCastOnly { |
| 105 | ConstCastResultId id; | 108 | ConstCastResultId id; |
| ... | @@ -120,6 +123,7 @@ struct ConstCastOnly { | ... | @@ -120,6 +123,7 @@ struct ConstCastOnly { |
| 120 | ConstCastBadNullTermArrays *sentinel_arrays; | 123 | ConstCastBadNullTermArrays *sentinel_arrays; |
| 121 | ConstCastBadCV *bad_cv; | 124 | ConstCastBadCV *bad_cv; |
| 122 | ConstCastPtrSentinel *bad_ptr_sentinel; | 125 | ConstCastPtrSentinel *bad_ptr_sentinel; |
| 126 | ConstCastIntShorten *int_shorten; | ||
| 123 | } data; | 127 | } data; |
| 124 | }; | 128 | }; |
| 125 | 129 | ||
| ... | @@ -189,6 +193,11 @@ struct ConstCastPtrSentinel { | ... | @@ -189,6 +193,11 @@ struct ConstCastPtrSentinel { |
| 189 | ZigType *actual_type; | 193 | ZigType *actual_type; |
| 190 | }; | 194 | }; |
| 191 | 195 | ||
| 196 | struct ConstCastIntShorten { | ||
| 197 | ZigType *wanted_type; | ||
| 198 | ZigType *actual_type; | ||
| 199 | }; | ||
| 200 | |||
| 192 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); | 201 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); |
| 193 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, | 202 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, |
| 194 | ResultLoc *result_loc); | 203 | ResultLoc *result_loc); |
| ... | @@ -248,6 +257,381 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n | ... | @@ -248,6 +257,381 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n |
| 248 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); | 257 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); |
| 249 | static ResultLoc *no_result_loc(void); | 258 | static ResultLoc *no_result_loc(void); |
| 250 | 259 | ||
| 260 | static void destroy_instruction(IrInstruction *inst) { | ||
| 261 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 262 | const char *name = ir_instruction_type_str(inst->id); | ||
| 263 | #else | ||
| 264 | const char *name = nullptr; | ||
| 265 | #endif | ||
| 266 | switch (inst->id) { | ||
| 267 | case IrInstructionIdInvalid: | ||
| 268 | zig_unreachable(); | ||
| 269 | case IrInstructionIdReturn: | ||
| 270 | return destroy(reinterpret_cast<IrInstructionReturn *>(inst), name); | ||
| 271 | case IrInstructionIdConst: | ||
| 272 | return destroy(reinterpret_cast<IrInstructionConst *>(inst), name); | ||
| 273 | case IrInstructionIdBinOp: | ||
| 274 | return destroy(reinterpret_cast<IrInstructionBinOp *>(inst), name); | ||
| 275 | case IrInstructionIdMergeErrSets: | ||
| 276 | return destroy(reinterpret_cast<IrInstructionMergeErrSets *>(inst), name); | ||
| 277 | case IrInstructionIdDeclVarSrc: | ||
| 278 | return destroy(reinterpret_cast<IrInstructionDeclVarSrc *>(inst), name); | ||
| 279 | case IrInstructionIdCast: | ||
| 280 | return destroy(reinterpret_cast<IrInstructionCast *>(inst), name); | ||
| 281 | case IrInstructionIdCallSrc: | ||
| 282 | return destroy(reinterpret_cast<IrInstructionCallSrc *>(inst), name); | ||
| 283 | case IrInstructionIdCallGen: | ||
| 284 | return destroy(reinterpret_cast<IrInstructionCallGen *>(inst), name); | ||
| 285 | case IrInstructionIdUnOp: | ||
| 286 | return destroy(reinterpret_cast<IrInstructionUnOp *>(inst), name); | ||
| 287 | case IrInstructionIdCondBr: | ||
| 288 | return destroy(reinterpret_cast<IrInstructionCondBr *>(inst), name); | ||
| 289 | case IrInstructionIdBr: | ||
| 290 | return destroy(reinterpret_cast<IrInstructionBr *>(inst), name); | ||
| 291 | case IrInstructionIdPhi: | ||
| 292 | return destroy(reinterpret_cast<IrInstructionPhi *>(inst), name); | ||
| 293 | case IrInstructionIdContainerInitList: | ||
| 294 | return destroy(reinterpret_cast<IrInstructionContainerInitList *>(inst), name); | ||
| 295 | case IrInstructionIdContainerInitFields: | ||
| 296 | return destroy(reinterpret_cast<IrInstructionContainerInitFields *>(inst), name); | ||
| 297 | case IrInstructionIdUnreachable: | ||
| 298 | return destroy(reinterpret_cast<IrInstructionUnreachable *>(inst), name); | ||
| 299 | case IrInstructionIdElemPtr: | ||
| 300 | return destroy(reinterpret_cast<IrInstructionElemPtr *>(inst), name); | ||
| 301 | case IrInstructionIdVarPtr: | ||
| 302 | return destroy(reinterpret_cast<IrInstructionVarPtr *>(inst), name); | ||
| 303 | case IrInstructionIdReturnPtr: | ||
| 304 | return destroy(reinterpret_cast<IrInstructionReturnPtr *>(inst), name); | ||
| 305 | case IrInstructionIdLoadPtr: | ||
| 306 | return destroy(reinterpret_cast<IrInstructionLoadPtr *>(inst), name); | ||
| 307 | case IrInstructionIdLoadPtrGen: | ||
| 308 | return destroy(reinterpret_cast<IrInstructionLoadPtrGen *>(inst), name); | ||
| 309 | case IrInstructionIdStorePtr: | ||
| 310 | return destroy(reinterpret_cast<IrInstructionStorePtr *>(inst), name); | ||
| 311 | case IrInstructionIdVectorStoreElem: | ||
| 312 | return destroy(reinterpret_cast<IrInstructionVectorStoreElem *>(inst), name); | ||
| 313 | case IrInstructionIdTypeOf: | ||
| 314 | return destroy(reinterpret_cast<IrInstructionTypeOf *>(inst), name); | ||
| 315 | case IrInstructionIdFieldPtr: | ||
| 316 | return destroy(reinterpret_cast<IrInstructionFieldPtr *>(inst), name); | ||
| 317 | case IrInstructionIdStructFieldPtr: | ||
| 318 | return destroy(reinterpret_cast<IrInstructionStructFieldPtr *>(inst), name); | ||
| 319 | case IrInstructionIdUnionFieldPtr: | ||
| 320 | return destroy(reinterpret_cast<IrInstructionUnionFieldPtr *>(inst), name); | ||
| 321 | case IrInstructionIdSetCold: | ||
| 322 | return destroy(reinterpret_cast<IrInstructionSetCold *>(inst), name); | ||
| 323 | case IrInstructionIdSetRuntimeSafety: | ||
| 324 | return destroy(reinterpret_cast<IrInstructionSetRuntimeSafety *>(inst), name); | ||
| 325 | case IrInstructionIdSetFloatMode: | ||
| 326 | return destroy(reinterpret_cast<IrInstructionSetFloatMode *>(inst), name); | ||
| 327 | case IrInstructionIdArrayType: | ||
| 328 | return destroy(reinterpret_cast<IrInstructionArrayType *>(inst), name); | ||
| 329 | case IrInstructionIdSliceType: | ||
| 330 | return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name); | ||
| 331 | case IrInstructionIdAnyFrameType: | ||
| 332 | return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name); | ||
| 333 | case IrInstructionIdGlobalAsm: | ||
| 334 | return destroy(reinterpret_cast<IrInstructionGlobalAsm *>(inst), name); | ||
| 335 | case IrInstructionIdAsm: | ||
| 336 | return destroy(reinterpret_cast<IrInstructionAsm *>(inst), name); | ||
| 337 | case IrInstructionIdSizeOf: | ||
| 338 | return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name); | ||
| 339 | case IrInstructionIdTestNonNull: | ||
| 340 | return destroy(reinterpret_cast<IrInstructionTestNonNull *>(inst), name); | ||
| 341 | case IrInstructionIdOptionalUnwrapPtr: | ||
| 342 | return destroy(reinterpret_cast<IrInstructionOptionalUnwrapPtr *>(inst), name); | ||
| 343 | case IrInstructionIdPopCount: | ||
| 344 | return destroy(reinterpret_cast<IrInstructionPopCount *>(inst), name); | ||
| 345 | case IrInstructionIdClz: | ||
| 346 | return destroy(reinterpret_cast<IrInstructionClz *>(inst), name); | ||
| 347 | case IrInstructionIdCtz: | ||
| 348 | return destroy(reinterpret_cast<IrInstructionCtz *>(inst), name); | ||
| 349 | case IrInstructionIdBswap: | ||
| 350 | return destroy(reinterpret_cast<IrInstructionBswap *>(inst), name); | ||
| 351 | case IrInstructionIdBitReverse: | ||
| 352 | return destroy(reinterpret_cast<IrInstructionBitReverse *>(inst), name); | ||
| 353 | case IrInstructionIdSwitchBr: | ||
| 354 | return destroy(reinterpret_cast<IrInstructionSwitchBr *>(inst), name); | ||
| 355 | case IrInstructionIdSwitchVar: | ||
| 356 | return destroy(reinterpret_cast<IrInstructionSwitchVar *>(inst), name); | ||
| 357 | case IrInstructionIdSwitchElseVar: | ||
| 358 | return destroy(reinterpret_cast<IrInstructionSwitchElseVar *>(inst), name); | ||
| 359 | case IrInstructionIdSwitchTarget: | ||
| 360 | return destroy(reinterpret_cast<IrInstructionSwitchTarget *>(inst), name); | ||
| 361 | case IrInstructionIdUnionTag: | ||
| 362 | return destroy(reinterpret_cast<IrInstructionUnionTag *>(inst), name); | ||
| 363 | case IrInstructionIdImport: | ||
| 364 | return destroy(reinterpret_cast<IrInstructionImport *>(inst), name); | ||
| 365 | case IrInstructionIdRef: | ||
| 366 | return destroy(reinterpret_cast<IrInstructionRef *>(inst), name); | ||
| 367 | case IrInstructionIdRefGen: | ||
| 368 | return destroy(reinterpret_cast<IrInstructionRefGen *>(inst), name); | ||
| 369 | case IrInstructionIdCompileErr: | ||
| 370 | return destroy(reinterpret_cast<IrInstructionCompileErr *>(inst), name); | ||
| 371 | case IrInstructionIdCompileLog: | ||
| 372 | return destroy(reinterpret_cast<IrInstructionCompileLog *>(inst), name); | ||
| 373 | case IrInstructionIdErrName: | ||
| 374 | return destroy(reinterpret_cast<IrInstructionErrName *>(inst), name); | ||
| 375 | case IrInstructionIdCImport: | ||
| 376 | return destroy(reinterpret_cast<IrInstructionCImport *>(inst), name); | ||
| 377 | case IrInstructionIdCInclude: | ||
| 378 | return destroy(reinterpret_cast<IrInstructionCInclude *>(inst), name); | ||
| 379 | case IrInstructionIdCDefine: | ||
| 380 | return destroy(reinterpret_cast<IrInstructionCDefine *>(inst), name); | ||
| 381 | case IrInstructionIdCUndef: | ||
| 382 | return destroy(reinterpret_cast<IrInstructionCUndef *>(inst), name); | ||
| 383 | case IrInstructionIdEmbedFile: | ||
| 384 | return destroy(reinterpret_cast<IrInstructionEmbedFile *>(inst), name); | ||
| 385 | case IrInstructionIdCmpxchgSrc: | ||
| 386 | return destroy(reinterpret_cast<IrInstructionCmpxchgSrc *>(inst), name); | ||
| 387 | case IrInstructionIdCmpxchgGen: | ||
| 388 | return destroy(reinterpret_cast<IrInstructionCmpxchgGen *>(inst), name); | ||
| 389 | case IrInstructionIdFence: | ||
| 390 | return destroy(reinterpret_cast<IrInstructionFence *>(inst), name); | ||
| 391 | case IrInstructionIdTruncate: | ||
| 392 | return destroy(reinterpret_cast<IrInstructionTruncate *>(inst), name); | ||
| 393 | case IrInstructionIdIntCast: | ||
| 394 | return destroy(reinterpret_cast<IrInstructionIntCast *>(inst), name); | ||
| 395 | case IrInstructionIdFloatCast: | ||
| 396 | return destroy(reinterpret_cast<IrInstructionFloatCast *>(inst), name); | ||
| 397 | case IrInstructionIdErrSetCast: | ||
| 398 | return destroy(reinterpret_cast<IrInstructionErrSetCast *>(inst), name); | ||
| 399 | case IrInstructionIdFromBytes: | ||
| 400 | return destroy(reinterpret_cast<IrInstructionFromBytes *>(inst), name); | ||
| 401 | case IrInstructionIdToBytes: | ||
| 402 | return destroy(reinterpret_cast<IrInstructionToBytes *>(inst), name); | ||
| 403 | case IrInstructionIdIntToFloat: | ||
| 404 | return destroy(reinterpret_cast<IrInstructionIntToFloat *>(inst), name); | ||
| 405 | case IrInstructionIdFloatToInt: | ||
| 406 | return destroy(reinterpret_cast<IrInstructionFloatToInt *>(inst), name); | ||
| 407 | case IrInstructionIdBoolToInt: | ||
| 408 | return destroy(reinterpret_cast<IrInstructionBoolToInt *>(inst), name); | ||
| 409 | case IrInstructionIdIntType: | ||
| 410 | return destroy(reinterpret_cast<IrInstructionIntType *>(inst), name); | ||
| 411 | case IrInstructionIdVectorType: | ||
| 412 | return destroy(reinterpret_cast<IrInstructionVectorType *>(inst), name); | ||
| 413 | case IrInstructionIdShuffleVector: | ||
| 414 | return destroy(reinterpret_cast<IrInstructionShuffleVector *>(inst), name); | ||
| 415 | case IrInstructionIdSplatSrc: | ||
| 416 | return destroy(reinterpret_cast<IrInstructionSplatSrc *>(inst), name); | ||
| 417 | case IrInstructionIdSplatGen: | ||
| 418 | return destroy(reinterpret_cast<IrInstructionSplatGen *>(inst), name); | ||
| 419 | case IrInstructionIdBoolNot: | ||
| 420 | return destroy(reinterpret_cast<IrInstructionBoolNot *>(inst), name); | ||
| 421 | case IrInstructionIdMemset: | ||
| 422 | return destroy(reinterpret_cast<IrInstructionMemset *>(inst), name); | ||
| 423 | case IrInstructionIdMemcpy: | ||
| 424 | return destroy(reinterpret_cast<IrInstructionMemcpy *>(inst), name); | ||
| 425 | case IrInstructionIdSliceSrc: | ||
| 426 | return destroy(reinterpret_cast<IrInstructionSliceSrc *>(inst), name); | ||
| 427 | case IrInstructionIdSliceGen: | ||
| 428 | return destroy(reinterpret_cast<IrInstructionSliceGen *>(inst), name); | ||
| 429 | case IrInstructionIdMemberCount: | ||
| 430 | return destroy(reinterpret_cast<IrInstructionMemberCount *>(inst), name); | ||
| 431 | case IrInstructionIdMemberType: | ||
| 432 | return destroy(reinterpret_cast<IrInstructionMemberType *>(inst), name); | ||
| 433 | case IrInstructionIdMemberName: | ||
| 434 | return destroy(reinterpret_cast<IrInstructionMemberName *>(inst), name); | ||
| 435 | case IrInstructionIdBreakpoint: | ||
| 436 | return destroy(reinterpret_cast<IrInstructionBreakpoint *>(inst), name); | ||
| 437 | case IrInstructionIdReturnAddress: | ||
| 438 | return destroy(reinterpret_cast<IrInstructionReturnAddress *>(inst), name); | ||
| 439 | case IrInstructionIdFrameAddress: | ||
| 440 | return destroy(reinterpret_cast<IrInstructionFrameAddress *>(inst), name); | ||
| 441 | case IrInstructionIdFrameHandle: | ||
| 442 | return destroy(reinterpret_cast<IrInstructionFrameHandle *>(inst), name); | ||
| 443 | case IrInstructionIdFrameType: | ||
| 444 | return destroy(reinterpret_cast<IrInstructionFrameType *>(inst), name); | ||
| 445 | case IrInstructionIdFrameSizeSrc: | ||
| 446 | return destroy(reinterpret_cast<IrInstructionFrameSizeSrc *>(inst), name); | ||
| 447 | case IrInstructionIdFrameSizeGen: | ||
| 448 | return destroy(reinterpret_cast<IrInstructionFrameSizeGen *>(inst), name); | ||
| 449 | case IrInstructionIdAlignOf: | ||
| 450 | return destroy(reinterpret_cast<IrInstructionAlignOf *>(inst), name); | ||
| 451 | case IrInstructionIdOverflowOp: | ||
| 452 | return destroy(reinterpret_cast<IrInstructionOverflowOp *>(inst), name); | ||
| 453 | case IrInstructionIdTestErrSrc: | ||
| 454 | return destroy(reinterpret_cast<IrInstructionTestErrSrc *>(inst), name); | ||
| 455 | case IrInstructionIdTestErrGen: | ||
| 456 | return destroy(reinterpret_cast<IrInstructionTestErrGen *>(inst), name); | ||
| 457 | case IrInstructionIdUnwrapErrCode: | ||
| 458 | return destroy(reinterpret_cast<IrInstructionUnwrapErrCode *>(inst), name); | ||
| 459 | case IrInstructionIdUnwrapErrPayload: | ||
| 460 | return destroy(reinterpret_cast<IrInstructionUnwrapErrPayload *>(inst), name); | ||
| 461 | case IrInstructionIdOptionalWrap: | ||
| 462 | return destroy(reinterpret_cast<IrInstructionOptionalWrap *>(inst), name); | ||
| 463 | case IrInstructionIdErrWrapCode: | ||
| 464 | return destroy(reinterpret_cast<IrInstructionErrWrapCode *>(inst), name); | ||
| 465 | case IrInstructionIdErrWrapPayload: | ||
| 466 | return destroy(reinterpret_cast<IrInstructionErrWrapPayload *>(inst), name); | ||
| 467 | case IrInstructionIdFnProto: | ||
| 468 | return destroy(reinterpret_cast<IrInstructionFnProto *>(inst), name); | ||
| 469 | case IrInstructionIdTestComptime: | ||
| 470 | return destroy(reinterpret_cast<IrInstructionTestComptime *>(inst), name); | ||
| 471 | case IrInstructionIdPtrCastSrc: | ||
| 472 | return destroy(reinterpret_cast<IrInstructionPtrCastSrc *>(inst), name); | ||
| 473 | case IrInstructionIdPtrCastGen: | ||
| 474 | return destroy(reinterpret_cast<IrInstructionPtrCastGen *>(inst), name); | ||
| 475 | case IrInstructionIdBitCastSrc: | ||
| 476 | return destroy(reinterpret_cast<IrInstructionBitCastSrc *>(inst), name); | ||
| 477 | case IrInstructionIdBitCastGen: | ||
| 478 | return destroy(reinterpret_cast<IrInstructionBitCastGen *>(inst), name); | ||
| 479 | case IrInstructionIdWidenOrShorten: | ||
| 480 | return destroy(reinterpret_cast<IrInstructionWidenOrShorten *>(inst), name); | ||
| 481 | case IrInstructionIdPtrToInt: | ||
| 482 | return destroy(reinterpret_cast<IrInstructionPtrToInt *>(inst), name); | ||
| 483 | case IrInstructionIdIntToPtr: | ||
| 484 | return destroy(reinterpret_cast<IrInstructionIntToPtr *>(inst), name); | ||
| 485 | case IrInstructionIdIntToEnum: | ||
| 486 | return destroy(reinterpret_cast<IrInstructionIntToEnum *>(inst), name); | ||
| 487 | case IrInstructionIdIntToErr: | ||
| 488 | return destroy(reinterpret_cast<IrInstructionIntToErr *>(inst), name); | ||
| 489 | case IrInstructionIdErrToInt: | ||
| 490 | return destroy(reinterpret_cast<IrInstructionErrToInt *>(inst), name); | ||
| 491 | case IrInstructionIdCheckSwitchProngs: | ||
| 492 | return destroy(reinterpret_cast<IrInstructionCheckSwitchProngs *>(inst), name); | ||
| 493 | case IrInstructionIdCheckStatementIsVoid: | ||
| 494 | return destroy(reinterpret_cast<IrInstructionCheckStatementIsVoid *>(inst), name); | ||
| 495 | case IrInstructionIdTypeName: | ||
| 496 | return destroy(reinterpret_cast<IrInstructionTypeName *>(inst), name); | ||
| 497 | case IrInstructionIdTagName: | ||
| 498 | return destroy(reinterpret_cast<IrInstructionTagName *>(inst), name); | ||
| 499 | case IrInstructionIdPtrType: | ||
| 500 | return destroy(reinterpret_cast<IrInstructionPtrType *>(inst), name); | ||
| 501 | case IrInstructionIdDeclRef: | ||
| 502 | return destroy(reinterpret_cast<IrInstructionDeclRef *>(inst), name); | ||
| 503 | case IrInstructionIdPanic: | ||
| 504 | return destroy(reinterpret_cast<IrInstructionPanic *>(inst), name); | ||
| 505 | case IrInstructionIdFieldParentPtr: | ||
| 506 | return destroy(reinterpret_cast<IrInstructionFieldParentPtr *>(inst), name); | ||
| 507 | case IrInstructionIdByteOffsetOf: | ||
| 508 | return destroy(reinterpret_cast<IrInstructionByteOffsetOf *>(inst), name); | ||
| 509 | case IrInstructionIdBitOffsetOf: | ||
| 510 | return destroy(reinterpret_cast<IrInstructionBitOffsetOf *>(inst), name); | ||
| 511 | case IrInstructionIdTypeInfo: | ||
| 512 | return destroy(reinterpret_cast<IrInstructionTypeInfo *>(inst), name); | ||
| 513 | case IrInstructionIdType: | ||
| 514 | return destroy(reinterpret_cast<IrInstructionType *>(inst), name); | ||
| 515 | case IrInstructionIdHasField: | ||
| 516 | return destroy(reinterpret_cast<IrInstructionHasField *>(inst), name); | ||
| 517 | case IrInstructionIdTypeId: | ||
| 518 | return destroy(reinterpret_cast<IrInstructionTypeId *>(inst), name); | ||
| 519 | case IrInstructionIdSetEvalBranchQuota: | ||
| 520 | return destroy(reinterpret_cast<IrInstructionSetEvalBranchQuota *>(inst), name); | ||
| 521 | case IrInstructionIdAlignCast: | ||
| 522 | return destroy(reinterpret_cast<IrInstructionAlignCast *>(inst), name); | ||
| 523 | case IrInstructionIdImplicitCast: | ||
| 524 | return destroy(reinterpret_cast<IrInstructionImplicitCast *>(inst), name); | ||
| 525 | case IrInstructionIdResolveResult: | ||
| 526 | return destroy(reinterpret_cast<IrInstructionResolveResult *>(inst), name); | ||
| 527 | case IrInstructionIdResetResult: | ||
| 528 | return destroy(reinterpret_cast<IrInstructionResetResult *>(inst), name); | ||
| 529 | case IrInstructionIdOpaqueType: | ||
| 530 | return destroy(reinterpret_cast<IrInstructionOpaqueType *>(inst), name); | ||
| 531 | case IrInstructionIdSetAlignStack: | ||
| 532 | return destroy(reinterpret_cast<IrInstructionSetAlignStack *>(inst), name); | ||
| 533 | case IrInstructionIdArgType: | ||
| 534 | return destroy(reinterpret_cast<IrInstructionArgType *>(inst), name); | ||
| 535 | case IrInstructionIdTagType: | ||
| 536 | return destroy(reinterpret_cast<IrInstructionTagType *>(inst), name); | ||
| 537 | case IrInstructionIdExport: | ||
| 538 | return destroy(reinterpret_cast<IrInstructionExport *>(inst), name); | ||
| 539 | case IrInstructionIdErrorReturnTrace: | ||
| 540 | return destroy(reinterpret_cast<IrInstructionErrorReturnTrace *>(inst), name); | ||
| 541 | case IrInstructionIdErrorUnion: | ||
| 542 | return destroy(reinterpret_cast<IrInstructionErrorUnion *>(inst), name); | ||
| 543 | case IrInstructionIdAtomicRmw: | ||
| 544 | return destroy(reinterpret_cast<IrInstructionAtomicRmw *>(inst), name); | ||
| 545 | case IrInstructionIdSaveErrRetAddr: | ||
| 546 | return destroy(reinterpret_cast<IrInstructionSaveErrRetAddr *>(inst), name); | ||
| 547 | case IrInstructionIdAddImplicitReturnType: | ||
| 548 | return destroy(reinterpret_cast<IrInstructionAddImplicitReturnType *>(inst), name); | ||
| 549 | case IrInstructionIdFloatOp: | ||
| 550 | return destroy(reinterpret_cast<IrInstructionFloatOp *>(inst), name); | ||
| 551 | case IrInstructionIdMulAdd: | ||
| 552 | return destroy(reinterpret_cast<IrInstructionMulAdd *>(inst), name); | ||
| 553 | case IrInstructionIdAtomicLoad: | ||
| 554 | return destroy(reinterpret_cast<IrInstructionAtomicLoad *>(inst), name); | ||
| 555 | case IrInstructionIdAtomicStore: | ||
| 556 | return destroy(reinterpret_cast<IrInstructionAtomicStore *>(inst), name); | ||
| 557 | case IrInstructionIdEnumToInt: | ||
| 558 | return destroy(reinterpret_cast<IrInstructionEnumToInt *>(inst), name); | ||
| 559 | case IrInstructionIdCheckRuntimeScope: | ||
| 560 | return destroy(reinterpret_cast<IrInstructionCheckRuntimeScope *>(inst), name); | ||
| 561 | case IrInstructionIdDeclVarGen: | ||
| 562 | return destroy(reinterpret_cast<IrInstructionDeclVarGen *>(inst), name); | ||
| 563 | case IrInstructionIdArrayToVector: | ||
| 564 | return destroy(reinterpret_cast<IrInstructionArrayToVector *>(inst), name); | ||
| 565 | case IrInstructionIdVectorToArray: | ||
| 566 | return destroy(reinterpret_cast<IrInstructionVectorToArray *>(inst), name); | ||
| 567 | case IrInstructionIdPtrOfArrayToSlice: | ||
| 568 | return destroy(reinterpret_cast<IrInstructionPtrOfArrayToSlice *>(inst), name); | ||
| 569 | case IrInstructionIdAssertZero: | ||
| 570 | return destroy(reinterpret_cast<IrInstructionAssertZero *>(inst), name); | ||
| 571 | case IrInstructionIdAssertNonNull: | ||
| 572 | return destroy(reinterpret_cast<IrInstructionAssertNonNull *>(inst), name); | ||
| 573 | case IrInstructionIdResizeSlice: | ||
| 574 | return destroy(reinterpret_cast<IrInstructionResizeSlice *>(inst), name); | ||
| 575 | case IrInstructionIdHasDecl: | ||
| 576 | return destroy(reinterpret_cast<IrInstructionHasDecl *>(inst), name); | ||
| 577 | case IrInstructionIdUndeclaredIdent: | ||
| 578 | return destroy(reinterpret_cast<IrInstructionUndeclaredIdent *>(inst), name); | ||
| 579 | case IrInstructionIdAllocaSrc: | ||
| 580 | return destroy(reinterpret_cast<IrInstructionAllocaSrc *>(inst), name); | ||
| 581 | case IrInstructionIdAllocaGen: | ||
| 582 | return destroy(reinterpret_cast<IrInstructionAllocaGen *>(inst), name); | ||
| 583 | case IrInstructionIdEndExpr: | ||
| 584 | return destroy(reinterpret_cast<IrInstructionEndExpr *>(inst), name); | ||
| 585 | case IrInstructionIdUnionInitNamedField: | ||
| 586 | return destroy(reinterpret_cast<IrInstructionUnionInitNamedField *>(inst), name); | ||
| 587 | case IrInstructionIdSuspendBegin: | ||
| 588 | return destroy(reinterpret_cast<IrInstructionSuspendBegin *>(inst), name); | ||
| 589 | case IrInstructionIdSuspendFinish: | ||
| 590 | return destroy(reinterpret_cast<IrInstructionSuspendFinish *>(inst), name); | ||
| 591 | case IrInstructionIdResume: | ||
| 592 | return destroy(reinterpret_cast<IrInstructionResume *>(inst), name); | ||
| 593 | case IrInstructionIdAwaitSrc: | ||
| 594 | return destroy(reinterpret_cast<IrInstructionAwaitSrc *>(inst), name); | ||
| 595 | case IrInstructionIdAwaitGen: | ||
| 596 | return destroy(reinterpret_cast<IrInstructionAwaitGen *>(inst), name); | ||
| 597 | case IrInstructionIdSpillBegin: | ||
| 598 | return destroy(reinterpret_cast<IrInstructionSpillBegin *>(inst), name); | ||
| 599 | case IrInstructionIdSpillEnd: | ||
| 600 | return destroy(reinterpret_cast<IrInstructionSpillEnd *>(inst), name); | ||
| 601 | case IrInstructionIdVectorExtractElem: | ||
| 602 | return destroy(reinterpret_cast<IrInstructionVectorExtractElem *>(inst), name); | ||
| 603 | } | ||
| 604 | zig_unreachable(); | ||
| 605 | } | ||
| 606 | |||
| 607 | static void ira_ref(IrAnalyze *ira) { | ||
| 608 | ira->ref_count += 1; | ||
| 609 | } | ||
| 610 | static void ira_deref(IrAnalyze *ira) { | ||
| 611 | if (ira->ref_count > 1) { | ||
| 612 | ira->ref_count -= 1; | ||
| 613 | return; | ||
| 614 | } | ||
| 615 | assert(ira->ref_count != 0); | ||
| 616 | |||
| 617 | for (size_t bb_i = 0; bb_i < ira->old_irb.exec->basic_block_list.length; bb_i += 1) { | ||
| 618 | IrBasicBlock *pass1_bb = ira->old_irb.exec->basic_block_list.items[bb_i]; | ||
| 619 | for (size_t inst_i = 0; inst_i < pass1_bb->instruction_list.length; inst_i += 1) { | ||
| 620 | IrInstruction *pass1_inst = pass1_bb->instruction_list.items[inst_i]; | ||
| 621 | destroy_instruction(pass1_inst); | ||
| 622 | } | ||
| 623 | destroy(pass1_bb, "IrBasicBlock"); | ||
| 624 | } | ||
| 625 | ira->old_irb.exec->basic_block_list.deinit(); | ||
| 626 | ira->old_irb.exec->tld_list.deinit(); | ||
| 627 | // cannot destroy here because of var->owner_exec | ||
| 628 | //destroy(ira->old_irb.exec, "IrExecutablePass1"); | ||
| 629 | ira->src_implicit_return_type_list.deinit(); | ||
| 630 | ira->resume_stack.deinit(); | ||
| 631 | ira->exec_context.mem_slot_list.deinit(); | ||
| 632 | destroy(ira, "IrAnalyze"); | ||
| 633 | } | ||
| 634 | |||
| 251 | static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { | 635 | static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { |
| 252 | assert(get_src_ptr_type(const_val->type) != nullptr); | 636 | assert(get_src_ptr_type(const_val->type) != nullptr); |
| 253 | assert(const_val->special == ConstValSpecialStatic); | 637 | assert(const_val->special == ConstValSpecialStatic); |
| ... | @@ -4186,7 +4570,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -4186,7 +4570,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod |
| 4186 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 4570 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 4187 | incoming_values[0] = val1; | 4571 | incoming_values[0] = val1; |
| 4188 | incoming_values[1] = val2; | 4572 | incoming_values[1] = val2; |
| 4189 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 4573 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 4190 | incoming_blocks[0] = post_val1_block; | 4574 | incoming_blocks[0] = post_val1_block; |
| 4191 | incoming_blocks[1] = post_val2_block; | 4575 | incoming_blocks[1] = post_val2_block; |
| 4192 | 4576 | ||
| ... | @@ -4277,7 +4661,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -4277,7 +4661,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode |
| 4277 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 4661 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 4278 | incoming_values[0] = null_result; | 4662 | incoming_values[0] = null_result; |
| 4279 | incoming_values[1] = unwrapped_payload; | 4663 | incoming_values[1] = unwrapped_payload; |
| 4280 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 4664 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 4281 | incoming_blocks[0] = after_null_block; | 4665 | incoming_blocks[0] = after_null_block; |
| 4282 | incoming_blocks[1] = after_ok_block; | 4666 | incoming_blocks[1] = after_ok_block; |
| 4283 | IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); | 4667 | IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); |
| ... | @@ -6044,7 +6428,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -6044,7 +6428,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 6044 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 6428 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 6045 | incoming_values[0] = then_expr_result; | 6429 | incoming_values[0] = then_expr_result; |
| 6046 | incoming_values[1] = else_expr_result; | 6430 | incoming_values[1] = else_expr_result; |
| 6047 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 6431 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 6048 | incoming_blocks[0] = after_then_block; | 6432 | incoming_blocks[0] = after_then_block; |
| 6049 | incoming_blocks[1] = after_else_block; | 6433 | incoming_blocks[1] = after_else_block; |
| 6050 | 6434 | ||
| ... | @@ -7398,7 +7782,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN | ... | @@ -7398,7 +7782,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN |
| 7398 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 7782 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 7399 | incoming_values[0] = then_expr_result; | 7783 | incoming_values[0] = then_expr_result; |
| 7400 | incoming_values[1] = else_expr_result; | 7784 | incoming_values[1] = else_expr_result; |
| 7401 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 7785 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 7402 | incoming_blocks[0] = after_then_block; | 7786 | incoming_blocks[0] = after_then_block; |
| 7403 | incoming_blocks[1] = after_else_block; | 7787 | incoming_blocks[1] = after_else_block; |
| 7404 | 7788 | ||
| ... | @@ -7495,7 +7879,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -7495,7 +7879,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 7495 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 7879 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 7496 | incoming_values[0] = then_expr_result; | 7880 | incoming_values[0] = then_expr_result; |
| 7497 | incoming_values[1] = else_expr_result; | 7881 | incoming_values[1] = else_expr_result; |
| 7498 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 7882 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 7499 | incoming_blocks[0] = after_then_block; | 7883 | incoming_blocks[0] = after_then_block; |
| 7500 | incoming_blocks[1] = after_else_block; | 7884 | incoming_blocks[1] = after_else_block; |
| 7501 | 7885 | ||
| ... | @@ -8092,7 +8476,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -8092,7 +8476,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode |
| 8092 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 8476 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 8093 | incoming_values[0] = err_result; | 8477 | incoming_values[0] = err_result; |
| 8094 | incoming_values[1] = unwrapped_payload; | 8478 | incoming_values[1] = unwrapped_payload; |
| 8095 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 8479 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 8096 | incoming_blocks[0] = after_err_block; | 8480 | incoming_blocks[0] = after_err_block; |
| 8097 | incoming_blocks[1] = after_ok_block; | 8481 | incoming_blocks[1] = after_ok_block; |
| 8098 | IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); | 8482 | IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); |
| ... | @@ -8680,7 +9064,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -8680,7 +9064,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8680 | bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { | 9064 | bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { |
| 8681 | assert(fn_entry); | 9065 | assert(fn_entry); |
| 8682 | 9066 | ||
| 8683 | IrExecutable *ir_executable = &fn_entry->ir_executable; | 9067 | IrExecutable *ir_executable = fn_entry->ir_executable; |
| 8684 | AstNode *body_node = fn_entry->body_node; | 9068 | AstNode *body_node = fn_entry->body_node; |
| 8685 | 9069 | ||
| 8686 | assert(fn_entry->child_scope); | 9070 | assert(fn_entry->child_scope); |
| ... | @@ -10224,6 +10608,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted | ... | @@ -10224,6 +10608,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 10224 | return result; | 10608 | return result; |
| 10225 | } | 10609 | } |
| 10226 | 10610 | ||
| 10611 | if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt) { | ||
| 10612 | result.id = ConstCastResultIdIntShorten; | ||
| 10613 | result.data.int_shorten = allocate_nonzero<ConstCastIntShorten>(1); | ||
| 10614 | result.data.int_shorten->wanted_type = wanted_type; | ||
| 10615 | result.data.int_shorten->actual_type = actual_type; | ||
| 10616 | return result; | ||
| 10617 | } | ||
| 10618 | |||
| 10227 | result.id = ConstCastResultIdType; | 10619 | result.id = ConstCastResultIdType; |
| 10228 | result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1); | 10620 | result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1); |
| 10229 | result.data.type_mismatch->wanted_type = wanted_type; | 10621 | result.data.type_mismatch->wanted_type = wanted_type; |
| ... | @@ -11490,7 +11882,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | ... | @@ -11490,7 +11882,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 11490 | if (expected_type != nullptr && type_is_invalid(expected_type)) | 11882 | if (expected_type != nullptr && type_is_invalid(expected_type)) |
| 11491 | return codegen->invalid_instruction->value; | 11883 | return codegen->invalid_instruction->value; |
| 11492 | 11884 | ||
| 11493 | IrExecutable *ir_executable = allocate<IrExecutable>(1); | 11885 | IrExecutable *ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1"); |
| 11494 | ir_executable->source_node = source_node; | 11886 | ir_executable->source_node = source_node; |
| 11495 | ir_executable->parent_exec = parent_exec; | 11887 | ir_executable->parent_exec = parent_exec; |
| 11496 | ir_executable->name = exec_name; | 11888 | ir_executable->name = exec_name; |
| ... | @@ -11512,7 +11904,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | ... | @@ -11512,7 +11904,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 11512 | ir_print(codegen, stderr, ir_executable, 2, IrPassSrc); | 11904 | ir_print(codegen, stderr, ir_executable, 2, IrPassSrc); |
| 11513 | fprintf(stderr, "}\n"); | 11905 | fprintf(stderr, "}\n"); |
| 11514 | } | 11906 | } |
| 11515 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); | 11907 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1, "IrExecutablePass2"); |
| 11516 | analyzed_executable->source_node = source_node; | 11908 | analyzed_executable->source_node = source_node; |
| 11517 | analyzed_executable->parent_exec = parent_exec; | 11909 | analyzed_executable->parent_exec = parent_exec; |
| 11518 | analyzed_executable->source_exec = ir_executable; | 11910 | analyzed_executable->source_exec = ir_executable; |
| ... | @@ -12641,6 +13033,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa | ... | @@ -12641,6 +13033,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa |
| 12641 | add_error_note(ira->codegen, parent_msg, source_node, | 13033 | add_error_note(ira->codegen, parent_msg, source_node, |
| 12642 | buf_sprintf("calling convention mismatch")); | 13034 | buf_sprintf("calling convention mismatch")); |
| 12643 | break; | 13035 | break; |
| 13036 | case ConstCastResultIdIntShorten: { | ||
| 13037 | ZigType *wanted_type = cast_result->data.int_shorten->wanted_type; | ||
| 13038 | ZigType *actual_type = cast_result->data.int_shorten->actual_type; | ||
| 13039 | const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; | ||
| 13040 | const char *actual_signed = actual_type->data.integral.is_signed ? "signed" : "unsigned"; | ||
| 13041 | add_error_note(ira->codegen, parent_msg, source_node, | ||
| 13042 | buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values", | ||
| 13043 | wanted_signed, wanted_type->data.integral.bit_count, | ||
| 13044 | actual_signed, actual_type->data.integral.bit_count)); | ||
| 13045 | break; | ||
| 13046 | } | ||
| 12644 | case ConstCastResultIdFnAlign: // TODO | 13047 | case ConstCastResultIdFnAlign: // TODO |
| 12645 | case ConstCastResultIdFnVarArgs: // TODO | 13048 | case ConstCastResultIdFnVarArgs: // TODO |
| 12646 | case ConstCastResultIdFnReturnType: // TODO | 13049 | case ConstCastResultIdFnReturnType: // TODO |
| ... | @@ -15597,6 +16000,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, | ... | @@ -15597,6 +16000,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 15597 | assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); | 16000 | assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); |
| 15598 | ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); | 16001 | ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); |
| 15599 | copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); | 16002 | copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); |
| 16003 | ira_ref(var->owner_exec->analysis); | ||
| 15600 | 16004 | ||
| 15601 | if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) { | 16005 | if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) { |
| 15602 | return ir_const_void(ira, &decl_var_instruction->base); | 16006 | return ir_const_void(ira, &decl_var_instruction->base); |
| ... | @@ -15869,8 +16273,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, | ... | @@ -15869,8 +16273,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| 15869 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | 16273 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 15870 | result->value->special = ConstValSpecialLazy; | 16274 | result->value->special = ConstValSpecialLazy; |
| 15871 | 16275 | ||
| 15872 | LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1); | 16276 | LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1, "LazyValueErrUnionType"); |
| 15873 | lazy_err_union_type->ira = ira; | 16277 | lazy_err_union_type->ira = ira; ira_ref(ira); |
| 15874 | result->value->data.x_lazy = &lazy_err_union_type->base; | 16278 | result->value->data.x_lazy = &lazy_err_union_type->base; |
| 15875 | lazy_err_union_type->base.id = LazyValueIdErrUnionType; | 16279 | lazy_err_union_type->base.id = LazyValueIdErrUnionType; |
| 15876 | 16280 | ||
| ... | @@ -17368,8 +17772,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -17368,8 +17772,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17368 | if (type_is_invalid(impl_fn->type_entry)) | 17772 | if (type_is_invalid(impl_fn->type_entry)) |
| 17369 | return ira->codegen->invalid_instruction; | 17773 | return ira->codegen->invalid_instruction; |
| 17370 | 17774 | ||
| 17371 | impl_fn->ir_executable.source_node = call_instruction->base.source_node; | 17775 | impl_fn->ir_executable->source_node = call_instruction->base.source_node; |
| 17372 | impl_fn->ir_executable.parent_exec = ira->new_irb.exec; | 17776 | impl_fn->ir_executable->parent_exec = ira->new_irb.exec; |
| 17373 | impl_fn->analyzed_executable.source_node = call_instruction->base.source_node; | 17777 | impl_fn->analyzed_executable.source_node = call_instruction->base.source_node; |
| 17374 | impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; | 17778 | impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; |
| 17375 | impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota; | 17779 | impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota; |
| ... | @@ -17722,8 +18126,8 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp | ... | @@ -17722,8 +18126,8 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp |
| 17722 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | 18126 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 17723 | result->value->special = ConstValSpecialLazy; | 18127 | result->value->special = ConstValSpecialLazy; |
| 17724 | 18128 | ||
| 17725 | LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1); | 18129 | LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1, "LazyValueOptType"); |
| 17726 | lazy_opt_type->ira = ira; | 18130 | lazy_opt_type->ira = ira; ira_ref(ira); |
| 17727 | result->value->data.x_lazy = &lazy_opt_type->base; | 18131 | result->value->data.x_lazy = &lazy_opt_type->base; |
| 17728 | lazy_opt_type->base.id = LazyValueIdOptType; | 18132 | lazy_opt_type->base.id = LazyValueIdOptType; |
| 17729 | 18133 | ||
| ... | @@ -19668,8 +20072,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -19668,8 +20072,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 19668 | IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); | 20072 | IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); |
| 19669 | result->value->special = ConstValSpecialLazy; | 20073 | result->value->special = ConstValSpecialLazy; |
| 19670 | 20074 | ||
| 19671 | LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1); | 20075 | LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1, "LazyValueSliceType"); |
| 19672 | lazy_slice_type->ira = ira; | 20076 | lazy_slice_type->ira = ira; ira_ref(ira); |
| 19673 | result->value->data.x_lazy = &lazy_slice_type->base; | 20077 | result->value->data.x_lazy = &lazy_slice_type->base; |
| 19674 | lazy_slice_type->base.id = LazyValueIdSliceType; | 20078 | lazy_slice_type->base.id = LazyValueIdSliceType; |
| 19675 | 20079 | ||
| ... | @@ -19828,8 +20232,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi | ... | @@ -19828,8 +20232,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi |
| 19828 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); | 20232 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); |
| 19829 | result->value->special = ConstValSpecialLazy; | 20233 | result->value->special = ConstValSpecialLazy; |
| 19830 | 20234 | ||
| 19831 | LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1); | 20235 | LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1, "LazyValueSizeOf"); |
| 19832 | lazy_size_of->ira = ira; | 20236 | lazy_size_of->ira = ira; ira_ref(ira); |
| 19833 | result->value->data.x_lazy = &lazy_size_of->base; | 20237 | result->value->data.x_lazy = &lazy_size_of->base; |
| 19834 | lazy_size_of->base.id = LazyValueIdSizeOf; | 20238 | lazy_size_of->base.id = LazyValueIdSizeOf; |
| 19835 | 20239 | ||
| ... | @@ -24556,8 +24960,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct | ... | @@ -24556,8 +24960,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct |
| 24556 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); | 24960 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); |
| 24557 | result->value->special = ConstValSpecialLazy; | 24961 | result->value->special = ConstValSpecialLazy; |
| 24558 | 24962 | ||
| 24559 | LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1); | 24963 | LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1, "LazyValueAlignOf"); |
| 24560 | lazy_align_of->ira = ira; | 24964 | lazy_align_of->ira = ira; ira_ref(ira); |
| 24561 | result->value->data.x_lazy = &lazy_align_of->base; | 24965 | result->value->data.x_lazy = &lazy_align_of->base; |
| 24562 | lazy_align_of->base.id = LazyValueIdAlignOf; | 24966 | lazy_align_of->base.id = LazyValueIdAlignOf; |
| 24563 | 24967 | ||
| ... | @@ -25040,8 +25444,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct | ... | @@ -25040,8 +25444,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct |
| 25040 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | 25444 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 25041 | result->value->special = ConstValSpecialLazy; | 25445 | result->value->special = ConstValSpecialLazy; |
| 25042 | 25446 | ||
| 25043 | LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1); | 25447 | LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1, "LazyValueFnType"); |
| 25044 | lazy_fn_type->ira = ira; | 25448 | lazy_fn_type->ira = ira; ira_ref(ira); |
| 25045 | result->value->data.x_lazy = &lazy_fn_type->base; | 25449 | result->value->data.x_lazy = &lazy_fn_type->base; |
| 25046 | lazy_fn_type->base.id = LazyValueIdFnType; | 25450 | lazy_fn_type->base.id = LazyValueIdFnType; |
| 25047 | 25451 | ||
| ... | @@ -26081,8 +26485,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct | ... | @@ -26081,8 +26485,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 26081 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | 26485 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 26082 | result->value->special = ConstValSpecialLazy; | 26486 | result->value->special = ConstValSpecialLazy; |
| 26083 | 26487 | ||
| 26084 | LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1); | 26488 | LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1, "LazyValuePtrType"); |
| 26085 | lazy_ptr_type->ira = ira; | 26489 | lazy_ptr_type->ira = ira; ira_ref(ira); |
| 26086 | result->value->data.x_lazy = &lazy_ptr_type->base; | 26490 | result->value->data.x_lazy = &lazy_ptr_type->base; |
| 26087 | lazy_ptr_type->base.id = LazyValueIdPtrType; | 26491 | lazy_ptr_type->base.id = LazyValueIdPtrType; |
| 26088 | 26492 | ||
| ... | @@ -27551,7 +27955,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ | ... | @@ -27551,7 +27955,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 27551 | assert(old_exec->first_err_trace_msg == nullptr); | 27955 | assert(old_exec->first_err_trace_msg == nullptr); |
| 27552 | assert(expected_type == nullptr || !type_is_invalid(expected_type)); | 27956 | assert(expected_type == nullptr || !type_is_invalid(expected_type)); |
| 27553 | 27957 | ||
| 27554 | IrAnalyze *ira = allocate<IrAnalyze>(1); | 27958 | IrAnalyze *ira = allocate<IrAnalyze>(1, "IrAnalyze"); |
| 27959 | ira->ref_count = 1; | ||
| 27555 | old_exec->analysis = ira; | 27960 | old_exec->analysis = ira; |
| 27556 | ira->codegen = codegen; | 27961 | ira->codegen = codegen; |
| 27557 | 27962 | ||
| ... | @@ -27618,6 +28023,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ | ... | @@ -27618,6 +28023,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 27618 | ira->instruction_index += 1; | 28023 | ira->instruction_index += 1; |
| 27619 | } | 28024 | } |
| 27620 | 28025 | ||
| 28026 | ZigType *res_type; | ||
| 27621 | if (new_exec->first_err_trace_msg != nullptr) { | 28027 | if (new_exec->first_err_trace_msg != nullptr) { |
| 27622 | codegen->trace_err = new_exec->first_err_trace_msg; | 28028 | codegen->trace_err = new_exec->first_err_trace_msg; |
| 27623 | if (codegen->trace_err != nullptr && new_exec->source_node != nullptr && | 28029 | if (codegen->trace_err != nullptr && new_exec->source_node != nullptr && |
| ... | @@ -27627,13 +28033,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ | ... | @@ -27627,13 +28033,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 27627 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, | 28033 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, |
| 27628 | new_exec->source_node, buf_create_from_str("referenced here")); | 28034 | new_exec->source_node, buf_create_from_str("referenced here")); |
| 27629 | } | 28035 | } |
| 27630 | return ira->codegen->builtin_types.entry_invalid; | 28036 | res_type = ira->codegen->builtin_types.entry_invalid; |
| 27631 | } else if (ira->src_implicit_return_type_list.length == 0) { | 28037 | } else if (ira->src_implicit_return_type_list.length == 0) { |
| 27632 | return codegen->builtin_types.entry_unreachable; | 28038 | res_type = codegen->builtin_types.entry_unreachable; |
| 27633 | } else { | 28039 | } else { |
| 27634 | return ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, | 28040 | res_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, |
| 27635 | ira->src_implicit_return_type_list.length); | 28041 | ira->src_implicit_return_type_list.length); |
| 27636 | } | 28042 | } |
| 28043 | |||
| 28044 | // It is now safe to free Pass 1 IR instructions. | ||
| 28045 | ira_deref(ira); | ||
| 28046 | |||
| 28047 | return res_type; | ||
| 27637 | } | 28048 | } |
| 27638 | 28049 | ||
| 27639 | bool ir_has_side_effects(IrInstruction *instruction) { | 28050 | bool ir_has_side_effects(IrInstruction *instruction) { |
| ... | @@ -27969,6 +28380,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -27969,6 +28380,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 27969 | val->special = ConstValSpecialStatic; | 28380 | val->special = ConstValSpecialStatic; |
| 27970 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); | 28381 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); |
| 27971 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); | 28382 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); |
| 28383 | |||
| 28384 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 27972 | return ErrorNone; | 28385 | return ErrorNone; |
| 27973 | } | 28386 | } |
| 27974 | case LazyValueIdSizeOf: { | 28387 | case LazyValueIdSizeOf: { |
| ... | @@ -28024,6 +28437,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -28024,6 +28437,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 28024 | val->special = ConstValSpecialStatic; | 28437 | val->special = ConstValSpecialStatic; |
| 28025 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); | 28438 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); |
| 28026 | bigint_init_unsigned(&val->data.x_bigint, abi_size); | 28439 | bigint_init_unsigned(&val->data.x_bigint, abi_size); |
| 28440 | |||
| 28441 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28027 | return ErrorNone; | 28442 | return ErrorNone; |
| 28028 | } | 28443 | } |
| 28029 | case LazyValueIdSliceType: { | 28444 | case LazyValueIdSliceType: { |
| ... | @@ -28102,6 +28517,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -28102,6 +28517,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 28102 | val->special = ConstValSpecialStatic; | 28517 | val->special = ConstValSpecialStatic; |
| 28103 | assert(val->type->id == ZigTypeIdMetaType); | 28518 | assert(val->type->id == ZigTypeIdMetaType); |
| 28104 | val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); | 28519 | val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 28520 | |||
| 28521 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28105 | return ErrorNone; | 28522 | return ErrorNone; |
| 28106 | } | 28523 | } |
| 28107 | case LazyValueIdPtrType: { | 28524 | case LazyValueIdPtrType: { |
| ... | @@ -28173,6 +28590,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -28173,6 +28590,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 28173 | lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, | 28590 | lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, |
| 28174 | allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); | 28591 | allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); |
| 28175 | val->special = ConstValSpecialStatic; | 28592 | val->special = ConstValSpecialStatic; |
| 28593 | |||
| 28594 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28176 | return ErrorNone; | 28595 | return ErrorNone; |
| 28177 | } | 28596 | } |
| 28178 | case LazyValueIdOptType: { | 28597 | case LazyValueIdOptType: { |
| ... | @@ -28195,16 +28614,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -28195,16 +28614,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 28195 | assert(val->type->id == ZigTypeIdMetaType); | 28614 | assert(val->type->id == ZigTypeIdMetaType); |
| 28196 | val->data.x_type = get_optional_type(ira->codegen, payload_type); | 28615 | val->data.x_type = get_optional_type(ira->codegen, payload_type); |
| 28197 | val->special = ConstValSpecialStatic; | 28616 | val->special = ConstValSpecialStatic; |
| 28617 | |||
| 28618 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28198 | return ErrorNone; | 28619 | return ErrorNone; |
| 28199 | } | 28620 | } |
| 28200 | case LazyValueIdFnType: { | 28621 | case LazyValueIdFnType: { |
| 28201 | LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(val->data.x_lazy); | 28622 | LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(val->data.x_lazy); |
| 28202 | ZigType *fn_type = ir_resolve_lazy_fn_type(lazy_fn_type->ira, source_node, lazy_fn_type); | 28623 | IrAnalyze *ira = lazy_fn_type->ira; |
| 28624 | ZigType *fn_type = ir_resolve_lazy_fn_type(ira, source_node, lazy_fn_type); | ||
| 28203 | if (fn_type == nullptr) | 28625 | if (fn_type == nullptr) |
| 28204 | return ErrorSemanticAnalyzeFail; | 28626 | return ErrorSemanticAnalyzeFail; |
| 28205 | val->special = ConstValSpecialStatic; | 28627 | val->special = ConstValSpecialStatic; |
| 28206 | assert(val->type->id == ZigTypeIdMetaType); | 28628 | assert(val->type->id == ZigTypeIdMetaType); |
| 28207 | val->data.x_type = fn_type; | 28629 | val->data.x_type = fn_type; |
| 28630 | |||
| 28631 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28208 | return ErrorNone; | 28632 | return ErrorNone; |
| 28209 | } | 28633 | } |
| 28210 | case LazyValueIdErrUnionType: { | 28634 | case LazyValueIdErrUnionType: { |
| ... | @@ -28233,6 +28657,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { | ... | @@ -28233,6 +28657,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { |
| 28233 | assert(val->type->id == ZigTypeIdMetaType); | 28657 | assert(val->type->id == ZigTypeIdMetaType); |
| 28234 | val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | 28658 | val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); |
| 28235 | val->special = ConstValSpecialStatic; | 28659 | val->special = ConstValSpecialStatic; |
| 28660 | |||
| 28661 | // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. | ||
| 28236 | return ErrorNone; | 28662 | return ErrorNone; |
| 28237 | } | 28663 | } |
| 28238 | } | 28664 | } |
src/libc_installation.cpp+1-1| ... | @@ -389,7 +389,7 @@ static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, Zi | ... | @@ -389,7 +389,7 @@ static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, Zi |
| 389 | } | 389 | } |
| 390 | Buf search_path = BUF_INIT; | 390 | Buf search_path = BUF_INIT; |
| 391 | buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); | 391 | buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); |
| 392 | buf_append_str(&search_path, "\\..\\..\\include"); | 392 | buf_append_str(&search_path, "..\\..\\include"); |
| 393 | 393 | ||
| 394 | Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path)); | 394 | Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path)); |
| 395 | bool exists; | 395 | bool exists; |
src/list.hpp+1-1| ... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
| 13 | template<typename T> | 13 | template<typename T> |
| 14 | struct ZigList { | 14 | struct ZigList { |
| 15 | void deinit() { | 15 | void deinit() { |
| 16 | free(items); | 16 | deallocate(items, capacity); |
| 17 | } | 17 | } |
| 18 | void append(const T& item) { | 18 | void append(const T& item) { |
| 19 | ensure_capacity(length + 1); | 19 | ensure_capacity(length + 1); |
src/memory_profiling.cpp+5-2| ... | @@ -35,7 +35,9 @@ static const char *get_default_name(const char *name_or_null, size_t type_size) | ... | @@ -35,7 +35,9 @@ static const char *get_default_name(const char *name_or_null, size_t type_size) |
| 35 | if (name_or_null != nullptr) return name_or_null; | 35 | if (name_or_null != nullptr) return name_or_null; |
| 36 | if (type_size >= unknown_names.length) { | 36 | if (type_size >= unknown_names.length) { |
| 37 | table_active = false; | 37 | table_active = false; |
| 38 | unknown_names.resize(type_size + 1); | 38 | while (type_size >= unknown_names.length) { |
| 39 | unknown_names.append(nullptr); | ||
| 40 | } | ||
| 39 | table_active = true; | 41 | table_active = true; |
| 40 | } | 42 | } |
| 41 | if (unknown_names.at(type_size) == nullptr) { | 43 | if (unknown_names.at(type_size) == nullptr) { |
| ... | @@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) { | ... | @@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) { |
| 66 | name = get_default_name(name, type_size); | 68 | name = get_default_name(name, type_size); |
| 67 | auto existing_entry = usage_table.maybe_get(name); | 69 | auto existing_entry = usage_table.maybe_get(name); |
| 68 | if (existing_entry == nullptr) { | 70 | if (existing_entry == nullptr) { |
| 69 | zig_panic("deallocated more than allocated; compromised memory usage stats"); | 71 | zig_panic("deallocated name '%s' (size %zu) not found in allocated table; compromised memory usage stats", |
| 72 | name, type_size); | ||
| 70 | } | 73 | } |
| 71 | if (existing_entry->value.type_size != type_size) { | 74 | if (existing_entry->value.type_size != type_size) { |
| 72 | zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size); | 75 | zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size); |
src/os.cpp+4-4| ... | @@ -1554,7 +1554,7 @@ void os_stderr_set_color(TermColor color) { | ... | @@ -1554,7 +1554,7 @@ void os_stderr_set_color(TermColor color) { |
| 1554 | Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { | 1554 | Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { |
| 1555 | #if defined(ZIG_OS_WINDOWS) | 1555 | #if defined(ZIG_OS_WINDOWS) |
| 1556 | buf_resize(output_buf, 0); | 1556 | buf_resize(output_buf, 0); |
| 1557 | buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); | 1557 | buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); |
| 1558 | switch (platform_type) { | 1558 | switch (platform_type) { |
| 1559 | case ZigLLVM_x86: | 1559 | case ZigLLVM_x86: |
| 1560 | buf_append_str(output_buf, "x86\\"); | 1560 | buf_append_str(output_buf, "x86\\"); |
| ... | @@ -1586,7 +1586,7 @@ Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Ar | ... | @@ -1586,7 +1586,7 @@ Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Ar |
| 1586 | Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { | 1586 | Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { |
| 1587 | #if defined(ZIG_OS_WINDOWS) | 1587 | #if defined(ZIG_OS_WINDOWS) |
| 1588 | buf_resize(output_buf, 0); | 1588 | buf_resize(output_buf, 0); |
| 1589 | buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); | 1589 | buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); |
| 1590 | if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { | 1590 | if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { |
| 1591 | return ErrorNone; | 1591 | return ErrorNone; |
| 1592 | } | 1592 | } |
| ... | @@ -1603,7 +1603,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch | ... | @@ -1603,7 +1603,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch |
| 1603 | #if defined(ZIG_OS_WINDOWS) | 1603 | #if defined(ZIG_OS_WINDOWS) |
| 1604 | { | 1604 | { |
| 1605 | buf_resize(output_buf, 0); | 1605 | buf_resize(output_buf, 0); |
| 1606 | buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr); | 1606 | buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr); |
| 1607 | switch (platform_type) { | 1607 | switch (platform_type) { |
| 1608 | case ZigLLVM_x86: | 1608 | case ZigLLVM_x86: |
| 1609 | buf_append_str(output_buf, "x86\\"); | 1609 | buf_append_str(output_buf, "x86\\"); |
| ... | @@ -1626,7 +1626,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch | ... | @@ -1626,7 +1626,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch |
| 1626 | } | 1626 | } |
| 1627 | { | 1627 | { |
| 1628 | buf_resize(output_buf, 0); | 1628 | buf_resize(output_buf, 0); |
| 1629 | buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr); | 1629 | buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr); |
| 1630 | switch (platform_type) { | 1630 | switch (platform_type) { |
| 1631 | case ZigLLVM_x86: | 1631 | case ZigLLVM_x86: |
| 1632 | buf_append_str(output_buf, "x86\\"); | 1632 | buf_append_str(output_buf, "x86\\"); |
src/util.hpp+1-1| ... | @@ -165,7 +165,7 @@ static inline void deallocate(T *old, size_t count, const char *name = nullptr) | ... | @@ -165,7 +165,7 @@ static inline void deallocate(T *old, size_t count, const char *name = nullptr) |
| 165 | 165 | ||
| 166 | template<typename T> | 166 | template<typename T> |
| 167 | static inline void destroy(T *old, const char *name = nullptr) { | 167 | static inline void destroy(T *old, const char *name = nullptr) { |
| 168 | return deallocate(old, 1); | 168 | return deallocate(old, 1, name); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | template <typename T, size_t n> | 171 | template <typename T, size_t n> |
test/compile_errors.zig+7| ... | @@ -1670,10 +1670,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1670,10 +1670,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1670 | \\ var spartan_count: u16 = 300; | 1670 | \\ var spartan_count: u16 = 300; |
| 1671 | \\ var byte: u8 = spartan_count; | 1671 | \\ var byte: u8 = spartan_count; |
| 1672 | \\} | 1672 | \\} |
| 1673 | \\export fn entry4() void { | ||
| 1674 | \\ var signed: i8 = -1; | ||
| 1675 | \\ var unsigned: u64 = signed; | ||
| 1676 | \\} | ||
| 1673 | , | 1677 | , |
| 1674 | "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'", | 1678 | "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'", |
| 1675 | "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'", | 1679 | "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'", |
| 1676 | "tmp.zig:11:20: error: expected type 'u8', found 'u16'", | 1680 | "tmp.zig:11:20: error: expected type 'u8', found 'u16'", |
| 1681 | "tmp.zig:11:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values", | ||
| 1682 | "tmp.zig:15:25: error: expected type 'u64', found 'i8'", | ||
| 1683 | "tmp.zig:15:25: note: unsigned 64-bit int cannot represent all possible signed 8-bit values", | ||
| 1677 | ); | 1684 | ); |
| 1678 | 1685 | ||
| 1679 | cases.add( | 1686 | cases.add( |
test/gen_h.zig+17-15| ... | @@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 10 | \\ B = 1, | 10 | \\ B = 1, |
| 11 | \\ C = 2 | 11 | \\ C = 2 |
| 12 | \\}; | 12 | \\}; |
| 13 | \\ | 13 | , |
| 14 | \\TEST_EXTERN_C void entry(enum Foo foo); | 14 | \\void entry(enum Foo foo); |
| 15 | \\ | ||
| 16 | ); | 15 | ); |
| 17 | 16 | ||
| 18 | cases.add("declare struct", | 17 | cases.add("declare struct", |
| ... | @@ -34,8 +33,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -34,8 +33,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 34 | \\ uint64_t E; | 33 | \\ uint64_t E; |
| 35 | \\ uint64_t F; | 34 | \\ uint64_t F; |
| 36 | \\}; | 35 | \\}; |
| 37 | \\ | 36 | , |
| 38 | \\TEST_EXTERN_C void entry(struct Foo foo); | 37 | \\void entry(struct Foo foo); |
| 39 | \\ | 38 | \\ |
| 40 | ); | 39 | ); |
| 41 | 40 | ||
| ... | @@ -69,19 +68,19 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -69,19 +68,19 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 69 | \\ bool C; | 68 | \\ bool C; |
| 70 | \\ struct Big D; | 69 | \\ struct Big D; |
| 71 | \\}; | 70 | \\}; |
| 72 | \\ | 71 | , |
| 73 | \\TEST_EXTERN_C void entry(union Foo foo); | 72 | \\void entry(union Foo foo); |
| 74 | \\ | 73 | \\ |
| 75 | ); | 74 | ); |
| 76 | 75 | ||
| 77 | cases.add("declare opaque type", | 76 | cases.add("declare opaque type", |
| 78 | \\export const Foo = @OpaqueType(); | 77 | \\const Foo = @OpaqueType(); |
| 79 | \\ | 78 | \\ |
| 80 | \\export fn entry(foo: ?*Foo) void { } | 79 | \\export fn entry(foo: ?*Foo) void { } |
| 81 | , | 80 | , |
| 82 | \\struct Foo; | 81 | \\struct Foo; |
| 83 | \\ | 82 | , |
| 84 | \\TEST_EXTERN_C void entry(struct Foo * foo); | 83 | \\void entry(struct Foo * foo); |
| 85 | ); | 84 | ); |
| 86 | 85 | ||
| 87 | cases.add("array field-type", | 86 | cases.add("array field-type", |
| ... | @@ -95,8 +94,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -95,8 +94,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 95 | \\ int32_t A[2]; | 94 | \\ int32_t A[2]; |
| 96 | \\ uint32_t * B[4]; | 95 | \\ uint32_t * B[4]; |
| 97 | \\}; | 96 | \\}; |
| 98 | \\ | 97 | , |
| 99 | \\TEST_EXTERN_C void entry(struct Foo foo, uint8_t bar[]); | 98 | \\void entry(struct Foo foo, uint8_t bar[]); |
| 100 | \\ | 99 | \\ |
| 101 | ); | 100 | ); |
| 102 | 101 | ||
| ... | @@ -110,7 +109,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -110,7 +109,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 110 | \\} | 109 | \\} |
| 111 | , | 110 | , |
| 112 | \\struct S; | 111 | \\struct S; |
| 113 | \\TEST_EXTERN_C uint8_t a(struct S * s); | 112 | , |
| 113 | \\uint8_t a(struct S * s); | ||
| 114 | \\ | 114 | \\ |
| 115 | ); | 115 | ); |
| 116 | 116 | ||
| ... | @@ -125,7 +125,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -125,7 +125,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 125 | \\} | 125 | \\} |
| 126 | , | 126 | , |
| 127 | \\union U; | 127 | \\union U; |
| 128 | \\TEST_EXTERN_C uint8_t a(union U * s); | 128 | , |
| 129 | \\uint8_t a(union U * s); | ||
| 129 | \\ | 130 | \\ |
| 130 | ); | 131 | ); |
| 131 | 132 | ||
| ... | @@ -140,7 +141,8 @@ pub fn addCases(cases: *tests.GenHContext) void { | ... | @@ -140,7 +141,8 @@ pub fn addCases(cases: *tests.GenHContext) void { |
| 140 | \\} | 141 | \\} |
| 141 | , | 142 | , |
| 142 | \\enum E; | 143 | \\enum E; |
| 143 | \\TEST_EXTERN_C uint8_t a(enum E * s); | 144 | , |
| 145 | \\uint8_t a(enum E * s); | ||
| 144 | \\ | 146 | \\ |
| 145 | ); | 147 | ); |
| 146 | } | 148 | } |
test/standalone/cat/main.zig+5-3| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const io = std.io; | 2 | const io = std.io; |
| 3 | const process = std.process; | 3 | const process = std.process; |
| 4 | const File = std.fs.File; | 4 | const fs = std.fs; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const warn = std.debug.warn; | 6 | const warn = std.debug.warn; |
| 7 | const allocator = std.debug.global_allocator; | 7 | const allocator = std.debug.global_allocator; |
| ... | @@ -12,6 +12,8 @@ pub fn main() !void { | ... | @@ -12,6 +12,8 @@ pub fn main() !void { |
| 12 | var catted_anything = false; | 12 | var catted_anything = false; |
| 13 | const stdout_file = io.getStdOut(); | 13 | const stdout_file = io.getStdOut(); |
| 14 | 14 | ||
| 15 | const cwd = fs.cwd(); | ||
| 16 | |||
| 15 | while (args_it.next(allocator)) |arg_or_err| { | 17 | while (args_it.next(allocator)) |arg_or_err| { |
| 16 | const arg = try unwrapArg(arg_or_err); | 18 | const arg = try unwrapArg(arg_or_err); |
| 17 | if (mem.eql(u8, arg, "-")) { | 19 | if (mem.eql(u8, arg, "-")) { |
| ... | @@ -20,7 +22,7 @@ pub fn main() !void { | ... | @@ -20,7 +22,7 @@ pub fn main() !void { |
| 20 | } else if (arg[0] == '-') { | 22 | } else if (arg[0] == '-') { |
| 21 | return usage(exe); | 23 | return usage(exe); |
| 22 | } else { | 24 | } else { |
| 23 | const file = File.openRead(arg) catch |err| { | 25 | const file = cwd.openFile(arg, .{}) catch |err| { |
| 24 | warn("Unable to open file: {}\n", @errorName(err)); | 26 | warn("Unable to open file: {}\n", @errorName(err)); |
| 25 | return err; | 27 | return err; |
| 26 | }; | 28 | }; |
| ... | @@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void { | ... | @@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void { |
| 40 | return error.Invalid; | 42 | return error.Invalid; |
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | fn cat_file(stdout: File, file: File) !void { | 45 | fn cat_file(stdout: fs.File, file: fs.File) !void { |
| 44 | var buf: [1024 * 4]u8 = undefined; | 46 | var buf: [1024 * 4]u8 = undefined; |
| 45 | 47 | ||
| 46 | while (true) { | 48 | while (true) { |
test/standalone/static_c_lib/foo.c+2| ... | @@ -2,3 +2,5 @@ | ... | @@ -2,3 +2,5 @@ |
| 2 | uint32_t add(uint32_t a, uint32_t b) { | 2 | uint32_t add(uint32_t a, uint32_t b) { |
| 3 | return a + b; | 3 | return a + b; |
| 4 | } | 4 | } |
| 5 | |||
| 6 | uint32_t foo = 12345; |
test/standalone/static_c_lib/foo.h+1| ... | @@ -1,2 +1,3 @@ | ... | @@ -1,2 +1,3 @@ |
| 1 | #include <stdint.h> | 1 | #include <stdint.h> |
| 2 | uint32_t add(uint32_t a, uint32_t b); | 2 | uint32_t add(uint32_t a, uint32_t b); |
| 3 | extern uint32_t foo; |
test/standalone/static_c_lib/foo.zig+4| ... | @@ -6,3 +6,7 @@ test "C add" { | ... | @@ -6,3 +6,7 @@ test "C add" { |
| 6 | const result = c.add(1, 2); | 6 | const result = c.add(1, 2); |
| 7 | expect(result == 3); | 7 | expect(result == 3); |
| 8 | } | 8 | } |
| 9 | |||
| 10 | test "C extern variable" { | ||
| 11 | expect(c.foo == 12345); | ||
| 12 | } |
test/tests.zig+20| ... | @@ -70,6 +70,26 @@ const test_targets = [_]TestTarget{ | ... | @@ -70,6 +70,26 @@ const test_targets = [_]TestTarget{ |
| 70 | .link_libc = true, | 70 | .link_libc = true, |
| 71 | }, | 71 | }, |
| 72 | 72 | ||
| 73 | TestTarget{ | ||
| 74 | .target = Target{ | ||
| 75 | .Cross = CrossTarget{ | ||
| 76 | .os = .linux, | ||
| 77 | .arch = .i386, | ||
| 78 | .abi = .none, | ||
| 79 | }, | ||
| 80 | }, | ||
| 81 | }, | ||
| 82 | TestTarget{ | ||
| 83 | .target = Target{ | ||
| 84 | .Cross = CrossTarget{ | ||
| 85 | .os = .linux, | ||
| 86 | .arch = .i386, | ||
| 87 | .abi = .musl, | ||
| 88 | }, | ||
| 89 | }, | ||
| 90 | .link_libc = true, | ||
| 91 | }, | ||
| 92 | |||
| 73 | TestTarget{ | 93 | TestTarget{ |
| 74 | .target = Target{ | 94 | .target = Target{ |
| 75 | .Cross = CrossTarget{ | 95 | .Cross = CrossTarget{ |