| author | |
| committer | |
| log | f9bd049c89e4d2b4d3f51a937ec2114c3cac9176 |
| tree | 81bf283c8ae2e06fd3a48d18e3b4196e194392d0 |
| parent | 3aeeb21b82915a3d03e75a88ded93049a5c1730c |
| parent | dad7af0b37f352c8c390438877ef1552a316ffde |
526 files changed, 9582 insertions(+), 4926 deletions(-)
build.zig+1-1| ... | ... | @@ -38,7 +38,7 @@ pub fn build(b: *Builder) !void { |
| 38 | 38 | const test_step = b.step("test", "Run all the tests"); |
| 39 | 39 | |
| 40 | 40 | var test_stage2 = b.addTest("src-self-hosted/test.zig"); |
| 41 | test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness | |
| 41 | test_stage2.setBuildMode(mode); | |
| 42 | 42 | test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig"); |
| 43 | 43 | |
| 44 | 44 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); |
lib/std/array_list.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const assert = debug.assert; |
lib/std/array_list_sentineled.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const mem = std.mem; |
lib/std/ascii.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does. |
| 2 | 7 | // I could have taken only a u7 to make this clear, but it would be slower |
| 3 | 8 | // It is my opinion that encodings other than UTF-8 should not be supported. |
lib/std/atomic.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const Stack = @import("atomic/stack.zig").Stack; |
| 2 | 7 | pub const Queue = @import("atomic/queue.zig").Queue; |
| 3 | 8 | pub const Int = @import("atomic/int.zig").Int; |
lib/std/atomic/int.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Thread-safe, lock-free integer |
| 2 | 7 | pub fn Int(comptime T: type) type { |
| 3 | 8 | return struct { |
lib/std/atomic/queue.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/atomic/stack.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const assert = std.debug.assert; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/base64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/bloom_filter.zig+6-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std.zig"); |
| 3 | 8 | const math = std.math; |
| ... | ... | @@ -153,7 +158,7 @@ pub fn BloomFilter( |
| 153 | 158 | } |
| 154 | 159 | |
| 155 | 160 | fn hashFunc(out: []u8, Ki: usize, in: []const u8) void { |
| 156 | var st = std.crypto.gimli.Hash.init(); | |
| 161 | var st = std.crypto.hash.Gimli.init(.{}); | |
| 157 | 162 | st.update(std.mem.asBytes(&Ki)); |
| 158 | 163 | st.update(in); |
| 159 | 164 | st.final(out); |
lib/std/buf_map.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const StringHashMap = std.StringHashMap; |
| 3 | 8 | const mem = std.mem; |
lib/std/buf_set.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const StringHashMap = std.StringHashMap; |
| 3 | 8 | const mem = @import("mem.zig"); |
lib/std/build.zig+32-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
| ... | ... | @@ -449,7 +454,33 @@ pub const Builder = struct { |
| 449 | 454 | return null; |
| 450 | 455 | }, |
| 451 | 456 | }, |
| 452 | .Int => panic("TODO integer options to build script", .{}), | |
| 457 | .Int => switch (entry.value.value) { | |
| 458 | .Flag => { | |
| 459 | warn("Expected -D{} to be an integer, but received a boolean.\n", .{name}); | |
| 460 | self.markInvalidUserInput(); | |
| 461 | return null; | |
| 462 | }, | |
| 463 | .Scalar => |s| { | |
| 464 | const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { | |
| 465 | error.Overflow => { | |
| 466 | warn("-D{} value {} cannot fit into type {}.\n", .{ name, s, @typeName(T) }); | |
| 467 | self.markInvalidUserInput(); | |
| 468 | return null; | |
| 469 | }, | |
| 470 | else => { | |
| 471 | warn("Expected -D{} to be an integer of type {}.\n", .{ name, @typeName(T) }); | |
| 472 | self.markInvalidUserInput(); | |
| 473 | return null; | |
| 474 | }, | |
| 475 | }; | |
| 476 | return n; | |
| 477 | }, | |
| 478 | .List => { | |
| 479 | warn("Expected -D{} to be an integer, but received a list.\n", .{name}); | |
| 480 | self.markInvalidUserInput(); | |
| 481 | return null; | |
| 482 | }, | |
| 483 | }, | |
| 453 | 484 | .Float => panic("TODO float options to build script", .{}), |
| 454 | 485 | .Enum => switch (entry.value.value) { |
| 455 | 486 | .Flag => { |
lib/std/build/check_file.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const build = std.build; |
| 3 | 8 | const Step = build.Step; |
lib/std/build/emit_raw.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | const Allocator = std.mem.Allocator; |
lib/std/build/fmt.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const build = @import("../build.zig"); |
| 3 | 8 | const Step = build.Step; |
lib/std/build/run.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const build = std.build; |
lib/std/build/translate_c.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const build = std.build; |
| 3 | 8 | const Step = build.Step; |
lib/std/build/write_file.zig+6-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const build = @import("../build.zig"); |
| 3 | 8 | const Step = build.Step; |
| ... | ... | @@ -53,7 +58,7 @@ pub const WriteFileStep = struct { |
| 53 | 58 | // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b |
| 54 | 59 | // directly and construct the path, and no "cache hit" detection happens; the files |
| 55 | 60 | // are always written. |
| 56 | var hash = std.crypto.Blake2b384.init(); | |
| 61 | var hash = std.crypto.hash.blake2.Blake2b384.init(.{}); | |
| 57 | 62 | |
| 58 | 63 | // Random bytes to make WriteFileStep unique. Refresh this with |
| 59 | 64 | // new random bytes when WriteFileStep implementation is modified |
lib/std/builtin.zig+5-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub usingnamespace @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | /// Deprecated: use `std.Target`. |
| ... | ... | @@ -254,7 +259,6 @@ pub const TypeInfo = union(enum) { |
| 254 | 259 | /// therefore must be kept in sync with the compiler implementation. |
| 255 | 260 | pub const StructField = struct { |
| 256 | 261 | name: []const u8, |
| 257 | offset: ?comptime_int, | |
| 258 | 262 | field_type: type, |
| 259 | 263 | default_value: anytype, |
| 260 | 264 | }; |
lib/std/c.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const page_size = std.mem.page_size; |
lib/std/c/ast.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const SegmentedList = std.SegmentedList; |
| 3 | 8 | const Token = std.c.Token; |
lib/std/c/darwin.zig+8-2| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const builtin = @import("builtin"); |
| ... | ... | @@ -41,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; |
| 41 | 46 | /// on this operating system. However when building object files or libraries, |
| 42 | 47 | /// the system libc won't be linked until the final executable. So we |
| 43 | 48 | /// export a weak symbol here, to be overridden by the real one. |
| 44 | pub extern "c" var _mh_execute_header: mach_hdr = undefined; | |
| 49 | var dummy_execute_header: mach_hdr = undefined; | |
| 50 | pub extern var _mh_execute_header: mach_hdr; | |
| 45 | 51 | comptime { |
| 46 | 52 | if (std.Target.current.isDarwin()) { |
| 47 | @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); | |
| 53 | @export(dummy_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); | |
| 48 | 54 | } |
| 49 | 55 | } |
| 50 | 56 |
lib/std/c/dragonfly.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | usingnamespace std.c; |
| 3 | 8 | extern "c" threadlocal var errno: c_int; |
lib/std/c/emscripten.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, |
| 3 | 8 | }; |
lib/std/c/freebsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | usingnamespace std.c; |
| 3 | 8 |
lib/std/c/fuchsia.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, |
| 3 | 8 | }; |
lib/std/c/haiku.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | flags: u32 = 0, |
| 3 | 8 | lock: i32 = 0, |
lib/std/c/hermit.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | inner: usize = ~@as(usize, 0), |
| 3 | 8 | }; |
lib/std/c/linux.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("../std.zig"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/c/minix.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | pub const pthread_mutex_t = extern struct { |
| 3 | 8 | size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, |
lib/std/c/netbsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 |
lib/std/c/openbsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | inner: ?*c_void = null, |
| 3 | 8 | }; |
lib/std/c/parse.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/c/solaris.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const pthread_mutex_t = extern struct { |
| 2 | 7 | __pthread_mutex_flag1: u16 = 0, |
| 3 | 8 | __pthread_mutex_flag2: u8 = 0, |
lib/std/c/tokenizer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
lib/std/c/windows.zig+5| ... | ... | @@ -1 +1,6 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub extern "c" fn _errno() *c_int; |
lib/std/cache_hash.zig+11-6| ... | ... | @@ -1,5 +1,10 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | const Blake3 = std.crypto.Blake3; | |
| 7 | const Blake3 = std.crypto.hash.Blake3; | |
| 3 | 8 | const fs = std.fs; |
| 4 | 9 | const base64 = std.base64; |
| 5 | 10 | const ArrayList = std.ArrayList; |
| ... | ... | @@ -51,7 +56,7 @@ pub const CacheHash = struct { |
| 51 | 56 | pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash { |
| 52 | 57 | return CacheHash{ |
| 53 | 58 | .allocator = allocator, |
| 54 | .blake3 = Blake3.init(), | |
| 59 | .blake3 = Blake3.init(.{}), | |
| 55 | 60 | .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}), |
| 56 | 61 | .manifest_file = null, |
| 57 | 62 | .manifest_dirty = false, |
| ... | ... | @@ -132,7 +137,7 @@ pub const CacheHash = struct { |
| 132 | 137 | |
| 133 | 138 | base64_encoder.encode(self.b64_digest[0..], &bin_digest); |
| 134 | 139 | |
| 135 | self.blake3 = Blake3.init(); | |
| 140 | self.blake3 = Blake3.init(.{}); | |
| 136 | 141 | self.blake3.update(&bin_digest); |
| 137 | 142 | |
| 138 | 143 | const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest}); |
| ... | ... | @@ -251,7 +256,7 @@ pub const CacheHash = struct { |
| 251 | 256 | // cache miss |
| 252 | 257 | // keep the manifest file open |
| 253 | 258 | // reset the hash |
| 254 | self.blake3 = Blake3.init(); | |
| 259 | self.blake3 = Blake3.init(.{}); | |
| 255 | 260 | self.blake3.update(&bin_digest); |
| 256 | 261 | |
| 257 | 262 | // Remove files not in the initial hash |
| ... | ... | @@ -299,7 +304,7 @@ pub const CacheHash = struct { |
| 299 | 304 | |
| 300 | 305 | // Hash while reading from disk, to keep the contents in the cpu cache while |
| 301 | 306 | // doing hashing. |
| 302 | var blake3 = Blake3.init(); | |
| 307 | var blake3 = Blake3.init(.{}); | |
| 303 | 308 | var off: usize = 0; |
| 304 | 309 | while (true) { |
| 305 | 310 | // give me everything you've got, captain |
| ... | ... | @@ -429,7 +434,7 @@ pub const CacheHash = struct { |
| 429 | 434 | }; |
| 430 | 435 | |
| 431 | 436 | fn hashFile(file: fs.File, bin_digest: []u8) !void { |
| 432 | var blake3 = Blake3.init(); | |
| 437 | var blake3 = Blake3.init(.{}); | |
| 433 | 438 | var buf: [1024]u8 = undefined; |
| 434 | 439 | |
| 435 | 440 | while (true) { |
lib/std/child_process.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const cstr = std.cstr; |
| 3 | 8 | const unicode = std.unicode; |
lib/std/coff.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std.zig"); |
| 3 | 8 | const io = std.io; |
lib/std/comptime_string_map.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
lib/std/crypto.zig+74-56| ... | ... | @@ -1,55 +1,68 @@ |
| 1 | pub const Md5 = @import("crypto/md5.zig").Md5; | |
| 2 | pub const Sha1 = @import("crypto/sha1.zig").Sha1; | |
| 3 | ||
| 4 | const sha2 = @import("crypto/sha2.zig"); | |
| 5 | pub const Sha224 = sha2.Sha224; | |
| 6 | pub const Sha256 = sha2.Sha256; | |
| 7 | pub const Sha384 = sha2.Sha384; | |
| 8 | pub const Sha512 = sha2.Sha512; | |
| 9 | ||
| 10 | const sha3 = @import("crypto/sha3.zig"); | |
| 11 | pub const Sha3_224 = sha3.Sha3_224; | |
| 12 | pub const Sha3_256 = sha3.Sha3_256; | |
| 13 | pub const Sha3_384 = sha3.Sha3_384; | |
| 14 | pub const Sha3_512 = sha3.Sha3_512; | |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | ||
| 7 | /// Hash functions. | |
| 8 | pub const hash = struct { | |
| 9 | pub const Md5 = @import("crypto/md5.zig").Md5; | |
| 10 | pub const Sha1 = @import("crypto/sha1.zig").Sha1; | |
| 11 | pub const sha2 = @import("crypto/sha2.zig"); | |
| 12 | pub const sha3 = @import("crypto/sha3.zig"); | |
| 13 | pub const blake2 = @import("crypto/blake2.zig"); | |
| 14 | pub const Blake3 = @import("crypto/blake3.zig").Blake3; | |
| 15 | pub const Gimli = @import("crypto/gimli.zig").Hash; | |
| 16 | }; | |
| 15 | 17 | |
| 16 | pub const gimli = @import("crypto/gimli.zig"); | |
| 18 | /// Authentication (MAC) functions. | |
| 19 | pub const auth = struct { | |
| 20 | pub const hmac = @import("crypto/hmac.zig"); | |
| 21 | }; | |
| 17 | 22 | |
| 18 | const blake2 = @import("crypto/blake2.zig"); | |
| 19 | pub const Blake2s224 = blake2.Blake2s224; | |
| 20 | pub const Blake2s256 = blake2.Blake2s256; | |
| 21 | pub const Blake2b384 = blake2.Blake2b384; | |
| 22 | pub const Blake2b512 = blake2.Blake2b512; | |
| 23 | /// Authenticated Encryption with Associated Data | |
| 24 | pub const aead = struct { | |
| 25 | const chacha20 = @import("crypto/chacha20.zig"); | |
| 23 | 26 | |
| 24 | pub const Blake3 = @import("crypto/blake3.zig").Blake3; | |
| 27 | pub const Gimli = @import("crypto/gimli.zig").Aead; | |
| 28 | pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; | |
| 29 | pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; | |
| 30 | }; | |
| 25 | 31 | |
| 26 | const hmac = @import("crypto/hmac.zig"); | |
| 27 | pub const HmacMd5 = hmac.HmacMd5; | |
| 28 | pub const HmacSha1 = hmac.HmacSha1; | |
| 29 | pub const HmacSha256 = hmac.HmacSha256; | |
| 30 | pub const HmacBlake2s256 = hmac.HmacBlake2s256; | |
| 32 | /// MAC functions requiring single-use secret keys. | |
| 33 | pub const onetimeauth = struct { | |
| 34 | pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; | |
| 35 | }; | |
| 31 | 36 | |
| 32 | pub const chacha20 = @import("crypto/chacha20.zig"); | |
| 33 | pub const chaCha20IETF = chacha20.chaCha20IETF; | |
| 34 | pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce; | |
| 35 | pub const xChaCha20IETF = chacha20.xChaCha20IETF; | |
| 37 | /// Core functions, that should rarely be used directly by applications. | |
| 38 | pub const core = struct { | |
| 39 | pub const aes = @import("crypto/aes.zig"); | |
| 40 | pub const Gimli = @import("crypto/gimli.zig").State; | |
| 41 | }; | |
| 36 | 42 | |
| 37 | pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; | |
| 43 | /// Elliptic-curve arithmetic. | |
| 44 | pub const ecc = struct { | |
| 45 | pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; | |
| 46 | pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; | |
| 47 | pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; | |
| 48 | }; | |
| 38 | 49 | |
| 39 | const import_aes = @import("crypto/aes.zig"); | |
| 40 | pub const AES128 = import_aes.AES128; | |
| 41 | pub const AES256 = import_aes.AES256; | |
| 50 | /// Diffie-Hellman key exchange functions. | |
| 51 | pub const dh = struct { | |
| 52 | pub const X25519 = @import("crypto/25519/x25519.zig").X25519; | |
| 53 | }; | |
| 42 | 54 | |
| 43 | pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; | |
| 44 | pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; | |
| 45 | pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; | |
| 46 | pub const X25519 = @import("crypto/25519/x25519.zig").X25519; | |
| 47 | pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; | |
| 55 | /// Digital signature functions. | |
| 56 | pub const sign = struct { | |
| 57 | pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; | |
| 58 | }; | |
| 48 | 59 | |
| 49 | pub const aead = struct { | |
| 50 | pub const Gimli = gimli.Aead; | |
| 51 | pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; | |
| 52 | pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; | |
| 60 | /// Stream ciphers. These do not provide any kind of authentication. | |
| 61 | /// Most applications should be using AEAD constructions instead of stream ciphers directly. | |
| 62 | pub const stream = struct { | |
| 63 | pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF; | |
| 64 | pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF; | |
| 65 | pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce; | |
| 53 | 66 | }; |
| 54 | 67 | |
| 55 | 68 | const std = @import("std.zig"); |
| ... | ... | @@ -78,27 +91,32 @@ test "crypto" { |
| 78 | 91 | |
| 79 | 92 | test "issue #4532: no index out of bounds" { |
| 80 | 93 | const types = [_]type{ |
| 81 | Md5, | |
| 82 | Sha1, | |
| 83 | Sha224, | |
| 84 | Sha256, | |
| 85 | Sha384, | |
| 86 | Sha512, | |
| 87 | Blake2s224, | |
| 88 | Blake2s256, | |
| 89 | Blake2b384, | |
| 90 | Blake2b512, | |
| 94 | hash.Md5, | |
| 95 | hash.Sha1, | |
| 96 | hash.sha2.Sha224, | |
| 97 | hash.sha2.Sha256, | |
| 98 | hash.sha2.Sha384, | |
| 99 | hash.sha2.Sha512, | |
| 100 | hash.sha3.Sha3_224, | |
| 101 | hash.sha3.Sha3_256, | |
| 102 | hash.sha3.Sha3_384, | |
| 103 | hash.sha3.Sha3_512, | |
| 104 | hash.blake2.Blake2s224, | |
| 105 | hash.blake2.Blake2s256, | |
| 106 | hash.blake2.Blake2b384, | |
| 107 | hash.blake2.Blake2b512, | |
| 108 | hash.Gimli, | |
| 91 | 109 | }; |
| 92 | 110 | |
| 93 | 111 | inline for (types) |Hasher| { |
| 94 | 112 | var block = [_]u8{'#'} ** Hasher.block_length; |
| 95 | 113 | var out1: [Hasher.digest_length]u8 = undefined; |
| 96 | 114 | var out2: [Hasher.digest_length]u8 = undefined; |
| 97 | ||
| 98 | var h = Hasher.init(); | |
| 115 | const h0 = Hasher.init(.{}); | |
| 116 | var h = h0; | |
| 99 | 117 | h.update(block[0..]); |
| 100 | 118 | h.final(out1[0..]); |
| 101 | h.reset(); | |
| 119 | h = h0; | |
| 102 | 120 | h.update(block[0..1]); |
| 103 | 121 | h.update(block[1..]); |
| 104 | 122 | h.final(out2[0..]); |
lib/std/crypto/25519/curve25519.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | /// Group operations over Curve25519. |
lib/std/crypto/25519/ed25519.zig+11-6| ... | ... | @@ -1,7 +1,12 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const fmt = std.fmt; |
| 3 | 8 | const mem = std.mem; |
| 4 | const Sha512 = std.crypto.Sha512; | |
| 9 | const Sha512 = std.crypto.hash.sha2.Sha512; | |
| 5 | 10 | |
| 6 | 11 | /// Ed25519 (EdDSA) signatures. |
| 7 | 12 | pub const Ed25519 = struct { |
| ... | ... | @@ -28,7 +33,7 @@ pub const Ed25519 = struct { |
| 28 | 33 | /// from which the actual secret is derived. |
| 29 | 34 | pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 { |
| 30 | 35 | var az: [Sha512.digest_length]u8 = undefined; |
| 31 | var h = Sha512.init(); | |
| 36 | var h = Sha512.init(.{}); | |
| 32 | 37 | h.update(&seed); |
| 33 | 38 | h.final(&az); |
| 34 | 39 | const p = try Curve.basePoint.clampedMul(az[0..32].*); |
| ... | ... | @@ -51,11 +56,11 @@ pub const Ed25519 = struct { |
| 51 | 56 | pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 { |
| 52 | 57 | const public_key = key_pair[32..]; |
| 53 | 58 | var az: [Sha512.digest_length]u8 = undefined; |
| 54 | var h = Sha512.init(); | |
| 59 | var h = Sha512.init(.{}); | |
| 55 | 60 | h.update(key_pair[0..seed_length]); |
| 56 | 61 | h.final(&az); |
| 57 | 62 | |
| 58 | h = Sha512.init(); | |
| 63 | h = Sha512.init(.{}); | |
| 59 | 64 | if (noise) |*z| { |
| 60 | 65 | h.update(z); |
| 61 | 66 | } |
| ... | ... | @@ -69,7 +74,7 @@ pub const Ed25519 = struct { |
| 69 | 74 | var sig: [signature_length]u8 = undefined; |
| 70 | 75 | mem.copy(u8, sig[0..32], &r.toBytes()); |
| 71 | 76 | mem.copy(u8, sig[32..], public_key); |
| 72 | h = Sha512.init(); | |
| 77 | h = Sha512.init(.{}); | |
| 73 | 78 | h.update(&sig); |
| 74 | 79 | h.update(msg); |
| 75 | 80 | var hram64: [Sha512.digest_length]u8 = undefined; |
| ... | ... | @@ -93,7 +98,7 @@ pub const Ed25519 = struct { |
| 93 | 98 | const a = try Curve.fromBytes(public_key); |
| 94 | 99 | try a.rejectIdentity(); |
| 95 | 100 | |
| 96 | var h = Sha512.init(); | |
| 101 | var h = Sha512.init(.{}); | |
| 97 | 102 | h.update(r); |
| 98 | 103 | h.update(&public_key); |
| 99 | 104 | h.update(msg); |
lib/std/crypto/25519/edwards25519.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const fmt = std.fmt; |
| 3 | 8 |
lib/std/crypto/25519/field.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const readIntLittle = std.mem.readIntLittle; |
| 3 | 8 | const writeIntLittle = std.mem.writeIntLittle; |
lib/std/crypto/25519/ristretto255.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const fmt = std.fmt; |
| 3 | 8 |
lib/std/crypto/25519/scalar.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
lib/std/crypto/25519/x25519.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const fmt = std.fmt; |
lib/std/crypto/aes.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Based on Go stdlib implementation |
| 2 | 7 | |
| 3 | 8 | const std = @import("../std.zig"); |
lib/std/crypto/benchmark.zig+25-19| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // zig run benchmark.zig --release-fast --override-lib-dir .. |
| 2 | 7 | |
| 3 | 8 | const builtin = @import("builtin"); |
| ... | ... | @@ -17,20 +22,20 @@ const Crypto = struct { |
| 17 | 22 | }; |
| 18 | 23 | |
| 19 | 24 | const hashes = [_]Crypto{ |
| 20 | Crypto{ .ty = crypto.Md5, .name = "md5" }, | |
| 21 | Crypto{ .ty = crypto.Sha1, .name = "sha1" }, | |
| 22 | Crypto{ .ty = crypto.Sha256, .name = "sha256" }, | |
| 23 | Crypto{ .ty = crypto.Sha512, .name = "sha512" }, | |
| 24 | Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" }, | |
| 25 | Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" }, | |
| 26 | Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" }, | |
| 27 | Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" }, | |
| 28 | Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" }, | |
| 29 | Crypto{ .ty = crypto.Blake3, .name = "blake3" }, | |
| 25 | Crypto{ .ty = crypto.hash.Md5, .name = "md5" }, | |
| 26 | Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" }, | |
| 27 | Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" }, | |
| 28 | Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" }, | |
| 29 | Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" }, | |
| 30 | Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" }, | |
| 31 | Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" }, | |
| 32 | Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" }, | |
| 33 | Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" }, | |
| 34 | Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" }, | |
| 30 | 35 | }; |
| 31 | 36 | |
| 32 | 37 | pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 { |
| 33 | var h = Hash.init(); | |
| 38 | var h = Hash.init(.{}); | |
| 34 | 39 | |
| 35 | 40 | var block: [Hash.digest_length]u8 = undefined; |
| 36 | 41 | prng.random.bytes(block[0..]); |
| ... | ... | @@ -50,19 +55,20 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 |
| 50 | 55 | } |
| 51 | 56 | |
| 52 | 57 | const macs = [_]Crypto{ |
| 53 | Crypto{ .ty = crypto.Poly1305, .name = "poly1305" }, | |
| 54 | Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" }, | |
| 55 | Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" }, | |
| 56 | Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" }, | |
| 58 | Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, | |
| 59 | Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" }, | |
| 60 | Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" }, | |
| 61 | Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" }, | |
| 62 | Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" }, | |
| 57 | 63 | }; |
| 58 | 64 | |
| 59 | 65 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { |
| 60 | std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | |
| 66 | std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | |
| 61 | 67 | |
| 62 | 68 | var in: [1 * MiB]u8 = undefined; |
| 63 | 69 | prng.random.bytes(in[0..]); |
| 64 | 70 | |
| 65 | var key: [32]u8 = undefined; | |
| 71 | var key: [64]u8 = undefined; | |
| 66 | 72 | prng.random.bytes(key[0..]); |
| 67 | 73 | |
| 68 | 74 | var offset: usize = 0; |
| ... | ... | @@ -79,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { |
| 79 | 85 | return throughput; |
| 80 | 86 | } |
| 81 | 87 | |
| 82 | const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }}; | |
| 88 | const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }}; | |
| 83 | 89 | |
| 84 | 90 | pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 { |
| 85 | 91 | std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length); |
| ... | ... | @@ -106,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c |
| 106 | 112 | return throughput; |
| 107 | 113 | } |
| 108 | 114 | |
| 109 | const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }}; | |
| 115 | const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; | |
| 110 | 116 | |
| 111 | 117 | pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { |
| 112 | 118 | var seed: [Signature.seed_length]u8 = undefined; |
lib/std/crypto/blake2.zig+107-78| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const mem = @import("../mem.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const debug = @import("../debug.zig"); |
| ... | ... | @@ -35,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type { |
| 35 | 40 | const Self = @This(); |
| 36 | 41 | pub const block_length = 64; |
| 37 | 42 | pub const digest_length = out_len / 8; |
| 43 | pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null }; | |
| 38 | 44 | |
| 39 | 45 | const iv = [8]u32{ |
| 40 | 46 | 0x6A09E667, |
| ... | ... | @@ -66,42 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type { |
| 66 | 72 | buf: [64]u8, |
| 67 | 73 | buf_len: u8, |
| 68 | 74 | |
| 69 | key: []const u8, | |
| 70 | ||
| 71 | pub fn init() Self { | |
| 72 | return init_keyed(""); | |
| 73 | } | |
| 74 | ||
| 75 | pub fn init_keyed(key: []const u8) Self { | |
| 75 | pub fn init(options: Options) Self { | |
| 76 | 76 | debug.assert(8 <= out_len and out_len <= 512); |
| 77 | 77 | |
| 78 | var s: Self = undefined; | |
| 79 | s.key = key; | |
| 80 | s.reset(); | |
| 81 | return s; | |
| 82 | } | |
| 83 | ||
| 84 | pub fn reset(d: *Self) void { | |
| 78 | var d: Self = undefined; | |
| 85 | 79 | mem.copy(u32, d.h[0..], iv[0..]); |
| 86 | 80 | |
| 81 | const key_len = if (options.key) |key| key.len else 0; | |
| 87 | 82 | // default parameters |
| 88 | d.h[0] ^= 0x01010000 ^ @truncate(u32, d.key.len << 8) ^ @intCast(u32, out_len >> 3); | |
| 83 | d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_len >> 3); | |
| 89 | 84 | d.t = 0; |
| 90 | 85 | d.buf_len = 0; |
| 91 | 86 | |
| 92 | if (d.key.len > 0) { | |
| 93 | mem.set(u8, d.buf[d.key.len..], 0); | |
| 94 | d.update(d.key); | |
| 87 | if (options.salt) |salt| { | |
| 88 | d.h[4] ^= mem.readIntLittle(u32, salt[0..4]); | |
| 89 | d.h[5] ^= mem.readIntLittle(u32, salt[4..8]); | |
| 90 | } | |
| 91 | if (options.context) |context| { | |
| 92 | d.h[6] ^= mem.readIntLittle(u32, context[0..4]); | |
| 93 | d.h[7] ^= mem.readIntLittle(u32, context[4..8]); | |
| 94 | } | |
| 95 | if (key_len > 0) { | |
| 96 | mem.set(u8, d.buf[key_len..], 0); | |
| 97 | d.update(options.key.?); | |
| 95 | 98 | d.buf_len = 64; |
| 96 | 99 | } |
| 100 | return d; | |
| 97 | 101 | } |
| 98 | 102 | |
| 99 | pub fn hash(b: []const u8, out: []u8) void { | |
| 100 | Self.hash_keyed("", b, out); | |
| 101 | } | |
| 102 | ||
| 103 | pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { | |
| 104 | var d = Self.init_keyed(key); | |
| 103 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 104 | var d = Self.init(options); | |
| 105 | 105 | d.update(b); |
| 106 | 106 | d.final(out); |
| 107 | 107 | } |
| ... | ... | @@ -210,7 +210,7 @@ test "blake2s224 single" { |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | 212 | test "blake2s224 streaming" { |
| 213 | var h = Blake2s224.init(); | |
| 213 | var h = Blake2s224.init(.{}); | |
| 214 | 214 | var out: [28]u8 = undefined; |
| 215 | 215 | |
| 216 | 216 | const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4"; |
| ... | ... | @@ -220,12 +220,12 @@ test "blake2s224 streaming" { |
| 220 | 220 | |
| 221 | 221 | const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"; |
| 222 | 222 | |
| 223 | h.reset(); | |
| 223 | h = Blake2s224.init(.{}); | |
| 224 | 224 | h.update("abc"); |
| 225 | 225 | h.final(out[0..]); |
| 226 | 226 | htest.assertEqual(h2, out[0..]); |
| 227 | 227 | |
| 228 | h.reset(); | |
| 228 | h = Blake2s224.init(.{}); | |
| 229 | 229 | h.update("a"); |
| 230 | 230 | h.update("b"); |
| 231 | 231 | h.update("c"); |
| ... | ... | @@ -234,16 +234,29 @@ test "blake2s224 streaming" { |
| 234 | 234 | |
| 235 | 235 | const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01"; |
| 236 | 236 | |
| 237 | h.reset(); | |
| 237 | h = Blake2s224.init(.{}); | |
| 238 | 238 | h.update("a" ** 32); |
| 239 | 239 | h.update("b" ** 32); |
| 240 | 240 | h.final(out[0..]); |
| 241 | 241 | htest.assertEqual(h3, out[0..]); |
| 242 | 242 | |
| 243 | h.reset(); | |
| 243 | h = Blake2s224.init(.{}); | |
| 244 | 244 | h.update("a" ** 32 ++ "b" ** 32); |
| 245 | 245 | h.final(out[0..]); |
| 246 | 246 | htest.assertEqual(h3, out[0..]); |
| 247 | ||
| 248 | const h4 = "a4d6a9d253441b80e5dfd60a04db169ffab77aec56a2855c402828c3"; | |
| 249 | ||
| 250 | h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); | |
| 251 | h.update("a" ** 32); | |
| 252 | h.update("b" ** 32); | |
| 253 | h.final(out[0..]); | |
| 254 | htest.assertEqual(h4, out[0..]); | |
| 255 | ||
| 256 | h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); | |
| 257 | h.update("a" ** 32 ++ "b" ** 32); | |
| 258 | h.final(out[0..]); | |
| 259 | htest.assertEqual(h4, out[0..]); | |
| 247 | 260 | } |
| 248 | 261 | |
| 249 | 262 | test "comptime blake2s224" { |
| ... | ... | @@ -256,7 +269,7 @@ test "comptime blake2s224" { |
| 256 | 269 | |
| 257 | 270 | htest.assertEqualHash(Blake2s224, h1, block[0..]); |
| 258 | 271 | |
| 259 | var h = Blake2s224.init(); | |
| 272 | var h = Blake2s224.init(.{}); | |
| 260 | 273 | h.update(&block); |
| 261 | 274 | h.final(out[0..]); |
| 262 | 275 | |
| ... | ... | @@ -279,7 +292,7 @@ test "blake2s256 single" { |
| 279 | 292 | } |
| 280 | 293 | |
| 281 | 294 | test "blake2s256 streaming" { |
| 282 | var h = Blake2s256.init(); | |
| 295 | var h = Blake2s256.init(.{}); | |
| 283 | 296 | var out: [32]u8 = undefined; |
| 284 | 297 | |
| 285 | 298 | const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"; |
| ... | ... | @@ -289,12 +302,12 @@ test "blake2s256 streaming" { |
| 289 | 302 | |
| 290 | 303 | const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"; |
| 291 | 304 | |
| 292 | h.reset(); | |
| 305 | h = Blake2s256.init(.{}); | |
| 293 | 306 | h.update("abc"); |
| 294 | 307 | h.final(out[0..]); |
| 295 | 308 | htest.assertEqual(h2, out[0..]); |
| 296 | 309 | |
| 297 | h.reset(); | |
| 310 | h = Blake2s256.init(.{}); | |
| 298 | 311 | h.update("a"); |
| 299 | 312 | h.update("b"); |
| 300 | 313 | h.update("c"); |
| ... | ... | @@ -303,13 +316,13 @@ test "blake2s256 streaming" { |
| 303 | 316 | |
| 304 | 317 | const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977"; |
| 305 | 318 | |
| 306 | h.reset(); | |
| 319 | h = Blake2s256.init(.{}); | |
| 307 | 320 | h.update("a" ** 32); |
| 308 | 321 | h.update("b" ** 32); |
| 309 | 322 | h.final(out[0..]); |
| 310 | 323 | htest.assertEqual(h3, out[0..]); |
| 311 | 324 | |
| 312 | h.reset(); | |
| 325 | h = Blake2s256.init(.{}); | |
| 313 | 326 | h.update("a" ** 32 ++ "b" ** 32); |
| 314 | 327 | h.final(out[0..]); |
| 315 | 328 | htest.assertEqual(h3, out[0..]); |
| ... | ... | @@ -321,16 +334,16 @@ test "blake2s256 keyed" { |
| 321 | 334 | const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6"; |
| 322 | 335 | const key = "secret_key"; |
| 323 | 336 | |
| 324 | Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); | |
| 337 | Blake2s256.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); | |
| 325 | 338 | htest.assertEqual(h1, out[0..]); |
| 326 | 339 | |
| 327 | var h = Blake2s256.init_keyed(key); | |
| 340 | var h = Blake2s256.init(.{ .key = key }); | |
| 328 | 341 | h.update("a" ** 64 ++ "b" ** 64); |
| 329 | 342 | h.final(out[0..]); |
| 330 | 343 | |
| 331 | 344 | htest.assertEqual(h1, out[0..]); |
| 332 | 345 | |
| 333 | h.reset(); | |
| 346 | h = Blake2s256.init(.{ .key = key }); | |
| 334 | 347 | h.update("a" ** 64); |
| 335 | 348 | h.update("b" ** 64); |
| 336 | 349 | h.final(out[0..]); |
| ... | ... | @@ -348,7 +361,7 @@ test "comptime blake2s256" { |
| 348 | 361 | |
| 349 | 362 | htest.assertEqualHash(Blake2s256, h1, block[0..]); |
| 350 | 363 | |
| 351 | var h = Blake2s256.init(); | |
| 364 | var h = Blake2s256.init(.{}); | |
| 352 | 365 | h.update(&block); |
| 353 | 366 | h.final(out[0..]); |
| 354 | 367 | |
| ... | ... | @@ -359,6 +372,7 @@ test "comptime blake2s256" { |
| 359 | 372 | ///////////////////// |
| 360 | 373 | // Blake2b |
| 361 | 374 | |
| 375 | pub const Blake2b256 = Blake2b(256); | |
| 362 | 376 | pub const Blake2b384 = Blake2b(384); |
| 363 | 377 | pub const Blake2b512 = Blake2b(512); |
| 364 | 378 | |
| ... | ... | @@ -367,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type { |
| 367 | 381 | const Self = @This(); |
| 368 | 382 | pub const block_length = 128; |
| 369 | 383 | pub const digest_length = out_len / 8; |
| 384 | pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null }; | |
| 370 | 385 | |
| 371 | 386 | const iv = [8]u64{ |
| 372 | 387 | 0x6a09e667f3bcc908, |
| ... | ... | @@ -400,42 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type { |
| 400 | 415 | buf: [128]u8, |
| 401 | 416 | buf_len: u8, |
| 402 | 417 | |
| 403 | key: []const u8, | |
| 404 | ||
| 405 | pub fn init() Self { | |
| 406 | return init_keyed(""); | |
| 407 | } | |
| 408 | ||
| 409 | pub fn init_keyed(key: []const u8) Self { | |
| 418 | pub fn init(options: Options) Self { | |
| 410 | 419 | debug.assert(8 <= out_len and out_len <= 512); |
| 411 | 420 | |
| 412 | var s: Self = undefined; | |
| 413 | s.key = key; | |
| 414 | s.reset(); | |
| 415 | return s; | |
| 416 | } | |
| 417 | ||
| 418 | pub fn reset(d: *Self) void { | |
| 421 | var d: Self = undefined; | |
| 419 | 422 | mem.copy(u64, d.h[0..], iv[0..]); |
| 420 | 423 | |
| 424 | const key_len = if (options.key) |key| key.len else 0; | |
| 421 | 425 | // default parameters |
| 422 | d.h[0] ^= 0x01010000 ^ (d.key.len << 8) ^ (out_len >> 3); | |
| 426 | d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_len >> 3); | |
| 423 | 427 | d.t = 0; |
| 424 | 428 | d.buf_len = 0; |
| 425 | 429 | |
| 426 | if (d.key.len > 0) { | |
| 427 | mem.set(u8, d.buf[d.key.len..], 0); | |
| 428 | d.update(d.key); | |
| 430 | if (options.salt) |salt| { | |
| 431 | d.h[4] ^= mem.readIntLittle(u64, salt[0..8]); | |
| 432 | d.h[5] ^= mem.readIntLittle(u64, salt[8..16]); | |
| 433 | } | |
| 434 | if (options.context) |context| { | |
| 435 | d.h[6] ^= mem.readIntLittle(u64, context[0..8]); | |
| 436 | d.h[7] ^= mem.readIntLittle(u64, context[8..16]); | |
| 437 | } | |
| 438 | if (key_len > 0) { | |
| 439 | mem.set(u8, d.buf[key_len..], 0); | |
| 440 | d.update(options.key.?); | |
| 429 | 441 | d.buf_len = 128; |
| 430 | 442 | } |
| 443 | return d; | |
| 431 | 444 | } |
| 432 | 445 | |
| 433 | pub fn hash(b: []const u8, out: []u8) void { | |
| 434 | Self.hash_keyed("", b, out); | |
| 435 | } | |
| 436 | ||
| 437 | pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { | |
| 438 | var d = Self.init_keyed(key); | |
| 446 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 447 | var d = Self.init(options); | |
| 439 | 448 | d.update(b); |
| 440 | 449 | d.final(out); |
| 441 | 450 | } |
| ... | ... | @@ -542,7 +551,7 @@ test "blake2b384 single" { |
| 542 | 551 | } |
| 543 | 552 | |
| 544 | 553 | test "blake2b384 streaming" { |
| 545 | var h = Blake2b384.init(); | |
| 554 | var h = Blake2b384.init(.{}); | |
| 546 | 555 | var out: [48]u8 = undefined; |
| 547 | 556 | |
| 548 | 557 | const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100"; |
| ... | ... | @@ -552,12 +561,12 @@ test "blake2b384 streaming" { |
| 552 | 561 | |
| 553 | 562 | const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4"; |
| 554 | 563 | |
| 555 | h.reset(); | |
| 564 | h = Blake2b384.init(.{}); | |
| 556 | 565 | h.update("abc"); |
| 557 | 566 | h.final(out[0..]); |
| 558 | 567 | htest.assertEqual(h2, out[0..]); |
| 559 | 568 | |
| 560 | h.reset(); | |
| 569 | h = Blake2b384.init(.{}); | |
| 561 | 570 | h.update("a"); |
| 562 | 571 | h.update("b"); |
| 563 | 572 | h.update("c"); |
| ... | ... | @@ -566,16 +575,36 @@ test "blake2b384 streaming" { |
| 566 | 575 | |
| 567 | 576 | const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c"; |
| 568 | 577 | |
| 569 | h.reset(); | |
| 578 | h = Blake2b384.init(.{}); | |
| 570 | 579 | h.update("a" ** 64 ++ "b" ** 64); |
| 571 | 580 | h.final(out[0..]); |
| 572 | 581 | htest.assertEqual(h3, out[0..]); |
| 573 | 582 | |
| 574 | h.reset(); | |
| 583 | h = Blake2b384.init(.{}); | |
| 584 | h.update("a" ** 64); | |
| 585 | h.update("b" ** 64); | |
| 586 | h.final(out[0..]); | |
| 587 | htest.assertEqual(h3, out[0..]); | |
| 588 | ||
| 589 | h = Blake2b384.init(.{}); | |
| 575 | 590 | h.update("a" ** 64); |
| 576 | 591 | h.update("b" ** 64); |
| 577 | 592 | h.final(out[0..]); |
| 578 | 593 | htest.assertEqual(h3, out[0..]); |
| 594 | ||
| 595 | const h4 = "934c48fcb197031c71f583d92f98703510805e72142e0b46f5752d1e971bc86c355d556035613ff7a4154b4de09dac5c"; | |
| 596 | ||
| 597 | h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); | |
| 598 | h.update("a" ** 64); | |
| 599 | h.update("b" ** 64); | |
| 600 | h.final(out[0..]); | |
| 601 | htest.assertEqual(h4, out[0..]); | |
| 602 | ||
| 603 | h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); | |
| 604 | h.update("a" ** 64); | |
| 605 | h.update("b" ** 64); | |
| 606 | h.final(out[0..]); | |
| 607 | htest.assertEqual(h4, out[0..]); | |
| 579 | 608 | } |
| 580 | 609 | |
| 581 | 610 | test "comptime blake2b384" { |
| ... | ... | @@ -588,7 +617,7 @@ test "comptime blake2b384" { |
| 588 | 617 | |
| 589 | 618 | htest.assertEqualHash(Blake2b384, h1, block[0..]); |
| 590 | 619 | |
| 591 | var h = Blake2b384.init(); | |
| 620 | var h = Blake2b384.init(.{}); | |
| 592 | 621 | h.update(&block); |
| 593 | 622 | h.final(out[0..]); |
| 594 | 623 | |
| ... | ... | @@ -611,7 +640,7 @@ test "blake2b512 single" { |
| 611 | 640 | } |
| 612 | 641 | |
| 613 | 642 | test "blake2b512 streaming" { |
| 614 | var h = Blake2b512.init(); | |
| 643 | var h = Blake2b512.init(.{}); | |
| 615 | 644 | var out: [64]u8 = undefined; |
| 616 | 645 | |
| 617 | 646 | const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"; |
| ... | ... | @@ -621,12 +650,12 @@ test "blake2b512 streaming" { |
| 621 | 650 | |
| 622 | 651 | const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; |
| 623 | 652 | |
| 624 | h.reset(); | |
| 653 | h = Blake2b512.init(.{}); | |
| 625 | 654 | h.update("abc"); |
| 626 | 655 | h.final(out[0..]); |
| 627 | 656 | htest.assertEqual(h2, out[0..]); |
| 628 | 657 | |
| 629 | h.reset(); | |
| 658 | h = Blake2b512.init(.{}); | |
| 630 | 659 | h.update("a"); |
| 631 | 660 | h.update("b"); |
| 632 | 661 | h.update("c"); |
| ... | ... | @@ -635,12 +664,12 @@ test "blake2b512 streaming" { |
| 635 | 664 | |
| 636 | 665 | const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; |
| 637 | 666 | |
| 638 | h.reset(); | |
| 667 | h = Blake2b512.init(.{}); | |
| 639 | 668 | h.update("a" ** 64 ++ "b" ** 64); |
| 640 | 669 | h.final(out[0..]); |
| 641 | 670 | htest.assertEqual(h3, out[0..]); |
| 642 | 671 | |
| 643 | h.reset(); | |
| 672 | h = Blake2b512.init(.{}); | |
| 644 | 673 | h.update("a" ** 64); |
| 645 | 674 | h.update("b" ** 64); |
| 646 | 675 | h.final(out[0..]); |
| ... | ... | @@ -653,16 +682,16 @@ test "blake2b512 keyed" { |
| 653 | 682 | const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d"; |
| 654 | 683 | const key = "secret_key"; |
| 655 | 684 | |
| 656 | Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); | |
| 685 | Blake2b512.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); | |
| 657 | 686 | htest.assertEqual(h1, out[0..]); |
| 658 | 687 | |
| 659 | var h = Blake2b512.init_keyed(key); | |
| 688 | var h = Blake2b512.init(.{ .key = key }); | |
| 660 | 689 | h.update("a" ** 64 ++ "b" ** 64); |
| 661 | 690 | h.final(out[0..]); |
| 662 | 691 | |
| 663 | 692 | htest.assertEqual(h1, out[0..]); |
| 664 | 693 | |
| 665 | h.reset(); | |
| 694 | h = Blake2b512.init(.{ .key = key }); | |
| 666 | 695 | h.update("a" ** 64); |
| 667 | 696 | h.update("b" ** 64); |
| 668 | 697 | h.final(out[0..]); |
| ... | ... | @@ -680,7 +709,7 @@ test "comptime blake2b512" { |
| 680 | 709 | |
| 681 | 710 | htest.assertEqualHash(Blake2b512, h1, block[0..]); |
| 682 | 711 | |
| 683 | var h = Blake2b512.init(); | |
| 712 | var h = Blake2b512.init(.{}); | |
| 684 | 713 | h.update(&block); |
| 685 | 714 | h.final(out[0..]); |
| 686 | 715 |
lib/std/crypto/blake3.zig+29-23| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Translated from BLAKE3 reference implementation. |
| 2 | 7 | // Source: https://github.com/BLAKE3-team/BLAKE3 |
| 3 | 8 | |
| ... | ... | @@ -274,6 +279,9 @@ fn parent_cv( |
| 274 | 279 | |
| 275 | 280 | /// An incremental hasher that can accept any number of writes. |
| 276 | 281 | pub const Blake3 = struct { |
| 282 | pub const Options = struct { key: ?[KEY_LEN]u8 = null }; | |
| 283 | pub const KdfOptions = struct {}; | |
| 284 | ||
| 277 | 285 | chunk_state: ChunkState, |
| 278 | 286 | key: [8]u32, |
| 279 | 287 | cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values: |
| ... | ... | @@ -291,21 +299,20 @@ pub const Blake3 = struct { |
| 291 | 299 | }; |
| 292 | 300 | } |
| 293 | 301 | |
| 294 | /// Construct a new `Blake3` for the regular hash function. | |
| 295 | pub fn init() Blake3 { | |
| 296 | return Blake3.init_internal(IV, 0); | |
| 297 | } | |
| 298 | ||
| 299 | /// Construct a new `Blake3` for the keyed hash function. | |
| 300 | pub fn init_keyed(key: [KEY_LEN]u8) Blake3 { | |
| 301 | var key_words: [8]u32 = undefined; | |
| 302 | words_from_little_endian_bytes(key_words[0..], key[0..]); | |
| 303 | return Blake3.init_internal(key_words, KEYED_HASH); | |
| 302 | /// Construct a new `Blake3` for the hash function, with an optional key | |
| 303 | pub fn init(options: Options) Blake3 { | |
| 304 | if (options.key) |key| { | |
| 305 | var key_words: [8]u32 = undefined; | |
| 306 | words_from_little_endian_bytes(key_words[0..], key[0..]); | |
| 307 | return Blake3.init_internal(key_words, KEYED_HASH); | |
| 308 | } else { | |
| 309 | return Blake3.init_internal(IV, 0); | |
| 310 | } | |
| 304 | 311 | } |
| 305 | 312 | |
| 306 | 313 | /// Construct a new `Blake3` for the key derivation function. The context |
| 307 | 314 | /// string should be hardcoded, globally unique, and application-specific. |
| 308 | pub fn init_derive_key(context: []const u8) Blake3 { | |
| 315 | pub fn initKdf(context: []const u8, options: KdfOptions) Blake3 { | |
| 309 | 316 | var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT); |
| 310 | 317 | context_hasher.update(context); |
| 311 | 318 | var context_key: [KEY_LEN]u8 = undefined; |
| ... | ... | @@ -315,18 +322,12 @@ pub const Blake3 = struct { |
| 315 | 322 | return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL); |
| 316 | 323 | } |
| 317 | 324 | |
| 318 | pub fn hash(in: []const u8, out: []u8) void { | |
| 319 | var hasher = Blake3.init(); | |
| 325 | pub fn hash(in: []const u8, out: []u8, options: Options) void { | |
| 326 | var hasher = Blake3.init(options); | |
| 320 | 327 | hasher.update(in); |
| 321 | 328 | hasher.final(out); |
| 322 | 329 | } |
| 323 | 330 | |
| 324 | /// Reset the `Blake3` to its initial state. | |
| 325 | pub fn reset(self: *Blake3) void { | |
| 326 | self.chunk_state = ChunkState.init(self.key, 0, self.flags); | |
| 327 | self.cv_stack_len = 0; | |
| 328 | } | |
| 329 | ||
| 330 | 331 | fn push_cv(self: *Blake3, cv: [8]u32) void { |
| 331 | 332 | self.cv_stack[self.cv_stack_len] = cv; |
| 332 | 333 | self.cv_stack_len += 1; |
| ... | ... | @@ -561,6 +562,9 @@ const reference_test = ReferenceTest{ |
| 561 | 562 | }; |
| 562 | 563 | |
| 563 | 564 | fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { |
| 565 | // Save initial state | |
| 566 | const initial_state = hasher.*; | |
| 567 | ||
| 564 | 568 | // Setup input pattern |
| 565 | 569 | var input_pattern: [251]u8 = undefined; |
| 566 | 570 | for (input_pattern) |*e, i| e.* = @truncate(u8, i); |
| ... | ... | @@ -576,18 +580,20 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { |
| 576 | 580 | // Read final hash value |
| 577 | 581 | var actual_bytes: [expected_hex.len / 2]u8 = undefined; |
| 578 | 582 | hasher.final(actual_bytes[0..]); |
| 579 | hasher.reset(); | |
| 580 | 583 | |
| 581 | 584 | // Compare to expected value |
| 582 | 585 | var expected_bytes: [expected_hex.len / 2]u8 = undefined; |
| 583 | 586 | fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable; |
| 584 | 587 | testing.expectEqual(actual_bytes, expected_bytes); |
| 588 | ||
| 589 | // Restore initial state | |
| 590 | hasher.* = initial_state; | |
| 585 | 591 | } |
| 586 | 592 | |
| 587 | 593 | test "BLAKE3 reference test cases" { |
| 588 | var hash = &Blake3.init(); | |
| 589 | var keyed_hash = &Blake3.init_keyed(reference_test.key.*); | |
| 590 | var derive_key = &Blake3.init_derive_key(reference_test.context_string); | |
| 594 | var hash = &Blake3.init(.{}); | |
| 595 | var keyed_hash = &Blake3.init(.{ .key = reference_test.key.* }); | |
| 596 | var derive_key = &Blake3.initKdf(reference_test.context_string, .{}); | |
| 591 | 597 | |
| 592 | 598 | for (reference_test.cases) |t| { |
| 593 | 599 | test_blake3(hash, t.input_len, t.hash.*); |
lib/std/crypto/chacha20.zig+79-68| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Based on public domain Supercop by Daniel J. Bernstein |
| 2 | 7 | |
| 3 | 8 | const std = @import("../std.zig"); |
| ... | ... | @@ -7,7 +12,7 @@ const assert = std.debug.assert; |
| 7 | 12 | const testing = std.testing; |
| 8 | 13 | const builtin = @import("builtin"); |
| 9 | 14 | const maxInt = std.math.maxInt; |
| 10 | const Poly1305 = std.crypto.Poly1305; | |
| 15 | const Poly1305 = std.crypto.onetimeauth.Poly1305; | |
| 11 | 16 | |
| 12 | 17 | const QuarterRound = struct { |
| 13 | 18 | a: usize, |
| ... | ... | @@ -132,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 { |
| 132 | 137 | /// |
| 133 | 138 | /// ChaCha20 is self-reversing. To decrypt just run the cipher with the same |
| 134 | 139 | /// counter, nonce, and key. |
| 135 | pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { | |
| 136 | assert(in.len >= out.len); | |
| 137 | assert((in.len >> 6) + counter <= maxInt(u32)); | |
| 138 | ||
| 139 | var c: [4]u32 = undefined; | |
| 140 | c[0] = counter; | |
| 141 | c[1] = mem.readIntLittle(u32, nonce[0..4]); | |
| 142 | c[2] = mem.readIntLittle(u32, nonce[4..8]); | |
| 143 | c[3] = mem.readIntLittle(u32, nonce[8..12]); | |
| 144 | chaCha20_internal(out, in, keyToWords(key), c); | |
| 145 | } | |
| 140 | pub const ChaCha20IETF = struct { | |
| 141 | pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { | |
| 142 | assert(in.len >= out.len); | |
| 143 | assert((in.len >> 6) + counter <= maxInt(u32)); | |
| 144 | ||
| 145 | var c: [4]u32 = undefined; | |
| 146 | c[0] = counter; | |
| 147 | c[1] = mem.readIntLittle(u32, nonce[0..4]); | |
| 148 | c[2] = mem.readIntLittle(u32, nonce[4..8]); | |
| 149 | c[3] = mem.readIntLittle(u32, nonce[8..12]); | |
| 150 | chaCha20_internal(out, in, keyToWords(key), c); | |
| 151 | } | |
| 152 | }; | |
| 146 | 153 | |
| 147 | 154 | /// This is the original ChaCha20 before RFC 7539, which recommends using the |
| 148 | 155 | /// orgininal version on applications such as disk or file encryption that might |
| 149 | 156 | /// exceed the 256 GiB limit of the 96-bit nonce version. |
| 150 | pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { | |
| 151 | assert(in.len >= out.len); | |
| 152 | assert(counter +% (in.len >> 6) >= counter); | |
| 153 | ||
| 154 | var cursor: usize = 0; | |
| 155 | const k = keyToWords(key); | |
| 156 | var c: [4]u32 = undefined; | |
| 157 | c[0] = @truncate(u32, counter); | |
| 158 | c[1] = @truncate(u32, counter >> 32); | |
| 159 | c[2] = mem.readIntLittle(u32, nonce[0..4]); | |
| 160 | c[3] = mem.readIntLittle(u32, nonce[4..8]); | |
| 161 | ||
| 162 | const block_size = (1 << 6); | |
| 163 | // The full block size is greater than the address space on a 32bit machine | |
| 164 | const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); | |
| 165 | ||
| 166 | // first partial big block | |
| 167 | if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { | |
| 168 | chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); | |
| 169 | cursor = big_block - cursor; | |
| 170 | c[1] += 1; | |
| 171 | if (comptime @sizeOf(usize) > 4) { | |
| 172 | // A big block is giant: 256 GiB, but we can avoid this limitation | |
| 173 | var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); | |
| 174 | var i: u32 = 0; | |
| 175 | while (remaining_blocks > 0) : (remaining_blocks -= 1) { | |
| 176 | chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); | |
| 177 | c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. | |
| 178 | cursor += big_block; | |
| 157 | pub const ChaCha20With64BitNonce = struct { | |
| 158 | pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { | |
| 159 | assert(in.len >= out.len); | |
| 160 | assert(counter +% (in.len >> 6) >= counter); | |
| 161 | ||
| 162 | var cursor: usize = 0; | |
| 163 | const k = keyToWords(key); | |
| 164 | var c: [4]u32 = undefined; | |
| 165 | c[0] = @truncate(u32, counter); | |
| 166 | c[1] = @truncate(u32, counter >> 32); | |
| 167 | c[2] = mem.readIntLittle(u32, nonce[0..4]); | |
| 168 | c[3] = mem.readIntLittle(u32, nonce[4..8]); | |
| 169 | ||
| 170 | const block_size = (1 << 6); | |
| 171 | // The full block size is greater than the address space on a 32bit machine | |
| 172 | const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); | |
| 173 | ||
| 174 | // first partial big block | |
| 175 | if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { | |
| 176 | chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); | |
| 177 | cursor = big_block - cursor; | |
| 178 | c[1] += 1; | |
| 179 | if (comptime @sizeOf(usize) > 4) { | |
| 180 | // A big block is giant: 256 GiB, but we can avoid this limitation | |
| 181 | var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); | |
| 182 | var i: u32 = 0; | |
| 183 | while (remaining_blocks > 0) : (remaining_blocks -= 1) { | |
| 184 | chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); | |
| 185 | c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. | |
| 186 | cursor += big_block; | |
| 187 | } | |
| 179 | 188 | } |
| 180 | 189 | } |
| 181 | } | |
| 182 | 190 | |
| 183 | chaCha20_internal(out[cursor..], in[cursor..], k, c); | |
| 184 | } | |
| 191 | chaCha20_internal(out[cursor..], in[cursor..], k, c); | |
| 192 | } | |
| 193 | }; | |
| 185 | 194 | |
| 186 | 195 | // https://tools.ietf.org/html/rfc7539#section-2.4.2 |
| 187 | 196 | test "crypto.chacha20 test vector sunscreen" { |
| ... | ... | @@ -216,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" { |
| 216 | 225 | 0, 0, 0, 0, |
| 217 | 226 | }; |
| 218 | 227 | |
| 219 | chaCha20IETF(result[0..], input[0..], 1, key, nonce); | |
| 228 | ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce); | |
| 220 | 229 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 221 | 230 | |
| 222 | 231 | // Chacha20 is self-reversing. |
| 223 | 232 | var plaintext: [114]u8 = undefined; |
| 224 | chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); | |
| 233 | ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce); | |
| 225 | 234 | testing.expect(mem.order(u8, input, &plaintext) == .eq); |
| 226 | 235 | } |
| 227 | 236 | |
| ... | ... | @@ -256,7 +265,7 @@ test "crypto.chacha20 test vector 1" { |
| 256 | 265 | }; |
| 257 | 266 | const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 258 | 267 | |
| 259 | chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); | |
| 268 | ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); | |
| 260 | 269 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 261 | 270 | } |
| 262 | 271 | |
| ... | ... | @@ -290,7 +299,7 @@ test "crypto.chacha20 test vector 2" { |
| 290 | 299 | }; |
| 291 | 300 | const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 292 | 301 | |
| 293 | chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); | |
| 302 | ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); | |
| 294 | 303 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 295 | 304 | } |
| 296 | 305 | |
| ... | ... | @@ -324,7 +333,7 @@ test "crypto.chacha20 test vector 3" { |
| 324 | 333 | }; |
| 325 | 334 | const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 }; |
| 326 | 335 | |
| 327 | chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); | |
| 336 | ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); | |
| 328 | 337 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 329 | 338 | } |
| 330 | 339 | |
| ... | ... | @@ -358,7 +367,7 @@ test "crypto.chacha20 test vector 4" { |
| 358 | 367 | }; |
| 359 | 368 | const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 }; |
| 360 | 369 | |
| 361 | chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); | |
| 370 | ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); | |
| 362 | 371 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 363 | 372 | } |
| 364 | 373 | |
| ... | ... | @@ -430,21 +439,21 @@ test "crypto.chacha20 test vector 5" { |
| 430 | 439 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 431 | 440 | }; |
| 432 | 441 | |
| 433 | chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); | |
| 442 | ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); | |
| 434 | 443 | testing.expectEqualSlices(u8, &expected_result, &result); |
| 435 | 444 | } |
| 436 | 445 | |
| 437 | 446 | pub const chacha20poly1305_tag_size = 16; |
| 438 | 447 | |
| 439 | pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { | |
| 448 | fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { | |
| 440 | 449 | assert(ciphertext.len >= plaintext.len); |
| 441 | 450 | |
| 442 | 451 | // derive poly1305 key |
| 443 | 452 | var polyKey = [_]u8{0} ** 32; |
| 444 | chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); | |
| 453 | ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); | |
| 445 | 454 | |
| 446 | 455 | // encrypt plaintext |
| 447 | chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); | |
| 456 | ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); | |
| 448 | 457 | |
| 449 | 458 | // construct mac |
| 450 | 459 | var mac = Poly1305.init(polyKey[0..]); |
| ... | ... | @@ -467,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta |
| 467 | 476 | mac.final(tag); |
| 468 | 477 | } |
| 469 | 478 | |
| 470 | pub fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { | |
| 479 | fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { | |
| 471 | 480 | return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce); |
| 472 | 481 | } |
| 473 | 482 | |
| 474 | 483 | /// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached. |
| 475 | pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { | |
| 484 | fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { | |
| 476 | 485 | // split ciphertext and tag |
| 477 | 486 | assert(dst.len >= ciphertext.len); |
| 478 | 487 | |
| 479 | 488 | // derive poly1305 key |
| 480 | 489 | var polyKey = [_]u8{0} ** 32; |
| 481 | chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); | |
| 490 | ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); | |
| 482 | 491 | |
| 483 | 492 | // construct mac |
| 484 | 493 | var mac = Poly1305.init(polyKey[0..]); |
| ... | ... | @@ -514,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con |
| 514 | 523 | } |
| 515 | 524 | |
| 516 | 525 | // decrypt ciphertext |
| 517 | chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce); | |
| 526 | ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce); | |
| 518 | 527 | } |
| 519 | 528 | |
| 520 | 529 | /// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal. |
| 521 | pub fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { | |
| 530 | fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { | |
| 522 | 531 | if (ciphertextAndTag.len < chacha20poly1305_tag_size) { |
| 523 | 532 | return error.InvalidMessage; |
| 524 | 533 | } |
| ... | ... | @@ -557,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } { |
| 557 | 566 | }; |
| 558 | 567 | } |
| 559 | 568 | |
| 560 | pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { | |
| 561 | const extended = extend(key, nonce); | |
| 562 | chaCha20IETF(out, in, counter, extended.key, extended.nonce); | |
| 563 | } | |
| 569 | pub const XChaCha20IETF = struct { | |
| 570 | pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { | |
| 571 | const extended = extend(key, nonce); | |
| 572 | ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce); | |
| 573 | } | |
| 574 | }; | |
| 564 | 575 | |
| 565 | 576 | pub const xchacha20poly1305_tag_size = 16; |
| 566 | 577 | |
| 567 | pub fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { | |
| 578 | fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { | |
| 568 | 579 | const extended = extend(key, nonce); |
| 569 | 580 | return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce); |
| 570 | 581 | } |
| 571 | 582 | |
| 572 | pub fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { | |
| 583 | fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { | |
| 573 | 584 | const extended = extend(key, nonce); |
| 574 | 585 | return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce); |
| 575 | 586 | } |
| 576 | 587 | |
| 577 | 588 | /// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached. |
| 578 | pub fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { | |
| 589 | fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { | |
| 579 | 590 | const extended = extend(key, nonce); |
| 580 | 591 | return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce); |
| 581 | 592 | } |
| 582 | 593 | |
| 583 | 594 | /// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal. |
| 584 | pub fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { | |
| 595 | fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { | |
| 585 | 596 | const extended = extend(key, nonce); |
| 586 | 597 | return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce); |
| 587 | 598 | } |
| ... | ... | @@ -709,7 +720,7 @@ test "crypto.xchacha20" { |
| 709 | 720 | const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."; |
| 710 | 721 | { |
| 711 | 722 | var ciphertext: [input.len]u8 = undefined; |
| 712 | xChaCha20IETF(ciphertext[0..], input[0..], 0, key, nonce); | |
| 723 | XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce); | |
| 713 | 724 | var buf: [2 * ciphertext.len]u8 = undefined; |
| 714 | 725 | testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D"); |
| 715 | 726 | } |
lib/std/crypto/gimli.zig+13-7| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Gimli is a 384-bit permutation designed to achieve high security with high |
| 2 | 7 | // performance across a broad range of platforms, including 64-bit Intel/AMD |
| 3 | 8 | // server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM |
| ... | ... | @@ -104,13 +109,14 @@ pub const Hash = struct { |
| 104 | 109 | state: State, |
| 105 | 110 | buf_off: usize, |
| 106 | 111 | |
| 112 | pub const block_length = State.RATE; | |
| 113 | pub const Options = struct {}; | |
| 114 | ||
| 107 | 115 | const Self = @This(); |
| 108 | 116 | |
| 109 | pub fn init() Self { | |
| 117 | pub fn init(options: Options) Self { | |
| 110 | 118 | return Self{ |
| 111 | .state = State{ | |
| 112 | .data = [_]u32{0} ** (State.BLOCKBYTES / 4), | |
| 113 | }, | |
| 119 | .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) }, | |
| 114 | 120 | .buf_off = 0, |
| 115 | 121 | }; |
| 116 | 122 | } |
| ... | ... | @@ -155,8 +161,8 @@ pub const Hash = struct { |
| 155 | 161 | } |
| 156 | 162 | }; |
| 157 | 163 | |
| 158 | pub fn hash(out: []u8, in: []const u8) void { | |
| 159 | var st = Hash.init(); | |
| 164 | pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void { | |
| 165 | var st = Hash.init(options); | |
| 160 | 166 | st.update(in); |
| 161 | 167 | st.final(out); |
| 162 | 168 | } |
| ... | ... | @@ -169,7 +175,7 @@ test "hash" { |
| 169 | 175 | var msg: [58 / 2]u8 = undefined; |
| 170 | 176 | try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C"); |
| 171 | 177 | var md: [32]u8 = undefined; |
| 172 | hash(&md, &msg); | |
| 178 | hash(&md, &msg, .{}); | |
| 173 | 179 | htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md); |
| 174 | 180 | } |
| 175 | 181 |
lib/std/crypto/hmac.zig+27-13| ... | ... | @@ -1,12 +1,26 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const crypto = std.crypto; |
| 3 | 8 | const debug = std.debug; |
| 4 | 9 | const mem = std.mem; |
| 5 | 10 | |
| 6 | pub const HmacMd5 = Hmac(crypto.Md5); | |
| 7 | pub const HmacSha1 = Hmac(crypto.Sha1); | |
| 8 | pub const HmacSha256 = Hmac(crypto.Sha256); | |
| 9 | pub const HmacBlake2s256 = Hmac(crypto.Blake2s256); | |
| 11 | pub const HmacMd5 = Hmac(crypto.hash.Md5); | |
| 12 | pub const HmacSha1 = Hmac(crypto.hash.Sha1); | |
| 13 | ||
| 14 | pub const sha2 = struct { | |
| 15 | pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224); | |
| 16 | pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256); | |
| 17 | pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384); | |
| 18 | pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512); | |
| 19 | }; | |
| 20 | ||
| 21 | pub const blake2 = struct { | |
| 22 | pub const HmacBlake2s256 = Hmac(crypto.hash.blake2.Blake2s256); | |
| 23 | }; | |
| 10 | 24 | |
| 11 | 25 | pub fn Hmac(comptime Hash: type) type { |
| 12 | 26 | return struct { |
| ... | ... | @@ -31,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type { |
| 31 | 45 | |
| 32 | 46 | // Normalize key length to block size of hash |
| 33 | 47 | if (key.len > Hash.block_length) { |
| 34 | Hash.hash(key, ctx.scratch[0..mac_length]); | |
| 48 | Hash.hash(key, ctx.scratch[0..mac_length], .{}); | |
| 35 | 49 | mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0); |
| 36 | 50 | } else if (key.len < Hash.block_length) { |
| 37 | 51 | mem.copy(u8, ctx.scratch[0..key.len], key); |
| ... | ... | @@ -48,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type { |
| 48 | 62 | b.* = ctx.scratch[i] ^ 0x36; |
| 49 | 63 | } |
| 50 | 64 | |
| 51 | ctx.hash = Hash.init(); | |
| 65 | ctx.hash = Hash.init(.{}); | |
| 52 | 66 | ctx.hash.update(ctx.i_key_pad[0..]); |
| 53 | 67 | return ctx; |
| 54 | 68 | } |
| ... | ... | @@ -61,10 +75,10 @@ pub fn Hmac(comptime Hash: type) type { |
| 61 | 75 | debug.assert(Hash.block_length >= out.len and out.len >= mac_length); |
| 62 | 76 | |
| 63 | 77 | ctx.hash.final(ctx.scratch[0..mac_length]); |
| 64 | ctx.hash.reset(); | |
| 65 | ctx.hash.update(ctx.o_key_pad[0..]); | |
| 66 | ctx.hash.update(ctx.scratch[0..mac_length]); | |
| 67 | ctx.hash.final(out[0..mac_length]); | |
| 78 | var ohash = Hash.init(.{}); | |
| 79 | ohash.update(ctx.o_key_pad[0..]); | |
| 80 | ohash.update(ctx.scratch[0..mac_length]); | |
| 81 | ohash.final(out[0..mac_length]); | |
| 68 | 82 | } |
| 69 | 83 | }; |
| 70 | 84 | } |
| ... | ... | @@ -90,10 +104,10 @@ test "hmac sha1" { |
| 90 | 104 | } |
| 91 | 105 | |
| 92 | 106 | test "hmac sha256" { |
| 93 | var out: [HmacSha256.mac_length]u8 = undefined; | |
| 94 | HmacSha256.create(out[0..], "", ""); | |
| 107 | var out: [sha2.HmacSha256.mac_length]u8 = undefined; | |
| 108 | sha2.HmacSha256.create(out[0..], "", ""); | |
| 95 | 109 | htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]); |
| 96 | 110 | |
| 97 | HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); | |
| 111 | sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); | |
| 98 | 112 | htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]); |
| 99 | 113 | } |
lib/std/crypto/md5.zig+27-19| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const mem = @import("../mem.zig"); |
| 2 | 7 | const math = @import("../math.zig"); |
| 3 | 8 | const endian = @import("../endian.zig"); |
| ... | ... | @@ -27,10 +32,14 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar |
| 27 | 32 | }; |
| 28 | 33 | } |
| 29 | 34 | |
| 35 | /// The MD5 function is now considered cryptographically broken. | |
| 36 | /// Namely, it is trivial to find multiple inputs producing the same hash. | |
| 37 | /// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. | |
| 30 | 38 | pub const Md5 = struct { |
| 31 | 39 | const Self = @This(); |
| 32 | 40 | pub const block_length = 64; |
| 33 | 41 | pub const digest_length = 16; |
| 42 | pub const Options = struct {}; | |
| 34 | 43 | |
| 35 | 44 | s: [4]u32, |
| 36 | 45 | // Streaming Cache |
| ... | ... | @@ -38,23 +47,22 @@ pub const Md5 = struct { |
| 38 | 47 | buf_len: u8, |
| 39 | 48 | total_len: u64, |
| 40 | 49 | |
| 41 | pub fn init() Self { | |
| 42 | var d: Self = undefined; | |
| 43 | d.reset(); | |
| 44 | return d; | |
| 45 | } | |
| 46 | ||
| 47 | pub fn reset(d: *Self) void { | |
| 48 | d.s[0] = 0x67452301; | |
| 49 | d.s[1] = 0xEFCDAB89; | |
| 50 | d.s[2] = 0x98BADCFE; | |
| 51 | d.s[3] = 0x10325476; | |
| 52 | d.buf_len = 0; | |
| 53 | d.total_len = 0; | |
| 50 | pub fn init(options: Options) Self { | |
| 51 | return Self{ | |
| 52 | .s = [_]u32{ | |
| 53 | 0x67452301, | |
| 54 | 0xEFCDAB89, | |
| 55 | 0x98BADCFE, | |
| 56 | 0x10325476, | |
| 57 | }, | |
| 58 | .buf = undefined, | |
| 59 | .buf_len = 0, | |
| 60 | .total_len = 0, | |
| 61 | }; | |
| 54 | 62 | } |
| 55 | 63 | |
| 56 | pub fn hash(b: []const u8, out: []u8) void { | |
| 57 | var d = Md5.init(); | |
| 64 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 65 | var d = Md5.init(options); | |
| 58 | 66 | d.update(b); |
| 59 | 67 | d.final(out); |
| 60 | 68 | } |
| ... | ... | @@ -250,18 +258,18 @@ test "md5 single" { |
| 250 | 258 | } |
| 251 | 259 | |
| 252 | 260 | test "md5 streaming" { |
| 253 | var h = Md5.init(); | |
| 261 | var h = Md5.init(.{}); | |
| 254 | 262 | var out: [16]u8 = undefined; |
| 255 | 263 | |
| 256 | 264 | h.final(out[0..]); |
| 257 | 265 | htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]); |
| 258 | 266 | |
| 259 | h.reset(); | |
| 267 | h = Md5.init(.{}); | |
| 260 | 268 | h.update("abc"); |
| 261 | 269 | h.final(out[0..]); |
| 262 | 270 | htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); |
| 263 | 271 | |
| 264 | h.reset(); | |
| 272 | h = Md5.init(.{}); | |
| 265 | 273 | h.update("a"); |
| 266 | 274 | h.update("b"); |
| 267 | 275 | h.update("c"); |
| ... | ... | @@ -274,7 +282,7 @@ test "md5 aligned final" { |
| 274 | 282 | var block = [_]u8{0} ** Md5.block_length; |
| 275 | 283 | var out: [Md5.digest_length]u8 = undefined; |
| 276 | 284 | |
| 277 | var h = Md5.init(); | |
| 285 | var h = Md5.init(.{}); | |
| 278 | 286 | h.update(&block); |
| 279 | 287 | h.final(out[0..]); |
| 280 | 288 | } |
lib/std/crypto/poly1305.zig+169-191| ... | ... | @@ -1,221 +1,199 @@ |
| 1 | // Translated from monocypher which is licensed under CC-0/BSD-3. | |
| 2 | // | |
| 3 | // https://monocypher.org/ | |
| 4 | ||
| 5 | const std = @import("../std.zig"); | |
| 6 | const builtin = std.builtin; | |
| 7 | ||
| 8 | const Endian = builtin.Endian; | |
| 9 | const readIntLittle = std.mem.readIntLittle; | |
| 10 | const writeIntLittle = std.mem.writeIntLittle; | |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | const std = @import("std"); | |
| 7 | const mem = std.mem; | |
| 11 | 8 | |
| 12 | 9 | pub const Poly1305 = struct { |
| 13 | const Self = @This(); | |
| 14 | ||
| 10 | pub const block_size: usize = 16; | |
| 15 | 11 | pub const mac_length = 16; |
| 16 | 12 | pub const minimum_key_length = 32; |
| 17 | 13 | |
| 18 | 14 | // constant multiplier (from the secret key) |
| 19 | r: [4]u32, | |
| 15 | r: [3]u64, | |
| 20 | 16 | // accumulated hash |
| 21 | h: [5]u32, | |
| 22 | // chunk of the message | |
| 23 | c: [5]u32, | |
| 17 | h: [3]u64 = [_]u64{ 0, 0, 0 }, | |
| 24 | 18 | // random number added at the end (from the secret key) |
| 25 | pad: [4]u32, | |
| 26 | // How many bytes are there in the chunk. | |
| 27 | c_idx: usize, | |
| 28 | ||
| 29 | fn secureZero(self: *Self) void { | |
| 30 | std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]); | |
| 31 | } | |
| 19 | pad: [2]u64, | |
| 20 | // how many bytes are waiting to be processed in a partial block | |
| 21 | leftover: usize = 0, | |
| 22 | // partial block buffer | |
| 23 | buf: [block_size]u8 align(16) = undefined, | |
| 32 | 24 | |
| 33 | pub fn create(out: []u8, msg: []const u8, key: []const u8) void { | |
| 34 | std.debug.assert(out.len >= mac_length); | |
| 25 | pub fn init(key: []const u8) Poly1305 { | |
| 35 | 26 | std.debug.assert(key.len >= minimum_key_length); |
| 27 | const t0 = mem.readIntLittle(u64, key[0..8]); | |
| 28 | const t1 = mem.readIntLittle(u64, key[8..16]); | |
| 29 | return Poly1305{ | |
| 30 | .r = [_]u64{ | |
| 31 | t0 & 0xffc0fffffff, | |
| 32 | ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff, | |
| 33 | ((t1 >> 24)) & 0x00ffffffc0f, | |
| 34 | }, | |
| 35 | .pad = [_]u64{ | |
| 36 | mem.readIntLittle(u64, key[16..24]), | |
| 37 | mem.readIntLittle(u64, key[24..32]), | |
| 38 | }, | |
| 39 | }; | |
| 40 | } | |
| 36 | 41 | |
| 37 | var ctx = Poly1305.init(key); | |
| 38 | ctx.update(msg); | |
| 39 | ctx.final(out); | |
| 42 | fn blocks(st: *Poly1305, m: []const u8, last: comptime bool) void { | |
| 43 | const hibit: u64 = if (last) 0 else 1 << 40; | |
| 44 | const r0 = st.r[0]; | |
| 45 | const r1 = st.r[1]; | |
| 46 | const r2 = st.r[2]; | |
| 47 | var h0 = st.h[0]; | |
| 48 | var h1 = st.h[1]; | |
| 49 | var h2 = st.h[2]; | |
| 50 | const s1 = r1 * (5 << 2); | |
| 51 | const s2 = r2 * (5 << 2); | |
| 52 | var i: usize = 0; | |
| 53 | while (i + block_size <= m.len) : (i += block_size) { | |
| 54 | // h += m[i] | |
| 55 | const t0 = mem.readIntLittle(u64, m[i..][0..8]); | |
| 56 | const t1 = mem.readIntLittle(u64, m[i + 8 ..][0..8]); | |
| 57 | h0 += @truncate(u44, t0); | |
| 58 | h1 += @truncate(u44, (t0 >> 44) | (t1 << 20)); | |
| 59 | h2 += @truncate(u42, t1 >> 24) | hibit; | |
| 60 | ||
| 61 | // h *= r | |
| 62 | const d0 = @as(u128, h0) * r0 + @as(u128, h1) * s2 + @as(u128, h2) * s1; | |
| 63 | var d1 = @as(u128, h0) * r1 + @as(u128, h1) * r0 + @as(u128, h2) * s2; | |
| 64 | var d2 = @as(u128, h0) * r2 + @as(u128, h1) * r1 + @as(u128, h2) * r0; | |
| 65 | ||
| 66 | // partial reduction | |
| 67 | var carry = @intCast(u64, d0 >> 44); | |
| 68 | h0 = @truncate(u44, d0); | |
| 69 | d1 += carry; | |
| 70 | carry = @intCast(u64, d1 >> 44); | |
| 71 | h1 = @truncate(u44, d1); | |
| 72 | d2 += carry; | |
| 73 | carry = @intCast(u64, d2 >> 42); | |
| 74 | h2 = @truncate(u42, d2); | |
| 75 | h0 += @truncate(u64, carry) * 5; | |
| 76 | carry = h0 >> 44; | |
| 77 | h0 = @truncate(u44, h0); | |
| 78 | h1 += carry; | |
| 79 | } | |
| 80 | st.h = [_]u64{ h0, h1, h2 }; | |
| 40 | 81 | } |
| 41 | 82 | |
| 42 | // Initialize the MAC context. | |
| 43 | // - key.len is sufficient size. | |
| 44 | pub fn init(key: []const u8) Self { | |
| 45 | var ctx: Poly1305 = undefined; | |
| 83 | pub fn update(st: *Poly1305, m: []const u8) void { | |
| 84 | var mb = m; | |
| 46 | 85 | |
| 47 | // Initial hash is zero | |
| 48 | { | |
| 49 | var i: usize = 0; | |
| 50 | while (i < 5) : (i += 1) { | |
| 51 | ctx.h[i] = 0; | |
| 86 | // handle leftover | |
| 87 | if (st.leftover > 0) { | |
| 88 | const want = std.math.min(block_size - st.leftover, mb.len); | |
| 89 | const mc = mb[0..want]; | |
| 90 | for (mc) |x, i| { | |
| 91 | st.buf[st.leftover + i] = x; | |
| 52 | 92 | } |
| 53 | } | |
| 54 | // add 2^130 to every input block | |
| 55 | ctx.c[4] = 1; | |
| 56 | polyClearC(&ctx); | |
| 57 | ||
| 58 | // load r and pad (r has some of its bits cleared) | |
| 59 | { | |
| 60 | var i: usize = 0; | |
| 61 | while (i < 1) : (i += 1) { | |
| 62 | ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff; | |
| 93 | mb = mb[want..]; | |
| 94 | st.leftover += want; | |
| 95 | if (st.leftover > block_size) { | |
| 96 | return; | |
| 63 | 97 | } |
| 98 | st.blocks(&st.buf, false); | |
| 99 | st.leftover = 0; | |
| 64 | 100 | } |
| 65 | { | |
| 66 | var i: usize = 1; | |
| 67 | while (i < 4) : (i += 1) { | |
| 68 | ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc; | |
| 69 | } | |
| 70 | } | |
| 71 | { | |
| 72 | var i: usize = 0; | |
| 73 | while (i < 4) : (i += 1) { | |
| 74 | ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]); | |
| 75 | } | |
| 76 | } | |
| 77 | ||
| 78 | return ctx; | |
| 79 | } | |
| 80 | ||
| 81 | // h = (h + c) * r | |
| 82 | // preconditions: | |
| 83 | // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff | |
| 84 | // ctx->c <= 1_ffffffff_ffffffff_ffffffff_ffffffff | |
| 85 | // ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff | |
| 86 | // Postcondition: | |
| 87 | // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff | |
| 88 | fn polyBlock(ctx: *Self) void { | |
| 89 | // s = h + c, without carry propagation | |
| 90 | const s0 = @as(u64, ctx.h[0]) + ctx.c[0]; // s0 <= 1_fffffffe | |
| 91 | const s1 = @as(u64, ctx.h[1]) + ctx.c[1]; // s1 <= 1_fffffffe | |
| 92 | const s2 = @as(u64, ctx.h[2]) + ctx.c[2]; // s2 <= 1_fffffffe | |
| 93 | const s3 = @as(u64, ctx.h[3]) + ctx.c[3]; // s3 <= 1_fffffffe | |
| 94 | const s4 = @as(u64, ctx.h[4]) + ctx.c[4]; // s4 <= 5 | |
| 95 | ||
| 96 | // Local all the things! | |
| 97 | const r0 = ctx.r[0]; // r0 <= 0fffffff | |
| 98 | const r1 = ctx.r[1]; // r1 <= 0ffffffc | |
| 99 | const r2 = ctx.r[2]; // r2 <= 0ffffffc | |
| 100 | const r3 = ctx.r[3]; // r3 <= 0ffffffc | |
| 101 | const rr0 = (r0 >> 2) * 5; // rr0 <= 13fffffb // lose 2 bits... | |
| 102 | const rr1 = (r1 >> 2) + r1; // rr1 <= 13fffffb // rr1 == (r1 >> 2) * 5 | |
| 103 | const rr2 = (r2 >> 2) + r2; // rr2 <= 13fffffb // rr1 == (r2 >> 2) * 5 | |
| 104 | const rr3 = (r3 >> 2) + r3; // rr3 <= 13fffffb // rr1 == (r3 >> 2) * 5 | |
| 105 | ||
| 106 | // (h + c) * r, without carry propagation | |
| 107 | const x0 = s0 * r0 + s1 * rr3 + s2 * rr2 + s3 * rr1 + s4 * rr0; //<=97ffffe007fffff8 | |
| 108 | const x1 = s0 * r1 + s1 * r0 + s2 * rr3 + s3 * rr2 + s4 * rr1; //<=8fffffe20ffffff6 | |
| 109 | const x2 = s0 * r2 + s1 * r1 + s2 * r0 + s3 * rr3 + s4 * rr2; //<=87ffffe417fffff4 | |
| 110 | const x3 = s0 * r3 + s1 * r2 + s2 * r1 + s3 * r0 + s4 * rr3; //<=7fffffe61ffffff2 | |
| 111 | const x4 = s4 * (r0 & 3); // ...recover 2 bits //<= f | |
| 112 | ||
| 113 | // partial reduction modulo 2^130 - 5 | |
| 114 | const _u5 = @truncate(u32, x4 + (x3 >> 32)); // u5 <= 7ffffff5 | |
| 115 | const _u0 = (_u5 >> 2) * 5 + (x0 & 0xffffffff); | |
| 116 | const _u1 = (_u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32); | |
| 117 | const _u2 = (_u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32); | |
| 118 | const _u3 = (_u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32); | |
| 119 | const _u4 = (_u3 >> 32) + (_u5 & 3); | |
| 120 | ||
| 121 | // Update the hash | |
| 122 | ctx.h[0] = @truncate(u32, _u0); // u0 <= 1_9ffffff0 | |
| 123 | ctx.h[1] = @truncate(u32, _u1); // u1 <= 1_97ffffe0 | |
| 124 | ctx.h[2] = @truncate(u32, _u2); // u2 <= 1_8fffffe2 | |
| 125 | ctx.h[3] = @truncate(u32, _u3); // u3 <= 1_87ffffe4 | |
| 126 | ctx.h[4] = @truncate(u32, _u4); // u4 <= 4 | |
| 127 | } | |
| 128 | ||
| 129 | // (re-)initializes the input counter and input buffer | |
| 130 | fn polyClearC(ctx: *Self) void { | |
| 131 | ctx.c[0] = 0; | |
| 132 | ctx.c[1] = 0; | |
| 133 | ctx.c[2] = 0; | |
| 134 | ctx.c[3] = 0; | |
| 135 | ctx.c_idx = 0; | |
| 136 | } | |
| 137 | 101 | |
| 138 | fn polyTakeInput(ctx: *Self, input: u8) void { | |
| 139 | const word = ctx.c_idx >> 2; | |
| 140 | const byte = ctx.c_idx & 3; | |
| 141 | ctx.c[word] |= std.math.shl(u32, input, byte * 8); | |
| 142 | ctx.c_idx += 1; | |
| 143 | } | |
| 102 | // process full blocks | |
| 103 | if (mb.len >= block_size) { | |
| 104 | const want = mb.len & ~(block_size - 1); | |
| 105 | st.blocks(mb[0..want], false); | |
| 106 | mb = mb[want..]; | |
| 107 | } | |
| 144 | 108 | |
| 145 | fn polyUpdate(ctx: *Self, msg: []const u8) void { | |
| 146 | for (msg) |b| { | |
| 147 | polyTakeInput(ctx, b); | |
| 148 | if (ctx.c_idx == 16) { | |
| 149 | polyBlock(ctx); | |
| 150 | polyClearC(ctx); | |
| 109 | // store leftover | |
| 110 | if (mb.len > 0) { | |
| 111 | for (mb) |x, i| { | |
| 112 | st.buf[st.leftover + i] = x; | |
| 151 | 113 | } |
| 114 | st.leftover += mb.len; | |
| 152 | 115 | } |
| 153 | 116 | } |
| 154 | 117 | |
| 155 | fn alignTo(x: usize, block_size: usize) usize { | |
| 156 | return ((~x) +% 1) & (block_size - 1); | |
| 157 | } | |
| 158 | ||
| 159 | // Feed data into the MAC context. | |
| 160 | pub fn update(ctx: *Self, msg: []const u8) void { | |
| 161 | // Align ourselves with block boundaries | |
| 162 | const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len); | |
| 163 | polyUpdate(ctx, msg[0..alignm]); | |
| 164 | ||
| 165 | var nmsg = msg[alignm..]; | |
| 166 | ||
| 167 | // Process the msg block by block | |
| 168 | const nb_blocks = nmsg.len >> 4; | |
| 169 | var i: usize = 0; | |
| 170 | while (i < nb_blocks) : (i += 1) { | |
| 171 | ctx.c[0] = readIntLittle(u32, nmsg[0..4]); | |
| 172 | ctx.c[1] = readIntLittle(u32, nmsg[4..8]); | |
| 173 | ctx.c[2] = readIntLittle(u32, nmsg[8..12]); | |
| 174 | ctx.c[3] = readIntLittle(u32, nmsg[12..16]); | |
| 175 | polyBlock(ctx); | |
| 176 | nmsg = nmsg[16..]; | |
| 177 | } | |
| 178 | if (nb_blocks > 0) { | |
| 179 | polyClearC(ctx); | |
| 118 | pub fn final(st: *Poly1305, out: []u8) void { | |
| 119 | std.debug.assert(out.len >= mac_length); | |
| 120 | if (st.leftover > 0) { | |
| 121 | var i = st.leftover; | |
| 122 | st.buf[i] = 1; | |
| 123 | i += 1; | |
| 124 | while (i < block_size) : (i += 1) { | |
| 125 | st.buf[i] = 0; | |
| 126 | } | |
| 127 | st.blocks(&st.buf, true); | |
| 180 | 128 | } |
| 181 | ||
| 182 | // remaining bytes | |
| 183 | polyUpdate(ctx, nmsg[0..]); | |
| 129 | // fully carry h | |
| 130 | var carry = st.h[1] >> 44; | |
| 131 | st.h[1] = @truncate(u44, st.h[1]); | |
| 132 | st.h[2] += carry; | |
| 133 | carry = st.h[2] >> 42; | |
| 134 | st.h[2] = @truncate(u42, st.h[2]); | |
| 135 | st.h[0] += carry * 5; | |
| 136 | carry = st.h[0] >> 44; | |
| 137 | st.h[0] = @truncate(u44, st.h[0]); | |
| 138 | st.h[1] += carry; | |
| 139 | carry = st.h[1] >> 44; | |
| 140 | st.h[1] = @truncate(u44, st.h[1]); | |
| 141 | st.h[2] += carry; | |
| 142 | carry = st.h[2] >> 42; | |
| 143 | st.h[2] = @truncate(u42, st.h[2]); | |
| 144 | st.h[0] += carry * 5; | |
| 145 | carry = st.h[0] >> 44; | |
| 146 | st.h[0] = @truncate(u44, st.h[0]); | |
| 147 | st.h[1] += carry; | |
| 148 | ||
| 149 | // compute h + -p | |
| 150 | var g0 = st.h[0] + 5; | |
| 151 | carry = g0 >> 44; | |
| 152 | g0 = @truncate(u44, g0); | |
| 153 | var g1 = st.h[1] + carry; | |
| 154 | carry = g1 >> 44; | |
| 155 | g1 = @truncate(u44, g1); | |
| 156 | var g2 = st.h[2] + carry -% (1 << 42); | |
| 157 | ||
| 158 | // (hopefully) constant-time select h if h < p, or h + -p if h >= p | |
| 159 | const mask = (g2 >> 63) -% 1; | |
| 160 | g0 &= mask; | |
| 161 | g1 &= mask; | |
| 162 | g2 &= mask; | |
| 163 | const nmask = ~mask; | |
| 164 | st.h[0] = (st.h[0] & nmask) | g0; | |
| 165 | st.h[1] = (st.h[1] & nmask) | g1; | |
| 166 | st.h[2] = (st.h[2] & nmask) | g2; | |
| 167 | ||
| 168 | // h = (h + pad) | |
| 169 | const t0 = st.pad[0]; | |
| 170 | const t1 = st.pad[1]; | |
| 171 | st.h[0] += @truncate(u44, t0); | |
| 172 | carry = st.h[0] >> 44; | |
| 173 | st.h[0] = @truncate(u44, st.h[0]); | |
| 174 | st.h[1] += @truncate(u44, (t0 >> 44) | (t1 << 20)) + carry; | |
| 175 | carry = st.h[1] >> 44; | |
| 176 | st.h[1] = @truncate(u44, st.h[1]); | |
| 177 | st.h[2] += @truncate(u42, t1 >> 24) + carry; | |
| 178 | st.h[2] = @truncate(u42, st.h[2]); | |
| 179 | ||
| 180 | // mac = h % (2^128) | |
| 181 | st.h[0] |= st.h[1] << 44; | |
| 182 | st.h[1] = (st.h[1] >> 20) | (st.h[2] << 24); | |
| 183 | ||
| 184 | mem.writeIntLittle(u64, out[0..8], st.h[0]); | |
| 185 | mem.writeIntLittle(u64, out[8..16], st.h[1]); | |
| 186 | ||
| 187 | std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]); | |
| 184 | 188 | } |
| 185 | 189 | |
| 186 | // Finalize the MAC and output into buffer provided by caller. | |
| 187 | pub fn final(ctx: *Self, out: []u8) void { | |
| 188 | // Process the last block (if any) | |
| 189 | if (ctx.c_idx != 0) { | |
| 190 | // move the final 1 according to remaining input length | |
| 191 | // (We may add less than 2^130 to the last input block) | |
| 192 | ctx.c[4] = 0; | |
| 193 | polyTakeInput(ctx, 1); | |
| 194 | // one last hash update | |
| 195 | polyBlock(ctx); | |
| 196 | } | |
| 190 | pub fn create(out: []u8, msg: []const u8, key: []const u8) void { | |
| 191 | std.debug.assert(out.len >= mac_length); | |
| 192 | std.debug.assert(key.len >= minimum_key_length); | |
| 197 | 193 | |
| 198 | // check if we should subtract 2^130-5 by performing the | |
| 199 | // corresponding carry propagation. | |
| 200 | const _u0 = @as(u64, 5) + ctx.h[0]; // <= 1_00000004 | |
| 201 | const _u1 = (_u0 >> 32) + ctx.h[1]; // <= 1_00000000 | |
| 202 | const _u2 = (_u1 >> 32) + ctx.h[2]; // <= 1_00000000 | |
| 203 | const _u3 = (_u2 >> 32) + ctx.h[3]; // <= 1_00000000 | |
| 204 | const _u4 = (_u3 >> 32) + ctx.h[4]; // <= 5 | |
| 205 | // u4 indicates how many times we should subtract 2^130-5 (0 or 1) | |
| 206 | ||
| 207 | // h + pad, minus 2^130-5 if u4 exceeds 3 | |
| 208 | const uu0 = (_u4 >> 2) * 5 + ctx.h[0] + ctx.pad[0]; // <= 2_00000003 | |
| 209 | const uu1 = (uu0 >> 32) + ctx.h[1] + ctx.pad[1]; // <= 2_00000000 | |
| 210 | const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 | |
| 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 | |
| 212 | ||
| 213 | writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); | |
| 214 | writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); | |
| 215 | writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); | |
| 216 | writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); | |
| 217 | ||
| 218 | ctx.secureZero(); | |
| 194 | var st = Poly1305.init(key); | |
| 195 | st.update(msg); | |
| 196 | st.final(out); | |
| 219 | 197 | } |
| 220 | 198 | }; |
| 221 | 199 |
lib/std/crypto/sha1.zig+29-24| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const mem = @import("../mem.zig"); |
| 2 | 7 | const math = @import("../math.zig"); |
| 3 | 8 | const endian = @import("../endian.zig"); |
| ... | ... | @@ -24,35 +29,35 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam { |
| 24 | 29 | }; |
| 25 | 30 | } |
| 26 | 31 | |
| 32 | /// The SHA-1 function is now considered cryptographically broken. | |
| 33 | /// Namely, it is feasible to find multiple inputs producing the same hash. | |
| 34 | /// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. | |
| 27 | 35 | pub const Sha1 = struct { |
| 28 | 36 | const Self = @This(); |
| 29 | 37 | pub const block_length = 64; |
| 30 | 38 | pub const digest_length = 20; |
| 39 | pub const Options = struct {}; | |
| 31 | 40 | |
| 32 | 41 | s: [5]u32, |
| 33 | 42 | // Streaming Cache |
| 34 | buf: [64]u8, | |
| 35 | buf_len: u8, | |
| 36 | total_len: u64, | |
| 37 | ||
| 38 | pub fn init() Self { | |
| 39 | var d: Self = undefined; | |
| 40 | d.reset(); | |
| 41 | return d; | |
| 42 | } | |
| 43 | ||
| 44 | pub fn reset(d: *Self) void { | |
| 45 | d.s[0] = 0x67452301; | |
| 46 | d.s[1] = 0xEFCDAB89; | |
| 47 | d.s[2] = 0x98BADCFE; | |
| 48 | d.s[3] = 0x10325476; | |
| 49 | d.s[4] = 0xC3D2E1F0; | |
| 50 | d.buf_len = 0; | |
| 51 | d.total_len = 0; | |
| 43 | buf: [64]u8 = undefined, | |
| 44 | buf_len: u8 = 0, | |
| 45 | total_len: u64 = 0, | |
| 46 | ||
| 47 | pub fn init(options: Options) Self { | |
| 48 | return Self{ | |
| 49 | .s = [_]u32{ | |
| 50 | 0x67452301, | |
| 51 | 0xEFCDAB89, | |
| 52 | 0x98BADCFE, | |
| 53 | 0x10325476, | |
| 54 | 0xC3D2E1F0, | |
| 55 | }, | |
| 56 | }; | |
| 52 | 57 | } |
| 53 | 58 | |
| 54 | pub fn hash(b: []const u8, out: []u8) void { | |
| 55 | var d = Sha1.init(); | |
| 59 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 60 | var d = Sha1.init(options); | |
| 56 | 61 | d.update(b); |
| 57 | 62 | d.final(out); |
| 58 | 63 | } |
| ... | ... | @@ -272,18 +277,18 @@ test "sha1 single" { |
| 272 | 277 | } |
| 273 | 278 | |
| 274 | 279 | test "sha1 streaming" { |
| 275 | var h = Sha1.init(); | |
| 280 | var h = Sha1.init(.{}); | |
| 276 | 281 | var out: [20]u8 = undefined; |
| 277 | 282 | |
| 278 | 283 | h.final(out[0..]); |
| 279 | 284 | htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); |
| 280 | 285 | |
| 281 | h.reset(); | |
| 286 | h = Sha1.init(.{}); | |
| 282 | 287 | h.update("abc"); |
| 283 | 288 | h.final(out[0..]); |
| 284 | 289 | htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); |
| 285 | 290 | |
| 286 | h.reset(); | |
| 291 | h = Sha1.init(.{}); | |
| 287 | 292 | h.update("a"); |
| 288 | 293 | h.update("b"); |
| 289 | 294 | h.update("c"); |
| ... | ... | @@ -295,7 +300,7 @@ test "sha1 aligned final" { |
| 295 | 300 | var block = [_]u8{0} ** Sha1.block_length; |
| 296 | 301 | var out: [Sha1.digest_length]u8 = undefined; |
| 297 | 302 | |
| 298 | var h = Sha1.init(); | |
| 303 | var h = Sha1.init(.{}); | |
| 299 | 304 | h.update(&block); |
| 300 | 305 | h.final(out[0..]); |
| 301 | 306 | } |
lib/std/crypto/sha2.zig+95-60| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const mem = @import("../mem.zig"); |
| 2 | 7 | const math = @import("../math.zig"); |
| 3 | 8 | const endian = @import("../endian.zig"); |
| ... | ... | @@ -72,7 +77,10 @@ const Sha256Params = Sha2Params32{ |
| 72 | 77 | .out_len = 256, |
| 73 | 78 | }; |
| 74 | 79 | |
| 80 | /// SHA-224 | |
| 75 | 81 | pub const Sha224 = Sha2_32(Sha224Params); |
| 82 | ||
| 83 | /// SHA-256 | |
| 76 | 84 | pub const Sha256 = Sha2_32(Sha256Params); |
| 77 | 85 | |
| 78 | 86 | fn Sha2_32(comptime params: Sha2Params32) type { |
| ... | ... | @@ -80,34 +88,31 @@ fn Sha2_32(comptime params: Sha2Params32) type { |
| 80 | 88 | const Self = @This(); |
| 81 | 89 | pub const block_length = 64; |
| 82 | 90 | pub const digest_length = params.out_len / 8; |
| 91 | pub const Options = struct {}; | |
| 83 | 92 | |
| 84 | 93 | s: [8]u32, |
| 85 | 94 | // Streaming Cache |
| 86 | buf: [64]u8, | |
| 87 | buf_len: u8, | |
| 88 | total_len: u64, | |
| 89 | ||
| 90 | pub fn init() Self { | |
| 91 | var d: Self = undefined; | |
| 92 | d.reset(); | |
| 93 | return d; | |
| 94 | } | |
| 95 | ||
| 96 | pub fn reset(d: *Self) void { | |
| 97 | d.s[0] = params.iv0; | |
| 98 | d.s[1] = params.iv1; | |
| 99 | d.s[2] = params.iv2; | |
| 100 | d.s[3] = params.iv3; | |
| 101 | d.s[4] = params.iv4; | |
| 102 | d.s[5] = params.iv5; | |
| 103 | d.s[6] = params.iv6; | |
| 104 | d.s[7] = params.iv7; | |
| 105 | d.buf_len = 0; | |
| 106 | d.total_len = 0; | |
| 95 | buf: [64]u8 = undefined, | |
| 96 | buf_len: u8 = 0, | |
| 97 | total_len: u64 = 0, | |
| 98 | ||
| 99 | pub fn init(options: Options) Self { | |
| 100 | return Self{ | |
| 101 | .s = [_]u32{ | |
| 102 | params.iv0, | |
| 103 | params.iv1, | |
| 104 | params.iv2, | |
| 105 | params.iv3, | |
| 106 | params.iv4, | |
| 107 | params.iv5, | |
| 108 | params.iv6, | |
| 109 | params.iv7, | |
| 110 | }, | |
| 111 | }; | |
| 107 | 112 | } |
| 108 | 113 | |
| 109 | pub fn hash(b: []const u8, out: []u8) void { | |
| 110 | var d = Self.init(); | |
| 114 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 115 | var d = Self.init(options); | |
| 111 | 116 | d.update(b); |
| 112 | 117 | d.final(out); |
| 113 | 118 | } |
| ... | ... | @@ -292,18 +297,18 @@ test "sha224 single" { |
| 292 | 297 | } |
| 293 | 298 | |
| 294 | 299 | test "sha224 streaming" { |
| 295 | var h = Sha224.init(); | |
| 300 | var h = Sha224.init(.{}); | |
| 296 | 301 | var out: [28]u8 = undefined; |
| 297 | 302 | |
| 298 | 303 | h.final(out[0..]); |
| 299 | 304 | htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); |
| 300 | 305 | |
| 301 | h.reset(); | |
| 306 | h = Sha224.init(.{}); | |
| 302 | 307 | h.update("abc"); |
| 303 | 308 | h.final(out[0..]); |
| 304 | 309 | htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); |
| 305 | 310 | |
| 306 | h.reset(); | |
| 311 | h = Sha224.init(.{}); | |
| 307 | 312 | h.update("a"); |
| 308 | 313 | h.update("b"); |
| 309 | 314 | h.update("c"); |
| ... | ... | @@ -318,18 +323,18 @@ test "sha256 single" { |
| 318 | 323 | } |
| 319 | 324 | |
| 320 | 325 | test "sha256 streaming" { |
| 321 | var h = Sha256.init(); | |
| 326 | var h = Sha256.init(.{}); | |
| 322 | 327 | var out: [32]u8 = undefined; |
| 323 | 328 | |
| 324 | 329 | h.final(out[0..]); |
| 325 | 330 | htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); |
| 326 | 331 | |
| 327 | h.reset(); | |
| 332 | h = Sha256.init(.{}); | |
| 328 | 333 | h.update("abc"); |
| 329 | 334 | h.final(out[0..]); |
| 330 | 335 | htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); |
| 331 | 336 | |
| 332 | h.reset(); | |
| 337 | h = Sha256.init(.{}); | |
| 333 | 338 | h.update("a"); |
| 334 | 339 | h.update("b"); |
| 335 | 340 | h.update("c"); |
| ... | ... | @@ -341,7 +346,7 @@ test "sha256 aligned final" { |
| 341 | 346 | var block = [_]u8{0} ** Sha256.block_length; |
| 342 | 347 | var out: [Sha256.digest_length]u8 = undefined; |
| 343 | 348 | |
| 344 | var h = Sha256.init(); | |
| 349 | var h = Sha256.init(.{}); | |
| 345 | 350 | h.update(&block); |
| 346 | 351 | h.final(out[0..]); |
| 347 | 352 | } |
| ... | ... | @@ -413,42 +418,72 @@ const Sha512Params = Sha2Params64{ |
| 413 | 418 | .out_len = 512, |
| 414 | 419 | }; |
| 415 | 420 | |
| 421 | const Sha512256Params = Sha2Params64{ | |
| 422 | .iv0 = 0x22312194FC2BF72C, | |
| 423 | .iv1 = 0x9F555FA3C84C64C2, | |
| 424 | .iv2 = 0x2393B86B6F53B151, | |
| 425 | .iv3 = 0x963877195940EABD, | |
| 426 | .iv4 = 0x96283EE2A88EFFE3, | |
| 427 | .iv5 = 0xBE5E1E2553863992, | |
| 428 | .iv6 = 0x2B0199FC2C85B8AA, | |
| 429 | .iv7 = 0x0EB72DDC81C52CA2, | |
| 430 | .out_len = 256, | |
| 431 | }; | |
| 432 | ||
| 433 | const Sha512T256Params = Sha2Params64{ | |
| 434 | .iv0 = 0x6A09E667F3BCC908, | |
| 435 | .iv1 = 0xBB67AE8584CAA73B, | |
| 436 | .iv2 = 0x3C6EF372FE94F82B, | |
| 437 | .iv3 = 0xA54FF53A5F1D36F1, | |
| 438 | .iv4 = 0x510E527FADE682D1, | |
| 439 | .iv5 = 0x9B05688C2B3E6C1F, | |
| 440 | .iv6 = 0x1F83D9ABFB41BD6B, | |
| 441 | .iv7 = 0x5BE0CD19137E2179, | |
| 442 | .out_len = 256, | |
| 443 | }; | |
| 444 | ||
| 445 | /// SHA-384 | |
| 416 | 446 | pub const Sha384 = Sha2_64(Sha384Params); |
| 447 | ||
| 448 | /// SHA-512 | |
| 417 | 449 | pub const Sha512 = Sha2_64(Sha512Params); |
| 418 | 450 | |
| 451 | /// SHA-512/256 | |
| 452 | pub const Sha512256 = Sha2_64(Sha512256Params); | |
| 453 | ||
| 454 | /// Truncated SHA-512 | |
| 455 | pub const Sha512T256 = Sha2_64(Sha512T256Params); | |
| 456 | ||
| 419 | 457 | fn Sha2_64(comptime params: Sha2Params64) type { |
| 420 | 458 | return struct { |
| 421 | 459 | const Self = @This(); |
| 422 | 460 | pub const block_length = 128; |
| 423 | 461 | pub const digest_length = params.out_len / 8; |
| 462 | pub const Options = struct {}; | |
| 424 | 463 | |
| 425 | 464 | s: [8]u64, |
| 426 | 465 | // Streaming Cache |
| 427 | buf: [128]u8, | |
| 428 | buf_len: u8, | |
| 429 | total_len: u128, | |
| 430 | ||
| 431 | pub fn init() Self { | |
| 432 | var d: Self = undefined; | |
| 433 | d.reset(); | |
| 434 | return d; | |
| 435 | } | |
| 436 | ||
| 437 | pub fn reset(d: *Self) void { | |
| 438 | d.s[0] = params.iv0; | |
| 439 | d.s[1] = params.iv1; | |
| 440 | d.s[2] = params.iv2; | |
| 441 | d.s[3] = params.iv3; | |
| 442 | d.s[4] = params.iv4; | |
| 443 | d.s[5] = params.iv5; | |
| 444 | d.s[6] = params.iv6; | |
| 445 | d.s[7] = params.iv7; | |
| 446 | d.buf_len = 0; | |
| 447 | d.total_len = 0; | |
| 466 | buf: [128]u8 = undefined, | |
| 467 | buf_len: u8 = 0, | |
| 468 | total_len: u128 = 0, | |
| 469 | ||
| 470 | pub fn init(options: Options) Self { | |
| 471 | return Self{ | |
| 472 | .s = [_]u64{ | |
| 473 | params.iv0, | |
| 474 | params.iv1, | |
| 475 | params.iv2, | |
| 476 | params.iv3, | |
| 477 | params.iv4, | |
| 478 | params.iv5, | |
| 479 | params.iv6, | |
| 480 | params.iv7, | |
| 481 | }, | |
| 482 | }; | |
| 448 | 483 | } |
| 449 | 484 | |
| 450 | pub fn hash(b: []const u8, out: []u8) void { | |
| 451 | var d = Self.init(); | |
| 485 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 486 | var d = Self.init(options); | |
| 452 | 487 | d.update(b); |
| 453 | 488 | d.final(out); |
| 454 | 489 | } |
| ... | ... | @@ -660,7 +695,7 @@ test "sha384 single" { |
| 660 | 695 | } |
| 661 | 696 | |
| 662 | 697 | test "sha384 streaming" { |
| 663 | var h = Sha384.init(); | |
| 698 | var h = Sha384.init(.{}); | |
| 664 | 699 | var out: [48]u8 = undefined; |
| 665 | 700 | |
| 666 | 701 | const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"; |
| ... | ... | @@ -669,12 +704,12 @@ test "sha384 streaming" { |
| 669 | 704 | |
| 670 | 705 | const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; |
| 671 | 706 | |
| 672 | h.reset(); | |
| 707 | h = Sha384.init(.{}); | |
| 673 | 708 | h.update("abc"); |
| 674 | 709 | h.final(out[0..]); |
| 675 | 710 | htest.assertEqual(h2, out[0..]); |
| 676 | 711 | |
| 677 | h.reset(); | |
| 712 | h = Sha384.init(.{}); | |
| 678 | 713 | h.update("a"); |
| 679 | 714 | h.update("b"); |
| 680 | 715 | h.update("c"); |
| ... | ... | @@ -694,7 +729,7 @@ test "sha512 single" { |
| 694 | 729 | } |
| 695 | 730 | |
| 696 | 731 | test "sha512 streaming" { |
| 697 | var h = Sha512.init(); | |
| 732 | var h = Sha512.init(.{}); | |
| 698 | 733 | var out: [64]u8 = undefined; |
| 699 | 734 | |
| 700 | 735 | const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; |
| ... | ... | @@ -703,12 +738,12 @@ test "sha512 streaming" { |
| 703 | 738 | |
| 704 | 739 | const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; |
| 705 | 740 | |
| 706 | h.reset(); | |
| 741 | h = Sha512.init(.{}); | |
| 707 | 742 | h.update("abc"); |
| 708 | 743 | h.final(out[0..]); |
| 709 | 744 | htest.assertEqual(h2, out[0..]); |
| 710 | 745 | |
| 711 | h.reset(); | |
| 746 | h = Sha512.init(.{}); | |
| 712 | 747 | h.update("a"); |
| 713 | 748 | h.update("b"); |
| 714 | 749 | h.update("c"); |
| ... | ... | @@ -720,7 +755,7 @@ test "sha512 aligned final" { |
| 720 | 755 | var block = [_]u8{0} ** Sha512.block_length; |
| 721 | 756 | var out: [Sha512.digest_length]u8 = undefined; |
| 722 | 757 | |
| 723 | var h = Sha512.init(); | |
| 758 | var h = Sha512.init(.{}); | |
| 724 | 759 | h.update(&block); |
| 725 | 760 | h.final(out[0..]); |
| 726 | 761 | } |
lib/std/crypto/sha3.zig+24-26| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const mem = @import("../mem.zig"); |
| 2 | 7 | const math = @import("../math.zig"); |
| 3 | 8 | const endian = @import("../endian.zig"); |
| ... | ... | @@ -15,25 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { |
| 15 | 20 | const Self = @This(); |
| 16 | 21 | pub const block_length = 200; |
| 17 | 22 | pub const digest_length = bits / 8; |
| 23 | pub const Options = struct {}; | |
| 18 | 24 | |
| 19 | 25 | s: [200]u8, |
| 20 | 26 | offset: usize, |
| 21 | 27 | rate: usize, |
| 22 | 28 | |
| 23 | pub fn init() Self { | |
| 24 | var d: Self = undefined; | |
| 25 | d.reset(); | |
| 26 | return d; | |
| 29 | pub fn init(options: Options) Self { | |
| 30 | return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) }; | |
| 27 | 31 | } |
| 28 | 32 | |
| 29 | pub fn reset(d: *Self) void { | |
| 30 | mem.set(u8, d.s[0..], 0); | |
| 31 | d.offset = 0; | |
| 32 | d.rate = 200 - (bits / 4); | |
| 33 | } | |
| 34 | ||
| 35 | pub fn hash(b: []const u8, out: []u8) void { | |
| 36 | var d = Self.init(); | |
| 33 | pub fn hash(b: []const u8, out: []u8, options: Options) void { | |
| 34 | var d = Self.init(options); | |
| 37 | 35 | d.update(b); |
| 38 | 36 | d.final(out); |
| 39 | 37 | } |
| ... | ... | @@ -178,18 +176,18 @@ test "sha3-224 single" { |
| 178 | 176 | } |
| 179 | 177 | |
| 180 | 178 | test "sha3-224 streaming" { |
| 181 | var h = Sha3_224.init(); | |
| 179 | var h = Sha3_224.init(.{}); | |
| 182 | 180 | var out: [28]u8 = undefined; |
| 183 | 181 | |
| 184 | 182 | h.final(out[0..]); |
| 185 | 183 | htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); |
| 186 | 184 | |
| 187 | h.reset(); | |
| 185 | h = Sha3_224.init(.{}); | |
| 188 | 186 | h.update("abc"); |
| 189 | 187 | h.final(out[0..]); |
| 190 | 188 | htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); |
| 191 | 189 | |
| 192 | h.reset(); | |
| 190 | h = Sha3_224.init(.{}); | |
| 193 | 191 | h.update("a"); |
| 194 | 192 | h.update("b"); |
| 195 | 193 | h.update("c"); |
| ... | ... | @@ -204,18 +202,18 @@ test "sha3-256 single" { |
| 204 | 202 | } |
| 205 | 203 | |
| 206 | 204 | test "sha3-256 streaming" { |
| 207 | var h = Sha3_256.init(); | |
| 205 | var h = Sha3_256.init(.{}); | |
| 208 | 206 | var out: [32]u8 = undefined; |
| 209 | 207 | |
| 210 | 208 | h.final(out[0..]); |
| 211 | 209 | htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); |
| 212 | 210 | |
| 213 | h.reset(); | |
| 211 | h = Sha3_256.init(.{}); | |
| 214 | 212 | h.update("abc"); |
| 215 | 213 | h.final(out[0..]); |
| 216 | 214 | htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); |
| 217 | 215 | |
| 218 | h.reset(); | |
| 216 | h = Sha3_256.init(.{}); | |
| 219 | 217 | h.update("a"); |
| 220 | 218 | h.update("b"); |
| 221 | 219 | h.update("c"); |
| ... | ... | @@ -227,7 +225,7 @@ test "sha3-256 aligned final" { |
| 227 | 225 | var block = [_]u8{0} ** Sha3_256.block_length; |
| 228 | 226 | var out: [Sha3_256.digest_length]u8 = undefined; |
| 229 | 227 | |
| 230 | var h = Sha3_256.init(); | |
| 228 | var h = Sha3_256.init(.{}); | |
| 231 | 229 | h.update(&block); |
| 232 | 230 | h.final(out[0..]); |
| 233 | 231 | } |
| ... | ... | @@ -242,7 +240,7 @@ test "sha3-384 single" { |
| 242 | 240 | } |
| 243 | 241 | |
| 244 | 242 | test "sha3-384 streaming" { |
| 245 | var h = Sha3_384.init(); | |
| 243 | var h = Sha3_384.init(.{}); | |
| 246 | 244 | var out: [48]u8 = undefined; |
| 247 | 245 | |
| 248 | 246 | const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; |
| ... | ... | @@ -250,12 +248,12 @@ test "sha3-384 streaming" { |
| 250 | 248 | htest.assertEqual(h1, out[0..]); |
| 251 | 249 | |
| 252 | 250 | const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; |
| 253 | h.reset(); | |
| 251 | h = Sha3_384.init(.{}); | |
| 254 | 252 | h.update("abc"); |
| 255 | 253 | h.final(out[0..]); |
| 256 | 254 | htest.assertEqual(h2, out[0..]); |
| 257 | 255 | |
| 258 | h.reset(); | |
| 256 | h = Sha3_384.init(.{}); | |
| 259 | 257 | h.update("a"); |
| 260 | 258 | h.update("b"); |
| 261 | 259 | h.update("c"); |
| ... | ... | @@ -273,7 +271,7 @@ test "sha3-512 single" { |
| 273 | 271 | } |
| 274 | 272 | |
| 275 | 273 | test "sha3-512 streaming" { |
| 276 | var h = Sha3_512.init(); | |
| 274 | var h = Sha3_512.init(.{}); | |
| 277 | 275 | var out: [64]u8 = undefined; |
| 278 | 276 | |
| 279 | 277 | const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"; |
| ... | ... | @@ -281,12 +279,12 @@ test "sha3-512 streaming" { |
| 281 | 279 | htest.assertEqual(h1, out[0..]); |
| 282 | 280 | |
| 283 | 281 | const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; |
| 284 | h.reset(); | |
| 282 | h = Sha3_512.init(.{}); | |
| 285 | 283 | h.update("abc"); |
| 286 | 284 | h.final(out[0..]); |
| 287 | 285 | htest.assertEqual(h2, out[0..]); |
| 288 | 286 | |
| 289 | h.reset(); | |
| 287 | h = Sha3_512.init(.{}); | |
| 290 | 288 | h.update("a"); |
| 291 | 289 | h.update("b"); |
| 292 | 290 | h.update("c"); |
| ... | ... | @@ -298,7 +296,7 @@ test "sha3-512 aligned final" { |
| 298 | 296 | var block = [_]u8{0} ** Sha3_512.block_length; |
| 299 | 297 | var out: [Sha3_512.digest_length]u8 = undefined; |
| 300 | 298 | |
| 301 | var h = Sha3_512.init(); | |
| 299 | var h = Sha3_512.init(.{}); | |
| 302 | 300 | h.update(&block); |
| 303 | 301 | h.final(out[0..]); |
| 304 | 302 | } |
lib/std/crypto/test.zig+6-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const mem = std.mem; |
| ... | ... | @@ -6,7 +11,7 @@ const fmt = std.fmt; |
| 6 | 11 | // Hash using the specified hasher `H` asserting `expected == H(input)`. |
| 7 | 12 | pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void { |
| 8 | 13 | var h: [expected.len / 2]u8 = undefined; |
| 9 | Hasher.hash(input, h[0..]); | |
| 14 | Hasher.hash(input, h[0..], .{}); | |
| 10 | 15 | |
| 11 | 16 | assertEqual(expected, &h); |
| 12 | 17 | } |
lib/std/cstr.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const debug = std.debug; |
lib/std/debug.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const math = std.math; |
lib/std/debug/leb128.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 |
lib/std/dwarf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const debug = std.debug; |
lib/std/dwarf_bits.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const TAG_padding = 0x00; |
| 2 | 7 | pub const TAG_array_type = 0x01; |
| 3 | 8 | pub const TAG_class_type = 0x02; |
lib/std/dynamic_library.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | const std = @import("std.zig"); |
lib/std/elf.zig+6| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
| ... | ... | @@ -558,6 +563,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void { |
| 558 | 563 | error.InputOutput => return error.FileSystem, |
| 559 | 564 | error.Unexpected => return error.Unexpected, |
| 560 | 565 | error.WouldBlock => return error.Unexpected, |
| 566 | error.NotOpenForReading => return error.Unexpected, | |
| 561 | 567 | error.AccessDenied => return error.Unexpected, |
| 562 | 568 | }; |
| 563 | 569 | if (len == 0) return error.UnexpectedEndOfFile; |
lib/std/event.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const Channel = @import("event/channel.zig").Channel; |
| 2 | 7 | pub const Future = @import("event/future.zig").Future; |
| 3 | 8 | pub const Group = @import("event/group.zig").Group; |
lib/std/event/batch.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 |
lib/std/event/channel.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/event/future.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/event/group.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const Lock = std.event.Lock; |
lib/std/event/lock.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/event/locked.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const Lock = std.event.Lock; |
| 3 | 8 |
lib/std/event/loop.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const root = @import("root"); |
lib/std/event/rwlock.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/event/rwlocked.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const RwLock = std.event.RwLock; |
| 3 | 8 |
lib/std/fifo.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // FIFO of fixed size items |
| 2 | 7 | // Usually used for e.g. byte buffers |
| 3 | 8 |
lib/std/fmt.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/fmt/errol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const enum3 = @import("errol/enum3.zig").enum3; |
| 3 | 8 | const enum3_data = @import("errol/enum3.zig").enum3_data; |
lib/std/fmt/errol/enum3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const enum3 = [_]u64{ |
| 2 | 7 | 0x4e2e2785c3a2a20b, |
| 3 | 8 | 0x240a28877a09a4e1, |
lib/std/fmt/errol/lookup.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const HP = struct { |
| 2 | 7 | val: f64, |
| 3 | 8 | off: f64, |
lib/std/fmt/parse_float.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Adapted from https://github.com/grzegorz-kraszewski/stringtofloat. |
| 2 | 7 | |
| 3 | 8 | // MIT License |
lib/std/fs.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std.zig"); |
| 3 | 8 | const os = std.os; |
lib/std/fs/file.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const os = std.os; |
lib/std/fs/get_app_data_dir.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const unicode = std.unicode; |
lib/std/fs/path.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("../std.zig"); |
| 3 | 8 | const debug = std.debug; |
lib/std/fs/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const builtin = std.builtin; |
lib/std/fs/wasi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const os = std.os; |
| 3 | 8 | const mem = std.mem; |
lib/std/fs/watch.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const event = std.event; |
lib/std/hash.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const adler = @import("hash/adler.zig"); |
| 2 | 7 | pub const Adler32 = adler.Adler32; |
| 3 | 8 |
lib/std/hash/adler.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Adler32 checksum. |
| 2 | 7 | // |
| 3 | 8 | // https://tools.ietf.org/html/rfc1950#section-9 |
lib/std/hash/auto_hash.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/hash/benchmark.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // zig run benchmark.zig --release-fast --override-lib-dir .. |
| 2 | 7 | |
| 3 | 8 | const builtin = @import("builtin"); |
lib/std/hash/cityhash.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/hash/crc.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // There are two implementations of CRC32 implemented with the following key characteristics: |
| 2 | 7 | // |
| 3 | 8 | // - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method. |
lib/std/hash/fnv.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // FNV1a - Fowler-Noll-Vo hash function |
| 2 | 7 | // |
| 3 | 8 | // FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties. |
lib/std/hash/murmur.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const testing = std.testing; |
lib/std/hash/siphash.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Siphash |
| 2 | 7 | // |
| 3 | 8 | // SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance |
lib/std/hash/wyhash.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
lib/std/hash_map.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const assert = debug.assert; |
lib/std/heap.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const root = @import("root"); |
| 3 | 8 | const debug = std.debug; |
lib/std/heap/arena_allocator.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const mem = std.mem; |
lib/std/heap/general_purpose_allocator.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | //! # General Purpose Allocator |
| 2 | 7 | //! |
| 3 | 8 | //! ## Design Priorities |
lib/std/heap/logging_allocator.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const Allocator = std.mem.Allocator; |
| 3 | 8 |
lib/std/http.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | test "std.http" { |
| 2 | 7 | _ = @import("http/headers.zig"); |
| 3 | 8 | } |
lib/std/http/headers.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // HTTP Header data structure/type |
| 2 | 7 | // Based on lua-http's http.header module |
| 3 | 8 | // |
lib/std/io.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const root = @import("root"); |
lib/std/io/bit_in_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.bit_reader.BitReader` |
| 2 | 7 | pub const BitInStream = @import("./bit_reader.zig").BitReader; |
| 3 | 8 |
lib/std/io/bit_out_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.bit_writer.BitWriter` |
| 2 | 7 | pub const BitOutStream = @import("./bit_writer.zig").BitWriter; |
| 3 | 8 |
lib/std/io/bit_reader.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
lib/std/io/bit_writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
lib/std/io/buffered_atomic_file.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const fs = std.fs; |
lib/std/io/buffered_in_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.buffered_reader.BufferedReader` |
| 2 | 7 | pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader; |
| 3 | 8 |
lib/std/io/buffered_out_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.buffered_writer.BufferedWriter` |
| 2 | 7 | pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter; |
| 3 | 8 |
lib/std/io/buffered_reader.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/io/buffered_writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 |
lib/std/io/c_out_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.c_writer.CWriter` |
| 2 | 7 | pub const COutStream = @import("./c_writer.zig").CWriter; |
| 3 | 8 |
lib/std/io/c_writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
lib/std/io/counting_out_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.counting_writer.CountingWriter` |
| 2 | 7 | pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter; |
| 3 | 8 |
lib/std/io/counting_writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const testing = std.testing; |
lib/std/io/fixed_buffer_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const testing = std.testing; |
lib/std/io/in_stream.zig+5| ... | ... | @@ -1,2 +1,7 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.reader.Reader` |
| 2 | 7 | pub const InStream = @import("./reader.zig").Reader; |
lib/std/io/multi_out_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.multi_writer.MultiWriter` |
| 2 | 7 | pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter; |
| 3 | 8 |
lib/std/io/multi_writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const testing = std.testing; |
lib/std/io/out_stream.zig+5| ... | ... | @@ -1,2 +1,7 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Deprecated: use `std.io.writer.Writer` |
| 2 | 7 | pub const OutStream = @import("./writer.zig").Writer; |
lib/std/io/peek_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const mem = std.mem; |
lib/std/io/reader.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const math = std.math; |
lib/std/io/seekable_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn SeekableStream( |
lib/std/io/serialization.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
lib/std/io/stream_source.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const testing = std.testing; |
lib/std/io/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const io = std.io; |
lib/std/io/writer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const mem = std.mem; |
lib/std/json.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // JSON parser conforming to RFC8259. |
| 2 | 7 | // |
| 3 | 8 | // https://tools.ietf.org/html/rfc8259 |
lib/std/json/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // RFC 8529 conformance tests. |
| 2 | 7 | // |
| 3 | 8 | // Tests are taken from https://github.com/nst/JSONTestSuite |
lib/std/json/write_stream.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/linked_list.zig+38-91| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const assert = debug.assert; |
| ... | ... | @@ -178,21 +183,9 @@ pub fn TailQueue(comptime T: type) type { |
| 178 | 183 | } |
| 179 | 184 | }; |
| 180 | 185 | |
| 181 | first: ?*Node, | |
| 182 | last: ?*Node, | |
| 183 | len: usize, | |
| 184 | ||
| 185 | /// Initialize a linked list. | |
| 186 | /// | |
| 187 | /// Returns: | |
| 188 | /// An empty linked list. | |
| 189 | pub fn init() Self { | |
| 190 | return Self{ | |
| 191 | .first = null, | |
| 192 | .last = null, | |
| 193 | .len = 0, | |
| 194 | }; | |
| 195 | } | |
| 186 | first: ?*Node = null, | |
| 187 | last: ?*Node = null, | |
| 188 | len: usize = 0, | |
| 196 | 189 | |
| 197 | 190 | /// Insert a new node after an existing one. |
| 198 | 191 | /// |
| ... | ... | @@ -335,65 +328,24 @@ pub fn TailQueue(comptime T: type) type { |
| 335 | 328 | list.remove(first); |
| 336 | 329 | return first; |
| 337 | 330 | } |
| 338 | ||
| 339 | /// Allocate a new node. | |
| 340 | /// | |
| 341 | /// Arguments: | |
| 342 | /// allocator: Dynamic memory allocator. | |
| 343 | /// | |
| 344 | /// Returns: | |
| 345 | /// A pointer to the new node. | |
| 346 | pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { | |
| 347 | return allocator.create(Node); | |
| 348 | } | |
| 349 | ||
| 350 | /// Deallocate a node. | |
| 351 | /// | |
| 352 | /// Arguments: | |
| 353 | /// node: Pointer to the node to deallocate. | |
| 354 | /// allocator: Dynamic memory allocator. | |
| 355 | pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void { | |
| 356 | allocator.destroy(node); | |
| 357 | } | |
| 358 | ||
| 359 | /// Allocate and initialize a node and its data. | |
| 360 | /// | |
| 361 | /// Arguments: | |
| 362 | /// data: The data to put inside the node. | |
| 363 | /// allocator: Dynamic memory allocator. | |
| 364 | /// | |
| 365 | /// Returns: | |
| 366 | /// A pointer to the new node. | |
| 367 | pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node { | |
| 368 | var node = try list.allocateNode(allocator); | |
| 369 | node.* = Node.init(data); | |
| 370 | return node; | |
| 371 | } | |
| 372 | 331 | }; |
| 373 | 332 | } |
| 374 | 333 | |
| 375 | 334 | test "basic TailQueue test" { |
| 376 | const allocator = testing.allocator; | |
| 377 | var list = TailQueue(u32).init(); | |
| 378 | ||
| 379 | var one = try list.createNode(1, allocator); | |
| 380 | var two = try list.createNode(2, allocator); | |
| 381 | var three = try list.createNode(3, allocator); | |
| 382 | var four = try list.createNode(4, allocator); | |
| 383 | var five = try list.createNode(5, allocator); | |
| 384 | defer { | |
| 385 | list.destroyNode(one, allocator); | |
| 386 | list.destroyNode(two, allocator); | |
| 387 | list.destroyNode(three, allocator); | |
| 388 | list.destroyNode(four, allocator); | |
| 389 | list.destroyNode(five, allocator); | |
| 390 | } | |
| 335 | const L = TailQueue(u32); | |
| 336 | var list = L{}; | |
| 337 | ||
| 338 | var one = L.Node{ .data = 1 }; | |
| 339 | var two = L.Node{ .data = 2 }; | |
| 340 | var three = L.Node{ .data = 3 }; | |
| 341 | var four = L.Node{ .data = 4 }; | |
| 342 | var five = L.Node{ .data = 5 }; | |
| 391 | 343 | |
| 392 | list.append(two); // {2} | |
| 393 | list.append(five); // {2, 5} | |
| 394 | list.prepend(one); // {1, 2, 5} | |
| 395 | list.insertBefore(five, four); // {1, 2, 4, 5} | |
| 396 | list.insertAfter(two, three); // {1, 2, 3, 4, 5} | |
| 344 | list.append(&two); // {2} | |
| 345 | list.append(&five); // {2, 5} | |
| 346 | list.prepend(&one); // {1, 2, 5} | |
| 347 | list.insertBefore(&five, &four); // {1, 2, 4, 5} | |
| 348 | list.insertAfter(&two, &three); // {1, 2, 3, 4, 5} | |
| 397 | 349 | |
| 398 | 350 | // Traverse forwards. |
| 399 | 351 | { |
| ... | ... | @@ -417,7 +369,7 @@ test "basic TailQueue test" { |
| 417 | 369 | |
| 418 | 370 | var first = list.popFirst(); // {2, 3, 4, 5} |
| 419 | 371 | var last = list.pop(); // {2, 3, 4} |
| 420 | list.remove(three); // {2, 4} | |
| 372 | list.remove(&three); // {2, 4} | |
| 421 | 373 | |
| 422 | 374 | testing.expect(list.first.?.data == 2); |
| 423 | 375 | testing.expect(list.last.?.data == 4); |
| ... | ... | @@ -425,30 +377,25 @@ test "basic TailQueue test" { |
| 425 | 377 | } |
| 426 | 378 | |
| 427 | 379 | test "TailQueue concatenation" { |
| 428 | const allocator = testing.allocator; | |
| 429 | var list1 = TailQueue(u32).init(); | |
| 430 | var list2 = TailQueue(u32).init(); | |
| 431 | ||
| 432 | var one = try list1.createNode(1, allocator); | |
| 433 | defer list1.destroyNode(one, allocator); | |
| 434 | var two = try list1.createNode(2, allocator); | |
| 435 | defer list1.destroyNode(two, allocator); | |
| 436 | var three = try list1.createNode(3, allocator); | |
| 437 | defer list1.destroyNode(three, allocator); | |
| 438 | var four = try list1.createNode(4, allocator); | |
| 439 | defer list1.destroyNode(four, allocator); | |
| 440 | var five = try list1.createNode(5, allocator); | |
| 441 | defer list1.destroyNode(five, allocator); | |
| 442 | ||
| 443 | list1.append(one); | |
| 444 | list1.append(two); | |
| 445 | list2.append(three); | |
| 446 | list2.append(four); | |
| 447 | list2.append(five); | |
| 380 | const L = TailQueue(u32); | |
| 381 | var list1 = L{}; | |
| 382 | var list2 = L{}; | |
| 383 | ||
| 384 | var one = L.Node{ .data = 1 }; | |
| 385 | var two = L.Node{ .data = 2 }; | |
| 386 | var three = L.Node{ .data = 3 }; | |
| 387 | var four = L.Node{ .data = 4 }; | |
| 388 | var five = L.Node{ .data = 5 }; | |
| 389 | ||
| 390 | list1.append(&one); | |
| 391 | list1.append(&two); | |
| 392 | list2.append(&three); | |
| 393 | list2.append(&four); | |
| 394 | list2.append(&five); | |
| 448 | 395 | |
| 449 | 396 | list1.concatByMoving(&list2); |
| 450 | 397 | |
| 451 | testing.expect(list1.last == five); | |
| 398 | testing.expect(list1.last == &five); | |
| 452 | 399 | testing.expect(list1.len == 5); |
| 453 | 400 | testing.expect(list2.first == null); |
| 454 | 401 | testing.expect(list2.last == null); |
lib/std/log.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const root = @import("root"); |
lib/std/macho.zig+17| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const mach_header = extern struct { |
| 2 | 7 | magic: u32, |
| 3 | 8 | cputype: cpu_type_t, |
| ... | ... | @@ -703,3 +708,15 @@ pub const cpu_type_t = integer_t; |
| 703 | 708 | pub const cpu_subtype_t = integer_t; |
| 704 | 709 | pub const integer_t = c_int; |
| 705 | 710 | pub const vm_prot_t = c_int; |
| 711 | ||
| 712 | /// CPU type targeting 64-bit Intel-based Macs | |
| 713 | pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007; | |
| 714 | ||
| 715 | /// CPU type targeting 64-bit ARM-based Macs | |
| 716 | pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C; | |
| 717 | ||
| 718 | /// All Intel-based Macs | |
| 719 | pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3; | |
| 720 | ||
| 721 | /// All ARM-based Macs | |
| 722 | pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0; |
lib/std/math.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/math/acos.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/acosh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/asin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/asinh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/atan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/atan2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/atanh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/big.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 |
lib/std/math/big/int.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const Limb = std.math.big.Limb; |
lib/std/math/big/int_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const testing = std.testing; |
lib/std/math/big/rational.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const math = std.math; |
lib/std/math/cbrt.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/ceil.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/abs.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/acos.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/acosh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/arg.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/asin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/asinh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/atan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/atanh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/conj.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/cos.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/cosh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/exp.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/ldexp.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/log.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/pow.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/proj.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/sin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/sinh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/sqrt.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/complex/tan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const math = std.math; |
lib/std/math/complex/tanh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/copysign.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/cos.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | 7 | // https://golang.org/LICENSE |
| 3 | 8 | // |
lib/std/math/cosh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/exp.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/exp2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/expm1.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/expo2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/fabs.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/floor.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/fma.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/frexp.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/hypot.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/ilogb.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/inf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 |
lib/std/math/isfinite.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/isinf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/isnan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/isnormal.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/ln.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/log.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/log10.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/log1p.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/log2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/modf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/nan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const math = @import("../math.zig"); |
| 2 | 7 | |
| 3 | 8 | /// Returns the nan representation for type T. |
lib/std/math/pow.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | 7 | // https://golang.org/LICENSE |
| 3 | 8 | // |
lib/std/math/powi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Based on Rust, which is licensed under the MIT license. |
| 2 | 7 | // https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT |
| 3 | 8 | // |
lib/std/math/round.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/scalbn.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/signbit.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/sin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | 7 | // https://golang.org/LICENSE |
| 3 | 8 | // |
lib/std/math/sinh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/sqrt.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const expect = std.testing.expect; |
lib/std/math/tan.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | 7 | // https://golang.org/LICENSE |
| 3 | 8 | // |
lib/std/math/tanh.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/math/trunc.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from musl, which is licensed under the MIT license: |
| 2 | 7 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT |
| 3 | 8 | // |
lib/std/mem.zig+24-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const debug = std.debug; |
| 3 | 8 | const assert = debug.assert; |
| ... | ... | @@ -221,9 +226,19 @@ pub fn zeroes(comptime T: type) T { |
| 221 | 226 | .Vector => |info| { |
| 222 | 227 | return @splat(info.len, zeroes(info.child)); |
| 223 | 228 | }, |
| 229 | .Union => |info| { | |
| 230 | if (comptime meta.containerLayout(T) == .Extern) { | |
| 231 | // The C language specification states that (global) unions | |
| 232 | // should be zero initialized to the first named member. | |
| 233 | var item: T = undefined; | |
| 234 | @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name))); | |
| 235 | return item; | |
| 236 | } | |
| 237 | ||
| 238 | @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); | |
| 239 | }, | |
| 224 | 240 | .ErrorUnion, |
| 225 | 241 | .ErrorSet, |
| 226 | .Union, | |
| 227 | 242 | .Fn, |
| 228 | 243 | .BoundFn, |
| 229 | 244 | .Type, |
| ... | ... | @@ -312,6 +327,14 @@ test "mem.zeroes" { |
| 312 | 327 | for (b.sentinel) |e| { |
| 313 | 328 | testing.expectEqual(@as(u8, 0), e); |
| 314 | 329 | } |
| 330 | ||
| 331 | const C_union = extern union { | |
| 332 | a: u8, | |
| 333 | b: u32, | |
| 334 | }; | |
| 335 | ||
| 336 | var c = zeroes(C_union); | |
| 337 | testing.expectEqual(@as(u8, 0), c.a); | |
| 315 | 338 | } |
| 316 | 339 | |
| 317 | 340 | /// Sets a slice to zeroes. |
lib/std/mem/Allocator.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | //! The standard memory allocation interface. |
| 2 | 7 | |
| 3 | 8 | const std = @import("../std.zig"); |
lib/std/meta.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const debug = std.debug; |
lib/std/meta/trailer_flags.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const meta = std.meta; |
| 3 | 8 | const testing = std.testing; |
lib/std/meta/trait.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const mem = std.mem; |
lib/std/mutex.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const os = std.os; |
lib/std/net.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/net/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const net = std.net; |
lib/std/once.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const testing = std.testing; |
lib/std/os.zig+24-17| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // This file contains thin wrappers around OS-specific APIs, with these |
| 2 | 7 | // specific goals in mind: |
| 3 | 8 | // * Convert "errno"-style error codes into Zig errors. |
| ... | ... | @@ -296,6 +301,7 @@ pub const ReadError = error{ |
| 296 | 301 | BrokenPipe, |
| 297 | 302 | ConnectionResetByPeer, |
| 298 | 303 | ConnectionTimedOut, |
| 304 | NotOpenForReading, | |
| 299 | 305 | |
| 300 | 306 | /// This error occurs when no global event loop is configured, |
| 301 | 307 | /// and reading from the file descriptor would block. |
| ... | ... | @@ -332,7 +338,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 332 | 338 | wasi.EINVAL => unreachable, |
| 333 | 339 | wasi.EFAULT => unreachable, |
| 334 | 340 | wasi.EAGAIN => unreachable, |
| 335 | wasi.EBADF => unreachable, // Always a race condition. | |
| 341 | wasi.EBADF => return error.NotOpenForReading, // Can be a race condition. | |
| 336 | 342 | wasi.EIO => return error.InputOutput, |
| 337 | 343 | wasi.EISDIR => return error.IsDir, |
| 338 | 344 | wasi.ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -364,7 +370,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 364 | 370 | } else { |
| 365 | 371 | return error.WouldBlock; |
| 366 | 372 | }, |
| 367 | EBADF => unreachable, // Always a race condition. | |
| 373 | EBADF => return error.NotOpenForReading, // Can be a race condition. | |
| 368 | 374 | EIO => return error.InputOutput, |
| 369 | 375 | EISDIR => return error.IsDir, |
| 370 | 376 | ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -402,7 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 402 | 408 | wasi.EINVAL => unreachable, |
| 403 | 409 | wasi.EFAULT => unreachable, |
| 404 | 410 | wasi.EAGAIN => unreachable, // currently not support in WASI |
| 405 | wasi.EBADF => unreachable, // always a race condition | |
| 411 | wasi.EBADF => return error.NotOpenForReading, // can be a race condition | |
| 406 | 412 | wasi.EIO => return error.InputOutput, |
| 407 | 413 | wasi.EISDIR => return error.IsDir, |
| 408 | 414 | wasi.ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -426,7 +432,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 426 | 432 | } else { |
| 427 | 433 | return error.WouldBlock; |
| 428 | 434 | }, |
| 429 | EBADF => unreachable, // always a race condition | |
| 435 | EBADF => return error.NotOpenForReading, // can be a race condition | |
| 430 | 436 | EIO => return error.InputOutput, |
| 431 | 437 | EISDIR => return error.IsDir, |
| 432 | 438 | ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -463,7 +469,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 463 | 469 | wasi.EINVAL => unreachable, |
| 464 | 470 | wasi.EFAULT => unreachable, |
| 465 | 471 | wasi.EAGAIN => unreachable, |
| 466 | wasi.EBADF => unreachable, // Always a race condition. | |
| 472 | wasi.EBADF => return error.NotOpenForReading, // Can be a race condition. | |
| 467 | 473 | wasi.EIO => return error.InputOutput, |
| 468 | 474 | wasi.EISDIR => return error.IsDir, |
| 469 | 475 | wasi.ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -490,7 +496,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 490 | 496 | } else { |
| 491 | 497 | return error.WouldBlock; |
| 492 | 498 | }, |
| 493 | EBADF => unreachable, // Always a race condition. | |
| 499 | EBADF => return error.NotOpenForReading, // Can be a race condition. | |
| 494 | 500 | EIO => return error.InputOutput, |
| 495 | 501 | EISDIR => return error.IsDir, |
| 496 | 502 | ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -607,7 +613,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 607 | 613 | wasi.EINVAL => unreachable, |
| 608 | 614 | wasi.EFAULT => unreachable, |
| 609 | 615 | wasi.EAGAIN => unreachable, |
| 610 | wasi.EBADF => unreachable, // always a race condition | |
| 616 | wasi.EBADF => return error.NotOpenForReading, // can be a race condition | |
| 611 | 617 | wasi.EIO => return error.InputOutput, |
| 612 | 618 | wasi.EISDIR => return error.IsDir, |
| 613 | 619 | wasi.ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -635,7 +641,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 635 | 641 | } else { |
| 636 | 642 | return error.WouldBlock; |
| 637 | 643 | }, |
| 638 | EBADF => unreachable, // always a race condition | |
| 644 | EBADF => return error.NotOpenForReading, // can be a race condition | |
| 639 | 645 | EIO => return error.InputOutput, |
| 640 | 646 | EISDIR => return error.IsDir, |
| 641 | 647 | ENOBUFS => return error.SystemResources, |
| ... | ... | @@ -660,6 +666,7 @@ pub const WriteError = error{ |
| 660 | 666 | BrokenPipe, |
| 661 | 667 | SystemResources, |
| 662 | 668 | OperationAborted, |
| 669 | NotOpenForWriting, | |
| 663 | 670 | |
| 664 | 671 | /// This error occurs when no global event loop is configured, |
| 665 | 672 | /// and reading from the file descriptor would block. |
| ... | ... | @@ -704,7 +711,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 704 | 711 | wasi.EINVAL => unreachable, |
| 705 | 712 | wasi.EFAULT => unreachable, |
| 706 | 713 | wasi.EAGAIN => unreachable, |
| 707 | wasi.EBADF => unreachable, // Always a race condition. | |
| 714 | wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. | |
| 708 | 715 | wasi.EDESTADDRREQ => unreachable, // `connect` was never called. |
| 709 | 716 | wasi.EDQUOT => return error.DiskQuota, |
| 710 | 717 | wasi.EFBIG => return error.FileTooBig, |
| ... | ... | @@ -736,7 +743,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 736 | 743 | } else { |
| 737 | 744 | return error.WouldBlock; |
| 738 | 745 | }, |
| 739 | EBADF => unreachable, // Always a race condition. | |
| 746 | EBADF => return error.NotOpenForWriting, // can be a race condition. | |
| 740 | 747 | EDESTADDRREQ => unreachable, // `connect` was never called. |
| 741 | 748 | EDQUOT => return error.DiskQuota, |
| 742 | 749 | EFBIG => return error.FileTooBig, |
| ... | ... | @@ -782,7 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize { |
| 782 | 789 | wasi.EINVAL => unreachable, |
| 783 | 790 | wasi.EFAULT => unreachable, |
| 784 | 791 | wasi.EAGAIN => unreachable, |
| 785 | wasi.EBADF => unreachable, // Always a race condition. | |
| 792 | wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. | |
| 786 | 793 | wasi.EDESTADDRREQ => unreachable, // `connect` was never called. |
| 787 | 794 | wasi.EDQUOT => return error.DiskQuota, |
| 788 | 795 | wasi.EFBIG => return error.FileTooBig, |
| ... | ... | @@ -809,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize { |
| 809 | 816 | } else { |
| 810 | 817 | return error.WouldBlock; |
| 811 | 818 | }, |
| 812 | EBADF => unreachable, // Always a race condition. | |
| 819 | EBADF => return error.NotOpenForWriting, // Can be a race condition. | |
| 813 | 820 | EDESTADDRREQ => unreachable, // `connect` was never called. |
| 814 | 821 | EDQUOT => return error.DiskQuota, |
| 815 | 822 | EFBIG => return error.FileTooBig, |
| ... | ... | @@ -862,7 +869,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 862 | 869 | wasi.EINVAL => unreachable, |
| 863 | 870 | wasi.EFAULT => unreachable, |
| 864 | 871 | wasi.EAGAIN => unreachable, |
| 865 | wasi.EBADF => unreachable, // Always a race condition. | |
| 872 | wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. | |
| 866 | 873 | wasi.EDESTADDRREQ => unreachable, // `connect` was never called. |
| 867 | 874 | wasi.EDQUOT => return error.DiskQuota, |
| 868 | 875 | wasi.EFBIG => return error.FileTooBig, |
| ... | ... | @@ -898,7 +905,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 898 | 905 | } else { |
| 899 | 906 | return error.WouldBlock; |
| 900 | 907 | }, |
| 901 | EBADF => unreachable, // Always a race condition. | |
| 908 | EBADF => return error.NotOpenForWriting, // Can be a race condition. | |
| 902 | 909 | EDESTADDRREQ => unreachable, // `connect` was never called. |
| 903 | 910 | EDQUOT => return error.DiskQuota, |
| 904 | 911 | EFBIG => return error.FileTooBig, |
| ... | ... | @@ -956,7 +963,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz |
| 956 | 963 | wasi.EINVAL => unreachable, |
| 957 | 964 | wasi.EFAULT => unreachable, |
| 958 | 965 | wasi.EAGAIN => unreachable, |
| 959 | wasi.EBADF => unreachable, // Always a race condition. | |
| 966 | wasi.EBADF => return error.NotOpenForWriting, // Can be a race condition. | |
| 960 | 967 | wasi.EDESTADDRREQ => unreachable, // `connect` was never called. |
| 961 | 968 | wasi.EDQUOT => return error.DiskQuota, |
| 962 | 969 | wasi.EFBIG => return error.FileTooBig, |
| ... | ... | @@ -986,7 +993,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz |
| 986 | 993 | } else { |
| 987 | 994 | return error.WouldBlock; |
| 988 | 995 | }, |
| 989 | EBADF => unreachable, // Always a race condition. | |
| 996 | EBADF => return error.NotOpenForWriting, // Can be a race condition. | |
| 990 | 997 | EDESTADDRREQ => unreachable, // `connect` was never called. |
| 991 | 998 | EDQUOT => return error.DiskQuota, |
| 992 | 999 | EFBIG => return error.FileTooBig, |
| ... | ... | @@ -1251,7 +1258,7 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void { |
| 1251 | 1258 | EBUSY, EINTR => continue, |
| 1252 | 1259 | EMFILE => return error.ProcessFdQuotaExceeded, |
| 1253 | 1260 | EINVAL => unreachable, // invalid parameters passed to dup2 |
| 1254 | EBADF => unreachable, // always a race condition | |
| 1261 | EBADF => unreachable, // invalid file descriptor | |
| 1255 | 1262 | else => |err| return unexpectedErrno(err), |
| 1256 | 1263 | } |
| 1257 | 1264 | } |
lib/std/os/bits.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | //! Platform-dependent types and values that are used along with OS-specific APIs. |
| 2 | 7 | //! These are imported into `std.c`, `std.os`, and `std.os.linux`. |
| 3 | 8 | //! Root source files can define `os.bits` and these will additionally be added |
lib/std/os/bits/darwin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/os/bits/dragonfly.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const maxInt = std.math.maxInt; |
| 3 | 8 |
lib/std/os/bits/freebsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const maxInt = std.math.maxInt; |
| 3 | 8 |
lib/std/os/bits/linux.zig+9-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("../../std.zig"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
| ... | ... | @@ -19,7 +24,7 @@ pub usingnamespace switch (builtin.arch) { |
| 19 | 24 | }; |
| 20 | 25 | |
| 21 | 26 | pub usingnamespace @import("linux/netlink.zig"); |
| 22 | pub const bpf = @import("linux/bpf.zig"); | |
| 27 | pub const BPF = @import("linux/bpf.zig"); | |
| 23 | 28 | |
| 24 | 29 | const is_mips = builtin.arch.isMIPS(); |
| 25 | 30 | |
| ... | ... | @@ -770,6 +775,9 @@ pub fn S_ISSOCK(m: u32) bool { |
| 770 | 775 | return m & S_IFMT == S_IFSOCK; |
| 771 | 776 | } |
| 772 | 777 | |
| 778 | pub const UTIME_NOW = 0x3fffffff; | |
| 779 | pub const UTIME_OMIT = 0x3ffffffe; | |
| 780 | ||
| 773 | 781 | pub const TFD_NONBLOCK = O_NONBLOCK; |
| 774 | 782 | pub const TFD_CLOEXEC = O_CLOEXEC; |
| 775 | 783 |
lib/std/os/bits/linux/arm-eabi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // arm-eabi-specific declarations that are intended to be imported into the POSIX namespace. |
| 2 | 7 | const std = @import("../../../std.zig"); |
| 3 | 8 | const linux = std.os.linux; |
lib/std/os/bits/linux/arm64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // arm64-specific declarations that are intended to be imported into the POSIX namespace. |
| 2 | 7 | // This does include Linux-only APIs. |
| 3 | 8 |
lib/std/os/bits/linux/bpf.zig+387-18| ... | ... | @@ -1,5 +1,65 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace std.os; |
| 2 | 7 | const std = @import("../../../std.zig"); |
| 8 | const expectEqual = std.testing.expectEqual; | |
| 9 | const fd_t = std.os.fd_t; | |
| 10 | const pid_t = std.os.pid_t; | |
| 11 | ||
| 12 | // instruction classes | |
| 13 | pub const LD = 0x00; | |
| 14 | pub const LDX = 0x01; | |
| 15 | pub const ST = 0x02; | |
| 16 | pub const STX = 0x03; | |
| 17 | pub const ALU = 0x04; | |
| 18 | pub const JMP = 0x05; | |
| 19 | pub const RET = 0x06; | |
| 20 | pub const MISC = 0x07; | |
| 21 | ||
| 22 | /// 32-bit | |
| 23 | pub const W = 0x00; | |
| 24 | /// 16-bit | |
| 25 | pub const H = 0x08; | |
| 26 | /// 8-bit | |
| 27 | pub const B = 0x10; | |
| 28 | /// 64-bit | |
| 29 | pub const DW = 0x18; | |
| 30 | ||
| 31 | pub const IMM = 0x00; | |
| 32 | pub const ABS = 0x20; | |
| 33 | pub const IND = 0x40; | |
| 34 | pub const MEM = 0x60; | |
| 35 | pub const LEN = 0x80; | |
| 36 | pub const MSH = 0xa0; | |
| 37 | ||
| 38 | // alu fields | |
| 39 | pub const ADD = 0x00; | |
| 40 | pub const SUB = 0x10; | |
| 41 | pub const MUL = 0x20; | |
| 42 | pub const DIV = 0x30; | |
| 43 | pub const OR = 0x40; | |
| 44 | pub const AND = 0x50; | |
| 45 | pub const LSH = 0x60; | |
| 46 | pub const RSH = 0x70; | |
| 47 | pub const NEG = 0x80; | |
| 48 | pub const MOD = 0x90; | |
| 49 | pub const XOR = 0xa0; | |
| 50 | ||
| 51 | // jmp fields | |
| 52 | pub const JA = 0x00; | |
| 53 | pub const JEQ = 0x10; | |
| 54 | pub const JGT = 0x20; | |
| 55 | pub const JGE = 0x30; | |
| 56 | pub const JSET = 0x40; | |
| 57 | ||
| 58 | //#define BPF_SRC(code) ((code) & 0x08) | |
| 59 | pub const K = 0x00; | |
| 60 | pub const X = 0x08; | |
| 61 | ||
| 62 | pub const MAXINSNS = 4096; | |
| 3 | 63 | |
| 4 | 64 | // instruction classes |
| 5 | 65 | /// jmp mode in word width |
| ... | ... | @@ -8,8 +68,6 @@ pub const JMP32 = 0x06; |
| 8 | 68 | pub const ALU64 = 0x07; |
| 9 | 69 | |
| 10 | 70 | // ld/ldx fields |
| 11 | /// double word (64-bit) | |
| 12 | pub const DW = 0x18; | |
| 13 | 71 | /// exclusive add |
| 14 | 72 | pub const XADD = 0xc0; |
| 15 | 73 | |
| ... | ... | @@ -148,6 +206,130 @@ pub const BPF_F_CLONE = 0x200; |
| 148 | 206 | /// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map |
| 149 | 207 | pub const BPF_F_MMAPABLE = 0x400; |
| 150 | 208 | |
| 209 | /// These values correspond to "syscalls" within the BPF program's environment | |
| 210 | pub const Helper = enum(i32) { | |
| 211 | unspec, | |
| 212 | map_lookup_elem, | |
| 213 | map_update_elem, | |
| 214 | map_delete_elem, | |
| 215 | probe_read, | |
| 216 | ktime_get_ns, | |
| 217 | trace_printk, | |
| 218 | get_prandom_u32, | |
| 219 | get_smp_processor_id, | |
| 220 | skb_store_bytes, | |
| 221 | l3_csum_replace, | |
| 222 | l4_csum_replace, | |
| 223 | tail_call, | |
| 224 | clone_redirect, | |
| 225 | get_current_pid_tgid, | |
| 226 | get_current_uid_gid, | |
| 227 | get_current_comm, | |
| 228 | get_cgroup_classid, | |
| 229 | skb_vlan_push, | |
| 230 | skb_vlan_pop, | |
| 231 | skb_get_tunnel_key, | |
| 232 | skb_set_tunnel_key, | |
| 233 | perf_event_read, | |
| 234 | redirect, | |
| 235 | get_route_realm, | |
| 236 | perf_event_output, | |
| 237 | skb_load_bytes, | |
| 238 | get_stackid, | |
| 239 | csum_diff, | |
| 240 | skb_get_tunnel_opt, | |
| 241 | skb_set_tunnel_opt, | |
| 242 | skb_change_proto, | |
| 243 | skb_change_type, | |
| 244 | skb_under_cgroup, | |
| 245 | get_hash_recalc, | |
| 246 | get_current_task, | |
| 247 | probe_write_user, | |
| 248 | current_task_under_cgroup, | |
| 249 | skb_change_tail, | |
| 250 | skb_pull_data, | |
| 251 | csum_update, | |
| 252 | set_hash_invalid, | |
| 253 | get_numa_node_id, | |
| 254 | skb_change_head, | |
| 255 | xdp_adjust_head, | |
| 256 | probe_read_str, | |
| 257 | get_socket_cookie, | |
| 258 | get_socket_uid, | |
| 259 | set_hash, | |
| 260 | setsockopt, | |
| 261 | skb_adjust_room, | |
| 262 | redirect_map, | |
| 263 | sk_redirect_map, | |
| 264 | sock_map_update, | |
| 265 | xdp_adjust_meta, | |
| 266 | perf_event_read_value, | |
| 267 | perf_prog_read_value, | |
| 268 | getsockopt, | |
| 269 | override_return, | |
| 270 | sock_ops_cb_flags_set, | |
| 271 | msg_redirect_map, | |
| 272 | msg_apply_bytes, | |
| 273 | msg_cork_bytes, | |
| 274 | msg_pull_data, | |
| 275 | bind, | |
| 276 | xdp_adjust_tail, | |
| 277 | skb_get_xfrm_state, | |
| 278 | get_stack, | |
| 279 | skb_load_bytes_relative, | |
| 280 | fib_lookup, | |
| 281 | sock_hash_update, | |
| 282 | msg_redirect_hash, | |
| 283 | sk_redirect_hash, | |
| 284 | lwt_push_encap, | |
| 285 | lwt_seg6_store_bytes, | |
| 286 | lwt_seg6_adjust_srh, | |
| 287 | lwt_seg6_action, | |
| 288 | rc_repeat, | |
| 289 | rc_keydown, | |
| 290 | skb_cgroup_id, | |
| 291 | get_current_cgroup_id, | |
| 292 | get_local_storage, | |
| 293 | sk_select_reuseport, | |
| 294 | skb_ancestor_cgroup_id, | |
| 295 | sk_lookup_tcp, | |
| 296 | sk_lookup_udp, | |
| 297 | sk_release, | |
| 298 | map_push_elem, | |
| 299 | map_pop_elem, | |
| 300 | map_peek_elem, | |
| 301 | msg_push_data, | |
| 302 | msg_pop_data, | |
| 303 | rc_pointer_rel, | |
| 304 | spin_lock, | |
| 305 | spin_unlock, | |
| 306 | sk_fullsock, | |
| 307 | tcp_sock, | |
| 308 | skb_ecn_set_ce, | |
| 309 | get_listener_sock, | |
| 310 | skc_lookup_tcp, | |
| 311 | tcp_check_syncookie, | |
| 312 | sysctl_get_name, | |
| 313 | sysctl_get_current_value, | |
| 314 | sysctl_get_new_value, | |
| 315 | sysctl_set_new_value, | |
| 316 | strtol, | |
| 317 | strtoul, | |
| 318 | sk_storage_get, | |
| 319 | sk_storage_delete, | |
| 320 | send_signal, | |
| 321 | tcp_gen_syncookie, | |
| 322 | skb_output, | |
| 323 | probe_read_user, | |
| 324 | probe_read_kernel, | |
| 325 | probe_read_user_str, | |
| 326 | probe_read_kernel_str, | |
| 327 | tcp_send_ack, | |
| 328 | send_signal_thread, | |
| 329 | jiffies64, | |
| 330 | _, | |
| 331 | }; | |
| 332 | ||
| 151 | 333 | /// a single BPF instruction |
| 152 | 334 | pub const Insn = packed struct { |
| 153 | 335 | code: u8, |
| ... | ... | @@ -158,32 +340,168 @@ pub const Insn = packed struct { |
| 158 | 340 | |
| 159 | 341 | /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack |
| 160 | 342 | /// frame |
| 161 | pub const Reg = enum(u4) { | |
| 162 | r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 | |
| 343 | pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; | |
| 344 | const Source = packed enum(u1) { reg, imm }; | |
| 345 | const AluOp = packed enum(u8) { | |
| 346 | add = ADD, | |
| 347 | sub = SUB, | |
| 348 | mul = MUL, | |
| 349 | div = DIV, | |
| 350 | op_or = OR, | |
| 351 | op_and = AND, | |
| 352 | lsh = LSH, | |
| 353 | rsh = RSH, | |
| 354 | neg = NEG, | |
| 355 | mod = MOD, | |
| 356 | xor = XOR, | |
| 357 | mov = MOV, | |
| 163 | 358 | }; |
| 164 | 359 | |
| 165 | const alu = 0x04; | |
| 166 | const jmp = 0x05; | |
| 167 | const mov = 0xb0; | |
| 168 | const k = 0; | |
| 169 | const exit_code = 0x90; | |
| 360 | pub const Size = packed enum(u8) { | |
| 361 | byte = B, | |
| 362 | half_word = H, | |
| 363 | word = W, | |
| 364 | double_word = DW, | |
| 365 | }; | |
| 366 | ||
| 367 | const JmpOp = packed enum(u8) { | |
| 368 | ja = JA, | |
| 369 | jeq = JEQ, | |
| 370 | jgt = JGT, | |
| 371 | jge = JGE, | |
| 372 | jset = JSET, | |
| 373 | }; | |
| 374 | ||
| 375 | const ImmOrReg = union(Source) { | |
| 376 | imm: i32, | |
| 377 | reg: Reg, | |
| 378 | }; | |
| 379 | ||
| 380 | fn imm_reg(code: u8, dst: Reg, src: anytype, off: i16) Insn { | |
| 381 | const imm_or_reg = if (@typeInfo(@TypeOf(src)) == .EnumLiteral) | |
| 382 | ImmOrReg{ .reg = @as(Reg, src) } | |
| 383 | else | |
| 384 | ImmOrReg{ .imm = src }; | |
| 385 | ||
| 386 | const src_type = switch (imm_or_reg) { | |
| 387 | .imm => K, | |
| 388 | .reg => X, | |
| 389 | }; | |
| 390 | ||
| 391 | return Insn{ | |
| 392 | .code = code | src_type, | |
| 393 | .dst = @enumToInt(dst), | |
| 394 | .src = switch (imm_or_reg) { | |
| 395 | .imm => 0, | |
| 396 | .reg => |r| @enumToInt(r), | |
| 397 | }, | |
| 398 | .off = off, | |
| 399 | .imm = switch (imm_or_reg) { | |
| 400 | .imm => |i| i, | |
| 401 | .reg => 0, | |
| 402 | }, | |
| 403 | }; | |
| 404 | } | |
| 405 | ||
| 406 | fn alu(comptime width: comptime_int, op: AluOp, dst: Reg, src: anytype) Insn { | |
| 407 | const width_bitfield = switch (width) { | |
| 408 | 32 => ALU, | |
| 409 | 64 => ALU64, | |
| 410 | else => @compileError("width must be 32 or 64"), | |
| 411 | }; | |
| 412 | ||
| 413 | return imm_reg(width_bitfield | @enumToInt(op), dst, src, 0); | |
| 414 | } | |
| 170 | 415 | |
| 171 | // TODO: implement more factory functions for the other instructions | |
| 172 | /// load immediate value into a register | |
| 173 | pub fn load_imm(dst: Reg, imm: i32) Insn { | |
| 416 | pub fn mov(dst: Reg, src: anytype) Insn { | |
| 417 | return alu(64, .mov, dst, src); | |
| 418 | } | |
| 419 | ||
| 420 | pub fn add(dst: Reg, src: anytype) Insn { | |
| 421 | return alu(64, .add, dst, src); | |
| 422 | } | |
| 423 | ||
| 424 | fn jmp(op: JmpOp, dst: Reg, src: anytype, off: i16) Insn { | |
| 425 | return imm_reg(JMP | @enumToInt(op), dst, src, off); | |
| 426 | } | |
| 427 | ||
| 428 | pub fn jeq(dst: Reg, src: anytype, off: i16) Insn { | |
| 429 | return jmp(.jeq, dst, src, off); | |
| 430 | } | |
| 431 | ||
| 432 | pub fn stx_mem(size: Size, dst: Reg, src: Reg, off: i16) Insn { | |
| 174 | 433 | return Insn{ |
| 175 | .code = alu | mov | k, | |
| 434 | .code = STX | @enumToInt(size) | MEM, | |
| 176 | 435 | .dst = @enumToInt(dst), |
| 436 | .src = @enumToInt(src), | |
| 437 | .off = off, | |
| 438 | .imm = 0, | |
| 439 | }; | |
| 440 | } | |
| 441 | ||
| 442 | pub fn xadd(dst: Reg, src: Reg) Insn { | |
| 443 | return Insn{ | |
| 444 | .code = STX | XADD | DW, | |
| 445 | .dst = @enumToInt(dst), | |
| 446 | .src = @enumToInt(src), | |
| 447 | .off = 0, | |
| 448 | .imm = 0, | |
| 449 | }; | |
| 450 | } | |
| 451 | ||
| 452 | /// direct packet access, R0 = *(uint *)(skb->data + imm32) | |
| 453 | pub fn ld_abs(size: Size, imm: i32) Insn { | |
| 454 | return Insn{ | |
| 455 | .code = LD | @enumToInt(size) | ABS, | |
| 456 | .dst = 0, | |
| 177 | 457 | .src = 0, |
| 178 | 458 | .off = 0, |
| 179 | 459 | .imm = imm, |
| 180 | 460 | }; |
| 181 | 461 | } |
| 182 | 462 | |
| 463 | fn ld_imm_impl1(dst: Reg, src: Reg, imm: u64) Insn { | |
| 464 | return Insn{ | |
| 465 | .code = LD | DW | IMM, | |
| 466 | .dst = @enumToInt(dst), | |
| 467 | .src = @enumToInt(src), | |
| 468 | .off = 0, | |
| 469 | .imm = @intCast(i32, @truncate(u32, imm)), | |
| 470 | }; | |
| 471 | } | |
| 472 | ||
| 473 | fn ld_imm_impl2(imm: u64) Insn { | |
| 474 | return Insn{ | |
| 475 | .code = 0, | |
| 476 | .dst = 0, | |
| 477 | .src = 0, | |
| 478 | .off = 0, | |
| 479 | .imm = @intCast(i32, @truncate(u32, imm >> 32)), | |
| 480 | }; | |
| 481 | } | |
| 482 | ||
| 483 | pub fn ld_map_fd1(dst: Reg, map_fd: fd_t) Insn { | |
| 484 | return ld_imm_impl1(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); | |
| 485 | } | |
| 486 | ||
| 487 | pub fn ld_map_fd2(map_fd: fd_t) Insn { | |
| 488 | return ld_imm_impl2(@intCast(u64, map_fd)); | |
| 489 | } | |
| 490 | ||
| 491 | pub fn call(helper: Helper) Insn { | |
| 492 | return Insn{ | |
| 493 | .code = JMP | CALL, | |
| 494 | .dst = 0, | |
| 495 | .src = 0, | |
| 496 | .off = 0, | |
| 497 | .imm = @enumToInt(helper), | |
| 498 | }; | |
| 499 | } | |
| 500 | ||
| 183 | 501 | /// exit BPF program |
| 184 | 502 | pub fn exit() Insn { |
| 185 | 503 | return Insn{ |
| 186 | .code = jmp | exit_code, | |
| 504 | .code = JMP | EXIT, | |
| 187 | 505 | .dst = 0, |
| 188 | 506 | .src = 0, |
| 189 | 507 | .off = 0, |
| ... | ... | @@ -192,6 +510,61 @@ pub const Insn = packed struct { |
| 192 | 510 | } |
| 193 | 511 | }; |
| 194 | 512 | |
| 513 | fn expect_insn(insn: Insn, val: u64) void { | |
| 514 | expectEqual(@bitCast(u64, insn), val); | |
| 515 | } | |
| 516 | ||
| 517 | test "insn bitsize" { | |
| 518 | expectEqual(@bitSizeOf(Insn), 64); | |
| 519 | } | |
| 520 | ||
| 521 | // mov instructions | |
| 522 | test "mov imm" { | |
| 523 | expect_insn(Insn.mov(.r1, 1), 0x00000001000001b7); | |
| 524 | } | |
| 525 | ||
| 526 | test "mov reg" { | |
| 527 | expect_insn(Insn.mov(.r6, .r1), 0x00000000000016bf); | |
| 528 | } | |
| 529 | ||
| 530 | // alu instructions | |
| 531 | test "add imm" { | |
| 532 | expect_insn(Insn.add(.r2, -4), 0xfffffffc00000207); | |
| 533 | } | |
| 534 | ||
| 535 | // ld instructions | |
| 536 | test "ld_abs" { | |
| 537 | expect_insn(Insn.ld_abs(.byte, 42), 0x0000002a00000030); | |
| 538 | } | |
| 539 | ||
| 540 | test "ld_map_fd" { | |
| 541 | expect_insn(Insn.ld_map_fd1(.r1, 42), 0x0000002a00001118); | |
| 542 | expect_insn(Insn.ld_map_fd2(42), 0x0000000000000000); | |
| 543 | } | |
| 544 | ||
| 545 | // st instructions | |
| 546 | test "stx_mem" { | |
| 547 | expect_insn(Insn.stx_mem(.word, .r10, .r0, -4), 0x00000000fffc0a63); | |
| 548 | } | |
| 549 | ||
| 550 | test "xadd" { | |
| 551 | expect_insn(Insn.xadd(.r0, .r1), 0x00000000000010db); | |
| 552 | } | |
| 553 | ||
| 554 | // jmp instructions | |
| 555 | test "jeq imm" { | |
| 556 | expect_insn(Insn.jeq(.r0, 0, 2), 0x0000000000020015); | |
| 557 | } | |
| 558 | ||
| 559 | // other instructions | |
| 560 | test "call" { | |
| 561 | expect_insn(Insn.call(.map_lookup_elem), 0x0000000100000085); | |
| 562 | } | |
| 563 | ||
| 564 | test "exit" { | |
| 565 | expect_insn(Insn.exit(), 0x0000000000000095); | |
| 566 | } | |
| 567 | ||
| 195 | 568 | pub const Cmd = extern enum(usize) { |
| 196 | 569 | map_create, |
| 197 | 570 | map_lookup_elem, |
| ... | ... | @@ -600,7 +973,3 @@ pub const Attr = extern union { |
| 600 | 973 | enable_stats: EnableStatsAttr, |
| 601 | 974 | iter_create: IterCreateAttr, |
| 602 | 975 | }; |
| 603 | ||
| 604 | pub fn bpf(cmd: Cmd, attr: *Attr, size: u32) usize { | |
| 605 | return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); | |
| 606 | } |
lib/std/os/bits/linux/errno-generic.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// Operation not permitted |
| 2 | 7 | pub const EPERM = 1; |
| 3 | 8 |
lib/std/os/bits/linux/errno-mips.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const EPERM = 1; |
| 2 | 7 | pub const ENOENT = 2; |
| 3 | 8 | pub const ESRCH = 3; |
lib/std/os/bits/linux/i386.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // i386-specific declarations that are intended to be imported into the POSIX namespace. |
| 2 | 7 | // This does include Linux-only APIs. |
| 3 | 8 |
lib/std/os/bits/linux/mips.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../../std.zig"); |
| 2 | 7 | const linux = std.os.linux; |
| 3 | 8 | const socklen_t = linux.socklen_t; |
lib/std/os/bits/linux/netlink.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../linux.zig"); |
| 2 | 7 | |
| 3 | 8 | /// Routing/device hook |
lib/std/os/bits/linux/riscv64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // riscv64-specific declarations that are intended to be imported into the POSIX namespace. |
| 2 | 7 | const std = @import("../../../std.zig"); |
| 3 | 8 | const uid_t = std.os.linux.uid_t; |
lib/std/os/bits/linux/x86_64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // x86-64-specific declarations that are intended to be imported into the POSIX namespace. |
| 2 | 7 | const std = @import("../../../std.zig"); |
| 3 | 8 | const pid_t = linux.pid_t; |
lib/std/os/bits/netbsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/os/bits/wasi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Convenience types and consts used by std.os module |
| 2 | 7 | pub const STDIN_FILENO = 0; |
| 3 | 8 | pub const STDOUT_FILENO = 1; |
lib/std/os/bits/windows.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime). |
| 2 | 7 | |
| 3 | 8 | usingnamespace @import("../windows/bits.zig"); |
lib/std/os/darwin.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("../std.zig"); |
| 3 | 8 | pub usingnamespace std.c; |
lib/std/os/dragonfly.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | pub usingnamespace std.c; |
| 3 | 8 | pub usingnamespace @import("bits.zig"); |
lib/std/os/freebsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | pub usingnamespace std.c; |
| 3 | 8 | pub usingnamespace @import("bits.zig"); |
lib/std/os/linux.zig+9| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // This file provides the system interface functions for Linux matching those |
| 2 | 7 | // that are provided by libc, whether or not libc is linked. The following |
| 3 | 8 | // abstractions are made: |
| ... | ... | @@ -1216,6 +1221,10 @@ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, |
| 1216 | 1221 | ); |
| 1217 | 1222 | } |
| 1218 | 1223 | |
| 1224 | pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize { | |
| 1225 | return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); | |
| 1226 | } | |
| 1227 | ||
| 1219 | 1228 | test "" { |
| 1220 | 1229 | if (builtin.os.tag == .linux) { |
| 1221 | 1230 | _ = @import("linux/test.zig"); |
lib/std/os/linux/arm-eabi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/linux/arm64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/linux/i386.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/linux/mips.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/linux/riscv64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/linux/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const linux = std.os.linux; |
lib/std/os/linux/tls.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const os = std.os; |
lib/std/os/linux/vdso.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../../std.zig"); |
| 2 | 7 | const elf = std.elf; |
| 3 | 8 | const linux = std.os.linux; |
lib/std/os/linux/x86_64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("../bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub fn syscall0(number: SYS) usize { |
lib/std/os/netbsd.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | pub usingnamespace std.c; |
| 3 | 8 | pub usingnamespace @import("bits.zig"); |
lib/std/os/test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const os = std.os; |
| 3 | 8 | const testing = std.testing; |
lib/std/os/uefi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | /// A protocol is an interface identified by a GUID. |
| 2 | 7 | pub const protocols = @import("uefi/protocols.zig"); |
| 3 | 8 |
lib/std/os/uefi/protocols.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol; |
| 2 | 7 | pub const loaded_image_device_path_protocol_guid = @import("protocols/loaded_image_protocol.zig").loaded_image_device_path_protocol_guid; |
| 3 | 8 |
lib/std/os/uefi/protocols/absolute_pointer_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/device_path_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 |
lib/std/os/uefi/protocols/edid_active_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 |
lib/std/os/uefi/protocols/edid_discovered_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 |
lib/std/os/uefi/protocols/edid_override_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Handle = uefi.Handle; |
lib/std/os/uefi/protocols/file_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Time = uefi.Time; |
lib/std/os/uefi/protocols/graphics_output_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Status = uefi.Status; |
lib/std/os/uefi/protocols/hii.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 |
lib/std/os/uefi/protocols/hii_database_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Status = uefi.Status; |
lib/std/os/uefi/protocols/hii_popup_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Status = uefi.Status; |
lib/std/os/uefi/protocols/ip6_config_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Event = uefi.Event; |
lib/std/os/uefi/protocols/ip6_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Event = uefi.Event; |
lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Handle = uefi.Handle; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/loaded_image_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Handle = uefi.Handle; |
lib/std/os/uefi/protocols/managed_network_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Event = uefi.Event; |
lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Handle = uefi.Handle; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/rng_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Status = uefi.Status; |
lib/std/os/uefi/protocols/shell_parameters_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const FileHandle = uefi.FileHandle; |
lib/std/os/uefi/protocols/simple_file_system_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const FileProtocol = uefi.protocols.FileProtocol; |
lib/std/os/uefi/protocols/simple_network_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/simple_pointer_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/simple_text_input_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/protocols/simple_text_output_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Status = uefi.Status; |
lib/std/os/uefi/protocols/udp6_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const Event = uefi.Event; |
lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Handle = uefi.Handle; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/status.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const high_bit = 1 << @typeInfo(usize).Int.bits - 1; |
| 2 | 7 | |
| 3 | 8 | pub const Status = extern enum(usize) { |
lib/std/os/uefi/tables.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const AllocateType = @import("tables/boot_services.zig").AllocateType; |
| 2 | 7 | pub const BootServices = @import("tables/boot_services.zig").BootServices; |
| 3 | 8 | pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; |
lib/std/os/uefi/tables/boot_services.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Event = uefi.Event; |
| 3 | 8 | const Guid = uefi.Guid; |
lib/std/os/uefi/tables/configuration_table.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 |
lib/std/os/uefi/tables/runtime_services.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const Guid = uefi.Guid; |
| 3 | 8 | const TableHeader = uefi.tables.TableHeader; |
lib/std/os/uefi/tables/system_table.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const uefi = @import("std").os.uefi; |
| 2 | 7 | const BootServices = uefi.tables.BootServices; |
| 3 | 8 | const ConfigurationTable = uefi.tables.ConfigurationTable; |
lib/std/os/uefi/tables/table_header.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const TableHeader = extern struct { |
| 2 | 7 | signature: u64, |
| 3 | 8 | revision: u32, |
lib/std/os/wasi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // wasi_snapshot_preview1 spec available (in witx format) here: |
| 2 | 7 | // * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx |
| 3 | 8 | // * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx |
lib/std/os/windows.zig+7| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // This file contains thin wrappers around Windows-specific APIs, with these |
| 2 | 7 | // specific goals in mind: |
| 3 | 8 | // * Convert "errno"-style error codes into Zig errors. |
| ... | ... | @@ -469,6 +474,7 @@ pub const WriteFileError = error{ |
| 469 | 474 | SystemResources, |
| 470 | 475 | OperationAborted, |
| 471 | 476 | BrokenPipe, |
| 477 | NotOpenForWriting, | |
| 472 | 478 | Unexpected, |
| 473 | 479 | }; |
| 474 | 480 | |
| ... | ... | @@ -542,6 +548,7 @@ pub fn WriteFile( |
| 542 | 548 | .NOT_ENOUGH_QUOTA => return error.SystemResources, |
| 543 | 549 | .IO_PENDING => unreachable, |
| 544 | 550 | .BROKEN_PIPE => return error.BrokenPipe, |
| 551 | .INVALID_HANDLE => return error.NotOpenForWriting, | |
| 545 | 552 | else => |err| return unexpectedError(err), |
| 546 | 553 | } |
| 547 | 554 | } |
lib/std/os/windows/advapi32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "advapi32" fn RegOpenKeyExW( |
lib/std/os/windows/bits.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Platform-dependent types and values that are used along with OS-specific APIs. |
| 2 | 7 | |
| 3 | 8 | const builtin = @import("builtin"); |
lib/std/os/windows/gdi32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub const PIXELFORMATDESCRIPTOR = extern struct { |
lib/std/os/windows/kernel32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(.Stdcall) ?*c_void; |
lib/std/os/windows/lang.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const NEUTRAL = 0x00; |
| 2 | 7 | pub const INVARIANT = 0x7f; |
| 3 | 8 | pub const AFRIKAANS = 0x36; |
lib/std/os/windows/ntdll.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "NtDll" fn RtlGetVersion( |
lib/std/os/windows/ntstatus.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55? |
| 2 | 7 | pub const NTSTATUS = extern enum(u32) { |
| 3 | 8 | /// The operation completed successfully. |
lib/std/os/windows/ole32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(.Stdcall) void; |
lib/std/os/windows/psapi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "psapi" fn EmptyWorkingSet(hProcess: HANDLE) callconv(.Stdcall) BOOL; |
lib/std/os/windows/shell32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub extern "shell32" fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*:0]WCHAR) callconv(.Stdcall) HRESULT; |
lib/std/os/windows/sublang.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const NEUTRAL = 0x00; |
| 2 | 7 | pub const DEFAULT = 0x01; |
| 3 | 8 | pub const SYS_DEFAULT = 0x02; |
lib/std/os/windows/user32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | // PM |
lib/std/os/windows/win32error.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d |
| 2 | 7 | pub const Win32Error = extern enum(u16) { |
| 3 | 8 | /// The operation completed successfully. |
lib/std/os/windows/ws2_32.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | usingnamespace @import("bits.zig"); |
| 2 | 7 | |
| 3 | 8 | pub const SOCKET = *@Type(.Opaque); |
lib/std/packed_int_array.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const debug = std.debug; |
lib/std/pdb.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std.zig"); |
| 3 | 8 | const io = std.io; |
lib/std/priority_queue.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const Allocator = std.mem.Allocator; |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/process.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const os = std.os; |
lib/std/progress.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const windows = std.os.windows; |
| 3 | 8 | const testing = std.testing; |
lib/std/rand.zig+7-2| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // The engines provided here should be initialized from an external source. For now, randomBytes |
| 2 | 7 | // from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using |
| 3 | 8 | // a normal PRNG will be faster and use substantially less stack space. |
| ... | ... | @@ -732,12 +737,12 @@ test "xoroshiro sequence" { |
| 732 | 737 | // CSPRNG |
| 733 | 738 | pub const Gimli = struct { |
| 734 | 739 | random: Random, |
| 735 | state: std.crypto.gimli.State, | |
| 740 | state: std.crypto.core.Gimli, | |
| 736 | 741 | |
| 737 | 742 | pub fn init(init_s: u64) Gimli { |
| 738 | 743 | var self = Gimli{ |
| 739 | 744 | .random = Random{ .fillFn = fill }, |
| 740 | .state = std.crypto.gimli.State{ | |
| 745 | .state = std.crypto.core.Gimli{ | |
| 741 | 746 | .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4), |
| 742 | 747 | }, |
| 743 | 748 | }; |
lib/std/rand/ziggurat.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Implements ZIGNOR [1]. |
| 2 | 7 | // |
| 3 | 8 | // [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*] |
lib/std/rb.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/reset_event.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const testing = std.testing; |
lib/std/segmented_list.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/sort.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/special/build_runner.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const root = @import("@build"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const builtin = @import("builtin"); |
lib/std/special/c.zig+6-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // This is Zig's multi-target implementation of libc. |
| 2 | 7 | // When builtin.link_libc is true, we need to export all the functions and |
| 3 | 8 | // provide an entire C API. |
| ... | ... | @@ -35,7 +40,7 @@ comptime { |
| 35 | 40 | } |
| 36 | 41 | } |
| 37 | 42 | |
| 38 | extern var _fltused: c_int = 1; | |
| 43 | var _fltused: c_int = 1; | |
| 39 | 44 | |
| 40 | 45 | extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 41 | 46 | fn wasm_start() callconv(.C) void { |
lib/std/special/compiler_rt.zig+6-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const is_test = builtin.is_test; |
| ... | ... | @@ -335,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn { |
| 335 | 340 | @panic("stack smashing detected"); |
| 336 | 341 | } |
| 337 | 342 | |
| 338 | extern var __stack_chk_guard: usize = blk: { | |
| 343 | var __stack_chk_guard: usize = blk: { | |
| 339 | 344 | var buf = [1]u8{0} ** @sizeOf(usize); |
| 340 | 345 | buf[@sizeOf(usize) - 1] = 255; |
| 341 | 346 | buf[@sizeOf(usize) - 2] = '\n'; |
lib/std/special/compiler_rt/addXf3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc |
lib/std/special/compiler_rt/addXf3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c |
lib/std/special/compiler_rt/arm.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // ARM specific builtins |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/ashldi3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __ashldi3 = @import("shift.zig").__ashldi3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/ashlti3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __ashlti3 = @import("shift.zig").__ashlti3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/ashrdi3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __ashrdi3 = @import("shift.zig").__ashrdi3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/ashrti3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __ashrti3 = @import("shift.zig").__ashrti3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/atomics.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 |
lib/std/special/compiler_rt/aulldiv.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 { |
lib/std/special/compiler_rt/aullrem.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { |
lib/std/special/compiler_rt/clear_cache.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const arch = std.builtin.cpu.arch; |
| 3 | 8 | const os = std.builtin.os.tag; |
lib/std/special/compiler_rt/clzsi2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | fn __clzsi2_generic(a: i32) callconv(.C) i32 { |
lib/std/special/compiler_rt/clzsi2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const clzsi2 = @import("clzsi2.zig"); |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/compareXf2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c |
lib/std/special/compiler_rt/comparedf2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparedf2_test.c |
lib/std/special/compiler_rt/comparesf2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparesf2_test.c |
lib/std/special/compiler_rt/divdf3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c |
lib/std/special/compiler_rt/divdf3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c |
lib/std/special/compiler_rt/divsf3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c |
lib/std/special/compiler_rt/divsf3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c |
lib/std/special/compiler_rt/divtf3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/divtf3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const math = std.math; |
| 3 | 8 | const testing = std.testing; |
lib/std/special/compiler_rt/divti3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const udivmod = @import("udivmod.zig").udivmod; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/divti3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __divti3 = @import("divti3.zig").__divti3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/extendXfYf2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const is_test = builtin.is_test; |
lib/std/special/compiler_rt/extendXfYf2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; |
| 3 | 8 | const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; |
lib/std/special/compiler_rt/fixdfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixdfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixdfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixdfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixdfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixdfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixdfti = @import("fixdfti.zig").__fixdfti; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixint.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const is_test = @import("builtin").is_test; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixint_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const is_test = @import("builtin").is_test; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixsfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixsfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixsfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixsfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixsfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixsfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixsfti = @import("fixsfti.zig").__fixsfti; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixtfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixtfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixtfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixtfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixtfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixint = @import("fixint.zig").fixint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixtfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixtfti = @import("fixtfti.zig").__fixtfti; |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const math = std.math; |
lib/std/special/compiler_rt/fixuint.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const is_test = @import("builtin").is_test; |
| 2 | 7 | const Log2Int = @import("std").math.Log2Int; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunsdfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunssfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfdi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfdi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfsi.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfsi_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfti.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const fixuint = @import("fixuint.zig").fixuint; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/fixunstfti_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatdidf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 |
lib/std/special/compiler_rt/floatdidf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatdidf = @import("floatdidf.zig").__floatdidf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatditf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatditf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatditf = @import("floatditf.zig").__floatditf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatsiXf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/special/compiler_rt/floattidf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floattidf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floattidf = @import("floattidf.zig").__floattidf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floattisf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floattisf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floattisf = @import("floattisf.zig").__floattisf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floattitf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floattitf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floattitf = @import("floattitf.zig").__floattitf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatundidf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 |
lib/std/special/compiler_rt/floatundidf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatundidf = @import("floatundidf.zig").__floatundidf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatundisf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/special/compiler_rt/floatunditf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatunditf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatunditf = @import("floatunditf.zig").__floatunditf; |
| 2 | 7 | |
| 3 | 8 | fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void { |
lib/std/special/compiler_rt/floatunsidf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/special/compiler_rt/floatunsisf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/special/compiler_rt/floatunsitf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatunsitf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; |
| 2 | 7 | |
| 3 | 8 | fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void { |
lib/std/special/compiler_rt/floatuntidf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatuntidf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatuntisf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatuntisf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/floatuntitf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 | const std = @import("std"); |
lib/std/special/compiler_rt/floatuntitf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/int.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Builtin functions that operate on integer types |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const testing = @import("std").testing; |
lib/std/special/compiler_rt/lshrdi3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __lshrdi3 = @import("shift.zig").__lshrdi3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/lshrti3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __lshrti3 = @import("shift.zig").__lshrti3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/modti3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c |
lib/std/special/compiler_rt/modti3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __modti3 = @import("modti3.zig").__modti3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/mulXf3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc |
lib/std/special/compiler_rt/mulXf3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Ported from: |
| 2 | 7 | // |
| 3 | 8 | // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c |
lib/std/special/compiler_rt/muldi3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | // Ported from |
lib/std/special/compiler_rt/muldi3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __muldi3 = @import("muldi3.zig").__muldi3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/mulodi4.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const compiler_rt = @import("../compiler_rt.zig"); |
| 3 | 8 | const maxInt = std.math.maxInt; |
lib/std/special/compiler_rt/mulodi4_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __mulodi4 = @import("mulodi4.zig").__mulodi4; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/muloti4.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const compiler_rt = @import("../compiler_rt.zig"); |
| 3 | 8 |
lib/std/special/compiler_rt/muloti4_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __muloti4 = @import("muloti4.zig").__muloti4; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/multi3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const compiler_rt = @import("../compiler_rt.zig"); |
| 3 | 8 |
lib/std/special/compiler_rt/multi3_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __multi3 = @import("multi3.zig").__multi3; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/negXf2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | pub fn __negsf2(a: f32) callconv(.C) f32 { |
lib/std/special/compiler_rt/popcountdi2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const compiler_rt = @import("../compiler_rt.zig"); |
| 3 | 8 |
lib/std/special/compiler_rt/popcountdi2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2; |
| 2 | 7 | const testing = @import("std").testing; |
| 3 | 8 |
lib/std/special/compiler_rt/shift.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const Log2Int = std.math.Log2Int; |
lib/std/special/compiler_rt/stack_probe.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | |
| 3 | 8 | // Zig's own stack-probe routine (available only on x86 and x86_64) |
lib/std/special/compiler_rt/truncXfYf2.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | pub fn __truncsfhf2(a: f32) callconv(.C) u16 { |
lib/std/special/compiler_rt/truncXfYf2_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; |
| 2 | 7 | |
| 3 | 8 | fn test__truncsfhf2(a: u32, expected: u16) void { |
lib/std/special/compiler_rt/udivmod.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const is_test = builtin.is_test; |
| 3 | 8 |
lib/std/special/compiler_rt/udivmoddi4_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Disable formatting to avoid unnecessary source repository bloat. |
| 2 | 7 | // zig fmt: off |
| 3 | 8 | const __udivmoddi4 = @import("int.zig").__udivmoddi4; |
lib/std/special/compiler_rt/udivmodti4.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const udivmod = @import("udivmod.zig").udivmod; |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const compiler_rt = @import("../compiler_rt.zig"); |
lib/std/special/compiler_rt/udivmodti4_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // Disable formatting to avoid unnecessary source repository bloat. |
| 2 | 7 | // zig fmt: off |
| 3 | 8 | const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; |
lib/std/special/compiler_rt/udivti3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const udivmodti4 = @import("udivmodti4.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/special/compiler_rt/umodti3.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const udivmodti4 = @import("udivmodti4.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const compiler_rt = @import("../compiler_rt.zig"); |
lib/std/special/init-exe/build.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const Builder = @import("std").build.Builder; |
| 2 | 7 | |
| 3 | 8 | pub fn build(b: *Builder) void { |
lib/std/special/init-exe/src/main.zig+6-1| ... | ... | @@ -1,5 +1,10 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | pub fn main() anyerror!void { |
| 4 | std.debug.warn("All your codebase are belong to us.\n", .{}); | |
| 9 | std.log.info("All your codebase are belong to us.", .{}); | |
| 5 | 10 | } |
lib/std/special/init-lib/build.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const Builder = @import("std").build.Builder; |
| 2 | 7 | |
| 3 | 8 | pub fn build(b: *Builder) void { |
lib/std/special/init-lib/src/main.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 |
lib/std/special/test_runner.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const io = std.io; |
| 3 | 8 | const builtin = @import("builtin"); |
lib/std/spinlock.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 |
lib/std/start.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | // This file is included in the compilation unit when exporting an executable. |
| 2 | 7 | |
| 3 | 8 | const root = @import("root"); |
lib/std/start_windows_tls.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 |
lib/std/std.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | pub const ArrayList = @import("array_list.zig").ArrayList; |
| 2 | 7 | pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned; |
| 3 | 8 | pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged; |
lib/std/target.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const builtin = std.builtin; |
lib/std/target/aarch64.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/amdgpu.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/arm.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/avr.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/bpf.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/hexagon.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/mips.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/msp430.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/nvptx.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/powerpc.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/riscv.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/sparc.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/systemz.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/wasm.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/target/x86.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const CpuFeature = std.Target.Cpu.Feature; |
| 3 | 8 | const CpuModel = std.Target.Cpu.Model; |
lib/std/testing.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const print = std.debug.print; |
| 3 | 8 |
lib/std/testing/failing_allocator.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
lib/std/thread.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const os = std.os; |
lib/std/time.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const builtin = std.builtin; |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/time/epoch.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | //! Epoch reference times in terms of their difference from |
| 2 | 7 | //! UTC 1970-01-01 in seconds. |
| 3 | 8 |
lib/std/unicode.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("./std.zig"); |
| 2 | 7 | const builtin = @import("builtin"); |
| 3 | 8 | const assert = std.debug.assert; |
lib/std/unicode/throughput_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std"); |
| 3 | 8 |
lib/std/valgrind.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const builtin = @import("builtin"); |
| 2 | 7 | const std = @import("std.zig"); |
| 3 | 8 | const math = std.math; |
lib/std/valgrind/callgrind.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const valgrind = std.valgrind; |
| 3 | 8 |
lib/std/valgrind/memcheck.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const testing = std.testing; |
| 3 | 8 | const valgrind = std.valgrind; |
lib/std/zig.zig+115-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std.zig"); |
| 2 | 7 | const tokenizer = @import("zig/tokenizer.zig"); |
| 3 | 8 | |
| ... | ... | @@ -21,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash { |
| 21 | 26 | std.mem.copy(u8, &out, src); |
| 22 | 27 | std.mem.set(u8, out[src.len..], 0); |
| 23 | 28 | } else { |
| 24 | std.crypto.Blake3.hash(src, &out); | |
| 29 | std.crypto.hash.Blake3.hash(src, &out, .{}); | |
| 25 | 30 | } |
| 26 | 31 | return out; |
| 27 | 32 | } |
| ... | ... | @@ -80,6 +85,115 @@ pub fn binNameAlloc( |
| 80 | 85 | } |
| 81 | 86 | } |
| 82 | 87 | |
| 88 | /// Only validates escape sequence characters. | |
| 89 | /// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between. | |
| 90 | pub fn parseCharLiteral( | |
| 91 | slice: []const u8, | |
| 92 | bad_index: *usize, // populated if error.InvalidCharacter is returned | |
| 93 | ) error{InvalidCharacter}!u32 { | |
| 94 | std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\''); | |
| 95 | ||
| 96 | if (slice[1] == '\\') { | |
| 97 | switch (slice[2]) { | |
| 98 | 'n' => return '\n', | |
| 99 | 'r' => return '\r', | |
| 100 | '\\' => return '\\', | |
| 101 | 't' => return '\t', | |
| 102 | '\'' => return '\'', | |
| 103 | '"' => return '"', | |
| 104 | 'x' => { | |
| 105 | if (slice.len != 6) { | |
| 106 | bad_index.* = slice.len - 2; | |
| 107 | return error.InvalidCharacter; | |
| 108 | } | |
| 109 | var value: u32 = 0; | |
| 110 | for (slice[3..5]) |c, i| { | |
| 111 | switch (c) { | |
| 112 | '0'...'9' => { | |
| 113 | value *= 16; | |
| 114 | value += c - '0'; | |
| 115 | }, | |
| 116 | 'a'...'f' => { | |
| 117 | value *= 16; | |
| 118 | value += c - 'a' + 10; | |
| 119 | }, | |
| 120 | 'A'...'F' => { | |
| 121 | value *= 16; | |
| 122 | value += c - 'A' + 10; | |
| 123 | }, | |
| 124 | else => { | |
| 125 | bad_index.* = 3 + i; | |
| 126 | return error.InvalidCharacter; | |
| 127 | }, | |
| 128 | } | |
| 129 | } | |
| 130 | return value; | |
| 131 | }, | |
| 132 | 'u' => { | |
| 133 | if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') { | |
| 134 | bad_index.* = 2; | |
| 135 | return error.InvalidCharacter; | |
| 136 | } | |
| 137 | var value: u32 = 0; | |
| 138 | for (slice[4 .. slice.len - 2]) |c, i| { | |
| 139 | switch (c) { | |
| 140 | '0'...'9' => { | |
| 141 | value *= 16; | |
| 142 | value += c - '0'; | |
| 143 | }, | |
| 144 | 'a'...'f' => { | |
| 145 | value *= 16; | |
| 146 | value += c - 'a' + 10; | |
| 147 | }, | |
| 148 | 'A'...'F' => { | |
| 149 | value *= 16; | |
| 150 | value += c - 'A' + 10; | |
| 151 | }, | |
| 152 | else => { | |
| 153 | bad_index.* = 4 + i; | |
| 154 | return error.InvalidCharacter; | |
| 155 | }, | |
| 156 | } | |
| 157 | if (value > 0x10ffff) { | |
| 158 | bad_index.* = 4 + i; | |
| 159 | return error.InvalidCharacter; | |
| 160 | } | |
| 161 | } | |
| 162 | return value; | |
| 163 | }, | |
| 164 | else => { | |
| 165 | bad_index.* = 2; | |
| 166 | return error.InvalidCharacter; | |
| 167 | }, | |
| 168 | } | |
| 169 | } | |
| 170 | return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable; | |
| 171 | } | |
| 172 | ||
| 173 | test "parseCharLiteral" { | |
| 174 | var bad_index: usize = undefined; | |
| 175 | std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a'); | |
| 176 | std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä'); | |
| 177 | std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0); | |
| 178 | std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f); | |
| 179 | std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f); | |
| 180 | std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041); | |
| 181 | std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0); | |
| 182 | std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041); | |
| 183 | std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f); | |
| 184 | std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF); | |
| 185 | ||
| 186 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index)); | |
| 187 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index)); | |
| 188 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index)); | |
| 189 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index)); | |
| 190 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index)); | |
| 191 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index)); | |
| 192 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index)); | |
| 193 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index)); | |
| 194 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index)); | |
| 195 | } | |
| 196 | ||
| 83 | 197 | test "" { |
| 84 | 198 | @import("std").meta.refAllDecls(@This()); |
| 85 | 199 | } |
lib/std/zig/ast.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const testing = std.testing; |
lib/std/zig/cross_target.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const Target = std.Target; |
lib/std/zig/parse.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const Allocator = std.mem.Allocator; |
lib/std/zig/parser_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | test "zig fmt: convert var to anytype" { |
| 2 | 7 | // TODO remove in next release cycle |
| 3 | 8 | try testTransform( |
lib/std/zig/perf_test.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 | const warn = std.debug.warn; |
lib/std/zig/render.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 | const mem = std.mem; |
lib/std/zig/string_literal.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const assert = std.debug.assert; |
| 3 | 8 |
lib/std/zig/system.zig+6| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const elf = std.elf; |
| 3 | 8 | const mem = std.mem; |
| ... | ... | @@ -857,6 +862,7 @@ pub const NativeTargetInfo = struct { |
| 857 | 862 | const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) { |
| 858 | 863 | error.OperationAborted => unreachable, // Windows-only |
| 859 | 864 | error.WouldBlock => unreachable, // Did not request blocking mode |
| 865 | error.NotOpenForReading => unreachable, | |
| 860 | 866 | error.SystemResources => return error.SystemResources, |
| 861 | 867 | error.IsDir => return error.UnableToReadElfFile, |
| 862 | 868 | error.BrokenPipe => return error.UnableToReadElfFile, |
lib/std/zig/system/macos.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | |
| 3 | 8 | pub fn version_from_build(build: []const u8) !std.builtin.Version { |
lib/std/zig/system/x86.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("std"); |
| 2 | 7 | const Target = std.Target; |
| 3 | 8 | const CrossTarget = std.zig.CrossTarget; |
lib/std/zig/tokenizer.zig+5| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 1 | 6 | const std = @import("../std.zig"); |
| 2 | 7 | const mem = std.mem; |
| 3 | 8 |
src-self-hosted/Module.zig+412-14| ... | ... | @@ -170,6 +170,9 @@ pub const Decl = struct { |
| 170 | 170 | /// This flag is set when this Decl is added to a check_for_deletion set, and cleared |
| 171 | 171 | /// when removed. |
| 172 | 172 | deletion_flag: bool, |
| 173 | /// Whether the corresponding AST decl has a `pub` keyword. | |
| 174 | is_pub: bool, | |
| 175 | ||
| 173 | 176 | /// An integer that can be checked against the corresponding incrementing |
| 174 | 177 | /// generation field of Module. This is used to determine whether `complete` status |
| 175 | 178 | /// represents pre- or post- re-analysis. |
| ... | ... | @@ -320,6 +323,16 @@ pub const Fn = struct { |
| 320 | 323 | } |
| 321 | 324 | }; |
| 322 | 325 | |
| 326 | pub const Var = struct { | |
| 327 | /// if is_extern == true this is undefined | |
| 328 | init: Value, | |
| 329 | owner_decl: *Decl, | |
| 330 | ||
| 331 | is_extern: bool, | |
| 332 | is_mutable: bool, | |
| 333 | is_threadlocal: bool, | |
| 334 | }; | |
| 335 | ||
| 323 | 336 | pub const Scope = struct { |
| 324 | 337 | tag: Tag, |
| 325 | 338 | |
| ... | ... | @@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1235 | 1248 | }; |
| 1236 | 1249 | defer fn_type_scope.instructions.deinit(self.gpa); |
| 1237 | 1250 | |
| 1251 | decl.is_pub = fn_proto.getTrailer("visib_token") != null; | |
| 1238 | 1252 | const body_node = fn_proto.getTrailer("body_node") orelse |
| 1239 | 1253 | return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); |
| 1240 | 1254 | |
| ... | ... | @@ -1419,8 +1433,213 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1419 | 1433 | } |
| 1420 | 1434 | return type_changed; |
| 1421 | 1435 | }, |
| 1422 | .VarDecl => @panic("TODO var decl"), | |
| 1423 | .Comptime => @panic("TODO comptime decl"), | |
| 1436 | .VarDecl => { | |
| 1437 | const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node); | |
| 1438 | ||
| 1439 | decl.analysis = .in_progress; | |
| 1440 | ||
| 1441 | // We need the memory for the Type to go into the arena for the Decl | |
| 1442 | var decl_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1443 | errdefer decl_arena.deinit(); | |
| 1444 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | |
| 1445 | ||
| 1446 | var block_scope: Scope.Block = .{ | |
| 1447 | .parent = null, | |
| 1448 | .func = null, | |
| 1449 | .decl = decl, | |
| 1450 | .instructions = .{}, | |
| 1451 | .arena = &decl_arena.allocator, | |
| 1452 | }; | |
| 1453 | defer block_scope.instructions.deinit(self.gpa); | |
| 1454 | ||
| 1455 | decl.is_pub = var_decl.getTrailer("visib_token") != null; | |
| 1456 | const is_extern = blk: { | |
| 1457 | const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse | |
| 1458 | break :blk false; | |
| 1459 | if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false; | |
| 1460 | if (var_decl.getTrailer("init_node")) |some| { | |
| 1461 | return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{}); | |
| 1462 | } | |
| 1463 | break :blk true; | |
| 1464 | }; | |
| 1465 | if (var_decl.getTrailer("lib_name")) |lib_name| { | |
| 1466 | assert(is_extern); | |
| 1467 | return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{}); | |
| 1468 | } | |
| 1469 | const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; | |
| 1470 | const is_threadlocal = if (var_decl.getTrailer("thread_local_token")) |some| blk: { | |
| 1471 | if (!is_mutable) { | |
| 1472 | return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); | |
| 1473 | } | |
| 1474 | break :blk true; | |
| 1475 | } else false; | |
| 1476 | assert(var_decl.getTrailer("comptime_token") == null); | |
| 1477 | if (var_decl.getTrailer("align_node")) |align_expr| { | |
| 1478 | return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{}); | |
| 1479 | } | |
| 1480 | if (var_decl.getTrailer("section_node")) |sect_expr| { | |
| 1481 | return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); | |
| 1482 | } | |
| 1483 | ||
| 1484 | const explicit_type = blk: { | |
| 1485 | const type_node = var_decl.getTrailer("type_node") orelse | |
| 1486 | break :blk null; | |
| 1487 | ||
| 1488 | // Temporary arena for the zir instructions. | |
| 1489 | var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1490 | defer type_scope_arena.deinit(); | |
| 1491 | var type_scope: Scope.GenZIR = .{ | |
| 1492 | .decl = decl, | |
| 1493 | .arena = &type_scope_arena.allocator, | |
| 1494 | .parent = decl.scope, | |
| 1495 | }; | |
| 1496 | defer type_scope.instructions.deinit(self.gpa); | |
| 1497 | ||
| 1498 | const src = tree.token_locs[type_node.firstToken()].start; | |
| 1499 | const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ | |
| 1500 | .ty = Type.initTag(.type), | |
| 1501 | .val = Value.initTag(.type_type), | |
| 1502 | }); | |
| 1503 | const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); | |
| 1504 | _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type); | |
| 1505 | ||
| 1506 | break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ | |
| 1507 | .instructions = type_scope.instructions.items, | |
| 1508 | }); | |
| 1509 | }; | |
| 1510 | ||
| 1511 | var var_type: Type = undefined; | |
| 1512 | const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: { | |
| 1513 | var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1514 | defer gen_scope_arena.deinit(); | |
| 1515 | var gen_scope: Scope.GenZIR = .{ | |
| 1516 | .decl = decl, | |
| 1517 | .arena = &gen_scope_arena.allocator, | |
| 1518 | .parent = decl.scope, | |
| 1519 | }; | |
| 1520 | defer gen_scope.instructions.deinit(self.gpa); | |
| 1521 | const src = tree.token_locs[init_node.firstToken()].start; | |
| 1522 | ||
| 1523 | // TODO comptime scope here | |
| 1524 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); | |
| 1525 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); | |
| 1526 | ||
| 1527 | var inner_block: Scope.Block = .{ | |
| 1528 | .parent = null, | |
| 1529 | .func = null, | |
| 1530 | .decl = decl, | |
| 1531 | .instructions = .{}, | |
| 1532 | .arena = &gen_scope_arena.allocator, | |
| 1533 | }; | |
| 1534 | defer inner_block.instructions.deinit(self.gpa); | |
| 1535 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); | |
| 1536 | ||
| 1537 | for (inner_block.instructions.items) |inst| { | |
| 1538 | if (inst.castTag(.ret)) |ret| { | |
| 1539 | const coerced = if (explicit_type) |some| | |
| 1540 | try self.coerce(&inner_block.base, some, ret.operand) | |
| 1541 | else | |
| 1542 | ret.operand; | |
| 1543 | const val = coerced.value() orelse | |
| 1544 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | |
| 1545 | ||
| 1546 | var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); | |
| 1547 | break :blk try val.copy(block_scope.arena); | |
| 1548 | } else { | |
| 1549 | return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); | |
| 1550 | } | |
| 1551 | } | |
| 1552 | unreachable; | |
| 1553 | } else if (!is_extern) { | |
| 1554 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); | |
| 1555 | } else if (explicit_type) |some| blk: { | |
| 1556 | var_type = some; | |
| 1557 | break :blk null; | |
| 1558 | } else { | |
| 1559 | return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); | |
| 1560 | }; | |
| 1561 | ||
| 1562 | if (is_mutable and !var_type.isValidVarType(is_extern)) { | |
| 1563 | return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type}); | |
| 1564 | } | |
| 1565 | ||
| 1566 | var type_changed = true; | |
| 1567 | if (decl.typedValueManaged()) |tvm| { | |
| 1568 | type_changed = !tvm.typed_value.ty.eql(var_type); | |
| 1569 | ||
| 1570 | tvm.deinit(self.gpa); | |
| 1571 | } | |
| 1572 | ||
| 1573 | const new_variable = try decl_arena.allocator.create(Var); | |
| 1574 | const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); | |
| 1575 | new_variable.* = .{ | |
| 1576 | .owner_decl = decl, | |
| 1577 | .init = value orelse undefined, | |
| 1578 | .is_extern = is_extern, | |
| 1579 | .is_mutable = is_mutable, | |
| 1580 | .is_threadlocal = is_threadlocal, | |
| 1581 | }; | |
| 1582 | var_payload.* = .{ .variable = new_variable }; | |
| 1583 | ||
| 1584 | decl_arena_state.* = decl_arena.state; | |
| 1585 | decl.typed_value = .{ | |
| 1586 | .most_recent = .{ | |
| 1587 | .typed_value = .{ | |
| 1588 | .ty = var_type, | |
| 1589 | .val = Value.initPayload(&var_payload.base), | |
| 1590 | }, | |
| 1591 | .arena = decl_arena_state, | |
| 1592 | }, | |
| 1593 | }; | |
| 1594 | decl.analysis = .complete; | |
| 1595 | decl.generation = self.generation; | |
| 1596 | ||
| 1597 | if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { | |
| 1598 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { | |
| 1599 | const export_src = tree.token_locs[maybe_export_token].start; | |
| 1600 | const name_loc = tree.token_locs[var_decl.name_token]; | |
| 1601 | const name = tree.tokenSliceLoc(name_loc); | |
| 1602 | // The scope needs to have the decl in it. | |
| 1603 | try self.analyzeExport(&block_scope.base, export_src, name, decl); | |
| 1604 | } | |
| 1605 | } | |
| 1606 | return type_changed; | |
| 1607 | }, | |
| 1608 | .Comptime => { | |
| 1609 | const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node); | |
| 1610 | ||
| 1611 | decl.analysis = .in_progress; | |
| 1612 | ||
| 1613 | // A comptime decl does not store any value so we can just deinit this arena after analysis is done. | |
| 1614 | var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 1615 | defer analysis_arena.deinit(); | |
| 1616 | var gen_scope: Scope.GenZIR = .{ | |
| 1617 | .decl = decl, | |
| 1618 | .arena = &analysis_arena.allocator, | |
| 1619 | .parent = decl.scope, | |
| 1620 | }; | |
| 1621 | defer gen_scope.instructions.deinit(self.gpa); | |
| 1622 | ||
| 1623 | // TODO comptime scope here | |
| 1624 | _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); | |
| 1625 | ||
| 1626 | var block_scope: Scope.Block = .{ | |
| 1627 | .parent = null, | |
| 1628 | .func = null, | |
| 1629 | .decl = decl, | |
| 1630 | .instructions = .{}, | |
| 1631 | .arena = &analysis_arena.allocator, | |
| 1632 | }; | |
| 1633 | defer block_scope.instructions.deinit(self.gpa); | |
| 1634 | ||
| 1635 | _ = try zir_sema.analyzeBody(self, &block_scope.base, .{ | |
| 1636 | .instructions = gen_scope.instructions.items, | |
| 1637 | }); | |
| 1638 | ||
| 1639 | decl.analysis = .complete; | |
| 1640 | decl.generation = self.generation; | |
| 1641 | return true; | |
| 1642 | }, | |
| 1424 | 1643 | .Use => @panic("TODO usingnamespace decl"), |
| 1425 | 1644 | else => unreachable, |
| 1426 | 1645 | } |
| ... | ... | @@ -1583,11 +1802,53 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1583 | 1802 | } |
| 1584 | 1803 | } |
| 1585 | 1804 | } |
| 1805 | } else if (src_decl.castTag(.VarDecl)) |var_decl| { | |
| 1806 | const name_loc = tree.token_locs[var_decl.name_token]; | |
| 1807 | const name = tree.tokenSliceLoc(name_loc); | |
| 1808 | const name_hash = root_scope.fullyQualifiedNameHash(name); | |
| 1809 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); | |
| 1810 | if (self.decl_table.get(name_hash)) |decl| { | |
| 1811 | // Update the AST Node index of the decl, even if its contents are unchanged, it may | |
| 1812 | // have been re-ordered. | |
| 1813 | decl.src_index = decl_i; | |
| 1814 | if (deleted_decls.remove(decl) == null) { | |
| 1815 | decl.analysis = .sema_failure; | |
| 1816 | const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name}); | |
| 1817 | errdefer err_msg.destroy(self.gpa); | |
| 1818 | try self.failed_decls.putNoClobber(self.gpa, decl, err_msg); | |
| 1819 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { | |
| 1820 | try self.markOutdatedDecl(decl); | |
| 1821 | decl.contents_hash = contents_hash; | |
| 1822 | } | |
| 1823 | } else { | |
| 1824 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1825 | root_scope.decls.appendAssumeCapacity(new_decl); | |
| 1826 | if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { | |
| 1827 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { | |
| 1828 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | |
| 1829 | } | |
| 1830 | } | |
| 1831 | } | |
| 1832 | } else if (src_decl.castTag(.Comptime)) |comptime_node| { | |
| 1833 | const name_index = self.getNextAnonNameIndex(); | |
| 1834 | const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index}); | |
| 1835 | defer self.gpa.free(name); | |
| 1836 | ||
| 1837 | const name_hash = root_scope.fullyQualifiedNameHash(name); | |
| 1838 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); | |
| 1839 | ||
| 1840 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1841 | root_scope.decls.appendAssumeCapacity(new_decl); | |
| 1842 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | |
| 1843 | } else if (src_decl.castTag(.ContainerField)) |container_field| { | |
| 1844 | log.err("TODO: analyze container field", .{}); | |
| 1845 | } else if (src_decl.castTag(.TestDecl)) |test_decl| { | |
| 1846 | log.err("TODO: analyze test decl", .{}); | |
| 1847 | } else if (src_decl.castTag(.Use)) |use_decl| { | |
| 1848 | log.err("TODO: analyze usingnamespace decl", .{}); | |
| 1586 | 1849 | } else { |
| 1587 | std.debug.panic("TODO: analyzeRootSrcFile {}", .{src_decl.tag}); | |
| 1850 | unreachable; | |
| 1588 | 1851 | } |
| 1589 | // TODO also look for global variable declarations | |
| 1590 | // TODO also look for comptime blocks and exported globals | |
| 1591 | 1852 | } |
| 1592 | 1853 | // Handle explicitly deleted decls from the source code. Not to be confused |
| 1593 | 1854 | // with when we delete decls because they are no longer referenced. |
| ... | ... | @@ -1790,6 +2051,7 @@ fn allocateNewDecl( |
| 1790 | 2051 | .wasm => .{ .wasm = null }, |
| 1791 | 2052 | }, |
| 1792 | 2053 | .generation = 0, |
| 2054 | .is_pub = false, | |
| 1793 | 2055 | }; |
| 1794 | 2056 | return new_decl; |
| 1795 | 2057 | } |
| ... | ... | @@ -2209,20 +2471,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn |
| 2209 | 2471 | }; |
| 2210 | 2472 | |
| 2211 | 2473 | const decl_tv = try decl.typedValue(); |
| 2212 | const ty_payload = try scope.arena().create(Type.Payload.Pointer); | |
| 2213 | ty_payload.* = .{ | |
| 2214 | .base = .{ .tag = .single_const_pointer }, | |
| 2215 | .pointee_type = decl_tv.ty, | |
| 2216 | }; | |
| 2474 | if (decl_tv.val.tag() == .variable) { | |
| 2475 | return self.analyzeVarRef(scope, src, decl_tv); | |
| 2476 | } | |
| 2477 | const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One); | |
| 2217 | 2478 | const val_payload = try scope.arena().create(Value.Payload.DeclRef); |
| 2218 | 2479 | val_payload.* = .{ .decl = decl }; |
| 2219 | 2480 | |
| 2220 | 2481 | return self.constInst(scope, src, .{ |
| 2221 | .ty = Type.initPayload(&ty_payload.base), | |
| 2482 | .ty = ty, | |
| 2222 | 2483 | .val = Value.initPayload(&val_payload.base), |
| 2223 | 2484 | }); |
| 2224 | 2485 | } |
| 2225 | 2486 | |
| 2487 | fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { | |
| 2488 | const variable = tv.val.cast(Value.Payload.Variable).?.variable; | |
| 2489 | ||
| 2490 | const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One); | |
| 2491 | if (!variable.is_mutable and !variable.is_extern) { | |
| 2492 | const val_payload = try scope.arena().create(Value.Payload.RefVal); | |
| 2493 | val_payload.* = .{ .val = variable.init }; | |
| 2494 | return self.constInst(scope, src, .{ | |
| 2495 | .ty = ty, | |
| 2496 | .val = Value.initPayload(&val_payload.base), | |
| 2497 | }); | |
| 2498 | } | |
| 2499 | ||
| 2500 | const b = try self.requireRuntimeBlock(scope, src); | |
| 2501 | const inst = try b.arena.create(Inst.VarPtr); | |
| 2502 | inst.* = .{ | |
| 2503 | .base = .{ | |
| 2504 | .tag = .varptr, | |
| 2505 | .ty = ty, | |
| 2506 | .src = src, | |
| 2507 | }, | |
| 2508 | .variable = variable, | |
| 2509 | }; | |
| 2510 | try b.instructions.append(self.gpa, &inst.base); | |
| 2511 | return &inst.base; | |
| 2512 | } | |
| 2513 | ||
| 2226 | 2514 | pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { |
| 2227 | 2515 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| 2228 | 2516 | .Pointer => ptr.ty.elemType(), |
| ... | ... | @@ -2523,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst |
| 2523 | 2811 | |
| 2524 | 2812 | // T to ?T |
| 2525 | 2813 | if (dest_type.zigTypeTag() == .Optional) { |
| 2526 | var buf: Type.Payload.Pointer = undefined; | |
| 2814 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2527 | 2815 | const child_type = dest_type.optionalChild(&buf); |
| 2528 | 2816 | if (child_type.eql(inst.ty)) { |
| 2529 | 2817 | return self.wrapOptional(scope, dest_type, inst); |
| ... | ... | @@ -2902,15 +3190,125 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: |
| 2902 | 3190 | return Value.initPayload(val_payload); |
| 2903 | 3191 | } |
| 2904 | 3192 | |
| 2905 | pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type { | |
| 3193 | pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { | |
| 3194 | if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { | |
| 3195 | return Type.initTag(.const_slice_u8); | |
| 3196 | } | |
| 3197 | // TODO stage1 type inference bug | |
| 3198 | const T = Type.Tag; | |
| 3199 | ||
| 3200 | const type_payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 3201 | type_payload.* = .{ | |
| 3202 | .base = .{ | |
| 3203 | .tag = switch (size) { | |
| 3204 | .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, | |
| 3205 | .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, | |
| 3206 | .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, | |
| 3207 | .Slice => if (mutable) T.mut_slice else T.const_slice, | |
| 3208 | }, | |
| 3209 | }, | |
| 3210 | .pointee_type = elem_ty, | |
| 3211 | }; | |
| 3212 | return Type.initPayload(&type_payload.base); | |
| 3213 | } | |
| 3214 | ||
| 3215 | pub fn ptrType( | |
| 3216 | self: *Module, | |
| 3217 | scope: *Scope, | |
| 3218 | src: usize, | |
| 3219 | elem_ty: Type, | |
| 3220 | sentinel: ?Value, | |
| 3221 | @"align": u32, | |
| 3222 | bit_offset: u16, | |
| 3223 | host_size: u16, | |
| 3224 | mutable: bool, | |
| 3225 | @"allowzero": bool, | |
| 3226 | @"volatile": bool, | |
| 3227 | size: std.builtin.TypeInfo.Pointer.Size, | |
| 3228 | ) Allocator.Error!Type { | |
| 3229 | assert(host_size == 0 or bit_offset < host_size * 8); | |
| 3230 | ||
| 3231 | // TODO check if type can be represented by simplePtrType | |
| 2906 | 3232 | const type_payload = try scope.arena().create(Type.Payload.Pointer); |
| 2907 | 3233 | type_payload.* = .{ |
| 2908 | .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, | |
| 2909 | 3234 | .pointee_type = elem_ty, |
| 3235 | .sentinel = sentinel, | |
| 3236 | .@"align" = @"align", | |
| 3237 | .bit_offset = bit_offset, | |
| 3238 | .host_size = host_size, | |
| 3239 | .@"allowzero" = @"allowzero", | |
| 3240 | .mutable = mutable, | |
| 3241 | .@"volatile" = @"volatile", | |
| 3242 | .size = size, | |
| 2910 | 3243 | }; |
| 2911 | 3244 | return Type.initPayload(&type_payload.base); |
| 2912 | 3245 | } |
| 2913 | 3246 | |
| 3247 | pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { | |
| 3248 | return Type.initPayload(switch (child_type.tag()) { | |
| 3249 | .single_const_pointer => blk: { | |
| 3250 | const payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 3251 | payload.* = .{ | |
| 3252 | .base = .{ .tag = .optional_single_const_pointer }, | |
| 3253 | .pointee_type = child_type.elemType(), | |
| 3254 | }; | |
| 3255 | break :blk &payload.base; | |
| 3256 | }, | |
| 3257 | .single_mut_pointer => blk: { | |
| 3258 | const payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 3259 | payload.* = .{ | |
| 3260 | .base = .{ .tag = .optional_single_mut_pointer }, | |
| 3261 | .pointee_type = child_type.elemType(), | |
| 3262 | }; | |
| 3263 | break :blk &payload.base; | |
| 3264 | }, | |
| 3265 | else => blk: { | |
| 3266 | const payload = try scope.arena().create(Type.Payload.Optional); | |
| 3267 | payload.* = .{ | |
| 3268 | .child_type = child_type, | |
| 3269 | }; | |
| 3270 | break :blk &payload.base; | |
| 3271 | }, | |
| 3272 | }); | |
| 3273 | } | |
| 3274 | ||
| 3275 | pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type { | |
| 3276 | if (elem_type.eql(Type.initTag(.u8))) { | |
| 3277 | if (sentinel) |some| { | |
| 3278 | if (some.eql(Value.initTag(.zero))) { | |
| 3279 | const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); | |
| 3280 | payload.* = .{ | |
| 3281 | .len = len, | |
| 3282 | }; | |
| 3283 | return Type.initPayload(&payload.base); | |
| 3284 | } | |
| 3285 | } else { | |
| 3286 | const payload = try scope.arena().create(Type.Payload.Array_u8); | |
| 3287 | payload.* = .{ | |
| 3288 | .len = len, | |
| 3289 | }; | |
| 3290 | return Type.initPayload(&payload.base); | |
| 3291 | } | |
| 3292 | } | |
| 3293 | ||
| 3294 | if (sentinel) |some| { | |
| 3295 | const payload = try scope.arena().create(Type.Payload.ArraySentinel); | |
| 3296 | payload.* = .{ | |
| 3297 | .len = len, | |
| 3298 | .sentinel = some, | |
| 3299 | .elem_type = elem_type, | |
| 3300 | }; | |
| 3301 | return Type.initPayload(&payload.base); | |
| 3302 | } | |
| 3303 | ||
| 3304 | const payload = try scope.arena().create(Type.Payload.Array); | |
| 3305 | payload.* = .{ | |
| 3306 | .len = len, | |
| 3307 | .elem_type = elem_type, | |
| 3308 | }; | |
| 3309 | return Type.initPayload(&payload.base); | |
| 3310 | } | |
| 3311 | ||
| 2914 | 3312 | pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { |
| 2915 | 3313 | const zir_module = scope.namespace(); |
| 2916 | 3314 | const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source"); |
src-self-hosted/astgen.zig+384-42| ... | ... | @@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) { |
| 20 | 20 | /// The expression must generate a pointer rather than a value. For example, the left hand side |
| 21 | 21 | /// of an assignment uses an "LValue" result location. |
| 22 | 22 | lvalue, |
| 23 | /// The expression must generate a pointer | |
| 24 | ref, | |
| 23 | 25 | /// The expression will be type coerced into this type, but it will be evaluated as an rvalue. |
| 24 | 26 | ty: *zir.Inst, |
| 25 | 27 | /// The expression must store its result into this typed pointer. |
| ... | ... | @@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z |
| 46 | 48 | |
| 47 | 49 | /// Turn Zig AST into untyped ZIR istructions. |
| 48 | 50 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { |
| 51 | if (rl == .lvalue) { | |
| 52 | switch (node.tag) { | |
| 53 | .Root => unreachable, | |
| 54 | .Use => unreachable, | |
| 55 | .TestDecl => unreachable, | |
| 56 | .DocComment => unreachable, | |
| 57 | .VarDecl => unreachable, | |
| 58 | .SwitchCase => unreachable, | |
| 59 | .SwitchElse => unreachable, | |
| 60 | .Else => unreachable, | |
| 61 | .Payload => unreachable, | |
| 62 | .PointerPayload => unreachable, | |
| 63 | .PointerIndexPayload => unreachable, | |
| 64 | .ErrorTag => unreachable, | |
| 65 | .FieldInitializer => unreachable, | |
| 66 | .ContainerField => unreachable, | |
| 67 | ||
| 68 | .Assign, | |
| 69 | .AssignBitAnd, | |
| 70 | .AssignBitOr, | |
| 71 | .AssignBitShiftLeft, | |
| 72 | .AssignBitShiftRight, | |
| 73 | .AssignBitXor, | |
| 74 | .AssignDiv, | |
| 75 | .AssignSub, | |
| 76 | .AssignSubWrap, | |
| 77 | .AssignMod, | |
| 78 | .AssignAdd, | |
| 79 | .AssignAddWrap, | |
| 80 | .AssignMul, | |
| 81 | .AssignMulWrap, | |
| 82 | .Add, | |
| 83 | .AddWrap, | |
| 84 | .Sub, | |
| 85 | .SubWrap, | |
| 86 | .Mul, | |
| 87 | .MulWrap, | |
| 88 | .Div, | |
| 89 | .Mod, | |
| 90 | .BitAnd, | |
| 91 | .BitOr, | |
| 92 | .BitShiftLeft, | |
| 93 | .BitShiftRight, | |
| 94 | .BitXor, | |
| 95 | .BangEqual, | |
| 96 | .EqualEqual, | |
| 97 | .GreaterThan, | |
| 98 | .GreaterOrEqual, | |
| 99 | .LessThan, | |
| 100 | .LessOrEqual, | |
| 101 | .ArrayCat, | |
| 102 | .ArrayMult, | |
| 103 | .BoolAnd, | |
| 104 | .BoolOr, | |
| 105 | .Asm, | |
| 106 | .StringLiteral, | |
| 107 | .IntegerLiteral, | |
| 108 | .Call, | |
| 109 | .Unreachable, | |
| 110 | .Return, | |
| 111 | .If, | |
| 112 | .While, | |
| 113 | .BoolNot, | |
| 114 | .AddressOf, | |
| 115 | .FloatLiteral, | |
| 116 | .UndefinedLiteral, | |
| 117 | .BoolLiteral, | |
| 118 | .NullLiteral, | |
| 119 | .OptionalType, | |
| 120 | .Block, | |
| 121 | .LabeledBlock, | |
| 122 | .Break, | |
| 123 | .PtrType, | |
| 124 | .GroupedExpression, | |
| 125 | .ArrayType, | |
| 126 | .ArrayTypeSentinel, | |
| 127 | .EnumLiteral, | |
| 128 | .MultilineStringLiteral, | |
| 129 | .CharLiteral, | |
| 130 | .Defer, | |
| 131 | .Catch, | |
| 132 | .ErrorUnion, | |
| 133 | .MergeErrorSets, | |
| 134 | .Range, | |
| 135 | .OrElse, | |
| 136 | .Await, | |
| 137 | .BitNot, | |
| 138 | .Negation, | |
| 139 | .NegationWrap, | |
| 140 | .Resume, | |
| 141 | .Try, | |
| 142 | .SliceType, | |
| 143 | .Slice, | |
| 144 | .ArrayInitializer, | |
| 145 | .ArrayInitializerDot, | |
| 146 | .StructInitializer, | |
| 147 | .StructInitializerDot, | |
| 148 | .Switch, | |
| 149 | .For, | |
| 150 | .Suspend, | |
| 151 | .Continue, | |
| 152 | .AnyType, | |
| 153 | .ErrorType, | |
| 154 | .FnProto, | |
| 155 | .AnyFrameType, | |
| 156 | .ErrorSetDecl, | |
| 157 | .ContainerDecl, | |
| 158 | .Comptime, | |
| 159 | .Nosuspend, | |
| 160 | => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), | |
| 161 | ||
| 162 | // @field can be assigned to | |
| 163 | .BuiltinCall => { | |
| 164 | const call = node.castTag(.BuiltinCall).?; | |
| 165 | const tree = scope.tree(); | |
| 166 | const builtin_name = tree.tokenSlice(call.builtin_token); | |
| 167 | ||
| 168 | if (!mem.eql(u8, builtin_name, "@field")) { | |
| 169 | return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); | |
| 170 | } | |
| 171 | }, | |
| 172 | ||
| 173 | // can be assigned to | |
| 174 | .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {}, | |
| 175 | } | |
| 176 | } | |
| 49 | 177 | switch (node.tag) { |
| 50 | 178 | .Root => unreachable, // Top-level declaration. |
| 51 | 179 | .Use => unreachable, // Top-level declaration. |
| ... | ... | @@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 60 | 188 | .PointerIndexPayload => unreachable, // Handled explicitly. |
| 61 | 189 | .ErrorTag => unreachable, // Handled explicitly. |
| 62 | 190 | .FieldInitializer => unreachable, // Handled explicitly. |
| 191 | .ContainerField => unreachable, // Handled explicitly. | |
| 63 | 192 | |
| 64 | 193 | .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), |
| 65 | 194 | .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)), |
| ... | ... | @@ -100,6 +229,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 100 | 229 | .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat), |
| 101 | 230 | .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul), |
| 102 | 231 | |
| 232 | .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), | |
| 233 | .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), | |
| 234 | ||
| 103 | 235 | .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), |
| 104 | 236 | .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), |
| 105 | 237 | .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), |
| ... | ... | @@ -124,11 +256,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 124 | 256 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?), |
| 125 | 257 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| 126 | 258 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 259 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), | |
| 260 | .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), | |
| 261 | .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), | |
| 262 | .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), | |
| 263 | .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), | |
| 264 | .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), | |
| 265 | .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), | |
| 127 | 266 | |
| 128 | 267 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 129 | 268 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), |
| 130 | .BoolAnd => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolAnd", .{}), | |
| 131 | .BoolOr => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolOr", .{}), | |
| 132 | 269 | .ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}), |
| 133 | 270 | .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}), |
| 134 | 271 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| ... | ... | @@ -139,9 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 139 | 276 | .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), |
| 140 | 277 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), |
| 141 | 278 | .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| 142 | .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}), | |
| 143 | .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}), | |
| 144 | .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}), | |
| 145 | 279 | .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), |
| 146 | 280 | .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), |
| 147 | 281 | .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), |
| ... | ... | @@ -156,15 +290,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 156 | 290 | .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), |
| 157 | 291 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 158 | 292 | .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}), |
| 159 | .EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}), | |
| 160 | .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}), | |
| 161 | .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}), | |
| 162 | .GroupedExpression => return mod.failNode(scope, node, "TODO implement astgen.expr for .GroupedExpression", .{}), | |
| 163 | 293 | .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}), |
| 164 | 294 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 165 | 295 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), |
| 166 | 296 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| 167 | .ContainerField => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerField", .{}), | |
| 168 | 297 | } |
| 169 | 298 | } |
| 170 | 299 | |
| ... | ... | @@ -187,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr |
| 187 | 316 | // proper type inference requires peer type resolution on the block's |
| 188 | 317 | // break operand expressions. |
| 189 | 318 | const branch_rl: ResultLoc = switch (label.result_loc) { |
| 190 | .discard, .none, .ty, .ptr, .lvalue => label.result_loc, | |
| 319 | .discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc, | |
| 191 | 320 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst }, |
| 192 | 321 | }; |
| 193 | 322 | const operand = try expr(mod, parent_scope, branch_rl, rhs); |
| ... | ... | @@ -426,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr |
| 426 | 555 | } |
| 427 | 556 | |
| 428 | 557 | fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { |
| 429 | return expr(mod, scope, .lvalue, node.rhs); | |
| 558 | return expr(mod, scope, .ref, node.rhs); | |
| 430 | 559 | } |
| 431 | 560 | |
| 432 | 561 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { |
| ... | ... | @@ -440,43 +569,67 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn |
| 440 | 569 | return addZIRUnOp(mod, scope, src, .optional_type, operand); |
| 441 | 570 | } |
| 442 | 571 | |
| 572 | fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { | |
| 573 | const tree = scope.tree(); | |
| 574 | const src = tree.token_locs[node.op_token].start; | |
| 575 | return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); | |
| 576 | } | |
| 577 | ||
| 443 | 578 | fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { |
| 444 | 579 | const tree = scope.tree(); |
| 445 | 580 | const src = tree.token_locs[node.op_token].start; |
| 581 | return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) { | |
| 582 | .Asterisk, .AsteriskAsterisk => .One, | |
| 583 | // TODO stage1 type inference bug | |
| 584 | .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { | |
| 585 | .Identifier => .C, | |
| 586 | else => .Many, | |
| 587 | }), | |
| 588 | else => unreachable, | |
| 589 | }); | |
| 590 | } | |
| 591 | ||
| 592 | fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { | |
| 446 | 593 | const meta_type = try addZIRInstConst(mod, scope, src, .{ |
| 447 | 594 | .ty = Type.initTag(.type), |
| 448 | 595 | .val = Value.initTag(.type_type), |
| 449 | 596 | }); |
| 450 | 597 | |
| 451 | const simple = node.ptr_info.allowzero_token == null and | |
| 452 | node.ptr_info.align_info == null and | |
| 453 | node.ptr_info.volatile_token == null and | |
| 454 | node.ptr_info.sentinel == null; | |
| 598 | const simple = ptr_info.allowzero_token == null and | |
| 599 | ptr_info.align_info == null and | |
| 600 | ptr_info.volatile_token == null and | |
| 601 | ptr_info.sentinel == null; | |
| 455 | 602 | |
| 456 | 603 | if (simple) { |
| 457 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 458 | return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null) | |
| 459 | .single_mut_ptr_type | |
| 460 | else | |
| 461 | .single_const_ptr_type, child_type); | |
| 604 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); | |
| 605 | const mutable = ptr_info.const_token == null; | |
| 606 | // TODO stage1 type inference bug | |
| 607 | const T = zir.Inst.Tag; | |
| 608 | return addZIRUnOp(mod, scope, src, switch (size) { | |
| 609 | .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, | |
| 610 | .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, | |
| 611 | .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, | |
| 612 | .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, | |
| 613 | }, child_type); | |
| 462 | 614 | } |
| 463 | 615 | |
| 464 | 616 | var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; |
| 465 | kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; | |
| 466 | if (node.ptr_info.align_info) |some| { | |
| 617 | kw_args.size = size; | |
| 618 | kw_args.@"allowzero" = ptr_info.allowzero_token != null; | |
| 619 | if (ptr_info.align_info) |some| { | |
| 467 | 620 | kw_args.@"align" = try expr(mod, scope, .none, some.node); |
| 468 | 621 | if (some.bit_range) |bit_range| { |
| 469 | 622 | kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); |
| 470 | 623 | kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); |
| 471 | 624 | } |
| 472 | 625 | } |
| 473 | kw_args.@"const" = node.ptr_info.const_token != null; | |
| 474 | kw_args.@"volatile" = node.ptr_info.volatile_token != null; | |
| 475 | if (node.ptr_info.sentinel) |some| { | |
| 626 | kw_args.mutable = ptr_info.const_token == null; | |
| 627 | kw_args.@"volatile" = ptr_info.volatile_token != null; | |
| 628 | if (ptr_info.sentinel) |some| { | |
| 476 | 629 | kw_args.sentinel = try expr(mod, scope, .none, some); |
| 477 | 630 | } |
| 478 | 631 | |
| 479 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 632 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); | |
| 480 | 633 | if (kw_args.sentinel) |some| { |
| 481 | 634 | kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); |
| 482 | 635 | } |
| ... | ... | @@ -484,13 +637,65 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir |
| 484 | 637 | return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); |
| 485 | 638 | } |
| 486 | 639 | |
| 640 | fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { | |
| 641 | const tree = scope.tree(); | |
| 642 | const src = tree.token_locs[node.op_token].start; | |
| 643 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 644 | .ty = Type.initTag(.type), | |
| 645 | .val = Value.initTag(.type_type), | |
| 646 | }); | |
| 647 | const usize_type = try addZIRInstConst(mod, scope, src, .{ | |
| 648 | .ty = Type.initTag(.type), | |
| 649 | .val = Value.initTag(.usize_type), | |
| 650 | }); | |
| 651 | ||
| 652 | // TODO check for [_]T | |
| 653 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); | |
| 654 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 655 | ||
| 656 | return addZIRBinOp(mod, scope, src, .array_type, len, child_type); | |
| 657 | } | |
| 658 | ||
| 659 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { | |
| 660 | const tree = scope.tree(); | |
| 661 | const src = tree.token_locs[node.op_token].start; | |
| 662 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 663 | .ty = Type.initTag(.type), | |
| 664 | .val = Value.initTag(.type_type), | |
| 665 | }); | |
| 666 | const usize_type = try addZIRInstConst(mod, scope, src, .{ | |
| 667 | .ty = Type.initTag(.type), | |
| 668 | .val = Value.initTag(.usize_type), | |
| 669 | }); | |
| 670 | ||
| 671 | // TODO check for [_]T | |
| 672 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); | |
| 673 | const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); | |
| 674 | const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 675 | const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); | |
| 676 | ||
| 677 | return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ | |
| 678 | .len = len, | |
| 679 | .sentinel = sentinel, | |
| 680 | .elem_type = elem_type, | |
| 681 | }, .{}); | |
| 682 | } | |
| 683 | ||
| 684 | fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst { | |
| 685 | const tree = scope.tree(); | |
| 686 | const src = tree.token_locs[node.name].start; | |
| 687 | const name = try identifierTokenString(mod, scope, node.name); | |
| 688 | ||
| 689 | return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{}); | |
| 690 | } | |
| 691 | ||
| 487 | 692 | fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { |
| 488 | 693 | const tree = scope.tree(); |
| 489 | 694 | const src = tree.token_locs[node.rtoken].start; |
| 490 | 695 | |
| 491 | const operand = try expr(mod, scope, .lvalue, node.lhs); | |
| 696 | const operand = try expr(mod, scope, .ref, node.lhs); | |
| 492 | 697 | const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand); |
| 493 | if (rl == .lvalue) return unwrapped_ptr; | |
| 698 | if (rl == .lvalue or rl == .ref) return unwrapped_ptr; | |
| 494 | 699 | |
| 495 | 700 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr)); |
| 496 | 701 | } |
| ... | ... | @@ -568,6 +773,88 @@ fn simpleBinOp( |
| 568 | 773 | return rlWrap(mod, scope, rl, result); |
| 569 | 774 | } |
| 570 | 775 | |
| 776 | fn boolBinOp( | |
| 777 | mod: *Module, | |
| 778 | scope: *Scope, | |
| 779 | rl: ResultLoc, | |
| 780 | infix_node: *ast.Node.SimpleInfixOp, | |
| 781 | ) InnerError!*zir.Inst { | |
| 782 | const tree = scope.tree(); | |
| 783 | const src = tree.token_locs[infix_node.op_token].start; | |
| 784 | const bool_type = try addZIRInstConst(mod, scope, src, .{ | |
| 785 | .ty = Type.initTag(.type), | |
| 786 | .val = Value.initTag(.bool_type), | |
| 787 | }); | |
| 788 | ||
| 789 | var block_scope: Scope.GenZIR = .{ | |
| 790 | .parent = scope, | |
| 791 | .decl = scope.decl().?, | |
| 792 | .arena = scope.arena(), | |
| 793 | .instructions = .{}, | |
| 794 | }; | |
| 795 | defer block_scope.instructions.deinit(mod.gpa); | |
| 796 | ||
| 797 | const lhs = try expr(mod, scope, .{ .ty = bool_type }, infix_node.lhs); | |
| 798 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | |
| 799 | .condition = lhs, | |
| 800 | .then_body = undefined, // populated below | |
| 801 | .else_body = undefined, // populated below | |
| 802 | }, .{}); | |
| 803 | ||
| 804 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 805 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | |
| 806 | }); | |
| 807 | ||
| 808 | var rhs_scope: Scope.GenZIR = .{ | |
| 809 | .parent = scope, | |
| 810 | .decl = block_scope.decl, | |
| 811 | .arena = block_scope.arena, | |
| 812 | .instructions = .{}, | |
| 813 | }; | |
| 814 | defer rhs_scope.instructions.deinit(mod.gpa); | |
| 815 | ||
| 816 | const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, infix_node.rhs); | |
| 817 | _ = try addZIRInst(mod, &rhs_scope.base, src, zir.Inst.Break, .{ | |
| 818 | .block = block, | |
| 819 | .operand = rhs, | |
| 820 | }, .{}); | |
| 821 | ||
| 822 | var const_scope: Scope.GenZIR = .{ | |
| 823 | .parent = scope, | |
| 824 | .decl = block_scope.decl, | |
| 825 | .arena = block_scope.arena, | |
| 826 | .instructions = .{}, | |
| 827 | }; | |
| 828 | defer const_scope.instructions.deinit(mod.gpa); | |
| 829 | ||
| 830 | const is_bool_and = infix_node.base.tag == .BoolAnd; | |
| 831 | _ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{ | |
| 832 | .block = block, | |
| 833 | .operand = try addZIRInstConst(mod, &const_scope.base, src, .{ | |
| 834 | .ty = Type.initTag(.bool), | |
| 835 | .val = if (is_bool_and) Value.initTag(.bool_false) else Value.initTag(.bool_true), | |
| 836 | }), | |
| 837 | }, .{}); | |
| 838 | ||
| 839 | if (is_bool_and) { | |
| 840 | // if lhs // AND | |
| 841 | // break rhs | |
| 842 | // else | |
| 843 | // break false | |
| 844 | condbr.positionals.then_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; | |
| 845 | condbr.positionals.else_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; | |
| 846 | } else { | |
| 847 | // if lhs // OR | |
| 848 | // break true | |
| 849 | // else | |
| 850 | // break rhs | |
| 851 | condbr.positionals.then_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; | |
| 852 | condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; | |
| 853 | } | |
| 854 | ||
| 855 | return rlWrap(mod, scope, rl, &block.base); | |
| 856 | } | |
| 857 | ||
| 571 | 858 | const CondKind = union(enum) { |
| 572 | 859 | bool, |
| 573 | 860 | optional: ?*zir.Inst, |
| ... | ... | @@ -583,13 +870,13 @@ const CondKind = union(enum) { |
| 583 | 870 | return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node); |
| 584 | 871 | }, |
| 585 | 872 | .optional => { |
| 586 | const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); | |
| 873 | const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node); | |
| 587 | 874 | self.* = .{ .optional = cond_ptr }; |
| 588 | 875 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); |
| 589 | 876 | return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result); |
| 590 | 877 | }, |
| 591 | 878 | .err_union => { |
| 592 | const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); | |
| 879 | const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node); | |
| 593 | 880 | self.* = .{ .err_union = err_ptr }; |
| 594 | 881 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); |
| 595 | 882 | return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result); |
| ... | ... | @@ -600,7 +887,11 @@ const CondKind = union(enum) { |
| 600 | 887 | fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { |
| 601 | 888 | if (self == .bool) return &then_scope.base; |
| 602 | 889 | |
| 603 | const payload = payload_node.?.castTag(.PointerPayload).?; | |
| 890 | const payload = payload_node.?.castTag(.PointerPayload) orelse { | |
| 891 | // condition is error union and payload is not explicitly ignored | |
| 892 | _ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?); | |
| 893 | return &then_scope.base; | |
| 894 | }; | |
| 604 | 895 | const is_ptr = payload.ptr_token != null; |
| 605 | 896 | const ident_node = payload.value_symbol.castTag(.Identifier).?; |
| 606 | 897 | |
| ... | ... | @@ -680,7 +971,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 680 | 971 | // proper type inference requires peer type resolution on the if's |
| 681 | 972 | // branches. |
| 682 | 973 | const branch_rl: ResultLoc = switch (rl) { |
| 683 | .discard, .none, .ty, .ptr, .lvalue => rl, | |
| 974 | .discard, .none, .ty, .ptr, .lvalue, .ref => rl, | |
| 684 | 975 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 685 | 976 | }; |
| 686 | 977 | |
| ... | ... | @@ -810,7 +1101,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 810 | 1101 | // proper type inference requires peer type resolution on the while's |
| 811 | 1102 | // branches. |
| 812 | 1103 | const branch_rl: ResultLoc = switch (rl) { |
| 813 | .discard, .none, .ty, .ptr, .lvalue => rl, | |
| 1104 | .discard, .none, .ty, .ptr, .lvalue, .ref => rl, | |
| 814 | 1105 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, |
| 815 | 1106 | }; |
| 816 | 1107 | |
| ... | ... | @@ -941,7 +1232,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 941 | 1232 | .local_ptr => { |
| 942 | 1233 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 943 | 1234 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 944 | if (rl == .lvalue) { | |
| 1235 | if (rl == .lvalue or rl == .ref) { | |
| 945 | 1236 | return local_ptr.ptr; |
| 946 | 1237 | } else { |
| 947 | 1238 | const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); |
| ... | ... | @@ -956,9 +1247,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 956 | 1247 | } |
| 957 | 1248 | |
| 958 | 1249 | if (mod.lookupDeclName(scope, ident_name)) |decl| { |
| 959 | // TODO handle lvalues | |
| 960 | 1250 | const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); |
| 961 | return rlWrap(mod, scope, rl, result); | |
| 1251 | if (rl == .lvalue or rl == .ref) | |
| 1252 | return result; | |
| 1253 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result)); | |
| 962 | 1254 | } |
| 963 | 1255 | |
| 964 | 1256 | return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name}); |
| ... | ... | @@ -983,6 +1275,54 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner |
| 983 | 1275 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); |
| 984 | 1276 | } |
| 985 | 1277 | |
| 1278 | fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst { | |
| 1279 | const tree = scope.tree(); | |
| 1280 | const lines = node.linesConst(); | |
| 1281 | const src = tree.token_locs[lines[0]].start; | |
| 1282 | ||
| 1283 | // line lengths and new lines | |
| 1284 | var len = lines.len - 1; | |
| 1285 | for (lines) |line| { | |
| 1286 | // 2 for the '//' + 1 for '\n' | |
| 1287 | len += tree.tokenSlice(line).len - 3; | |
| 1288 | } | |
| 1289 | ||
| 1290 | const bytes = try scope.arena().alloc(u8, len); | |
| 1291 | var i: usize = 0; | |
| 1292 | for (lines) |line, line_i| { | |
| 1293 | if (line_i != 0) { | |
| 1294 | bytes[i] = '\n'; | |
| 1295 | i += 1; | |
| 1296 | } | |
| 1297 | const slice = tree.tokenSlice(line); | |
| 1298 | mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]); | |
| 1299 | i += slice.len - 3; | |
| 1300 | } | |
| 1301 | ||
| 1302 | return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); | |
| 1303 | } | |
| 1304 | ||
| 1305 | fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst { | |
| 1306 | const tree = scope.tree(); | |
| 1307 | const src = tree.token_locs[node.token].start; | |
| 1308 | const slice = tree.tokenSlice(node.token); | |
| 1309 | ||
| 1310 | var bad_index: usize = undefined; | |
| 1311 | const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { | |
| 1312 | error.InvalidCharacter => { | |
| 1313 | const bad_byte = slice[bad_index]; | |
| 1314 | return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte}); | |
| 1315 | }, | |
| 1316 | }; | |
| 1317 | ||
| 1318 | const int_payload = try scope.arena().create(Value.Payload.Int_u64); | |
| 1319 | int_payload.* = .{ .int = value }; | |
| 1320 | return addZIRInstConst(mod, scope, src, .{ | |
| 1321 | .ty = Type.initTag(.comptime_int), | |
| 1322 | .val = Value.initPayload(&int_payload.base), | |
| 1323 | }); | |
| 1324 | } | |
| 1325 | ||
| 986 | 1326 | fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst { |
| 987 | 1327 | const arena = scope.arena(); |
| 988 | 1328 | const tree = scope.tree(); |
| ... | ... | @@ -1158,7 +1498,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I |
| 1158 | 1498 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1159 | 1499 | return result; |
| 1160 | 1500 | }, |
| 1161 | .lvalue => { | |
| 1501 | .lvalue => unreachable, | |
| 1502 | .ref => { | |
| 1162 | 1503 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 1163 | 1504 | return addZIRUnOp(mod, scope, result.src, .ref, result); |
| 1164 | 1505 | }, |
| ... | ... | @@ -1209,9 +1550,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa |
| 1209 | 1550 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1210 | 1551 | return result; |
| 1211 | 1552 | }, |
| 1212 | .lvalue => { | |
| 1213 | const operand = try expr(mod, scope, .lvalue, params[1]); | |
| 1214 | const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand); | |
| 1553 | .lvalue => unreachable, | |
| 1554 | .ref => { | |
| 1555 | const operand = try expr(mod, scope, .ref, params[1]); | |
| 1556 | const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand); | |
| 1215 | 1557 | return result; |
| 1216 | 1558 | }, |
| 1217 | 1559 | .ty => |result_ty| { |
| ... | ... | @@ -1476,7 +1818,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr |
| 1476 | 1818 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1477 | 1819 | return result; |
| 1478 | 1820 | }, |
| 1479 | .lvalue => { | |
| 1821 | .lvalue, .ref => { | |
| 1480 | 1822 | // We need a pointer but we have a value. |
| 1481 | 1823 | return addZIRUnOp(mod, scope, result.src, .ref, result); |
| 1482 | 1824 | }, |
src-self-hosted/cbe.h deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | #if __STDC_VERSION__ >= 201112L | |
| 2 | #define zig_noreturn _Noreturn | |
| 3 | #elif __GNUC__ | |
| 4 | #define zig_noreturn __attribute__ ((noreturn)) | |
| 5 | #elif _MSC_VER | |
| 6 | #define zig_noreturn __declspec(noreturn) | |
| 7 | #else | |
| 8 | #define zig_noreturn | |
| 9 | #endif | |
| 10 | ||
| 11 | #if __GNUC__ | |
| 12 | #define zig_unreachable() __builtin_unreachable() | |
| 13 | #else | |
| 14 | #define zig_unreachable() | |
| 15 | #endif |
src-self-hosted/codegen.zig+131-100| ... | ... | @@ -59,20 +59,20 @@ pub const GenerateSymbolError = error{ |
| 59 | 59 | }; |
| 60 | 60 | |
| 61 | 61 | pub fn generateSymbol( |
| 62 | bin_file: *link.File.Elf, | |
| 62 | bin_file: *link.File, | |
| 63 | 63 | src: usize, |
| 64 | 64 | typed_value: TypedValue, |
| 65 | 65 | code: *std.ArrayList(u8), |
| 66 | 66 | dbg_line: *std.ArrayList(u8), |
| 67 | 67 | dbg_info: *std.ArrayList(u8), |
| 68 | dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, | |
| 68 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | |
| 69 | 69 | ) GenerateSymbolError!Result { |
| 70 | 70 | const tracy = trace(@src()); |
| 71 | 71 | defer tracy.end(); |
| 72 | 72 | |
| 73 | 73 | switch (typed_value.ty.zigTypeTag()) { |
| 74 | 74 | .Fn => { |
| 75 | switch (bin_file.base.options.target.cpu.arch) { | |
| 75 | switch (bin_file.options.target.cpu.arch) { | |
| 76 | 76 | .wasm32 => unreachable, // has its own code path |
| 77 | 77 | .wasm64 => unreachable, // has its own code path |
| 78 | 78 | //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), |
| ... | ... | @@ -151,7 +151,7 @@ pub fn generateSymbol( |
| 151 | 151 | } |
| 152 | 152 | return Result{ |
| 153 | 153 | .fail = try ErrorMsg.create( |
| 154 | bin_file.base.allocator, | |
| 154 | bin_file.allocator, | |
| 155 | 155 | src, |
| 156 | 156 | "TODO implement generateSymbol for more kinds of arrays", |
| 157 | 157 | .{}, |
| ... | ... | @@ -164,12 +164,11 @@ pub fn generateSymbol( |
| 164 | 164 | if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { |
| 165 | 165 | const decl = payload.decl; |
| 166 | 166 | if (decl.analysis != .complete) return error.AnalysisFail; |
| 167 | assert(decl.link.elf.local_sym_index != 0); | |
| 168 | 167 | // TODO handle the dependency of this symbol on the decl's vaddr. |
| 169 | 168 | // If the decl changes vaddr, then this symbol needs to get regenerated. |
| 170 | const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value; | |
| 171 | const endian = bin_file.base.options.target.cpu.arch.endian(); | |
| 172 | switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) { | |
| 169 | const vaddr = bin_file.getDeclVAddr(decl); | |
| 170 | const endian = bin_file.options.target.cpu.arch.endian(); | |
| 171 | switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { | |
| 173 | 172 | 16 => { |
| 174 | 173 | try code.resize(2); |
| 175 | 174 | mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); |
| ... | ... | @@ -188,7 +187,7 @@ pub fn generateSymbol( |
| 188 | 187 | } |
| 189 | 188 | return Result{ |
| 190 | 189 | .fail = try ErrorMsg.create( |
| 191 | bin_file.base.allocator, | |
| 190 | bin_file.allocator, | |
| 192 | 191 | src, |
| 193 | 192 | "TODO implement generateSymbol for pointer {}", |
| 194 | 193 | .{typed_value.val}, |
| ... | ... | @@ -198,7 +197,7 @@ pub fn generateSymbol( |
| 198 | 197 | .Int => { |
| 199 | 198 | // TODO populate .debug_info for the integer |
| 200 | 199 | |
| 201 | const info = typed_value.ty.intInfo(bin_file.base.options.target); | |
| 200 | const info = typed_value.ty.intInfo(bin_file.options.target); | |
| 202 | 201 | if (info.bits == 8 and !info.signed) { |
| 203 | 202 | const x = typed_value.val.toUnsignedInt(); |
| 204 | 203 | try code.append(@intCast(u8, x)); |
| ... | ... | @@ -206,7 +205,7 @@ pub fn generateSymbol( |
| 206 | 205 | } |
| 207 | 206 | return Result{ |
| 208 | 207 | .fail = try ErrorMsg.create( |
| 209 | bin_file.base.allocator, | |
| 208 | bin_file.allocator, | |
| 210 | 209 | src, |
| 211 | 210 | "TODO implement generateSymbol for int type '{}'", |
| 212 | 211 | .{typed_value.ty}, |
| ... | ... | @@ -216,7 +215,7 @@ pub fn generateSymbol( |
| 216 | 215 | else => |t| { |
| 217 | 216 | return Result{ |
| 218 | 217 | .fail = try ErrorMsg.create( |
| 219 | bin_file.base.allocator, | |
| 218 | bin_file.allocator, | |
| 220 | 219 | src, |
| 221 | 220 | "TODO implement generateSymbol for type '{}'", |
| 222 | 221 | .{@tagName(t)}, |
| ... | ... | @@ -234,13 +233,13 @@ const InnerError = error{ |
| 234 | 233 | fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 235 | 234 | return struct { |
| 236 | 235 | gpa: *Allocator, |
| 237 | bin_file: *link.File.Elf, | |
| 236 | bin_file: *link.File, | |
| 238 | 237 | target: *const std.Target, |
| 239 | 238 | mod_fn: *const Module.Fn, |
| 240 | 239 | code: *std.ArrayList(u8), |
| 241 | 240 | dbg_line: *std.ArrayList(u8), |
| 242 | 241 | dbg_info: *std.ArrayList(u8), |
| 243 | dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, | |
| 242 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | |
| 244 | 243 | err_msg: ?*ErrorMsg, |
| 245 | 244 | args: []MCValue, |
| 246 | 245 | ret_mcv: MCValue, |
| ... | ... | @@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 405 | 404 | const Self = @This(); |
| 406 | 405 | |
| 407 | 406 | fn generateSymbol( |
| 408 | bin_file: *link.File.Elf, | |
| 407 | bin_file: *link.File, | |
| 409 | 408 | src: usize, |
| 410 | 409 | typed_value: TypedValue, |
| 411 | 410 | code: *std.ArrayList(u8), |
| 412 | 411 | dbg_line: *std.ArrayList(u8), |
| 413 | 412 | dbg_info: *std.ArrayList(u8), |
| 414 | dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, | |
| 413 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | |
| 415 | 414 | ) GenerateSymbolError!Result { |
| 416 | 415 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; |
| 417 | 416 | |
| 418 | 417 | const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty; |
| 419 | 418 | |
| 420 | var branch_stack = std.ArrayList(Branch).init(bin_file.base.allocator); | |
| 419 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); | |
| 421 | 420 | defer { |
| 422 | 421 | assert(branch_stack.items.len == 1); |
| 423 | branch_stack.items[0].deinit(bin_file.base.allocator); | |
| 422 | branch_stack.items[0].deinit(bin_file.allocator); | |
| 424 | 423 | branch_stack.deinit(); |
| 425 | 424 | } |
| 426 | 425 | const branch = try branch_stack.addOne(); |
| ... | ... | @@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 443 | 442 | }; |
| 444 | 443 | |
| 445 | 444 | var function = Self{ |
| 446 | .gpa = bin_file.base.allocator, | |
| 447 | .target = &bin_file.base.options.target, | |
| 445 | .gpa = bin_file.allocator, | |
| 446 | .target = &bin_file.options.target, | |
| 448 | 447 | .bin_file = bin_file, |
| 449 | 448 | .mod_fn = module_fn, |
| 450 | 449 | .code = code, |
| ... | ... | @@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 464 | 463 | .rbrace_src = src_data.rbrace_src, |
| 465 | 464 | .source = src_data.source, |
| 466 | 465 | }; |
| 467 | defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator); | |
| 466 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); | |
| 468 | 467 | |
| 469 | 468 | var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) { |
| 470 | 469 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| ... | ... | @@ -684,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 684 | 683 | .unreach => return MCValue{ .unreach = {} }, |
| 685 | 684 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 686 | 685 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 686 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | |
| 687 | 687 | } |
| 688 | 688 | } |
| 689 | 689 | |
| ... | ... | @@ -858,6 +858,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 858 | 858 | } |
| 859 | 859 | } |
| 860 | 860 | |
| 861 | fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue { | |
| 862 | // No side effects, so if it's unreferenced, do nothing. | |
| 863 | if (inst.base.isUnused()) | |
| 864 | return MCValue.dead; | |
| 865 | ||
| 866 | switch (arch) { | |
| 867 | else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}), | |
| 868 | } | |
| 869 | } | |
| 870 | ||
| 871 | fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { | |
| 872 | if (!inst.operandDies(op_index) or !mcv.isMutable()) | |
| 873 | return false; | |
| 874 | ||
| 875 | // OK we're going to do it, but we need to clear the operand death bit so that | |
| 876 | // it stays allocated. | |
| 877 | inst.clearOperandDeath(op_index); | |
| 878 | return true; | |
| 879 | } | |
| 880 | ||
| 861 | 881 | fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 862 | 882 | const elem_ty = inst.base.ty; |
| 863 | 883 | if (!elem_ty.hasCodeGenBits()) |
| ... | ... | @@ -867,9 +887,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 867 | 887 | if (inst.base.isUnused() and !is_volatile) |
| 868 | 888 | return MCValue.dead; |
| 869 | 889 | const dst_mcv: MCValue = blk: { |
| 870 | if (inst.base.operandDies(0) and ptr.isMutable()) { | |
| 890 | if (reuseOperand(&inst.base, 0, ptr)) { | |
| 871 | 891 | // The MCValue that holds the pointer can be re-used as the value. |
| 872 | // TODO track this in the register/stack allocation metadata. | |
| 873 | 892 | break :blk ptr; |
| 874 | 893 | } else { |
| 875 | 894 | break :blk try self.allocRegOrMem(&inst.base); |
| ... | ... | @@ -966,7 +985,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 966 | 985 | var dst_mcv: MCValue = undefined; |
| 967 | 986 | var src_mcv: MCValue = undefined; |
| 968 | 987 | var src_inst: *ir.Inst = undefined; |
| 969 | if (inst.operandDies(0) and lhs.isMutable()) { | |
| 988 | if (reuseOperand(inst, 0, lhs)) { | |
| 970 | 989 | // LHS dies; use it as the destination. |
| 971 | 990 | // Both operands cannot be memory. |
| 972 | 991 | src_inst = op_rhs; |
| ... | ... | @@ -977,7 +996,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 977 | 996 | dst_mcv = lhs; |
| 978 | 997 | src_mcv = rhs; |
| 979 | 998 | } |
| 980 | } else if (inst.operandDies(1) and rhs.isMutable()) { | |
| 999 | } else if (reuseOperand(inst, 1, rhs)) { | |
| 981 | 1000 | // RHS dies; use it as the destination. |
| 982 | 1001 | // Both operands cannot be memory. |
| 983 | 1002 | src_inst = op_lhs; |
| ... | ... | @@ -1124,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1124 | 1143 | var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty); |
| 1125 | 1144 | defer info.deinit(self); |
| 1126 | 1145 | |
| 1127 | switch (arch) { | |
| 1128 | .x86_64 => { | |
| 1129 | for (info.args) |mc_arg, arg_i| { | |
| 1130 | const arg = inst.args[arg_i]; | |
| 1131 | const arg_mcv = try self.resolveInst(inst.args[arg_i]); | |
| 1132 | // Here we do not use setRegOrMem even though the logic is similar, because | |
| 1133 | // the function call will move the stack pointer, so the offsets are different. | |
| 1134 | switch (mc_arg) { | |
| 1135 | .none => continue, | |
| 1136 | .register => |reg| { | |
| 1137 | try self.genSetReg(arg.src, reg, arg_mcv); | |
| 1138 | // TODO interact with the register allocator to mark the instruction as moved. | |
| 1139 | }, | |
| 1140 | .stack_offset => { | |
| 1141 | // Here we need to emit instructions like this: | |
| 1142 | // mov qword ptr [rsp + stack_offset], x | |
| 1143 | return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); | |
| 1144 | }, | |
| 1145 | .ptr_stack_offset => { | |
| 1146 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | |
| 1147 | }, | |
| 1148 | .ptr_embedded_in_code => { | |
| 1149 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | |
| 1150 | }, | |
| 1151 | .undef => unreachable, | |
| 1152 | .immediate => unreachable, | |
| 1153 | .unreach => unreachable, | |
| 1154 | .dead => unreachable, | |
| 1155 | .embedded_in_code => unreachable, | |
| 1156 | .memory => unreachable, | |
| 1157 | .compare_flags_signed => unreachable, | |
| 1158 | .compare_flags_unsigned => unreachable, | |
| 1146 | // Due to incremental compilation, how function calls are generated depends | |
| 1147 | // on linking. | |
| 1148 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 1149 | switch (arch) { | |
| 1150 | .x86_64 => { | |
| 1151 | for (info.args) |mc_arg, arg_i| { | |
| 1152 | const arg = inst.args[arg_i]; | |
| 1153 | const arg_mcv = try self.resolveInst(inst.args[arg_i]); | |
| 1154 | // Here we do not use setRegOrMem even though the logic is similar, because | |
| 1155 | // the function call will move the stack pointer, so the offsets are different. | |
| 1156 | switch (mc_arg) { | |
| 1157 | .none => continue, | |
| 1158 | .register => |reg| { | |
| 1159 | try self.genSetReg(arg.src, reg, arg_mcv); | |
| 1160 | // TODO interact with the register allocator to mark the instruction as moved. | |
| 1161 | }, | |
| 1162 | .stack_offset => { | |
| 1163 | // Here we need to emit instructions like this: | |
| 1164 | // mov qword ptr [rsp + stack_offset], x | |
| 1165 | return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); | |
| 1166 | }, | |
| 1167 | .ptr_stack_offset => { | |
| 1168 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | |
| 1169 | }, | |
| 1170 | .ptr_embedded_in_code => { | |
| 1171 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | |
| 1172 | }, | |
| 1173 | .undef => unreachable, | |
| 1174 | .immediate => unreachable, | |
| 1175 | .unreach => unreachable, | |
| 1176 | .dead => unreachable, | |
| 1177 | .embedded_in_code => unreachable, | |
| 1178 | .memory => unreachable, | |
| 1179 | .compare_flags_signed => unreachable, | |
| 1180 | .compare_flags_unsigned => unreachable, | |
| 1181 | } | |
| 1159 | 1182 | } |
| 1160 | } | |
| 1161 | 1183 | |
| 1162 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | |
| 1163 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | |
| 1164 | const func = func_val.func; | |
| 1165 | const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; | |
| 1166 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 1167 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 1168 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | |
| 1169 | // ff 14 25 xx xx xx xx call [addr] | |
| 1170 | try self.code.ensureCapacity(self.code.items.len + 7); | |
| 1171 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); | |
| 1172 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); | |
| 1184 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | |
| 1185 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | |
| 1186 | const func = func_val.func; | |
| 1187 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | |
| 1188 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 1189 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 1190 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | |
| 1191 | // ff 14 25 xx xx xx xx call [addr] | |
| 1192 | try self.code.ensureCapacity(self.code.items.len + 7); | |
| 1193 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); | |
| 1194 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); | |
| 1195 | } else { | |
| 1196 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | |
| 1197 | } | |
| 1173 | 1198 | } else { |
| 1174 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | |
| 1199 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | |
| 1175 | 1200 | } |
| 1176 | } else { | |
| 1177 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | |
| 1178 | } | |
| 1179 | }, | |
| 1180 | .riscv64 => { | |
| 1181 | if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); | |
| 1182 | ||
| 1183 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | |
| 1184 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | |
| 1185 | const func = func_val.func; | |
| 1186 | const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; | |
| 1187 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 1188 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 1189 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | |
| 1190 | ||
| 1191 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); | |
| 1192 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | |
| 1201 | }, | |
| 1202 | .riscv64 => { | |
| 1203 | if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); | |
| 1204 | ||
| 1205 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | |
| 1206 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | |
| 1207 | const func = func_val.func; | |
| 1208 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | |
| 1209 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 1210 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 1211 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | |
| 1212 | ||
| 1213 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); | |
| 1214 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | |
| 1215 | } else { | |
| 1216 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | |
| 1217 | } | |
| 1193 | 1218 | } else { |
| 1194 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | |
| 1219 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | |
| 1195 | 1220 | } |
| 1196 | } else { | |
| 1197 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | |
| 1198 | } | |
| 1199 | }, | |
| 1200 | else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), | |
| 1221 | }, | |
| 1222 | else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), | |
| 1223 | } | |
| 1224 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | |
| 1225 | return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO", .{}); | |
| 1226 | } else { | |
| 1227 | unreachable; | |
| 1201 | 1228 | } |
| 1202 | 1229 | |
| 1203 | 1230 | return info.return_value; |
| ... | ... | @@ -2016,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2016 | 2043 | switch (typed_value.ty.zigTypeTag()) { |
| 2017 | 2044 | .Pointer => { |
| 2018 | 2045 | if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { |
| 2019 | const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; | |
| 2020 | const decl = payload.decl; | |
| 2021 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; | |
| 2022 | return MCValue{ .memory = got_addr }; | |
| 2046 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 2047 | const decl = payload.decl; | |
| 2048 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | |
| 2049 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; | |
| 2050 | return MCValue{ .memory = got_addr }; | |
| 2051 | } else { | |
| 2052 | return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); | |
| 2053 | } | |
| 2023 | 2054 | } |
| 2024 | 2055 | return self.fail(src, "TODO codegen more kinds of const pointers", .{}); |
| 2025 | 2056 | }, |
| ... | ... | @@ -2040,7 +2071,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2040 | 2071 | if (typed_value.val.isNull()) |
| 2041 | 2072 | return MCValue{ .immediate = 0 }; |
| 2042 | 2073 | |
| 2043 | var buf: Type.Payload.Pointer = undefined; | |
| 2074 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2044 | 2075 | return self.genTypedValue(src, .{ |
| 2045 | 2076 | .ty = typed_value.ty.optionalChild(&buf), |
| 2046 | 2077 | .val = typed_value.val, |
| ... | ... | @@ -2147,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2147 | 2178 | |
| 2148 | 2179 | /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`. |
| 2149 | 2180 | fn wantSafety(self: *Self) bool { |
| 2150 | return switch (self.bin_file.base.options.optimize_mode) { | |
| 2181 | return switch (self.bin_file.options.optimize_mode) { | |
| 2151 | 2182 | .Debug => true, |
| 2152 | 2183 | .ReleaseSafe => true, |
| 2153 | 2184 | .ReleaseFast => false, |
| ... | ... | @@ -2158,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2158 | 2189 | fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError { |
| 2159 | 2190 | @setCold(true); |
| 2160 | 2191 | assert(self.err_msg == null); |
| 2161 | self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args); | |
| 2192 | self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args); | |
| 2162 | 2193 | return error.CodegenFail; |
| 2163 | 2194 | } |
| 2164 | 2195 |
src-self-hosted/codegen/wasm.zig+59-37| ... | ... | @@ -62,58 +62,80 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void { |
| 62 | 62 | // TODO: check for and handle death of instructions |
| 63 | 63 | const tv = decl.typed_value.most_recent.typed_value; |
| 64 | 64 | const mod_fn = tv.val.cast(Value.Payload.Function).?.func; |
| 65 | for (mod_fn.analysis.success.instructions) |inst| try genInst(writer, inst); | |
| 65 | for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst); | |
| 66 | 66 | |
| 67 | 67 | // Write 'end' opcode |
| 68 | 68 | try writer.writeByte(0x0B); |
| 69 | 69 | |
| 70 | 70 | // Fill in the size of the generated code to the reserved space at the |
| 71 | 71 | // beginning of the buffer. |
| 72 | leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, buf.items.len - 5)); | |
| 72 | const size = buf.items.len - 5 + decl.fn_link.wasm.?.idx_refs.items.len * 5; | |
| 73 | leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, size)); | |
| 73 | 74 | } |
| 74 | 75 | |
| 75 | fn genInst(writer: ArrayList(u8).Writer, inst: *Inst) !void { | |
| 76 | fn genInst(buf: *ArrayList(u8), decl: *Decl, inst: *Inst) !void { | |
| 76 | 77 | return switch (inst.tag) { |
| 78 | .call => genCall(buf, decl, inst.castTag(.call).?), | |
| 79 | .constant => genConstant(buf, decl, inst.castTag(.constant).?), | |
| 77 | 80 | .dbg_stmt => {}, |
| 78 | .ret => genRet(writer, inst.castTag(.ret).?), | |
| 81 | .ret => genRet(buf, decl, inst.castTag(.ret).?), | |
| 82 | .retvoid => {}, | |
| 79 | 83 | else => error.TODOImplementMoreWasmCodegen, |
| 80 | 84 | }; |
| 81 | 85 | } |
| 82 | 86 | |
| 83 | fn genRet(writer: ArrayList(u8).Writer, inst: *Inst.UnOp) !void { | |
| 84 | switch (inst.operand.tag) { | |
| 85 | .constant => { | |
| 86 | const constant = inst.operand.castTag(.constant).?; | |
| 87 | switch (inst.operand.ty.tag()) { | |
| 88 | .u32 => { | |
| 89 | try writer.writeByte(0x41); // i32.const | |
| 90 | try leb.writeILEB128(writer, constant.val.toUnsignedInt()); | |
| 91 | }, | |
| 92 | .i32 => { | |
| 93 | try writer.writeByte(0x41); // i32.const | |
| 94 | try leb.writeILEB128(writer, constant.val.toSignedInt()); | |
| 95 | }, | |
| 96 | .u64 => { | |
| 97 | try writer.writeByte(0x42); // i64.const | |
| 98 | try leb.writeILEB128(writer, constant.val.toUnsignedInt()); | |
| 99 | }, | |
| 100 | .i64 => { | |
| 101 | try writer.writeByte(0x42); // i64.const | |
| 102 | try leb.writeILEB128(writer, constant.val.toSignedInt()); | |
| 103 | }, | |
| 104 | .f32 => { | |
| 105 | try writer.writeByte(0x43); // f32.const | |
| 106 | // TODO: enforce LE byte order | |
| 107 | try writer.writeAll(mem.asBytes(&constant.val.toFloat(f32))); | |
| 108 | }, | |
| 109 | .f64 => { | |
| 110 | try writer.writeByte(0x44); // f64.const | |
| 111 | // TODO: enforce LE byte order | |
| 112 | try writer.writeAll(mem.asBytes(&constant.val.toFloat(f64))); | |
| 113 | }, | |
| 114 | else => return error.TODOImplementMoreWasmCodegen, | |
| 115 | } | |
| 87 | fn genConstant(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Constant) !void { | |
| 88 | const writer = buf.writer(); | |
| 89 | switch (inst.base.ty.tag()) { | |
| 90 | .u32 => { | |
| 91 | try writer.writeByte(0x41); // i32.const | |
| 92 | try leb.writeILEB128(writer, inst.val.toUnsignedInt()); | |
| 93 | }, | |
| 94 | .i32 => { | |
| 95 | try writer.writeByte(0x41); // i32.const | |
| 96 | try leb.writeILEB128(writer, inst.val.toSignedInt()); | |
| 97 | }, | |
| 98 | .u64 => { | |
| 99 | try writer.writeByte(0x42); // i64.const | |
| 100 | try leb.writeILEB128(writer, inst.val.toUnsignedInt()); | |
| 101 | }, | |
| 102 | .i64 => { | |
| 103 | try writer.writeByte(0x42); // i64.const | |
| 104 | try leb.writeILEB128(writer, inst.val.toSignedInt()); | |
| 116 | 105 | }, |
| 106 | .f32 => { | |
| 107 | try writer.writeByte(0x43); // f32.const | |
| 108 | // TODO: enforce LE byte order | |
| 109 | try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32))); | |
| 110 | }, | |
| 111 | .f64 => { | |
| 112 | try writer.writeByte(0x44); // f64.const | |
| 113 | // TODO: enforce LE byte order | |
| 114 | try writer.writeAll(mem.asBytes(&inst.val.toFloat(f64))); | |
| 115 | }, | |
| 116 | .void => {}, | |
| 117 | 117 | else => return error.TODOImplementMoreWasmCodegen, |
| 118 | 118 | } |
| 119 | 119 | } |
| 120 | ||
| 121 | fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void { | |
| 122 | try genInst(buf, decl, inst.operand); | |
| 123 | } | |
| 124 | ||
| 125 | fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void { | |
| 126 | const func_inst = inst.func.castTag(.constant).?; | |
| 127 | const func_val = func_inst.val.cast(Value.Payload.Function).?; | |
| 128 | const target = func_val.func.owner_decl; | |
| 129 | const target_ty = target.typed_value.most_recent.typed_value.ty; | |
| 130 | ||
| 131 | if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen; | |
| 132 | ||
| 133 | try buf.append(0x10); // call | |
| 134 | ||
| 135 | // The function index immediate argument will be filled in using this data | |
| 136 | // in link.Wasm.flush(). | |
| 137 | try decl.fn_link.wasm.?.idx_refs.append(buf.allocator, .{ | |
| 138 | .offset = @intCast(u32, buf.items.len), | |
| 139 | .decl = target, | |
| 140 | }); | |
| 141 | } |
src-self-hosted/introspect.zig+8-5| ... | ... | @@ -87,6 +87,13 @@ pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 { |
| 87 | 87 | return fs.getAppDataDir(allocator, appname); |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | pub fn openGlobalCacheDir() !fs.Dir { | |
| 91 | var buf: [fs.MAX_PATH_BYTES]u8 = undefined; | |
| 92 | var fba = std.heap.FixedBufferAllocator.init(&buf); | |
| 93 | const path_name = try resolveGlobalCacheDir(&fba.allocator); | |
| 94 | return fs.cwd().makeOpenPath(path_name, .{}); | |
| 95 | } | |
| 96 | ||
| 90 | 97 | var compiler_id_mutex = std.Mutex{}; |
| 91 | 98 | var compiler_id: [16]u8 = undefined; |
| 92 | 99 | var compiler_id_computed = false; |
| ... | ... | @@ -99,11 +106,7 @@ pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 { |
| 99 | 106 | return compiler_id; |
| 100 | 107 | compiler_id_computed = true; |
| 101 | 108 | |
| 102 | const global_cache_dir = try resolveGlobalCacheDir(gpa); | |
| 103 | defer gpa.free(global_cache_dir); | |
| 104 | ||
| 105 | // TODO Introduce openGlobalCacheDir which returns a dir handle rather than a string. | |
| 106 | var cache_dir = try fs.cwd().openDir(global_cache_dir, .{}); | |
| 109 | var cache_dir = try openGlobalCacheDir(); | |
| 107 | 110 | defer cache_dir.close(); |
| 108 | 111 | |
| 109 | 112 | var ch = try CacheHash.init(gpa, cache_dir, "exe"); |
src-self-hosted/ir.zig+21| ... | ... | @@ -42,6 +42,11 @@ pub const Inst = struct { |
| 42 | 42 | return @truncate(u1, self.deaths >> index) != 0; |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void { | |
| 46 | assert(index < deaths_bits); | |
| 47 | self.deaths &= ~(@as(DeathsInt, 1) << index); | |
| 48 | } | |
| 49 | ||
| 45 | 50 | pub fn specialOperandDeaths(self: Inst) bool { |
| 46 | 51 | return (self.deaths & (1 << deaths_bits)) != 0; |
| 47 | 52 | } |
| ... | ... | @@ -76,6 +81,7 @@ pub const Inst = struct { |
| 76 | 81 | ref, |
| 77 | 82 | ret, |
| 78 | 83 | retvoid, |
| 84 | varptr, | |
| 79 | 85 | /// Write a value to a pointer. LHS is pointer, RHS is value. |
| 80 | 86 | store, |
| 81 | 87 | sub, |
| ... | ... | @@ -130,6 +136,7 @@ pub const Inst = struct { |
| 130 | 136 | .condbr => CondBr, |
| 131 | 137 | .constant => Constant, |
| 132 | 138 | .loop => Loop, |
| 139 | .varptr => VarPtr, | |
| 133 | 140 | }; |
| 134 | 141 | } |
| 135 | 142 | |
| ... | ... | @@ -429,6 +436,20 @@ pub const Inst = struct { |
| 429 | 436 | return null; |
| 430 | 437 | } |
| 431 | 438 | }; |
| 439 | ||
| 440 | pub const VarPtr = struct { | |
| 441 | pub const base_tag = Tag.varptr; | |
| 442 | ||
| 443 | base: Inst, | |
| 444 | variable: *Module.Var, | |
| 445 | ||
| 446 | pub fn operandCount(self: *const VarPtr) usize { | |
| 447 | return 0; | |
| 448 | } | |
| 449 | pub fn getOperand(self: *const VarPtr, index: usize) ?*Inst { | |
| 450 | return null; | |
| 451 | } | |
| 452 | }; | |
| 432 | 453 | }; |
| 433 | 454 | |
| 434 | 455 | pub const Body = struct { |
src-self-hosted/link.zig+36-2686| ... | ... | @@ -1,28 +1,10 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | |
| 3 | const assert = std.debug.assert; | |
| 4 | 2 | const Allocator = std.mem.Allocator; |
| 5 | const ir = @import("ir.zig"); | |
| 6 | 3 | const Module = @import("Module.zig"); |
| 7 | 4 | const fs = std.fs; |
| 8 | const elf = std.elf; | |
| 9 | const codegen = @import("codegen.zig"); | |
| 10 | const c_codegen = @import("codegen/c.zig"); | |
| 11 | const log = std.log.scoped(.link); | |
| 12 | const DW = std.dwarf; | |
| 13 | 5 | const trace = @import("tracy.zig").trace; |
| 14 | const leb128 = std.debug.leb; | |
| 15 | 6 | const Package = @import("Package.zig"); |
| 16 | const Value = @import("value.zig").Value; | |
| 17 | 7 | const Type = @import("type.zig").Type; |
| 18 | const build_options = @import("build_options"); | |
| 19 | ||
| 20 | const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | |
| 21 | ||
| 22 | // TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented. | |
| 23 | // zig fmt: off | |
| 24 | ||
| 25 | const default_entry_addr = 0x8000000; | |
| 26 | 8 | |
| 27 | 9 | pub const Options = struct { |
| 28 | 10 | target: std.Target, |
| ... | ... | @@ -40,8 +22,12 @@ pub const Options = struct { |
| 40 | 22 | program_code_size_hint: u64 = 256 * 1024, |
| 41 | 23 | }; |
| 42 | 24 | |
| 43 | ||
| 44 | 25 | pub const File = struct { |
| 26 | tag: Tag, | |
| 27 | options: Options, | |
| 28 | file: ?fs.File, | |
| 29 | allocator: *Allocator, | |
| 30 | ||
| 45 | 31 | pub const LinkBlock = union { |
| 46 | 32 | elf: Elf.TextBlock, |
| 47 | 33 | macho: MachO.TextBlock, |
| ... | ... | @@ -56,16 +42,24 @@ pub const File = struct { |
| 56 | 42 | wasm: ?Wasm.FnData, |
| 57 | 43 | }; |
| 58 | 44 | |
| 59 | tag: Tag, | |
| 60 | options: Options, | |
| 61 | file: ?fs.File, | |
| 62 | allocator: *Allocator, | |
| 45 | /// For DWARF .debug_info. | |
| 46 | pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true); | |
| 47 | ||
| 48 | /// For DWARF .debug_info. | |
| 49 | pub const DbgInfoTypeReloc = struct { | |
| 50 | /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). | |
| 51 | /// This is where the .debug_info tag for the type is. | |
| 52 | off: u32, | |
| 53 | /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). | |
| 54 | /// List of DW.AT_type / DW.FORM_ref4 that points to the type. | |
| 55 | relocs: std.ArrayListUnmanaged(u32), | |
| 56 | }; | |
| 63 | 57 | |
| 64 | 58 | /// Attempts incremental linking, if the file already exists. If |
| 65 | 59 | /// incremental linking fails, falls back to truncating the file and |
| 66 | 60 | /// rewriting it. A malicious file is detected as incremental link failure |
| 67 | 61 | /// and does not cause Illegal Behavior. This operation is not atomic. |
| 68 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { | |
| 62 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { | |
| 69 | 63 | switch (options.object_format) { |
| 70 | 64 | .unknown => unreachable, |
| 71 | 65 | .coff => return error.TODOImplementCoff, |
| ... | ... | @@ -110,6 +104,8 @@ pub const File = struct { |
| 110 | 104 | } |
| 111 | 105 | } |
| 112 | 106 | |
| 107 | /// May be called before or after updateDeclExports but must be called | |
| 108 | /// after allocateDeclIndexes for any given Decl. | |
| 113 | 109 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 114 | 110 | switch (base.tag) { |
| 115 | 111 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), |
| ... | ... | @@ -127,6 +123,8 @@ pub const File = struct { |
| 127 | 123 | } |
| 128 | 124 | } |
| 129 | 125 | |
| 126 | /// Must be called before any call to updateDecl or updateDeclExports for | |
| 127 | /// any given Decl. | |
| 130 | 128 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { |
| 131 | 129 | switch (base.tag) { |
| 132 | 130 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), |
| ... | ... | @@ -200,7 +198,8 @@ pub const File = struct { |
| 200 | 198 | }; |
| 201 | 199 | } |
| 202 | 200 | |
| 203 | /// Must be called only after a successful call to `updateDecl`. | |
| 201 | /// May be called before or after updateDecl, but must be called after | |
| 202 | /// allocateDeclIndexes for any given Decl. | |
| 204 | 203 | pub fn updateDeclExports( |
| 205 | 204 | base: *File, |
| 206 | 205 | module: *Module, |
| ... | ... | @@ -215,6 +214,15 @@ pub const File = struct { |
| 215 | 214 | } |
| 216 | 215 | } |
| 217 | 216 | |
| 217 | pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 { | |
| 218 | switch (base.tag) { | |
| 219 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl), | |
| 220 | .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl), | |
| 221 | .c => unreachable, | |
| 222 | .wasm => unreachable, | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 218 | 226 | pub const Tag = enum { |
| 219 | 227 | elf, |
| 220 | 228 | macho, |
| ... | ... | @@ -226,2670 +234,12 @@ pub const File = struct { |
| 226 | 234 | no_entry_point_found: bool = false, |
| 227 | 235 | }; |
| 228 | 236 | |
| 229 | pub const C = struct { | |
| 230 | pub const base_tag: Tag = .c; | |
| 231 | ||
| 232 | base: File, | |
| 233 | ||
| 234 | header: std.ArrayList(u8), | |
| 235 | constants: std.ArrayList(u8), | |
| 236 | main: std.ArrayList(u8), | |
| 237 | ||
| 238 | called: std.StringHashMap(void), | |
| 239 | need_stddef: bool = false, | |
| 240 | need_stdint: bool = false, | |
| 241 | error_msg: *Module.ErrorMsg = undefined, | |
| 242 | ||
| 243 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { | |
| 244 | assert(options.object_format == .c); | |
| 245 | ||
| 246 | const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = determineMode(options) }); | |
| 247 | errdefer file.close(); | |
| 248 | ||
| 249 | var c_file = try allocator.create(C); | |
| 250 | errdefer allocator.destroy(c_file); | |
| 251 | ||
| 252 | c_file.* = File.C{ | |
| 253 | .base = .{ | |
| 254 | .tag = .c, | |
| 255 | .options = options, | |
| 256 | .file = file, | |
| 257 | .allocator = allocator, | |
| 258 | }, | |
| 259 | .main = std.ArrayList(u8).init(allocator), | |
| 260 | .header = std.ArrayList(u8).init(allocator), | |
| 261 | .constants = std.ArrayList(u8).init(allocator), | |
| 262 | .called = std.StringHashMap(void).init(allocator), | |
| 263 | }; | |
| 264 | ||
| 265 | return &c_file.base; | |
| 266 | } | |
| 267 | ||
| 268 | pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{AnalysisFail, OutOfMemory} { | |
| 269 | self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args); | |
| 270 | return error.AnalysisFail; | |
| 271 | } | |
| 272 | ||
| 273 | pub fn deinit(self: *File.C) void { | |
| 274 | self.main.deinit(); | |
| 275 | self.header.deinit(); | |
| 276 | self.constants.deinit(); | |
| 277 | self.called.deinit(); | |
| 278 | } | |
| 279 | ||
| 280 | pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { | |
| 281 | c_codegen.generate(self, decl) catch |err| { | |
| 282 | if (err == error.AnalysisFail) { | |
| 283 | try module.failed_decls.put(module.gpa, decl, self.error_msg); | |
| 284 | } | |
| 285 | return err; | |
| 286 | }; | |
| 287 | } | |
| 288 | ||
| 289 | pub fn flush(self: *File.C, module: *Module) !void { | |
| 290 | const writer = self.base.file.?.writer(); | |
| 291 | try writer.writeAll(@embedFile("cbe.h")); | |
| 292 | var includes = false; | |
| 293 | if (self.need_stddef) { | |
| 294 | try writer.writeAll("#include <stddef.h>\n"); | |
| 295 | includes = true; | |
| 296 | } | |
| 297 | if (self.need_stdint) { | |
| 298 | try writer.writeAll("#include <stdint.h>\n"); | |
| 299 | includes = true; | |
| 300 | } | |
| 301 | if (includes) { | |
| 302 | try writer.writeByte('\n'); | |
| 303 | } | |
| 304 | if (self.header.items.len > 0) { | |
| 305 | try writer.print("{}\n", .{self.header.items}); | |
| 306 | } | |
| 307 | if (self.constants.items.len > 0) { | |
| 308 | try writer.print("{}\n", .{self.constants.items}); | |
| 309 | } | |
| 310 | if (self.main.items.len > 1) { | |
| 311 | const last_two = self.main.items[self.main.items.len - 2 ..]; | |
| 312 | if (std.mem.eql(u8, last_two, "\n\n")) { | |
| 313 | self.main.items.len -= 1; | |
| 314 | } | |
| 315 | } | |
| 316 | try writer.writeAll(self.main.items); | |
| 317 | self.base.file.?.close(); | |
| 318 | self.base.file = null; | |
| 319 | } | |
| 320 | }; | |
| 321 | ||
| 322 | pub const Elf = struct { | |
| 323 | pub const base_tag: Tag = .elf; | |
| 324 | ||
| 325 | base: File, | |
| 326 | ||
| 327 | ptr_width: enum { p32, p64 }, | |
| 328 | ||
| 329 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 330 | /// Same order as in the file. | |
| 331 | sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){}, | |
| 332 | shdr_table_offset: ?u64 = null, | |
| 333 | ||
| 334 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 335 | /// Same order as in the file. | |
| 336 | program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){}, | |
| 337 | phdr_table_offset: ?u64 = null, | |
| 338 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags | |
| 339 | phdr_load_re_index: ?u16 = null, | |
| 340 | /// The index into the program headers of the global offset table. | |
| 341 | /// It needs PT_LOAD and Read flags. | |
| 342 | phdr_got_index: ?u16 = null, | |
| 343 | entry_addr: ?u64 = null, | |
| 344 | ||
| 345 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | |
| 346 | shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | |
| 347 | shstrtab_index: ?u16 = null, | |
| 348 | ||
| 349 | text_section_index: ?u16 = null, | |
| 350 | symtab_section_index: ?u16 = null, | |
| 351 | got_section_index: ?u16 = null, | |
| 352 | debug_info_section_index: ?u16 = null, | |
| 353 | debug_abbrev_section_index: ?u16 = null, | |
| 354 | debug_str_section_index: ?u16 = null, | |
| 355 | debug_aranges_section_index: ?u16 = null, | |
| 356 | debug_line_section_index: ?u16 = null, | |
| 357 | ||
| 358 | debug_abbrev_table_offset: ?u64 = null, | |
| 359 | ||
| 360 | /// The same order as in the file. ELF requires global symbols to all be after the | |
| 361 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and | |
| 362 | /// write them at the end. These are only the local symbols. The length of this array | |
| 363 | /// is the value used for sh_info in the .symtab section. | |
| 364 | local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | |
| 365 | global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | |
| 366 | ||
| 367 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 368 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 369 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 370 | ||
| 371 | /// Same order as in the file. The value is the absolute vaddr value. | |
| 372 | /// If the vaddr of the executable program header changes, the entire | |
| 373 | /// offset table needs to be rewritten. | |
| 374 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | |
| 375 | ||
| 376 | phdr_table_dirty: bool = false, | |
| 377 | shdr_table_dirty: bool = false, | |
| 378 | shstrtab_dirty: bool = false, | |
| 379 | debug_strtab_dirty: bool = false, | |
| 380 | offset_table_count_dirty: bool = false, | |
| 381 | debug_abbrev_section_dirty: bool = false, | |
| 382 | debug_aranges_section_dirty: bool = false, | |
| 383 | ||
| 384 | debug_info_header_dirty: bool = false, | |
| 385 | debug_line_header_dirty: bool = false, | |
| 386 | ||
| 387 | error_flags: ErrorFlags = ErrorFlags{}, | |
| 388 | ||
| 389 | /// A list of text blocks that have surplus capacity. This list can have false | |
| 390 | /// positives, as functions grow and shrink over time, only sometimes being added | |
| 391 | /// or removed from the freelist. | |
| 392 | /// | |
| 393 | /// A text block has surplus capacity when its overcapacity value is greater than | |
| 394 | /// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so | |
| 395 | /// much extra capacity, that we could fit a small new symbol in it, itself with | |
| 396 | /// ideal_capacity or more. | |
| 397 | /// | |
| 398 | /// Ideal capacity is defined by size * alloc_num / alloc_den. | |
| 399 | /// | |
| 400 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that | |
| 401 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | |
| 402 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | |
| 403 | /// by 1 byte. It will then have -1 overcapacity. | |
| 404 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | |
| 405 | last_text_block: ?*TextBlock = null, | |
| 406 | ||
| 407 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. | |
| 408 | /// This is the same concept as `text_block_free_list`; see those doc comments. | |
| 409 | dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, | |
| 410 | dbg_line_fn_first: ?*SrcFn = null, | |
| 411 | dbg_line_fn_last: ?*SrcFn = null, | |
| 412 | ||
| 413 | /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. | |
| 414 | /// This is the same concept as `text_block_free_list`; see those doc comments. | |
| 415 | dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, | |
| 416 | dbg_info_decl_first: ?*TextBlock = null, | |
| 417 | dbg_info_decl_last: ?*TextBlock = null, | |
| 418 | ||
| 419 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | |
| 420 | const alloc_num = 4; | |
| 421 | const alloc_den = 3; | |
| 422 | ||
| 423 | /// In order for a slice of bytes to be considered eligible to keep metadata pointing at | |
| 424 | /// it as a possible place to put new symbols, it must have enough room for this many bytes | |
| 425 | /// (plus extra for reserved capacity). | |
| 426 | const minimum_text_block_size = 64; | |
| 427 | const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; | |
| 428 | ||
| 429 | pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true); | |
| 430 | ||
| 431 | const DbgInfoTypeReloc = struct { | |
| 432 | /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). | |
| 433 | /// This is where the .debug_info tag for the type is. | |
| 434 | off: u32, | |
| 435 | /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). | |
| 436 | /// List of DW.AT_type / DW.FORM_ref4 that points to the type. | |
| 437 | relocs: std.ArrayListUnmanaged(u32), | |
| 438 | }; | |
| 439 | ||
| 440 | pub const TextBlock = struct { | |
| 441 | /// Each decl always gets a local symbol with the fully qualified name. | |
| 442 | /// The vaddr and size are found here directly. | |
| 443 | /// The file offset is found by computing the vaddr offset from the section vaddr | |
| 444 | /// the symbol references, and adding that to the file offset of the section. | |
| 445 | /// If this field is 0, it means the codegen size = 0 and there is no symbol or | |
| 446 | /// offset table entry. | |
| 447 | local_sym_index: u32, | |
| 448 | /// This field is undefined for symbols with size = 0. | |
| 449 | offset_table_index: u32, | |
| 450 | /// Points to the previous and next neighbors, based on the `text_offset`. | |
| 451 | /// This can be used to find, for example, the capacity of this `TextBlock`. | |
| 452 | prev: ?*TextBlock, | |
| 453 | next: ?*TextBlock, | |
| 454 | ||
| 455 | /// Previous/next linked list pointers. This value is `next ^ prev`. | |
| 456 | /// This is the linked list node for this Decl's corresponding .debug_info tag. | |
| 457 | dbg_info_prev: ?*TextBlock, | |
| 458 | dbg_info_next: ?*TextBlock, | |
| 459 | /// Offset into .debug_info pointing to the tag for this Decl. | |
| 460 | dbg_info_off: u32, | |
| 461 | /// Size of the .debug_info tag for this Decl, not including padding. | |
| 462 | dbg_info_len: u32, | |
| 463 | ||
| 464 | pub const empty = TextBlock{ | |
| 465 | .local_sym_index = 0, | |
| 466 | .offset_table_index = undefined, | |
| 467 | .prev = null, | |
| 468 | .next = null, | |
| 469 | .dbg_info_prev = null, | |
| 470 | .dbg_info_next = null, | |
| 471 | .dbg_info_off = undefined, | |
| 472 | .dbg_info_len = undefined, | |
| 473 | }; | |
| 474 | ||
| 475 | /// Returns how much room there is to grow in virtual address space. | |
| 476 | /// File offset relocation happens transparently, so it is not included in | |
| 477 | /// this calculation. | |
| 478 | fn capacity(self: TextBlock, elf_file: Elf) u64 { | |
| 479 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; | |
| 480 | if (self.next) |next| { | |
| 481 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; | |
| 482 | return next_sym.st_value - self_sym.st_value; | |
| 483 | } else { | |
| 484 | // We are the last block. The capacity is limited only by virtual address space. | |
| 485 | return std.math.maxInt(u32) - self_sym.st_value; | |
| 486 | } | |
| 487 | } | |
| 488 | ||
| 489 | fn freeListEligible(self: TextBlock, elf_file: Elf) bool { | |
| 490 | // No need to keep a free list node for the last block. | |
| 491 | const next = self.next orelse return false; | |
| 492 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; | |
| 493 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; | |
| 494 | const cap = next_sym.st_value - self_sym.st_value; | |
| 495 | const ideal_cap = self_sym.st_size * alloc_num / alloc_den; | |
| 496 | if (cap <= ideal_cap) return false; | |
| 497 | const surplus = cap - ideal_cap; | |
| 498 | return surplus >= min_text_capacity; | |
| 499 | } | |
| 500 | }; | |
| 501 | ||
| 502 | pub const Export = struct { | |
| 503 | sym_index: ?u32 = null, | |
| 504 | }; | |
| 505 | ||
| 506 | pub const SrcFn = struct { | |
| 507 | /// Offset from the beginning of the Debug Line Program header that contains this function. | |
| 508 | off: u32, | |
| 509 | /// Size of the line number program component belonging to this function, not | |
| 510 | /// including padding. | |
| 511 | len: u32, | |
| 512 | ||
| 513 | /// Points to the previous and next neighbors, based on the offset from .debug_line. | |
| 514 | /// This can be used to find, for example, the capacity of this `SrcFn`. | |
| 515 | prev: ?*SrcFn, | |
| 516 | next: ?*SrcFn, | |
| 517 | ||
| 518 | pub const empty: SrcFn = .{ | |
| 519 | .off = 0, | |
| 520 | .len = 0, | |
| 521 | .prev = null, | |
| 522 | .next = null, | |
| 523 | }; | |
| 524 | }; | |
| 525 | ||
| 526 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { | |
| 527 | assert(options.object_format == .elf); | |
| 528 | ||
| 529 | const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) }); | |
| 530 | errdefer file.close(); | |
| 531 | ||
| 532 | var elf_file = try allocator.create(Elf); | |
| 533 | errdefer allocator.destroy(elf_file); | |
| 534 | ||
| 535 | elf_file.* = openFile(allocator, file, options) catch |err| switch (err) { | |
| 536 | error.IncrFailed => try createFile(allocator, file, options), | |
| 537 | else => |e| return e, | |
| 538 | }; | |
| 539 | ||
| 540 | return &elf_file.base; | |
| 541 | } | |
| 542 | ||
| 543 | /// Returns error.IncrFailed if incremental update could not be performed. | |
| 544 | fn openFile(allocator: *Allocator, file: fs.File, options: Options) !Elf { | |
| 545 | switch (options.output_mode) { | |
| 546 | .Exe => {}, | |
| 547 | .Obj => {}, | |
| 548 | .Lib => return error.IncrFailed, | |
| 549 | } | |
| 550 | var self: Elf = .{ | |
| 551 | .base = .{ | |
| 552 | .file = file, | |
| 553 | .tag = .elf, | |
| 554 | .options = options, | |
| 555 | .allocator = allocator, | |
| 556 | }, | |
| 557 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | |
| 558 | 32 => .p32, | |
| 559 | 64 => .p64, | |
| 560 | else => return error.UnsupportedELFArchitecture, | |
| 561 | }, | |
| 562 | }; | |
| 563 | errdefer self.deinit(); | |
| 564 | ||
| 565 | // TODO implement reading the elf file | |
| 566 | return error.IncrFailed; | |
| 567 | //try self.populateMissingMetadata(); | |
| 568 | //return self; | |
| 569 | } | |
| 570 | ||
| 571 | /// Truncates the existing file contents and overwrites the contents. | |
| 572 | /// Returns an error if `file` is not already open with +read +write +seek abilities. | |
| 573 | fn createFile(allocator: *Allocator, file: fs.File, options: Options) !Elf { | |
| 574 | switch (options.output_mode) { | |
| 575 | .Exe => {}, | |
| 576 | .Obj => {}, | |
| 577 | .Lib => return error.TODOImplementWritingLibFiles, | |
| 578 | } | |
| 579 | var self: Elf = .{ | |
| 580 | .base = .{ | |
| 581 | .tag = .elf, | |
| 582 | .options = options, | |
| 583 | .allocator = allocator, | |
| 584 | .file = file, | |
| 585 | }, | |
| 586 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | |
| 587 | 32 => .p32, | |
| 588 | 64 => .p64, | |
| 589 | else => return error.UnsupportedELFArchitecture, | |
| 590 | }, | |
| 591 | .shdr_table_dirty = true, | |
| 592 | }; | |
| 593 | errdefer self.deinit(); | |
| 594 | ||
| 595 | // Index 0 is always a null symbol. | |
| 596 | try self.local_symbols.append(allocator, .{ | |
| 597 | .st_name = 0, | |
| 598 | .st_info = 0, | |
| 599 | .st_other = 0, | |
| 600 | .st_shndx = 0, | |
| 601 | .st_value = 0, | |
| 602 | .st_size = 0, | |
| 603 | }); | |
| 604 | ||
| 605 | // There must always be a null section in index 0 | |
| 606 | try self.sections.append(allocator, .{ | |
| 607 | .sh_name = 0, | |
| 608 | .sh_type = elf.SHT_NULL, | |
| 609 | .sh_flags = 0, | |
| 610 | .sh_addr = 0, | |
| 611 | .sh_offset = 0, | |
| 612 | .sh_size = 0, | |
| 613 | .sh_link = 0, | |
| 614 | .sh_info = 0, | |
| 615 | .sh_addralign = 0, | |
| 616 | .sh_entsize = 0, | |
| 617 | }); | |
| 618 | ||
| 619 | try self.populateMissingMetadata(); | |
| 620 | ||
| 621 | return self; | |
| 622 | } | |
| 623 | ||
| 624 | pub fn deinit(self: *Elf) void { | |
| 625 | self.sections.deinit(self.base.allocator); | |
| 626 | self.program_headers.deinit(self.base.allocator); | |
| 627 | self.shstrtab.deinit(self.base.allocator); | |
| 628 | self.debug_strtab.deinit(self.base.allocator); | |
| 629 | self.local_symbols.deinit(self.base.allocator); | |
| 630 | self.global_symbols.deinit(self.base.allocator); | |
| 631 | self.global_symbol_free_list.deinit(self.base.allocator); | |
| 632 | self.local_symbol_free_list.deinit(self.base.allocator); | |
| 633 | self.offset_table_free_list.deinit(self.base.allocator); | |
| 634 | self.text_block_free_list.deinit(self.base.allocator); | |
| 635 | self.dbg_line_fn_free_list.deinit(self.base.allocator); | |
| 636 | self.dbg_info_decl_free_list.deinit(self.base.allocator); | |
| 637 | self.offset_table.deinit(self.base.allocator); | |
| 638 | } | |
| 639 | ||
| 640 | fn getDebugLineProgramOff(self: Elf) u32 { | |
| 641 | return self.dbg_line_fn_first.?.off; | |
| 642 | } | |
| 643 | ||
| 644 | fn getDebugLineProgramEnd(self: Elf) u32 { | |
| 645 | return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len; | |
| 646 | } | |
| 647 | ||
| 648 | /// Returns end pos of collision, if any. | |
| 649 | fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | |
| 650 | const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32; | |
| 651 | const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); | |
| 652 | if (start < ehdr_size) | |
| 653 | return ehdr_size; | |
| 654 | ||
| 655 | const end = start + satMul(size, alloc_num) / alloc_den; | |
| 656 | ||
| 657 | if (self.shdr_table_offset) |off| { | |
| 658 | const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); | |
| 659 | const tight_size = self.sections.items.len * shdr_size; | |
| 660 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | |
| 661 | const test_end = off + increased_size; | |
| 662 | if (end > off and start < test_end) { | |
| 663 | return test_end; | |
| 664 | } | |
| 665 | } | |
| 666 | ||
| 667 | if (self.phdr_table_offset) |off| { | |
| 668 | const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); | |
| 669 | const tight_size = self.sections.items.len * phdr_size; | |
| 670 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | |
| 671 | const test_end = off + increased_size; | |
| 672 | if (end > off and start < test_end) { | |
| 673 | return test_end; | |
| 674 | } | |
| 675 | } | |
| 676 | ||
| 677 | for (self.sections.items) |section| { | |
| 678 | const increased_size = satMul(section.sh_size, alloc_num) / alloc_den; | |
| 679 | const test_end = section.sh_offset + increased_size; | |
| 680 | if (end > section.sh_offset and start < test_end) { | |
| 681 | return test_end; | |
| 682 | } | |
| 683 | } | |
| 684 | for (self.program_headers.items) |program_header| { | |
| 685 | const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den; | |
| 686 | const test_end = program_header.p_offset + increased_size; | |
| 687 | if (end > program_header.p_offset and start < test_end) { | |
| 688 | return test_end; | |
| 689 | } | |
| 690 | } | |
| 691 | return null; | |
| 692 | } | |
| 693 | ||
| 694 | fn allocatedSize(self: *Elf, start: u64) u64 { | |
| 695 | if (start == 0) | |
| 696 | return 0; | |
| 697 | var min_pos: u64 = std.math.maxInt(u64); | |
| 698 | if (self.shdr_table_offset) |off| { | |
| 699 | if (off > start and off < min_pos) min_pos = off; | |
| 700 | } | |
| 701 | if (self.phdr_table_offset) |off| { | |
| 702 | if (off > start and off < min_pos) min_pos = off; | |
| 703 | } | |
| 704 | for (self.sections.items) |section| { | |
| 705 | if (section.sh_offset <= start) continue; | |
| 706 | if (section.sh_offset < min_pos) min_pos = section.sh_offset; | |
| 707 | } | |
| 708 | for (self.program_headers.items) |program_header| { | |
| 709 | if (program_header.p_offset <= start) continue; | |
| 710 | if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; | |
| 711 | } | |
| 712 | return min_pos - start; | |
| 713 | } | |
| 714 | ||
| 715 | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 { | |
| 716 | var start: u64 = 0; | |
| 717 | while (self.detectAllocCollision(start, object_size)) |item_end| { | |
| 718 | start = mem.alignForwardGeneric(u64, item_end, min_alignment); | |
| 719 | } | |
| 720 | return start; | |
| 721 | } | |
| 722 | ||
| 723 | /// TODO Improve this to use a table. | |
| 724 | fn makeString(self: *Elf, bytes: []const u8) !u32 { | |
| 725 | try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1); | |
| 726 | const result = self.shstrtab.items.len; | |
| 727 | self.shstrtab.appendSliceAssumeCapacity(bytes); | |
| 728 | self.shstrtab.appendAssumeCapacity(0); | |
| 729 | return @intCast(u32, result); | |
| 730 | } | |
| 731 | ||
| 732 | /// TODO Improve this to use a table. | |
| 733 | fn makeDebugString(self: *Elf, bytes: []const u8) !u32 { | |
| 734 | try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1); | |
| 735 | const result = self.debug_strtab.items.len; | |
| 736 | self.debug_strtab.appendSliceAssumeCapacity(bytes); | |
| 737 | self.debug_strtab.appendAssumeCapacity(0); | |
| 738 | return @intCast(u32, result); | |
| 739 | } | |
| 740 | ||
| 741 | fn getString(self: *Elf, str_off: u32) []const u8 { | |
| 742 | assert(str_off < self.shstrtab.items.len); | |
| 743 | return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); | |
| 744 | } | |
| 745 | ||
| 746 | fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 { | |
| 747 | const existing_name = self.getString(old_str_off); | |
| 748 | if (mem.eql(u8, existing_name, new_name)) { | |
| 749 | return old_str_off; | |
| 750 | } | |
| 751 | return self.makeString(new_name); | |
| 752 | } | |
| 753 | ||
| 754 | pub fn populateMissingMetadata(self: *Elf) !void { | |
| 755 | const small_ptr = switch (self.ptr_width) { | |
| 756 | .p32 => true, | |
| 757 | .p64 => false, | |
| 758 | }; | |
| 759 | const ptr_size: u8 = self.ptrWidthBytes(); | |
| 760 | if (self.phdr_load_re_index == null) { | |
| 761 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); | |
| 762 | const file_size = self.base.options.program_code_size_hint; | |
| 763 | const p_align = 0x1000; | |
| 764 | const off = self.findFreeSpace(file_size, p_align); | |
| 765 | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 766 | try self.program_headers.append(self.base.allocator, .{ | |
| 767 | .p_type = elf.PT_LOAD, | |
| 768 | .p_offset = off, | |
| 769 | .p_filesz = file_size, | |
| 770 | .p_vaddr = default_entry_addr, | |
| 771 | .p_paddr = default_entry_addr, | |
| 772 | .p_memsz = file_size, | |
| 773 | .p_align = p_align, | |
| 774 | .p_flags = elf.PF_X | elf.PF_R, | |
| 775 | }); | |
| 776 | self.entry_addr = null; | |
| 777 | self.phdr_table_dirty = true; | |
| 778 | } | |
| 779 | if (self.phdr_got_index == null) { | |
| 780 | self.phdr_got_index = @intCast(u16, self.program_headers.items.len); | |
| 781 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; | |
| 782 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | |
| 783 | // page align. | |
| 784 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); | |
| 785 | const off = self.findFreeSpace(file_size, p_align); | |
| 786 | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 787 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. | |
| 788 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something | |
| 789 | // else in virtual memory. | |
| 790 | const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000; | |
| 791 | try self.program_headers.append(self.base.allocator, .{ | |
| 792 | .p_type = elf.PT_LOAD, | |
| 793 | .p_offset = off, | |
| 794 | .p_filesz = file_size, | |
| 795 | .p_vaddr = default_got_addr, | |
| 796 | .p_paddr = default_got_addr, | |
| 797 | .p_memsz = file_size, | |
| 798 | .p_align = p_align, | |
| 799 | .p_flags = elf.PF_R, | |
| 800 | }); | |
| 801 | self.phdr_table_dirty = true; | |
| 802 | } | |
| 803 | if (self.shstrtab_index == null) { | |
| 804 | self.shstrtab_index = @intCast(u16, self.sections.items.len); | |
| 805 | assert(self.shstrtab.items.len == 0); | |
| 806 | try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0 | |
| 807 | const off = self.findFreeSpace(self.shstrtab.items.len, 1); | |
| 808 | log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); | |
| 809 | try self.sections.append(self.base.allocator, .{ | |
| 810 | .sh_name = try self.makeString(".shstrtab"), | |
| 811 | .sh_type = elf.SHT_STRTAB, | |
| 812 | .sh_flags = 0, | |
| 813 | .sh_addr = 0, | |
| 814 | .sh_offset = off, | |
| 815 | .sh_size = self.shstrtab.items.len, | |
| 816 | .sh_link = 0, | |
| 817 | .sh_info = 0, | |
| 818 | .sh_addralign = 1, | |
| 819 | .sh_entsize = 0, | |
| 820 | }); | |
| 821 | self.shstrtab_dirty = true; | |
| 822 | self.shdr_table_dirty = true; | |
| 823 | } | |
| 824 | if (self.text_section_index == null) { | |
| 825 | self.text_section_index = @intCast(u16, self.sections.items.len); | |
| 826 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 827 | ||
| 828 | try self.sections.append(self.base.allocator, .{ | |
| 829 | .sh_name = try self.makeString(".text"), | |
| 830 | .sh_type = elf.SHT_PROGBITS, | |
| 831 | .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 832 | .sh_addr = phdr.p_vaddr, | |
| 833 | .sh_offset = phdr.p_offset, | |
| 834 | .sh_size = phdr.p_filesz, | |
| 835 | .sh_link = 0, | |
| 836 | .sh_info = 0, | |
| 837 | .sh_addralign = phdr.p_align, | |
| 838 | .sh_entsize = 0, | |
| 839 | }); | |
| 840 | self.shdr_table_dirty = true; | |
| 841 | } | |
| 842 | if (self.got_section_index == null) { | |
| 843 | self.got_section_index = @intCast(u16, self.sections.items.len); | |
| 844 | const phdr = &self.program_headers.items[self.phdr_got_index.?]; | |
| 845 | ||
| 846 | try self.sections.append(self.base.allocator, .{ | |
| 847 | .sh_name = try self.makeString(".got"), | |
| 848 | .sh_type = elf.SHT_PROGBITS, | |
| 849 | .sh_flags = elf.SHF_ALLOC, | |
| 850 | .sh_addr = phdr.p_vaddr, | |
| 851 | .sh_offset = phdr.p_offset, | |
| 852 | .sh_size = phdr.p_filesz, | |
| 853 | .sh_link = 0, | |
| 854 | .sh_info = 0, | |
| 855 | .sh_addralign = phdr.p_align, | |
| 856 | .sh_entsize = 0, | |
| 857 | }); | |
| 858 | self.shdr_table_dirty = true; | |
| 859 | } | |
| 860 | if (self.symtab_section_index == null) { | |
| 861 | self.symtab_section_index = @intCast(u16, self.sections.items.len); | |
| 862 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | |
| 863 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | |
| 864 | const file_size = self.base.options.symbol_count_hint * each_size; | |
| 865 | const off = self.findFreeSpace(file_size, min_align); | |
| 866 | log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 867 | ||
| 868 | try self.sections.append(self.base.allocator, .{ | |
| 869 | .sh_name = try self.makeString(".symtab"), | |
| 870 | .sh_type = elf.SHT_SYMTAB, | |
| 871 | .sh_flags = 0, | |
| 872 | .sh_addr = 0, | |
| 873 | .sh_offset = off, | |
| 874 | .sh_size = file_size, | |
| 875 | // The section header index of the associated string table. | |
| 876 | .sh_link = self.shstrtab_index.?, | |
| 877 | .sh_info = @intCast(u32, self.local_symbols.items.len), | |
| 878 | .sh_addralign = min_align, | |
| 879 | .sh_entsize = each_size, | |
| 880 | }); | |
| 881 | self.shdr_table_dirty = true; | |
| 882 | try self.writeSymbol(0); | |
| 883 | } | |
| 884 | if (self.debug_str_section_index == null) { | |
| 885 | self.debug_str_section_index = @intCast(u16, self.sections.items.len); | |
| 886 | assert(self.debug_strtab.items.len == 0); | |
| 887 | try self.sections.append(self.base.allocator, .{ | |
| 888 | .sh_name = try self.makeString(".debug_str"), | |
| 889 | .sh_type = elf.SHT_PROGBITS, | |
| 890 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, | |
| 891 | .sh_addr = 0, | |
| 892 | .sh_offset = 0, | |
| 893 | .sh_size = self.debug_strtab.items.len, | |
| 894 | .sh_link = 0, | |
| 895 | .sh_info = 0, | |
| 896 | .sh_addralign = 1, | |
| 897 | .sh_entsize = 1, | |
| 898 | }); | |
| 899 | self.debug_strtab_dirty = true; | |
| 900 | self.shdr_table_dirty = true; | |
| 901 | } | |
| 902 | if (self.debug_info_section_index == null) { | |
| 903 | self.debug_info_section_index = @intCast(u16, self.sections.items.len); | |
| 904 | ||
| 905 | const file_size_hint = 200; | |
| 906 | const p_align = 1; | |
| 907 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 908 | log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{ | |
| 909 | off, | |
| 910 | off + file_size_hint, | |
| 911 | }); | |
| 912 | try self.sections.append(self.base.allocator, .{ | |
| 913 | .sh_name = try self.makeString(".debug_info"), | |
| 914 | .sh_type = elf.SHT_PROGBITS, | |
| 915 | .sh_flags = 0, | |
| 916 | .sh_addr = 0, | |
| 917 | .sh_offset = off, | |
| 918 | .sh_size = file_size_hint, | |
| 919 | .sh_link = 0, | |
| 920 | .sh_info = 0, | |
| 921 | .sh_addralign = p_align, | |
| 922 | .sh_entsize = 0, | |
| 923 | }); | |
| 924 | self.shdr_table_dirty = true; | |
| 925 | self.debug_info_header_dirty = true; | |
| 926 | } | |
| 927 | if (self.debug_abbrev_section_index == null) { | |
| 928 | self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); | |
| 929 | ||
| 930 | const file_size_hint = 128; | |
| 931 | const p_align = 1; | |
| 932 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 933 | log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{ | |
| 934 | off, | |
| 935 | off + file_size_hint, | |
| 936 | }); | |
| 937 | try self.sections.append(self.base.allocator, .{ | |
| 938 | .sh_name = try self.makeString(".debug_abbrev"), | |
| 939 | .sh_type = elf.SHT_PROGBITS, | |
| 940 | .sh_flags = 0, | |
| 941 | .sh_addr = 0, | |
| 942 | .sh_offset = off, | |
| 943 | .sh_size = file_size_hint, | |
| 944 | .sh_link = 0, | |
| 945 | .sh_info = 0, | |
| 946 | .sh_addralign = p_align, | |
| 947 | .sh_entsize = 0, | |
| 948 | }); | |
| 949 | self.shdr_table_dirty = true; | |
| 950 | self.debug_abbrev_section_dirty = true; | |
| 951 | } | |
| 952 | if (self.debug_aranges_section_index == null) { | |
| 953 | self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); | |
| 954 | ||
| 955 | const file_size_hint = 160; | |
| 956 | const p_align = 16; | |
| 957 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 958 | log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{ | |
| 959 | off, | |
| 960 | off + file_size_hint, | |
| 961 | }); | |
| 962 | try self.sections.append(self.base.allocator, .{ | |
| 963 | .sh_name = try self.makeString(".debug_aranges"), | |
| 964 | .sh_type = elf.SHT_PROGBITS, | |
| 965 | .sh_flags = 0, | |
| 966 | .sh_addr = 0, | |
| 967 | .sh_offset = off, | |
| 968 | .sh_size = file_size_hint, | |
| 969 | .sh_link = 0, | |
| 970 | .sh_info = 0, | |
| 971 | .sh_addralign = p_align, | |
| 972 | .sh_entsize = 0, | |
| 973 | }); | |
| 974 | self.shdr_table_dirty = true; | |
| 975 | self.debug_aranges_section_dirty = true; | |
| 976 | } | |
| 977 | if (self.debug_line_section_index == null) { | |
| 978 | self.debug_line_section_index = @intCast(u16, self.sections.items.len); | |
| 979 | ||
| 980 | const file_size_hint = 250; | |
| 981 | const p_align = 1; | |
| 982 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 983 | log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{ | |
| 984 | off, | |
| 985 | off + file_size_hint, | |
| 986 | }); | |
| 987 | try self.sections.append(self.base.allocator, .{ | |
| 988 | .sh_name = try self.makeString(".debug_line"), | |
| 989 | .sh_type = elf.SHT_PROGBITS, | |
| 990 | .sh_flags = 0, | |
| 991 | .sh_addr = 0, | |
| 992 | .sh_offset = off, | |
| 993 | .sh_size = file_size_hint, | |
| 994 | .sh_link = 0, | |
| 995 | .sh_info = 0, | |
| 996 | .sh_addralign = p_align, | |
| 997 | .sh_entsize = 0, | |
| 998 | }); | |
| 999 | self.shdr_table_dirty = true; | |
| 1000 | self.debug_line_header_dirty = true; | |
| 1001 | } | |
| 1002 | const shsize: u64 = switch (self.ptr_width) { | |
| 1003 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 1004 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 1005 | }; | |
| 1006 | const shalign: u16 = switch (self.ptr_width) { | |
| 1007 | .p32 => @alignOf(elf.Elf32_Shdr), | |
| 1008 | .p64 => @alignOf(elf.Elf64_Shdr), | |
| 1009 | }; | |
| 1010 | if (self.shdr_table_offset == null) { | |
| 1011 | self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign); | |
| 1012 | self.shdr_table_dirty = true; | |
| 1013 | } | |
| 1014 | const phsize: u64 = switch (self.ptr_width) { | |
| 1015 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 1016 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 1017 | }; | |
| 1018 | const phalign: u16 = switch (self.ptr_width) { | |
| 1019 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 1020 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 1021 | }; | |
| 1022 | if (self.phdr_table_offset == null) { | |
| 1023 | self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign); | |
| 1024 | self.phdr_table_dirty = true; | |
| 1025 | } | |
| 1026 | { | |
| 1027 | // Iterate over symbols, populating free_list and last_text_block. | |
| 1028 | if (self.local_symbols.items.len != 1) { | |
| 1029 | @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); | |
| 1030 | } | |
| 1031 | // We are starting with an empty file. The default values are correct, null and empty list. | |
| 1032 | } | |
| 1033 | } | |
| 1034 | ||
| 1035 | pub const abbrev_compile_unit = 1; | |
| 1036 | pub const abbrev_subprogram = 2; | |
| 1037 | pub const abbrev_subprogram_retvoid = 3; | |
| 1038 | pub const abbrev_base_type = 4; | |
| 1039 | pub const abbrev_pad1 = 5; | |
| 1040 | pub const abbrev_parameter = 6; | |
| 1041 | ||
| 1042 | /// Commit pending changes and write headers. | |
| 1043 | pub fn flush(self: *Elf, module: *Module) !void { | |
| 1044 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 1045 | const foreign_endian = target_endian != std.Target.current.cpu.arch.endian(); | |
| 1046 | const ptr_width_bytes: u8 = self.ptrWidthBytes(); | |
| 1047 | const init_len_size: usize = switch (self.ptr_width) { | |
| 1048 | .p32 => 4, | |
| 1049 | .p64 => 12, | |
| 1050 | }; | |
| 1051 | ||
| 1052 | // Unfortunately these have to be buffered and done at the end because ELF does not allow | |
| 1053 | // mixing local and global symbols within a symbol table. | |
| 1054 | try self.writeAllGlobalSymbols(); | |
| 1055 | ||
| 1056 | if (self.debug_abbrev_section_dirty) { | |
| 1057 | const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?]; | |
| 1058 | ||
| 1059 | // These are LEB encoded but since the values are all less than 127 | |
| 1060 | // we can simply append these bytes. | |
| 1061 | const abbrev_buf = [_]u8{ | |
| 1062 | abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header | |
| 1063 | DW.AT_stmt_list, DW.FORM_sec_offset, | |
| 1064 | DW.AT_low_pc , DW.FORM_addr, | |
| 1065 | DW.AT_high_pc , DW.FORM_addr, | |
| 1066 | DW.AT_name , DW.FORM_strp, | |
| 1067 | DW.AT_comp_dir , DW.FORM_strp, | |
| 1068 | DW.AT_producer , DW.FORM_strp, | |
| 1069 | DW.AT_language , DW.FORM_data2, | |
| 1070 | 0, 0, // table sentinel | |
| 1071 | ||
| 1072 | abbrev_subprogram, DW.TAG_subprogram, DW.CHILDREN_yes, // header | |
| 1073 | DW.AT_low_pc , DW.FORM_addr, | |
| 1074 | DW.AT_high_pc , DW.FORM_data4, | |
| 1075 | DW.AT_type , DW.FORM_ref4, | |
| 1076 | DW.AT_name , DW.FORM_string, | |
| 1077 | 0, 0, // table sentinel | |
| 1078 | ||
| 1079 | abbrev_subprogram_retvoid, DW.TAG_subprogram, DW.CHILDREN_yes, // header | |
| 1080 | DW.AT_low_pc , DW.FORM_addr, | |
| 1081 | DW.AT_high_pc , DW.FORM_data4, | |
| 1082 | DW.AT_name , DW.FORM_string, | |
| 1083 | 0, 0, // table sentinel | |
| 1084 | ||
| 1085 | abbrev_base_type, DW.TAG_base_type, DW.CHILDREN_no, // header | |
| 1086 | DW.AT_encoding , DW.FORM_data1, | |
| 1087 | DW.AT_byte_size, DW.FORM_data1, | |
| 1088 | DW.AT_name , DW.FORM_string, | |
| 1089 | 0, 0, // table sentinel | |
| 1090 | ||
| 1091 | abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header | |
| 1092 | 0, 0, // table sentinel | |
| 1093 | ||
| 1094 | abbrev_parameter, DW.TAG_formal_parameter, DW.CHILDREN_no, // header | |
| 1095 | DW.AT_location , DW.FORM_exprloc, | |
| 1096 | DW.AT_type , DW.FORM_ref4, | |
| 1097 | DW.AT_name , DW.FORM_string, | |
| 1098 | 0, 0, // table sentinel | |
| 1099 | ||
| 1100 | 0, 0, 0, // section sentinel | |
| 1101 | }; | |
| 1102 | ||
| 1103 | const needed_size = abbrev_buf.len; | |
| 1104 | const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset); | |
| 1105 | if (needed_size > allocated_size) { | |
| 1106 | debug_abbrev_sect.sh_size = 0; // free the space | |
| 1107 | debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 1108 | } | |
| 1109 | debug_abbrev_sect.sh_size = needed_size; | |
| 1110 | log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{ | |
| 1111 | debug_abbrev_sect.sh_offset, | |
| 1112 | debug_abbrev_sect.sh_offset + needed_size, | |
| 1113 | }); | |
| 1114 | ||
| 1115 | const abbrev_offset = 0; | |
| 1116 | self.debug_abbrev_table_offset = abbrev_offset; | |
| 1117 | try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset); | |
| 1118 | if (!self.shdr_table_dirty) { | |
| 1119 | // Then it won't get written with the others and we need to do it. | |
| 1120 | try self.writeSectHeader(self.debug_abbrev_section_index.?); | |
| 1121 | } | |
| 1122 | ||
| 1123 | self.debug_abbrev_section_dirty = false; | |
| 1124 | } | |
| 1125 | ||
| 1126 | if (self.debug_info_header_dirty) debug_info: { | |
| 1127 | // If this value is null it means there is an error in the module; | |
| 1128 | // leave debug_info_header_dirty=true. | |
| 1129 | const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; | |
| 1130 | const last_dbg_info_decl = self.dbg_info_decl_last.?; | |
| 1131 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 1132 | ||
| 1133 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 1134 | defer di_buf.deinit(); | |
| 1135 | ||
| 1136 | // We have a function to compute the upper bound size, because it's needed | |
| 1137 | // for determining where to put the offset of the first `LinkBlock`. | |
| 1138 | try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes()); | |
| 1139 | ||
| 1140 | // initial length - length of the .debug_info contribution for this compilation unit, | |
| 1141 | // not including the initial length itself. | |
| 1142 | // We have to come back and write it later after we know the size. | |
| 1143 | const after_init_len = di_buf.items.len + init_len_size; | |
| 1144 | // +1 for the final 0 that ends the compilation unit children. | |
| 1145 | const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1; | |
| 1146 | const init_len = dbg_info_end - after_init_len; | |
| 1147 | switch (self.ptr_width) { | |
| 1148 | .p32 => { | |
| 1149 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); | |
| 1150 | }, | |
| 1151 | .p64 => { | |
| 1152 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | |
| 1153 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); | |
| 1154 | }, | |
| 1155 | } | |
| 1156 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version | |
| 1157 | const abbrev_offset = self.debug_abbrev_table_offset.?; | |
| 1158 | switch (self.ptr_width) { | |
| 1159 | .p32 => { | |
| 1160 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian); | |
| 1161 | di_buf.appendAssumeCapacity(4); // address size | |
| 1162 | }, | |
| 1163 | .p64 => { | |
| 1164 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); | |
| 1165 | di_buf.appendAssumeCapacity(8); // address size | |
| 1166 | }, | |
| 1167 | } | |
| 1168 | // Write the form for the compile unit, which must match the abbrev table above. | |
| 1169 | const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path); | |
| 1170 | const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path); | |
| 1171 | const producer_strp = try self.makeDebugString(producer_string); | |
| 1172 | // Currently only one compilation unit is supported, so the address range is simply | |
| 1173 | // identical to the main program header virtual address and memory size. | |
| 1174 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1175 | const low_pc = text_phdr.p_vaddr; | |
| 1176 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; | |
| 1177 | ||
| 1178 | di_buf.appendAssumeCapacity(abbrev_compile_unit); | |
| 1179 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset | |
| 1180 | self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); | |
| 1181 | self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); | |
| 1182 | self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); | |
| 1183 | self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp); | |
| 1184 | self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp); | |
| 1185 | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: | |
| 1186 | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 | |
| 1187 | // Until then we say it is C99. | |
| 1188 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); | |
| 1189 | ||
| 1190 | if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { | |
| 1191 | // Move the first N decls to the end to make more padding for the header. | |
| 1192 | @panic("TODO: handle .debug_info header exceeding its padding"); | |
| 1193 | } | |
| 1194 | const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len; | |
| 1195 | try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset); | |
| 1196 | self.debug_info_header_dirty = false; | |
| 1197 | } | |
| 1198 | ||
| 1199 | if (self.debug_aranges_section_dirty) { | |
| 1200 | const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?]; | |
| 1201 | ||
| 1202 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 1203 | defer di_buf.deinit(); | |
| 1204 | ||
| 1205 | // Enough for all the data without resizing. When support for more compilation units | |
| 1206 | // is added, the size of this section will become more variable. | |
| 1207 | try di_buf.ensureCapacity(100); | |
| 1208 | ||
| 1209 | // initial length - length of the .debug_aranges contribution for this compilation unit, | |
| 1210 | // not including the initial length itself. | |
| 1211 | // We have to come back and write it later after we know the size. | |
| 1212 | const init_len_index = di_buf.items.len; | |
| 1213 | di_buf.items.len += init_len_size; | |
| 1214 | const after_init_len = di_buf.items.len; | |
| 1215 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version | |
| 1216 | // When more than one compilation unit is supported, this will be the offset to it. | |
| 1217 | // For now it is always at offset 0 in .debug_info. | |
| 1218 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset | |
| 1219 | di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size | |
| 1220 | di_buf.appendAssumeCapacity(0); // segment_selector_size | |
| 1221 | ||
| 1222 | const end_header_offset = di_buf.items.len; | |
| 1223 | const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2); | |
| 1224 | di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset); | |
| 1225 | ||
| 1226 | // Currently only one compilation unit is supported, so the address range is simply | |
| 1227 | // identical to the main program header virtual address and memory size. | |
| 1228 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1229 | self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr); | |
| 1230 | self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz); | |
| 1231 | ||
| 1232 | // Sentinel. | |
| 1233 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); | |
| 1234 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); | |
| 1235 | ||
| 1236 | // Go back and populate the initial length. | |
| 1237 | const init_len = di_buf.items.len - after_init_len; | |
| 1238 | switch (self.ptr_width) { | |
| 1239 | .p32 => { | |
| 1240 | mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian); | |
| 1241 | }, | |
| 1242 | .p64 => { | |
| 1243 | // initial length - length of the .debug_aranges contribution for this compilation unit, | |
| 1244 | // not including the initial length itself. | |
| 1245 | di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; | |
| 1246 | mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian); | |
| 1247 | }, | |
| 1248 | } | |
| 1249 | ||
| 1250 | const needed_size = di_buf.items.len; | |
| 1251 | const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset); | |
| 1252 | if (needed_size > allocated_size) { | |
| 1253 | debug_aranges_sect.sh_size = 0; // free the space | |
| 1254 | debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16); | |
| 1255 | } | |
| 1256 | debug_aranges_sect.sh_size = needed_size; | |
| 1257 | log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{ | |
| 1258 | debug_aranges_sect.sh_offset, | |
| 1259 | debug_aranges_sect.sh_offset + needed_size, | |
| 1260 | }); | |
| 1261 | ||
| 1262 | try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset); | |
| 1263 | if (!self.shdr_table_dirty) { | |
| 1264 | // Then it won't get written with the others and we need to do it. | |
| 1265 | try self.writeSectHeader(self.debug_aranges_section_index.?); | |
| 1266 | } | |
| 1267 | ||
| 1268 | self.debug_aranges_section_dirty = false; | |
| 1269 | } | |
| 1270 | if (self.debug_line_header_dirty) debug_line: { | |
| 1271 | if (self.dbg_line_fn_first == null) { | |
| 1272 | break :debug_line; // Error in module; leave debug_line_header_dirty=true. | |
| 1273 | } | |
| 1274 | const dbg_line_prg_off = self.getDebugLineProgramOff(); | |
| 1275 | const dbg_line_prg_end = self.getDebugLineProgramEnd(); | |
| 1276 | assert(dbg_line_prg_end != 0); | |
| 1277 | ||
| 1278 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | |
| 1279 | ||
| 1280 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 1281 | defer di_buf.deinit(); | |
| 1282 | ||
| 1283 | // The size of this header is variable, depending on the number of directories, | |
| 1284 | // files, and padding. We have a function to compute the upper bound size, however, | |
| 1285 | // because it's needed for determining where to put the offset of the first `SrcFn`. | |
| 1286 | try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); | |
| 1287 | ||
| 1288 | // initial length - length of the .debug_line contribution for this compilation unit, | |
| 1289 | // not including the initial length itself. | |
| 1290 | const after_init_len = di_buf.items.len + init_len_size; | |
| 1291 | const init_len = dbg_line_prg_end - after_init_len; | |
| 1292 | switch (self.ptr_width) { | |
| 1293 | .p32 => { | |
| 1294 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); | |
| 1295 | }, | |
| 1296 | .p64 => { | |
| 1297 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | |
| 1298 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); | |
| 1299 | }, | |
| 1300 | } | |
| 1301 | ||
| 1302 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version | |
| 1303 | ||
| 1304 | // Empirically, debug info consumers do not respect this field, or otherwise | |
| 1305 | // consider it to be an error when it does not point exactly to the end of the header. | |
| 1306 | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for | |
| 1307 | // padding rather than this field. | |
| 1308 | const before_header_len = di_buf.items.len; | |
| 1309 | di_buf.items.len += ptr_width_bytes; // We will come back and write this. | |
| 1310 | const after_header_len = di_buf.items.len; | |
| 1311 | ||
| 1312 | const opcode_base = DW.LNS_set_isa + 1; | |
| 1313 | di_buf.appendSliceAssumeCapacity(&[_]u8{ | |
| 1314 | 1, // minimum_instruction_length | |
| 1315 | 1, // maximum_operations_per_instruction | |
| 1316 | 1, // default_is_stmt | |
| 1317 | 1, // line_base (signed) | |
| 1318 | 1, // line_range | |
| 1319 | opcode_base, | |
| 1320 | ||
| 1321 | // Standard opcode lengths. The number of items here is based on `opcode_base`. | |
| 1322 | // The value is the number of LEB128 operands the instruction takes. | |
| 1323 | 0, // `DW.LNS_copy` | |
| 1324 | 1, // `DW.LNS_advance_pc` | |
| 1325 | 1, // `DW.LNS_advance_line` | |
| 1326 | 1, // `DW.LNS_set_file` | |
| 1327 | 1, // `DW.LNS_set_column` | |
| 1328 | 0, // `DW.LNS_negate_stmt` | |
| 1329 | 0, // `DW.LNS_set_basic_block` | |
| 1330 | 0, // `DW.LNS_const_add_pc` | |
| 1331 | 1, // `DW.LNS_fixed_advance_pc` | |
| 1332 | 0, // `DW.LNS_set_prologue_end` | |
| 1333 | 0, // `DW.LNS_set_epilogue_begin` | |
| 1334 | 1, // `DW.LNS_set_isa` | |
| 1335 | ||
| 1336 | 0, // include_directories (none except the compilation unit cwd) | |
| 1337 | }); | |
| 1338 | // file_names[0] | |
| 1339 | di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name | |
| 1340 | di_buf.appendSliceAssumeCapacity(&[_]u8{ | |
| 1341 | 0, // null byte for the relative path name | |
| 1342 | 0, // directory_index | |
| 1343 | 0, // mtime (TODO supply this) | |
| 1344 | 0, // file size bytes (TODO supply this) | |
| 1345 | 0, // file_names sentinel | |
| 1346 | }); | |
| 1347 | ||
| 1348 | const header_len = di_buf.items.len - after_header_len; | |
| 1349 | switch (self.ptr_width) { | |
| 1350 | .p32 => { | |
| 1351 | mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); | |
| 1352 | }, | |
| 1353 | .p64 => { | |
| 1354 | mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); | |
| 1355 | }, | |
| 1356 | } | |
| 1357 | ||
| 1358 | // We use NOPs because consumers empirically do not respect the header length field. | |
| 1359 | if (di_buf.items.len > dbg_line_prg_off) { | |
| 1360 | // Move the first N files to the end to make more padding for the header. | |
| 1361 | @panic("TODO: handle .debug_line header exceeding its padding"); | |
| 1362 | } | |
| 1363 | const jmp_amt = dbg_line_prg_off - di_buf.items.len; | |
| 1364 | try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset); | |
| 1365 | self.debug_line_header_dirty = false; | |
| 1366 | } | |
| 1367 | ||
| 1368 | if (self.phdr_table_dirty) { | |
| 1369 | const phsize: u64 = switch (self.ptr_width) { | |
| 1370 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 1371 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 1372 | }; | |
| 1373 | const phalign: u16 = switch (self.ptr_width) { | |
| 1374 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 1375 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 1376 | }; | |
| 1377 | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); | |
| 1378 | const needed_size = self.program_headers.items.len * phsize; | |
| 1379 | ||
| 1380 | if (needed_size > allocated_size) { | |
| 1381 | self.phdr_table_offset = null; // free the space | |
| 1382 | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); | |
| 1383 | } | |
| 1384 | ||
| 1385 | switch (self.ptr_width) { | |
| 1386 | .p32 => { | |
| 1387 | const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); | |
| 1388 | defer self.base.allocator.free(buf); | |
| 1389 | ||
| 1390 | for (buf) |*phdr, i| { | |
| 1391 | phdr.* = progHeaderTo32(self.program_headers.items[i]); | |
| 1392 | if (foreign_endian) { | |
| 1393 | bswapAllFields(elf.Elf32_Phdr, phdr); | |
| 1394 | } | |
| 1395 | } | |
| 1396 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); | |
| 1397 | }, | |
| 1398 | .p64 => { | |
| 1399 | const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); | |
| 1400 | defer self.base.allocator.free(buf); | |
| 1401 | ||
| 1402 | for (buf) |*phdr, i| { | |
| 1403 | phdr.* = self.program_headers.items[i]; | |
| 1404 | if (foreign_endian) { | |
| 1405 | bswapAllFields(elf.Elf64_Phdr, phdr); | |
| 1406 | } | |
| 1407 | } | |
| 1408 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); | |
| 1409 | }, | |
| 1410 | } | |
| 1411 | self.phdr_table_dirty = false; | |
| 1412 | } | |
| 1413 | ||
| 1414 | { | |
| 1415 | const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; | |
| 1416 | if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { | |
| 1417 | const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); | |
| 1418 | const needed_size = self.shstrtab.items.len; | |
| 1419 | ||
| 1420 | if (needed_size > allocated_size) { | |
| 1421 | shstrtab_sect.sh_size = 0; // free the space | |
| 1422 | shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 1423 | } | |
| 1424 | shstrtab_sect.sh_size = needed_size; | |
| 1425 | log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); | |
| 1426 | ||
| 1427 | try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); | |
| 1428 | if (!self.shdr_table_dirty) { | |
| 1429 | // Then it won't get written with the others and we need to do it. | |
| 1430 | try self.writeSectHeader(self.shstrtab_index.?); | |
| 1431 | } | |
| 1432 | self.shstrtab_dirty = false; | |
| 1433 | } | |
| 1434 | } | |
| 1435 | { | |
| 1436 | const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; | |
| 1437 | if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) { | |
| 1438 | const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); | |
| 1439 | const needed_size = self.debug_strtab.items.len; | |
| 1440 | ||
| 1441 | if (needed_size > allocated_size) { | |
| 1442 | debug_strtab_sect.sh_size = 0; // free the space | |
| 1443 | debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 1444 | } | |
| 1445 | debug_strtab_sect.sh_size = needed_size; | |
| 1446 | log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size }); | |
| 1447 | ||
| 1448 | try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset); | |
| 1449 | if (!self.shdr_table_dirty) { | |
| 1450 | // Then it won't get written with the others and we need to do it. | |
| 1451 | try self.writeSectHeader(self.debug_str_section_index.?); | |
| 1452 | } | |
| 1453 | self.debug_strtab_dirty = false; | |
| 1454 | } | |
| 1455 | } | |
| 1456 | if (self.shdr_table_dirty) { | |
| 1457 | const shsize: u64 = switch (self.ptr_width) { | |
| 1458 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 1459 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 1460 | }; | |
| 1461 | const shalign: u16 = switch (self.ptr_width) { | |
| 1462 | .p32 => @alignOf(elf.Elf32_Shdr), | |
| 1463 | .p64 => @alignOf(elf.Elf64_Shdr), | |
| 1464 | }; | |
| 1465 | const allocated_size = self.allocatedSize(self.shdr_table_offset.?); | |
| 1466 | const needed_size = self.sections.items.len * shsize; | |
| 1467 | ||
| 1468 | if (needed_size > allocated_size) { | |
| 1469 | self.shdr_table_offset = null; // free the space | |
| 1470 | self.shdr_table_offset = self.findFreeSpace(needed_size, shalign); | |
| 1471 | } | |
| 1472 | ||
| 1473 | switch (self.ptr_width) { | |
| 1474 | .p32 => { | |
| 1475 | const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); | |
| 1476 | defer self.base.allocator.free(buf); | |
| 1477 | ||
| 1478 | for (buf) |*shdr, i| { | |
| 1479 | shdr.* = sectHeaderTo32(self.sections.items[i]); | |
| 1480 | log.debug("writing section {}\n", .{shdr.*}); | |
| 1481 | if (foreign_endian) { | |
| 1482 | bswapAllFields(elf.Elf32_Shdr, shdr); | |
| 1483 | } | |
| 1484 | } | |
| 1485 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); | |
| 1486 | }, | |
| 1487 | .p64 => { | |
| 1488 | const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); | |
| 1489 | defer self.base.allocator.free(buf); | |
| 1490 | ||
| 1491 | for (buf) |*shdr, i| { | |
| 1492 | shdr.* = self.sections.items[i]; | |
| 1493 | log.debug("writing section {}\n", .{shdr.*}); | |
| 1494 | if (foreign_endian) { | |
| 1495 | bswapAllFields(elf.Elf64_Shdr, shdr); | |
| 1496 | } | |
| 1497 | } | |
| 1498 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); | |
| 1499 | }, | |
| 1500 | } | |
| 1501 | self.shdr_table_dirty = false; | |
| 1502 | } | |
| 1503 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | |
| 1504 | log.debug("flushing. no_entry_point_found = true\n", .{}); | |
| 1505 | self.error_flags.no_entry_point_found = true; | |
| 1506 | } else { | |
| 1507 | log.debug("flushing. no_entry_point_found = false\n", .{}); | |
| 1508 | self.error_flags.no_entry_point_found = false; | |
| 1509 | try self.writeElfHeader(); | |
| 1510 | } | |
| 1511 | ||
| 1512 | // The point of flush() is to commit changes, so in theory, nothing should | |
| 1513 | // be dirty after this. However, it is possible for some things to remain | |
| 1514 | // dirty because they fail to be written in the event of compile errors, | |
| 1515 | // such as debug_line_header_dirty and debug_info_header_dirty. | |
| 1516 | assert(!self.debug_abbrev_section_dirty); | |
| 1517 | assert(!self.debug_aranges_section_dirty); | |
| 1518 | assert(!self.phdr_table_dirty); | |
| 1519 | assert(!self.shdr_table_dirty); | |
| 1520 | assert(!self.shstrtab_dirty); | |
| 1521 | assert(!self.debug_strtab_dirty); | |
| 1522 | } | |
| 1523 | ||
| 1524 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { | |
| 1525 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 1526 | switch (self.ptr_width) { | |
| 1527 | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian), | |
| 1528 | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), | |
| 1529 | } | |
| 1530 | } | |
| 1531 | ||
| 1532 | fn writeElfHeader(self: *Elf) !void { | |
| 1533 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; | |
| 1534 | ||
| 1535 | var index: usize = 0; | |
| 1536 | hdr_buf[0..4].* = "\x7fELF".*; | |
| 1537 | index += 4; | |
| 1538 | ||
| 1539 | hdr_buf[index] = switch (self.ptr_width) { | |
| 1540 | .p32 => elf.ELFCLASS32, | |
| 1541 | .p64 => elf.ELFCLASS64, | |
| 1542 | }; | |
| 1543 | index += 1; | |
| 1544 | ||
| 1545 | const endian = self.base.options.target.cpu.arch.endian(); | |
| 1546 | hdr_buf[index] = switch (endian) { | |
| 1547 | .Little => elf.ELFDATA2LSB, | |
| 1548 | .Big => elf.ELFDATA2MSB, | |
| 1549 | }; | |
| 1550 | index += 1; | |
| 1551 | ||
| 1552 | hdr_buf[index] = 1; // ELF version | |
| 1553 | index += 1; | |
| 1554 | ||
| 1555 | // OS ABI, often set to 0 regardless of target platform | |
| 1556 | // ABI Version, possibly used by glibc but not by static executables | |
| 1557 | // padding | |
| 1558 | mem.set(u8, hdr_buf[index..][0..9], 0); | |
| 1559 | index += 9; | |
| 1560 | ||
| 1561 | assert(index == 16); | |
| 1562 | ||
| 1563 | const elf_type = switch (self.base.options.output_mode) { | |
| 1564 | .Exe => elf.ET.EXEC, | |
| 1565 | .Obj => elf.ET.REL, | |
| 1566 | .Lib => switch (self.base.options.link_mode) { | |
| 1567 | .Static => elf.ET.REL, | |
| 1568 | .Dynamic => elf.ET.DYN, | |
| 1569 | }, | |
| 1570 | }; | |
| 1571 | mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian); | |
| 1572 | index += 2; | |
| 1573 | ||
| 1574 | const machine = self.base.options.target.cpu.arch.toElfMachine(); | |
| 1575 | mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian); | |
| 1576 | index += 2; | |
| 1577 | ||
| 1578 | // ELF Version, again | |
| 1579 | mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); | |
| 1580 | index += 4; | |
| 1581 | ||
| 1582 | const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?; | |
| 1583 | ||
| 1584 | switch (self.ptr_width) { | |
| 1585 | .p32 => { | |
| 1586 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian); | |
| 1587 | index += 4; | |
| 1588 | ||
| 1589 | // e_phoff | |
| 1590 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian); | |
| 1591 | index += 4; | |
| 1592 | ||
| 1593 | // e_shoff | |
| 1594 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian); | |
| 1595 | index += 4; | |
| 1596 | }, | |
| 1597 | .p64 => { | |
| 1598 | // e_entry | |
| 1599 | mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian); | |
| 1600 | index += 8; | |
| 1601 | ||
| 1602 | // e_phoff | |
| 1603 | mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian); | |
| 1604 | index += 8; | |
| 1605 | ||
| 1606 | // e_shoff | |
| 1607 | mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian); | |
| 1608 | index += 8; | |
| 1609 | }, | |
| 1610 | } | |
| 1611 | ||
| 1612 | const e_flags = 0; | |
| 1613 | mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian); | |
| 1614 | index += 4; | |
| 1615 | ||
| 1616 | const e_ehsize: u16 = switch (self.ptr_width) { | |
| 1617 | .p32 => @sizeOf(elf.Elf32_Ehdr), | |
| 1618 | .p64 => @sizeOf(elf.Elf64_Ehdr), | |
| 1619 | }; | |
| 1620 | mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian); | |
| 1621 | index += 2; | |
| 1622 | ||
| 1623 | const e_phentsize: u16 = switch (self.ptr_width) { | |
| 1624 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 1625 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 1626 | }; | |
| 1627 | mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); | |
| 1628 | index += 2; | |
| 1629 | ||
| 1630 | const e_phnum = @intCast(u16, self.program_headers.items.len); | |
| 1631 | mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian); | |
| 1632 | index += 2; | |
| 1633 | ||
| 1634 | const e_shentsize: u16 = switch (self.ptr_width) { | |
| 1635 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 1636 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 1637 | }; | |
| 1638 | mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); | |
| 1639 | index += 2; | |
| 1640 | ||
| 1641 | const e_shnum = @intCast(u16, self.sections.items.len); | |
| 1642 | mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); | |
| 1643 | index += 2; | |
| 1644 | ||
| 1645 | mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian); | |
| 1646 | index += 2; | |
| 1647 | ||
| 1648 | assert(index == e_ehsize); | |
| 1649 | ||
| 1650 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); | |
| 1651 | } | |
| 1652 | ||
| 1653 | fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | |
| 1654 | var already_have_free_list_node = false; | |
| 1655 | { | |
| 1656 | var i: usize = 0; | |
| 1657 | while (i < self.text_block_free_list.items.len) { | |
| 1658 | if (self.text_block_free_list.items[i] == text_block) { | |
| 1659 | _ = self.text_block_free_list.swapRemove(i); | |
| 1660 | continue; | |
| 1661 | } | |
| 1662 | if (self.text_block_free_list.items[i] == text_block.prev) { | |
| 1663 | already_have_free_list_node = true; | |
| 1664 | } | |
| 1665 | i += 1; | |
| 1666 | } | |
| 1667 | } | |
| 1668 | ||
| 1669 | if (self.last_text_block == text_block) { | |
| 1670 | // TODO shrink the .text section size here | |
| 1671 | self.last_text_block = text_block.prev; | |
| 1672 | } | |
| 1673 | ||
| 1674 | if (text_block.prev) |prev| { | |
| 1675 | prev.next = text_block.next; | |
| 1676 | ||
| 1677 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { | |
| 1678 | // The free list is heuristics, it doesn't have to be perfect, so we can | |
| 1679 | // ignore the OOM here. | |
| 1680 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; | |
| 1681 | } | |
| 1682 | } else { | |
| 1683 | text_block.prev = null; | |
| 1684 | } | |
| 1685 | ||
| 1686 | if (text_block.next) |next| { | |
| 1687 | next.prev = text_block.prev; | |
| 1688 | } else { | |
| 1689 | text_block.next = null; | |
| 1690 | } | |
| 1691 | } | |
| 1692 | ||
| 1693 | fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void { | |
| 1694 | // TODO check the new capacity, and if it crosses the size threshold into a big enough | |
| 1695 | // capacity, insert a free list node for it. | |
| 1696 | } | |
| 1697 | ||
| 1698 | fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | |
| 1699 | const sym = self.local_symbols.items[text_block.local_sym_index]; | |
| 1700 | const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; | |
| 1701 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); | |
| 1702 | if (!need_realloc) return sym.st_value; | |
| 1703 | return self.allocateTextBlock(text_block, new_block_size, alignment); | |
| 1704 | } | |
| 1705 | ||
| 1706 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | |
| 1707 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1708 | const shdr = &self.sections.items[self.text_section_index.?]; | |
| 1709 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | |
| 1710 | ||
| 1711 | // We use these to indicate our intention to update metadata, placing the new block, | |
| 1712 | // and possibly removing a free list node. | |
| 1713 | // It would be simpler to do it inside the for loop below, but that would cause a | |
| 1714 | // problem if an error was returned later in the function. So this action | |
| 1715 | // is actually carried out at the end of the function, when errors are no longer possible. | |
| 1716 | var block_placement: ?*TextBlock = null; | |
| 1717 | var free_list_removal: ?usize = null; | |
| 1718 | ||
| 1719 | // First we look for an appropriately sized free list node. | |
| 1720 | // The list is unordered. We'll just take the first thing that works. | |
| 1721 | const vaddr = blk: { | |
| 1722 | var i: usize = 0; | |
| 1723 | while (i < self.text_block_free_list.items.len) { | |
| 1724 | const big_block = self.text_block_free_list.items[i]; | |
| 1725 | // We now have a pointer to a live text block that has too much capacity. | |
| 1726 | // Is it enough that we could fit this new text block? | |
| 1727 | const sym = self.local_symbols.items[big_block.local_sym_index]; | |
| 1728 | const capacity = big_block.capacity(self.*); | |
| 1729 | const ideal_capacity = capacity * alloc_num / alloc_den; | |
| 1730 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | |
| 1731 | const capacity_end_vaddr = sym.st_value + capacity; | |
| 1732 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; | |
| 1733 | const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); | |
| 1734 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | |
| 1735 | // Additional bookkeeping here to notice if this free list node | |
| 1736 | // should be deleted because the block that it points to has grown to take up | |
| 1737 | // more of the extra capacity. | |
| 1738 | if (!big_block.freeListEligible(self.*)) { | |
| 1739 | _ = self.text_block_free_list.swapRemove(i); | |
| 1740 | } else { | |
| 1741 | i += 1; | |
| 1742 | } | |
| 1743 | continue; | |
| 1744 | } | |
| 1745 | // At this point we know that we will place the new block here. But the | |
| 1746 | // remaining question is whether there is still yet enough capacity left | |
| 1747 | // over for there to still be a free list node. | |
| 1748 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; | |
| 1749 | const keep_free_list_node = remaining_capacity >= min_text_capacity; | |
| 1750 | ||
| 1751 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 1752 | block_placement = big_block; | |
| 1753 | if (!keep_free_list_node) { | |
| 1754 | free_list_removal = i; | |
| 1755 | } | |
| 1756 | break :blk new_start_vaddr; | |
| 1757 | } else if (self.last_text_block) |last| { | |
| 1758 | const sym = self.local_symbols.items[last.local_sym_index]; | |
| 1759 | const ideal_capacity = sym.st_size * alloc_num / alloc_den; | |
| 1760 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | |
| 1761 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); | |
| 1762 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 1763 | block_placement = last; | |
| 1764 | break :blk new_start_vaddr; | |
| 1765 | } else { | |
| 1766 | break :blk phdr.p_vaddr; | |
| 1767 | } | |
| 1768 | }; | |
| 1769 | ||
| 1770 | const expand_text_section = block_placement == null or block_placement.?.next == null; | |
| 1771 | if (expand_text_section) { | |
| 1772 | const text_capacity = self.allocatedSize(shdr.sh_offset); | |
| 1773 | const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; | |
| 1774 | if (needed_size > text_capacity) { | |
| 1775 | // Must move the entire text section. | |
| 1776 | const new_offset = self.findFreeSpace(needed_size, 0x1000); | |
| 1777 | const text_size = if (self.last_text_block) |last| blk: { | |
| 1778 | const sym = self.local_symbols.items[last.local_sym_index]; | |
| 1779 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; | |
| 1780 | } else 0; | |
| 1781 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size); | |
| 1782 | if (amt != text_size) return error.InputOutput; | |
| 1783 | shdr.sh_offset = new_offset; | |
| 1784 | phdr.p_offset = new_offset; | |
| 1785 | } | |
| 1786 | self.last_text_block = text_block; | |
| 1787 | ||
| 1788 | shdr.sh_size = needed_size; | |
| 1789 | phdr.p_memsz = needed_size; | |
| 1790 | phdr.p_filesz = needed_size; | |
| 1791 | ||
| 1792 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address | |
| 1793 | // range of the compilation unit. When we expand the text section, this range changes, | |
| 1794 | // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty. | |
| 1795 | self.debug_info_header_dirty = true; | |
| 1796 | // This becomes dirty for the same reason. We could potentially make this more | |
| 1797 | // fine-grained with the addition of support for more compilation units. It is planned to | |
| 1798 | // model each package as a different compilation unit. | |
| 1799 | self.debug_aranges_section_dirty = true; | |
| 1800 | ||
| 1801 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | |
| 1802 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 1803 | } | |
| 1804 | ||
| 1805 | // This function can also reallocate a text block. | |
| 1806 | // In this case we need to "unplug" it from its previous location before | |
| 1807 | // plugging it in to its new location. | |
| 1808 | if (text_block.prev) |prev| { | |
| 1809 | prev.next = text_block.next; | |
| 1810 | } | |
| 1811 | if (text_block.next) |next| { | |
| 1812 | next.prev = text_block.prev; | |
| 1813 | } | |
| 1814 | ||
| 1815 | if (block_placement) |big_block| { | |
| 1816 | text_block.prev = big_block; | |
| 1817 | text_block.next = big_block.next; | |
| 1818 | big_block.next = text_block; | |
| 1819 | } else { | |
| 1820 | text_block.prev = null; | |
| 1821 | text_block.next = null; | |
| 1822 | } | |
| 1823 | if (free_list_removal) |i| { | |
| 1824 | _ = self.text_block_free_list.swapRemove(i); | |
| 1825 | } | |
| 1826 | return vaddr; | |
| 1827 | } | |
| 1828 | ||
| 1829 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | |
| 1830 | if (decl.link.elf.local_sym_index != 0) return; | |
| 1831 | ||
| 1832 | try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); | |
| 1833 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | |
| 1834 | ||
| 1835 | if (self.local_symbol_free_list.popOrNull()) |i| { | |
| 1836 | log.debug("reusing symbol index {} for {}\n", .{ i, decl.name }); | |
| 1837 | decl.link.elf.local_sym_index = i; | |
| 1838 | } else { | |
| 1839 | log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); | |
| 1840 | decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len); | |
| 1841 | _ = self.local_symbols.addOneAssumeCapacity(); | |
| 1842 | } | |
| 1843 | ||
| 1844 | if (self.offset_table_free_list.popOrNull()) |i| { | |
| 1845 | decl.link.elf.offset_table_index = i; | |
| 1846 | } else { | |
| 1847 | decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len); | |
| 1848 | _ = self.offset_table.addOneAssumeCapacity(); | |
| 1849 | self.offset_table_count_dirty = true; | |
| 1850 | } | |
| 1851 | ||
| 1852 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1853 | ||
| 1854 | self.local_symbols.items[decl.link.elf.local_sym_index] = .{ | |
| 1855 | .st_name = 0, | |
| 1856 | .st_info = 0, | |
| 1857 | .st_other = 0, | |
| 1858 | .st_shndx = 0, | |
| 1859 | .st_value = phdr.p_vaddr, | |
| 1860 | .st_size = 0, | |
| 1861 | }; | |
| 1862 | self.offset_table.items[decl.link.elf.offset_table_index] = 0; | |
| 1863 | } | |
| 1864 | ||
| 1865 | pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | |
| 1866 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | |
| 1867 | self.freeTextBlock(&decl.link.elf); | |
| 1868 | if (decl.link.elf.local_sym_index != 0) { | |
| 1869 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; | |
| 1870 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; | |
| 1871 | ||
| 1872 | self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; | |
| 1873 | ||
| 1874 | decl.link.elf.local_sym_index = 0; | |
| 1875 | } | |
| 1876 | // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing | |
| 1877 | // is desired for both. | |
| 1878 | _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); | |
| 1879 | if (decl.fn_link.elf.prev) |prev| { | |
| 1880 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 1881 | prev.next = decl.fn_link.elf.next; | |
| 1882 | if (decl.fn_link.elf.next) |next| { | |
| 1883 | next.prev = prev; | |
| 1884 | } else { | |
| 1885 | self.dbg_line_fn_last = prev; | |
| 1886 | } | |
| 1887 | } else if (decl.fn_link.elf.next) |next| { | |
| 1888 | self.dbg_line_fn_first = next; | |
| 1889 | next.prev = null; | |
| 1890 | } | |
| 1891 | if (self.dbg_line_fn_first == &decl.fn_link.elf) { | |
| 1892 | self.dbg_line_fn_first = null; | |
| 1893 | } | |
| 1894 | if (self.dbg_line_fn_last == &decl.fn_link.elf) { | |
| 1895 | self.dbg_line_fn_last = null; | |
| 1896 | } | |
| 1897 | } | |
| 1898 | ||
| 1899 | pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | |
| 1900 | const tracy = trace(@src()); | |
| 1901 | defer tracy.end(); | |
| 1902 | ||
| 1903 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1904 | defer code_buffer.deinit(); | |
| 1905 | ||
| 1906 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1907 | defer dbg_line_buffer.deinit(); | |
| 1908 | ||
| 1909 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1910 | defer dbg_info_buffer.deinit(); | |
| 1911 | ||
| 1912 | var dbg_info_type_relocs: DbgInfoTypeRelocsTable = .{}; | |
| 1913 | defer { | |
| 1914 | for (dbg_info_type_relocs.items()) |*entry| { | |
| 1915 | entry.value.relocs.deinit(self.base.allocator); | |
| 1916 | } | |
| 1917 | dbg_info_type_relocs.deinit(self.base.allocator); | |
| 1918 | } | |
| 1919 | ||
| 1920 | const typed_value = decl.typed_value.most_recent.typed_value; | |
| 1921 | const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { | |
| 1922 | .Fn => true, | |
| 1923 | else => false, | |
| 1924 | }; | |
| 1925 | if (is_fn) { | |
| 1926 | //if (mem.eql(u8, mem.spanZ(decl.name), "add")) { | |
| 1927 | // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*); | |
| 1928 | //} | |
| 1929 | ||
| 1930 | // For functions we need to add a prologue to the debug line program. | |
| 1931 | try dbg_line_buffer.ensureCapacity(26); | |
| 1932 | ||
| 1933 | const line_off: u28 = blk: { | |
| 1934 | if (decl.scope.cast(Module.Scope.File)) |scope_file| { | |
| 1935 | const tree = scope_file.contents.tree; | |
| 1936 | const file_ast_decls = tree.root_node.decls(); | |
| 1937 | // TODO Look into improving the performance here by adding a token-index-to-line | |
| 1938 | // lookup table. Currently this involves scanning over the source code for newlines. | |
| 1939 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | |
| 1940 | const block = fn_proto.body().?.castTag(.Block).?; | |
| 1941 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); | |
| 1942 | break :blk @intCast(u28, line_delta); | |
| 1943 | } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| { | |
| 1944 | const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src; | |
| 1945 | const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off); | |
| 1946 | break :blk @intCast(u28, line_delta); | |
| 1947 | } else { | |
| 1948 | unreachable; | |
| 1949 | } | |
| 1950 | }; | |
| 1951 | ||
| 1952 | const ptr_width_bytes = self.ptrWidthBytes(); | |
| 1953 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | |
| 1954 | DW.LNS_extended_op, | |
| 1955 | ptr_width_bytes + 1, | |
| 1956 | DW.LNE_set_address, | |
| 1957 | }); | |
| 1958 | // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. | |
| 1959 | assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); | |
| 1960 | dbg_line_buffer.items.len += ptr_width_bytes; | |
| 1961 | ||
| 1962 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); | |
| 1963 | // This is the "relocatable" relative line offset from the previous function's end curly | |
| 1964 | // to this function's begin curly. | |
| 1965 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); | |
| 1966 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. | |
| 1967 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); | |
| 1968 | ||
| 1969 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); | |
| 1970 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); | |
| 1971 | // Once we support more than one source file, this will have the ability to be more | |
| 1972 | // than one possible value. | |
| 1973 | const file_index = 1; | |
| 1974 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); | |
| 1975 | ||
| 1976 | // Emit a line for the begin curly with prologue_end=false. The codegen will | |
| 1977 | // do the work of setting prologue_end=true and epilogue_begin=true. | |
| 1978 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); | |
| 1979 | ||
| 1980 | // .debug_info subprogram | |
| 1981 | const decl_name_with_null = decl.name[0..mem.lenZ(decl.name) + 1]; | |
| 1982 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); | |
| 1983 | ||
| 1984 | const fn_ret_type = typed_value.ty.fnReturnType(); | |
| 1985 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | |
| 1986 | if (fn_ret_has_bits) { | |
| 1987 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | |
| 1988 | } else { | |
| 1989 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); | |
| 1990 | } | |
| 1991 | // These get overwritten after generating the machine code. These values are | |
| 1992 | // "relocations" and have to be in this fixed place so that functions can be | |
| 1993 | // moved in virtual address space. | |
| 1994 | assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); | |
| 1995 | dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr | |
| 1996 | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); | |
| 1997 | dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 | |
| 1998 | if (fn_ret_has_bits) { | |
| 1999 | const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); | |
| 2000 | if (!gop.found_existing) { | |
| 2001 | gop.entry.value = .{ | |
| 2002 | .off = undefined, | |
| 2003 | .relocs = .{}, | |
| 2004 | }; | |
| 2005 | } | |
| 2006 | try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); | |
| 2007 | dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 | |
| 2008 | } | |
| 2009 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string | |
| 2010 | } else { | |
| 2011 | // TODO implement .debug_info for global variables | |
| 2012 | } | |
| 2013 | const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs); | |
| 2014 | const code = switch (res) { | |
| 2015 | .externally_managed => |x| x, | |
| 2016 | .appended => code_buffer.items, | |
| 2017 | .fail => |em| { | |
| 2018 | decl.analysis = .codegen_failure; | |
| 2019 | try module.failed_decls.put(module.gpa, decl, em); | |
| 2020 | return; | |
| 2021 | }, | |
| 2022 | }; | |
| 2023 | ||
| 2024 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | |
| 2025 | ||
| 2026 | const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; | |
| 2027 | ||
| 2028 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | |
| 2029 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | |
| 2030 | if (local_sym.st_size != 0) { | |
| 2031 | const capacity = decl.link.elf.capacity(self.*); | |
| 2032 | const need_realloc = code.len > capacity or | |
| 2033 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); | |
| 2034 | if (need_realloc) { | |
| 2035 | const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment); | |
| 2036 | log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); | |
| 2037 | if (vaddr != local_sym.st_value) { | |
| 2038 | local_sym.st_value = vaddr; | |
| 2039 | ||
| 2040 | log.debug(" (writing new offset table entry)\n", .{}); | |
| 2041 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; | |
| 2042 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | |
| 2043 | } | |
| 2044 | } else if (code.len < local_sym.st_size) { | |
| 2045 | self.shrinkTextBlock(&decl.link.elf, code.len); | |
| 2046 | } | |
| 2047 | local_sym.st_size = code.len; | |
| 2048 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name)); | |
| 2049 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; | |
| 2050 | local_sym.st_other = 0; | |
| 2051 | local_sym.st_shndx = self.text_section_index.?; | |
| 2052 | // TODO this write could be avoided if no fields of the symbol were changed. | |
| 2053 | try self.writeSymbol(decl.link.elf.local_sym_index); | |
| 2054 | } else { | |
| 2055 | const decl_name = mem.spanZ(decl.name); | |
| 2056 | const name_str_index = try self.makeString(decl_name); | |
| 2057 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment); | |
| 2058 | log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); | |
| 2059 | errdefer self.freeTextBlock(&decl.link.elf); | |
| 2060 | ||
| 2061 | local_sym.* = .{ | |
| 2062 | .st_name = name_str_index, | |
| 2063 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, | |
| 2064 | .st_other = 0, | |
| 2065 | .st_shndx = self.text_section_index.?, | |
| 2066 | .st_value = vaddr, | |
| 2067 | .st_size = code.len, | |
| 2068 | }; | |
| 2069 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; | |
| 2070 | ||
| 2071 | try self.writeSymbol(decl.link.elf.local_sym_index); | |
| 2072 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | |
| 2073 | } | |
| 2074 | ||
| 2075 | const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr; | |
| 2076 | const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; | |
| 2077 | try self.base.file.?.pwriteAll(code, file_offset); | |
| 2078 | ||
| 2079 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 2080 | ||
| 2081 | const text_block = &decl.link.elf; | |
| 2082 | ||
| 2083 | // If the Decl is a function, we need to update the .debug_line program. | |
| 2084 | if (is_fn) { | |
| 2085 | // Perform the relocations based on vaddr. | |
| 2086 | switch (self.ptr_width) { | |
| 2087 | .p32 => { | |
| 2088 | { | |
| 2089 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; | |
| 2090 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | |
| 2091 | } | |
| 2092 | { | |
| 2093 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; | |
| 2094 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | |
| 2095 | } | |
| 2096 | }, | |
| 2097 | .p64 => { | |
| 2098 | { | |
| 2099 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; | |
| 2100 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | |
| 2101 | } | |
| 2102 | { | |
| 2103 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; | |
| 2104 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | |
| 2105 | } | |
| 2106 | }, | |
| 2107 | } | |
| 2108 | { | |
| 2109 | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; | |
| 2110 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); | |
| 2111 | } | |
| 2112 | ||
| 2113 | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); | |
| 2114 | ||
| 2115 | // Now we have the full contents and may allocate a region to store it. | |
| 2116 | ||
| 2117 | // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for | |
| 2118 | // `TextBlock` and the .debug_info. If you are editing this logic, you | |
| 2119 | // probably need to edit that logic too. | |
| 2120 | ||
| 2121 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | |
| 2122 | const src_fn = &decl.fn_link.elf; | |
| 2123 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | |
| 2124 | if (self.dbg_line_fn_last) |last| { | |
| 2125 | if (src_fn.next) |next| { | |
| 2126 | // Update existing function - non-last item. | |
| 2127 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | |
| 2128 | // It grew too big, so we move it to a new location. | |
| 2129 | if (src_fn.prev) |prev| { | |
| 2130 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2131 | prev.next = src_fn.next; | |
| 2132 | } | |
| 2133 | next.prev = src_fn.prev; | |
| 2134 | src_fn.next = null; | |
| 2135 | // Populate where it used to be with NOPs. | |
| 2136 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | |
| 2137 | try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); | |
| 2138 | // TODO Look at the free list before appending at the end. | |
| 2139 | src_fn.prev = last; | |
| 2140 | last.next = src_fn; | |
| 2141 | self.dbg_line_fn_last = src_fn; | |
| 2142 | ||
| 2143 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | |
| 2144 | } | |
| 2145 | } else if (src_fn.prev == null) { | |
| 2146 | // Append new function. | |
| 2147 | // TODO Look at the free list before appending at the end. | |
| 2148 | src_fn.prev = last; | |
| 2149 | last.next = src_fn; | |
| 2150 | self.dbg_line_fn_last = src_fn; | |
| 2151 | ||
| 2152 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | |
| 2153 | } | |
| 2154 | } else { | |
| 2155 | // This is the first function of the Line Number Program. | |
| 2156 | self.dbg_line_fn_first = src_fn; | |
| 2157 | self.dbg_line_fn_last = src_fn; | |
| 2158 | ||
| 2159 | src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; | |
| 2160 | } | |
| 2161 | ||
| 2162 | const last_src_fn = self.dbg_line_fn_last.?; | |
| 2163 | const needed_size = last_src_fn.off + last_src_fn.len; | |
| 2164 | if (needed_size != debug_line_sect.sh_size) { | |
| 2165 | if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { | |
| 2166 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 2167 | const existing_size = last_src_fn.off; | |
| 2168 | log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{ | |
| 2169 | existing_size, | |
| 2170 | debug_line_sect.sh_offset, | |
| 2171 | new_offset, | |
| 2172 | }); | |
| 2173 | const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 2174 | if (amt != existing_size) return error.InputOutput; | |
| 2175 | debug_line_sect.sh_offset = new_offset; | |
| 2176 | } | |
| 2177 | debug_line_sect.sh_size = needed_size; | |
| 2178 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 2179 | self.debug_line_header_dirty = true; | |
| 2180 | } | |
| 2181 | const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; | |
| 2182 | const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | |
| 2183 | ||
| 2184 | // We only have support for one compilation unit so far, so the offsets are directly | |
| 2185 | // from the .debug_line section. | |
| 2186 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | |
| 2187 | try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); | |
| 2188 | ||
| 2189 | // .debug_info - End the TAG_subprogram children. | |
| 2190 | try dbg_info_buffer.append(0); | |
| 2191 | } | |
| 2192 | ||
| 2193 | // Now we emit the .debug_info types of the Decl. These will count towards the size of | |
| 2194 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual | |
| 2195 | // relocations yet. | |
| 2196 | for (dbg_info_type_relocs.items()) |*entry| { | |
| 2197 | entry.value.off = @intCast(u32, dbg_info_buffer.items.len); | |
| 2198 | try self.addDbgInfoType(entry.key, &dbg_info_buffer); | |
| 2199 | } | |
| 2200 | ||
| 2201 | try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); | |
| 2202 | ||
| 2203 | // Now that we have the offset assigned we can finally perform type relocations. | |
| 2204 | for (dbg_info_type_relocs.items()) |entry| { | |
| 2205 | for (entry.value.relocs.items) |off| { | |
| 2206 | mem.writeInt( | |
| 2207 | u32, | |
| 2208 | dbg_info_buffer.items[off..][0..4], | |
| 2209 | text_block.dbg_info_off + entry.value.off, | |
| 2210 | target_endian, | |
| 2211 | ); | |
| 2212 | } | |
| 2213 | } | |
| 2214 | ||
| 2215 | try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items); | |
| 2216 | ||
| 2217 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | |
| 2218 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | |
| 2219 | return self.updateDeclExports(module, decl, decl_exports); | |
| 2220 | } | |
| 2221 | ||
| 2222 | /// Asserts the type has codegen bits. | |
| 2223 | fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { | |
| 2224 | switch (ty.zigTypeTag()) { | |
| 2225 | .Void => unreachable, | |
| 2226 | .NoReturn => unreachable, | |
| 2227 | .Bool => { | |
| 2228 | try dbg_info_buffer.appendSlice(&[_]u8{ | |
| 2229 | abbrev_base_type, | |
| 2230 | DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 | |
| 2231 | 1, // DW.AT_byte_size, DW.FORM_data1 | |
| 2232 | 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string | |
| 2233 | }); | |
| 2234 | }, | |
| 2235 | .Int => { | |
| 2236 | const info = ty.intInfo(self.base.options.target); | |
| 2237 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); | |
| 2238 | dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); | |
| 2239 | // DW.AT_encoding, DW.FORM_data1 | |
| 2240 | dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned); | |
| 2241 | // DW.AT_byte_size, DW.FORM_data1 | |
| 2242 | dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); | |
| 2243 | // DW.AT_name, DW.FORM_string | |
| 2244 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); | |
| 2245 | }, | |
| 2246 | else => { | |
| 2247 | std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty}); | |
| 2248 | try dbg_info_buffer.append(abbrev_pad1); | |
| 2249 | }, | |
| 2250 | } | |
| 2251 | } | |
| 2252 | ||
| 2253 | fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void { | |
| 2254 | const tracy = trace(@src()); | |
| 2255 | defer tracy.end(); | |
| 2256 | ||
| 2257 | // This logic is nearly identical to the logic above in `updateDecl` for | |
| 2258 | // `SrcFn` and the line number programs. If you are editing this logic, you | |
| 2259 | // probably need to edit that logic too. | |
| 2260 | ||
| 2261 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 2262 | text_block.dbg_info_len = len; | |
| 2263 | if (self.dbg_info_decl_last) |last| { | |
| 2264 | if (text_block.dbg_info_next) |next| { | |
| 2265 | // Update existing Decl - non-last item. | |
| 2266 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { | |
| 2267 | // It grew too big, so we move it to a new location. | |
| 2268 | if (text_block.dbg_info_prev) |prev| { | |
| 2269 | _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2270 | prev.dbg_info_next = text_block.dbg_info_next; | |
| 2271 | } | |
| 2272 | next.dbg_info_prev = text_block.dbg_info_prev; | |
| 2273 | text_block.dbg_info_next = null; | |
| 2274 | // Populate where it used to be with NOPs. | |
| 2275 | const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; | |
| 2276 | try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos); | |
| 2277 | // TODO Look at the free list before appending at the end. | |
| 2278 | text_block.dbg_info_prev = last; | |
| 2279 | last.dbg_info_next = text_block; | |
| 2280 | self.dbg_info_decl_last = text_block; | |
| 2281 | ||
| 2282 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | |
| 2283 | } | |
| 2284 | } else if (text_block.dbg_info_prev == null) { | |
| 2285 | // Append new Decl. | |
| 2286 | // TODO Look at the free list before appending at the end. | |
| 2287 | text_block.dbg_info_prev = last; | |
| 2288 | last.dbg_info_next = text_block; | |
| 2289 | self.dbg_info_decl_last = text_block; | |
| 2290 | ||
| 2291 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | |
| 2292 | } | |
| 2293 | } else { | |
| 2294 | // This is the first Decl of the .debug_info | |
| 2295 | self.dbg_info_decl_first = text_block; | |
| 2296 | self.dbg_info_decl_last = text_block; | |
| 2297 | ||
| 2298 | text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den; | |
| 2299 | } | |
| 2300 | } | |
| 2301 | ||
| 2302 | fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void { | |
| 2303 | const tracy = trace(@src()); | |
| 2304 | defer tracy.end(); | |
| 2305 | ||
| 2306 | // This logic is nearly identical to the logic above in `updateDecl` for | |
| 2307 | // `SrcFn` and the line number programs. If you are editing this logic, you | |
| 2308 | // probably need to edit that logic too. | |
| 2309 | ||
| 2310 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 2311 | ||
| 2312 | const last_decl = self.dbg_info_decl_last.?; | |
| 2313 | // +1 for a trailing zero to end the children of the decl tag. | |
| 2314 | const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; | |
| 2315 | if (needed_size != debug_info_sect.sh_size) { | |
| 2316 | if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) { | |
| 2317 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 2318 | const existing_size = last_decl.dbg_info_off; | |
| 2319 | log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{ | |
| 2320 | existing_size, | |
| 2321 | debug_info_sect.sh_offset, | |
| 2322 | new_offset, | |
| 2323 | }); | |
| 2324 | const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 2325 | if (amt != existing_size) return error.InputOutput; | |
| 2326 | debug_info_sect.sh_offset = new_offset; | |
| 2327 | } | |
| 2328 | debug_info_sect.sh_size = needed_size; | |
| 2329 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 2330 | self.debug_info_header_dirty = true; | |
| 2331 | } | |
| 2332 | const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev| | |
| 2333 | text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len) | |
| 2334 | else | |
| 2335 | 0; | |
| 2336 | const next_padding_size: u32 = if (text_block.dbg_info_next) |next| | |
| 2337 | next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len) | |
| 2338 | else | |
| 2339 | 0; | |
| 2340 | ||
| 2341 | // To end the children of the decl tag. | |
| 2342 | const trailing_zero = text_block.dbg_info_next == null; | |
| 2343 | ||
| 2344 | // We only have support for one compilation unit so far, so the offsets are directly | |
| 2345 | // from the .debug_info section. | |
| 2346 | const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; | |
| 2347 | try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos); | |
| 2348 | } | |
| 2349 | ||
| 2350 | pub fn updateDeclExports( | |
| 2351 | self: *Elf, | |
| 2352 | module: *Module, | |
| 2353 | decl: *const Module.Decl, | |
| 2354 | exports: []const *Module.Export, | |
| 2355 | ) !void { | |
| 2356 | const tracy = trace(@src()); | |
| 2357 | defer tracy.end(); | |
| 2358 | ||
| 2359 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); | |
| 2360 | const typed_value = decl.typed_value.most_recent.typed_value; | |
| 2361 | if (decl.link.elf.local_sym_index == 0) return; | |
| 2362 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; | |
| 2363 | ||
| 2364 | for (exports) |exp| { | |
| 2365 | if (exp.options.section) |section_name| { | |
| 2366 | if (!mem.eql(u8, section_name, ".text")) { | |
| 2367 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | |
| 2368 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2369 | exp, | |
| 2370 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), | |
| 2371 | ); | |
| 2372 | continue; | |
| 2373 | } | |
| 2374 | } | |
| 2375 | const stb_bits: u8 = switch (exp.options.linkage) { | |
| 2376 | .Internal => elf.STB_LOCAL, | |
| 2377 | .Strong => blk: { | |
| 2378 | if (mem.eql(u8, exp.options.name, "_start")) { | |
| 2379 | self.entry_addr = decl_sym.st_value; | |
| 2380 | } | |
| 2381 | break :blk elf.STB_GLOBAL; | |
| 2382 | }, | |
| 2383 | .Weak => elf.STB_WEAK, | |
| 2384 | .LinkOnce => { | |
| 2385 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | |
| 2386 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2387 | exp, | |
| 2388 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), | |
| 2389 | ); | |
| 2390 | continue; | |
| 2391 | }, | |
| 2392 | }; | |
| 2393 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); | |
| 2394 | if (exp.link.sym_index) |i| { | |
| 2395 | const sym = &self.global_symbols.items[i]; | |
| 2396 | sym.* = .{ | |
| 2397 | .st_name = try self.updateString(sym.st_name, exp.options.name), | |
| 2398 | .st_info = (stb_bits << 4) | stt_bits, | |
| 2399 | .st_other = 0, | |
| 2400 | .st_shndx = self.text_section_index.?, | |
| 2401 | .st_value = decl_sym.st_value, | |
| 2402 | .st_size = decl_sym.st_size, | |
| 2403 | }; | |
| 2404 | } else { | |
| 2405 | const name = try self.makeString(exp.options.name); | |
| 2406 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { | |
| 2407 | _ = self.global_symbols.addOneAssumeCapacity(); | |
| 2408 | break :blk self.global_symbols.items.len - 1; | |
| 2409 | }; | |
| 2410 | self.global_symbols.items[i] = .{ | |
| 2411 | .st_name = name, | |
| 2412 | .st_info = (stb_bits << 4) | stt_bits, | |
| 2413 | .st_other = 0, | |
| 2414 | .st_shndx = self.text_section_index.?, | |
| 2415 | .st_value = decl_sym.st_value, | |
| 2416 | .st_size = decl_sym.st_size, | |
| 2417 | }; | |
| 2418 | ||
| 2419 | exp.link.sym_index = @intCast(u32, i); | |
| 2420 | } | |
| 2421 | } | |
| 2422 | } | |
| 2423 | ||
| 2424 | /// Must be called only after a successful call to `updateDecl`. | |
| 2425 | pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void { | |
| 2426 | const tracy = trace(@src()); | |
| 2427 | defer tracy.end(); | |
| 2428 | ||
| 2429 | const scope_file = decl.scope.cast(Module.Scope.File).?; | |
| 2430 | const tree = scope_file.contents.tree; | |
| 2431 | const file_ast_decls = tree.root_node.decls(); | |
| 2432 | // TODO Look into improving the performance here by adding a token-index-to-line | |
| 2433 | // lookup table. Currently this involves scanning over the source code for newlines. | |
| 2434 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | |
| 2435 | const block = fn_proto.body().?.castTag(.Block).?; | |
| 2436 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); | |
| 2437 | const casted_line_off = @intCast(u28, line_delta); | |
| 2438 | ||
| 2439 | const shdr = &self.sections.items[self.debug_line_section_index.?]; | |
| 2440 | const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); | |
| 2441 | var data: [4]u8 = undefined; | |
| 2442 | leb128.writeUnsignedFixed(4, &data, casted_line_off); | |
| 2443 | try self.base.file.?.pwriteAll(&data, file_pos); | |
| 2444 | } | |
| 2445 | ||
| 2446 | pub fn deleteExport(self: *Elf, exp: Export) void { | |
| 2447 | const sym_index = exp.sym_index orelse return; | |
| 2448 | self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; | |
| 2449 | self.global_symbols.items[sym_index].st_info = 0; | |
| 2450 | } | |
| 2451 | ||
| 2452 | fn writeProgHeader(self: *Elf, index: usize) !void { | |
| 2453 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2454 | const offset = self.program_headers.items[index].p_offset; | |
| 2455 | switch (self.base.options.target.cpu.arch.ptrBitWidth()) { | |
| 2456 | 32 => { | |
| 2457 | var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])}; | |
| 2458 | if (foreign_endian) { | |
| 2459 | bswapAllFields(elf.Elf32_Phdr, &phdr[0]); | |
| 2460 | } | |
| 2461 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); | |
| 2462 | }, | |
| 2463 | 64 => { | |
| 2464 | var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]}; | |
| 2465 | if (foreign_endian) { | |
| 2466 | bswapAllFields(elf.Elf64_Phdr, &phdr[0]); | |
| 2467 | } | |
| 2468 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); | |
| 2469 | }, | |
| 2470 | else => return error.UnsupportedArchitecture, | |
| 2471 | } | |
| 2472 | } | |
| 2473 | ||
| 2474 | fn writeSectHeader(self: *Elf, index: usize) !void { | |
| 2475 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2476 | switch (self.base.options.target.cpu.arch.ptrBitWidth()) { | |
| 2477 | 32 => { | |
| 2478 | var shdr: [1]elf.Elf32_Shdr = undefined; | |
| 2479 | shdr[0] = sectHeaderTo32(self.sections.items[index]); | |
| 2480 | if (foreign_endian) { | |
| 2481 | bswapAllFields(elf.Elf32_Shdr, &shdr[0]); | |
| 2482 | } | |
| 2483 | const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr); | |
| 2484 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); | |
| 2485 | }, | |
| 2486 | 64 => { | |
| 2487 | var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; | |
| 2488 | if (foreign_endian) { | |
| 2489 | bswapAllFields(elf.Elf64_Shdr, &shdr[0]); | |
| 2490 | } | |
| 2491 | const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr); | |
| 2492 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); | |
| 2493 | }, | |
| 2494 | else => return error.UnsupportedArchitecture, | |
| 2495 | } | |
| 2496 | } | |
| 2497 | ||
| 2498 | fn writeOffsetTableEntry(self: *Elf, index: usize) !void { | |
| 2499 | const shdr = &self.sections.items[self.got_section_index.?]; | |
| 2500 | const phdr = &self.program_headers.items[self.phdr_got_index.?]; | |
| 2501 | const entry_size: u16 = self.ptrWidthBytes(); | |
| 2502 | if (self.offset_table_count_dirty) { | |
| 2503 | // TODO Also detect virtual address collisions. | |
| 2504 | const allocated_size = self.allocatedSize(shdr.sh_offset); | |
| 2505 | const needed_size = self.local_symbols.items.len * entry_size; | |
| 2506 | if (needed_size > allocated_size) { | |
| 2507 | // Must move the entire got section. | |
| 2508 | const new_offset = self.findFreeSpace(needed_size, entry_size); | |
| 2509 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size); | |
| 2510 | if (amt != shdr.sh_size) return error.InputOutput; | |
| 2511 | shdr.sh_offset = new_offset; | |
| 2512 | phdr.p_offset = new_offset; | |
| 2513 | } | |
| 2514 | shdr.sh_size = needed_size; | |
| 2515 | phdr.p_memsz = needed_size; | |
| 2516 | phdr.p_filesz = needed_size; | |
| 2517 | ||
| 2518 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 2519 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | |
| 2520 | ||
| 2521 | self.offset_table_count_dirty = false; | |
| 2522 | } | |
| 2523 | const endian = self.base.options.target.cpu.arch.endian(); | |
| 2524 | const off = shdr.sh_offset + @as(u64, entry_size) * index; | |
| 2525 | switch (self.ptr_width) { | |
| 2526 | .p32 => { | |
| 2527 | var buf: [4]u8 = undefined; | |
| 2528 | mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian); | |
| 2529 | try self.base.file.?.pwriteAll(&buf, off); | |
| 2530 | }, | |
| 2531 | .p64 => { | |
| 2532 | var buf: [8]u8 = undefined; | |
| 2533 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); | |
| 2534 | try self.base.file.?.pwriteAll(&buf, off); | |
| 2535 | }, | |
| 2536 | } | |
| 2537 | } | |
| 2538 | ||
| 2539 | fn writeSymbol(self: *Elf, index: usize) !void { | |
| 2540 | const tracy = trace(@src()); | |
| 2541 | defer tracy.end(); | |
| 2542 | ||
| 2543 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | |
| 2544 | // Make sure we are not pointlessly writing symbol data that will have to get relocated | |
| 2545 | // due to running out of space. | |
| 2546 | if (self.local_symbols.items.len != syms_sect.sh_info) { | |
| 2547 | const sym_size: u64 = switch (self.ptr_width) { | |
| 2548 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 2549 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 2550 | }; | |
| 2551 | const sym_align: u16 = switch (self.ptr_width) { | |
| 2552 | .p32 => @alignOf(elf.Elf32_Sym), | |
| 2553 | .p64 => @alignOf(elf.Elf64_Sym), | |
| 2554 | }; | |
| 2555 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; | |
| 2556 | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { | |
| 2557 | // Move all the symbols to a new file location. | |
| 2558 | const new_offset = self.findFreeSpace(needed_size, sym_align); | |
| 2559 | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; | |
| 2560 | const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 2561 | if (amt != existing_size) return error.InputOutput; | |
| 2562 | syms_sect.sh_offset = new_offset; | |
| 2563 | } | |
| 2564 | syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); | |
| 2565 | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later | |
| 2566 | self.shdr_table_dirty = true; // TODO look into only writing one section | |
| 2567 | } | |
| 2568 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2569 | switch (self.ptr_width) { | |
| 2570 | .p32 => { | |
| 2571 | var sym = [1]elf.Elf32_Sym{ | |
| 2572 | .{ | |
| 2573 | .st_name = self.local_symbols.items[index].st_name, | |
| 2574 | .st_value = @intCast(u32, self.local_symbols.items[index].st_value), | |
| 2575 | .st_size = @intCast(u32, self.local_symbols.items[index].st_size), | |
| 2576 | .st_info = self.local_symbols.items[index].st_info, | |
| 2577 | .st_other = self.local_symbols.items[index].st_other, | |
| 2578 | .st_shndx = self.local_symbols.items[index].st_shndx, | |
| 2579 | }, | |
| 2580 | }; | |
| 2581 | if (foreign_endian) { | |
| 2582 | bswapAllFields(elf.Elf32_Sym, &sym[0]); | |
| 2583 | } | |
| 2584 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; | |
| 2585 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | |
| 2586 | }, | |
| 2587 | .p64 => { | |
| 2588 | var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; | |
| 2589 | if (foreign_endian) { | |
| 2590 | bswapAllFields(elf.Elf64_Sym, &sym[0]); | |
| 2591 | } | |
| 2592 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; | |
| 2593 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | |
| 2594 | }, | |
| 2595 | } | |
| 2596 | } | |
| 2597 | ||
| 2598 | fn writeAllGlobalSymbols(self: *Elf) !void { | |
| 2599 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | |
| 2600 | const sym_size: u64 = switch (self.ptr_width) { | |
| 2601 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 2602 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 2603 | }; | |
| 2604 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2605 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; | |
| 2606 | switch (self.ptr_width) { | |
| 2607 | .p32 => { | |
| 2608 | const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); | |
| 2609 | defer self.base.allocator.free(buf); | |
| 2610 | ||
| 2611 | for (buf) |*sym, i| { | |
| 2612 | sym.* = .{ | |
| 2613 | .st_name = self.global_symbols.items[i].st_name, | |
| 2614 | .st_value = @intCast(u32, self.global_symbols.items[i].st_value), | |
| 2615 | .st_size = @intCast(u32, self.global_symbols.items[i].st_size), | |
| 2616 | .st_info = self.global_symbols.items[i].st_info, | |
| 2617 | .st_other = self.global_symbols.items[i].st_other, | |
| 2618 | .st_shndx = self.global_symbols.items[i].st_shndx, | |
| 2619 | }; | |
| 2620 | if (foreign_endian) { | |
| 2621 | bswapAllFields(elf.Elf32_Sym, sym); | |
| 2622 | } | |
| 2623 | } | |
| 2624 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); | |
| 2625 | }, | |
| 2626 | .p64 => { | |
| 2627 | const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len); | |
| 2628 | defer self.base.allocator.free(buf); | |
| 2629 | ||
| 2630 | for (buf) |*sym, i| { | |
| 2631 | sym.* = .{ | |
| 2632 | .st_name = self.global_symbols.items[i].st_name, | |
| 2633 | .st_value = self.global_symbols.items[i].st_value, | |
| 2634 | .st_size = self.global_symbols.items[i].st_size, | |
| 2635 | .st_info = self.global_symbols.items[i].st_info, | |
| 2636 | .st_other = self.global_symbols.items[i].st_other, | |
| 2637 | .st_shndx = self.global_symbols.items[i].st_shndx, | |
| 2638 | }; | |
| 2639 | if (foreign_endian) { | |
| 2640 | bswapAllFields(elf.Elf64_Sym, sym); | |
| 2641 | } | |
| 2642 | } | |
| 2643 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); | |
| 2644 | }, | |
| 2645 | } | |
| 2646 | } | |
| 2647 | ||
| 2648 | fn ptrWidthBytes(self: Elf) u8 { | |
| 2649 | return switch (self.ptr_width) { | |
| 2650 | .p32 => 4, | |
| 2651 | .p64 => 8, | |
| 2652 | }; | |
| 2653 | } | |
| 2654 | ||
| 2655 | /// The reloc offset for the virtual address of a function in its Line Number Program. | |
| 2656 | /// Size is a virtual address integer. | |
| 2657 | const dbg_line_vaddr_reloc_index = 3; | |
| 2658 | /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. | |
| 2659 | /// Size is a virtual address integer. | |
| 2660 | const dbg_info_low_pc_reloc_index = 1; | |
| 2661 | ||
| 2662 | /// The reloc offset for the line offset of a function from the previous function's line. | |
| 2663 | /// It's a fixed-size 4-byte ULEB128. | |
| 2664 | fn getRelocDbgLineOff(self: Elf) usize { | |
| 2665 | return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; | |
| 2666 | } | |
| 2667 | ||
| 2668 | fn getRelocDbgFileIndex(self: Elf) usize { | |
| 2669 | return self.getRelocDbgLineOff() + 5; | |
| 2670 | } | |
| 2671 | ||
| 2672 | fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 { | |
| 2673 | return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); | |
| 2674 | } | |
| 2675 | ||
| 2676 | fn dbgLineNeededHeaderBytes(self: Elf) u32 { | |
| 2677 | const directory_entry_format_count = 1; | |
| 2678 | const file_name_entry_format_count = 1; | |
| 2679 | const directory_count = 1; | |
| 2680 | const file_name_count = 1; | |
| 2681 | return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + | |
| 2682 | directory_count * 8 + file_name_count * 8 + | |
| 2683 | // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like | |
| 2684 | // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. | |
| 2685 | self.base.options.root_pkg.root_src_dir_path.len + | |
| 2686 | self.base.options.root_pkg.root_src_path.len); | |
| 2687 | ||
| 2688 | } | |
| 2689 | ||
| 2690 | fn dbgInfoNeededHeaderBytes(self: Elf) u32 { | |
| 2691 | return 120; | |
| 2692 | } | |
| 2693 | ||
| 2694 | const min_nop_size = 2; | |
| 2695 | ||
| 2696 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | |
| 2697 | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes | |
| 2698 | /// are less than 126,976 bytes (if this limit is ever reached, this function can be | |
| 2699 | /// improved to make more than one pwritev call, or the limit can be raised by a fixed | |
| 2700 | /// amount by increasing the length of `vecs`). | |
| 2701 | fn pwriteDbgLineNops( | |
| 2702 | self: *Elf, | |
| 2703 | prev_padding_size: usize, | |
| 2704 | buf: []const u8, | |
| 2705 | next_padding_size: usize, | |
| 2706 | offset: usize, | |
| 2707 | ) !void { | |
| 2708 | const tracy = trace(@src()); | |
| 2709 | defer tracy.end(); | |
| 2710 | ||
| 2711 | const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; | |
| 2712 | const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0}; | |
| 2713 | var vecs: [32]std.os.iovec_const = undefined; | |
| 2714 | var vec_index: usize = 0; | |
| 2715 | { | |
| 2716 | var padding_left = prev_padding_size; | |
| 2717 | if (padding_left % 2 != 0) { | |
| 2718 | vecs[vec_index] = .{ | |
| 2719 | .iov_base = &three_byte_nop, | |
| 2720 | .iov_len = three_byte_nop.len, | |
| 2721 | }; | |
| 2722 | vec_index += 1; | |
| 2723 | padding_left -= three_byte_nop.len; | |
| 2724 | } | |
| 2725 | while (padding_left > page_of_nops.len) { | |
| 2726 | vecs[vec_index] = .{ | |
| 2727 | .iov_base = &page_of_nops, | |
| 2728 | .iov_len = page_of_nops.len, | |
| 2729 | }; | |
| 2730 | vec_index += 1; | |
| 2731 | padding_left -= page_of_nops.len; | |
| 2732 | } | |
| 2733 | if (padding_left > 0) { | |
| 2734 | vecs[vec_index] = .{ | |
| 2735 | .iov_base = &page_of_nops, | |
| 2736 | .iov_len = padding_left, | |
| 2737 | }; | |
| 2738 | vec_index += 1; | |
| 2739 | } | |
| 2740 | } | |
| 2741 | ||
| 2742 | vecs[vec_index] = .{ | |
| 2743 | .iov_base = buf.ptr, | |
| 2744 | .iov_len = buf.len, | |
| 2745 | }; | |
| 2746 | vec_index += 1; | |
| 2747 | ||
| 2748 | { | |
| 2749 | var padding_left = next_padding_size; | |
| 2750 | if (padding_left % 2 != 0) { | |
| 2751 | vecs[vec_index] = .{ | |
| 2752 | .iov_base = &three_byte_nop, | |
| 2753 | .iov_len = three_byte_nop.len, | |
| 2754 | }; | |
| 2755 | vec_index += 1; | |
| 2756 | padding_left -= three_byte_nop.len; | |
| 2757 | } | |
| 2758 | while (padding_left > page_of_nops.len) { | |
| 2759 | vecs[vec_index] = .{ | |
| 2760 | .iov_base = &page_of_nops, | |
| 2761 | .iov_len = page_of_nops.len, | |
| 2762 | }; | |
| 2763 | vec_index += 1; | |
| 2764 | padding_left -= page_of_nops.len; | |
| 2765 | } | |
| 2766 | if (padding_left > 0) { | |
| 2767 | vecs[vec_index] = .{ | |
| 2768 | .iov_base = &page_of_nops, | |
| 2769 | .iov_len = padding_left, | |
| 2770 | }; | |
| 2771 | vec_index += 1; | |
| 2772 | } | |
| 2773 | } | |
| 2774 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | |
| 2775 | } | |
| 2776 | ||
| 2777 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | |
| 2778 | /// bytes of padding. | |
| 2779 | fn pwriteDbgInfoNops( | |
| 2780 | self: *Elf, | |
| 2781 | prev_padding_size: usize, | |
| 2782 | buf: []const u8, | |
| 2783 | next_padding_size: usize, | |
| 2784 | trailing_zero: bool, | |
| 2785 | offset: usize, | |
| 2786 | ) !void { | |
| 2787 | const tracy = trace(@src()); | |
| 2788 | defer tracy.end(); | |
| 2789 | ||
| 2790 | const page_of_nops = [1]u8{abbrev_pad1} ** 4096; | |
| 2791 | var vecs: [32]std.os.iovec_const = undefined; | |
| 2792 | var vec_index: usize = 0; | |
| 2793 | { | |
| 2794 | var padding_left = prev_padding_size; | |
| 2795 | while (padding_left > page_of_nops.len) { | |
| 2796 | vecs[vec_index] = .{ | |
| 2797 | .iov_base = &page_of_nops, | |
| 2798 | .iov_len = page_of_nops.len, | |
| 2799 | }; | |
| 2800 | vec_index += 1; | |
| 2801 | padding_left -= page_of_nops.len; | |
| 2802 | } | |
| 2803 | if (padding_left > 0) { | |
| 2804 | vecs[vec_index] = .{ | |
| 2805 | .iov_base = &page_of_nops, | |
| 2806 | .iov_len = padding_left, | |
| 2807 | }; | |
| 2808 | vec_index += 1; | |
| 2809 | } | |
| 2810 | } | |
| 2811 | ||
| 2812 | vecs[vec_index] = .{ | |
| 2813 | .iov_base = buf.ptr, | |
| 2814 | .iov_len = buf.len, | |
| 2815 | }; | |
| 2816 | vec_index += 1; | |
| 2817 | ||
| 2818 | { | |
| 2819 | var padding_left = next_padding_size; | |
| 2820 | while (padding_left > page_of_nops.len) { | |
| 2821 | vecs[vec_index] = .{ | |
| 2822 | .iov_base = &page_of_nops, | |
| 2823 | .iov_len = page_of_nops.len, | |
| 2824 | }; | |
| 2825 | vec_index += 1; | |
| 2826 | padding_left -= page_of_nops.len; | |
| 2827 | } | |
| 2828 | if (padding_left > 0) { | |
| 2829 | vecs[vec_index] = .{ | |
| 2830 | .iov_base = &page_of_nops, | |
| 2831 | .iov_len = padding_left, | |
| 2832 | }; | |
| 2833 | vec_index += 1; | |
| 2834 | } | |
| 2835 | } | |
| 2836 | ||
| 2837 | if (trailing_zero) { | |
| 2838 | var zbuf = [1]u8{0}; | |
| 2839 | vecs[vec_index] = .{ | |
| 2840 | .iov_base = &zbuf, | |
| 2841 | .iov_len = zbuf.len, | |
| 2842 | }; | |
| 2843 | vec_index += 1; | |
| 2844 | } | |
| 2845 | ||
| 2846 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | |
| 2847 | } | |
| 2848 | ||
| 2849 | }; | |
| 2850 | ||
| 237 | pub const C = @import("link/C.zig"); | |
| 238 | pub const Elf = @import("link/Elf.zig"); | |
| 2851 | 239 | pub const MachO = @import("link/MachO.zig"); |
| 2852 | const Wasm = @import("link/Wasm.zig"); | |
| 240 | pub const Wasm = @import("link/Wasm.zig"); | |
| 2853 | 241 | }; |
| 2854 | 242 | |
| 2855 | /// Saturating multiplication | |
| 2856 | fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | |
| 2857 | const T = @TypeOf(a, b); | |
| 2858 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | |
| 2859 | } | |
| 2860 | ||
| 2861 | fn bswapAllFields(comptime S: type, ptr: *S) void { | |
| 2862 | @panic("TODO implement bswapAllFields"); | |
| 2863 | } | |
| 2864 | ||
| 2865 | fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { | |
| 2866 | return .{ | |
| 2867 | .p_type = phdr.p_type, | |
| 2868 | .p_flags = phdr.p_flags, | |
| 2869 | .p_offset = @intCast(u32, phdr.p_offset), | |
| 2870 | .p_vaddr = @intCast(u32, phdr.p_vaddr), | |
| 2871 | .p_paddr = @intCast(u32, phdr.p_paddr), | |
| 2872 | .p_filesz = @intCast(u32, phdr.p_filesz), | |
| 2873 | .p_memsz = @intCast(u32, phdr.p_memsz), | |
| 2874 | .p_align = @intCast(u32, phdr.p_align), | |
| 2875 | }; | |
| 2876 | } | |
| 2877 | ||
| 2878 | fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { | |
| 2879 | return .{ | |
| 2880 | .sh_name = shdr.sh_name, | |
| 2881 | .sh_type = shdr.sh_type, | |
| 2882 | .sh_flags = @intCast(u32, shdr.sh_flags), | |
| 2883 | .sh_addr = @intCast(u32, shdr.sh_addr), | |
| 2884 | .sh_offset = @intCast(u32, shdr.sh_offset), | |
| 2885 | .sh_size = @intCast(u32, shdr.sh_size), | |
| 2886 | .sh_link = shdr.sh_link, | |
| 2887 | .sh_info = shdr.sh_info, | |
| 2888 | .sh_addralign = @intCast(u32, shdr.sh_addralign), | |
| 2889 | .sh_entsize = @intCast(u32, shdr.sh_entsize), | |
| 2890 | }; | |
| 2891 | } | |
| 2892 | ||
| 2893 | 243 | pub fn determineMode(options: Options) fs.File.Mode { |
| 2894 | 244 | // On common systems with a 0o022 umask, 0o777 will still result in a file created |
| 2895 | 245 | // with 0o755 permissions, but it works appropriately if the system is configured |
src-self-hosted/link/C.zig created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | const std = @import("std"); | |
| 2 | const mem = std.mem; | |
| 3 | const assert = std.debug.assert; | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const Module = @import("../Module.zig"); | |
| 6 | const fs = std.fs; | |
| 7 | const codegen = @import("../codegen/c.zig"); | |
| 8 | const link = @import("../link.zig"); | |
| 9 | const File = link.File; | |
| 10 | const C = @This(); | |
| 11 | ||
| 12 | pub const base_tag: File.Tag = .c; | |
| 13 | ||
| 14 | base: File, | |
| 15 | ||
| 16 | header: std.ArrayList(u8), | |
| 17 | constants: std.ArrayList(u8), | |
| 18 | main: std.ArrayList(u8), | |
| 19 | ||
| 20 | called: std.StringHashMap(void), | |
| 21 | need_stddef: bool = false, | |
| 22 | need_stdint: bool = false, | |
| 23 | error_msg: *Module.ErrorMsg = undefined, | |
| 24 | ||
| 25 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File { | |
| 26 | assert(options.object_format == .c); | |
| 27 | ||
| 28 | const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); | |
| 29 | errdefer file.close(); | |
| 30 | ||
| 31 | var c_file = try allocator.create(C); | |
| 32 | errdefer allocator.destroy(c_file); | |
| 33 | ||
| 34 | c_file.* = C{ | |
| 35 | .base = .{ | |
| 36 | .tag = .c, | |
| 37 | .options = options, | |
| 38 | .file = file, | |
| 39 | .allocator = allocator, | |
| 40 | }, | |
| 41 | .main = std.ArrayList(u8).init(allocator), | |
| 42 | .header = std.ArrayList(u8).init(allocator), | |
| 43 | .constants = std.ArrayList(u8).init(allocator), | |
| 44 | .called = std.StringHashMap(void).init(allocator), | |
| 45 | }; | |
| 46 | ||
| 47 | return &c_file.base; | |
| 48 | } | |
| 49 | ||
| 50 | pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { | |
| 51 | self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args); | |
| 52 | return error.AnalysisFail; | |
| 53 | } | |
| 54 | ||
| 55 | pub fn deinit(self: *C) void { | |
| 56 | self.main.deinit(); | |
| 57 | self.header.deinit(); | |
| 58 | self.constants.deinit(); | |
| 59 | self.called.deinit(); | |
| 60 | } | |
| 61 | ||
| 62 | pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | |
| 63 | codegen.generate(self, decl) catch |err| { | |
| 64 | if (err == error.AnalysisFail) { | |
| 65 | try module.failed_decls.put(module.gpa, decl, self.error_msg); | |
| 66 | } | |
| 67 | return err; | |
| 68 | }; | |
| 69 | } | |
| 70 | ||
| 71 | pub fn flush(self: *C, module: *Module) !void { | |
| 72 | const writer = self.base.file.?.writer(); | |
| 73 | try writer.writeAll(@embedFile("cbe.h")); | |
| 74 | var includes = false; | |
| 75 | if (self.need_stddef) { | |
| 76 | try writer.writeAll("#include <stddef.h>\n"); | |
| 77 | includes = true; | |
| 78 | } | |
| 79 | if (self.need_stdint) { | |
| 80 | try writer.writeAll("#include <stdint.h>\n"); | |
| 81 | includes = true; | |
| 82 | } | |
| 83 | if (includes) { | |
| 84 | try writer.writeByte('\n'); | |
| 85 | } | |
| 86 | if (self.header.items.len > 0) { | |
| 87 | try writer.print("{}\n", .{self.header.items}); | |
| 88 | } | |
| 89 | if (self.constants.items.len > 0) { | |
| 90 | try writer.print("{}\n", .{self.constants.items}); | |
| 91 | } | |
| 92 | if (self.main.items.len > 1) { | |
| 93 | const last_two = self.main.items[self.main.items.len - 2 ..]; | |
| 94 | if (std.mem.eql(u8, last_two, "\n\n")) { | |
| 95 | self.main.items.len -= 1; | |
| 96 | } | |
| 97 | } | |
| 98 | try writer.writeAll(self.main.items); | |
| 99 | self.base.file.?.close(); | |
| 100 | self.base.file = null; | |
| 101 | } |
src-self-hosted/link/Elf.zig created+2583| ... | ... | @@ -0,0 +1,2583 @@ |
| 1 | const std = @import("std"); | |
| 2 | const mem = std.mem; | |
| 3 | const assert = std.debug.assert; | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const ir = @import("../ir.zig"); | |
| 6 | const Module = @import("../Module.zig"); | |
| 7 | const fs = std.fs; | |
| 8 | const elf = std.elf; | |
| 9 | const codegen = @import("../codegen.zig"); | |
| 10 | const log = std.log.scoped(.link); | |
| 11 | const DW = std.dwarf; | |
| 12 | const trace = @import("../tracy.zig").trace; | |
| 13 | const leb128 = std.debug.leb; | |
| 14 | const Package = @import("../Package.zig"); | |
| 15 | const Value = @import("../value.zig").Value; | |
| 16 | const Type = @import("../type.zig").Type; | |
| 17 | const build_options = @import("build_options"); | |
| 18 | const link = @import("../link.zig"); | |
| 19 | const File = link.File; | |
| 20 | const Elf = @This(); | |
| 21 | ||
| 22 | const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | |
| 23 | const default_entry_addr = 0x8000000; | |
| 24 | ||
| 25 | // TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented. | |
| 26 | // zig fmt: off | |
| 27 | ||
| 28 | pub const base_tag: File.Tag = .elf; | |
| 29 | ||
| 30 | base: File, | |
| 31 | ||
| 32 | ptr_width: enum { p32, p64 }, | |
| 33 | ||
| 34 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 35 | /// Same order as in the file. | |
| 36 | sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){}, | |
| 37 | shdr_table_offset: ?u64 = null, | |
| 38 | ||
| 39 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 40 | /// Same order as in the file. | |
| 41 | program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){}, | |
| 42 | phdr_table_offset: ?u64 = null, | |
| 43 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags | |
| 44 | phdr_load_re_index: ?u16 = null, | |
| 45 | /// The index into the program headers of the global offset table. | |
| 46 | /// It needs PT_LOAD and Read flags. | |
| 47 | phdr_got_index: ?u16 = null, | |
| 48 | entry_addr: ?u64 = null, | |
| 49 | ||
| 50 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | |
| 51 | shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | |
| 52 | shstrtab_index: ?u16 = null, | |
| 53 | ||
| 54 | text_section_index: ?u16 = null, | |
| 55 | symtab_section_index: ?u16 = null, | |
| 56 | got_section_index: ?u16 = null, | |
| 57 | debug_info_section_index: ?u16 = null, | |
| 58 | debug_abbrev_section_index: ?u16 = null, | |
| 59 | debug_str_section_index: ?u16 = null, | |
| 60 | debug_aranges_section_index: ?u16 = null, | |
| 61 | debug_line_section_index: ?u16 = null, | |
| 62 | ||
| 63 | debug_abbrev_table_offset: ?u64 = null, | |
| 64 | ||
| 65 | /// The same order as in the file. ELF requires global symbols to all be after the | |
| 66 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and | |
| 67 | /// write them at the end. These are only the local symbols. The length of this array | |
| 68 | /// is the value used for sh_info in the .symtab section. | |
| 69 | local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | |
| 70 | global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | |
| 71 | ||
| 72 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 73 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 74 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 75 | ||
| 76 | /// Same order as in the file. The value is the absolute vaddr value. | |
| 77 | /// If the vaddr of the executable program header changes, the entire | |
| 78 | /// offset table needs to be rewritten. | |
| 79 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | |
| 80 | ||
| 81 | phdr_table_dirty: bool = false, | |
| 82 | shdr_table_dirty: bool = false, | |
| 83 | shstrtab_dirty: bool = false, | |
| 84 | debug_strtab_dirty: bool = false, | |
| 85 | offset_table_count_dirty: bool = false, | |
| 86 | debug_abbrev_section_dirty: bool = false, | |
| 87 | debug_aranges_section_dirty: bool = false, | |
| 88 | ||
| 89 | debug_info_header_dirty: bool = false, | |
| 90 | debug_line_header_dirty: bool = false, | |
| 91 | ||
| 92 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | |
| 93 | ||
| 94 | /// A list of text blocks that have surplus capacity. This list can have false | |
| 95 | /// positives, as functions grow and shrink over time, only sometimes being added | |
| 96 | /// or removed from the freelist. | |
| 97 | /// | |
| 98 | /// A text block has surplus capacity when its overcapacity value is greater than | |
| 99 | /// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so | |
| 100 | /// much extra capacity, that we could fit a small new symbol in it, itself with | |
| 101 | /// ideal_capacity or more. | |
| 102 | /// | |
| 103 | /// Ideal capacity is defined by size * alloc_num / alloc_den. | |
| 104 | /// | |
| 105 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that | |
| 106 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | |
| 107 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | |
| 108 | /// by 1 byte. It will then have -1 overcapacity. | |
| 109 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | |
| 110 | last_text_block: ?*TextBlock = null, | |
| 111 | ||
| 112 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. | |
| 113 | /// This is the same concept as `text_block_free_list`; see those doc comments. | |
| 114 | dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, | |
| 115 | dbg_line_fn_first: ?*SrcFn = null, | |
| 116 | dbg_line_fn_last: ?*SrcFn = null, | |
| 117 | ||
| 118 | /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. | |
| 119 | /// This is the same concept as `text_block_free_list`; see those doc comments. | |
| 120 | dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, | |
| 121 | dbg_info_decl_first: ?*TextBlock = null, | |
| 122 | dbg_info_decl_last: ?*TextBlock = null, | |
| 123 | ||
| 124 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | |
| 125 | const alloc_num = 4; | |
| 126 | const alloc_den = 3; | |
| 127 | ||
| 128 | /// In order for a slice of bytes to be considered eligible to keep metadata pointing at | |
| 129 | /// it as a possible place to put new symbols, it must have enough room for this many bytes | |
| 130 | /// (plus extra for reserved capacity). | |
| 131 | const minimum_text_block_size = 64; | |
| 132 | const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; | |
| 133 | ||
| 134 | pub const TextBlock = struct { | |
| 135 | /// Each decl always gets a local symbol with the fully qualified name. | |
| 136 | /// The vaddr and size are found here directly. | |
| 137 | /// The file offset is found by computing the vaddr offset from the section vaddr | |
| 138 | /// the symbol references, and adding that to the file offset of the section. | |
| 139 | /// If this field is 0, it means the codegen size = 0 and there is no symbol or | |
| 140 | /// offset table entry. | |
| 141 | local_sym_index: u32, | |
| 142 | /// This field is undefined for symbols with size = 0. | |
| 143 | offset_table_index: u32, | |
| 144 | /// Points to the previous and next neighbors, based on the `text_offset`. | |
| 145 | /// This can be used to find, for example, the capacity of this `TextBlock`. | |
| 146 | prev: ?*TextBlock, | |
| 147 | next: ?*TextBlock, | |
| 148 | ||
| 149 | /// Previous/next linked list pointers. This value is `next ^ prev`. | |
| 150 | /// This is the linked list node for this Decl's corresponding .debug_info tag. | |
| 151 | dbg_info_prev: ?*TextBlock, | |
| 152 | dbg_info_next: ?*TextBlock, | |
| 153 | /// Offset into .debug_info pointing to the tag for this Decl. | |
| 154 | dbg_info_off: u32, | |
| 155 | /// Size of the .debug_info tag for this Decl, not including padding. | |
| 156 | dbg_info_len: u32, | |
| 157 | ||
| 158 | pub const empty = TextBlock{ | |
| 159 | .local_sym_index = 0, | |
| 160 | .offset_table_index = undefined, | |
| 161 | .prev = null, | |
| 162 | .next = null, | |
| 163 | .dbg_info_prev = null, | |
| 164 | .dbg_info_next = null, | |
| 165 | .dbg_info_off = undefined, | |
| 166 | .dbg_info_len = undefined, | |
| 167 | }; | |
| 168 | ||
| 169 | /// Returns how much room there is to grow in virtual address space. | |
| 170 | /// File offset relocation happens transparently, so it is not included in | |
| 171 | /// this calculation. | |
| 172 | fn capacity(self: TextBlock, elf_file: Elf) u64 { | |
| 173 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; | |
| 174 | if (self.next) |next| { | |
| 175 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; | |
| 176 | return next_sym.st_value - self_sym.st_value; | |
| 177 | } else { | |
| 178 | // We are the last block. The capacity is limited only by virtual address space. | |
| 179 | return std.math.maxInt(u32) - self_sym.st_value; | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | fn freeListEligible(self: TextBlock, elf_file: Elf) bool { | |
| 184 | // No need to keep a free list node for the last block. | |
| 185 | const next = self.next orelse return false; | |
| 186 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; | |
| 187 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; | |
| 188 | const cap = next_sym.st_value - self_sym.st_value; | |
| 189 | const ideal_cap = self_sym.st_size * alloc_num / alloc_den; | |
| 190 | if (cap <= ideal_cap) return false; | |
| 191 | const surplus = cap - ideal_cap; | |
| 192 | return surplus >= min_text_capacity; | |
| 193 | } | |
| 194 | }; | |
| 195 | ||
| 196 | pub const Export = struct { | |
| 197 | sym_index: ?u32 = null, | |
| 198 | }; | |
| 199 | ||
| 200 | pub const SrcFn = struct { | |
| 201 | /// Offset from the beginning of the Debug Line Program header that contains this function. | |
| 202 | off: u32, | |
| 203 | /// Size of the line number program component belonging to this function, not | |
| 204 | /// including padding. | |
| 205 | len: u32, | |
| 206 | ||
| 207 | /// Points to the previous and next neighbors, based on the offset from .debug_line. | |
| 208 | /// This can be used to find, for example, the capacity of this `SrcFn`. | |
| 209 | prev: ?*SrcFn, | |
| 210 | next: ?*SrcFn, | |
| 211 | ||
| 212 | pub const empty: SrcFn = .{ | |
| 213 | .off = 0, | |
| 214 | .len = 0, | |
| 215 | .prev = null, | |
| 216 | .next = null, | |
| 217 | }; | |
| 218 | }; | |
| 219 | ||
| 220 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File { | |
| 221 | assert(options.object_format == .elf); | |
| 222 | ||
| 223 | const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) }); | |
| 224 | errdefer file.close(); | |
| 225 | ||
| 226 | var elf_file = try allocator.create(Elf); | |
| 227 | errdefer allocator.destroy(elf_file); | |
| 228 | ||
| 229 | elf_file.* = openFile(allocator, file, options) catch |err| switch (err) { | |
| 230 | error.IncrFailed => try createFile(allocator, file, options), | |
| 231 | else => |e| return e, | |
| 232 | }; | |
| 233 | ||
| 234 | return &elf_file.base; | |
| 235 | } | |
| 236 | ||
| 237 | /// Returns error.IncrFailed if incremental update could not be performed. | |
| 238 | fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf { | |
| 239 | switch (options.output_mode) { | |
| 240 | .Exe => {}, | |
| 241 | .Obj => {}, | |
| 242 | .Lib => return error.IncrFailed, | |
| 243 | } | |
| 244 | var self: Elf = .{ | |
| 245 | .base = .{ | |
| 246 | .file = file, | |
| 247 | .tag = .elf, | |
| 248 | .options = options, | |
| 249 | .allocator = allocator, | |
| 250 | }, | |
| 251 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | |
| 252 | 32 => .p32, | |
| 253 | 64 => .p64, | |
| 254 | else => return error.UnsupportedELFArchitecture, | |
| 255 | }, | |
| 256 | }; | |
| 257 | errdefer self.deinit(); | |
| 258 | ||
| 259 | // TODO implement reading the elf file | |
| 260 | return error.IncrFailed; | |
| 261 | //try self.populateMissingMetadata(); | |
| 262 | //return self; | |
| 263 | } | |
| 264 | ||
| 265 | /// Truncates the existing file contents and overwrites the contents. | |
| 266 | /// Returns an error if `file` is not already open with +read +write +seek abilities. | |
| 267 | fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf { | |
| 268 | switch (options.output_mode) { | |
| 269 | .Exe => {}, | |
| 270 | .Obj => {}, | |
| 271 | .Lib => return error.TODOImplementWritingLibFiles, | |
| 272 | } | |
| 273 | var self: Elf = .{ | |
| 274 | .base = .{ | |
| 275 | .tag = .elf, | |
| 276 | .options = options, | |
| 277 | .allocator = allocator, | |
| 278 | .file = file, | |
| 279 | }, | |
| 280 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | |
| 281 | 32 => .p32, | |
| 282 | 64 => .p64, | |
| 283 | else => return error.UnsupportedELFArchitecture, | |
| 284 | }, | |
| 285 | .shdr_table_dirty = true, | |
| 286 | }; | |
| 287 | errdefer self.deinit(); | |
| 288 | ||
| 289 | // Index 0 is always a null symbol. | |
| 290 | try self.local_symbols.append(allocator, .{ | |
| 291 | .st_name = 0, | |
| 292 | .st_info = 0, | |
| 293 | .st_other = 0, | |
| 294 | .st_shndx = 0, | |
| 295 | .st_value = 0, | |
| 296 | .st_size = 0, | |
| 297 | }); | |
| 298 | ||
| 299 | // There must always be a null section in index 0 | |
| 300 | try self.sections.append(allocator, .{ | |
| 301 | .sh_name = 0, | |
| 302 | .sh_type = elf.SHT_NULL, | |
| 303 | .sh_flags = 0, | |
| 304 | .sh_addr = 0, | |
| 305 | .sh_offset = 0, | |
| 306 | .sh_size = 0, | |
| 307 | .sh_link = 0, | |
| 308 | .sh_info = 0, | |
| 309 | .sh_addralign = 0, | |
| 310 | .sh_entsize = 0, | |
| 311 | }); | |
| 312 | ||
| 313 | try self.populateMissingMetadata(); | |
| 314 | ||
| 315 | return self; | |
| 316 | } | |
| 317 | ||
| 318 | pub fn deinit(self: *Elf) void { | |
| 319 | self.sections.deinit(self.base.allocator); | |
| 320 | self.program_headers.deinit(self.base.allocator); | |
| 321 | self.shstrtab.deinit(self.base.allocator); | |
| 322 | self.debug_strtab.deinit(self.base.allocator); | |
| 323 | self.local_symbols.deinit(self.base.allocator); | |
| 324 | self.global_symbols.deinit(self.base.allocator); | |
| 325 | self.global_symbol_free_list.deinit(self.base.allocator); | |
| 326 | self.local_symbol_free_list.deinit(self.base.allocator); | |
| 327 | self.offset_table_free_list.deinit(self.base.allocator); | |
| 328 | self.text_block_free_list.deinit(self.base.allocator); | |
| 329 | self.dbg_line_fn_free_list.deinit(self.base.allocator); | |
| 330 | self.dbg_info_decl_free_list.deinit(self.base.allocator); | |
| 331 | self.offset_table.deinit(self.base.allocator); | |
| 332 | } | |
| 333 | ||
| 334 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { | |
| 335 | assert(decl.link.elf.local_sym_index != 0); | |
| 336 | return self.local_symbols.items[decl.link.elf.local_sym_index].st_value; | |
| 337 | } | |
| 338 | ||
| 339 | fn getDebugLineProgramOff(self: Elf) u32 { | |
| 340 | return self.dbg_line_fn_first.?.off; | |
| 341 | } | |
| 342 | ||
| 343 | fn getDebugLineProgramEnd(self: Elf) u32 { | |
| 344 | return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len; | |
| 345 | } | |
| 346 | ||
| 347 | /// Returns end pos of collision, if any. | |
| 348 | fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | |
| 349 | const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32; | |
| 350 | const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); | |
| 351 | if (start < ehdr_size) | |
| 352 | return ehdr_size; | |
| 353 | ||
| 354 | const end = start + satMul(size, alloc_num) / alloc_den; | |
| 355 | ||
| 356 | if (self.shdr_table_offset) |off| { | |
| 357 | const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); | |
| 358 | const tight_size = self.sections.items.len * shdr_size; | |
| 359 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | |
| 360 | const test_end = off + increased_size; | |
| 361 | if (end > off and start < test_end) { | |
| 362 | return test_end; | |
| 363 | } | |
| 364 | } | |
| 365 | ||
| 366 | if (self.phdr_table_offset) |off| { | |
| 367 | const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); | |
| 368 | const tight_size = self.sections.items.len * phdr_size; | |
| 369 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | |
| 370 | const test_end = off + increased_size; | |
| 371 | if (end > off and start < test_end) { | |
| 372 | return test_end; | |
| 373 | } | |
| 374 | } | |
| 375 | ||
| 376 | for (self.sections.items) |section| { | |
| 377 | const increased_size = satMul(section.sh_size, alloc_num) / alloc_den; | |
| 378 | const test_end = section.sh_offset + increased_size; | |
| 379 | if (end > section.sh_offset and start < test_end) { | |
| 380 | return test_end; | |
| 381 | } | |
| 382 | } | |
| 383 | for (self.program_headers.items) |program_header| { | |
| 384 | const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den; | |
| 385 | const test_end = program_header.p_offset + increased_size; | |
| 386 | if (end > program_header.p_offset and start < test_end) { | |
| 387 | return test_end; | |
| 388 | } | |
| 389 | } | |
| 390 | return null; | |
| 391 | } | |
| 392 | ||
| 393 | fn allocatedSize(self: *Elf, start: u64) u64 { | |
| 394 | if (start == 0) | |
| 395 | return 0; | |
| 396 | var min_pos: u64 = std.math.maxInt(u64); | |
| 397 | if (self.shdr_table_offset) |off| { | |
| 398 | if (off > start and off < min_pos) min_pos = off; | |
| 399 | } | |
| 400 | if (self.phdr_table_offset) |off| { | |
| 401 | if (off > start and off < min_pos) min_pos = off; | |
| 402 | } | |
| 403 | for (self.sections.items) |section| { | |
| 404 | if (section.sh_offset <= start) continue; | |
| 405 | if (section.sh_offset < min_pos) min_pos = section.sh_offset; | |
| 406 | } | |
| 407 | for (self.program_headers.items) |program_header| { | |
| 408 | if (program_header.p_offset <= start) continue; | |
| 409 | if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; | |
| 410 | } | |
| 411 | return min_pos - start; | |
| 412 | } | |
| 413 | ||
| 414 | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 { | |
| 415 | var start: u64 = 0; | |
| 416 | while (self.detectAllocCollision(start, object_size)) |item_end| { | |
| 417 | start = mem.alignForwardGeneric(u64, item_end, min_alignment); | |
| 418 | } | |
| 419 | return start; | |
| 420 | } | |
| 421 | ||
| 422 | /// TODO Improve this to use a table. | |
| 423 | fn makeString(self: *Elf, bytes: []const u8) !u32 { | |
| 424 | try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1); | |
| 425 | const result = self.shstrtab.items.len; | |
| 426 | self.shstrtab.appendSliceAssumeCapacity(bytes); | |
| 427 | self.shstrtab.appendAssumeCapacity(0); | |
| 428 | return @intCast(u32, result); | |
| 429 | } | |
| 430 | ||
| 431 | /// TODO Improve this to use a table. | |
| 432 | fn makeDebugString(self: *Elf, bytes: []const u8) !u32 { | |
| 433 | try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1); | |
| 434 | const result = self.debug_strtab.items.len; | |
| 435 | self.debug_strtab.appendSliceAssumeCapacity(bytes); | |
| 436 | self.debug_strtab.appendAssumeCapacity(0); | |
| 437 | return @intCast(u32, result); | |
| 438 | } | |
| 439 | ||
| 440 | fn getString(self: *Elf, str_off: u32) []const u8 { | |
| 441 | assert(str_off < self.shstrtab.items.len); | |
| 442 | return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); | |
| 443 | } | |
| 444 | ||
| 445 | fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 { | |
| 446 | const existing_name = self.getString(old_str_off); | |
| 447 | if (mem.eql(u8, existing_name, new_name)) { | |
| 448 | return old_str_off; | |
| 449 | } | |
| 450 | return self.makeString(new_name); | |
| 451 | } | |
| 452 | ||
| 453 | pub fn populateMissingMetadata(self: *Elf) !void { | |
| 454 | const small_ptr = switch (self.ptr_width) { | |
| 455 | .p32 => true, | |
| 456 | .p64 => false, | |
| 457 | }; | |
| 458 | const ptr_size: u8 = self.ptrWidthBytes(); | |
| 459 | if (self.phdr_load_re_index == null) { | |
| 460 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); | |
| 461 | const file_size = self.base.options.program_code_size_hint; | |
| 462 | const p_align = 0x1000; | |
| 463 | const off = self.findFreeSpace(file_size, p_align); | |
| 464 | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 465 | try self.program_headers.append(self.base.allocator, .{ | |
| 466 | .p_type = elf.PT_LOAD, | |
| 467 | .p_offset = off, | |
| 468 | .p_filesz = file_size, | |
| 469 | .p_vaddr = default_entry_addr, | |
| 470 | .p_paddr = default_entry_addr, | |
| 471 | .p_memsz = file_size, | |
| 472 | .p_align = p_align, | |
| 473 | .p_flags = elf.PF_X | elf.PF_R, | |
| 474 | }); | |
| 475 | self.entry_addr = null; | |
| 476 | self.phdr_table_dirty = true; | |
| 477 | } | |
| 478 | if (self.phdr_got_index == null) { | |
| 479 | self.phdr_got_index = @intCast(u16, self.program_headers.items.len); | |
| 480 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; | |
| 481 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | |
| 482 | // page align. | |
| 483 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); | |
| 484 | const off = self.findFreeSpace(file_size, p_align); | |
| 485 | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 486 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. | |
| 487 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something | |
| 488 | // else in virtual memory. | |
| 489 | const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000; | |
| 490 | try self.program_headers.append(self.base.allocator, .{ | |
| 491 | .p_type = elf.PT_LOAD, | |
| 492 | .p_offset = off, | |
| 493 | .p_filesz = file_size, | |
| 494 | .p_vaddr = default_got_addr, | |
| 495 | .p_paddr = default_got_addr, | |
| 496 | .p_memsz = file_size, | |
| 497 | .p_align = p_align, | |
| 498 | .p_flags = elf.PF_R, | |
| 499 | }); | |
| 500 | self.phdr_table_dirty = true; | |
| 501 | } | |
| 502 | if (self.shstrtab_index == null) { | |
| 503 | self.shstrtab_index = @intCast(u16, self.sections.items.len); | |
| 504 | assert(self.shstrtab.items.len == 0); | |
| 505 | try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0 | |
| 506 | const off = self.findFreeSpace(self.shstrtab.items.len, 1); | |
| 507 | log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); | |
| 508 | try self.sections.append(self.base.allocator, .{ | |
| 509 | .sh_name = try self.makeString(".shstrtab"), | |
| 510 | .sh_type = elf.SHT_STRTAB, | |
| 511 | .sh_flags = 0, | |
| 512 | .sh_addr = 0, | |
| 513 | .sh_offset = off, | |
| 514 | .sh_size = self.shstrtab.items.len, | |
| 515 | .sh_link = 0, | |
| 516 | .sh_info = 0, | |
| 517 | .sh_addralign = 1, | |
| 518 | .sh_entsize = 0, | |
| 519 | }); | |
| 520 | self.shstrtab_dirty = true; | |
| 521 | self.shdr_table_dirty = true; | |
| 522 | } | |
| 523 | if (self.text_section_index == null) { | |
| 524 | self.text_section_index = @intCast(u16, self.sections.items.len); | |
| 525 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 526 | ||
| 527 | try self.sections.append(self.base.allocator, .{ | |
| 528 | .sh_name = try self.makeString(".text"), | |
| 529 | .sh_type = elf.SHT_PROGBITS, | |
| 530 | .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 531 | .sh_addr = phdr.p_vaddr, | |
| 532 | .sh_offset = phdr.p_offset, | |
| 533 | .sh_size = phdr.p_filesz, | |
| 534 | .sh_link = 0, | |
| 535 | .sh_info = 0, | |
| 536 | .sh_addralign = phdr.p_align, | |
| 537 | .sh_entsize = 0, | |
| 538 | }); | |
| 539 | self.shdr_table_dirty = true; | |
| 540 | } | |
| 541 | if (self.got_section_index == null) { | |
| 542 | self.got_section_index = @intCast(u16, self.sections.items.len); | |
| 543 | const phdr = &self.program_headers.items[self.phdr_got_index.?]; | |
| 544 | ||
| 545 | try self.sections.append(self.base.allocator, .{ | |
| 546 | .sh_name = try self.makeString(".got"), | |
| 547 | .sh_type = elf.SHT_PROGBITS, | |
| 548 | .sh_flags = elf.SHF_ALLOC, | |
| 549 | .sh_addr = phdr.p_vaddr, | |
| 550 | .sh_offset = phdr.p_offset, | |
| 551 | .sh_size = phdr.p_filesz, | |
| 552 | .sh_link = 0, | |
| 553 | .sh_info = 0, | |
| 554 | .sh_addralign = phdr.p_align, | |
| 555 | .sh_entsize = 0, | |
| 556 | }); | |
| 557 | self.shdr_table_dirty = true; | |
| 558 | } | |
| 559 | if (self.symtab_section_index == null) { | |
| 560 | self.symtab_section_index = @intCast(u16, self.sections.items.len); | |
| 561 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | |
| 562 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | |
| 563 | const file_size = self.base.options.symbol_count_hint * each_size; | |
| 564 | const off = self.findFreeSpace(file_size, min_align); | |
| 565 | log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | |
| 566 | ||
| 567 | try self.sections.append(self.base.allocator, .{ | |
| 568 | .sh_name = try self.makeString(".symtab"), | |
| 569 | .sh_type = elf.SHT_SYMTAB, | |
| 570 | .sh_flags = 0, | |
| 571 | .sh_addr = 0, | |
| 572 | .sh_offset = off, | |
| 573 | .sh_size = file_size, | |
| 574 | // The section header index of the associated string table. | |
| 575 | .sh_link = self.shstrtab_index.?, | |
| 576 | .sh_info = @intCast(u32, self.local_symbols.items.len), | |
| 577 | .sh_addralign = min_align, | |
| 578 | .sh_entsize = each_size, | |
| 579 | }); | |
| 580 | self.shdr_table_dirty = true; | |
| 581 | try self.writeSymbol(0); | |
| 582 | } | |
| 583 | if (self.debug_str_section_index == null) { | |
| 584 | self.debug_str_section_index = @intCast(u16, self.sections.items.len); | |
| 585 | assert(self.debug_strtab.items.len == 0); | |
| 586 | try self.sections.append(self.base.allocator, .{ | |
| 587 | .sh_name = try self.makeString(".debug_str"), | |
| 588 | .sh_type = elf.SHT_PROGBITS, | |
| 589 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, | |
| 590 | .sh_addr = 0, | |
| 591 | .sh_offset = 0, | |
| 592 | .sh_size = self.debug_strtab.items.len, | |
| 593 | .sh_link = 0, | |
| 594 | .sh_info = 0, | |
| 595 | .sh_addralign = 1, | |
| 596 | .sh_entsize = 1, | |
| 597 | }); | |
| 598 | self.debug_strtab_dirty = true; | |
| 599 | self.shdr_table_dirty = true; | |
| 600 | } | |
| 601 | if (self.debug_info_section_index == null) { | |
| 602 | self.debug_info_section_index = @intCast(u16, self.sections.items.len); | |
| 603 | ||
| 604 | const file_size_hint = 200; | |
| 605 | const p_align = 1; | |
| 606 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 607 | log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{ | |
| 608 | off, | |
| 609 | off + file_size_hint, | |
| 610 | }); | |
| 611 | try self.sections.append(self.base.allocator, .{ | |
| 612 | .sh_name = try self.makeString(".debug_info"), | |
| 613 | .sh_type = elf.SHT_PROGBITS, | |
| 614 | .sh_flags = 0, | |
| 615 | .sh_addr = 0, | |
| 616 | .sh_offset = off, | |
| 617 | .sh_size = file_size_hint, | |
| 618 | .sh_link = 0, | |
| 619 | .sh_info = 0, | |
| 620 | .sh_addralign = p_align, | |
| 621 | .sh_entsize = 0, | |
| 622 | }); | |
| 623 | self.shdr_table_dirty = true; | |
| 624 | self.debug_info_header_dirty = true; | |
| 625 | } | |
| 626 | if (self.debug_abbrev_section_index == null) { | |
| 627 | self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); | |
| 628 | ||
| 629 | const file_size_hint = 128; | |
| 630 | const p_align = 1; | |
| 631 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 632 | log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{ | |
| 633 | off, | |
| 634 | off + file_size_hint, | |
| 635 | }); | |
| 636 | try self.sections.append(self.base.allocator, .{ | |
| 637 | .sh_name = try self.makeString(".debug_abbrev"), | |
| 638 | .sh_type = elf.SHT_PROGBITS, | |
| 639 | .sh_flags = 0, | |
| 640 | .sh_addr = 0, | |
| 641 | .sh_offset = off, | |
| 642 | .sh_size = file_size_hint, | |
| 643 | .sh_link = 0, | |
| 644 | .sh_info = 0, | |
| 645 | .sh_addralign = p_align, | |
| 646 | .sh_entsize = 0, | |
| 647 | }); | |
| 648 | self.shdr_table_dirty = true; | |
| 649 | self.debug_abbrev_section_dirty = true; | |
| 650 | } | |
| 651 | if (self.debug_aranges_section_index == null) { | |
| 652 | self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); | |
| 653 | ||
| 654 | const file_size_hint = 160; | |
| 655 | const p_align = 16; | |
| 656 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 657 | log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{ | |
| 658 | off, | |
| 659 | off + file_size_hint, | |
| 660 | }); | |
| 661 | try self.sections.append(self.base.allocator, .{ | |
| 662 | .sh_name = try self.makeString(".debug_aranges"), | |
| 663 | .sh_type = elf.SHT_PROGBITS, | |
| 664 | .sh_flags = 0, | |
| 665 | .sh_addr = 0, | |
| 666 | .sh_offset = off, | |
| 667 | .sh_size = file_size_hint, | |
| 668 | .sh_link = 0, | |
| 669 | .sh_info = 0, | |
| 670 | .sh_addralign = p_align, | |
| 671 | .sh_entsize = 0, | |
| 672 | }); | |
| 673 | self.shdr_table_dirty = true; | |
| 674 | self.debug_aranges_section_dirty = true; | |
| 675 | } | |
| 676 | if (self.debug_line_section_index == null) { | |
| 677 | self.debug_line_section_index = @intCast(u16, self.sections.items.len); | |
| 678 | ||
| 679 | const file_size_hint = 250; | |
| 680 | const p_align = 1; | |
| 681 | const off = self.findFreeSpace(file_size_hint, p_align); | |
| 682 | log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{ | |
| 683 | off, | |
| 684 | off + file_size_hint, | |
| 685 | }); | |
| 686 | try self.sections.append(self.base.allocator, .{ | |
| 687 | .sh_name = try self.makeString(".debug_line"), | |
| 688 | .sh_type = elf.SHT_PROGBITS, | |
| 689 | .sh_flags = 0, | |
| 690 | .sh_addr = 0, | |
| 691 | .sh_offset = off, | |
| 692 | .sh_size = file_size_hint, | |
| 693 | .sh_link = 0, | |
| 694 | .sh_info = 0, | |
| 695 | .sh_addralign = p_align, | |
| 696 | .sh_entsize = 0, | |
| 697 | }); | |
| 698 | self.shdr_table_dirty = true; | |
| 699 | self.debug_line_header_dirty = true; | |
| 700 | } | |
| 701 | const shsize: u64 = switch (self.ptr_width) { | |
| 702 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 703 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 704 | }; | |
| 705 | const shalign: u16 = switch (self.ptr_width) { | |
| 706 | .p32 => @alignOf(elf.Elf32_Shdr), | |
| 707 | .p64 => @alignOf(elf.Elf64_Shdr), | |
| 708 | }; | |
| 709 | if (self.shdr_table_offset == null) { | |
| 710 | self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign); | |
| 711 | self.shdr_table_dirty = true; | |
| 712 | } | |
| 713 | const phsize: u64 = switch (self.ptr_width) { | |
| 714 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 715 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 716 | }; | |
| 717 | const phalign: u16 = switch (self.ptr_width) { | |
| 718 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 719 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 720 | }; | |
| 721 | if (self.phdr_table_offset == null) { | |
| 722 | self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign); | |
| 723 | self.phdr_table_dirty = true; | |
| 724 | } | |
| 725 | { | |
| 726 | // Iterate over symbols, populating free_list and last_text_block. | |
| 727 | if (self.local_symbols.items.len != 1) { | |
| 728 | @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); | |
| 729 | } | |
| 730 | // We are starting with an empty file. The default values are correct, null and empty list. | |
| 731 | } | |
| 732 | } | |
| 733 | ||
| 734 | pub const abbrev_compile_unit = 1; | |
| 735 | pub const abbrev_subprogram = 2; | |
| 736 | pub const abbrev_subprogram_retvoid = 3; | |
| 737 | pub const abbrev_base_type = 4; | |
| 738 | pub const abbrev_pad1 = 5; | |
| 739 | pub const abbrev_parameter = 6; | |
| 740 | ||
| 741 | /// Commit pending changes and write headers. | |
| 742 | pub fn flush(self: *Elf, module: *Module) !void { | |
| 743 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 744 | const foreign_endian = target_endian != std.Target.current.cpu.arch.endian(); | |
| 745 | const ptr_width_bytes: u8 = self.ptrWidthBytes(); | |
| 746 | const init_len_size: usize = switch (self.ptr_width) { | |
| 747 | .p32 => 4, | |
| 748 | .p64 => 12, | |
| 749 | }; | |
| 750 | ||
| 751 | // Unfortunately these have to be buffered and done at the end because ELF does not allow | |
| 752 | // mixing local and global symbols within a symbol table. | |
| 753 | try self.writeAllGlobalSymbols(); | |
| 754 | ||
| 755 | if (self.debug_abbrev_section_dirty) { | |
| 756 | const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?]; | |
| 757 | ||
| 758 | // These are LEB encoded but since the values are all less than 127 | |
| 759 | // we can simply append these bytes. | |
| 760 | const abbrev_buf = [_]u8{ | |
| 761 | abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header | |
| 762 | DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc, | |
| 763 | DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr, | |
| 764 | DW.AT_name, DW.FORM_strp, DW.AT_comp_dir, | |
| 765 | DW.FORM_strp, DW.AT_producer, DW.FORM_strp, | |
| 766 | DW.AT_language, DW.FORM_data2, 0, | |
| 767 | 0, // table sentinel | |
| 768 | abbrev_subprogram, DW.TAG_subprogram, | |
| 769 | DW.CHILDREN_yes, // header | |
| 770 | DW.AT_low_pc, DW.FORM_addr, | |
| 771 | DW.AT_high_pc, DW.FORM_data4, DW.AT_type, | |
| 772 | DW.FORM_ref4, DW.AT_name, DW.FORM_string, | |
| 773 | 0, 0, // table sentinel | |
| 774 | abbrev_subprogram_retvoid, | |
| 775 | DW.TAG_subprogram, DW.CHILDREN_yes, // header | |
| 776 | DW.AT_low_pc, | |
| 777 | DW.FORM_addr, DW.AT_high_pc, DW.FORM_data4, | |
| 778 | DW.AT_name, DW.FORM_string, 0, | |
| 779 | 0, // table sentinel | |
| 780 | abbrev_base_type, DW.TAG_base_type, | |
| 781 | DW.CHILDREN_no, // header | |
| 782 | DW.AT_encoding, DW.FORM_data1, | |
| 783 | DW.AT_byte_size, DW.FORM_data1, DW.AT_name, | |
| 784 | DW.FORM_string, 0, 0, // table sentinel | |
| 785 | ||
| 786 | abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header | |
| 787 | 0, 0, // table sentinel | |
| 788 | abbrev_parameter, | |
| 789 | DW.TAG_formal_parameter, DW.CHILDREN_no, // header | |
| 790 | DW.AT_location, | |
| 791 | DW.FORM_exprloc, DW.AT_type, DW.FORM_ref4, | |
| 792 | DW.AT_name, DW.FORM_string, 0, | |
| 793 | 0, // table sentinel | |
| 794 | 0, 0, | |
| 795 | 0, // section sentinel | |
| 796 | }; | |
| 797 | ||
| 798 | const needed_size = abbrev_buf.len; | |
| 799 | const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset); | |
| 800 | if (needed_size > allocated_size) { | |
| 801 | debug_abbrev_sect.sh_size = 0; // free the space | |
| 802 | debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 803 | } | |
| 804 | debug_abbrev_sect.sh_size = needed_size; | |
| 805 | log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{ | |
| 806 | debug_abbrev_sect.sh_offset, | |
| 807 | debug_abbrev_sect.sh_offset + needed_size, | |
| 808 | }); | |
| 809 | ||
| 810 | const abbrev_offset = 0; | |
| 811 | self.debug_abbrev_table_offset = abbrev_offset; | |
| 812 | try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset); | |
| 813 | if (!self.shdr_table_dirty) { | |
| 814 | // Then it won't get written with the others and we need to do it. | |
| 815 | try self.writeSectHeader(self.debug_abbrev_section_index.?); | |
| 816 | } | |
| 817 | ||
| 818 | self.debug_abbrev_section_dirty = false; | |
| 819 | } | |
| 820 | ||
| 821 | if (self.debug_info_header_dirty) debug_info: { | |
| 822 | // If this value is null it means there is an error in the module; | |
| 823 | // leave debug_info_header_dirty=true. | |
| 824 | const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; | |
| 825 | const last_dbg_info_decl = self.dbg_info_decl_last.?; | |
| 826 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 827 | ||
| 828 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 829 | defer di_buf.deinit(); | |
| 830 | ||
| 831 | // We have a function to compute the upper bound size, because it's needed | |
| 832 | // for determining where to put the offset of the first `LinkBlock`. | |
| 833 | try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes()); | |
| 834 | ||
| 835 | // initial length - length of the .debug_info contribution for this compilation unit, | |
| 836 | // not including the initial length itself. | |
| 837 | // We have to come back and write it later after we know the size. | |
| 838 | const after_init_len = di_buf.items.len + init_len_size; | |
| 839 | // +1 for the final 0 that ends the compilation unit children. | |
| 840 | const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1; | |
| 841 | const init_len = dbg_info_end - after_init_len; | |
| 842 | switch (self.ptr_width) { | |
| 843 | .p32 => { | |
| 844 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); | |
| 845 | }, | |
| 846 | .p64 => { | |
| 847 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | |
| 848 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); | |
| 849 | }, | |
| 850 | } | |
| 851 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version | |
| 852 | const abbrev_offset = self.debug_abbrev_table_offset.?; | |
| 853 | switch (self.ptr_width) { | |
| 854 | .p32 => { | |
| 855 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian); | |
| 856 | di_buf.appendAssumeCapacity(4); // address size | |
| 857 | }, | |
| 858 | .p64 => { | |
| 859 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); | |
| 860 | di_buf.appendAssumeCapacity(8); // address size | |
| 861 | }, | |
| 862 | } | |
| 863 | // Write the form for the compile unit, which must match the abbrev table above. | |
| 864 | const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path); | |
| 865 | const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path); | |
| 866 | const producer_strp = try self.makeDebugString(producer_string); | |
| 867 | // Currently only one compilation unit is supported, so the address range is simply | |
| 868 | // identical to the main program header virtual address and memory size. | |
| 869 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 870 | const low_pc = text_phdr.p_vaddr; | |
| 871 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; | |
| 872 | ||
| 873 | di_buf.appendAssumeCapacity(abbrev_compile_unit); | |
| 874 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset | |
| 875 | self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); | |
| 876 | self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); | |
| 877 | self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); | |
| 878 | self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp); | |
| 879 | self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp); | |
| 880 | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: | |
| 881 | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 | |
| 882 | // Until then we say it is C99. | |
| 883 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); | |
| 884 | ||
| 885 | if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { | |
| 886 | // Move the first N decls to the end to make more padding for the header. | |
| 887 | @panic("TODO: handle .debug_info header exceeding its padding"); | |
| 888 | } | |
| 889 | const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len; | |
| 890 | try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset); | |
| 891 | self.debug_info_header_dirty = false; | |
| 892 | } | |
| 893 | ||
| 894 | if (self.debug_aranges_section_dirty) { | |
| 895 | const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?]; | |
| 896 | ||
| 897 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 898 | defer di_buf.deinit(); | |
| 899 | ||
| 900 | // Enough for all the data without resizing. When support for more compilation units | |
| 901 | // is added, the size of this section will become more variable. | |
| 902 | try di_buf.ensureCapacity(100); | |
| 903 | ||
| 904 | // initial length - length of the .debug_aranges contribution for this compilation unit, | |
| 905 | // not including the initial length itself. | |
| 906 | // We have to come back and write it later after we know the size. | |
| 907 | const init_len_index = di_buf.items.len; | |
| 908 | di_buf.items.len += init_len_size; | |
| 909 | const after_init_len = di_buf.items.len; | |
| 910 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version | |
| 911 | // When more than one compilation unit is supported, this will be the offset to it. | |
| 912 | // For now it is always at offset 0 in .debug_info. | |
| 913 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset | |
| 914 | di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size | |
| 915 | di_buf.appendAssumeCapacity(0); // segment_selector_size | |
| 916 | ||
| 917 | const end_header_offset = di_buf.items.len; | |
| 918 | const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2); | |
| 919 | di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset); | |
| 920 | ||
| 921 | // Currently only one compilation unit is supported, so the address range is simply | |
| 922 | // identical to the main program header virtual address and memory size. | |
| 923 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 924 | self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr); | |
| 925 | self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz); | |
| 926 | ||
| 927 | // Sentinel. | |
| 928 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); | |
| 929 | self.writeDwarfAddrAssumeCapacity(&di_buf, 0); | |
| 930 | ||
| 931 | // Go back and populate the initial length. | |
| 932 | const init_len = di_buf.items.len - after_init_len; | |
| 933 | switch (self.ptr_width) { | |
| 934 | .p32 => { | |
| 935 | mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian); | |
| 936 | }, | |
| 937 | .p64 => { | |
| 938 | // initial length - length of the .debug_aranges contribution for this compilation unit, | |
| 939 | // not including the initial length itself. | |
| 940 | di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; | |
| 941 | mem.writeInt(u64, di_buf.items[init_len_index + 4 ..][0..8], init_len, target_endian); | |
| 942 | }, | |
| 943 | } | |
| 944 | ||
| 945 | const needed_size = di_buf.items.len; | |
| 946 | const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset); | |
| 947 | if (needed_size > allocated_size) { | |
| 948 | debug_aranges_sect.sh_size = 0; // free the space | |
| 949 | debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16); | |
| 950 | } | |
| 951 | debug_aranges_sect.sh_size = needed_size; | |
| 952 | log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{ | |
| 953 | debug_aranges_sect.sh_offset, | |
| 954 | debug_aranges_sect.sh_offset + needed_size, | |
| 955 | }); | |
| 956 | ||
| 957 | try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset); | |
| 958 | if (!self.shdr_table_dirty) { | |
| 959 | // Then it won't get written with the others and we need to do it. | |
| 960 | try self.writeSectHeader(self.debug_aranges_section_index.?); | |
| 961 | } | |
| 962 | ||
| 963 | self.debug_aranges_section_dirty = false; | |
| 964 | } | |
| 965 | if (self.debug_line_header_dirty) debug_line: { | |
| 966 | if (self.dbg_line_fn_first == null) { | |
| 967 | break :debug_line; // Error in module; leave debug_line_header_dirty=true. | |
| 968 | } | |
| 969 | const dbg_line_prg_off = self.getDebugLineProgramOff(); | |
| 970 | const dbg_line_prg_end = self.getDebugLineProgramEnd(); | |
| 971 | assert(dbg_line_prg_end != 0); | |
| 972 | ||
| 973 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | |
| 974 | ||
| 975 | var di_buf = std.ArrayList(u8).init(self.base.allocator); | |
| 976 | defer di_buf.deinit(); | |
| 977 | ||
| 978 | // The size of this header is variable, depending on the number of directories, | |
| 979 | // files, and padding. We have a function to compute the upper bound size, however, | |
| 980 | // because it's needed for determining where to put the offset of the first `SrcFn`. | |
| 981 | try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); | |
| 982 | ||
| 983 | // initial length - length of the .debug_line contribution for this compilation unit, | |
| 984 | // not including the initial length itself. | |
| 985 | const after_init_len = di_buf.items.len + init_len_size; | |
| 986 | const init_len = dbg_line_prg_end - after_init_len; | |
| 987 | switch (self.ptr_width) { | |
| 988 | .p32 => { | |
| 989 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); | |
| 990 | }, | |
| 991 | .p64 => { | |
| 992 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | |
| 993 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); | |
| 994 | }, | |
| 995 | } | |
| 996 | ||
| 997 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version | |
| 998 | ||
| 999 | // Empirically, debug info consumers do not respect this field, or otherwise | |
| 1000 | // consider it to be an error when it does not point exactly to the end of the header. | |
| 1001 | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for | |
| 1002 | // padding rather than this field. | |
| 1003 | const before_header_len = di_buf.items.len; | |
| 1004 | di_buf.items.len += ptr_width_bytes; // We will come back and write this. | |
| 1005 | const after_header_len = di_buf.items.len; | |
| 1006 | ||
| 1007 | const opcode_base = DW.LNS_set_isa + 1; | |
| 1008 | di_buf.appendSliceAssumeCapacity(&[_]u8{ | |
| 1009 | 1, // minimum_instruction_length | |
| 1010 | 1, // maximum_operations_per_instruction | |
| 1011 | 1, // default_is_stmt | |
| 1012 | 1, // line_base (signed) | |
| 1013 | 1, // line_range | |
| 1014 | opcode_base, | |
| 1015 | ||
| 1016 | // Standard opcode lengths. The number of items here is based on `opcode_base`. | |
| 1017 | // The value is the number of LEB128 operands the instruction takes. | |
| 1018 | 0, // `DW.LNS_copy` | |
| 1019 | 1, // `DW.LNS_advance_pc` | |
| 1020 | 1, // `DW.LNS_advance_line` | |
| 1021 | 1, // `DW.LNS_set_file` | |
| 1022 | 1, // `DW.LNS_set_column` | |
| 1023 | 0, // `DW.LNS_negate_stmt` | |
| 1024 | 0, // `DW.LNS_set_basic_block` | |
| 1025 | 0, // `DW.LNS_const_add_pc` | |
| 1026 | 1, // `DW.LNS_fixed_advance_pc` | |
| 1027 | 0, // `DW.LNS_set_prologue_end` | |
| 1028 | 0, // `DW.LNS_set_epilogue_begin` | |
| 1029 | 1, // `DW.LNS_set_isa` | |
| 1030 | ||
| 1031 | 0, // include_directories (none except the compilation unit cwd) | |
| 1032 | }); | |
| 1033 | // file_names[0] | |
| 1034 | di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name | |
| 1035 | di_buf.appendSliceAssumeCapacity(&[_]u8{ | |
| 1036 | 0, // null byte for the relative path name | |
| 1037 | 0, // directory_index | |
| 1038 | 0, // mtime (TODO supply this) | |
| 1039 | 0, // file size bytes (TODO supply this) | |
| 1040 | 0, // file_names sentinel | |
| 1041 | }); | |
| 1042 | ||
| 1043 | const header_len = di_buf.items.len - after_header_len; | |
| 1044 | switch (self.ptr_width) { | |
| 1045 | .p32 => { | |
| 1046 | mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); | |
| 1047 | }, | |
| 1048 | .p64 => { | |
| 1049 | mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); | |
| 1050 | }, | |
| 1051 | } | |
| 1052 | ||
| 1053 | // We use NOPs because consumers empirically do not respect the header length field. | |
| 1054 | if (di_buf.items.len > dbg_line_prg_off) { | |
| 1055 | // Move the first N files to the end to make more padding for the header. | |
| 1056 | @panic("TODO: handle .debug_line header exceeding its padding"); | |
| 1057 | } | |
| 1058 | const jmp_amt = dbg_line_prg_off - di_buf.items.len; | |
| 1059 | try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset); | |
| 1060 | self.debug_line_header_dirty = false; | |
| 1061 | } | |
| 1062 | ||
| 1063 | if (self.phdr_table_dirty) { | |
| 1064 | const phsize: u64 = switch (self.ptr_width) { | |
| 1065 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 1066 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 1067 | }; | |
| 1068 | const phalign: u16 = switch (self.ptr_width) { | |
| 1069 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 1070 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 1071 | }; | |
| 1072 | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); | |
| 1073 | const needed_size = self.program_headers.items.len * phsize; | |
| 1074 | ||
| 1075 | if (needed_size > allocated_size) { | |
| 1076 | self.phdr_table_offset = null; // free the space | |
| 1077 | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); | |
| 1078 | } | |
| 1079 | ||
| 1080 | switch (self.ptr_width) { | |
| 1081 | .p32 => { | |
| 1082 | const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); | |
| 1083 | defer self.base.allocator.free(buf); | |
| 1084 | ||
| 1085 | for (buf) |*phdr, i| { | |
| 1086 | phdr.* = progHeaderTo32(self.program_headers.items[i]); | |
| 1087 | if (foreign_endian) { | |
| 1088 | bswapAllFields(elf.Elf32_Phdr, phdr); | |
| 1089 | } | |
| 1090 | } | |
| 1091 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); | |
| 1092 | }, | |
| 1093 | .p64 => { | |
| 1094 | const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); | |
| 1095 | defer self.base.allocator.free(buf); | |
| 1096 | ||
| 1097 | for (buf) |*phdr, i| { | |
| 1098 | phdr.* = self.program_headers.items[i]; | |
| 1099 | if (foreign_endian) { | |
| 1100 | bswapAllFields(elf.Elf64_Phdr, phdr); | |
| 1101 | } | |
| 1102 | } | |
| 1103 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); | |
| 1104 | }, | |
| 1105 | } | |
| 1106 | self.phdr_table_dirty = false; | |
| 1107 | } | |
| 1108 | ||
| 1109 | { | |
| 1110 | const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; | |
| 1111 | if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { | |
| 1112 | const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); | |
| 1113 | const needed_size = self.shstrtab.items.len; | |
| 1114 | ||
| 1115 | if (needed_size > allocated_size) { | |
| 1116 | shstrtab_sect.sh_size = 0; // free the space | |
| 1117 | shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 1118 | } | |
| 1119 | shstrtab_sect.sh_size = needed_size; | |
| 1120 | log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); | |
| 1121 | ||
| 1122 | try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); | |
| 1123 | if (!self.shdr_table_dirty) { | |
| 1124 | // Then it won't get written with the others and we need to do it. | |
| 1125 | try self.writeSectHeader(self.shstrtab_index.?); | |
| 1126 | } | |
| 1127 | self.shstrtab_dirty = false; | |
| 1128 | } | |
| 1129 | } | |
| 1130 | { | |
| 1131 | const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; | |
| 1132 | if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) { | |
| 1133 | const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); | |
| 1134 | const needed_size = self.debug_strtab.items.len; | |
| 1135 | ||
| 1136 | if (needed_size > allocated_size) { | |
| 1137 | debug_strtab_sect.sh_size = 0; // free the space | |
| 1138 | debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); | |
| 1139 | } | |
| 1140 | debug_strtab_sect.sh_size = needed_size; | |
| 1141 | log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size }); | |
| 1142 | ||
| 1143 | try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset); | |
| 1144 | if (!self.shdr_table_dirty) { | |
| 1145 | // Then it won't get written with the others and we need to do it. | |
| 1146 | try self.writeSectHeader(self.debug_str_section_index.?); | |
| 1147 | } | |
| 1148 | self.debug_strtab_dirty = false; | |
| 1149 | } | |
| 1150 | } | |
| 1151 | if (self.shdr_table_dirty) { | |
| 1152 | const shsize: u64 = switch (self.ptr_width) { | |
| 1153 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 1154 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 1155 | }; | |
| 1156 | const shalign: u16 = switch (self.ptr_width) { | |
| 1157 | .p32 => @alignOf(elf.Elf32_Shdr), | |
| 1158 | .p64 => @alignOf(elf.Elf64_Shdr), | |
| 1159 | }; | |
| 1160 | const allocated_size = self.allocatedSize(self.shdr_table_offset.?); | |
| 1161 | const needed_size = self.sections.items.len * shsize; | |
| 1162 | ||
| 1163 | if (needed_size > allocated_size) { | |
| 1164 | self.shdr_table_offset = null; // free the space | |
| 1165 | self.shdr_table_offset = self.findFreeSpace(needed_size, shalign); | |
| 1166 | } | |
| 1167 | ||
| 1168 | switch (self.ptr_width) { | |
| 1169 | .p32 => { | |
| 1170 | const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); | |
| 1171 | defer self.base.allocator.free(buf); | |
| 1172 | ||
| 1173 | for (buf) |*shdr, i| { | |
| 1174 | shdr.* = sectHeaderTo32(self.sections.items[i]); | |
| 1175 | log.debug("writing section {}\n", .{shdr.*}); | |
| 1176 | if (foreign_endian) { | |
| 1177 | bswapAllFields(elf.Elf32_Shdr, shdr); | |
| 1178 | } | |
| 1179 | } | |
| 1180 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); | |
| 1181 | }, | |
| 1182 | .p64 => { | |
| 1183 | const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); | |
| 1184 | defer self.base.allocator.free(buf); | |
| 1185 | ||
| 1186 | for (buf) |*shdr, i| { | |
| 1187 | shdr.* = self.sections.items[i]; | |
| 1188 | log.debug("writing section {}\n", .{shdr.*}); | |
| 1189 | if (foreign_endian) { | |
| 1190 | bswapAllFields(elf.Elf64_Shdr, shdr); | |
| 1191 | } | |
| 1192 | } | |
| 1193 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); | |
| 1194 | }, | |
| 1195 | } | |
| 1196 | self.shdr_table_dirty = false; | |
| 1197 | } | |
| 1198 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | |
| 1199 | log.debug("flushing. no_entry_point_found = true\n", .{}); | |
| 1200 | self.error_flags.no_entry_point_found = true; | |
| 1201 | } else { | |
| 1202 | log.debug("flushing. no_entry_point_found = false\n", .{}); | |
| 1203 | self.error_flags.no_entry_point_found = false; | |
| 1204 | try self.writeElfHeader(); | |
| 1205 | } | |
| 1206 | ||
| 1207 | // The point of flush() is to commit changes, so in theory, nothing should | |
| 1208 | // be dirty after this. However, it is possible for some things to remain | |
| 1209 | // dirty because they fail to be written in the event of compile errors, | |
| 1210 | // such as debug_line_header_dirty and debug_info_header_dirty. | |
| 1211 | assert(!self.debug_abbrev_section_dirty); | |
| 1212 | assert(!self.debug_aranges_section_dirty); | |
| 1213 | assert(!self.phdr_table_dirty); | |
| 1214 | assert(!self.shdr_table_dirty); | |
| 1215 | assert(!self.shstrtab_dirty); | |
| 1216 | assert(!self.debug_strtab_dirty); | |
| 1217 | } | |
| 1218 | ||
| 1219 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { | |
| 1220 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 1221 | switch (self.ptr_width) { | |
| 1222 | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian), | |
| 1223 | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), | |
| 1224 | } | |
| 1225 | } | |
| 1226 | ||
| 1227 | fn writeElfHeader(self: *Elf) !void { | |
| 1228 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; | |
| 1229 | ||
| 1230 | var index: usize = 0; | |
| 1231 | hdr_buf[0..4].* = "\x7fELF".*; | |
| 1232 | index += 4; | |
| 1233 | ||
| 1234 | hdr_buf[index] = switch (self.ptr_width) { | |
| 1235 | .p32 => elf.ELFCLASS32, | |
| 1236 | .p64 => elf.ELFCLASS64, | |
| 1237 | }; | |
| 1238 | index += 1; | |
| 1239 | ||
| 1240 | const endian = self.base.options.target.cpu.arch.endian(); | |
| 1241 | hdr_buf[index] = switch (endian) { | |
| 1242 | .Little => elf.ELFDATA2LSB, | |
| 1243 | .Big => elf.ELFDATA2MSB, | |
| 1244 | }; | |
| 1245 | index += 1; | |
| 1246 | ||
| 1247 | hdr_buf[index] = 1; // ELF version | |
| 1248 | index += 1; | |
| 1249 | ||
| 1250 | // OS ABI, often set to 0 regardless of target platform | |
| 1251 | // ABI Version, possibly used by glibc but not by static executables | |
| 1252 | // padding | |
| 1253 | mem.set(u8, hdr_buf[index..][0..9], 0); | |
| 1254 | index += 9; | |
| 1255 | ||
| 1256 | assert(index == 16); | |
| 1257 | ||
| 1258 | const elf_type = switch (self.base.options.output_mode) { | |
| 1259 | .Exe => elf.ET.EXEC, | |
| 1260 | .Obj => elf.ET.REL, | |
| 1261 | .Lib => switch (self.base.options.link_mode) { | |
| 1262 | .Static => elf.ET.REL, | |
| 1263 | .Dynamic => elf.ET.DYN, | |
| 1264 | }, | |
| 1265 | }; | |
| 1266 | mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian); | |
| 1267 | index += 2; | |
| 1268 | ||
| 1269 | const machine = self.base.options.target.cpu.arch.toElfMachine(); | |
| 1270 | mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian); | |
| 1271 | index += 2; | |
| 1272 | ||
| 1273 | // ELF Version, again | |
| 1274 | mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); | |
| 1275 | index += 4; | |
| 1276 | ||
| 1277 | const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?; | |
| 1278 | ||
| 1279 | switch (self.ptr_width) { | |
| 1280 | .p32 => { | |
| 1281 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian); | |
| 1282 | index += 4; | |
| 1283 | ||
| 1284 | // e_phoff | |
| 1285 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian); | |
| 1286 | index += 4; | |
| 1287 | ||
| 1288 | // e_shoff | |
| 1289 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian); | |
| 1290 | index += 4; | |
| 1291 | }, | |
| 1292 | .p64 => { | |
| 1293 | // e_entry | |
| 1294 | mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian); | |
| 1295 | index += 8; | |
| 1296 | ||
| 1297 | // e_phoff | |
| 1298 | mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian); | |
| 1299 | index += 8; | |
| 1300 | ||
| 1301 | // e_shoff | |
| 1302 | mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian); | |
| 1303 | index += 8; | |
| 1304 | }, | |
| 1305 | } | |
| 1306 | ||
| 1307 | const e_flags = 0; | |
| 1308 | mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian); | |
| 1309 | index += 4; | |
| 1310 | ||
| 1311 | const e_ehsize: u16 = switch (self.ptr_width) { | |
| 1312 | .p32 => @sizeOf(elf.Elf32_Ehdr), | |
| 1313 | .p64 => @sizeOf(elf.Elf64_Ehdr), | |
| 1314 | }; | |
| 1315 | mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian); | |
| 1316 | index += 2; | |
| 1317 | ||
| 1318 | const e_phentsize: u16 = switch (self.ptr_width) { | |
| 1319 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 1320 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 1321 | }; | |
| 1322 | mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); | |
| 1323 | index += 2; | |
| 1324 | ||
| 1325 | const e_phnum = @intCast(u16, self.program_headers.items.len); | |
| 1326 | mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian); | |
| 1327 | index += 2; | |
| 1328 | ||
| 1329 | const e_shentsize: u16 = switch (self.ptr_width) { | |
| 1330 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 1331 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 1332 | }; | |
| 1333 | mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); | |
| 1334 | index += 2; | |
| 1335 | ||
| 1336 | const e_shnum = @intCast(u16, self.sections.items.len); | |
| 1337 | mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); | |
| 1338 | index += 2; | |
| 1339 | ||
| 1340 | mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian); | |
| 1341 | index += 2; | |
| 1342 | ||
| 1343 | assert(index == e_ehsize); | |
| 1344 | ||
| 1345 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); | |
| 1346 | } | |
| 1347 | ||
| 1348 | fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | |
| 1349 | var already_have_free_list_node = false; | |
| 1350 | { | |
| 1351 | var i: usize = 0; | |
| 1352 | while (i < self.text_block_free_list.items.len) { | |
| 1353 | if (self.text_block_free_list.items[i] == text_block) { | |
| 1354 | _ = self.text_block_free_list.swapRemove(i); | |
| 1355 | continue; | |
| 1356 | } | |
| 1357 | if (self.text_block_free_list.items[i] == text_block.prev) { | |
| 1358 | already_have_free_list_node = true; | |
| 1359 | } | |
| 1360 | i += 1; | |
| 1361 | } | |
| 1362 | } | |
| 1363 | ||
| 1364 | if (self.last_text_block == text_block) { | |
| 1365 | // TODO shrink the .text section size here | |
| 1366 | self.last_text_block = text_block.prev; | |
| 1367 | } | |
| 1368 | ||
| 1369 | if (text_block.prev) |prev| { | |
| 1370 | prev.next = text_block.next; | |
| 1371 | ||
| 1372 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { | |
| 1373 | // The free list is heuristics, it doesn't have to be perfect, so we can | |
| 1374 | // ignore the OOM here. | |
| 1375 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; | |
| 1376 | } | |
| 1377 | } else { | |
| 1378 | text_block.prev = null; | |
| 1379 | } | |
| 1380 | ||
| 1381 | if (text_block.next) |next| { | |
| 1382 | next.prev = text_block.prev; | |
| 1383 | } else { | |
| 1384 | text_block.next = null; | |
| 1385 | } | |
| 1386 | } | |
| 1387 | ||
| 1388 | fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void { | |
| 1389 | // TODO check the new capacity, and if it crosses the size threshold into a big enough | |
| 1390 | // capacity, insert a free list node for it. | |
| 1391 | } | |
| 1392 | ||
| 1393 | fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | |
| 1394 | const sym = self.local_symbols.items[text_block.local_sym_index]; | |
| 1395 | const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; | |
| 1396 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); | |
| 1397 | if (!need_realloc) return sym.st_value; | |
| 1398 | return self.allocateTextBlock(text_block, new_block_size, alignment); | |
| 1399 | } | |
| 1400 | ||
| 1401 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | |
| 1402 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1403 | const shdr = &self.sections.items[self.text_section_index.?]; | |
| 1404 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | |
| 1405 | ||
| 1406 | // We use these to indicate our intention to update metadata, placing the new block, | |
| 1407 | // and possibly removing a free list node. | |
| 1408 | // It would be simpler to do it inside the for loop below, but that would cause a | |
| 1409 | // problem if an error was returned later in the function. So this action | |
| 1410 | // is actually carried out at the end of the function, when errors are no longer possible. | |
| 1411 | var block_placement: ?*TextBlock = null; | |
| 1412 | var free_list_removal: ?usize = null; | |
| 1413 | ||
| 1414 | // First we look for an appropriately sized free list node. | |
| 1415 | // The list is unordered. We'll just take the first thing that works. | |
| 1416 | const vaddr = blk: { | |
| 1417 | var i: usize = 0; | |
| 1418 | while (i < self.text_block_free_list.items.len) { | |
| 1419 | const big_block = self.text_block_free_list.items[i]; | |
| 1420 | // We now have a pointer to a live text block that has too much capacity. | |
| 1421 | // Is it enough that we could fit this new text block? | |
| 1422 | const sym = self.local_symbols.items[big_block.local_sym_index]; | |
| 1423 | const capacity = big_block.capacity(self.*); | |
| 1424 | const ideal_capacity = capacity * alloc_num / alloc_den; | |
| 1425 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | |
| 1426 | const capacity_end_vaddr = sym.st_value + capacity; | |
| 1427 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; | |
| 1428 | const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); | |
| 1429 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | |
| 1430 | // Additional bookkeeping here to notice if this free list node | |
| 1431 | // should be deleted because the block that it points to has grown to take up | |
| 1432 | // more of the extra capacity. | |
| 1433 | if (!big_block.freeListEligible(self.*)) { | |
| 1434 | _ = self.text_block_free_list.swapRemove(i); | |
| 1435 | } else { | |
| 1436 | i += 1; | |
| 1437 | } | |
| 1438 | continue; | |
| 1439 | } | |
| 1440 | // At this point we know that we will place the new block here. But the | |
| 1441 | // remaining question is whether there is still yet enough capacity left | |
| 1442 | // over for there to still be a free list node. | |
| 1443 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; | |
| 1444 | const keep_free_list_node = remaining_capacity >= min_text_capacity; | |
| 1445 | ||
| 1446 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 1447 | block_placement = big_block; | |
| 1448 | if (!keep_free_list_node) { | |
| 1449 | free_list_removal = i; | |
| 1450 | } | |
| 1451 | break :blk new_start_vaddr; | |
| 1452 | } else if (self.last_text_block) |last| { | |
| 1453 | const sym = self.local_symbols.items[last.local_sym_index]; | |
| 1454 | const ideal_capacity = sym.st_size * alloc_num / alloc_den; | |
| 1455 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | |
| 1456 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); | |
| 1457 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 1458 | block_placement = last; | |
| 1459 | break :blk new_start_vaddr; | |
| 1460 | } else { | |
| 1461 | break :blk phdr.p_vaddr; | |
| 1462 | } | |
| 1463 | }; | |
| 1464 | ||
| 1465 | const expand_text_section = block_placement == null or block_placement.?.next == null; | |
| 1466 | if (expand_text_section) { | |
| 1467 | const text_capacity = self.allocatedSize(shdr.sh_offset); | |
| 1468 | const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; | |
| 1469 | if (needed_size > text_capacity) { | |
| 1470 | // Must move the entire text section. | |
| 1471 | const new_offset = self.findFreeSpace(needed_size, 0x1000); | |
| 1472 | const text_size = if (self.last_text_block) |last| blk: { | |
| 1473 | const sym = self.local_symbols.items[last.local_sym_index]; | |
| 1474 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; | |
| 1475 | } else 0; | |
| 1476 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size); | |
| 1477 | if (amt != text_size) return error.InputOutput; | |
| 1478 | shdr.sh_offset = new_offset; | |
| 1479 | phdr.p_offset = new_offset; | |
| 1480 | } | |
| 1481 | self.last_text_block = text_block; | |
| 1482 | ||
| 1483 | shdr.sh_size = needed_size; | |
| 1484 | phdr.p_memsz = needed_size; | |
| 1485 | phdr.p_filesz = needed_size; | |
| 1486 | ||
| 1487 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address | |
| 1488 | // range of the compilation unit. When we expand the text section, this range changes, | |
| 1489 | // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty. | |
| 1490 | self.debug_info_header_dirty = true; | |
| 1491 | // This becomes dirty for the same reason. We could potentially make this more | |
| 1492 | // fine-grained with the addition of support for more compilation units. It is planned to | |
| 1493 | // model each package as a different compilation unit. | |
| 1494 | self.debug_aranges_section_dirty = true; | |
| 1495 | ||
| 1496 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | |
| 1497 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 1498 | } | |
| 1499 | ||
| 1500 | // This function can also reallocate a text block. | |
| 1501 | // In this case we need to "unplug" it from its previous location before | |
| 1502 | // plugging it in to its new location. | |
| 1503 | if (text_block.prev) |prev| { | |
| 1504 | prev.next = text_block.next; | |
| 1505 | } | |
| 1506 | if (text_block.next) |next| { | |
| 1507 | next.prev = text_block.prev; | |
| 1508 | } | |
| 1509 | ||
| 1510 | if (block_placement) |big_block| { | |
| 1511 | text_block.prev = big_block; | |
| 1512 | text_block.next = big_block.next; | |
| 1513 | big_block.next = text_block; | |
| 1514 | } else { | |
| 1515 | text_block.prev = null; | |
| 1516 | text_block.next = null; | |
| 1517 | } | |
| 1518 | if (free_list_removal) |i| { | |
| 1519 | _ = self.text_block_free_list.swapRemove(i); | |
| 1520 | } | |
| 1521 | return vaddr; | |
| 1522 | } | |
| 1523 | ||
| 1524 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | |
| 1525 | if (decl.link.elf.local_sym_index != 0) return; | |
| 1526 | ||
| 1527 | try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); | |
| 1528 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | |
| 1529 | ||
| 1530 | if (self.local_symbol_free_list.popOrNull()) |i| { | |
| 1531 | log.debug("reusing symbol index {} for {}\n", .{ i, decl.name }); | |
| 1532 | decl.link.elf.local_sym_index = i; | |
| 1533 | } else { | |
| 1534 | log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); | |
| 1535 | decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len); | |
| 1536 | _ = self.local_symbols.addOneAssumeCapacity(); | |
| 1537 | } | |
| 1538 | ||
| 1539 | if (self.offset_table_free_list.popOrNull()) |i| { | |
| 1540 | decl.link.elf.offset_table_index = i; | |
| 1541 | } else { | |
| 1542 | decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len); | |
| 1543 | _ = self.offset_table.addOneAssumeCapacity(); | |
| 1544 | self.offset_table_count_dirty = true; | |
| 1545 | } | |
| 1546 | ||
| 1547 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | |
| 1548 | ||
| 1549 | self.local_symbols.items[decl.link.elf.local_sym_index] = .{ | |
| 1550 | .st_name = 0, | |
| 1551 | .st_info = 0, | |
| 1552 | .st_other = 0, | |
| 1553 | .st_shndx = 0, | |
| 1554 | .st_value = phdr.p_vaddr, | |
| 1555 | .st_size = 0, | |
| 1556 | }; | |
| 1557 | self.offset_table.items[decl.link.elf.offset_table_index] = 0; | |
| 1558 | } | |
| 1559 | ||
| 1560 | pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | |
| 1561 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | |
| 1562 | self.freeTextBlock(&decl.link.elf); | |
| 1563 | if (decl.link.elf.local_sym_index != 0) { | |
| 1564 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; | |
| 1565 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; | |
| 1566 | ||
| 1567 | self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; | |
| 1568 | ||
| 1569 | decl.link.elf.local_sym_index = 0; | |
| 1570 | } | |
| 1571 | // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing | |
| 1572 | // is desired for both. | |
| 1573 | _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); | |
| 1574 | if (decl.fn_link.elf.prev) |prev| { | |
| 1575 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 1576 | prev.next = decl.fn_link.elf.next; | |
| 1577 | if (decl.fn_link.elf.next) |next| { | |
| 1578 | next.prev = prev; | |
| 1579 | } else { | |
| 1580 | self.dbg_line_fn_last = prev; | |
| 1581 | } | |
| 1582 | } else if (decl.fn_link.elf.next) |next| { | |
| 1583 | self.dbg_line_fn_first = next; | |
| 1584 | next.prev = null; | |
| 1585 | } | |
| 1586 | if (self.dbg_line_fn_first == &decl.fn_link.elf) { | |
| 1587 | self.dbg_line_fn_first = null; | |
| 1588 | } | |
| 1589 | if (self.dbg_line_fn_last == &decl.fn_link.elf) { | |
| 1590 | self.dbg_line_fn_last = null; | |
| 1591 | } | |
| 1592 | } | |
| 1593 | ||
| 1594 | pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | |
| 1595 | const tracy = trace(@src()); | |
| 1596 | defer tracy.end(); | |
| 1597 | ||
| 1598 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1599 | defer code_buffer.deinit(); | |
| 1600 | ||
| 1601 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1602 | defer dbg_line_buffer.deinit(); | |
| 1603 | ||
| 1604 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | |
| 1605 | defer dbg_info_buffer.deinit(); | |
| 1606 | ||
| 1607 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | |
| 1608 | defer { | |
| 1609 | for (dbg_info_type_relocs.items()) |*entry| { | |
| 1610 | entry.value.relocs.deinit(self.base.allocator); | |
| 1611 | } | |
| 1612 | dbg_info_type_relocs.deinit(self.base.allocator); | |
| 1613 | } | |
| 1614 | ||
| 1615 | const typed_value = decl.typed_value.most_recent.typed_value; | |
| 1616 | const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { | |
| 1617 | .Fn => true, | |
| 1618 | else => false, | |
| 1619 | }; | |
| 1620 | if (is_fn) { | |
| 1621 | //if (mem.eql(u8, mem.spanZ(decl.name), "add")) { | |
| 1622 | // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*); | |
| 1623 | //} | |
| 1624 | ||
| 1625 | // For functions we need to add a prologue to the debug line program. | |
| 1626 | try dbg_line_buffer.ensureCapacity(26); | |
| 1627 | ||
| 1628 | const line_off: u28 = blk: { | |
| 1629 | if (decl.scope.cast(Module.Scope.File)) |scope_file| { | |
| 1630 | const tree = scope_file.contents.tree; | |
| 1631 | const file_ast_decls = tree.root_node.decls(); | |
| 1632 | // TODO Look into improving the performance here by adding a token-index-to-line | |
| 1633 | // lookup table. Currently this involves scanning over the source code for newlines. | |
| 1634 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | |
| 1635 | const block = fn_proto.body().?.castTag(.Block).?; | |
| 1636 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); | |
| 1637 | break :blk @intCast(u28, line_delta); | |
| 1638 | } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| { | |
| 1639 | const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src; | |
| 1640 | const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off); | |
| 1641 | break :blk @intCast(u28, line_delta); | |
| 1642 | } else { | |
| 1643 | unreachable; | |
| 1644 | } | |
| 1645 | }; | |
| 1646 | ||
| 1647 | const ptr_width_bytes = self.ptrWidthBytes(); | |
| 1648 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | |
| 1649 | DW.LNS_extended_op, | |
| 1650 | ptr_width_bytes + 1, | |
| 1651 | DW.LNE_set_address, | |
| 1652 | }); | |
| 1653 | // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. | |
| 1654 | assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); | |
| 1655 | dbg_line_buffer.items.len += ptr_width_bytes; | |
| 1656 | ||
| 1657 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); | |
| 1658 | // This is the "relocatable" relative line offset from the previous function's end curly | |
| 1659 | // to this function's begin curly. | |
| 1660 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); | |
| 1661 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. | |
| 1662 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); | |
| 1663 | ||
| 1664 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); | |
| 1665 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); | |
| 1666 | // Once we support more than one source file, this will have the ability to be more | |
| 1667 | // than one possible value. | |
| 1668 | const file_index = 1; | |
| 1669 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); | |
| 1670 | ||
| 1671 | // Emit a line for the begin curly with prologue_end=false. The codegen will | |
| 1672 | // do the work of setting prologue_end=true and epilogue_begin=true. | |
| 1673 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); | |
| 1674 | ||
| 1675 | // .debug_info subprogram | |
| 1676 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; | |
| 1677 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); | |
| 1678 | ||
| 1679 | const fn_ret_type = typed_value.ty.fnReturnType(); | |
| 1680 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | |
| 1681 | if (fn_ret_has_bits) { | |
| 1682 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | |
| 1683 | } else { | |
| 1684 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); | |
| 1685 | } | |
| 1686 | // These get overwritten after generating the machine code. These values are | |
| 1687 | // "relocations" and have to be in this fixed place so that functions can be | |
| 1688 | // moved in virtual address space. | |
| 1689 | assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); | |
| 1690 | dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr | |
| 1691 | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); | |
| 1692 | dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 | |
| 1693 | if (fn_ret_has_bits) { | |
| 1694 | const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); | |
| 1695 | if (!gop.found_existing) { | |
| 1696 | gop.entry.value = .{ | |
| 1697 | .off = undefined, | |
| 1698 | .relocs = .{}, | |
| 1699 | }; | |
| 1700 | } | |
| 1701 | try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); | |
| 1702 | dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 | |
| 1703 | } | |
| 1704 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string | |
| 1705 | } else { | |
| 1706 | // TODO implement .debug_info for global variables | |
| 1707 | } | |
| 1708 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs); | |
| 1709 | const code = switch (res) { | |
| 1710 | .externally_managed => |x| x, | |
| 1711 | .appended => code_buffer.items, | |
| 1712 | .fail => |em| { | |
| 1713 | decl.analysis = .codegen_failure; | |
| 1714 | try module.failed_decls.put(module.gpa, decl, em); | |
| 1715 | return; | |
| 1716 | }, | |
| 1717 | }; | |
| 1718 | ||
| 1719 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | |
| 1720 | ||
| 1721 | const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; | |
| 1722 | ||
| 1723 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | |
| 1724 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | |
| 1725 | if (local_sym.st_size != 0) { | |
| 1726 | const capacity = decl.link.elf.capacity(self.*); | |
| 1727 | const need_realloc = code.len > capacity or | |
| 1728 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); | |
| 1729 | if (need_realloc) { | |
| 1730 | const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment); | |
| 1731 | log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); | |
| 1732 | if (vaddr != local_sym.st_value) { | |
| 1733 | local_sym.st_value = vaddr; | |
| 1734 | ||
| 1735 | log.debug(" (writing new offset table entry)\n", .{}); | |
| 1736 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; | |
| 1737 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | |
| 1738 | } | |
| 1739 | } else if (code.len < local_sym.st_size) { | |
| 1740 | self.shrinkTextBlock(&decl.link.elf, code.len); | |
| 1741 | } | |
| 1742 | local_sym.st_size = code.len; | |
| 1743 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name)); | |
| 1744 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; | |
| 1745 | local_sym.st_other = 0; | |
| 1746 | local_sym.st_shndx = self.text_section_index.?; | |
| 1747 | // TODO this write could be avoided if no fields of the symbol were changed. | |
| 1748 | try self.writeSymbol(decl.link.elf.local_sym_index); | |
| 1749 | } else { | |
| 1750 | const decl_name = mem.spanZ(decl.name); | |
| 1751 | const name_str_index = try self.makeString(decl_name); | |
| 1752 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment); | |
| 1753 | log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); | |
| 1754 | errdefer self.freeTextBlock(&decl.link.elf); | |
| 1755 | ||
| 1756 | local_sym.* = .{ | |
| 1757 | .st_name = name_str_index, | |
| 1758 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, | |
| 1759 | .st_other = 0, | |
| 1760 | .st_shndx = self.text_section_index.?, | |
| 1761 | .st_value = vaddr, | |
| 1762 | .st_size = code.len, | |
| 1763 | }; | |
| 1764 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; | |
| 1765 | ||
| 1766 | try self.writeSymbol(decl.link.elf.local_sym_index); | |
| 1767 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | |
| 1768 | } | |
| 1769 | ||
| 1770 | const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr; | |
| 1771 | const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; | |
| 1772 | try self.base.file.?.pwriteAll(code, file_offset); | |
| 1773 | ||
| 1774 | const target_endian = self.base.options.target.cpu.arch.endian(); | |
| 1775 | ||
| 1776 | const text_block = &decl.link.elf; | |
| 1777 | ||
| 1778 | // If the Decl is a function, we need to update the .debug_line program. | |
| 1779 | if (is_fn) { | |
| 1780 | // Perform the relocations based on vaddr. | |
| 1781 | switch (self.ptr_width) { | |
| 1782 | .p32 => { | |
| 1783 | { | |
| 1784 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; | |
| 1785 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | |
| 1786 | } | |
| 1787 | { | |
| 1788 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; | |
| 1789 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | |
| 1790 | } | |
| 1791 | }, | |
| 1792 | .p64 => { | |
| 1793 | { | |
| 1794 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; | |
| 1795 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | |
| 1796 | } | |
| 1797 | { | |
| 1798 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; | |
| 1799 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | |
| 1800 | } | |
| 1801 | }, | |
| 1802 | } | |
| 1803 | { | |
| 1804 | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; | |
| 1805 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); | |
| 1806 | } | |
| 1807 | ||
| 1808 | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); | |
| 1809 | ||
| 1810 | // Now we have the full contents and may allocate a region to store it. | |
| 1811 | ||
| 1812 | // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for | |
| 1813 | // `TextBlock` and the .debug_info. If you are editing this logic, you | |
| 1814 | // probably need to edit that logic too. | |
| 1815 | ||
| 1816 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | |
| 1817 | const src_fn = &decl.fn_link.elf; | |
| 1818 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | |
| 1819 | if (self.dbg_line_fn_last) |last| { | |
| 1820 | if (src_fn.next) |next| { | |
| 1821 | // Update existing function - non-last item. | |
| 1822 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | |
| 1823 | // It grew too big, so we move it to a new location. | |
| 1824 | if (src_fn.prev) |prev| { | |
| 1825 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 1826 | prev.next = src_fn.next; | |
| 1827 | } | |
| 1828 | next.prev = src_fn.prev; | |
| 1829 | src_fn.next = null; | |
| 1830 | // Populate where it used to be with NOPs. | |
| 1831 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | |
| 1832 | try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); | |
| 1833 | // TODO Look at the free list before appending at the end. | |
| 1834 | src_fn.prev = last; | |
| 1835 | last.next = src_fn; | |
| 1836 | self.dbg_line_fn_last = src_fn; | |
| 1837 | ||
| 1838 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | |
| 1839 | } | |
| 1840 | } else if (src_fn.prev == null) { | |
| 1841 | // Append new function. | |
| 1842 | // TODO Look at the free list before appending at the end. | |
| 1843 | src_fn.prev = last; | |
| 1844 | last.next = src_fn; | |
| 1845 | self.dbg_line_fn_last = src_fn; | |
| 1846 | ||
| 1847 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | |
| 1848 | } | |
| 1849 | } else { | |
| 1850 | // This is the first function of the Line Number Program. | |
| 1851 | self.dbg_line_fn_first = src_fn; | |
| 1852 | self.dbg_line_fn_last = src_fn; | |
| 1853 | ||
| 1854 | src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; | |
| 1855 | } | |
| 1856 | ||
| 1857 | const last_src_fn = self.dbg_line_fn_last.?; | |
| 1858 | const needed_size = last_src_fn.off + last_src_fn.len; | |
| 1859 | if (needed_size != debug_line_sect.sh_size) { | |
| 1860 | if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { | |
| 1861 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 1862 | const existing_size = last_src_fn.off; | |
| 1863 | log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{ | |
| 1864 | existing_size, | |
| 1865 | debug_line_sect.sh_offset, | |
| 1866 | new_offset, | |
| 1867 | }); | |
| 1868 | const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 1869 | if (amt != existing_size) return error.InputOutput; | |
| 1870 | debug_line_sect.sh_offset = new_offset; | |
| 1871 | } | |
| 1872 | debug_line_sect.sh_size = needed_size; | |
| 1873 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 1874 | self.debug_line_header_dirty = true; | |
| 1875 | } | |
| 1876 | const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; | |
| 1877 | const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | |
| 1878 | ||
| 1879 | // We only have support for one compilation unit so far, so the offsets are directly | |
| 1880 | // from the .debug_line section. | |
| 1881 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | |
| 1882 | try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); | |
| 1883 | ||
| 1884 | // .debug_info - End the TAG_subprogram children. | |
| 1885 | try dbg_info_buffer.append(0); | |
| 1886 | } | |
| 1887 | ||
| 1888 | // Now we emit the .debug_info types of the Decl. These will count towards the size of | |
| 1889 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual | |
| 1890 | // relocations yet. | |
| 1891 | for (dbg_info_type_relocs.items()) |*entry| { | |
| 1892 | entry.value.off = @intCast(u32, dbg_info_buffer.items.len); | |
| 1893 | try self.addDbgInfoType(entry.key, &dbg_info_buffer); | |
| 1894 | } | |
| 1895 | ||
| 1896 | try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); | |
| 1897 | ||
| 1898 | // Now that we have the offset assigned we can finally perform type relocations. | |
| 1899 | for (dbg_info_type_relocs.items()) |entry| { | |
| 1900 | for (entry.value.relocs.items) |off| { | |
| 1901 | mem.writeInt( | |
| 1902 | u32, | |
| 1903 | dbg_info_buffer.items[off..][0..4], | |
| 1904 | text_block.dbg_info_off + entry.value.off, | |
| 1905 | target_endian, | |
| 1906 | ); | |
| 1907 | } | |
| 1908 | } | |
| 1909 | ||
| 1910 | try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items); | |
| 1911 | ||
| 1912 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | |
| 1913 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | |
| 1914 | return self.updateDeclExports(module, decl, decl_exports); | |
| 1915 | } | |
| 1916 | ||
| 1917 | /// Asserts the type has codegen bits. | |
| 1918 | fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { | |
| 1919 | switch (ty.zigTypeTag()) { | |
| 1920 | .Void => unreachable, | |
| 1921 | .NoReturn => unreachable, | |
| 1922 | .Bool => { | |
| 1923 | try dbg_info_buffer.appendSlice(&[_]u8{ | |
| 1924 | abbrev_base_type, | |
| 1925 | DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 | |
| 1926 | 1, // DW.AT_byte_size, DW.FORM_data1 | |
| 1927 | 'b', | |
| 1928 | 'o', | |
| 1929 | 'o', | |
| 1930 | 'l', | |
| 1931 | 0, // DW.AT_name, DW.FORM_string | |
| 1932 | }); | |
| 1933 | }, | |
| 1934 | .Int => { | |
| 1935 | const info = ty.intInfo(self.base.options.target); | |
| 1936 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); | |
| 1937 | dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); | |
| 1938 | // DW.AT_encoding, DW.FORM_data1 | |
| 1939 | dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned); | |
| 1940 | // DW.AT_byte_size, DW.FORM_data1 | |
| 1941 | dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); | |
| 1942 | // DW.AT_name, DW.FORM_string | |
| 1943 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); | |
| 1944 | }, | |
| 1945 | else => { | |
| 1946 | std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty}); | |
| 1947 | try dbg_info_buffer.append(abbrev_pad1); | |
| 1948 | }, | |
| 1949 | } | |
| 1950 | } | |
| 1951 | ||
| 1952 | fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void { | |
| 1953 | const tracy = trace(@src()); | |
| 1954 | defer tracy.end(); | |
| 1955 | ||
| 1956 | // This logic is nearly identical to the logic above in `updateDecl` for | |
| 1957 | // `SrcFn` and the line number programs. If you are editing this logic, you | |
| 1958 | // probably need to edit that logic too. | |
| 1959 | ||
| 1960 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 1961 | text_block.dbg_info_len = len; | |
| 1962 | if (self.dbg_info_decl_last) |last| { | |
| 1963 | if (text_block.dbg_info_next) |next| { | |
| 1964 | // Update existing Decl - non-last item. | |
| 1965 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { | |
| 1966 | // It grew too big, so we move it to a new location. | |
| 1967 | if (text_block.dbg_info_prev) |prev| { | |
| 1968 | _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 1969 | prev.dbg_info_next = text_block.dbg_info_next; | |
| 1970 | } | |
| 1971 | next.dbg_info_prev = text_block.dbg_info_prev; | |
| 1972 | text_block.dbg_info_next = null; | |
| 1973 | // Populate where it used to be with NOPs. | |
| 1974 | const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; | |
| 1975 | try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos); | |
| 1976 | // TODO Look at the free list before appending at the end. | |
| 1977 | text_block.dbg_info_prev = last; | |
| 1978 | last.dbg_info_next = text_block; | |
| 1979 | self.dbg_info_decl_last = text_block; | |
| 1980 | ||
| 1981 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | |
| 1982 | } | |
| 1983 | } else if (text_block.dbg_info_prev == null) { | |
| 1984 | // Append new Decl. | |
| 1985 | // TODO Look at the free list before appending at the end. | |
| 1986 | text_block.dbg_info_prev = last; | |
| 1987 | last.dbg_info_next = text_block; | |
| 1988 | self.dbg_info_decl_last = text_block; | |
| 1989 | ||
| 1990 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | |
| 1991 | } | |
| 1992 | } else { | |
| 1993 | // This is the first Decl of the .debug_info | |
| 1994 | self.dbg_info_decl_first = text_block; | |
| 1995 | self.dbg_info_decl_last = text_block; | |
| 1996 | ||
| 1997 | text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den; | |
| 1998 | } | |
| 1999 | } | |
| 2000 | ||
| 2001 | fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void { | |
| 2002 | const tracy = trace(@src()); | |
| 2003 | defer tracy.end(); | |
| 2004 | ||
| 2005 | // This logic is nearly identical to the logic above in `updateDecl` for | |
| 2006 | // `SrcFn` and the line number programs. If you are editing this logic, you | |
| 2007 | // probably need to edit that logic too. | |
| 2008 | ||
| 2009 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; | |
| 2010 | ||
| 2011 | const last_decl = self.dbg_info_decl_last.?; | |
| 2012 | // +1 for a trailing zero to end the children of the decl tag. | |
| 2013 | const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; | |
| 2014 | if (needed_size != debug_info_sect.sh_size) { | |
| 2015 | if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) { | |
| 2016 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 2017 | const existing_size = last_decl.dbg_info_off; | |
| 2018 | log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{ | |
| 2019 | existing_size, | |
| 2020 | debug_info_sect.sh_offset, | |
| 2021 | new_offset, | |
| 2022 | }); | |
| 2023 | const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 2024 | if (amt != existing_size) return error.InputOutput; | |
| 2025 | debug_info_sect.sh_offset = new_offset; | |
| 2026 | } | |
| 2027 | debug_info_sect.sh_size = needed_size; | |
| 2028 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 2029 | self.debug_info_header_dirty = true; | |
| 2030 | } | |
| 2031 | const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev| | |
| 2032 | text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len) | |
| 2033 | else | |
| 2034 | 0; | |
| 2035 | const next_padding_size: u32 = if (text_block.dbg_info_next) |next| | |
| 2036 | next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len) | |
| 2037 | else | |
| 2038 | 0; | |
| 2039 | ||
| 2040 | // To end the children of the decl tag. | |
| 2041 | const trailing_zero = text_block.dbg_info_next == null; | |
| 2042 | ||
| 2043 | // We only have support for one compilation unit so far, so the offsets are directly | |
| 2044 | // from the .debug_info section. | |
| 2045 | const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; | |
| 2046 | try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos); | |
| 2047 | } | |
| 2048 | ||
| 2049 | pub fn updateDeclExports( | |
| 2050 | self: *Elf, | |
| 2051 | module: *Module, | |
| 2052 | decl: *const Module.Decl, | |
| 2053 | exports: []const *Module.Export, | |
| 2054 | ) !void { | |
| 2055 | const tracy = trace(@src()); | |
| 2056 | defer tracy.end(); | |
| 2057 | ||
| 2058 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); | |
| 2059 | const typed_value = decl.typed_value.most_recent.typed_value; | |
| 2060 | if (decl.link.elf.local_sym_index == 0) return; | |
| 2061 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; | |
| 2062 | ||
| 2063 | for (exports) |exp| { | |
| 2064 | if (exp.options.section) |section_name| { | |
| 2065 | if (!mem.eql(u8, section_name, ".text")) { | |
| 2066 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | |
| 2067 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2068 | exp, | |
| 2069 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), | |
| 2070 | ); | |
| 2071 | continue; | |
| 2072 | } | |
| 2073 | } | |
| 2074 | const stb_bits: u8 = switch (exp.options.linkage) { | |
| 2075 | .Internal => elf.STB_LOCAL, | |
| 2076 | .Strong => blk: { | |
| 2077 | if (mem.eql(u8, exp.options.name, "_start")) { | |
| 2078 | self.entry_addr = decl_sym.st_value; | |
| 2079 | } | |
| 2080 | break :blk elf.STB_GLOBAL; | |
| 2081 | }, | |
| 2082 | .Weak => elf.STB_WEAK, | |
| 2083 | .LinkOnce => { | |
| 2084 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | |
| 2085 | module.failed_exports.putAssumeCapacityNoClobber( | |
| 2086 | exp, | |
| 2087 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), | |
| 2088 | ); | |
| 2089 | continue; | |
| 2090 | }, | |
| 2091 | }; | |
| 2092 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); | |
| 2093 | if (exp.link.sym_index) |i| { | |
| 2094 | const sym = &self.global_symbols.items[i]; | |
| 2095 | sym.* = .{ | |
| 2096 | .st_name = try self.updateString(sym.st_name, exp.options.name), | |
| 2097 | .st_info = (stb_bits << 4) | stt_bits, | |
| 2098 | .st_other = 0, | |
| 2099 | .st_shndx = self.text_section_index.?, | |
| 2100 | .st_value = decl_sym.st_value, | |
| 2101 | .st_size = decl_sym.st_size, | |
| 2102 | }; | |
| 2103 | } else { | |
| 2104 | const name = try self.makeString(exp.options.name); | |
| 2105 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { | |
| 2106 | _ = self.global_symbols.addOneAssumeCapacity(); | |
| 2107 | break :blk self.global_symbols.items.len - 1; | |
| 2108 | }; | |
| 2109 | self.global_symbols.items[i] = .{ | |
| 2110 | .st_name = name, | |
| 2111 | .st_info = (stb_bits << 4) | stt_bits, | |
| 2112 | .st_other = 0, | |
| 2113 | .st_shndx = self.text_section_index.?, | |
| 2114 | .st_value = decl_sym.st_value, | |
| 2115 | .st_size = decl_sym.st_size, | |
| 2116 | }; | |
| 2117 | ||
| 2118 | exp.link.sym_index = @intCast(u32, i); | |
| 2119 | } | |
| 2120 | } | |
| 2121 | } | |
| 2122 | ||
| 2123 | /// Must be called only after a successful call to `updateDecl`. | |
| 2124 | pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void { | |
| 2125 | const tracy = trace(@src()); | |
| 2126 | defer tracy.end(); | |
| 2127 | ||
| 2128 | const scope_file = decl.scope.cast(Module.Scope.File).?; | |
| 2129 | const tree = scope_file.contents.tree; | |
| 2130 | const file_ast_decls = tree.root_node.decls(); | |
| 2131 | // TODO Look into improving the performance here by adding a token-index-to-line | |
| 2132 | // lookup table. Currently this involves scanning over the source code for newlines. | |
| 2133 | const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; | |
| 2134 | const block = fn_proto.body().?.castTag(.Block).?; | |
| 2135 | const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); | |
| 2136 | const casted_line_off = @intCast(u28, line_delta); | |
| 2137 | ||
| 2138 | const shdr = &self.sections.items[self.debug_line_section_index.?]; | |
| 2139 | const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); | |
| 2140 | var data: [4]u8 = undefined; | |
| 2141 | leb128.writeUnsignedFixed(4, &data, casted_line_off); | |
| 2142 | try self.base.file.?.pwriteAll(&data, file_pos); | |
| 2143 | } | |
| 2144 | ||
| 2145 | pub fn deleteExport(self: *Elf, exp: Export) void { | |
| 2146 | const sym_index = exp.sym_index orelse return; | |
| 2147 | self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; | |
| 2148 | self.global_symbols.items[sym_index].st_info = 0; | |
| 2149 | } | |
| 2150 | ||
| 2151 | fn writeProgHeader(self: *Elf, index: usize) !void { | |
| 2152 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2153 | const offset = self.program_headers.items[index].p_offset; | |
| 2154 | switch (self.base.options.target.cpu.arch.ptrBitWidth()) { | |
| 2155 | 32 => { | |
| 2156 | var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])}; | |
| 2157 | if (foreign_endian) { | |
| 2158 | bswapAllFields(elf.Elf32_Phdr, &phdr[0]); | |
| 2159 | } | |
| 2160 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); | |
| 2161 | }, | |
| 2162 | 64 => { | |
| 2163 | var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]}; | |
| 2164 | if (foreign_endian) { | |
| 2165 | bswapAllFields(elf.Elf64_Phdr, &phdr[0]); | |
| 2166 | } | |
| 2167 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); | |
| 2168 | }, | |
| 2169 | else => return error.UnsupportedArchitecture, | |
| 2170 | } | |
| 2171 | } | |
| 2172 | ||
| 2173 | fn writeSectHeader(self: *Elf, index: usize) !void { | |
| 2174 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2175 | switch (self.base.options.target.cpu.arch.ptrBitWidth()) { | |
| 2176 | 32 => { | |
| 2177 | var shdr: [1]elf.Elf32_Shdr = undefined; | |
| 2178 | shdr[0] = sectHeaderTo32(self.sections.items[index]); | |
| 2179 | if (foreign_endian) { | |
| 2180 | bswapAllFields(elf.Elf32_Shdr, &shdr[0]); | |
| 2181 | } | |
| 2182 | const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr); | |
| 2183 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); | |
| 2184 | }, | |
| 2185 | 64 => { | |
| 2186 | var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; | |
| 2187 | if (foreign_endian) { | |
| 2188 | bswapAllFields(elf.Elf64_Shdr, &shdr[0]); | |
| 2189 | } | |
| 2190 | const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr); | |
| 2191 | return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); | |
| 2192 | }, | |
| 2193 | else => return error.UnsupportedArchitecture, | |
| 2194 | } | |
| 2195 | } | |
| 2196 | ||
| 2197 | fn writeOffsetTableEntry(self: *Elf, index: usize) !void { | |
| 2198 | const shdr = &self.sections.items[self.got_section_index.?]; | |
| 2199 | const phdr = &self.program_headers.items[self.phdr_got_index.?]; | |
| 2200 | const entry_size: u16 = self.ptrWidthBytes(); | |
| 2201 | if (self.offset_table_count_dirty) { | |
| 2202 | // TODO Also detect virtual address collisions. | |
| 2203 | const allocated_size = self.allocatedSize(shdr.sh_offset); | |
| 2204 | const needed_size = self.local_symbols.items.len * entry_size; | |
| 2205 | if (needed_size > allocated_size) { | |
| 2206 | // Must move the entire got section. | |
| 2207 | const new_offset = self.findFreeSpace(needed_size, entry_size); | |
| 2208 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size); | |
| 2209 | if (amt != shdr.sh_size) return error.InputOutput; | |
| 2210 | shdr.sh_offset = new_offset; | |
| 2211 | phdr.p_offset = new_offset; | |
| 2212 | } | |
| 2213 | shdr.sh_size = needed_size; | |
| 2214 | phdr.p_memsz = needed_size; | |
| 2215 | phdr.p_filesz = needed_size; | |
| 2216 | ||
| 2217 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | |
| 2218 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | |
| 2219 | ||
| 2220 | self.offset_table_count_dirty = false; | |
| 2221 | } | |
| 2222 | const endian = self.base.options.target.cpu.arch.endian(); | |
| 2223 | const off = shdr.sh_offset + @as(u64, entry_size) * index; | |
| 2224 | switch (self.ptr_width) { | |
| 2225 | .p32 => { | |
| 2226 | var buf: [4]u8 = undefined; | |
| 2227 | mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian); | |
| 2228 | try self.base.file.?.pwriteAll(&buf, off); | |
| 2229 | }, | |
| 2230 | .p64 => { | |
| 2231 | var buf: [8]u8 = undefined; | |
| 2232 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); | |
| 2233 | try self.base.file.?.pwriteAll(&buf, off); | |
| 2234 | }, | |
| 2235 | } | |
| 2236 | } | |
| 2237 | ||
| 2238 | fn writeSymbol(self: *Elf, index: usize) !void { | |
| 2239 | const tracy = trace(@src()); | |
| 2240 | defer tracy.end(); | |
| 2241 | ||
| 2242 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | |
| 2243 | // Make sure we are not pointlessly writing symbol data that will have to get relocated | |
| 2244 | // due to running out of space. | |
| 2245 | if (self.local_symbols.items.len != syms_sect.sh_info) { | |
| 2246 | const sym_size: u64 = switch (self.ptr_width) { | |
| 2247 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 2248 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 2249 | }; | |
| 2250 | const sym_align: u16 = switch (self.ptr_width) { | |
| 2251 | .p32 => @alignOf(elf.Elf32_Sym), | |
| 2252 | .p64 => @alignOf(elf.Elf64_Sym), | |
| 2253 | }; | |
| 2254 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; | |
| 2255 | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { | |
| 2256 | // Move all the symbols to a new file location. | |
| 2257 | const new_offset = self.findFreeSpace(needed_size, sym_align); | |
| 2258 | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; | |
| 2259 | const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); | |
| 2260 | if (amt != existing_size) return error.InputOutput; | |
| 2261 | syms_sect.sh_offset = new_offset; | |
| 2262 | } | |
| 2263 | syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); | |
| 2264 | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later | |
| 2265 | self.shdr_table_dirty = true; // TODO look into only writing one section | |
| 2266 | } | |
| 2267 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2268 | switch (self.ptr_width) { | |
| 2269 | .p32 => { | |
| 2270 | var sym = [1]elf.Elf32_Sym{ | |
| 2271 | .{ | |
| 2272 | .st_name = self.local_symbols.items[index].st_name, | |
| 2273 | .st_value = @intCast(u32, self.local_symbols.items[index].st_value), | |
| 2274 | .st_size = @intCast(u32, self.local_symbols.items[index].st_size), | |
| 2275 | .st_info = self.local_symbols.items[index].st_info, | |
| 2276 | .st_other = self.local_symbols.items[index].st_other, | |
| 2277 | .st_shndx = self.local_symbols.items[index].st_shndx, | |
| 2278 | }, | |
| 2279 | }; | |
| 2280 | if (foreign_endian) { | |
| 2281 | bswapAllFields(elf.Elf32_Sym, &sym[0]); | |
| 2282 | } | |
| 2283 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; | |
| 2284 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | |
| 2285 | }, | |
| 2286 | .p64 => { | |
| 2287 | var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; | |
| 2288 | if (foreign_endian) { | |
| 2289 | bswapAllFields(elf.Elf64_Sym, &sym[0]); | |
| 2290 | } | |
| 2291 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; | |
| 2292 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | |
| 2293 | }, | |
| 2294 | } | |
| 2295 | } | |
| 2296 | ||
| 2297 | fn writeAllGlobalSymbols(self: *Elf) !void { | |
| 2298 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | |
| 2299 | const sym_size: u64 = switch (self.ptr_width) { | |
| 2300 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 2301 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 2302 | }; | |
| 2303 | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | |
| 2304 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; | |
| 2305 | switch (self.ptr_width) { | |
| 2306 | .p32 => { | |
| 2307 | const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); | |
| 2308 | defer self.base.allocator.free(buf); | |
| 2309 | ||
| 2310 | for (buf) |*sym, i| { | |
| 2311 | sym.* = .{ | |
| 2312 | .st_name = self.global_symbols.items[i].st_name, | |
| 2313 | .st_value = @intCast(u32, self.global_symbols.items[i].st_value), | |
| 2314 | .st_size = @intCast(u32, self.global_symbols.items[i].st_size), | |
| 2315 | .st_info = self.global_symbols.items[i].st_info, | |
| 2316 | .st_other = self.global_symbols.items[i].st_other, | |
| 2317 | .st_shndx = self.global_symbols.items[i].st_shndx, | |
| 2318 | }; | |
| 2319 | if (foreign_endian) { | |
| 2320 | bswapAllFields(elf.Elf32_Sym, sym); | |
| 2321 | } | |
| 2322 | } | |
| 2323 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); | |
| 2324 | }, | |
| 2325 | .p64 => { | |
| 2326 | const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len); | |
| 2327 | defer self.base.allocator.free(buf); | |
| 2328 | ||
| 2329 | for (buf) |*sym, i| { | |
| 2330 | sym.* = .{ | |
| 2331 | .st_name = self.global_symbols.items[i].st_name, | |
| 2332 | .st_value = self.global_symbols.items[i].st_value, | |
| 2333 | .st_size = self.global_symbols.items[i].st_size, | |
| 2334 | .st_info = self.global_symbols.items[i].st_info, | |
| 2335 | .st_other = self.global_symbols.items[i].st_other, | |
| 2336 | .st_shndx = self.global_symbols.items[i].st_shndx, | |
| 2337 | }; | |
| 2338 | if (foreign_endian) { | |
| 2339 | bswapAllFields(elf.Elf64_Sym, sym); | |
| 2340 | } | |
| 2341 | } | |
| 2342 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); | |
| 2343 | }, | |
| 2344 | } | |
| 2345 | } | |
| 2346 | ||
| 2347 | fn ptrWidthBytes(self: Elf) u8 { | |
| 2348 | return switch (self.ptr_width) { | |
| 2349 | .p32 => 4, | |
| 2350 | .p64 => 8, | |
| 2351 | }; | |
| 2352 | } | |
| 2353 | ||
| 2354 | /// The reloc offset for the virtual address of a function in its Line Number Program. | |
| 2355 | /// Size is a virtual address integer. | |
| 2356 | const dbg_line_vaddr_reloc_index = 3; | |
| 2357 | /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. | |
| 2358 | /// Size is a virtual address integer. | |
| 2359 | const dbg_info_low_pc_reloc_index = 1; | |
| 2360 | ||
| 2361 | /// The reloc offset for the line offset of a function from the previous function's line. | |
| 2362 | /// It's a fixed-size 4-byte ULEB128. | |
| 2363 | fn getRelocDbgLineOff(self: Elf) usize { | |
| 2364 | return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; | |
| 2365 | } | |
| 2366 | ||
| 2367 | fn getRelocDbgFileIndex(self: Elf) usize { | |
| 2368 | return self.getRelocDbgLineOff() + 5; | |
| 2369 | } | |
| 2370 | ||
| 2371 | fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 { | |
| 2372 | return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); | |
| 2373 | } | |
| 2374 | ||
| 2375 | fn dbgLineNeededHeaderBytes(self: Elf) u32 { | |
| 2376 | const directory_entry_format_count = 1; | |
| 2377 | const file_name_entry_format_count = 1; | |
| 2378 | const directory_count = 1; | |
| 2379 | const file_name_count = 1; | |
| 2380 | return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + | |
| 2381 | directory_count * 8 + file_name_count * 8 + | |
| 2382 | // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like | |
| 2383 | // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. | |
| 2384 | self.base.options.root_pkg.root_src_dir_path.len + | |
| 2385 | self.base.options.root_pkg.root_src_path.len); | |
| 2386 | } | |
| 2387 | ||
| 2388 | fn dbgInfoNeededHeaderBytes(self: Elf) u32 { | |
| 2389 | return 120; | |
| 2390 | } | |
| 2391 | ||
| 2392 | const min_nop_size = 2; | |
| 2393 | ||
| 2394 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | |
| 2395 | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes | |
| 2396 | /// are less than 126,976 bytes (if this limit is ever reached, this function can be | |
| 2397 | /// improved to make more than one pwritev call, or the limit can be raised by a fixed | |
| 2398 | /// amount by increasing the length of `vecs`). | |
| 2399 | fn pwriteDbgLineNops( | |
| 2400 | self: *Elf, | |
| 2401 | prev_padding_size: usize, | |
| 2402 | buf: []const u8, | |
| 2403 | next_padding_size: usize, | |
| 2404 | offset: usize, | |
| 2405 | ) !void { | |
| 2406 | const tracy = trace(@src()); | |
| 2407 | defer tracy.end(); | |
| 2408 | ||
| 2409 | const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; | |
| 2410 | const three_byte_nop = [3]u8{ DW.LNS_advance_pc, 0b1000_0000, 0 }; | |
| 2411 | var vecs: [32]std.os.iovec_const = undefined; | |
| 2412 | var vec_index: usize = 0; | |
| 2413 | { | |
| 2414 | var padding_left = prev_padding_size; | |
| 2415 | if (padding_left % 2 != 0) { | |
| 2416 | vecs[vec_index] = .{ | |
| 2417 | .iov_base = &three_byte_nop, | |
| 2418 | .iov_len = three_byte_nop.len, | |
| 2419 | }; | |
| 2420 | vec_index += 1; | |
| 2421 | padding_left -= three_byte_nop.len; | |
| 2422 | } | |
| 2423 | while (padding_left > page_of_nops.len) { | |
| 2424 | vecs[vec_index] = .{ | |
| 2425 | .iov_base = &page_of_nops, | |
| 2426 | .iov_len = page_of_nops.len, | |
| 2427 | }; | |
| 2428 | vec_index += 1; | |
| 2429 | padding_left -= page_of_nops.len; | |
| 2430 | } | |
| 2431 | if (padding_left > 0) { | |
| 2432 | vecs[vec_index] = .{ | |
| 2433 | .iov_base = &page_of_nops, | |
| 2434 | .iov_len = padding_left, | |
| 2435 | }; | |
| 2436 | vec_index += 1; | |
| 2437 | } | |
| 2438 | } | |
| 2439 | ||
| 2440 | vecs[vec_index] = .{ | |
| 2441 | .iov_base = buf.ptr, | |
| 2442 | .iov_len = buf.len, | |
| 2443 | }; | |
| 2444 | vec_index += 1; | |
| 2445 | ||
| 2446 | { | |
| 2447 | var padding_left = next_padding_size; | |
| 2448 | if (padding_left % 2 != 0) { | |
| 2449 | vecs[vec_index] = .{ | |
| 2450 | .iov_base = &three_byte_nop, | |
| 2451 | .iov_len = three_byte_nop.len, | |
| 2452 | }; | |
| 2453 | vec_index += 1; | |
| 2454 | padding_left -= three_byte_nop.len; | |
| 2455 | } | |
| 2456 | while (padding_left > page_of_nops.len) { | |
| 2457 | vecs[vec_index] = .{ | |
| 2458 | .iov_base = &page_of_nops, | |
| 2459 | .iov_len = page_of_nops.len, | |
| 2460 | }; | |
| 2461 | vec_index += 1; | |
| 2462 | padding_left -= page_of_nops.len; | |
| 2463 | } | |
| 2464 | if (padding_left > 0) { | |
| 2465 | vecs[vec_index] = .{ | |
| 2466 | .iov_base = &page_of_nops, | |
| 2467 | .iov_len = padding_left, | |
| 2468 | }; | |
| 2469 | vec_index += 1; | |
| 2470 | } | |
| 2471 | } | |
| 2472 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | |
| 2473 | } | |
| 2474 | ||
| 2475 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | |
| 2476 | /// bytes of padding. | |
| 2477 | fn pwriteDbgInfoNops( | |
| 2478 | self: *Elf, | |
| 2479 | prev_padding_size: usize, | |
| 2480 | buf: []const u8, | |
| 2481 | next_padding_size: usize, | |
| 2482 | trailing_zero: bool, | |
| 2483 | offset: usize, | |
| 2484 | ) !void { | |
| 2485 | const tracy = trace(@src()); | |
| 2486 | defer tracy.end(); | |
| 2487 | ||
| 2488 | const page_of_nops = [1]u8{abbrev_pad1} ** 4096; | |
| 2489 | var vecs: [32]std.os.iovec_const = undefined; | |
| 2490 | var vec_index: usize = 0; | |
| 2491 | { | |
| 2492 | var padding_left = prev_padding_size; | |
| 2493 | while (padding_left > page_of_nops.len) { | |
| 2494 | vecs[vec_index] = .{ | |
| 2495 | .iov_base = &page_of_nops, | |
| 2496 | .iov_len = page_of_nops.len, | |
| 2497 | }; | |
| 2498 | vec_index += 1; | |
| 2499 | padding_left -= page_of_nops.len; | |
| 2500 | } | |
| 2501 | if (padding_left > 0) { | |
| 2502 | vecs[vec_index] = .{ | |
| 2503 | .iov_base = &page_of_nops, | |
| 2504 | .iov_len = padding_left, | |
| 2505 | }; | |
| 2506 | vec_index += 1; | |
| 2507 | } | |
| 2508 | } | |
| 2509 | ||
| 2510 | vecs[vec_index] = .{ | |
| 2511 | .iov_base = buf.ptr, | |
| 2512 | .iov_len = buf.len, | |
| 2513 | }; | |
| 2514 | vec_index += 1; | |
| 2515 | ||
| 2516 | { | |
| 2517 | var padding_left = next_padding_size; | |
| 2518 | while (padding_left > page_of_nops.len) { | |
| 2519 | vecs[vec_index] = .{ | |
| 2520 | .iov_base = &page_of_nops, | |
| 2521 | .iov_len = page_of_nops.len, | |
| 2522 | }; | |
| 2523 | vec_index += 1; | |
| 2524 | padding_left -= page_of_nops.len; | |
| 2525 | } | |
| 2526 | if (padding_left > 0) { | |
| 2527 | vecs[vec_index] = .{ | |
| 2528 | .iov_base = &page_of_nops, | |
| 2529 | .iov_len = padding_left, | |
| 2530 | }; | |
| 2531 | vec_index += 1; | |
| 2532 | } | |
| 2533 | } | |
| 2534 | ||
| 2535 | if (trailing_zero) { | |
| 2536 | var zbuf = [1]u8{0}; | |
| 2537 | vecs[vec_index] = .{ | |
| 2538 | .iov_base = &zbuf, | |
| 2539 | .iov_len = zbuf.len, | |
| 2540 | }; | |
| 2541 | vec_index += 1; | |
| 2542 | } | |
| 2543 | ||
| 2544 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | |
| 2545 | } | |
| 2546 | ||
| 2547 | /// Saturating multiplication | |
| 2548 | fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | |
| 2549 | const T = @TypeOf(a, b); | |
| 2550 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | |
| 2551 | } | |
| 2552 | ||
| 2553 | fn bswapAllFields(comptime S: type, ptr: *S) void { | |
| 2554 | @panic("TODO implement bswapAllFields"); | |
| 2555 | } | |
| 2556 | ||
| 2557 | fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { | |
| 2558 | return .{ | |
| 2559 | .p_type = phdr.p_type, | |
| 2560 | .p_flags = phdr.p_flags, | |
| 2561 | .p_offset = @intCast(u32, phdr.p_offset), | |
| 2562 | .p_vaddr = @intCast(u32, phdr.p_vaddr), | |
| 2563 | .p_paddr = @intCast(u32, phdr.p_paddr), | |
| 2564 | .p_filesz = @intCast(u32, phdr.p_filesz), | |
| 2565 | .p_memsz = @intCast(u32, phdr.p_memsz), | |
| 2566 | .p_align = @intCast(u32, phdr.p_align), | |
| 2567 | }; | |
| 2568 | } | |
| 2569 | ||
| 2570 | fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { | |
| 2571 | return .{ | |
| 2572 | .sh_name = shdr.sh_name, | |
| 2573 | .sh_type = shdr.sh_type, | |
| 2574 | .sh_flags = @intCast(u32, shdr.sh_flags), | |
| 2575 | .sh_addr = @intCast(u32, shdr.sh_addr), | |
| 2576 | .sh_offset = @intCast(u32, shdr.sh_offset), | |
| 2577 | .sh_size = @intCast(u32, shdr.sh_size), | |
| 2578 | .sh_link = shdr.sh_link, | |
| 2579 | .sh_info = shdr.sh_info, | |
| 2580 | .sh_addralign = @intCast(u32, shdr.sh_addralign), | |
| 2581 | .sh_entsize = @intCast(u32, shdr.sh_entsize), | |
| 2582 | }; | |
| 2583 | } |
src-self-hosted/link/MachO.zig+128-5| ... | ... | @@ -4,15 +4,29 @@ const std = @import("std"); |
| 4 | 4 | const Allocator = std.mem.Allocator; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const fs = std.fs; |
| 7 | const log = std.log.scoped(.link); | |
| 8 | const macho = std.macho; | |
| 9 | const math = std.math; | |
| 10 | const mem = std.mem; | |
| 7 | 11 | |
| 8 | 12 | const Module = @import("../Module.zig"); |
| 9 | 13 | const link = @import("../link.zig"); |
| 10 | 14 | const File = link.File; |
| 11 | 15 | |
| 12 | pub const base_tag: Tag = File.Tag.macho; | |
| 16 | pub const base_tag: File.Tag = File.Tag.macho; | |
| 13 | 17 | |
| 14 | 18 | base: File, |
| 15 | 19 | |
| 20 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 21 | /// Same order as in the file. | |
| 22 | segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){}, | |
| 23 | ||
| 24 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | |
| 25 | /// Same order as in the file. | |
| 26 | sections: std.ArrayListUnmanaged(macho.section_64) = std.ArrayListUnmanaged(macho.section_64){}, | |
| 27 | ||
| 28 | entry_addr: ?u64 = null, | |
| 29 | ||
| 16 | 30 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 17 | 31 | |
| 18 | 32 | pub const TextBlock = struct { |
| ... | ... | @@ -67,15 +81,120 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO |
| 67 | 81 | /// Returns an error if `file` is not already open with +read +write +seek abilities. |
| 68 | 82 | fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO { |
| 69 | 83 | switch (options.output_mode) { |
| 70 | .Exe => return error.TODOImplementWritingMachOExeFiles, | |
| 71 | .Obj => return error.TODOImplementWritingMachOObjFiles, | |
| 84 | .Exe => {}, | |
| 85 | .Obj => {}, | |
| 72 | 86 | .Lib => return error.TODOImplementWritingLibFiles, |
| 73 | 87 | } |
| 88 | ||
| 89 | var self: MachO = .{ | |
| 90 | .base = .{ | |
| 91 | .file = file, | |
| 92 | .tag = .macho, | |
| 93 | .options = options, | |
| 94 | .allocator = allocator, | |
| 95 | }, | |
| 96 | }; | |
| 97 | errdefer self.deinit(); | |
| 98 | ||
| 99 | if (options.output_mode == .Exe) { | |
| 100 | // The first segment command for executables is always a __PAGEZERO segment. | |
| 101 | try self.segment_cmds.append(allocator, .{ | |
| 102 | .cmd = macho.LC_SEGMENT_64, | |
| 103 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 104 | .segname = self.makeString("__PAGEZERO"), | |
| 105 | .vmaddr = 0, | |
| 106 | .vmsize = 0, | |
| 107 | .fileoff = 0, | |
| 108 | .filesize = 0, | |
| 109 | .maxprot = 0, | |
| 110 | .initprot = 0, | |
| 111 | .nsects = 0, | |
| 112 | .flags = 0, | |
| 113 | }); | |
| 114 | } | |
| 115 | ||
| 116 | return self; | |
| 117 | } | |
| 118 | ||
| 119 | fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 { | |
| 120 | var buf: [16]u8 = undefined; | |
| 121 | if (bytes.len > buf.len) @compileError("MachO segment/section name too long"); | |
| 122 | mem.copy(u8, buf[0..], bytes); | |
| 123 | return buf; | |
| 124 | } | |
| 125 | ||
| 126 | fn writeMachOHeader(self: *MachO) !void { | |
| 127 | var hdr: macho.mach_header_64 = undefined; | |
| 128 | hdr.magic = macho.MH_MAGIC_64; | |
| 129 | ||
| 130 | const CpuInfo = struct { | |
| 131 | cpu_type: macho.cpu_type_t, | |
| 132 | cpu_subtype: macho.cpu_subtype_t, | |
| 133 | }; | |
| 134 | ||
| 135 | const cpu_info: CpuInfo = switch (self.base.options.target.cpu.arch) { | |
| 136 | .aarch64 => .{ | |
| 137 | .cpu_type = macho.CPU_TYPE_ARM64, | |
| 138 | .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL, | |
| 139 | }, | |
| 140 | .x86_64 => .{ | |
| 141 | .cpu_type = macho.CPU_TYPE_X86_64, | |
| 142 | .cpu_subtype = macho.CPU_SUBTYPE_X86_64_ALL, | |
| 143 | }, | |
| 144 | else => return error.UnsupportedMachOArchitecture, | |
| 145 | }; | |
| 146 | hdr.cputype = cpu_info.cpu_type; | |
| 147 | hdr.cpusubtype = cpu_info.cpu_subtype; | |
| 148 | ||
| 149 | const filetype: u32 = switch (self.base.options.output_mode) { | |
| 150 | .Exe => macho.MH_EXECUTE, | |
| 151 | .Obj => macho.MH_OBJECT, | |
| 152 | .Lib => switch (self.base.options.link_mode) { | |
| 153 | .Static => return error.TODOStaticLibMachOType, | |
| 154 | .Dynamic => macho.MH_DYLIB, | |
| 155 | }, | |
| 156 | }; | |
| 157 | hdr.filetype = filetype; | |
| 158 | ||
| 159 | // TODO consider other commands | |
| 160 | const ncmds = try math.cast(u32, self.segment_cmds.items.len); | |
| 161 | hdr.ncmds = ncmds; | |
| 162 | hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64); | |
| 163 | ||
| 164 | // TODO should these be set to something else? | |
| 165 | hdr.flags = 0; | |
| 166 | hdr.reserved = 0; | |
| 167 | ||
| 168 | try self.base.file.?.pwriteAll(@ptrCast([*]const u8, &hdr)[0..@sizeOf(macho.mach_header_64)], 0); | |
| 74 | 169 | } |
| 75 | 170 | |
| 76 | pub fn flush(self: *MachO, module: *Module) !void {} | |
| 171 | pub fn flush(self: *MachO, module: *Module) !void { | |
| 172 | // TODO implement flush | |
| 173 | { | |
| 174 | const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len); | |
| 175 | defer self.base.allocator.free(buf); | |
| 176 | ||
| 177 | for (buf) |*seg, i| { | |
| 178 | seg.* = self.segment_cmds.items[i]; | |
| 179 | } | |
| 180 | ||
| 181 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64)); | |
| 182 | } | |
| 183 | ||
| 184 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | |
| 185 | log.debug("flushing. no_entry_point_found = true\n", .{}); | |
| 186 | self.error_flags.no_entry_point_found = true; | |
| 187 | } else { | |
| 188 | log.debug("flushing. no_entry_point_found = false\n", .{}); | |
| 189 | self.error_flags.no_entry_point_found = false; | |
| 190 | try self.writeMachOHeader(); | |
| 191 | } | |
| 192 | } | |
| 77 | 193 | |
| 78 | pub fn deinit(self: *MachO) void {} | |
| 194 | pub fn deinit(self: *MachO) void { | |
| 195 | self.segment_cmds.deinit(self.base.allocator); | |
| 196 | self.sections.deinit(self.base.allocator); | |
| 197 | } | |
| 79 | 198 | |
| 80 | 199 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} |
| 81 | 200 | |
| ... | ... | @@ -91,3 +210,7 @@ pub fn updateDeclExports( |
| 91 | 210 | ) !void {} |
| 92 | 211 | |
| 93 | 212 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| 213 | ||
| 214 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | |
| 215 | @panic("TODO implement getDeclVAddr for MachO"); | |
| 216 | } |
src-self-hosted/link/Wasm.zig+158-360| ... | ... | @@ -32,19 +32,22 @@ const spec = struct { |
| 32 | 32 | pub const base_tag = link.File.Tag.wasm; |
| 33 | 33 | |
| 34 | 34 | pub const FnData = struct { |
| 35 | funcidx: u32, | |
| 35 | /// Generated code for the type of the function | |
| 36 | functype: std.ArrayListUnmanaged(u8) = .{}, | |
| 37 | /// Generated code for the body of the function | |
| 38 | code: std.ArrayListUnmanaged(u8) = .{}, | |
| 39 | /// Locations in the generated code where function indexes must be filled in. | |
| 40 | /// This must be kept ordered by offset. | |
| 41 | idx_refs: std.ArrayListUnmanaged(struct { offset: u32, decl: *Module.Decl }) = .{}, | |
| 36 | 42 | }; |
| 37 | 43 | |
| 38 | 44 | base: link.File, |
| 39 | 45 | |
| 40 | types: Types, | |
| 41 | funcs: Funcs, | |
| 42 | exports: Exports, | |
| 43 | ||
| 44 | /// Array over the section structs used in the various sections above to | |
| 45 | /// allow iteration when shifting sections to make space. | |
| 46 | /// TODO: this should eventually be size 11 when we use all the sections. | |
| 47 | sections: [4]*Section, | |
| 46 | /// List of all function Decls to be written to the output file. The index of | |
| 47 | /// each Decl in this list at the time of writing the binary is used as the | |
| 48 | /// function index. | |
| 49 | /// TODO: can/should we access some data structure in Module directly? | |
| 50 | funcs: std.ArrayListUnmanaged(*Module.Decl) = .{}, | |
| 48 | 51 | |
| 49 | 52 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File { |
| 50 | 53 | assert(options.object_format == .wasm); |
| ... | ... | @@ -58,10 +61,6 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option |
| 58 | 61 | |
| 59 | 62 | try file.writeAll(&(spec.magic ++ spec.version)); |
| 60 | 63 | |
| 61 | // TODO: this should vary depending on the section and be less arbitrary | |
| 62 | const size = 1024; | |
| 63 | const offset = @sizeOf(@TypeOf(spec.magic ++ spec.version)); | |
| 64 | ||
| 65 | 64 | wasm.* = .{ |
| 66 | 65 | .base = .{ |
| 67 | 66 | .tag = .wasm, |
| ... | ... | @@ -69,52 +68,42 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option |
| 69 | 68 | .file = file, |
| 70 | 69 | .allocator = allocator, |
| 71 | 70 | }, |
| 72 | ||
| 73 | .types = try Types.init(file, offset, size), | |
| 74 | .funcs = try Funcs.init(file, offset + size, size, offset + 3 * size, size), | |
| 75 | .exports = try Exports.init(file, offset + 2 * size, size), | |
| 76 | ||
| 77 | // These must be ordered as they will appear in the output file | |
| 78 | .sections = [_]*Section{ | |
| 79 | &wasm.types.typesec.section, | |
| 80 | &wasm.funcs.funcsec, | |
| 81 | &wasm.exports.exportsec, | |
| 82 | &wasm.funcs.codesec.section, | |
| 83 | }, | |
| 84 | 71 | }; |
| 85 | 72 | |
| 86 | try file.setEndPos(offset + 4 * size); | |
| 87 | ||
| 88 | 73 | return &wasm.base; |
| 89 | 74 | } |
| 90 | 75 | |
| 91 | 76 | pub fn deinit(self: *Wasm) void { |
| 92 | self.types.deinit(); | |
| 93 | self.funcs.deinit(); | |
| 77 | for (self.funcs.items) |decl| { | |
| 78 | decl.fn_link.wasm.?.functype.deinit(self.base.allocator); | |
| 79 | decl.fn_link.wasm.?.code.deinit(self.base.allocator); | |
| 80 | decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator); | |
| 81 | } | |
| 82 | self.funcs.deinit(self.base.allocator); | |
| 94 | 83 | } |
| 95 | 84 | |
| 85 | // Generate code for the Decl, storing it in memory to be later written to | |
| 86 | // the file on flush(). | |
| 96 | 87 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 97 | 88 | if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn) |
| 98 | 89 | return error.TODOImplementNonFnDeclsForWasm; |
| 99 | 90 | |
| 100 | if (decl.fn_link.wasm) |fn_data| { | |
| 101 | self.funcs.free(fn_data.funcidx); | |
| 102 | } | |
| 103 | ||
| 104 | var buf = std.ArrayList(u8).init(self.base.allocator); | |
| 105 | defer buf.deinit(); | |
| 106 | ||
| 107 | try codegen.genFunctype(&buf, decl); | |
| 108 | const typeidx = try self.types.new(buf.items); | |
| 109 | buf.items.len = 0; | |
| 110 | ||
| 111 | try codegen.genCode(&buf, decl); | |
| 112 | const funcidx = try self.funcs.new(typeidx, buf.items); | |
| 113 | ||
| 114 | decl.fn_link.wasm = .{ .funcidx = funcidx }; | |
| 115 | ||
| 116 | // TODO: we should be more smart and set this only when needed | |
| 117 | self.exports.dirty = true; | |
| 91 | if (decl.fn_link.wasm) |*fn_data| { | |
| 92 | fn_data.functype.items.len = 0; | |
| 93 | fn_data.code.items.len = 0; | |
| 94 | fn_data.idx_refs.items.len = 0; | |
| 95 | } else { | |
| 96 | decl.fn_link.wasm = .{}; | |
| 97 | try self.funcs.append(self.base.allocator, decl); | |
| 98 | } | |
| 99 | const fn_data = &decl.fn_link.wasm.?; | |
| 100 | ||
| 101 | var managed_functype = fn_data.functype.toManaged(self.base.allocator); | |
| 102 | var managed_code = fn_data.code.toManaged(self.base.allocator); | |
| 103 | try codegen.genFunctype(&managed_functype, decl); | |
| 104 | try codegen.genCode(&managed_code, decl); | |
| 105 | fn_data.functype = managed_functype.toUnmanaged(); | |
| 106 | fn_data.code = managed_code.toUnmanaged(); | |
| 118 | 107 | } |
| 119 | 108 | |
| 120 | 109 | pub fn updateDeclExports( |
| ... | ... | @@ -122,332 +111,141 @@ pub fn updateDeclExports( |
| 122 | 111 | module: *Module, |
| 123 | 112 | decl: *const Module.Decl, |
| 124 | 113 | exports: []const *Module.Export, |
| 125 | ) !void { | |
| 126 | self.exports.dirty = true; | |
| 127 | } | |
| 114 | ) !void {} | |
| 128 | 115 | |
| 129 | 116 | pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 130 | 117 | // TODO: remove this assert when non-function Decls are implemented |
| 131 | 118 | assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn); |
| 132 | if (decl.fn_link.wasm) |fn_data| { | |
| 133 | self.funcs.free(fn_data.funcidx); | |
| 134 | decl.fn_link.wasm = null; | |
| 135 | } | |
| 119 | _ = self.funcs.swapRemove(self.getFuncidx(decl).?); | |
| 120 | decl.fn_link.wasm.?.functype.deinit(self.base.allocator); | |
| 121 | decl.fn_link.wasm.?.code.deinit(self.base.allocator); | |
| 122 | decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator); | |
| 123 | decl.fn_link.wasm = null; | |
| 136 | 124 | } |
| 137 | 125 | |
| 138 | 126 | pub fn flush(self: *Wasm, module: *Module) !void { |
| 139 | if (self.exports.dirty) try self.exports.writeAll(module); | |
| 140 | } | |
| 141 | ||
| 142 | /// This struct describes the location of a named section + custom section | |
| 143 | /// padding in the output file. This is all the data we need to allow for | |
| 144 | /// shifting sections around when padding runs out. | |
| 145 | const Section = struct { | |
| 146 | /// The size of a section header: 1 byte section id + 5 bytes | |
| 147 | /// for the fixed-width ULEB128 encoded contents size. | |
| 148 | const header_size = 1 + 5; | |
| 149 | /// Offset of the section id byte from the start of the file. | |
| 150 | offset: u64, | |
| 151 | /// Size of the section, including the header and directly | |
| 152 | /// following custom section used for padding if any. | |
| 153 | size: u64, | |
| 154 | ||
| 155 | /// Resize the usable part of the section, handling the following custom | |
| 156 | /// section used for padding. If there is not enough padding left, shift | |
| 157 | /// all following sections to make space. Takes the current and target | |
| 158 | /// contents sizes of the section as arguments. | |
| 159 | fn resize(self: *Section, file: fs.File, current: u32, target: u32) !void { | |
| 160 | // Section header + target contents size + custom section header | |
| 161 | // + custom section name + empty custom section > owned chunk of the file | |
| 162 | if (header_size + target + header_size + 1 + 0 > self.size) | |
| 163 | return error.TODOImplementSectionShifting; | |
| 164 | ||
| 165 | const new_custom_start = self.offset + header_size + target; | |
| 166 | const new_custom_contents_size = self.size - target - 2 * header_size; | |
| 167 | assert(new_custom_contents_size >= 1); | |
| 168 | // +1 for the name of the custom section, which we set to an empty string | |
| 169 | var custom_header: [header_size + 1]u8 = undefined; | |
| 170 | custom_header[0] = spec.custom_id; | |
| 171 | leb.writeUnsignedFixed(5, custom_header[1..header_size], @intCast(u32, new_custom_contents_size)); | |
| 172 | custom_header[header_size] = 0; | |
| 173 | try file.pwriteAll(&custom_header, new_custom_start); | |
| 174 | } | |
| 175 | }; | |
| 176 | ||
| 177 | /// This can be used to manage the contents of any section which uses a vector | |
| 178 | /// of contents. This interface maintains index stability while allowing for | |
| 179 | /// reuse of "dead" indexes. | |
| 180 | const VecSection = struct { | |
| 181 | /// Represents a single entry in the vector (e.g. a type in the type section) | |
| 182 | const Entry = struct { | |
| 183 | /// Offset from the start of the section contents in bytes | |
| 184 | offset: u32, | |
| 185 | /// Size in bytes of the entry | |
| 186 | size: u32, | |
| 187 | }; | |
| 188 | section: Section, | |
| 189 | /// Size in bytes of the contents of the section. Does not include | |
| 190 | /// the "header" containing the section id and this value. | |
| 191 | contents_size: u32, | |
| 192 | /// List of all entries in the contents of the section. | |
| 193 | entries: std.ArrayListUnmanaged(Entry) = std.ArrayListUnmanaged(Entry){}, | |
| 194 | /// List of indexes of unreferenced entries which may be | |
| 195 | /// overwritten and reused. | |
| 196 | dead_list: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){}, | |
| 197 | ||
| 198 | /// Write the headers of the section and custom padding section | |
| 199 | fn init(comptime section_id: u8, file: fs.File, offset: u64, initial_size: u64) !VecSection { | |
| 200 | // section id, section size, empty vector, custom section id, | |
| 201 | // custom section size, empty custom section name | |
| 202 | var initial_data: [1 + 5 + 5 + 1 + 5 + 1]u8 = undefined; | |
| 203 | ||
| 204 | assert(initial_size >= initial_data.len); | |
| 205 | ||
| 206 | comptime var i = 0; | |
| 207 | initial_data[i] = section_id; | |
| 208 | i += 1; | |
| 209 | leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 5); | |
| 210 | i += 5; | |
| 211 | leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 0); | |
| 212 | i += 5; | |
| 213 | initial_data[i] = spec.custom_id; | |
| 214 | i += 1; | |
| 215 | leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], @intCast(u32, initial_size - @sizeOf(@TypeOf(initial_data)))); | |
| 216 | i += 5; | |
| 217 | initial_data[i] = 0; | |
| 218 | ||
| 219 | try file.pwriteAll(&initial_data, offset); | |
| 220 | ||
| 221 | return VecSection{ | |
| 222 | .section = .{ | |
| 223 | .offset = offset, | |
| 224 | .size = initial_size, | |
| 225 | }, | |
| 226 | .contents_size = 5, | |
| 227 | }; | |
| 228 | } | |
| 229 | ||
| 230 | fn deinit(self: *VecSection, allocator: *Allocator) void { | |
| 231 | self.entries.deinit(allocator); | |
| 232 | self.dead_list.deinit(allocator); | |
| 233 | } | |
| 234 | ||
| 235 | /// Write a new entry into the file, returning the index used. | |
| 236 | fn addEntry(self: *VecSection, file: fs.File, allocator: *Allocator, data: []const u8) !u32 { | |
| 237 | // First look for a dead entry we can reuse | |
| 238 | for (self.dead_list.items) |dead_idx, i| { | |
| 239 | const dead_entry = &self.entries.items[dead_idx]; | |
| 240 | if (dead_entry.size == data.len) { | |
| 241 | // Found a dead entry of the right length, overwrite it | |
| 242 | try file.pwriteAll(data, self.section.offset + Section.header_size + dead_entry.offset); | |
| 243 | _ = self.dead_list.swapRemove(i); | |
| 244 | return dead_idx; | |
| 245 | } | |
| 127 | const file = self.base.file.?; | |
| 128 | const header_size = 5 + 1; | |
| 129 | ||
| 130 | // No need to rewrite the magic/version header | |
| 131 | try file.setEndPos(@sizeOf(@TypeOf(spec.magic ++ spec.version))); | |
| 132 | try file.seekTo(@sizeOf(@TypeOf(spec.magic ++ spec.version))); | |
| 133 | ||
| 134 | // Type section | |
| 135 | { | |
| 136 | const header_offset = try reserveVecSectionHeader(file); | |
| 137 | for (self.funcs.items) |decl| { | |
| 138 | try file.writeAll(decl.fn_link.wasm.?.functype.items); | |
| 246 | 139 | } |
| 247 | ||
| 248 | // TODO: We can be more efficient if we special-case one or | |
| 249 | // more consecutive dead entries at the end of the vector. | |
| 250 | ||
| 251 | // We failed to find a dead entry to reuse, so write the new | |
| 252 | // entry to the end of the section. | |
| 253 | try self.section.resize(file, self.contents_size, self.contents_size + @intCast(u32, data.len)); | |
| 254 | try file.pwriteAll(data, self.section.offset + Section.header_size + self.contents_size); | |
| 255 | try self.entries.append(allocator, .{ | |
| 256 | .offset = self.contents_size, | |
| 257 | .size = @intCast(u32, data.len), | |
| 258 | }); | |
| 259 | self.contents_size += @intCast(u32, data.len); | |
| 260 | // Make sure the dead list always has enough space to store all free'd | |
| 261 | // entries. This makes it so that delEntry() cannot fail. | |
| 262 | // TODO: figure out a better way that doesn't waste as much memory | |
| 263 | try self.dead_list.ensureCapacity(allocator, self.entries.items.len); | |
| 264 | ||
| 265 | // Update the size in the section header and the item count of | |
| 266 | // the contents vector. | |
| 267 | var size_and_count: [10]u8 = undefined; | |
| 268 | leb.writeUnsignedFixed(5, size_and_count[0..5], self.contents_size); | |
| 269 | leb.writeUnsignedFixed(5, size_and_count[5..], @intCast(u32, self.entries.items.len)); | |
| 270 | try file.pwriteAll(&size_and_count, self.section.offset + 1); | |
| 271 | ||
| 272 | return @intCast(u32, self.entries.items.len - 1); | |
| 273 | } | |
| 274 | ||
| 275 | /// Mark the type referenced by the given index as dead. | |
| 276 | fn delEntry(self: *VecSection, index: u32) void { | |
| 277 | self.dead_list.appendAssumeCapacity(index); | |
| 278 | } | |
| 279 | }; | |
| 280 | ||
| 281 | const Types = struct { | |
| 282 | typesec: VecSection, | |
| 283 | ||
| 284 | fn init(file: fs.File, offset: u64, initial_size: u64) !Types { | |
| 285 | return Types{ .typesec = try VecSection.init(spec.types_id, file, offset, initial_size) }; | |
| 286 | } | |
| 287 | ||
| 288 | fn deinit(self: *Types) void { | |
| 289 | const wasm = @fieldParentPtr(Wasm, "types", self); | |
| 290 | self.typesec.deinit(wasm.base.allocator); | |
| 291 | } | |
| 292 | ||
| 293 | fn new(self: *Types, data: []const u8) !u32 { | |
| 294 | const wasm = @fieldParentPtr(Wasm, "types", self); | |
| 295 | return self.typesec.addEntry(wasm.base.file.?, wasm.base.allocator, data); | |
| 296 | } | |
| 297 | ||
| 298 | fn free(self: *Types, typeidx: u32) void { | |
| 299 | self.typesec.delEntry(typeidx); | |
| 300 | } | |
| 301 | }; | |
| 302 | ||
| 303 | const Funcs = struct { | |
| 304 | /// This section needs special handling to keep the indexes matching with | |
| 305 | /// the codesec, so we cant just use a VecSection. | |
| 306 | funcsec: Section, | |
| 307 | /// The typeidx stored for each function, indexed by funcidx. | |
| 308 | func_types: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){}, | |
| 309 | codesec: VecSection, | |
| 310 | ||
| 311 | fn init(file: fs.File, funcs_offset: u64, funcs_size: u64, code_offset: u64, code_size: u64) !Funcs { | |
| 312 | return Funcs{ | |
| 313 | .funcsec = (try VecSection.init(spec.funcs_id, file, funcs_offset, funcs_size)).section, | |
| 314 | .codesec = try VecSection.init(spec.code_id, file, code_offset, code_size), | |
| 315 | }; | |
| 316 | } | |
| 317 | ||
| 318 | fn deinit(self: *Funcs) void { | |
| 319 | const wasm = @fieldParentPtr(Wasm, "funcs", self); | |
| 320 | self.func_types.deinit(wasm.base.allocator); | |
| 321 | self.codesec.deinit(wasm.base.allocator); | |
| 322 | } | |
| 323 | ||
| 324 | /// Add a new function to the binary, first finding space for and writing | |
| 325 | /// the code then writing the typeidx to the corresponding index in the | |
| 326 | /// funcsec. Returns the function index used. | |
| 327 | fn new(self: *Funcs, typeidx: u32, code: []const u8) !u32 { | |
| 328 | const wasm = @fieldParentPtr(Wasm, "funcs", self); | |
| 329 | const file = wasm.base.file.?; | |
| 330 | const allocator = wasm.base.allocator; | |
| 331 | ||
| 332 | assert(self.func_types.items.len == self.codesec.entries.items.len); | |
| 333 | ||
| 334 | // TODO: consider nop-padding the code if there is a close but not perfect fit | |
| 335 | const funcidx = try self.codesec.addEntry(file, allocator, code); | |
| 336 | ||
| 337 | if (self.func_types.items.len < self.codesec.entries.items.len) { | |
| 338 | // u32 vector length + funcs_count u32s in the vector | |
| 339 | const current = 5 + @intCast(u32, self.func_types.items.len) * 5; | |
| 340 | try self.funcsec.resize(file, current, current + 5); | |
| 341 | try self.func_types.append(allocator, typeidx); | |
| 342 | ||
| 343 | // Update the size in the section header and the item count of | |
| 344 | // the contents vector. | |
| 345 | const count = @intCast(u32, self.func_types.items.len); | |
| 346 | var size_and_count: [10]u8 = undefined; | |
| 347 | leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + count * 5); | |
| 348 | leb.writeUnsignedFixed(5, size_and_count[5..], count); | |
| 349 | try file.pwriteAll(&size_and_count, self.funcsec.offset + 1); | |
| 350 | } else { | |
| 351 | // We are overwriting a dead function and may now free the type | |
| 352 | wasm.types.free(self.func_types.items[funcidx]); | |
| 353 | } | |
| 354 | ||
| 355 | assert(self.func_types.items.len == self.codesec.entries.items.len); | |
| 356 | ||
| 357 | var typeidx_leb: [5]u8 = undefined; | |
| 358 | leb.writeUnsignedFixed(5, &typeidx_leb, typeidx); | |
| 359 | try file.pwriteAll(&typeidx_leb, self.funcsec.offset + Section.header_size + 5 + funcidx * 5); | |
| 360 | ||
| 361 | return funcidx; | |
| 362 | } | |
| 363 | ||
| 364 | fn free(self: *Funcs, funcidx: u32) void { | |
| 365 | self.codesec.delEntry(funcidx); | |
| 366 | } | |
| 367 | }; | |
| 368 | ||
| 369 | /// Exports are tricky. We can't leave dead entries in the binary as they | |
| 370 | /// would obviously be visible from the execution environment. The simplest | |
| 371 | /// way to work around this is to re-emit the export section whenever | |
| 372 | /// something changes. This also makes it easier to ensure exported function | |
| 373 | /// and global indexes are updated as they change. | |
| 374 | const Exports = struct { | |
| 375 | exportsec: Section, | |
| 376 | /// Size in bytes of the contents of the section. Does not include | |
| 377 | /// the "header" containing the section id and this value. | |
| 378 | contents_size: u32, | |
| 379 | /// If this is true, then exports will be rewritten on flush() | |
| 380 | dirty: bool, | |
| 381 | ||
| 382 | fn init(file: fs.File, offset: u64, initial_size: u64) !Exports { | |
| 383 | return Exports{ | |
| 384 | .exportsec = (try VecSection.init(spec.exports_id, file, offset, initial_size)).section, | |
| 385 | .contents_size = 5, | |
| 386 | .dirty = false, | |
| 387 | }; | |
| 388 | } | |
| 389 | ||
| 390 | fn writeAll(self: *Exports, module: *Module) !void { | |
| 391 | const wasm = @fieldParentPtr(Wasm, "exports", self); | |
| 392 | const file = wasm.base.file.?; | |
| 393 | var buf: [5]u8 = undefined; | |
| 394 | ||
| 395 | // First ensure the section is the right size | |
| 396 | var export_count: u32 = 0; | |
| 397 | var new_contents_size: u32 = 5; | |
| 140 | try writeVecSectionHeader( | |
| 141 | file, | |
| 142 | header_offset, | |
| 143 | spec.types_id, | |
| 144 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | |
| 145 | @intCast(u32, self.funcs.items.len), | |
| 146 | ); | |
| 147 | } | |
| 148 | ||
| 149 | // Function section | |
| 150 | { | |
| 151 | const header_offset = try reserveVecSectionHeader(file); | |
| 152 | const writer = file.writer(); | |
| 153 | for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx)); | |
| 154 | try writeVecSectionHeader( | |
| 155 | file, | |
| 156 | header_offset, | |
| 157 | spec.funcs_id, | |
| 158 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | |
| 159 | @intCast(u32, self.funcs.items.len), | |
| 160 | ); | |
| 161 | } | |
| 162 | ||
| 163 | // Export section | |
| 164 | { | |
| 165 | const header_offset = try reserveVecSectionHeader(file); | |
| 166 | const writer = file.writer(); | |
| 167 | var count: u32 = 0; | |
| 398 | 168 | for (module.decl_exports.entries.items) |entry| { |
| 399 | for (entry.value) |e| { | |
| 400 | export_count += 1; | |
| 401 | new_contents_size += calcSize(e); | |
| 169 | for (entry.value) |exprt| { | |
| 170 | // Export name length + name | |
| 171 | try leb.writeULEB128(writer, @intCast(u32, exprt.options.name.len)); | |
| 172 | try writer.writeAll(exprt.options.name); | |
| 173 | ||
| 174 | switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) { | |
| 175 | .Fn => { | |
| 176 | // Type of the export | |
| 177 | try writer.writeByte(0x00); | |
| 178 | // Exported function index | |
| 179 | try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?); | |
| 180 | }, | |
| 181 | else => return error.TODOImplementNonFnDeclsForWasm, | |
| 182 | } | |
| 183 | ||
| 184 | count += 1; | |
| 402 | 185 | } |
| 403 | 186 | } |
| 404 | if (new_contents_size != self.contents_size) { | |
| 405 | try self.exportsec.resize(file, self.contents_size, new_contents_size); | |
| 406 | leb.writeUnsignedFixed(5, &buf, new_contents_size); | |
| 407 | try file.pwriteAll(&buf, self.exportsec.offset + 1); | |
| 408 | } | |
| 409 | ||
| 410 | try file.seekTo(self.exportsec.offset + Section.header_size); | |
| 187 | try writeVecSectionHeader( | |
| 188 | file, | |
| 189 | header_offset, | |
| 190 | spec.exports_id, | |
| 191 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | |
| 192 | count, | |
| 193 | ); | |
| 194 | } | |
| 195 | ||
| 196 | // Code section | |
| 197 | { | |
| 198 | const header_offset = try reserveVecSectionHeader(file); | |
| 411 | 199 | const writer = file.writer(); |
| 200 | for (self.funcs.items) |decl| { | |
| 201 | const fn_data = &decl.fn_link.wasm.?; | |
| 202 | ||
| 203 | // Write the already generated code to the file, inserting | |
| 204 | // function indexes where required. | |
| 205 | var current: u32 = 0; | |
| 206 | for (fn_data.idx_refs.items) |idx_ref| { | |
| 207 | try writer.writeAll(fn_data.code.items[current..idx_ref.offset]); | |
| 208 | current = idx_ref.offset; | |
| 209 | // Use a fixed width here to make calculating the code size | |
| 210 | // in codegen.wasm.genCode() simpler. | |
| 211 | var buf: [5]u8 = undefined; | |
| 212 | leb.writeUnsignedFixed(5, &buf, self.getFuncidx(idx_ref.decl).?); | |
| 213 | try writer.writeAll(&buf); | |
| 214 | } | |
| 412 | 215 | |
| 413 | // Length of the exports vec | |
| 414 | leb.writeUnsignedFixed(5, &buf, export_count); | |
| 415 | try writer.writeAll(&buf); | |
| 416 | ||
| 417 | for (module.decl_exports.entries.items) |entry| | |
| 418 | for (entry.value) |e| try writeExport(writer, e); | |
| 419 | ||
| 420 | self.dirty = false; | |
| 216 | try writer.writeAll(fn_data.code.items[current..]); | |
| 217 | } | |
| 218 | try writeVecSectionHeader( | |
| 219 | file, | |
| 220 | header_offset, | |
| 221 | spec.code_id, | |
| 222 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | |
| 223 | @intCast(u32, self.funcs.items.len), | |
| 224 | ); | |
| 421 | 225 | } |
| 226 | } | |
| 422 | 227 | |
| 423 | /// Return the total number of bytes an export will take. | |
| 424 | /// TODO: fixed-width LEB128 is currently used for simplicity, but should | |
| 425 | /// be replaced with proper variable-length LEB128 as it is inefficient. | |
| 426 | fn calcSize(e: *Module.Export) u32 { | |
| 427 | // LEB128 name length + name bytes + export type + LEB128 index | |
| 428 | return 5 + @intCast(u32, e.options.name.len) + 1 + 5; | |
| 429 | } | |
| 228 | /// Get the current index of a given Decl in the function list | |
| 229 | /// TODO: we could maintain a hash map to potentially make this | |
| 230 | fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 { | |
| 231 | return for (self.funcs.items) |func, idx| { | |
| 232 | if (func == decl) break @intCast(u32, idx); | |
| 233 | } else null; | |
| 234 | } | |
| 430 | 235 | |
| 431 | /// Write the data for a single export to the given file at a given offset. | |
| 432 | /// TODO: fixed-width LEB128 is currently used for simplicity, but should | |
| 433 | /// be replaced with proper variable-length LEB128 as it is inefficient. | |
| 434 | fn writeExport(writer: anytype, e: *Module.Export) !void { | |
| 435 | var buf: [5]u8 = undefined; | |
| 436 | ||
| 437 | // Export name length + name | |
| 438 | leb.writeUnsignedFixed(5, &buf, @intCast(u32, e.options.name.len)); | |
| 439 | try writer.writeAll(&buf); | |
| 440 | try writer.writeAll(e.options.name); | |
| 441 | ||
| 442 | switch (e.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) { | |
| 443 | .Fn => { | |
| 444 | // Type of the export | |
| 445 | try writer.writeByte(0x00); | |
| 446 | // Exported function index | |
| 447 | leb.writeUnsignedFixed(5, &buf, e.exported_decl.fn_link.wasm.?.funcidx); | |
| 448 | try writer.writeAll(&buf); | |
| 449 | }, | |
| 450 | else => return error.TODOImplementNonFnDeclsForWasm, | |
| 451 | } | |
| 452 | } | |
| 453 | }; | |
| 236 | fn reserveVecSectionHeader(file: fs.File) !u64 { | |
| 237 | // section id + fixed leb contents size + fixed leb vector length | |
| 238 | const header_size = 1 + 5 + 5; | |
| 239 | // TODO: this should be a single lseek(2) call, but fs.File does not | |
| 240 | // currently provide a way to do this. | |
| 241 | try file.seekBy(header_size); | |
| 242 | return (try file.getPos()) - header_size; | |
| 243 | } | |
| 244 | ||
| 245 | fn writeVecSectionHeader(file: fs.File, offset: u64, section: u8, size: u32, items: u32) !void { | |
| 246 | var buf: [1 + 5 + 5]u8 = undefined; | |
| 247 | buf[0] = section; | |
| 248 | leb.writeUnsignedFixed(5, buf[1..6], size); | |
| 249 | leb.writeUnsignedFixed(5, buf[6..], items); | |
| 250 | try file.pwriteAll(&buf, offset); | |
| 251 | } |
src-self-hosted/link/cbe.h created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | #if __STDC_VERSION__ >= 201112L | |
| 2 | #define zig_noreturn _Noreturn | |
| 3 | #elif __GNUC__ | |
| 4 | #define zig_noreturn __attribute__ ((noreturn)) | |
| 5 | #elif _MSC_VER | |
| 6 | #define zig_noreturn __declspec(noreturn) | |
| 7 | #else | |
| 8 | #define zig_noreturn | |
| 9 | #endif | |
| 10 | ||
| 11 | #if __GNUC__ | |
| 12 | #define zig_unreachable() __builtin_unreachable() | |
| 13 | #else | |
| 14 | #define zig_unreachable() | |
| 15 | #endif |
src-self-hosted/main.zig+2| ... | ... | @@ -742,6 +742,7 @@ const FmtError = error{ |
| 742 | 742 | LinkQuotaExceeded, |
| 743 | 743 | FileBusy, |
| 744 | 744 | EndOfStream, |
| 745 | NotOpenForWriting, | |
| 745 | 746 | } || fs.File.OpenError; |
| 746 | 747 | |
| 747 | 748 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { |
| ... | ... | @@ -807,6 +808,7 @@ fn fmtPathFile( |
| 807 | 808 | const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) { |
| 808 | 809 | error.ConnectionResetByPeer => unreachable, |
| 809 | 810 | error.ConnectionTimedOut => unreachable, |
| 811 | error.NotOpenForReading => unreachable, | |
| 810 | 812 | else => |e| return e, |
| 811 | 813 | }; |
| 812 | 814 | source_file.close(); |
src-self-hosted/stage2.zig+4| ... | ... | @@ -153,6 +153,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { |
| 153 | 153 | const c_out_stream = std.io.cOutStream(output_file); |
| 154 | 154 | _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { |
| 155 | 155 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode |
| 156 | error.NotOpenForWriting => unreachable, | |
| 156 | 157 | error.SystemResources => return .SystemResources, |
| 157 | 158 | error.OperationAborted => return .OperationAborted, |
| 158 | 159 | error.BrokenPipe => return .BrokenPipe, |
| ... | ... | @@ -611,6 +612,8 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ |
| 611 | 612 | error.SystemResources => return .SystemResources, |
| 612 | 613 | error.OperationAborted => return .OperationAborted, |
| 613 | 614 | error.WouldBlock => unreachable, |
| 615 | error.NotOpenForWriting => unreachable, | |
| 616 | error.NotOpenForReading => unreachable, | |
| 614 | 617 | error.Unexpected => return .Unexpected, |
| 615 | 618 | error.EndOfStream => return .EndOfFile, |
| 616 | 619 | error.IsDir => return .IsDir, |
| ... | ... | @@ -666,6 +669,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: |
| 666 | 669 | const c_out_stream = std.io.cOutStream(output_file); |
| 667 | 670 | libc.render(c_out_stream) catch |err| switch (err) { |
| 668 | 671 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode |
| 672 | error.NotOpenForWriting => unreachable, | |
| 669 | 673 | error.SystemResources => return .SystemResources, |
| 670 | 674 | error.OperationAborted => return .OperationAborted, |
| 671 | 675 | error.BrokenPipe => return .BrokenPipe, |
src-self-hosted/test.zig+1-1| ... | ... | @@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine; |
| 10 | 10 | const enable_wasmtime: bool = build_options.enable_wasmtime; |
| 11 | 11 | const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir; |
| 12 | 12 | |
| 13 | const cheader = @embedFile("cbe.h"); | |
| 13 | const cheader = @embedFile("link/cbe.h"); | |
| 14 | 14 | |
| 15 | 15 | test "self-hosted" { |
| 16 | 16 | var ctx = TestContext.init(); |
src-self-hosted/translate_c.zig+41-13| ... | ... | @@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 498 | 498 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 499 | 499 | }, |
| 500 | 500 | .Var => { |
| 501 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); | |
| 501 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null); | |
| 502 | 502 | }, |
| 503 | 503 | .Empty => { |
| 504 | 504 | // Do nothing |
| ... | ... | @@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 679 | 679 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 680 | 680 | } |
| 681 | 681 | |
| 682 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | |
| 683 | const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); | |
| 682 | /// if mangled_name is not null, this var decl was declared in a block scope. | |
| 683 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void { | |
| 684 | const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); | |
| 684 | 685 | if (c.global_scope.sym_table.contains(var_name)) |
| 685 | 686 | return; // Avoid processing this decl twice |
| 686 | 687 | const rp = makeRestorePoint(c); |
| 687 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 688 | const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub"); | |
| 688 | 689 | |
| 689 | 690 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) |
| 690 | 691 | null |
| ... | ... | @@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 701 | 702 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 702 | 703 | const storage_class = ZigClangVarDecl_getStorageClass(var_decl); |
| 703 | 704 | const is_const = ZigClangQualType_isConstQualified(qual_type); |
| 704 | ||
| 705 | const extern_tok = if (storage_class == .Extern) | |
| 705 | const has_init = ZigClangVarDecl_hasInit(var_decl); | |
| 706 | ||
| 707 | // In C extern variables with initializers behave like Zig exports. | |
| 708 | // extern int foo = 2; | |
| 709 | // does the same as: | |
| 710 | // extern int foo; | |
| 711 | // int foo = 2; | |
| 712 | const extern_tok = if (storage_class == .Extern and !has_init) | |
| 706 | 713 | try appendToken(c, .Keyword_extern, "extern") |
| 707 | 714 | else if (storage_class != .Static) |
| 708 | 715 | try appendToken(c, .Keyword_export, "export") |
| ... | ... | @@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 730 | 737 | // If the initialization expression is not present, initialize with undefined. |
| 731 | 738 | // If it is an integer literal, we can skip the @as since it will be redundant |
| 732 | 739 | // with the variable type. |
| 733 | if (ZigClangVarDecl_hasInit(var_decl)) { | |
| 740 | if (has_init) { | |
| 734 | 741 | eq_tok = try appendToken(c, .Equal, "="); |
| 735 | 742 | init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 736 | 743 | transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { |
| ... | ... | @@ -745,7 +752,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 745 | 752 | try transCreateNodeUndefinedLiteral(c); |
| 746 | 753 | } else if (storage_class != .Extern) { |
| 747 | 754 | eq_tok = try appendToken(c, .Equal, "="); |
| 748 | init_node = try transCreateNodeIdentifierUnchecked(c, "undefined"); | |
| 755 | // The C language specification states that variables with static or threadlocal | |
| 756 | // storage without an initializer are initialized to a zero value. | |
| 757 | ||
| 758 | // @import("std").mem.zeroes(T) | |
| 759 | const import_fn_call = try c.createBuiltinCall("@import", 1); | |
| 760 | const std_node = try transCreateNodeStringLiteral(c, "\"std\""); | |
| 761 | import_fn_call.params()[0] = std_node; | |
| 762 | import_fn_call.rparen_token = try appendToken(c, .RParen, ")"); | |
| 763 | const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem"); | |
| 764 | const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes"); | |
| 765 | ||
| 766 | const zero_init_call = try c.createCall(outer_field_access, 1); | |
| 767 | zero_init_call.params()[0] = type_node; | |
| 768 | zero_init_call.rtoken = try appendToken(c, .RParen, ")"); | |
| 769 | ||
| 770 | init_node = &zero_init_call.base; | |
| 749 | 771 | } |
| 750 | 772 | |
| 751 | 773 | const linksection_expr = blk: { |
| ... | ... | @@ -1561,15 +1583,22 @@ fn transDeclStmtOne( |
| 1561 | 1583 | .Var => { |
| 1562 | 1584 | const var_decl = @ptrCast(*const ZigClangVarDecl, decl); |
| 1563 | 1585 | |
| 1564 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) | |
| 1565 | null | |
| 1566 | else | |
| 1567 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | |
| 1568 | 1586 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 1569 | 1587 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( |
| 1570 | 1588 | @ptrCast(*const ZigClangNamedDecl, var_decl), |
| 1571 | 1589 | )); |
| 1572 | 1590 | const mangled_name = try block_scope.makeMangledName(c, name); |
| 1591 | ||
| 1592 | switch (ZigClangVarDecl_getStorageClass(var_decl)) { | |
| 1593 | .Extern, .Static => { | |
| 1594 | // This is actually a global variable, put it in the global scope and reference it. | |
| 1595 | // `_ = mangled_name;` | |
| 1596 | try visitVarDecl(rp.c, var_decl, mangled_name); | |
| 1597 | return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name)); | |
| 1598 | }, | |
| 1599 | else => {}, | |
| 1600 | } | |
| 1601 | ||
| 1573 | 1602 | const mut_tok = if (ZigClangQualType_isConstQualified(qual_type)) |
| 1574 | 1603 | try appendToken(c, .Keyword_const, "const") |
| 1575 | 1604 | else |
| ... | ... | @@ -1597,7 +1626,6 @@ fn transDeclStmtOne( |
| 1597 | 1626 | .mut_token = mut_tok, |
| 1598 | 1627 | .semicolon_token = semicolon_token, |
| 1599 | 1628 | }, .{ |
| 1600 | .thread_local_token = thread_local_token, | |
| 1601 | 1629 | .eq_token = eq_token, |
| 1602 | 1630 | .type_node = type_node, |
| 1603 | 1631 | .init_node = init_node, |
src-self-hosted/type.zig+516-55| ... | ... | @@ -65,16 +65,25 @@ pub const Type = extern union { |
| 65 | 65 | .fn_ccc_void_no_args => return .Fn, |
| 66 | 66 | .function => return .Fn, |
| 67 | 67 | |
| 68 | .array, .array_u8_sentinel_0 => return .Array, | |
| 69 | .single_const_pointer => return .Pointer, | |
| 70 | .single_mut_pointer => return .Pointer, | |
| 71 | .single_const_pointer_to_comptime_int => return .Pointer, | |
| 72 | .const_slice_u8 => return .Pointer, | |
| 68 | .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, | |
| 69 | .single_const_pointer_to_comptime_int, | |
| 70 | .const_slice_u8, | |
| 71 | .single_const_pointer, | |
| 72 | .single_mut_pointer, | |
| 73 | .many_const_pointer, | |
| 74 | .many_mut_pointer, | |
| 75 | .c_const_pointer, | |
| 76 | .c_mut_pointer, | |
| 77 | .const_slice, | |
| 78 | .mut_slice, | |
| 79 | .pointer, | |
| 80 | => return .Pointer, | |
| 73 | 81 | |
| 74 | 82 | .optional, |
| 75 | 83 | .optional_single_const_pointer, |
| 76 | 84 | .optional_single_mut_pointer, |
| 77 | 85 | => return .Optional, |
| 86 | .enum_literal => return .EnumLiteral, | |
| 78 | 87 | } |
| 79 | 88 | } |
| 80 | 89 | |
| ... | ... | @@ -107,13 +116,19 @@ pub const Type = extern union { |
| 107 | 116 | return @fieldParentPtr(T, "base", self.ptr_otherwise); |
| 108 | 117 | } |
| 109 | 118 | |
| 110 | pub fn castPointer(self: Type) ?*Payload.Pointer { | |
| 119 | pub fn castPointer(self: Type) ?*Payload.PointerSimple { | |
| 111 | 120 | return switch (self.tag()) { |
| 112 | 121 | .single_const_pointer, |
| 113 | 122 | .single_mut_pointer, |
| 123 | .many_const_pointer, | |
| 124 | .many_mut_pointer, | |
| 125 | .c_const_pointer, | |
| 126 | .c_mut_pointer, | |
| 127 | .const_slice, | |
| 128 | .mut_slice, | |
| 114 | 129 | .optional_single_const_pointer, |
| 115 | 130 | .optional_single_mut_pointer, |
| 116 | => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise), | |
| 131 | => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), | |
| 117 | 132 | else => null, |
| 118 | 133 | }; |
| 119 | 134 | } |
| ... | ... | @@ -127,6 +142,7 @@ pub const Type = extern union { |
| 127 | 142 | if (zig_tag_a != zig_tag_b) |
| 128 | 143 | return false; |
| 129 | 144 | switch (zig_tag_a) { |
| 145 | .EnumLiteral => return true, | |
| 130 | 146 | .Type => return true, |
| 131 | 147 | .Void => return true, |
| 132 | 148 | .Bool => return true, |
| ... | ... | @@ -196,8 +212,8 @@ pub const Type = extern union { |
| 196 | 212 | return true; |
| 197 | 213 | }, |
| 198 | 214 | .Optional => { |
| 199 | var buf_a: Payload.Pointer = undefined; | |
| 200 | var buf_b: Payload.Pointer = undefined; | |
| 215 | var buf_a: Payload.PointerSimple = undefined; | |
| 216 | var buf_b: Payload.PointerSimple = undefined; | |
| 201 | 217 | return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); |
| 202 | 218 | }, |
| 203 | 219 | .Float, |
| ... | ... | @@ -211,7 +227,6 @@ pub const Type = extern union { |
| 211 | 227 | .Frame, |
| 212 | 228 | .AnyFrame, |
| 213 | 229 | .Vector, |
| 214 | .EnumLiteral, | |
| 215 | 230 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
| 216 | 231 | } |
| 217 | 232 | } |
| ... | ... | @@ -262,7 +277,7 @@ pub const Type = extern union { |
| 262 | 277 | } |
| 263 | 278 | }, |
| 264 | 279 | .Optional => { |
| 265 | var buf: Payload.Pointer = undefined; | |
| 280 | var buf: Payload.PointerSimple = undefined; | |
| 266 | 281 | std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); |
| 267 | 282 | }, |
| 268 | 283 | .Float, |
| ... | ... | @@ -327,9 +342,11 @@ pub const Type = extern union { |
| 327 | 342 | .fn_ccc_void_no_args, |
| 328 | 343 | .single_const_pointer_to_comptime_int, |
| 329 | 344 | .const_slice_u8, |
| 345 | .enum_literal, | |
| 330 | 346 | => unreachable, |
| 331 | 347 | |
| 332 | 348 | .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0), |
| 349 | .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8), | |
| 333 | 350 | .array => { |
| 334 | 351 | const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); |
| 335 | 352 | const new_payload = try allocator.create(Payload.Array); |
| ... | ... | @@ -340,6 +357,17 @@ pub const Type = extern union { |
| 340 | 357 | }; |
| 341 | 358 | return Type{ .ptr_otherwise = &new_payload.base }; |
| 342 | 359 | }, |
| 360 | .array_sentinel => { | |
| 361 | const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); | |
| 362 | const new_payload = try allocator.create(Payload.ArraySentinel); | |
| 363 | new_payload.* = .{ | |
| 364 | .base = payload.base, | |
| 365 | .len = payload.len, | |
| 366 | .sentinel = try payload.sentinel.copy(allocator), | |
| 367 | .elem_type = try payload.elem_type.copy(allocator), | |
| 368 | }; | |
| 369 | return Type{ .ptr_otherwise = &new_payload.base }; | |
| 370 | }, | |
| 343 | 371 | .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned), |
| 344 | 372 | .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned), |
| 345 | 373 | .function => { |
| ... | ... | @@ -360,9 +388,34 @@ pub const Type = extern union { |
| 360 | 388 | .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), |
| 361 | 389 | .single_const_pointer, |
| 362 | 390 | .single_mut_pointer, |
| 391 | .many_const_pointer, | |
| 392 | .many_mut_pointer, | |
| 393 | .c_const_pointer, | |
| 394 | .c_mut_pointer, | |
| 395 | .const_slice, | |
| 396 | .mut_slice, | |
| 363 | 397 | .optional_single_mut_pointer, |
| 364 | 398 | .optional_single_const_pointer, |
| 365 | => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"), | |
| 399 | => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), | |
| 400 | ||
| 401 | .pointer => { | |
| 402 | const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); | |
| 403 | const new_payload = try allocator.create(Payload.Pointer); | |
| 404 | new_payload.* = .{ | |
| 405 | .base = payload.base, | |
| 406 | ||
| 407 | .pointee_type = try payload.pointee_type.copy(allocator), | |
| 408 | .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, | |
| 409 | .@"align" = payload.@"align", | |
| 410 | .bit_offset = payload.bit_offset, | |
| 411 | .host_size = payload.host_size, | |
| 412 | .@"allowzero" = payload.@"allowzero", | |
| 413 | .mutable = payload.mutable, | |
| 414 | .@"volatile" = payload.@"volatile", | |
| 415 | .size = payload.size, | |
| 416 | }; | |
| 417 | return Type{ .ptr_otherwise = &new_payload.base }; | |
| 418 | }, | |
| 366 | 419 | } |
| 367 | 420 | } |
| 368 | 421 | |
| ... | ... | @@ -425,6 +478,7 @@ pub const Type = extern union { |
| 425 | 478 | .noreturn, |
| 426 | 479 | => return out_stream.writeAll(@tagName(t)), |
| 427 | 480 | |
| 481 | .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), | |
| 428 | 482 | .@"null" => return out_stream.writeAll("@TypeOf(null)"), |
| 429 | 483 | .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"), |
| 430 | 484 | |
| ... | ... | @@ -442,9 +496,14 @@ pub const Type = extern union { |
| 442 | 496 | try param_type.format("", .{}, out_stream); |
| 443 | 497 | } |
| 444 | 498 | try out_stream.writeAll(") "); |
| 445 | try payload.return_type.format("", .{}, out_stream); | |
| 499 | ty = payload.return_type; | |
| 500 | continue; | |
| 446 | 501 | }, |
| 447 | 502 | |
| 503 | .array_u8 => { | |
| 504 | const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise); | |
| 505 | return out_stream.print("[{}]u8", .{payload.len}); | |
| 506 | }, | |
| 448 | 507 | .array_u8_sentinel_0 => { |
| 449 | 508 | const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); |
| 450 | 509 | return out_stream.print("[{}:0]u8", .{payload.len}); |
| ... | ... | @@ -455,18 +514,60 @@ pub const Type = extern union { |
| 455 | 514 | ty = payload.elem_type; |
| 456 | 515 | continue; |
| 457 | 516 | }, |
| 517 | .array_sentinel => { | |
| 518 | const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise); | |
| 519 | try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel }); | |
| 520 | ty = payload.elem_type; | |
| 521 | continue; | |
| 522 | }, | |
| 458 | 523 | .single_const_pointer => { |
| 459 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 524 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 460 | 525 | try out_stream.writeAll("*const "); |
| 461 | 526 | ty = payload.pointee_type; |
| 462 | 527 | continue; |
| 463 | 528 | }, |
| 464 | 529 | .single_mut_pointer => { |
| 465 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 530 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 466 | 531 | try out_stream.writeAll("*"); |
| 467 | 532 | ty = payload.pointee_type; |
| 468 | 533 | continue; |
| 469 | 534 | }, |
| 535 | .many_const_pointer => { | |
| 536 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 537 | try out_stream.writeAll("[*]const "); | |
| 538 | ty = payload.pointee_type; | |
| 539 | continue; | |
| 540 | }, | |
| 541 | .many_mut_pointer => { | |
| 542 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 543 | try out_stream.writeAll("[*]"); | |
| 544 | ty = payload.pointee_type; | |
| 545 | continue; | |
| 546 | }, | |
| 547 | .c_const_pointer => { | |
| 548 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 549 | try out_stream.writeAll("[*c]const "); | |
| 550 | ty = payload.pointee_type; | |
| 551 | continue; | |
| 552 | }, | |
| 553 | .c_mut_pointer => { | |
| 554 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 555 | try out_stream.writeAll("[*c]"); | |
| 556 | ty = payload.pointee_type; | |
| 557 | continue; | |
| 558 | }, | |
| 559 | .const_slice => { | |
| 560 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 561 | try out_stream.writeAll("[]const "); | |
| 562 | ty = payload.pointee_type; | |
| 563 | continue; | |
| 564 | }, | |
| 565 | .mut_slice => { | |
| 566 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 567 | try out_stream.writeAll("[]"); | |
| 568 | ty = payload.pointee_type; | |
| 569 | continue; | |
| 570 | }, | |
| 470 | 571 | .int_signed => { |
| 471 | 572 | const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); |
| 472 | 573 | return out_stream.print("i{}", .{payload.bits}); |
| ... | ... | @@ -482,17 +583,45 @@ pub const Type = extern union { |
| 482 | 583 | continue; |
| 483 | 584 | }, |
| 484 | 585 | .optional_single_const_pointer => { |
| 485 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 586 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 486 | 587 | try out_stream.writeAll("?*const "); |
| 487 | 588 | ty = payload.pointee_type; |
| 488 | 589 | continue; |
| 489 | 590 | }, |
| 490 | 591 | .optional_single_mut_pointer => { |
| 491 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 592 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 492 | 593 | try out_stream.writeAll("?*"); |
| 493 | 594 | ty = payload.pointee_type; |
| 494 | 595 | continue; |
| 495 | 596 | }, |
| 597 | ||
| 598 | .pointer => { | |
| 599 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 600 | if (payload.sentinel) |some| switch (payload.size) { | |
| 601 | .One, .C => unreachable, | |
| 602 | .Many => try out_stream.writeAll("[*:{}]"), | |
| 603 | .Slice => try out_stream.writeAll("[:{}]"), | |
| 604 | } else switch (payload.size) { | |
| 605 | .One => try out_stream.writeAll("*"), | |
| 606 | .Many => try out_stream.writeAll("[*]"), | |
| 607 | .C => try out_stream.writeAll("[*c]"), | |
| 608 | .Slice => try out_stream.writeAll("[]"), | |
| 609 | } | |
| 610 | if (payload.@"align" != 0) { | |
| 611 | try out_stream.print("align({}", .{payload.@"align"}); | |
| 612 | ||
| 613 | if (payload.bit_offset != 0) { | |
| 614 | try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); | |
| 615 | } | |
| 616 | try out_stream.writeAll(") "); | |
| 617 | } | |
| 618 | if (!payload.mutable) try out_stream.writeAll("const "); | |
| 619 | if (payload.@"volatile") try out_stream.writeAll("volatile "); | |
| 620 | if (payload.@"allowzero") try out_stream.writeAll("allowzero "); | |
| 621 | ||
| 622 | ty = payload.pointee_type; | |
| 623 | continue; | |
| 624 | }, | |
| 496 | 625 | } |
| 497 | 626 | unreachable; |
| 498 | 627 | } |
| ... | ... | @@ -539,6 +668,7 @@ pub const Type = extern union { |
| 539 | 668 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), |
| 540 | 669 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), |
| 541 | 670 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 671 | .enum_literal => return Value.initTag(.enum_literal_type), | |
| 542 | 672 | else => { |
| 543 | 673 | const ty_payload = try allocator.create(Value.Payload.Ty); |
| 544 | 674 | ty_payload.* = .{ .ty = self }; |
| ... | ... | @@ -588,8 +718,8 @@ pub const Type = extern union { |
| 588 | 718 | => true, |
| 589 | 719 | // TODO lazy types |
| 590 | 720 | .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, |
| 591 | .single_const_pointer => self.elemType().hasCodeGenBits(), | |
| 592 | .single_mut_pointer => self.elemType().hasCodeGenBits(), | |
| 721 | .array_u8 => self.arrayLen() != 0, | |
| 722 | .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), | |
| 593 | 723 | .int_signed => self.cast(Payload.IntSigned).?.bits == 0, |
| 594 | 724 | .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, |
| 595 | 725 | |
| ... | ... | @@ -601,6 +731,7 @@ pub const Type = extern union { |
| 601 | 731 | .noreturn, |
| 602 | 732 | .@"null", |
| 603 | 733 | .@"undefined", |
| 734 | .enum_literal, | |
| 604 | 735 | => false, |
| 605 | 736 | }; |
| 606 | 737 | } |
| ... | ... | @@ -616,6 +747,7 @@ pub const Type = extern union { |
| 616 | 747 | .i8, |
| 617 | 748 | .bool, |
| 618 | 749 | .array_u8_sentinel_0, |
| 750 | .array_u8, | |
| 619 | 751 | => return 1, |
| 620 | 752 | |
| 621 | 753 | .fn_noreturn_no_args, // represents machine code; not a pointer |
| ... | ... | @@ -638,10 +770,23 @@ pub const Type = extern union { |
| 638 | 770 | .const_slice_u8, |
| 639 | 771 | .single_const_pointer, |
| 640 | 772 | .single_mut_pointer, |
| 773 | .many_const_pointer, | |
| 774 | .many_mut_pointer, | |
| 775 | .c_const_pointer, | |
| 776 | .c_mut_pointer, | |
| 777 | .const_slice, | |
| 778 | .mut_slice, | |
| 641 | 779 | .optional_single_const_pointer, |
| 642 | 780 | .optional_single_mut_pointer, |
| 643 | 781 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), |
| 644 | 782 | |
| 783 | .pointer => { | |
| 784 | const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); | |
| 785 | ||
| 786 | if (payload.@"align" != 0) return payload.@"align"; | |
| 787 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); | |
| 788 | }, | |
| 789 | ||
| 645 | 790 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| 646 | 791 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), |
| 647 | 792 | .c_int => return @divExact(CType.int.sizeInBits(target), 8), |
| ... | ... | @@ -659,7 +804,7 @@ pub const Type = extern union { |
| 659 | 804 | |
| 660 | 805 | .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type |
| 661 | 806 | |
| 662 | .array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target), | |
| 807 | .array, .array_sentinel => return self.elemType().abiAlignment(target), | |
| 663 | 808 | |
| 664 | 809 | .int_signed, .int_unsigned => { |
| 665 | 810 | const bits: u16 = if (self.cast(Payload.IntSigned)) |pl| |
| ... | ... | @@ -673,7 +818,7 @@ pub const Type = extern union { |
| 673 | 818 | }, |
| 674 | 819 | |
| 675 | 820 | .optional => { |
| 676 | var buf: Payload.Pointer = undefined; | |
| 821 | var buf: Payload.PointerSimple = undefined; | |
| 677 | 822 | const child_type = self.optionalChild(&buf); |
| 678 | 823 | if (!child_type.hasCodeGenBits()) return 1; |
| 679 | 824 | |
| ... | ... | @@ -691,6 +836,7 @@ pub const Type = extern union { |
| 691 | 836 | .noreturn, |
| 692 | 837 | .@"null", |
| 693 | 838 | .@"undefined", |
| 839 | .enum_literal, | |
| 694 | 840 | => unreachable, |
| 695 | 841 | }; |
| 696 | 842 | } |
| ... | ... | @@ -711,31 +857,55 @@ pub const Type = extern union { |
| 711 | 857 | .noreturn => unreachable, |
| 712 | 858 | .@"null" => unreachable, |
| 713 | 859 | .@"undefined" => unreachable, |
| 860 | .enum_literal => unreachable, | |
| 861 | .single_const_pointer_to_comptime_int => unreachable, | |
| 714 | 862 | |
| 715 | 863 | .u8, |
| 716 | 864 | .i8, |
| 717 | 865 | .bool, |
| 718 | 866 | => return 1, |
| 719 | 867 | |
| 720 | .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len, | |
| 868 | .array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len, | |
| 869 | .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1, | |
| 721 | 870 | .array => { |
| 722 | 871 | const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); |
| 723 | 872 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); |
| 724 | 873 | return payload.len * elem_size; |
| 725 | 874 | }, |
| 875 | .array_sentinel => { | |
| 876 | const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); | |
| 877 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | |
| 878 | return (payload.len + 1) * elem_size; | |
| 879 | }, | |
| 726 | 880 | .i16, .u16 => return 2, |
| 727 | 881 | .i32, .u32 => return 4, |
| 728 | 882 | .i64, .u64 => return 8, |
| 729 | 883 | |
| 730 | .isize, | |
| 731 | .usize, | |
| 732 | .single_const_pointer_to_comptime_int, | |
| 884 | .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | |
| 885 | ||
| 886 | .const_slice, | |
| 887 | .mut_slice, | |
| 733 | 888 | .const_slice_u8, |
| 734 | .single_const_pointer, | |
| 735 | .single_mut_pointer, | |
| 889 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, | |
| 890 | ||
| 736 | 891 | .optional_single_const_pointer, |
| 737 | 892 | .optional_single_mut_pointer, |
| 738 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | |
| 893 | => { | |
| 894 | if (self.elemType().hasCodeGenBits()) return 1; | |
| 895 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); | |
| 896 | }, | |
| 897 | ||
| 898 | .single_const_pointer, | |
| 899 | .single_mut_pointer, | |
| 900 | .many_const_pointer, | |
| 901 | .many_mut_pointer, | |
| 902 | .c_const_pointer, | |
| 903 | .c_mut_pointer, | |
| 904 | .pointer, | |
| 905 | => { | |
| 906 | if (self.elemType().hasCodeGenBits()) return 0; | |
| 907 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); | |
| 908 | }, | |
| 739 | 909 | |
| 740 | 910 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| 741 | 911 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), |
| ... | ... | @@ -766,7 +936,7 @@ pub const Type = extern union { |
| 766 | 936 | }, |
| 767 | 937 | |
| 768 | 938 | .optional => { |
| 769 | var buf: Payload.Pointer = undefined; | |
| 939 | var buf: Payload.PointerSimple = undefined; | |
| 770 | 940 | const child_type = self.optionalChild(&buf); |
| 771 | 941 | if (!child_type.hasCodeGenBits()) return 1; |
| 772 | 942 | |
| ... | ... | @@ -818,6 +988,8 @@ pub const Type = extern union { |
| 818 | 988 | .@"null", |
| 819 | 989 | .@"undefined", |
| 820 | 990 | .array, |
| 991 | .array_sentinel, | |
| 992 | .array_u8, | |
| 821 | 993 | .array_u8_sentinel_0, |
| 822 | 994 | .const_slice_u8, |
| 823 | 995 | .fn_noreturn_no_args, |
| ... | ... | @@ -830,12 +1002,21 @@ pub const Type = extern union { |
| 830 | 1002 | .optional, |
| 831 | 1003 | .optional_single_mut_pointer, |
| 832 | 1004 | .optional_single_const_pointer, |
| 1005 | .enum_literal, | |
| 1006 | .many_const_pointer, | |
| 1007 | .many_mut_pointer, | |
| 1008 | .c_const_pointer, | |
| 1009 | .c_mut_pointer, | |
| 1010 | .const_slice, | |
| 1011 | .mut_slice, | |
| 833 | 1012 | => false, |
| 834 | 1013 | |
| 835 | 1014 | .single_const_pointer, |
| 836 | 1015 | .single_mut_pointer, |
| 837 | 1016 | .single_const_pointer_to_comptime_int, |
| 838 | 1017 | => true, |
| 1018 | ||
| 1019 | .pointer => self.cast(Payload.Pointer).?.size == .One, | |
| 839 | 1020 | }; |
| 840 | 1021 | } |
| 841 | 1022 | |
| ... | ... | @@ -875,9 +1056,15 @@ pub const Type = extern union { |
| 875 | 1056 | .@"null", |
| 876 | 1057 | .@"undefined", |
| 877 | 1058 | .array, |
| 1059 | .array_sentinel, | |
| 1060 | .array_u8, | |
| 878 | 1061 | .array_u8_sentinel_0, |
| 879 | 1062 | .single_const_pointer, |
| 880 | 1063 | .single_mut_pointer, |
| 1064 | .many_const_pointer, | |
| 1065 | .many_mut_pointer, | |
| 1066 | .c_const_pointer, | |
| 1067 | .c_mut_pointer, | |
| 881 | 1068 | .single_const_pointer_to_comptime_int, |
| 882 | 1069 | .fn_noreturn_no_args, |
| 883 | 1070 | .fn_void_no_args, |
| ... | ... | @@ -889,9 +1076,15 @@ pub const Type = extern union { |
| 889 | 1076 | .optional, |
| 890 | 1077 | .optional_single_mut_pointer, |
| 891 | 1078 | .optional_single_const_pointer, |
| 1079 | .enum_literal, | |
| 892 | 1080 | => false, |
| 893 | 1081 | |
| 894 | .const_slice_u8 => true, | |
| 1082 | .const_slice, | |
| 1083 | .mut_slice, | |
| 1084 | .const_slice_u8, | |
| 1085 | => true, | |
| 1086 | ||
| 1087 | .pointer => self.cast(Payload.Pointer).?.size == .Slice, | |
| 895 | 1088 | }; |
| 896 | 1089 | } |
| 897 | 1090 | |
| ... | ... | @@ -931,6 +1124,8 @@ pub const Type = extern union { |
| 931 | 1124 | .@"null", |
| 932 | 1125 | .@"undefined", |
| 933 | 1126 | .array, |
| 1127 | .array_sentinel, | |
| 1128 | .array_u8, | |
| 934 | 1129 | .array_u8_sentinel_0, |
| 935 | 1130 | .fn_noreturn_no_args, |
| 936 | 1131 | .fn_void_no_args, |
| ... | ... | @@ -940,15 +1135,24 @@ pub const Type = extern union { |
| 940 | 1135 | .int_unsigned, |
| 941 | 1136 | .int_signed, |
| 942 | 1137 | .single_mut_pointer, |
| 1138 | .many_mut_pointer, | |
| 1139 | .c_mut_pointer, | |
| 943 | 1140 | .optional, |
| 944 | 1141 | .optional_single_mut_pointer, |
| 945 | 1142 | .optional_single_const_pointer, |
| 1143 | .enum_literal, | |
| 1144 | .mut_slice, | |
| 946 | 1145 | => false, |
| 947 | 1146 | |
| 948 | 1147 | .single_const_pointer, |
| 1148 | .many_const_pointer, | |
| 1149 | .c_const_pointer, | |
| 949 | 1150 | .single_const_pointer_to_comptime_int, |
| 950 | 1151 | .const_slice_u8, |
| 1152 | .const_slice, | |
| 951 | 1153 | => true, |
| 1154 | ||
| 1155 | .pointer => !self.cast(Payload.Pointer).?.mutable, | |
| 952 | 1156 | }; |
| 953 | 1157 | } |
| 954 | 1158 | |
| ... | ... | @@ -988,6 +1192,8 @@ pub const Type = extern union { |
| 988 | 1192 | .@"null", |
| 989 | 1193 | .@"undefined", |
| 990 | 1194 | .array, |
| 1195 | .array_sentinel, | |
| 1196 | .array_u8, | |
| 991 | 1197 | .array_u8_sentinel_0, |
| 992 | 1198 | .fn_noreturn_no_args, |
| 993 | 1199 | .fn_void_no_args, |
| ... | ... | @@ -998,12 +1204,24 @@ pub const Type = extern union { |
| 998 | 1204 | .int_signed, |
| 999 | 1205 | .single_mut_pointer, |
| 1000 | 1206 | .single_const_pointer, |
| 1207 | .many_const_pointer, | |
| 1208 | .many_mut_pointer, | |
| 1209 | .c_const_pointer, | |
| 1210 | .c_mut_pointer, | |
| 1211 | .const_slice, | |
| 1212 | .mut_slice, | |
| 1001 | 1213 | .single_const_pointer_to_comptime_int, |
| 1002 | 1214 | .const_slice_u8, |
| 1003 | 1215 | .optional, |
| 1004 | 1216 | .optional_single_mut_pointer, |
| 1005 | 1217 | .optional_single_const_pointer, |
| 1218 | .enum_literal, | |
| 1006 | 1219 | => false, |
| 1220 | ||
| 1221 | .pointer => { | |
| 1222 | const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); | |
| 1223 | return payload.@"volatile"; | |
| 1224 | }, | |
| 1007 | 1225 | }; |
| 1008 | 1226 | } |
| 1009 | 1227 | |
| ... | ... | @@ -1012,7 +1230,7 @@ pub const Type = extern union { |
| 1012 | 1230 | switch (self.tag()) { |
| 1013 | 1231 | .optional_single_const_pointer, .optional_single_mut_pointer => return true, |
| 1014 | 1232 | .optional => { |
| 1015 | var buf: Payload.Pointer = undefined; | |
| 1233 | var buf: Payload.PointerSimple = undefined; | |
| 1016 | 1234 | const child_type = self.optionalChild(&buf); |
| 1017 | 1235 | // optionals of zero sized pointers behave like bools |
| 1018 | 1236 | if (!child_type.hasCodeGenBits()) return false; |
| ... | ... | @@ -1023,6 +1241,45 @@ pub const Type = extern union { |
| 1023 | 1241 | } |
| 1024 | 1242 | } |
| 1025 | 1243 | |
| 1244 | /// Returns if type can be used for a runtime variable | |
| 1245 | pub fn isValidVarType(self: Type, is_extern: bool) bool { | |
| 1246 | var ty = self; | |
| 1247 | while (true) switch (ty.zigTypeTag()) { | |
| 1248 | .Bool, | |
| 1249 | .Int, | |
| 1250 | .Float, | |
| 1251 | .ErrorSet, | |
| 1252 | .Enum, | |
| 1253 | .Frame, | |
| 1254 | .AnyFrame, | |
| 1255 | .Vector, | |
| 1256 | => return true, | |
| 1257 | ||
| 1258 | .Opaque => return is_extern, | |
| 1259 | .BoundFn, | |
| 1260 | .ComptimeFloat, | |
| 1261 | .ComptimeInt, | |
| 1262 | .EnumLiteral, | |
| 1263 | .NoReturn, | |
| 1264 | .Type, | |
| 1265 | .Void, | |
| 1266 | .Undefined, | |
| 1267 | .Null, | |
| 1268 | => return false, | |
| 1269 | ||
| 1270 | .Optional => { | |
| 1271 | var buf: Payload.PointerSimple = undefined; | |
| 1272 | return ty.optionalChild(&buf).isValidVarType(is_extern); | |
| 1273 | }, | |
| 1274 | .Pointer, .Array => ty = ty.elemType(), | |
| 1275 | ||
| 1276 | .ErrorUnion => @panic("TODO fn isValidVarType"), | |
| 1277 | .Fn => @panic("TODO fn isValidVarType"), | |
| 1278 | .Struct => @panic("TODO struct isValidVarType"), | |
| 1279 | .Union => @panic("TODO union isValidVarType"), | |
| 1280 | }; | |
| 1281 | } | |
| 1282 | ||
| 1026 | 1283 | /// Asserts the type is a pointer or array type. |
| 1027 | 1284 | pub fn elemType(self: Type) Type { |
| 1028 | 1285 | return switch (self.tag()) { |
| ... | ... | @@ -1069,18 +1326,28 @@ pub const Type = extern union { |
| 1069 | 1326 | .optional, |
| 1070 | 1327 | .optional_single_const_pointer, |
| 1071 | 1328 | .optional_single_mut_pointer, |
| 1329 | .enum_literal, | |
| 1072 | 1330 | => unreachable, |
| 1073 | 1331 | |
| 1074 | 1332 | .array => self.cast(Payload.Array).?.elem_type, |
| 1075 | .single_const_pointer => self.castPointer().?.pointee_type, | |
| 1076 | .single_mut_pointer => self.castPointer().?.pointee_type, | |
| 1077 | .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), | |
| 1333 | .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, | |
| 1334 | .single_const_pointer, | |
| 1335 | .single_mut_pointer, | |
| 1336 | .many_const_pointer, | |
| 1337 | .many_mut_pointer, | |
| 1338 | .c_const_pointer, | |
| 1339 | .c_mut_pointer, | |
| 1340 | .const_slice, | |
| 1341 | .mut_slice, | |
| 1342 | => self.castPointer().?.pointee_type, | |
| 1343 | .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), | |
| 1078 | 1344 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 1345 | .pointer => self.cast(Payload.Pointer).?.pointee_type, | |
| 1079 | 1346 | }; |
| 1080 | 1347 | } |
| 1081 | 1348 | |
| 1082 | 1349 | /// Asserts that the type is an optional. |
| 1083 | pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type { | |
| 1350 | pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type { | |
| 1084 | 1351 | return switch (self.tag()) { |
| 1085 | 1352 | .optional => self.cast(Payload.Optional).?.child_type, |
| 1086 | 1353 | .optional_single_mut_pointer => { |
| ... | ... | @@ -1107,7 +1374,7 @@ pub const Type = extern union { |
| 1107 | 1374 | return switch (self.tag()) { |
| 1108 | 1375 | .optional => self.cast(Payload.Optional).?.child_type, |
| 1109 | 1376 | .optional_single_mut_pointer, .optional_single_const_pointer => { |
| 1110 | const payload = try allocator.create(Payload.Pointer); | |
| 1377 | const payload = try allocator.create(Payload.PointerSimple); | |
| 1111 | 1378 | payload.* = .{ |
| 1112 | 1379 | .base = .{ |
| 1113 | 1380 | .tag = if (self.tag() == .optional_single_const_pointer) |
| ... | ... | @@ -1164,8 +1431,15 @@ pub const Type = extern union { |
| 1164 | 1431 | .fn_naked_noreturn_no_args, |
| 1165 | 1432 | .fn_ccc_void_no_args, |
| 1166 | 1433 | .function, |
| 1434 | .pointer, | |
| 1167 | 1435 | .single_const_pointer, |
| 1168 | 1436 | .single_mut_pointer, |
| 1437 | .many_const_pointer, | |
| 1438 | .many_mut_pointer, | |
| 1439 | .c_const_pointer, | |
| 1440 | .c_mut_pointer, | |
| 1441 | .const_slice, | |
| 1442 | .mut_slice, | |
| 1169 | 1443 | .single_const_pointer_to_comptime_int, |
| 1170 | 1444 | .const_slice_u8, |
| 1171 | 1445 | .int_unsigned, |
| ... | ... | @@ -1173,9 +1447,12 @@ pub const Type = extern union { |
| 1173 | 1447 | .optional, |
| 1174 | 1448 | .optional_single_mut_pointer, |
| 1175 | 1449 | .optional_single_const_pointer, |
| 1450 | .enum_literal, | |
| 1176 | 1451 | => unreachable, |
| 1177 | 1452 | |
| 1178 | 1453 | .array => self.cast(Payload.Array).?.len, |
| 1454 | .array_sentinel => self.cast(Payload.ArraySentinel).?.len, | |
| 1455 | .array_u8 => self.cast(Payload.Array_u8).?.len, | |
| 1179 | 1456 | .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len, |
| 1180 | 1457 | }; |
| 1181 | 1458 | } |
| ... | ... | @@ -1221,8 +1498,15 @@ pub const Type = extern union { |
| 1221 | 1498 | .fn_naked_noreturn_no_args, |
| 1222 | 1499 | .fn_ccc_void_no_args, |
| 1223 | 1500 | .function, |
| 1501 | .pointer, | |
| 1224 | 1502 | .single_const_pointer, |
| 1225 | 1503 | .single_mut_pointer, |
| 1504 | .many_const_pointer, | |
| 1505 | .many_mut_pointer, | |
| 1506 | .c_const_pointer, | |
| 1507 | .c_mut_pointer, | |
| 1508 | .const_slice, | |
| 1509 | .mut_slice, | |
| 1226 | 1510 | .single_const_pointer_to_comptime_int, |
| 1227 | 1511 | .const_slice_u8, |
| 1228 | 1512 | .int_unsigned, |
| ... | ... | @@ -1230,9 +1514,11 @@ pub const Type = extern union { |
| 1230 | 1514 | .optional, |
| 1231 | 1515 | .optional_single_mut_pointer, |
| 1232 | 1516 | .optional_single_const_pointer, |
| 1517 | .enum_literal, | |
| 1233 | 1518 | => unreachable, |
| 1234 | 1519 | |
| 1235 | .array => return null, | |
| 1520 | .array, .array_u8 => return null, | |
| 1521 | .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel, | |
| 1236 | 1522 | .array_u8_sentinel_0 => return Value.initTag(.zero), |
| 1237 | 1523 | }; |
| 1238 | 1524 | } |
| ... | ... | @@ -1266,10 +1552,19 @@ pub const Type = extern union { |
| 1266 | 1552 | .fn_ccc_void_no_args, |
| 1267 | 1553 | .function, |
| 1268 | 1554 | .array, |
| 1555 | .array_sentinel, | |
| 1556 | .array_u8, | |
| 1557 | .array_u8_sentinel_0, | |
| 1558 | .pointer, | |
| 1269 | 1559 | .single_const_pointer, |
| 1270 | 1560 | .single_mut_pointer, |
| 1561 | .many_const_pointer, | |
| 1562 | .many_mut_pointer, | |
| 1563 | .c_const_pointer, | |
| 1564 | .c_mut_pointer, | |
| 1565 | .const_slice, | |
| 1566 | .mut_slice, | |
| 1271 | 1567 | .single_const_pointer_to_comptime_int, |
| 1272 | .array_u8_sentinel_0, | |
| 1273 | 1568 | .const_slice_u8, |
| 1274 | 1569 | .int_unsigned, |
| 1275 | 1570 | .u8, |
| ... | ... | @@ -1284,6 +1579,7 @@ pub const Type = extern union { |
| 1284 | 1579 | .optional, |
| 1285 | 1580 | .optional_single_mut_pointer, |
| 1286 | 1581 | .optional_single_const_pointer, |
| 1582 | .enum_literal, | |
| 1287 | 1583 | => false, |
| 1288 | 1584 | |
| 1289 | 1585 | .int_signed, |
| ... | ... | @@ -1324,10 +1620,19 @@ pub const Type = extern union { |
| 1324 | 1620 | .fn_ccc_void_no_args, |
| 1325 | 1621 | .function, |
| 1326 | 1622 | .array, |
| 1623 | .array_sentinel, | |
| 1624 | .array_u8, | |
| 1625 | .array_u8_sentinel_0, | |
| 1626 | .pointer, | |
| 1327 | 1627 | .single_const_pointer, |
| 1328 | 1628 | .single_mut_pointer, |
| 1629 | .many_const_pointer, | |
| 1630 | .many_mut_pointer, | |
| 1631 | .c_const_pointer, | |
| 1632 | .c_mut_pointer, | |
| 1633 | .const_slice, | |
| 1634 | .mut_slice, | |
| 1329 | 1635 | .single_const_pointer_to_comptime_int, |
| 1330 | .array_u8_sentinel_0, | |
| 1331 | 1636 | .const_slice_u8, |
| 1332 | 1637 | .int_signed, |
| 1333 | 1638 | .i8, |
| ... | ... | @@ -1342,6 +1647,7 @@ pub const Type = extern union { |
| 1342 | 1647 | .optional, |
| 1343 | 1648 | .optional_single_mut_pointer, |
| 1344 | 1649 | .optional_single_const_pointer, |
| 1650 | .enum_literal, | |
| 1345 | 1651 | => false, |
| 1346 | 1652 | |
| 1347 | 1653 | .int_unsigned, |
| ... | ... | @@ -1382,14 +1688,24 @@ pub const Type = extern union { |
| 1382 | 1688 | .fn_ccc_void_no_args, |
| 1383 | 1689 | .function, |
| 1384 | 1690 | .array, |
| 1691 | .array_sentinel, | |
| 1692 | .array_u8, | |
| 1693 | .array_u8_sentinel_0, | |
| 1694 | .pointer, | |
| 1385 | 1695 | .single_const_pointer, |
| 1386 | 1696 | .single_mut_pointer, |
| 1697 | .many_const_pointer, | |
| 1698 | .many_mut_pointer, | |
| 1699 | .c_const_pointer, | |
| 1700 | .c_mut_pointer, | |
| 1701 | .const_slice, | |
| 1702 | .mut_slice, | |
| 1387 | 1703 | .single_const_pointer_to_comptime_int, |
| 1388 | .array_u8_sentinel_0, | |
| 1389 | 1704 | .const_slice_u8, |
| 1390 | 1705 | .optional, |
| 1391 | 1706 | .optional_single_mut_pointer, |
| 1392 | 1707 | .optional_single_const_pointer, |
| 1708 | .enum_literal, | |
| 1393 | 1709 | => unreachable, |
| 1394 | 1710 | |
| 1395 | 1711 | .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, |
| ... | ... | @@ -1438,10 +1754,19 @@ pub const Type = extern union { |
| 1438 | 1754 | .fn_ccc_void_no_args, |
| 1439 | 1755 | .function, |
| 1440 | 1756 | .array, |
| 1757 | .array_sentinel, | |
| 1758 | .array_u8, | |
| 1759 | .array_u8_sentinel_0, | |
| 1760 | .pointer, | |
| 1441 | 1761 | .single_const_pointer, |
| 1442 | 1762 | .single_mut_pointer, |
| 1763 | .many_const_pointer, | |
| 1764 | .many_mut_pointer, | |
| 1765 | .c_const_pointer, | |
| 1766 | .c_mut_pointer, | |
| 1767 | .const_slice, | |
| 1768 | .mut_slice, | |
| 1443 | 1769 | .single_const_pointer_to_comptime_int, |
| 1444 | .array_u8_sentinel_0, | |
| 1445 | 1770 | .const_slice_u8, |
| 1446 | 1771 | .int_unsigned, |
| 1447 | 1772 | .int_signed, |
| ... | ... | @@ -1456,6 +1781,7 @@ pub const Type = extern union { |
| 1456 | 1781 | .optional, |
| 1457 | 1782 | .optional_single_mut_pointer, |
| 1458 | 1783 | .optional_single_const_pointer, |
| 1784 | .enum_literal, | |
| 1459 | 1785 | => false, |
| 1460 | 1786 | |
| 1461 | 1787 | .usize, |
| ... | ... | @@ -1523,10 +1849,19 @@ pub const Type = extern union { |
| 1523 | 1849 | .@"null", |
| 1524 | 1850 | .@"undefined", |
| 1525 | 1851 | .array, |
| 1852 | .array_sentinel, | |
| 1853 | .array_u8, | |
| 1854 | .array_u8_sentinel_0, | |
| 1855 | .pointer, | |
| 1526 | 1856 | .single_const_pointer, |
| 1527 | 1857 | .single_mut_pointer, |
| 1858 | .many_const_pointer, | |
| 1859 | .many_mut_pointer, | |
| 1860 | .c_const_pointer, | |
| 1861 | .c_mut_pointer, | |
| 1862 | .const_slice, | |
| 1863 | .mut_slice, | |
| 1528 | 1864 | .single_const_pointer_to_comptime_int, |
| 1529 | .array_u8_sentinel_0, | |
| 1530 | 1865 | .const_slice_u8, |
| 1531 | 1866 | .u8, |
| 1532 | 1867 | .i8, |
| ... | ... | @@ -1551,6 +1886,7 @@ pub const Type = extern union { |
| 1551 | 1886 | .optional, |
| 1552 | 1887 | .optional_single_mut_pointer, |
| 1553 | 1888 | .optional_single_const_pointer, |
| 1889 | .enum_literal, | |
| 1554 | 1890 | => unreachable, |
| 1555 | 1891 | }; |
| 1556 | 1892 | } |
| ... | ... | @@ -1584,10 +1920,19 @@ pub const Type = extern union { |
| 1584 | 1920 | .@"null", |
| 1585 | 1921 | .@"undefined", |
| 1586 | 1922 | .array, |
| 1923 | .array_sentinel, | |
| 1924 | .array_u8, | |
| 1925 | .array_u8_sentinel_0, | |
| 1926 | .pointer, | |
| 1587 | 1927 | .single_const_pointer, |
| 1588 | 1928 | .single_mut_pointer, |
| 1929 | .many_const_pointer, | |
| 1930 | .many_mut_pointer, | |
| 1931 | .c_const_pointer, | |
| 1932 | .c_mut_pointer, | |
| 1933 | .const_slice, | |
| 1934 | .mut_slice, | |
| 1589 | 1935 | .single_const_pointer_to_comptime_int, |
| 1590 | .array_u8_sentinel_0, | |
| 1591 | 1936 | .const_slice_u8, |
| 1592 | 1937 | .u8, |
| 1593 | 1938 | .i8, |
| ... | ... | @@ -1612,6 +1957,7 @@ pub const Type = extern union { |
| 1612 | 1957 | .optional, |
| 1613 | 1958 | .optional_single_mut_pointer, |
| 1614 | 1959 | .optional_single_const_pointer, |
| 1960 | .enum_literal, | |
| 1615 | 1961 | => unreachable, |
| 1616 | 1962 | } |
| 1617 | 1963 | } |
| ... | ... | @@ -1644,10 +1990,19 @@ pub const Type = extern union { |
| 1644 | 1990 | .@"null", |
| 1645 | 1991 | .@"undefined", |
| 1646 | 1992 | .array, |
| 1993 | .array_sentinel, | |
| 1994 | .array_u8, | |
| 1995 | .array_u8_sentinel_0, | |
| 1996 | .pointer, | |
| 1647 | 1997 | .single_const_pointer, |
| 1648 | 1998 | .single_mut_pointer, |
| 1999 | .many_const_pointer, | |
| 2000 | .many_mut_pointer, | |
| 2001 | .c_const_pointer, | |
| 2002 | .c_mut_pointer, | |
| 2003 | .const_slice, | |
| 2004 | .mut_slice, | |
| 1649 | 2005 | .single_const_pointer_to_comptime_int, |
| 1650 | .array_u8_sentinel_0, | |
| 1651 | 2006 | .const_slice_u8, |
| 1652 | 2007 | .u8, |
| 1653 | 2008 | .i8, |
| ... | ... | @@ -1672,6 +2027,7 @@ pub const Type = extern union { |
| 1672 | 2027 | .optional, |
| 1673 | 2028 | .optional_single_mut_pointer, |
| 1674 | 2029 | .optional_single_const_pointer, |
| 2030 | .enum_literal, | |
| 1675 | 2031 | => unreachable, |
| 1676 | 2032 | } |
| 1677 | 2033 | } |
| ... | ... | @@ -1704,10 +2060,19 @@ pub const Type = extern union { |
| 1704 | 2060 | .@"null", |
| 1705 | 2061 | .@"undefined", |
| 1706 | 2062 | .array, |
| 2063 | .array_sentinel, | |
| 2064 | .array_u8, | |
| 2065 | .array_u8_sentinel_0, | |
| 2066 | .pointer, | |
| 1707 | 2067 | .single_const_pointer, |
| 1708 | 2068 | .single_mut_pointer, |
| 2069 | .many_const_pointer, | |
| 2070 | .many_mut_pointer, | |
| 2071 | .c_const_pointer, | |
| 2072 | .c_mut_pointer, | |
| 2073 | .const_slice, | |
| 2074 | .mut_slice, | |
| 1709 | 2075 | .single_const_pointer_to_comptime_int, |
| 1710 | .array_u8_sentinel_0, | |
| 1711 | 2076 | .const_slice_u8, |
| 1712 | 2077 | .u8, |
| 1713 | 2078 | .i8, |
| ... | ... | @@ -1732,6 +2097,7 @@ pub const Type = extern union { |
| 1732 | 2097 | .optional, |
| 1733 | 2098 | .optional_single_mut_pointer, |
| 1734 | 2099 | .optional_single_const_pointer, |
| 2100 | .enum_literal, | |
| 1735 | 2101 | => unreachable, |
| 1736 | 2102 | }; |
| 1737 | 2103 | } |
| ... | ... | @@ -1761,10 +2127,19 @@ pub const Type = extern union { |
| 1761 | 2127 | .@"null", |
| 1762 | 2128 | .@"undefined", |
| 1763 | 2129 | .array, |
| 2130 | .array_sentinel, | |
| 2131 | .array_u8, | |
| 2132 | .array_u8_sentinel_0, | |
| 2133 | .pointer, | |
| 1764 | 2134 | .single_const_pointer, |
| 1765 | 2135 | .single_mut_pointer, |
| 2136 | .many_const_pointer, | |
| 2137 | .many_mut_pointer, | |
| 2138 | .c_const_pointer, | |
| 2139 | .c_mut_pointer, | |
| 2140 | .const_slice, | |
| 2141 | .mut_slice, | |
| 1766 | 2142 | .single_const_pointer_to_comptime_int, |
| 1767 | .array_u8_sentinel_0, | |
| 1768 | 2143 | .const_slice_u8, |
| 1769 | 2144 | .u8, |
| 1770 | 2145 | .i8, |
| ... | ... | @@ -1789,6 +2164,7 @@ pub const Type = extern union { |
| 1789 | 2164 | .optional, |
| 1790 | 2165 | .optional_single_mut_pointer, |
| 1791 | 2166 | .optional_single_const_pointer, |
| 2167 | .enum_literal, | |
| 1792 | 2168 | => unreachable, |
| 1793 | 2169 | }; |
| 1794 | 2170 | } |
| ... | ... | @@ -1818,10 +2194,19 @@ pub const Type = extern union { |
| 1818 | 2194 | .@"null", |
| 1819 | 2195 | .@"undefined", |
| 1820 | 2196 | .array, |
| 2197 | .array_sentinel, | |
| 2198 | .array_u8, | |
| 2199 | .array_u8_sentinel_0, | |
| 2200 | .pointer, | |
| 1821 | 2201 | .single_const_pointer, |
| 1822 | 2202 | .single_mut_pointer, |
| 2203 | .many_const_pointer, | |
| 2204 | .many_mut_pointer, | |
| 2205 | .c_const_pointer, | |
| 2206 | .c_mut_pointer, | |
| 2207 | .const_slice, | |
| 2208 | .mut_slice, | |
| 1823 | 2209 | .single_const_pointer_to_comptime_int, |
| 1824 | .array_u8_sentinel_0, | |
| 1825 | 2210 | .const_slice_u8, |
| 1826 | 2211 | .u8, |
| 1827 | 2212 | .i8, |
| ... | ... | @@ -1846,6 +2231,7 @@ pub const Type = extern union { |
| 1846 | 2231 | .optional, |
| 1847 | 2232 | .optional_single_mut_pointer, |
| 1848 | 2233 | .optional_single_const_pointer, |
| 2234 | .enum_literal, | |
| 1849 | 2235 | => unreachable, |
| 1850 | 2236 | }; |
| 1851 | 2237 | } |
| ... | ... | @@ -1895,14 +2281,24 @@ pub const Type = extern union { |
| 1895 | 2281 | .fn_ccc_void_no_args, |
| 1896 | 2282 | .function, |
| 1897 | 2283 | .array, |
| 2284 | .array_sentinel, | |
| 2285 | .array_u8, | |
| 2286 | .array_u8_sentinel_0, | |
| 2287 | .pointer, | |
| 1898 | 2288 | .single_const_pointer, |
| 1899 | 2289 | .single_mut_pointer, |
| 2290 | .many_const_pointer, | |
| 2291 | .many_mut_pointer, | |
| 2292 | .c_const_pointer, | |
| 2293 | .c_mut_pointer, | |
| 2294 | .const_slice, | |
| 2295 | .mut_slice, | |
| 1900 | 2296 | .single_const_pointer_to_comptime_int, |
| 1901 | .array_u8_sentinel_0, | |
| 1902 | 2297 | .const_slice_u8, |
| 1903 | 2298 | .optional, |
| 1904 | 2299 | .optional_single_mut_pointer, |
| 1905 | 2300 | .optional_single_const_pointer, |
| 2301 | .enum_literal, | |
| 1906 | 2302 | => false, |
| 1907 | 2303 | }; |
| 1908 | 2304 | } |
| ... | ... | @@ -1944,12 +2340,16 @@ pub const Type = extern union { |
| 1944 | 2340 | .fn_ccc_void_no_args, |
| 1945 | 2341 | .function, |
| 1946 | 2342 | .single_const_pointer_to_comptime_int, |
| 2343 | .array_sentinel, | |
| 1947 | 2344 | .array_u8_sentinel_0, |
| 1948 | 2345 | .const_slice_u8, |
| 2346 | .const_slice, | |
| 2347 | .mut_slice, | |
| 1949 | 2348 | .c_void, |
| 1950 | 2349 | .optional, |
| 1951 | 2350 | .optional_single_mut_pointer, |
| 1952 | 2351 | .optional_single_const_pointer, |
| 2352 | .enum_literal, | |
| 1953 | 2353 | => return null, |
| 1954 | 2354 | |
| 1955 | 2355 | .void => return Value.initTag(.void_value), |
| ... | ... | @@ -1971,18 +2371,27 @@ pub const Type = extern union { |
| 1971 | 2371 | return null; |
| 1972 | 2372 | } |
| 1973 | 2373 | }, |
| 1974 | .array => { | |
| 1975 | const array = ty.cast(Payload.Array).?; | |
| 1976 | if (array.len == 0) | |
| 2374 | .array, .array_u8 => { | |
| 2375 | if (ty.arrayLen() == 0) | |
| 1977 | 2376 | return Value.initTag(.empty_array); |
| 1978 | ty = array.elem_type; | |
| 2377 | ty = ty.elemType(); | |
| 1979 | 2378 | continue; |
| 1980 | 2379 | }, |
| 1981 | .single_const_pointer, .single_mut_pointer => { | |
| 2380 | .many_const_pointer, | |
| 2381 | .many_mut_pointer, | |
| 2382 | .c_const_pointer, | |
| 2383 | .c_mut_pointer, | |
| 2384 | .single_const_pointer, | |
| 2385 | .single_mut_pointer, | |
| 2386 | => { | |
| 1982 | 2387 | const ptr = ty.castPointer().?; |
| 1983 | 2388 | ty = ptr.pointee_type; |
| 1984 | 2389 | continue; |
| 1985 | 2390 | }, |
| 2391 | .pointer => { | |
| 2392 | ty = ty.cast(Payload.Pointer).?.pointee_type; | |
| 2393 | continue; | |
| 2394 | }, | |
| 1986 | 2395 | }; |
| 1987 | 2396 | } |
| 1988 | 2397 | |
| ... | ... | @@ -2022,7 +2431,6 @@ pub const Type = extern union { |
| 2022 | 2431 | .fn_ccc_void_no_args, |
| 2023 | 2432 | .function, |
| 2024 | 2433 | .single_const_pointer_to_comptime_int, |
| 2025 | .array_u8_sentinel_0, | |
| 2026 | 2434 | .const_slice_u8, |
| 2027 | 2435 | .c_void, |
| 2028 | 2436 | .void, |
| ... | ... | @@ -2032,12 +2440,26 @@ pub const Type = extern union { |
| 2032 | 2440 | .int_unsigned, |
| 2033 | 2441 | .int_signed, |
| 2034 | 2442 | .array, |
| 2443 | .array_sentinel, | |
| 2444 | .array_u8, | |
| 2445 | .array_u8_sentinel_0, | |
| 2035 | 2446 | .single_const_pointer, |
| 2036 | 2447 | .single_mut_pointer, |
| 2448 | .many_const_pointer, | |
| 2449 | .many_mut_pointer, | |
| 2450 | .const_slice, | |
| 2451 | .mut_slice, | |
| 2037 | 2452 | .optional, |
| 2038 | 2453 | .optional_single_mut_pointer, |
| 2039 | 2454 | .optional_single_const_pointer, |
| 2455 | .enum_literal, | |
| 2040 | 2456 | => return false, |
| 2457 | ||
| 2458 | .c_const_pointer, | |
| 2459 | .c_mut_pointer, | |
| 2460 | => return true, | |
| 2461 | ||
| 2462 | .pointer => self.cast(Payload.Pointer).?.size == .C, | |
| 2041 | 2463 | }; |
| 2042 | 2464 | } |
| 2043 | 2465 | |
| ... | ... | @@ -2080,6 +2502,7 @@ pub const Type = extern union { |
| 2080 | 2502 | comptime_int, |
| 2081 | 2503 | comptime_float, |
| 2082 | 2504 | noreturn, |
| 2505 | enum_literal, | |
| 2083 | 2506 | @"null", |
| 2084 | 2507 | @"undefined", |
| 2085 | 2508 | fn_noreturn_no_args, |
| ... | ... | @@ -2090,10 +2513,19 @@ pub const Type = extern union { |
| 2090 | 2513 | const_slice_u8, // See last_no_payload_tag below. |
| 2091 | 2514 | // After this, the tag requires a payload. |
| 2092 | 2515 | |
| 2516 | array_u8, | |
| 2093 | 2517 | array_u8_sentinel_0, |
| 2094 | 2518 | array, |
| 2519 | array_sentinel, | |
| 2520 | pointer, | |
| 2095 | 2521 | single_const_pointer, |
| 2096 | 2522 | single_mut_pointer, |
| 2523 | many_const_pointer, | |
| 2524 | many_mut_pointer, | |
| 2525 | c_const_pointer, | |
| 2526 | c_mut_pointer, | |
| 2527 | const_slice, | |
| 2528 | mut_slice, | |
| 2097 | 2529 | int_signed, |
| 2098 | 2530 | int_unsigned, |
| 2099 | 2531 | function, |
| ... | ... | @@ -2114,14 +2546,28 @@ pub const Type = extern union { |
| 2114 | 2546 | len: u64, |
| 2115 | 2547 | }; |
| 2116 | 2548 | |
| 2549 | pub const Array_u8 = struct { | |
| 2550 | base: Payload = Payload{ .tag = .array_u8 }, | |
| 2551 | ||
| 2552 | len: u64, | |
| 2553 | }; | |
| 2554 | ||
| 2117 | 2555 | pub const Array = struct { |
| 2118 | 2556 | base: Payload = Payload{ .tag = .array }, |
| 2119 | 2557 | |
| 2558 | len: u64, | |
| 2120 | 2559 | elem_type: Type, |
| 2560 | }; | |
| 2561 | ||
| 2562 | pub const ArraySentinel = struct { | |
| 2563 | base: Payload = Payload{ .tag = .array_sentinel }, | |
| 2564 | ||
| 2121 | 2565 | len: u64, |
| 2566 | sentinel: Value, | |
| 2567 | elem_type: Type, | |
| 2122 | 2568 | }; |
| 2123 | 2569 | |
| 2124 | pub const Pointer = struct { | |
| 2570 | pub const PointerSimple = struct { | |
| 2125 | 2571 | base: Payload, |
| 2126 | 2572 | |
| 2127 | 2573 | pointee_type: Type, |
| ... | ... | @@ -2152,6 +2598,21 @@ pub const Type = extern union { |
| 2152 | 2598 | |
| 2153 | 2599 | child_type: Type, |
| 2154 | 2600 | }; |
| 2601 | ||
| 2602 | pub const Pointer = struct { | |
| 2603 | base: Payload = .{ .tag = .pointer }, | |
| 2604 | ||
| 2605 | pointee_type: Type, | |
| 2606 | sentinel: ?Value, | |
| 2607 | /// If zero use pointee_type.AbiAlign() | |
| 2608 | @"align": u32, | |
| 2609 | bit_offset: u16, | |
| 2610 | host_size: u16, | |
| 2611 | @"allowzero": bool, | |
| 2612 | mutable: bool, | |
| 2613 | @"volatile": bool, | |
| 2614 | size: std.builtin.TypeInfo.Pointer.Size, | |
| 2615 | }; | |
| 2155 | 2616 | }; |
| 2156 | 2617 | }; |
| 2157 | 2618 |
src-self-hosted/value.zig+60-1| ... | ... | @@ -60,6 +60,7 @@ pub const Value = extern union { |
| 60 | 60 | fn_ccc_void_no_args_type, |
| 61 | 61 | single_const_pointer_to_comptime_int_type, |
| 62 | 62 | const_slice_u8_type, |
| 63 | enum_literal_type, | |
| 63 | 64 | |
| 64 | 65 | undef, |
| 65 | 66 | zero, |
| ... | ... | @@ -78,6 +79,7 @@ pub const Value = extern union { |
| 78 | 79 | int_big_positive, |
| 79 | 80 | int_big_negative, |
| 80 | 81 | function, |
| 82 | variable, | |
| 81 | 83 | ref_val, |
| 82 | 84 | decl_ref, |
| 83 | 85 | elem_ptr, |
| ... | ... | @@ -87,6 +89,7 @@ pub const Value = extern union { |
| 87 | 89 | float_32, |
| 88 | 90 | float_64, |
| 89 | 91 | float_128, |
| 92 | enum_literal, | |
| 90 | 93 | |
| 91 | 94 | pub const last_no_payload_tag = Tag.bool_false; |
| 92 | 95 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| ... | ... | @@ -164,6 +167,7 @@ pub const Value = extern union { |
| 164 | 167 | .fn_ccc_void_no_args_type, |
| 165 | 168 | .single_const_pointer_to_comptime_int_type, |
| 166 | 169 | .const_slice_u8_type, |
| 170 | .enum_literal_type, | |
| 167 | 171 | .undef, |
| 168 | 172 | .zero, |
| 169 | 173 | .void_value, |
| ... | ... | @@ -193,6 +197,7 @@ pub const Value = extern union { |
| 193 | 197 | @panic("TODO implement copying of big ints"); |
| 194 | 198 | }, |
| 195 | 199 | .function => return self.copyPayloadShallow(allocator, Payload.Function), |
| 200 | .variable => return self.copyPayloadShallow(allocator, Payload.Variable), | |
| 196 | 201 | .ref_val => { |
| 197 | 202 | const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); |
| 198 | 203 | const new_payload = try allocator.create(Payload.RefVal); |
| ... | ... | @@ -227,6 +232,15 @@ pub const Value = extern union { |
| 227 | 232 | .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32), |
| 228 | 233 | .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), |
| 229 | 234 | .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), |
| 235 | .enum_literal => { | |
| 236 | const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); | |
| 237 | const new_payload = try allocator.create(Payload.Bytes); | |
| 238 | new_payload.* = .{ | |
| 239 | .base = payload.base, | |
| 240 | .data = try allocator.dupe(u8, payload.data), | |
| 241 | }; | |
| 242 | return Value{ .ptr_otherwise = &new_payload.base }; | |
| 243 | }, | |
| 230 | 244 | } |
| 231 | 245 | } |
| 232 | 246 | |
| ... | ... | @@ -285,6 +299,7 @@ pub const Value = extern union { |
| 285 | 299 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), |
| 286 | 300 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), |
| 287 | 301 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), |
| 302 | .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), | |
| 288 | 303 | |
| 289 | 304 | .null_value => return out_stream.writeAll("null"), |
| 290 | 305 | .undef => return out_stream.writeAll("undefined"), |
| ... | ... | @@ -306,6 +321,7 @@ pub const Value = extern union { |
| 306 | 321 | .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), |
| 307 | 322 | .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), |
| 308 | 323 | .function => return out_stream.writeAll("(function)"), |
| 324 | .variable => return out_stream.writeAll("(variable)"), | |
| 309 | 325 | .ref_val => { |
| 310 | 326 | const ref_val = val.cast(Payload.RefVal).?; |
| 311 | 327 | try out_stream.writeAll("&const "); |
| ... | ... | @@ -318,7 +334,7 @@ pub const Value = extern union { |
| 318 | 334 | val = elem_ptr.array_ptr; |
| 319 | 335 | }, |
| 320 | 336 | .empty_array => return out_stream.writeAll(".{}"), |
| 321 | .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), | |
| 337 | .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), | |
| 322 | 338 | .repeated => { |
| 323 | 339 | try out_stream.writeAll("(repeated) "); |
| 324 | 340 | val = val.cast(Payload.Repeated).?.val; |
| ... | ... | @@ -391,6 +407,7 @@ pub const Value = extern union { |
| 391 | 407 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), |
| 392 | 408 | .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), |
| 393 | 409 | .const_slice_u8_type => Type.initTag(.const_slice_u8), |
| 410 | .enum_literal_type => Type.initTag(.enum_literal), | |
| 394 | 411 | |
| 395 | 412 | .undef, |
| 396 | 413 | .zero, |
| ... | ... | @@ -405,6 +422,7 @@ pub const Value = extern union { |
| 405 | 422 | .int_big_positive, |
| 406 | 423 | .int_big_negative, |
| 407 | 424 | .function, |
| 425 | .variable, | |
| 408 | 426 | .ref_val, |
| 409 | 427 | .decl_ref, |
| 410 | 428 | .elem_ptr, |
| ... | ... | @@ -414,6 +432,7 @@ pub const Value = extern union { |
| 414 | 432 | .float_32, |
| 415 | 433 | .float_64, |
| 416 | 434 | .float_128, |
| 435 | .enum_literal, | |
| 417 | 436 | => unreachable, |
| 418 | 437 | }; |
| 419 | 438 | } |
| ... | ... | @@ -462,8 +481,10 @@ pub const Value = extern union { |
| 462 | 481 | .fn_ccc_void_no_args_type, |
| 463 | 482 | .single_const_pointer_to_comptime_int_type, |
| 464 | 483 | .const_slice_u8_type, |
| 484 | .enum_literal_type, | |
| 465 | 485 | .null_value, |
| 466 | 486 | .function, |
| 487 | .variable, | |
| 467 | 488 | .ref_val, |
| 468 | 489 | .decl_ref, |
| 469 | 490 | .elem_ptr, |
| ... | ... | @@ -476,6 +497,7 @@ pub const Value = extern union { |
| 476 | 497 | .void_value, |
| 477 | 498 | .unreachable_value, |
| 478 | 499 | .empty_array, |
| 500 | .enum_literal, | |
| 479 | 501 | => unreachable, |
| 480 | 502 | |
| 481 | 503 | .undef => unreachable, |
| ... | ... | @@ -537,8 +559,10 @@ pub const Value = extern union { |
| 537 | 559 | .fn_ccc_void_no_args_type, |
| 538 | 560 | .single_const_pointer_to_comptime_int_type, |
| 539 | 561 | .const_slice_u8_type, |
| 562 | .enum_literal_type, | |
| 540 | 563 | .null_value, |
| 541 | 564 | .function, |
| 565 | .variable, | |
| 542 | 566 | .ref_val, |
| 543 | 567 | .decl_ref, |
| 544 | 568 | .elem_ptr, |
| ... | ... | @@ -551,6 +575,7 @@ pub const Value = extern union { |
| 551 | 575 | .void_value, |
| 552 | 576 | .unreachable_value, |
| 553 | 577 | .empty_array, |
| 578 | .enum_literal, | |
| 554 | 579 | => unreachable, |
| 555 | 580 | |
| 556 | 581 | .undef => unreachable, |
| ... | ... | @@ -612,8 +637,10 @@ pub const Value = extern union { |
| 612 | 637 | .fn_ccc_void_no_args_type, |
| 613 | 638 | .single_const_pointer_to_comptime_int_type, |
| 614 | 639 | .const_slice_u8_type, |
| 640 | .enum_literal_type, | |
| 615 | 641 | .null_value, |
| 616 | 642 | .function, |
| 643 | .variable, | |
| 617 | 644 | .ref_val, |
| 618 | 645 | .decl_ref, |
| 619 | 646 | .elem_ptr, |
| ... | ... | @@ -626,6 +653,7 @@ pub const Value = extern union { |
| 626 | 653 | .void_value, |
| 627 | 654 | .unreachable_value, |
| 628 | 655 | .empty_array, |
| 656 | .enum_literal, | |
| 629 | 657 | => unreachable, |
| 630 | 658 | |
| 631 | 659 | .undef => unreachable, |
| ... | ... | @@ -713,8 +741,10 @@ pub const Value = extern union { |
| 713 | 741 | .fn_ccc_void_no_args_type, |
| 714 | 742 | .single_const_pointer_to_comptime_int_type, |
| 715 | 743 | .const_slice_u8_type, |
| 744 | .enum_literal_type, | |
| 716 | 745 | .null_value, |
| 717 | 746 | .function, |
| 747 | .variable, | |
| 718 | 748 | .ref_val, |
| 719 | 749 | .decl_ref, |
| 720 | 750 | .elem_ptr, |
| ... | ... | @@ -728,6 +758,7 @@ pub const Value = extern union { |
| 728 | 758 | .void_value, |
| 729 | 759 | .unreachable_value, |
| 730 | 760 | .empty_array, |
| 761 | .enum_literal, | |
| 731 | 762 | => unreachable, |
| 732 | 763 | |
| 733 | 764 | .zero, |
| ... | ... | @@ -793,8 +824,10 @@ pub const Value = extern union { |
| 793 | 824 | .fn_ccc_void_no_args_type, |
| 794 | 825 | .single_const_pointer_to_comptime_int_type, |
| 795 | 826 | .const_slice_u8_type, |
| 827 | .enum_literal_type, | |
| 796 | 828 | .null_value, |
| 797 | 829 | .function, |
| 830 | .variable, | |
| 798 | 831 | .ref_val, |
| 799 | 832 | .decl_ref, |
| 800 | 833 | .elem_ptr, |
| ... | ... | @@ -807,6 +840,7 @@ pub const Value = extern union { |
| 807 | 840 | .void_value, |
| 808 | 841 | .unreachable_value, |
| 809 | 842 | .empty_array, |
| 843 | .enum_literal, | |
| 810 | 844 | => unreachable, |
| 811 | 845 | |
| 812 | 846 | .zero, |
| ... | ... | @@ -953,10 +987,12 @@ pub const Value = extern union { |
| 953 | 987 | .fn_ccc_void_no_args_type, |
| 954 | 988 | .single_const_pointer_to_comptime_int_type, |
| 955 | 989 | .const_slice_u8_type, |
| 990 | .enum_literal_type, | |
| 956 | 991 | .bool_true, |
| 957 | 992 | .bool_false, |
| 958 | 993 | .null_value, |
| 959 | 994 | .function, |
| 995 | .variable, | |
| 960 | 996 | .ref_val, |
| 961 | 997 | .decl_ref, |
| 962 | 998 | .elem_ptr, |
| ... | ... | @@ -970,6 +1006,7 @@ pub const Value = extern union { |
| 970 | 1006 | .empty_array, |
| 971 | 1007 | .void_value, |
| 972 | 1008 | .unreachable_value, |
| 1009 | .enum_literal, | |
| 973 | 1010 | => unreachable, |
| 974 | 1011 | |
| 975 | 1012 | .zero => false, |
| ... | ... | @@ -1025,8 +1062,10 @@ pub const Value = extern union { |
| 1025 | 1062 | .fn_ccc_void_no_args_type, |
| 1026 | 1063 | .single_const_pointer_to_comptime_int_type, |
| 1027 | 1064 | .const_slice_u8_type, |
| 1065 | .enum_literal_type, | |
| 1028 | 1066 | .null_value, |
| 1029 | 1067 | .function, |
| 1068 | .variable, | |
| 1030 | 1069 | .ref_val, |
| 1031 | 1070 | .decl_ref, |
| 1032 | 1071 | .elem_ptr, |
| ... | ... | @@ -1036,6 +1075,7 @@ pub const Value = extern union { |
| 1036 | 1075 | .void_value, |
| 1037 | 1076 | .unreachable_value, |
| 1038 | 1077 | .empty_array, |
| 1078 | .enum_literal, | |
| 1039 | 1079 | => unreachable, |
| 1040 | 1080 | |
| 1041 | 1081 | .zero, |
| ... | ... | @@ -1102,6 +1142,11 @@ pub const Value = extern union { |
| 1102 | 1142 | } |
| 1103 | 1143 | |
| 1104 | 1144 | pub fn eql(a: Value, b: Value) bool { |
| 1145 | if (a.tag() == b.tag() and a.tag() == .enum_literal) { | |
| 1146 | const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data; | |
| 1147 | const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data; | |
| 1148 | return std.mem.eql(u8, a_name, b_name); | |
| 1149 | } | |
| 1105 | 1150 | // TODO non numerical comparisons |
| 1106 | 1151 | return compare(a, .eq, b); |
| 1107 | 1152 | } |
| ... | ... | @@ -1151,11 +1196,13 @@ pub const Value = extern union { |
| 1151 | 1196 | .fn_ccc_void_no_args_type, |
| 1152 | 1197 | .single_const_pointer_to_comptime_int_type, |
| 1153 | 1198 | .const_slice_u8_type, |
| 1199 | .enum_literal_type, | |
| 1154 | 1200 | .zero, |
| 1155 | 1201 | .bool_true, |
| 1156 | 1202 | .bool_false, |
| 1157 | 1203 | .null_value, |
| 1158 | 1204 | .function, |
| 1205 | .variable, | |
| 1159 | 1206 | .int_u64, |
| 1160 | 1207 | .int_i64, |
| 1161 | 1208 | .int_big_positive, |
| ... | ... | @@ -1170,6 +1217,7 @@ pub const Value = extern union { |
| 1170 | 1217 | .void_value, |
| 1171 | 1218 | .unreachable_value, |
| 1172 | 1219 | .empty_array, |
| 1220 | .enum_literal, | |
| 1173 | 1221 | => unreachable, |
| 1174 | 1222 | |
| 1175 | 1223 | .ref_val => self.cast(Payload.RefVal).?.val, |
| ... | ... | @@ -1227,11 +1275,13 @@ pub const Value = extern union { |
| 1227 | 1275 | .fn_ccc_void_no_args_type, |
| 1228 | 1276 | .single_const_pointer_to_comptime_int_type, |
| 1229 | 1277 | .const_slice_u8_type, |
| 1278 | .enum_literal_type, | |
| 1230 | 1279 | .zero, |
| 1231 | 1280 | .bool_true, |
| 1232 | 1281 | .bool_false, |
| 1233 | 1282 | .null_value, |
| 1234 | 1283 | .function, |
| 1284 | .variable, | |
| 1235 | 1285 | .int_u64, |
| 1236 | 1286 | .int_i64, |
| 1237 | 1287 | .int_big_positive, |
| ... | ... | @@ -1246,6 +1296,7 @@ pub const Value = extern union { |
| 1246 | 1296 | .float_128, |
| 1247 | 1297 | .void_value, |
| 1248 | 1298 | .unreachable_value, |
| 1299 | .enum_literal, | |
| 1249 | 1300 | => unreachable, |
| 1250 | 1301 | |
| 1251 | 1302 | .empty_array => unreachable, // out of bounds array index |
| ... | ... | @@ -1320,11 +1371,13 @@ pub const Value = extern union { |
| 1320 | 1371 | .fn_ccc_void_no_args_type, |
| 1321 | 1372 | .single_const_pointer_to_comptime_int_type, |
| 1322 | 1373 | .const_slice_u8_type, |
| 1374 | .enum_literal_type, | |
| 1323 | 1375 | .zero, |
| 1324 | 1376 | .empty_array, |
| 1325 | 1377 | .bool_true, |
| 1326 | 1378 | .bool_false, |
| 1327 | 1379 | .function, |
| 1380 | .variable, | |
| 1328 | 1381 | .int_u64, |
| 1329 | 1382 | .int_i64, |
| 1330 | 1383 | .int_big_positive, |
| ... | ... | @@ -1339,6 +1392,7 @@ pub const Value = extern union { |
| 1339 | 1392 | .float_64, |
| 1340 | 1393 | .float_128, |
| 1341 | 1394 | .void_value, |
| 1395 | .enum_literal, | |
| 1342 | 1396 | => false, |
| 1343 | 1397 | |
| 1344 | 1398 | .undef => unreachable, |
| ... | ... | @@ -1398,6 +1452,11 @@ pub const Value = extern union { |
| 1398 | 1452 | func: *Module.Fn, |
| 1399 | 1453 | }; |
| 1400 | 1454 | |
| 1455 | pub const Variable = struct { | |
| 1456 | base: Payload = Payload{ .tag = .variable }, | |
| 1457 | variable: *Module.Var, | |
| 1458 | }; | |
| 1459 | ||
| 1401 | 1460 | pub const ArraySentinel0_u8_Type = struct { |
| 1402 | 1461 | base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, |
| 1403 | 1462 | len: u64, |
src-self-hosted/zir.zig+146-9| ... | ... | @@ -47,6 +47,10 @@ pub const Inst = struct { |
| 47 | 47 | array_cat, |
| 48 | 48 | /// Array multiplication `a ** b` |
| 49 | 49 | array_mul, |
| 50 | /// Create an array type | |
| 51 | array_type, | |
| 52 | /// Create an array type with sentinel | |
| 53 | array_type_sentinel, | |
| 50 | 54 | /// Function parameter value. These must be first in a function's main block, |
| 51 | 55 | /// in respective order with the parameters. |
| 52 | 56 | arg, |
| ... | ... | @@ -58,11 +62,11 @@ pub const Inst = struct { |
| 58 | 62 | bitand, |
| 59 | 63 | /// TODO delete this instruction, it has no purpose. |
| 60 | 64 | bitcast, |
| 61 | /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted | |
| 62 | /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated | |
| 65 | /// An arbitrary typed pointer is pointer-casted to a new Pointer. | |
| 66 | /// The destination type is given by LHS. The cast is to be evaluated | |
| 63 | 67 | /// as if it were a bit-cast operation from the operand pointer element type to the |
| 64 | 68 | /// provided destination type. |
| 65 | bitcast_lvalue, | |
| 69 | bitcast_ref, | |
| 66 | 70 | /// A typed result location pointer is bitcasted to a new result location pointer. |
| 67 | 71 | /// The new result location pointer has an inferred type. |
| 68 | 72 | bitcast_result_ptr, |
| ... | ... | @@ -190,10 +194,22 @@ pub const Inst = struct { |
| 190 | 194 | shl, |
| 191 | 195 | /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. |
| 192 | 196 | shr, |
| 193 | /// Create a const pointer type based on the element type. `*const T` | |
| 197 | /// Create a const pointer type with element type T. `*const T` | |
| 194 | 198 | single_const_ptr_type, |
| 195 | /// Create a mutable pointer type based on the element type. `*T` | |
| 199 | /// Create a mutable pointer type with element type T. `*T` | |
| 196 | 200 | single_mut_ptr_type, |
| 201 | /// Create a const pointer type with element type T. `[*]const T` | |
| 202 | many_const_ptr_type, | |
| 203 | /// Create a mutable pointer type with element type T. `[*]T` | |
| 204 | many_mut_ptr_type, | |
| 205 | /// Create a const pointer type with element type T. `[*c]const T` | |
| 206 | c_const_ptr_type, | |
| 207 | /// Create a mutable pointer type with element type T. `[*c]T` | |
| 208 | c_mut_ptr_type, | |
| 209 | /// Create a mutable slice type with element type T. `[]T` | |
| 210 | mut_slice_type, | |
| 211 | /// Create a const slice type with element type T. `[]T` | |
| 212 | const_slice_type, | |
| 197 | 213 | /// Create a pointer type with attributes |
| 198 | 214 | ptr_type, |
| 199 | 215 | /// Write a value to a pointer. For loading, see `deref`. |
| ... | ... | @@ -225,6 +241,10 @@ pub const Inst = struct { |
| 225 | 241 | unwrap_err_safe, |
| 226 | 242 | /// Same as previous, but without safety checks. Used for orelse, if and while |
| 227 | 243 | unwrap_err_unsafe, |
| 244 | /// Takes a *E!T and raises a compiler error if T != void | |
| 245 | ensure_err_payload_void, | |
| 246 | /// Enum literal | |
| 247 | enum_literal, | |
| 228 | 248 | |
| 229 | 249 | pub fn Type(tag: Tag) type { |
| 230 | 250 | return switch (tag) { |
| ... | ... | @@ -250,21 +270,29 @@ pub const Inst = struct { |
| 250 | 270 | .ensure_result_non_error, |
| 251 | 271 | .bitcast_result_ptr, |
| 252 | 272 | .ref, |
| 253 | .bitcast_lvalue, | |
| 273 | .bitcast_ref, | |
| 254 | 274 | .typeof, |
| 255 | 275 | .single_const_ptr_type, |
| 256 | 276 | .single_mut_ptr_type, |
| 277 | .many_const_ptr_type, | |
| 278 | .many_mut_ptr_type, | |
| 279 | .c_const_ptr_type, | |
| 280 | .c_mut_ptr_type, | |
| 281 | .mut_slice_type, | |
| 282 | .const_slice_type, | |
| 257 | 283 | .optional_type, |
| 258 | 284 | .unwrap_optional_safe, |
| 259 | 285 | .unwrap_optional_unsafe, |
| 260 | 286 | .unwrap_err_safe, |
| 261 | 287 | .unwrap_err_unsafe, |
| 288 | .ensure_err_payload_void, | |
| 262 | 289 | => UnOp, |
| 263 | 290 | |
| 264 | 291 | .add, |
| 265 | 292 | .addwrap, |
| 266 | 293 | .array_cat, |
| 267 | 294 | .array_mul, |
| 295 | .array_type, | |
| 268 | 296 | .bitand, |
| 269 | 297 | .bitor, |
| 270 | 298 | .div, |
| ... | ... | @@ -291,6 +319,7 @@ pub const Inst = struct { |
| 291 | 319 | => BinOp, |
| 292 | 320 | |
| 293 | 321 | .arg => Arg, |
| 322 | .array_type_sentinel => ArrayTypeSentinel, | |
| 294 | 323 | .block => Block, |
| 295 | 324 | .@"break" => Break, |
| 296 | 325 | .breakvoid => BreakVoid, |
| ... | ... | @@ -317,6 +346,7 @@ pub const Inst = struct { |
| 317 | 346 | .elemptr => ElemPtr, |
| 318 | 347 | .condbr => CondBr, |
| 319 | 348 | .ptr_type => PtrType, |
| 349 | .enum_literal => EnumLiteral, | |
| 320 | 350 | }; |
| 321 | 351 | } |
| 322 | 352 | |
| ... | ... | @@ -330,12 +360,14 @@ pub const Inst = struct { |
| 330 | 360 | .alloc_inferred, |
| 331 | 361 | .array_cat, |
| 332 | 362 | .array_mul, |
| 363 | .array_type, | |
| 364 | .array_type_sentinel, | |
| 333 | 365 | .arg, |
| 334 | 366 | .as, |
| 335 | 367 | .@"asm", |
| 336 | 368 | .bitand, |
| 337 | 369 | .bitcast, |
| 338 | .bitcast_lvalue, | |
| 370 | .bitcast_ref, | |
| 339 | 371 | .bitcast_result_ptr, |
| 340 | 372 | .bitor, |
| 341 | 373 | .block, |
| ... | ... | @@ -386,6 +418,12 @@ pub const Inst = struct { |
| 386 | 418 | .shr, |
| 387 | 419 | .single_const_ptr_type, |
| 388 | 420 | .single_mut_ptr_type, |
| 421 | .many_const_ptr_type, | |
| 422 | .many_mut_ptr_type, | |
| 423 | .c_const_ptr_type, | |
| 424 | .c_mut_ptr_type, | |
| 425 | .mut_slice_type, | |
| 426 | .const_slice_type, | |
| 389 | 427 | .store, |
| 390 | 428 | .str, |
| 391 | 429 | .sub, |
| ... | ... | @@ -398,6 +436,8 @@ pub const Inst = struct { |
| 398 | 436 | .unwrap_err_safe, |
| 399 | 437 | .unwrap_err_unsafe, |
| 400 | 438 | .ptr_type, |
| 439 | .ensure_err_payload_void, | |
| 440 | .enum_literal, | |
| 401 | 441 | => false, |
| 402 | 442 | |
| 403 | 443 | .@"break", |
| ... | ... | @@ -840,11 +880,34 @@ pub const Inst = struct { |
| 840 | 880 | @"align": ?*Inst = null, |
| 841 | 881 | align_bit_start: ?*Inst = null, |
| 842 | 882 | align_bit_end: ?*Inst = null, |
| 843 | @"const": bool = true, | |
| 883 | mutable: bool = true, | |
| 844 | 884 | @"volatile": bool = false, |
| 845 | 885 | sentinel: ?*Inst = null, |
| 886 | size: std.builtin.TypeInfo.Pointer.Size = .One, | |
| 846 | 887 | }, |
| 847 | 888 | }; |
| 889 | ||
| 890 | pub const ArrayTypeSentinel = struct { | |
| 891 | pub const base_tag = Tag.array_type_sentinel; | |
| 892 | base: Inst, | |
| 893 | ||
| 894 | positionals: struct { | |
| 895 | len: *Inst, | |
| 896 | sentinel: *Inst, | |
| 897 | elem_type: *Inst, | |
| 898 | }, | |
| 899 | kw_args: struct {}, | |
| 900 | }; | |
| 901 | ||
| 902 | pub const EnumLiteral = struct { | |
| 903 | pub const base_tag = Tag.enum_literal; | |
| 904 | base: Inst, | |
| 905 | ||
| 906 | positionals: struct { | |
| 907 | name: []const u8, | |
| 908 | }, | |
| 909 | kw_args: struct {}, | |
| 910 | }; | |
| 848 | 911 | }; |
| 849 | 912 | |
| 850 | 913 | pub const ErrorMsg = struct { |
| ... | ... | @@ -1714,6 +1777,9 @@ const EmitZIR = struct { |
| 1714 | 1777 | const decl_ref = try self.emitDeclRef(inst.src, declref.decl); |
| 1715 | 1778 | try new_body.instructions.append(decl_ref); |
| 1716 | 1779 | break :blk decl_ref; |
| 1780 | } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: { | |
| 1781 | const owner_decl = var_pl.variable.owner_decl; | |
| 1782 | break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); | |
| 1717 | 1783 | } else blk: { |
| 1718 | 1784 | break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; |
| 1719 | 1785 | }; |
| ... | ... | @@ -1837,6 +1903,11 @@ const EmitZIR = struct { |
| 1837 | 1903 | if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { |
| 1838 | 1904 | const decl = decl_ref.decl; |
| 1839 | 1905 | return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl)); |
| 1906 | } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { | |
| 1907 | return self.emitTypedValue(src, .{ | |
| 1908 | .ty = typed_value.ty, | |
| 1909 | .val = variable.variable.init, | |
| 1910 | }); | |
| 1840 | 1911 | } |
| 1841 | 1912 | if (typed_value.val.isUndef()) { |
| 1842 | 1913 | const as_inst = try self.arena.allocator.create(Inst.BinOp); |
| ... | ... | @@ -1922,6 +1993,25 @@ const EmitZIR = struct { |
| 1922 | 1993 | return self.emitUnnamedDecl(&str_inst.base); |
| 1923 | 1994 | }, |
| 1924 | 1995 | .Void => return self.emitPrimitive(src, .void_value), |
| 1996 | .Bool => if (typed_value.val.toBool()) | |
| 1997 | return self.emitPrimitive(src, .@"true") | |
| 1998 | else | |
| 1999 | return self.emitPrimitive(src, .@"false"), | |
| 2000 | .EnumLiteral => { | |
| 2001 | const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise); | |
| 2002 | const inst = try self.arena.allocator.create(Inst.Str); | |
| 2003 | inst.* = .{ | |
| 2004 | .base = .{ | |
| 2005 | .src = src, | |
| 2006 | .tag = .enum_literal, | |
| 2007 | }, | |
| 2008 | .positionals = .{ | |
| 2009 | .bytes = enum_literal.data, | |
| 2010 | }, | |
| 2011 | .kw_args = .{}, | |
| 2012 | }; | |
| 2013 | return self.emitUnnamedDecl(&inst.base); | |
| 2014 | }, | |
| 1925 | 2015 | else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), |
| 1926 | 2016 | } |
| 1927 | 2017 | } |
| ... | ... | @@ -2269,6 +2359,8 @@ const EmitZIR = struct { |
| 2269 | 2359 | }; |
| 2270 | 2360 | break :blk &new_inst.base; |
| 2271 | 2361 | }, |
| 2362 | ||
| 2363 | .varptr => @panic("TODO"), | |
| 2272 | 2364 | }; |
| 2273 | 2365 | try self.metadata.put(new_inst, .{ .deaths = inst.deaths }); |
| 2274 | 2366 | try instructions.append(new_inst); |
| ... | ... | @@ -2376,7 +2468,7 @@ const EmitZIR = struct { |
| 2376 | 2468 | } |
| 2377 | 2469 | }, |
| 2378 | 2470 | .Optional => { |
| 2379 | var buf: Type.Payload.Pointer = undefined; | |
| 2471 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2380 | 2472 | const inst = try self.arena.allocator.create(Inst.UnOp); |
| 2381 | 2473 | inst.* = .{ |
| 2382 | 2474 | .base = .{ |
| ... | ... | @@ -2390,6 +2482,51 @@ const EmitZIR = struct { |
| 2390 | 2482 | }; |
| 2391 | 2483 | return self.emitUnnamedDecl(&inst.base); |
| 2392 | 2484 | }, |
| 2485 | .Array => { | |
| 2486 | var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() }; | |
| 2487 | const len = Value.initPayload(&len_pl.base); | |
| 2488 | ||
| 2489 | const inst = if (ty.arraySentinel()) |sentinel| blk: { | |
| 2490 | const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel); | |
| 2491 | inst.* = .{ | |
| 2492 | .base = .{ | |
| 2493 | .src = src, | |
| 2494 | .tag = .array_type, | |
| 2495 | }, | |
| 2496 | .positionals = .{ | |
| 2497 | .len = (try self.emitTypedValue(src, .{ | |
| 2498 | .ty = Type.initTag(.usize), | |
| 2499 | .val = len, | |
| 2500 | })).inst, | |
| 2501 | .sentinel = (try self.emitTypedValue(src, .{ | |
| 2502 | .ty = ty.elemType(), | |
| 2503 | .val = sentinel, | |
| 2504 | })).inst, | |
| 2505 | .elem_type = (try self.emitType(src, ty.elemType())).inst, | |
| 2506 | }, | |
| 2507 | .kw_args = .{}, | |
| 2508 | }; | |
| 2509 | break :blk &inst.base; | |
| 2510 | } else blk: { | |
| 2511 | const inst = try self.arena.allocator.create(Inst.BinOp); | |
| 2512 | inst.* = .{ | |
| 2513 | .base = .{ | |
| 2514 | .src = src, | |
| 2515 | .tag = .array_type, | |
| 2516 | }, | |
| 2517 | .positionals = .{ | |
| 2518 | .lhs = (try self.emitTypedValue(src, .{ | |
| 2519 | .ty = Type.initTag(.usize), | |
| 2520 | .val = len, | |
| 2521 | })).inst, | |
| 2522 | .rhs = (try self.emitType(src, ty.elemType())).inst, | |
| 2523 | }, | |
| 2524 | .kw_args = .{}, | |
| 2525 | }; | |
| 2526 | break :blk &inst.base; | |
| 2527 | }; | |
| 2528 | return self.emitUnnamedDecl(inst); | |
| 2529 | }, | |
| 2393 | 2530 | else => std.debug.panic("TODO implement emitType for {}", .{ty}), |
| 2394 | 2531 | }, |
| 2395 | 2532 | } |
src-self-hosted/zir_sema.zig+112-46| ... | ... | @@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 29 | 29 | .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?), |
| 30 | 30 | .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?), |
| 31 | 31 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 32 | .bitcast_lvalue => return analyzeInstBitCastLValue(mod, scope, old_inst.castTag(.bitcast_lvalue).?), | |
| 32 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | |
| 33 | 33 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 34 | 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?), |
| 35 | 35 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| ... | ... | @@ -51,8 +51,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 51 | 51 | .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), |
| 52 | 52 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 53 | 53 | .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), |
| 54 | .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?), | |
| 55 | .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?), | |
| 54 | .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), | |
| 55 | .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), | |
| 56 | .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), | |
| 57 | .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), | |
| 58 | .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), | |
| 59 | .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), | |
| 60 | .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), | |
| 61 | .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), | |
| 56 | 62 | .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), |
| 57 | 63 | .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), |
| 58 | 64 | .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), |
| ... | ... | @@ -112,6 +118,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 112 | 118 | .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false), |
| 113 | 119 | .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true), |
| 114 | 120 | .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false), |
| 121 | .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), | |
| 122 | .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), | |
| 123 | .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), | |
| 124 | .enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?), | |
| 115 | 125 | } |
| 116 | 126 | } |
| 117 | 127 | |
| ... | ... | @@ -263,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { |
| 263 | 273 | return val.toType(); |
| 264 | 274 | } |
| 265 | 275 | |
| 276 | fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { | |
| 277 | const new_inst = try resolveInst(mod, scope, old_inst); | |
| 278 | const coerced = try mod.coerce(scope, dest_type, new_inst); | |
| 279 | const val = try mod.resolveConstValue(scope, coerced); | |
| 280 | ||
| 281 | return val.toUnsignedInt(); | |
| 282 | } | |
| 283 | ||
| 266 | 284 | pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { |
| 267 | 285 | const new_inst = try resolveInst(mod, scope, old_inst); |
| 268 | 286 | const val = try mod.resolveConstValue(scope, new_inst); |
| ... | ... | @@ -295,8 +313,8 @@ fn analyzeInstCoerceResultBlockPtr( |
| 295 | 313 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{}); |
| 296 | 314 | } |
| 297 | 315 | |
| 298 | fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 299 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{}); | |
| 316 | fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 317 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{}); | |
| 300 | 318 | } |
| 301 | 319 | |
| 302 | 320 | fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| ... | ... | @@ -320,7 +338,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr |
| 320 | 338 | |
| 321 | 339 | fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 322 | 340 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 323 | const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty); | |
| 341 | const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); | |
| 324 | 342 | |
| 325 | 343 | if (operand.value()) |val| { |
| 326 | 344 | const ref_payload = try scope.arena().create(Value.Payload.RefVal); |
| ... | ... | @@ -361,7 +379,11 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. |
| 361 | 379 | |
| 362 | 380 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 363 | 381 | const var_type = try resolveType(mod, scope, inst.positionals.operand); |
| 364 | const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); | |
| 382 | // TODO this should happen only for var allocs | |
| 383 | if (!var_type.isValidVarType(false)) { | |
| 384 | return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); | |
| 385 | } | |
| 386 | const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One); | |
| 365 | 387 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 366 | 388 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 367 | 389 | } |
| ... | ... | @@ -573,8 +595,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne |
| 573 | 595 | |
| 574 | 596 | fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst { |
| 575 | 597 | const decl = inst.positionals.decl; |
| 576 | const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl); | |
| 577 | return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src); | |
| 598 | return mod.analyzeDeclRef(scope, inst.base.src, decl); | |
| 578 | 599 | } |
| 579 | 600 | |
| 580 | 601 | fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| ... | ... | @@ -675,31 +696,36 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I |
| 675 | 696 | fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst { |
| 676 | 697 | const child_type = try resolveType(mod, scope, optional.positionals.operand); |
| 677 | 698 | |
| 678 | return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) { | |
| 679 | .single_const_pointer => blk: { | |
| 680 | const payload = try scope.arena().create(Type.Payload.Pointer); | |
| 681 | payload.* = .{ | |
| 682 | .base = .{ .tag = .optional_single_const_pointer }, | |
| 683 | .pointee_type = child_type.elemType(), | |
| 684 | }; | |
| 685 | break :blk &payload.base; | |
| 686 | }, | |
| 687 | .single_mut_pointer => blk: { | |
| 688 | const payload = try scope.arena().create(Type.Payload.Pointer); | |
| 689 | payload.* = .{ | |
| 690 | .base = .{ .tag = .optional_single_mut_pointer }, | |
| 691 | .pointee_type = child_type.elemType(), | |
| 692 | }; | |
| 693 | break :blk &payload.base; | |
| 694 | }, | |
| 695 | else => blk: { | |
| 696 | const payload = try scope.arena().create(Type.Payload.Optional); | |
| 697 | payload.* = .{ | |
| 698 | .child_type = child_type, | |
| 699 | }; | |
| 700 | break :blk &payload.base; | |
| 701 | }, | |
| 702 | })); | |
| 699 | return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type)); | |
| 700 | } | |
| 701 | ||
| 702 | fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst { | |
| 703 | // TODO these should be lazily evaluated | |
| 704 | const len = try resolveInstConst(mod, scope, array.positionals.lhs); | |
| 705 | const elem_type = try resolveType(mod, scope, array.positionals.rhs); | |
| 706 | ||
| 707 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type)); | |
| 708 | } | |
| 709 | ||
| 710 | fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst { | |
| 711 | // TODO these should be lazily evaluated | |
| 712 | const len = try resolveInstConst(mod, scope, array.positionals.len); | |
| 713 | const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel); | |
| 714 | const elem_type = try resolveType(mod, scope, array.positionals.elem_type); | |
| 715 | ||
| 716 | return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type)); | |
| 717 | } | |
| 718 | ||
| 719 | fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst { | |
| 720 | const payload = try scope.arena().create(Value.Payload.Bytes); | |
| 721 | payload.* = .{ | |
| 722 | .base = .{ .tag = .enum_literal }, | |
| 723 | .data = try scope.arena().dupe(u8, inst.positionals.name), | |
| 724 | }; | |
| 725 | return mod.constInst(scope, inst.base.src, .{ | |
| 726 | .ty = Type.initTag(.enum_literal), | |
| 727 | .val = Value.initPayload(&payload.base), | |
| 728 | }); | |
| 703 | 729 | } |
| 704 | 730 | |
| 705 | 731 | fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { |
| ... | ... | @@ -711,7 +737,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp |
| 711 | 737 | } |
| 712 | 738 | |
| 713 | 739 | const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena()); |
| 714 | const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type); | |
| 740 | const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); | |
| 715 | 741 | |
| 716 | 742 | if (operand.value()) |val| { |
| 717 | 743 | if (val.isNull()) { |
| ... | ... | @@ -735,6 +761,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf |
| 735 | 761 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{}); |
| 736 | 762 | } |
| 737 | 763 | |
| 764 | fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | |
| 765 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{}); | |
| 766 | } | |
| 767 | ||
| 738 | 768 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| 739 | 769 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); |
| 740 | 770 | |
| ... | ... | @@ -760,7 +790,12 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne |
| 760 | 790 | const arena = scope.arena(); |
| 761 | 791 | const param_types = try arena.alloc(Type, fntype.positionals.param_types.len); |
| 762 | 792 | for (fntype.positionals.param_types) |param_type, i| { |
| 763 | param_types[i] = try resolveType(mod, scope, param_type); | |
| 793 | const resolved = try resolveType(mod, scope, param_type); | |
| 794 | // TODO skip for comptime params | |
| 795 | if (!resolved.isValidVarType(false)) { | |
| 796 | return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); | |
| 797 | } | |
| 798 | param_types[i] = resolved; | |
| 764 | 799 | } |
| 765 | 800 | |
| 766 | 801 | const payload = try arena.create(Type.Payload.Function); |
| ... | ... | @@ -919,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 919 | 954 | // required a larger index. |
| 920 | 955 | const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); |
| 921 | 956 | |
| 922 | const type_payload = try scope.arena().create(Type.Payload.Pointer); | |
| 957 | const type_payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 923 | 958 | type_payload.* = .{ |
| 924 | 959 | .base = .{ .tag = .single_const_pointer }, |
| 925 | 960 | .pointee_type = array_ptr.ty.elemType().elemType(), |
| ... | ... | @@ -1290,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr |
| 1290 | 1325 | return decl; |
| 1291 | 1326 | } |
| 1292 | 1327 | |
| 1293 | fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1328 | fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { | |
| 1294 | 1329 | const elem_type = try resolveType(mod, scope, inst.positionals.operand); |
| 1295 | const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type); | |
| 1296 | return mod.constType(scope, inst.base.src, ty); | |
| 1297 | } | |
| 1298 | ||
| 1299 | fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1300 | const elem_type = try resolveType(mod, scope, inst.positionals.operand); | |
| 1301 | const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type); | |
| 1330 | const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size); | |
| 1302 | 1331 | return mod.constType(scope, inst.base.src, ty); |
| 1303 | 1332 | } |
| 1304 | 1333 | |
| 1305 | 1334 | fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { |
| 1306 | return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); | |
| 1335 | // TODO lazy values | |
| 1336 | const @"align" = if (inst.kw_args.@"align") |some| | |
| 1337 | @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32))) | |
| 1338 | else | |
| 1339 | 0; | |
| 1340 | const bit_offset = if (inst.kw_args.align_bit_start) |some| | |
| 1341 | @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) | |
| 1342 | else | |
| 1343 | 0; | |
| 1344 | const host_size = if (inst.kw_args.align_bit_end) |some| | |
| 1345 | @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) | |
| 1346 | else | |
| 1347 | 0; | |
| 1348 | ||
| 1349 | if (host_size != 0 and bit_offset >= host_size * 8) | |
| 1350 | return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); | |
| 1351 | ||
| 1352 | const sentinel = if (inst.kw_args.sentinel) |some| | |
| 1353 | (try resolveInstConst(mod, scope, some)).val | |
| 1354 | else | |
| 1355 | null; | |
| 1356 | ||
| 1357 | const elem_type = try resolveType(mod, scope, inst.positionals.child_type); | |
| 1358 | ||
| 1359 | const ty = try mod.ptrType( | |
| 1360 | scope, | |
| 1361 | inst.base.src, | |
| 1362 | elem_type, | |
| 1363 | sentinel, | |
| 1364 | @"align", | |
| 1365 | bit_offset, | |
| 1366 | host_size, | |
| 1367 | inst.kw_args.mutable, | |
| 1368 | inst.kw_args.@"allowzero", | |
| 1369 | inst.kw_args.@"volatile", | |
| 1370 | inst.kw_args.size, | |
| 1371 | ); | |
| 1372 | return mod.constType(scope, inst.base.src, ty); | |
| 1307 | 1373 | } |
src/all_types.hpp+1| ... | ... | @@ -1420,6 +1420,7 @@ struct ZigTypeStruct { |
| 1420 | 1420 | bool requires_comptime; |
| 1421 | 1421 | bool resolve_loop_flag_zero_bits; |
| 1422 | 1422 | bool resolve_loop_flag_other; |
| 1423 | bool created_by_at_type; | |
| 1423 | 1424 | }; |
| 1424 | 1425 | |
| 1425 | 1426 | struct ZigTypeOptional { |
src/analyze.cpp+5-5| ... | ... | @@ -138,7 +138,7 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope |
| 138 | 138 | dest->parent = parent; |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, | |
| 141 | ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, | |
| 142 | 142 | ZigType *import, Buf *bare_name) |
| 143 | 143 | { |
| 144 | 144 | ScopeDecls *scope = heap::c_allocator.create<ScopeDecls>(); |
| ... | ... | @@ -2821,7 +2821,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2821 | 2821 | |
| 2822 | 2822 | src_assert(struct_type->data.structure.fields == nullptr, decl_node); |
| 2823 | 2823 | struct_type->data.structure.fields = alloc_type_struct_fields(field_count); |
| 2824 | } else if (is_anon_container(struct_type)) { | |
| 2824 | } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { | |
| 2825 | 2825 | field_count = struct_type->data.structure.src_field_count; |
| 2826 | 2826 | |
| 2827 | 2827 | src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node); |
| ... | ... | @@ -2856,7 +2856,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2856 | 2856 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2857 | 2857 | return ErrorSemanticAnalyzeFail; |
| 2858 | 2858 | } |
| 2859 | } else if (is_anon_container(struct_type)) { | |
| 2859 | } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { | |
| 2860 | 2860 | field_node = type_struct_field->decl_node; |
| 2861 | 2861 | |
| 2862 | 2862 | src_assert(type_struct_field->type_entry != nullptr, field_node); |
| ... | ... | @@ -2883,7 +2883,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2883 | 2883 | type_struct_field->type_val = field_type_val; |
| 2884 | 2884 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) |
| 2885 | 2885 | return ErrorSemanticAnalyzeFail; |
| 2886 | } else if (is_anon_container(struct_type)) { | |
| 2886 | } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { | |
| 2887 | 2887 | field_type_val = type_struct_field->type_val; |
| 2888 | 2888 | } else zig_unreachable(); |
| 2889 | 2889 | |
| ... | ... | @@ -8331,7 +8331,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 8331 | 8331 | ZigLLVMDIFile *di_file; |
| 8332 | 8332 | ZigLLVMDIScope *di_scope; |
| 8333 | 8333 | unsigned line; |
| 8334 | if (decl_node != nullptr) { | |
| 8334 | if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) { | |
| 8335 | 8335 | Scope *scope = &struct_type->data.structure.decls_scope->base; |
| 8336 | 8336 | ZigType *import = get_scope_import(scope); |
| 8337 | 8337 | di_file = import->data.structure.root_struct->di_file; |
src/analyze.hpp+1| ... | ... | @@ -116,6 +116,7 @@ void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool |
| 116 | 116 | |
| 117 | 117 | void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val); |
| 118 | 118 | |
| 119 | ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name); | |
| 119 | 120 | ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 120 | 121 | ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 121 | 122 | ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent); |
src/codegen.cpp+5-4| ... | ... | @@ -293,13 +293,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { |
| 293 | 293 | } |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { | |
| 296 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { | |
| 297 | 297 | switch (id) { |
| 298 | 298 | case GlobalLinkageIdInternal: |
| 299 | 299 | return LLVMInternalLinkage; |
| 300 | 300 | case GlobalLinkageIdStrong: |
| 301 | 301 | return LLVMExternalLinkage; |
| 302 | 302 | case GlobalLinkageIdWeak: |
| 303 | if (is_extern) return LLVMExternalWeakLinkage; | |
| 303 | 304 | return LLVMWeakODRLinkage; |
| 304 | 305 | case GlobalLinkageIdLinkOnce: |
| 305 | 306 | return LLVMLinkOnceODRLinkage; |
| ... | ... | @@ -522,7 +523,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 522 | 523 | } |
| 523 | 524 | |
| 524 | 525 | |
| 525 | LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage)); | |
| 526 | LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr)); | |
| 526 | 527 | |
| 527 | 528 | if (linkage == GlobalLinkageIdInternal) { |
| 528 | 529 | LLVMSetUnnamedAddr(llvm_fn, true); |
| ... | ... | @@ -7963,7 +7964,7 @@ static void do_code_gen(CodeGen *g) { |
| 7963 | 7964 | global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); |
| 7964 | 7965 | // TODO debug info for the extern variable |
| 7965 | 7966 | |
| 7966 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | |
| 7967 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true)); | |
| 7967 | 7968 | maybe_import_dll(g, global_value, GlobalLinkageIdStrong); |
| 7968 | 7969 | LLVMSetAlignment(global_value, var->align_bytes); |
| 7969 | 7970 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| ... | ... | @@ -7976,7 +7977,7 @@ static void do_code_gen(CodeGen *g) { |
| 7976 | 7977 | global_value = var->const_value->llvm_global; |
| 7977 | 7978 | |
| 7978 | 7979 | if (exported) { |
| 7979 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | |
| 7980 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false)); | |
| 7980 | 7981 | maybe_export_dll(g, global_value, GlobalLinkageIdStrong); |
| 7981 | 7982 | } |
| 7982 | 7983 | if (var->section_name) { |
src/ir.cpp+120-50| ... | ... | @@ -25679,37 +25679,20 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy |
| 25679 | 25679 | struct_field_val->type = type_info_struct_field_type; |
| 25680 | 25680 | |
| 25681 | 25681 | ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4); |
| 25682 | inner_fields[1]->special = ConstValSpecialStatic; | |
| 25683 | inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int); | |
| 25684 | ||
| 25685 | ZigType *field_type = resolve_struct_field_type(ira->codegen, struct_field); | |
| 25686 | if (field_type == nullptr) | |
| 25687 | return ErrorSemanticAnalyzeFail; | |
| 25688 | if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) | |
| 25689 | return err; | |
| 25690 | if (!type_has_bits(ira->codegen, struct_field->type_entry)) { | |
| 25691 | inner_fields[1]->data.x_optional = nullptr; | |
| 25692 | } else { | |
| 25693 | size_t byte_offset = struct_field->offset; | |
| 25694 | inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>(); | |
| 25695 | inner_fields[1]->data.x_optional->special = ConstValSpecialStatic; | |
| 25696 | inner_fields[1]->data.x_optional->type = ira->codegen->builtin_types.entry_num_lit_int; | |
| 25697 | bigint_init_unsigned(&inner_fields[1]->data.x_optional->data.x_bigint, byte_offset); | |
| 25698 | } | |
| 25699 | 25682 | |
| 25700 | inner_fields[2]->special = ConstValSpecialStatic; | |
| 25701 | inner_fields[2]->type = ira->codegen->builtin_types.entry_type; | |
| 25702 | inner_fields[2]->data.x_type = struct_field->type_entry; | |
| 25683 | inner_fields[1]->special = ConstValSpecialStatic; | |
| 25684 | inner_fields[1]->type = ira->codegen->builtin_types.entry_type; | |
| 25685 | inner_fields[1]->data.x_type = struct_field->type_entry; | |
| 25703 | 25686 | |
| 25704 | 25687 | // default_value: anytype |
| 25705 | inner_fields[3]->special = ConstValSpecialStatic; | |
| 25706 | inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry); | |
| 25707 | if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail; | |
| 25688 | inner_fields[2]->special = ConstValSpecialStatic; | |
| 25689 | inner_fields[2]->type = get_optional_type2(ira->codegen, struct_field->type_entry); | |
| 25690 | if (inner_fields[2]->type == nullptr) return ErrorSemanticAnalyzeFail; | |
| 25708 | 25691 | memoize_field_init_val(ira->codegen, type_entry, struct_field); |
| 25709 | 25692 | if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){ |
| 25710 | 25693 | return ErrorSemanticAnalyzeFail; |
| 25711 | 25694 | } |
| 25712 | set_optional_payload(inner_fields[3], struct_field->init_val); | |
| 25695 | set_optional_payload(inner_fields[2], struct_field->init_val); | |
| 25713 | 25696 | |
| 25714 | 25697 | ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee; |
| 25715 | 25698 | init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true); |
| ... | ... | @@ -25960,6 +25943,36 @@ static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *sour |
| 25960 | 25943 | return value->data.x_optional->data.x_type; |
| 25961 | 25944 | } |
| 25962 | 25945 | |
| 25946 | static Error get_const_field_buf(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, | |
| 25947 | const char *name, size_t field_index, Buf *out) | |
| 25948 | { | |
| 25949 | ZigValue *slice = get_const_field(ira, source_node, struct_value, name, field_index); | |
| 25950 | ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; | |
| 25951 | ZigValue *len = slice->data.x_struct.fields[slice_len_index]; | |
| 25952 | assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | |
| 25953 | assert(ptr->data.x_ptr.data.base_array.elem_index == 0); | |
| 25954 | ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; | |
| 25955 | assert(arr->special == ConstValSpecialStatic); | |
| 25956 | switch (arr->data.x_array.special) { | |
| 25957 | case ConstArraySpecialUndef: | |
| 25958 | return ErrorSemanticAnalyzeFail; | |
| 25959 | case ConstArraySpecialNone: { | |
| 25960 | buf_resize(out, 0); | |
| 25961 | size_t count = bigint_as_usize(&len->data.x_bigint); | |
| 25962 | for (size_t j = 0; j < count; j++) { | |
| 25963 | ZigValue *ch_val = &arr->data.x_array.data.s_none.elements[j]; | |
| 25964 | unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); | |
| 25965 | buf_append_char(out, ch); | |
| 25966 | } | |
| 25967 | break; | |
| 25968 | } | |
| 25969 | case ConstArraySpecialBuf: | |
| 25970 | buf_init_from_buf(out, arr->data.x_array.data.s_buf); | |
| 25971 | break; | |
| 25972 | } | |
| 25973 | return ErrorNone; | |
| 25974 | } | |
| 25975 | ||
| 25963 | 25976 | static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeId tagTypeId, ZigValue *payload) { |
| 25964 | 25977 | Error err; |
| 25965 | 25978 | switch (tagTypeId) { |
| ... | ... | @@ -26163,30 +26176,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI |
| 26163 | 26176 | assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); |
| 26164 | 26177 | ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>(); |
| 26165 | 26178 | err_entry->decl_node = source_instr->source_node; |
| 26166 | ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0); | |
| 26167 | ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index]; | |
| 26168 | ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index]; | |
| 26169 | assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | |
| 26170 | assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0); | |
| 26171 | ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val; | |
| 26172 | assert(name_arr->special == ConstValSpecialStatic); | |
| 26173 | switch (name_arr->data.x_array.special) { | |
| 26174 | case ConstArraySpecialUndef: | |
| 26175 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26176 | case ConstArraySpecialNone: { | |
| 26177 | buf_resize(&err_entry->name, 0); | |
| 26178 | size_t name_count = bigint_as_usize(&name_len->data.x_bigint); | |
| 26179 | for (size_t j = 0; j < name_count; j++) { | |
| 26180 | ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j]; | |
| 26181 | unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); | |
| 26182 | buf_append_char(&err_entry->name, ch); | |
| 26183 | } | |
| 26184 | break; | |
| 26185 | } | |
| 26186 | case ConstArraySpecialBuf: | |
| 26187 | buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf); | |
| 26188 | break; | |
| 26189 | } | |
| 26179 | Error err; | |
| 26180 | if ((err = get_const_field_buf(ira, source_instr->source_node, error, "name", 0, &err_entry->name))) | |
| 26181 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26190 | 26182 | auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); |
| 26191 | 26183 | if (existing_entry) { |
| 26192 | 26184 | err_entry->value = existing_entry->value->value; |
| ... | ... | @@ -26206,14 +26198,92 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI |
| 26206 | 26198 | } |
| 26207 | 26199 | return err_set_type; |
| 26208 | 26200 | } |
| 26201 | case ZigTypeIdStruct: { | |
| 26202 | assert(payload->special == ConstValSpecialStatic); | |
| 26203 | assert(payload->type == ir_type_info_get_type(ira, "Struct", nullptr)); | |
| 26204 | ||
| 26205 | ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); | |
| 26206 | assert(layout_value->special == ConstValSpecialStatic); | |
| 26207 | assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); | |
| 26208 | ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); | |
| 26209 | ||
| 26210 | ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 1); | |
| 26211 | assert(fields_value->special == ConstValSpecialStatic); | |
| 26212 | assert(is_slice(fields_value->type)); | |
| 26213 | ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; | |
| 26214 | ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; | |
| 26215 | size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); | |
| 26216 | ||
| 26217 | ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 2); | |
| 26218 | assert(decls_value->special == ConstValSpecialStatic); | |
| 26219 | assert(is_slice(decls_value->type)); | |
| 26220 | ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; | |
| 26221 | size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); | |
| 26222 | if (decls_len != 0) { | |
| 26223 | ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type")); | |
| 26224 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26225 | } | |
| 26226 | ||
| 26227 | bool is_tuple; | |
| 26228 | get_const_field_bool(ira, source_instr->source_node, payload, "is_tuple", 3, &is_tuple); | |
| 26229 | ||
| 26230 | ZigType *entry = new_type_table_entry(ZigTypeIdStruct); | |
| 26231 | buf_init_from_buf(&entry->name, | |
| 26232 | get_anon_type_name(ira->codegen, ira->old_irb.exec, "struct", source_instr->scope, source_instr->source_node, &entry->name)); | |
| 26233 | entry->data.structure.decl_node = source_instr->source_node; | |
| 26234 | entry->data.structure.fields = alloc_type_struct_fields(fields_len); | |
| 26235 | entry->data.structure.fields_by_name.init(fields_len); | |
| 26236 | entry->data.structure.src_field_count = fields_len; | |
| 26237 | entry->data.structure.layout = layout; | |
| 26238 | entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; | |
| 26239 | entry->data.structure.created_by_at_type = true; | |
| 26240 | entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name); | |
| 26241 | ||
| 26242 | assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | |
| 26243 | assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); | |
| 26244 | ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; | |
| 26245 | assert(fields_arr->special == ConstValSpecialStatic); | |
| 26246 | assert(fields_arr->data.x_array.special == ConstArraySpecialNone); | |
| 26247 | for (size_t i = 0; i < fields_len; i++) { | |
| 26248 | ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; | |
| 26249 | assert(field_value->type == ir_type_info_get_type(ira, "StructField", nullptr)); | |
| 26250 | TypeStructField *field = entry->data.structure.fields[i]; | |
| 26251 | field->name = buf_alloc(); | |
| 26252 | if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name))) | |
| 26253 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26254 | field->decl_node = source_instr->source_node; | |
| 26255 | ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1); | |
| 26256 | field->type_val = type_value; | |
| 26257 | field->type_entry = type_value->data.x_type; | |
| 26258 | if (entry->data.structure.fields_by_name.put_unique(field->name, field) != nullptr) { | |
| 26259 | ir_add_error(ira, source_instr, buf_sprintf("duplicate struct field '%s'", buf_ptr(field->name))); | |
| 26260 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26261 | } | |
| 26262 | ZigValue *default_value = get_const_field(ira, source_instr->source_node, field_value, "default_value", 2); | |
| 26263 | if (default_value->type->id == ZigTypeIdNull) { | |
| 26264 | field->init_val = nullptr; | |
| 26265 | } else if (default_value->type->id == ZigTypeIdOptional && default_value->type->data.maybe.child_type == field->type_entry) { | |
| 26266 | field->init_val = default_value->data.x_optional; | |
| 26267 | } else if (default_value->type == field->type_entry) { | |
| 26268 | field->init_val = default_value; | |
| 26269 | } else { | |
| 26270 | ir_add_error(ira, source_instr, | |
| 26271 | buf_sprintf("default_value of field '%s' is of type '%s', expected '%s' or '?%s'", | |
| 26272 | buf_ptr(field->name), buf_ptr(&default_value->type->name), | |
| 26273 | buf_ptr(&field->type_entry->name), buf_ptr(&field->type_entry->name))); | |
| 26274 | return ira->codegen->invalid_inst_gen->value->type; | |
| 26275 | } | |
| 26276 | } | |
| 26277 | ||
| 26278 | return entry; | |
| 26279 | } | |
| 26209 | 26280 | case ZigTypeIdEnum: |
| 26281 | case ZigTypeIdUnion: | |
| 26210 | 26282 | ir_add_error(ira, source_instr, buf_sprintf( |
| 26211 | 26283 | "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); |
| 26212 | 26284 | return ira->codegen->invalid_inst_gen->value->type; |
| 26213 | case ZigTypeIdUnion: | |
| 26214 | 26285 | case ZigTypeIdFn: |
| 26215 | 26286 | case ZigTypeIdBoundFn: |
| 26216 | case ZigTypeIdStruct: | |
| 26217 | 26287 | ir_add_error(ira, source_instr, buf_sprintf( |
| 26218 | 26288 | "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId))); |
| 26219 | 26289 | return ira->codegen->invalid_inst_gen->value->type; |
src/parser.cpp+3| ... | ... | @@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B |
| 680 | 680 | AstNode *var_decl = ast_parse_var_decl(pc); |
| 681 | 681 | if (var_decl != nullptr) { |
| 682 | 682 | assert(var_decl->type == NodeTypeVariableDeclaration); |
| 683 | if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { | |
| 684 | ast_error(pc, first, "extern variables have no initializers"); | |
| 685 | } | |
| 683 | 686 | var_decl->line = first->start_line; |
| 684 | 687 | var_decl->column = first->start_column; |
| 685 | 688 | var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; |
test/compile_errors.zig+9-3| ... | ... | @@ -2,6 +2,12 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addTest("reject extern variables with initializers", | |
| 6 | \\extern var foo: int = 2; | |
| 7 | , &[_][]const u8{ | |
| 8 | "tmp.zig:1:1: error: extern variables have no initializers", | |
| 9 | }); | |
| 10 | ||
| 5 | 11 | cases.addTest("duplicate/unused labels", |
| 6 | 12 | \\comptime { |
| 7 | 13 | \\ blk: { blk: while (false) {} } |
| ... | ... | @@ -1395,12 +1401,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1395 | 1401 | "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'", |
| 1396 | 1402 | }); |
| 1397 | 1403 | |
| 1398 | cases.add("Struct unavailable for @Type", | |
| 1404 | cases.add("struct with declarations unavailable for @Type", | |
| 1399 | 1405 | \\export fn entry() void { |
| 1400 | \\ _ = @Type(@typeInfo(struct { })); | |
| 1406 | \\ _ = @Type(@typeInfo(struct { const foo = 1; })); | |
| 1401 | 1407 | \\} |
| 1402 | 1408 | , &[_][]const u8{ |
| 1403 | "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'", | |
| 1409 | "tmp.zig:2:15: error: TypeInfo.Struct.decls must be empty for @Type", | |
| 1404 | 1410 | }); |
| 1405 | 1411 | |
| 1406 | 1412 | cases.add("wrong type for argument tuple to @asyncCall", |
test/run_translated_c.zig+14| ... | ... | @@ -3,6 +3,20 @@ const tests = @import("tests.zig"); |
| 3 | 3 | const nl = std.cstr.line_sep; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 6 | cases.add("static variable in block scope", | |
| 7 | \\#include <stdlib.h> | |
| 8 | \\int foo() { | |
| 9 | \\ static int bar; | |
| 10 | \\ bar += 1; | |
| 11 | \\ return bar; | |
| 12 | \\} | |
| 13 | \\int main() { | |
| 14 | \\ foo(); | |
| 15 | \\ foo(); | |
| 16 | \\ if (foo() != 3) abort(); | |
| 17 | \\} | |
| 18 | , ""); | |
| 19 | ||
| 6 | 20 | cases.add("array initializer", |
| 7 | 21 | \\#include <stdlib.h> |
| 8 | 22 | \\int main(int argc, char **argv) { |
test/stack_traces.zig+3-3| ... | ... | @@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 282 | 282 | \\source.zig:10:8: [address] in main (test) |
| 283 | 283 | \\ foo(); |
| 284 | 284 | \\ ^ |
| 285 | \\start.zig:249:29: [address] in std.start.posixCallMainAndExit (test) | |
| 285 | \\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test) | |
| 286 | 286 | \\ return root.main(); |
| 287 | 287 | \\ ^ |
| 288 | \\start.zig:123:5: [address] in std.start._start (test) | |
| 288 | \\start.zig:128:5: [address] in std.start._start (test) | |
| 289 | 289 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 290 | 290 | \\ ^ |
| 291 | 291 | \\ |
| ... | ... | @@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 294 | 294 | switch (std.Target.current.cpu.arch) { |
| 295 | 295 | .aarch64 => "", // TODO disabled; results in segfault |
| 296 | 296 | else => |
| 297 | \\start.zig:123:5: [address] in std.start._start (test) | |
| 297 | \\start.zig:128:5: [address] in std.start._start (test) | |
| 298 | 298 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 299 | 299 | \\ ^ |
| 300 | 300 | \\ |
test/stage1/behavior/type.zig+44| ... | ... | @@ -236,3 +236,47 @@ test "Type.ErrorSet" { |
| 236 | 236 | _ = @Type(@typeInfo(error{A})); |
| 237 | 237 | _ = @Type(@typeInfo(error{ A, B, C })); |
| 238 | 238 | } |
| 239 | ||
| 240 | test "Type.Struct" { | |
| 241 | const A = @Type(@typeInfo(struct { x: u8, y: u32 })); | |
| 242 | const infoA = @typeInfo(A).Struct; | |
| 243 | testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout); | |
| 244 | testing.expectEqualSlices(u8, "x", infoA.fields[0].name); | |
| 245 | testing.expectEqual(u8, infoA.fields[0].field_type); | |
| 246 | testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value); | |
| 247 | testing.expectEqualSlices(u8, "y", infoA.fields[1].name); | |
| 248 | testing.expectEqual(u32, infoA.fields[1].field_type); | |
| 249 | testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value); | |
| 250 | testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls); | |
| 251 | testing.expectEqual(@as(bool, false), infoA.is_tuple); | |
| 252 | ||
| 253 | var a = A{ .x = 0, .y = 1 }; | |
| 254 | testing.expectEqual(@as(u8, 0), a.x); | |
| 255 | testing.expectEqual(@as(u32, 1), a.y); | |
| 256 | a.y += 1; | |
| 257 | testing.expectEqual(@as(u32, 2), a.y); | |
| 258 | ||
| 259 | const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 })); | |
| 260 | const infoB = @typeInfo(B).Struct; | |
| 261 | testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout); | |
| 262 | testing.expectEqualSlices(u8, "x", infoB.fields[0].name); | |
| 263 | testing.expectEqual(u8, infoB.fields[0].field_type); | |
| 264 | testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value); | |
| 265 | testing.expectEqualSlices(u8, "y", infoB.fields[1].name); | |
| 266 | testing.expectEqual(u32, infoB.fields[1].field_type); | |
| 267 | testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value); | |
| 268 | testing.expectEqual(@as(usize, 0), infoB.decls.len); | |
| 269 | testing.expectEqual(@as(bool, false), infoB.is_tuple); | |
| 270 | ||
| 271 | const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 })); | |
| 272 | const infoC = @typeInfo(C).Struct; | |
| 273 | testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout); | |
| 274 | testing.expectEqualSlices(u8, "x", infoC.fields[0].name); | |
| 275 | testing.expectEqual(u8, infoC.fields[0].field_type); | |
| 276 | testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value); | |
| 277 | testing.expectEqualSlices(u8, "y", infoC.fields[1].name); | |
| 278 | testing.expectEqual(u32, infoC.fields[1].field_type); | |
| 279 | testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value); | |
| 280 | testing.expectEqual(@as(usize, 0), infoC.decls.len); | |
| 281 | testing.expectEqual(@as(bool, false), infoC.is_tuple); | |
| 282 | } |
test/stage1/behavior/type_info.zig-11| ... | ... | @@ -238,7 +238,6 @@ fn testStruct() void { |
| 238 | 238 | expect(struct_info == .Struct); |
| 239 | 239 | expect(struct_info.Struct.layout == .Packed); |
| 240 | 240 | expect(struct_info.Struct.fields.len == 4); |
| 241 | expect(struct_info.Struct.fields[1].offset == null); | |
| 242 | 241 | expect(struct_info.Struct.fields[2].field_type == *TestStruct); |
| 243 | 242 | expect(struct_info.Struct.fields[2].default_value == null); |
| 244 | 243 | expect(struct_info.Struct.fields[3].default_value.? == 4); |
| ... | ... | @@ -320,16 +319,6 @@ fn testAnyFrame() void { |
| 320 | 319 | } |
| 321 | 320 | } |
| 322 | 321 | |
| 323 | test "type info: optional field unwrapping" { | |
| 324 | const Struct = struct { | |
| 325 | cdOffset: u32, | |
| 326 | }; | |
| 327 | ||
| 328 | const field = @typeInfo(Struct).Struct.fields[0]; | |
| 329 | ||
| 330 | _ = field.offset orelse 0; | |
| 331 | } | |
| 332 | ||
| 333 | 322 | test "type info: pass to function" { |
| 334 | 323 | _ = passTypeInfo(@typeInfo(void)); |
| 335 | 324 | _ = comptime passTypeInfo(@typeInfo(void)); |
test/stage2/compare_output.zig deleted-578| ... | ... | @@ -1,578 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | |
| 3 | // self-hosted does not yet support PE executable files / COFF object files | |
| 4 | // or mach-o files. So we do these test cases cross compiling for x86_64-linux. | |
| 5 | const linux_x64 = std.zig.CrossTarget{ | |
| 6 | .cpu_arch = .x86_64, | |
| 7 | .os_tag = .linux, | |
| 8 | }; | |
| 9 | ||
| 10 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 11 | .cpu_arch = .riscv64, | |
| 12 | .os_tag = .linux, | |
| 13 | }; | |
| 14 | ||
| 15 | const wasi = std.zig.CrossTarget{ | |
| 16 | .cpu_arch = .wasm32, | |
| 17 | .os_tag = .wasi, | |
| 18 | }; | |
| 19 | ||
| 20 | pub fn addCases(ctx: *TestContext) !void { | |
| 21 | { | |
| 22 | var case = ctx.exe("hello world with updates", linux_x64); | |
| 23 | ||
| 24 | case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); | |
| 25 | ||
| 26 | case.addError( | |
| 27 | \\export fn _start() noreturn { | |
| 28 | \\} | |
| 29 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); | |
| 30 | ||
| 31 | // Regular old hello world | |
| 32 | case.addCompareOutput( | |
| 33 | \\export fn _start() noreturn { | |
| 34 | \\ print(); | |
| 35 | \\ | |
| 36 | \\ exit(); | |
| 37 | \\} | |
| 38 | \\ | |
| 39 | \\fn print() void { | |
| 40 | \\ asm volatile ("syscall" | |
| 41 | \\ : | |
| 42 | \\ : [number] "{rax}" (1), | |
| 43 | \\ [arg1] "{rdi}" (1), | |
| 44 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), | |
| 45 | \\ [arg3] "{rdx}" (14) | |
| 46 | \\ : "rcx", "r11", "memory" | |
| 47 | \\ ); | |
| 48 | \\ return; | |
| 49 | \\} | |
| 50 | \\ | |
| 51 | \\fn exit() noreturn { | |
| 52 | \\ asm volatile ("syscall" | |
| 53 | \\ : | |
| 54 | \\ : [number] "{rax}" (231), | |
| 55 | \\ [arg1] "{rdi}" (0) | |
| 56 | \\ : "rcx", "r11", "memory" | |
| 57 | \\ ); | |
| 58 | \\ unreachable; | |
| 59 | \\} | |
| 60 | , | |
| 61 | "Hello, World!\n", | |
| 62 | ); | |
| 63 | // Now change the message only | |
| 64 | case.addCompareOutput( | |
| 65 | \\export fn _start() noreturn { | |
| 66 | \\ print(); | |
| 67 | \\ | |
| 68 | \\ exit(); | |
| 69 | \\} | |
| 70 | \\ | |
| 71 | \\fn print() void { | |
| 72 | \\ asm volatile ("syscall" | |
| 73 | \\ : | |
| 74 | \\ : [number] "{rax}" (1), | |
| 75 | \\ [arg1] "{rdi}" (1), | |
| 76 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | |
| 77 | \\ [arg3] "{rdx}" (104) | |
| 78 | \\ : "rcx", "r11", "memory" | |
| 79 | \\ ); | |
| 80 | \\ return; | |
| 81 | \\} | |
| 82 | \\ | |
| 83 | \\fn exit() noreturn { | |
| 84 | \\ asm volatile ("syscall" | |
| 85 | \\ : | |
| 86 | \\ : [number] "{rax}" (231), | |
| 87 | \\ [arg1] "{rdi}" (0) | |
| 88 | \\ : "rcx", "r11", "memory" | |
| 89 | \\ ); | |
| 90 | \\ unreachable; | |
| 91 | \\} | |
| 92 | , | |
| 93 | "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", | |
| 94 | ); | |
| 95 | // Now we print it twice. | |
| 96 | case.addCompareOutput( | |
| 97 | \\export fn _start() noreturn { | |
| 98 | \\ print(); | |
| 99 | \\ print(); | |
| 100 | \\ | |
| 101 | \\ exit(); | |
| 102 | \\} | |
| 103 | \\ | |
| 104 | \\fn print() void { | |
| 105 | \\ asm volatile ("syscall" | |
| 106 | \\ : | |
| 107 | \\ : [number] "{rax}" (1), | |
| 108 | \\ [arg1] "{rdi}" (1), | |
| 109 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | |
| 110 | \\ [arg3] "{rdx}" (104) | |
| 111 | \\ : "rcx", "r11", "memory" | |
| 112 | \\ ); | |
| 113 | \\ return; | |
| 114 | \\} | |
| 115 | \\ | |
| 116 | \\fn exit() noreturn { | |
| 117 | \\ asm volatile ("syscall" | |
| 118 | \\ : | |
| 119 | \\ : [number] "{rax}" (231), | |
| 120 | \\ [arg1] "{rdi}" (0) | |
| 121 | \\ : "rcx", "r11", "memory" | |
| 122 | \\ ); | |
| 123 | \\ unreachable; | |
| 124 | \\} | |
| 125 | , | |
| 126 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | |
| 127 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | |
| 128 | \\ | |
| 129 | ); | |
| 130 | } | |
| 131 | ||
| 132 | { | |
| 133 | var case = ctx.exe("hello world", linux_riscv64); | |
| 134 | // Regular old hello world | |
| 135 | case.addCompareOutput( | |
| 136 | \\export fn _start() noreturn { | |
| 137 | \\ print(); | |
| 138 | \\ | |
| 139 | \\ exit(); | |
| 140 | \\} | |
| 141 | \\ | |
| 142 | \\fn print() void { | |
| 143 | \\ asm volatile ("ecall" | |
| 144 | \\ : | |
| 145 | \\ : [number] "{a7}" (64), | |
| 146 | \\ [arg1] "{a0}" (1), | |
| 147 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | |
| 148 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | |
| 149 | \\ : "rcx", "r11", "memory" | |
| 150 | \\ ); | |
| 151 | \\ return; | |
| 152 | \\} | |
| 153 | \\ | |
| 154 | \\fn exit() noreturn { | |
| 155 | \\ asm volatile ("ecall" | |
| 156 | \\ : | |
| 157 | \\ : [number] "{a7}" (94), | |
| 158 | \\ [arg1] "{a0}" (0) | |
| 159 | \\ : "rcx", "r11", "memory" | |
| 160 | \\ ); | |
| 161 | \\ unreachable; | |
| 162 | \\} | |
| 163 | , | |
| 164 | "Hello, World!\n", | |
| 165 | ); | |
| 166 | } | |
| 167 | ||
| 168 | { | |
| 169 | var case = ctx.exe("adding numbers at comptime", linux_x64); | |
| 170 | case.addCompareOutput( | |
| 171 | \\export fn _start() noreturn { | |
| 172 | \\ asm volatile ("syscall" | |
| 173 | \\ : | |
| 174 | \\ : [number] "{rax}" (1), | |
| 175 | \\ [arg1] "{rdi}" (1), | |
| 176 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), | |
| 177 | \\ [arg3] "{rdx}" (10 + 4) | |
| 178 | \\ : "rcx", "r11", "memory" | |
| 179 | \\ ); | |
| 180 | \\ asm volatile ("syscall" | |
| 181 | \\ : | |
| 182 | \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), | |
| 183 | \\ [arg1] "{rdi}" (0) | |
| 184 | \\ : "rcx", "r11", "memory" | |
| 185 | \\ ); | |
| 186 | \\ unreachable; | |
| 187 | \\} | |
| 188 | , | |
| 189 | "Hello, World!\n", | |
| 190 | ); | |
| 191 | } | |
| 192 | ||
| 193 | { | |
| 194 | var case = ctx.exe("adding numbers at runtime", linux_x64); | |
| 195 | case.addCompareOutput( | |
| 196 | \\export fn _start() noreturn { | |
| 197 | \\ add(3, 4); | |
| 198 | \\ | |
| 199 | \\ exit(); | |
| 200 | \\} | |
| 201 | \\ | |
| 202 | \\fn add(a: u32, b: u32) void { | |
| 203 | \\ if (a + b != 7) unreachable; | |
| 204 | \\} | |
| 205 | \\ | |
| 206 | \\fn exit() noreturn { | |
| 207 | \\ asm volatile ("syscall" | |
| 208 | \\ : | |
| 209 | \\ : [number] "{rax}" (231), | |
| 210 | \\ [arg1] "{rdi}" (0) | |
| 211 | \\ : "rcx", "r11", "memory" | |
| 212 | \\ ); | |
| 213 | \\ unreachable; | |
| 214 | \\} | |
| 215 | , | |
| 216 | "", | |
| 217 | ); | |
| 218 | } | |
| 219 | ||
| 220 | { | |
| 221 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | |
| 222 | case.addCompareOutput( | |
| 223 | \\export fn _start() noreturn { | |
| 224 | \\ sub(7, 4); | |
| 225 | \\ | |
| 226 | \\ exit(); | |
| 227 | \\} | |
| 228 | \\ | |
| 229 | \\fn sub(a: u32, b: u32) void { | |
| 230 | \\ if (a - b != 3) unreachable; | |
| 231 | \\} | |
| 232 | \\ | |
| 233 | \\fn exit() noreturn { | |
| 234 | \\ asm volatile ("syscall" | |
| 235 | \\ : | |
| 236 | \\ : [number] "{rax}" (231), | |
| 237 | \\ [arg1] "{rdi}" (0) | |
| 238 | \\ : "rcx", "r11", "memory" | |
| 239 | \\ ); | |
| 240 | \\ unreachable; | |
| 241 | \\} | |
| 242 | , | |
| 243 | "", | |
| 244 | ); | |
| 245 | } | |
| 246 | ||
| 247 | { | |
| 248 | var case = ctx.exe("assert function", linux_x64); | |
| 249 | case.addCompareOutput( | |
| 250 | \\export fn _start() noreturn { | |
| 251 | \\ add(3, 4); | |
| 252 | \\ | |
| 253 | \\ exit(); | |
| 254 | \\} | |
| 255 | \\ | |
| 256 | \\fn add(a: u32, b: u32) void { | |
| 257 | \\ assert(a + b == 7); | |
| 258 | \\} | |
| 259 | \\ | |
| 260 | \\pub fn assert(ok: bool) void { | |
| 261 | \\ if (!ok) unreachable; // assertion failure | |
| 262 | \\} | |
| 263 | \\ | |
| 264 | \\fn exit() noreturn { | |
| 265 | \\ asm volatile ("syscall" | |
| 266 | \\ : | |
| 267 | \\ : [number] "{rax}" (231), | |
| 268 | \\ [arg1] "{rdi}" (0) | |
| 269 | \\ : "rcx", "r11", "memory" | |
| 270 | \\ ); | |
| 271 | \\ unreachable; | |
| 272 | \\} | |
| 273 | , | |
| 274 | "", | |
| 275 | ); | |
| 276 | ||
| 277 | // Tests copying a register. For the `c = a + b`, it has to | |
| 278 | // preserve both a and b, because they are both used later. | |
| 279 | case.addCompareOutput( | |
| 280 | \\export fn _start() noreturn { | |
| 281 | \\ add(3, 4); | |
| 282 | \\ | |
| 283 | \\ exit(); | |
| 284 | \\} | |
| 285 | \\ | |
| 286 | \\fn add(a: u32, b: u32) void { | |
| 287 | \\ const c = a + b; // 7 | |
| 288 | \\ const d = a + c; // 10 | |
| 289 | \\ const e = d + b; // 14 | |
| 290 | \\ assert(e == 14); | |
| 291 | \\} | |
| 292 | \\ | |
| 293 | \\pub fn assert(ok: bool) void { | |
| 294 | \\ if (!ok) unreachable; // assertion failure | |
| 295 | \\} | |
| 296 | \\ | |
| 297 | \\fn exit() noreturn { | |
| 298 | \\ asm volatile ("syscall" | |
| 299 | \\ : | |
| 300 | \\ : [number] "{rax}" (231), | |
| 301 | \\ [arg1] "{rdi}" (0) | |
| 302 | \\ : "rcx", "r11", "memory" | |
| 303 | \\ ); | |
| 304 | \\ unreachable; | |
| 305 | \\} | |
| 306 | , | |
| 307 | "", | |
| 308 | ); | |
| 309 | ||
| 310 | // More stress on the liveness detection. | |
| 311 | case.addCompareOutput( | |
| 312 | \\export fn _start() noreturn { | |
| 313 | \\ add(3, 4); | |
| 314 | \\ | |
| 315 | \\ exit(); | |
| 316 | \\} | |
| 317 | \\ | |
| 318 | \\fn add(a: u32, b: u32) void { | |
| 319 | \\ const c = a + b; // 7 | |
| 320 | \\ const d = a + c; // 10 | |
| 321 | \\ const e = d + b; // 14 | |
| 322 | \\ const f = d + e; // 24 | |
| 323 | \\ const g = e + f; // 38 | |
| 324 | \\ const h = f + g; // 62 | |
| 325 | \\ const i = g + h; // 100 | |
| 326 | \\ assert(i == 100); | |
| 327 | \\} | |
| 328 | \\ | |
| 329 | \\pub fn assert(ok: bool) void { | |
| 330 | \\ if (!ok) unreachable; // assertion failure | |
| 331 | \\} | |
| 332 | \\ | |
| 333 | \\fn exit() noreturn { | |
| 334 | \\ asm volatile ("syscall" | |
| 335 | \\ : | |
| 336 | \\ : [number] "{rax}" (231), | |
| 337 | \\ [arg1] "{rdi}" (0) | |
| 338 | \\ : "rcx", "r11", "memory" | |
| 339 | \\ ); | |
| 340 | \\ unreachable; | |
| 341 | \\} | |
| 342 | , | |
| 343 | "", | |
| 344 | ); | |
| 345 | ||
| 346 | // Requires a second move. The register allocator should figure out to re-use rax. | |
| 347 | case.addCompareOutput( | |
| 348 | \\export fn _start() noreturn { | |
| 349 | \\ add(3, 4); | |
| 350 | \\ | |
| 351 | \\ exit(); | |
| 352 | \\} | |
| 353 | \\ | |
| 354 | \\fn add(a: u32, b: u32) void { | |
| 355 | \\ const c = a + b; // 7 | |
| 356 | \\ const d = a + c; // 10 | |
| 357 | \\ const e = d + b; // 14 | |
| 358 | \\ const f = d + e; // 24 | |
| 359 | \\ const g = e + f; // 38 | |
| 360 | \\ const h = f + g; // 62 | |
| 361 | \\ const i = g + h; // 100 | |
| 362 | \\ const j = i + d; // 110 | |
| 363 | \\ assert(j == 110); | |
| 364 | \\} | |
| 365 | \\ | |
| 366 | \\pub fn assert(ok: bool) void { | |
| 367 | \\ if (!ok) unreachable; // assertion failure | |
| 368 | \\} | |
| 369 | \\ | |
| 370 | \\fn exit() noreturn { | |
| 371 | \\ asm volatile ("syscall" | |
| 372 | \\ : | |
| 373 | \\ : [number] "{rax}" (231), | |
| 374 | \\ [arg1] "{rdi}" (0) | |
| 375 | \\ : "rcx", "r11", "memory" | |
| 376 | \\ ); | |
| 377 | \\ unreachable; | |
| 378 | \\} | |
| 379 | , | |
| 380 | "", | |
| 381 | ); | |
| 382 | ||
| 383 | // Now we test integer return values. | |
| 384 | case.addCompareOutput( | |
| 385 | \\export fn _start() noreturn { | |
| 386 | \\ assert(add(3, 4) == 7); | |
| 387 | \\ assert(add(20, 10) == 30); | |
| 388 | \\ | |
| 389 | \\ exit(); | |
| 390 | \\} | |
| 391 | \\ | |
| 392 | \\fn add(a: u32, b: u32) u32 { | |
| 393 | \\ return a + b; | |
| 394 | \\} | |
| 395 | \\ | |
| 396 | \\pub fn assert(ok: bool) void { | |
| 397 | \\ if (!ok) unreachable; // assertion failure | |
| 398 | \\} | |
| 399 | \\ | |
| 400 | \\fn exit() noreturn { | |
| 401 | \\ asm volatile ("syscall" | |
| 402 | \\ : | |
| 403 | \\ : [number] "{rax}" (231), | |
| 404 | \\ [arg1] "{rdi}" (0) | |
| 405 | \\ : "rcx", "r11", "memory" | |
| 406 | \\ ); | |
| 407 | \\ unreachable; | |
| 408 | \\} | |
| 409 | , | |
| 410 | "", | |
| 411 | ); | |
| 412 | ||
| 413 | // Local mutable variables. | |
| 414 | case.addCompareOutput( | |
| 415 | \\export fn _start() noreturn { | |
| 416 | \\ assert(add(3, 4) == 7); | |
| 417 | \\ assert(add(20, 10) == 30); | |
| 418 | \\ | |
| 419 | \\ exit(); | |
| 420 | \\} | |
| 421 | \\ | |
| 422 | \\fn add(a: u32, b: u32) u32 { | |
| 423 | \\ var x: u32 = undefined; | |
| 424 | \\ x = 0; | |
| 425 | \\ x += a; | |
| 426 | \\ x += b; | |
| 427 | \\ return x; | |
| 428 | \\} | |
| 429 | \\ | |
| 430 | \\pub fn assert(ok: bool) void { | |
| 431 | \\ if (!ok) unreachable; // assertion failure | |
| 432 | \\} | |
| 433 | \\ | |
| 434 | \\fn exit() noreturn { | |
| 435 | \\ asm volatile ("syscall" | |
| 436 | \\ : | |
| 437 | \\ : [number] "{rax}" (231), | |
| 438 | \\ [arg1] "{rdi}" (0) | |
| 439 | \\ : "rcx", "r11", "memory" | |
| 440 | \\ ); | |
| 441 | \\ unreachable; | |
| 442 | \\} | |
| 443 | , | |
| 444 | "", | |
| 445 | ); | |
| 446 | ||
| 447 | // Optionals | |
| 448 | case.addCompareOutput( | |
| 449 | \\export fn _start() noreturn { | |
| 450 | \\ const a: u32 = 2; | |
| 451 | \\ const b: ?u32 = a; | |
| 452 | \\ const c = b.?; | |
| 453 | \\ if (c != 2) unreachable; | |
| 454 | \\ | |
| 455 | \\ exit(); | |
| 456 | \\} | |
| 457 | \\ | |
| 458 | \\fn exit() noreturn { | |
| 459 | \\ asm volatile ("syscall" | |
| 460 | \\ : | |
| 461 | \\ : [number] "{rax}" (231), | |
| 462 | \\ [arg1] "{rdi}" (0) | |
| 463 | \\ : "rcx", "r11", "memory" | |
| 464 | \\ ); | |
| 465 | \\ unreachable; | |
| 466 | \\} | |
| 467 | , | |
| 468 | "", | |
| 469 | ); | |
| 470 | ||
| 471 | // While loops | |
| 472 | case.addCompareOutput( | |
| 473 | \\export fn _start() noreturn { | |
| 474 | \\ var i: u32 = 0; | |
| 475 | \\ while (i < 4) : (i += 1) print(); | |
| 476 | \\ assert(i == 4); | |
| 477 | \\ | |
| 478 | \\ exit(); | |
| 479 | \\} | |
| 480 | \\ | |
| 481 | \\fn print() void { | |
| 482 | \\ asm volatile ("syscall" | |
| 483 | \\ : | |
| 484 | \\ : [number] "{rax}" (1), | |
| 485 | \\ [arg1] "{rdi}" (1), | |
| 486 | \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), | |
| 487 | \\ [arg3] "{rdx}" (6) | |
| 488 | \\ : "rcx", "r11", "memory" | |
| 489 | \\ ); | |
| 490 | \\ return; | |
| 491 | \\} | |
| 492 | \\ | |
| 493 | \\pub fn assert(ok: bool) void { | |
| 494 | \\ if (!ok) unreachable; // assertion failure | |
| 495 | \\} | |
| 496 | \\ | |
| 497 | \\fn exit() noreturn { | |
| 498 | \\ asm volatile ("syscall" | |
| 499 | \\ : | |
| 500 | \\ : [number] "{rax}" (231), | |
| 501 | \\ [arg1] "{rdi}" (0) | |
| 502 | \\ : "rcx", "r11", "memory" | |
| 503 | \\ ); | |
| 504 | \\ unreachable; | |
| 505 | \\} | |
| 506 | , | |
| 507 | "hello\nhello\nhello\nhello\n", | |
| 508 | ); | |
| 509 | ||
| 510 | // Labeled blocks (no conditional branch) | |
| 511 | case.addCompareOutput( | |
| 512 | \\export fn _start() noreturn { | |
| 513 | \\ assert(add(3, 4) == 20); | |
| 514 | \\ | |
| 515 | \\ exit(); | |
| 516 | \\} | |
| 517 | \\ | |
| 518 | \\fn add(a: u32, b: u32) u32 { | |
| 519 | \\ const x: u32 = blk: { | |
| 520 | \\ const c = a + b; // 7 | |
| 521 | \\ const d = a + c; // 10 | |
| 522 | \\ const e = d + b; // 14 | |
| 523 | \\ break :blk e; | |
| 524 | \\ }; | |
| 525 | \\ const y = x + a; // 17 | |
| 526 | \\ const z = y + a; // 20 | |
| 527 | \\ return z; | |
| 528 | \\} | |
| 529 | \\ | |
| 530 | \\pub fn assert(ok: bool) void { | |
| 531 | \\ if (!ok) unreachable; // assertion failure | |
| 532 | \\} | |
| 533 | \\ | |
| 534 | \\fn exit() noreturn { | |
| 535 | \\ asm volatile ("syscall" | |
| 536 | \\ : | |
| 537 | \\ : [number] "{rax}" (231), | |
| 538 | \\ [arg1] "{rdi}" (0) | |
| 539 | \\ : "rcx", "r11", "memory" | |
| 540 | \\ ); | |
| 541 | \\ unreachable; | |
| 542 | \\} | |
| 543 | , | |
| 544 | "", | |
| 545 | ); | |
| 546 | } | |
| 547 | ||
| 548 | { | |
| 549 | var case = ctx.exe("wasm returns", wasi); | |
| 550 | ||
| 551 | case.addCompareOutput( | |
| 552 | \\export fn _start() u32 { | |
| 553 | \\ return 42; | |
| 554 | \\} | |
| 555 | , | |
| 556 | "42\n", | |
| 557 | ); | |
| 558 | ||
| 559 | case.addCompareOutput( | |
| 560 | \\export fn _start() i64 { | |
| 561 | \\ return 42; | |
| 562 | \\} | |
| 563 | , | |
| 564 | "42\n", | |
| 565 | ); | |
| 566 | ||
| 567 | case.addCompareOutput( | |
| 568 | \\export fn _start() f32 { | |
| 569 | \\ return 42.0; | |
| 570 | \\} | |
| 571 | , | |
| 572 | // This is what you get when you take the bits of the IEE-754 | |
| 573 | // representation of 42.0 and reinterpret them as an unsigned | |
| 574 | // integer. Guess that's a bug in wasmtime. | |
| 575 | "1109917696\n", | |
| 576 | ); | |
| 577 | } | |
| 578 | } |
test/stage2/compile_errors.zig deleted-135| ... | ... | @@ -1,135 +0,0 @@ |
| 1 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | |
| 2 | const std = @import("std"); | |
| 3 | ||
| 4 | const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg; | |
| 5 | ||
| 6 | const linux_x64 = std.zig.CrossTarget{ | |
| 7 | .cpu_arch = .x86_64, | |
| 8 | .os_tag = .linux, | |
| 9 | }; | |
| 10 | ||
| 11 | pub fn addCases(ctx: *TestContext) !void { | |
| 12 | ctx.compileErrorZIR("call undefined local", linux_x64, | |
| 13 | \\@noreturn = primitive(noreturn) | |
| 14 | \\ | |
| 15 | \\@start_fnty = fntype([], @noreturn, cc=Naked) | |
| 16 | \\@start = fn(@start_fnty, { | |
| 17 | \\ %0 = call(%test, []) | |
| 18 | \\}) | |
| 19 | // TODO: address inconsistency in this message and the one in the next test | |
| 20 | , &[_][]const u8{":5:13: error: unrecognized identifier: %test"}); | |
| 21 | ||
| 22 | ctx.compileErrorZIR("call with non-existent target", linux_x64, | |
| 23 | \\@noreturn = primitive(noreturn) | |
| 24 | \\ | |
| 25 | \\@start_fnty = fntype([], @noreturn, cc=Naked) | |
| 26 | \\@start = fn(@start_fnty, { | |
| 27 | \\ %0 = call(@notafunc, []) | |
| 28 | \\}) | |
| 29 | \\@0 = str("_start") | |
| 30 | \\@1 = export(@0, "start") | |
| 31 | , &[_][]const u8{":5:13: error: decl 'notafunc' not found"}); | |
| 32 | ||
| 33 | // TODO: this error should occur at the call site, not the fntype decl | |
| 34 | ctx.compileErrorZIR("call naked function", linux_x64, | |
| 35 | \\@noreturn = primitive(noreturn) | |
| 36 | \\ | |
| 37 | \\@start_fnty = fntype([], @noreturn, cc=Naked) | |
| 38 | \\@s = fn(@start_fnty, {}) | |
| 39 | \\@start = fn(@start_fnty, { | |
| 40 | \\ %0 = call(@s, []) | |
| 41 | \\}) | |
| 42 | \\@0 = str("_start") | |
| 43 | \\@1 = export(@0, "start") | |
| 44 | , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"}); | |
| 45 | ||
| 46 | ctx.incrementalFailureZIR("exported symbol collision", linux_x64, | |
| 47 | \\@noreturn = primitive(noreturn) | |
| 48 | \\ | |
| 49 | \\@start_fnty = fntype([], @noreturn) | |
| 50 | \\@start = fn(@start_fnty, {}) | |
| 51 | \\ | |
| 52 | \\@0 = str("_start") | |
| 53 | \\@1 = export(@0, "start") | |
| 54 | \\@2 = export(@0, "start") | |
| 55 | , &[_][]const u8{":8:13: error: exported symbol collision: _start"}, | |
| 56 | \\@noreturn = primitive(noreturn) | |
| 57 | \\ | |
| 58 | \\@start_fnty = fntype([], @noreturn) | |
| 59 | \\@start = fn(@start_fnty, {}) | |
| 60 | \\ | |
| 61 | \\@0 = str("_start") | |
| 62 | \\@1 = export(@0, "start") | |
| 63 | ); | |
| 64 | ||
| 65 | ctx.compileError("function redefinition", linux_x64, | |
| 66 | \\fn entry() void {} | |
| 67 | \\fn entry() void {} | |
| 68 | , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); | |
| 69 | ||
| 70 | //ctx.incrementalFailure("function redefinition", linux_x64, | |
| 71 | // \\fn entry() void {} | |
| 72 | // \\fn entry() void {} | |
| 73 | //, &[_][]const u8{":2:4: error: redefinition of 'entry'"}, | |
| 74 | // \\fn entry() void {} | |
| 75 | //); | |
| 76 | ||
| 77 | //// TODO: need to make sure this works with other variants of export. | |
| 78 | //ctx.incrementalFailure("exported symbol collision", linux_x64, | |
| 79 | // \\export fn entry() void {} | |
| 80 | // \\export fn entry() void {} | |
| 81 | //, &[_][]const u8{":2:11: error: redefinition of 'entry'"}, | |
| 82 | // \\export fn entry() void {} | |
| 83 | //); | |
| 84 | ||
| 85 | // ctx.incrementalFailure("missing function name", linux_x64, | |
| 86 | // \\fn() void {} | |
| 87 | // , &[_][]const u8{":1:3: error: missing function name"}, | |
| 88 | // \\fn a() void {} | |
| 89 | // ); | |
| 90 | ||
| 91 | // TODO: re-enable these tests. | |
| 92 | // https://github.com/ziglang/zig/issues/1364 | |
| 93 | ||
| 94 | //ctx.testCompileError( | |
| 95 | // \\comptime { | |
| 96 | // \\ return; | |
| 97 | // \\} | |
| 98 | //, "1.zig", 2, 5, "return expression outside function definition"); | |
| 99 | ||
| 100 | //ctx.testCompileError( | |
| 101 | // \\export fn entry() void { | |
| 102 | // \\ defer return; | |
| 103 | // \\} | |
| 104 | //, "1.zig", 2, 11, "cannot return from defer expression"); | |
| 105 | ||
| 106 | //ctx.testCompileError( | |
| 107 | // \\export fn entry() c_int { | |
| 108 | // \\ return 36893488147419103232; | |
| 109 | // \\} | |
| 110 | //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); | |
| 111 | ||
| 112 | //ctx.testCompileError( | |
| 113 | // \\comptime { | |
| 114 | // \\ var a: *align(4) align(4) i32 = 0; | |
| 115 | // \\} | |
| 116 | //, "1.zig", 2, 22, "Extra align qualifier"); | |
| 117 | ||
| 118 | //ctx.testCompileError( | |
| 119 | // \\comptime { | |
| 120 | // \\ var b: *const const i32 = 0; | |
| 121 | // \\} | |
| 122 | //, "1.zig", 2, 19, "Extra align qualifier"); | |
| 123 | ||
| 124 | //ctx.testCompileError( | |
| 125 | // \\comptime { | |
| 126 | // \\ var c: *volatile volatile i32 = 0; | |
| 127 | // \\} | |
| 128 | //, "1.zig", 2, 22, "Extra align qualifier"); | |
| 129 | ||
| 130 | //ctx.testCompileError( | |
| 131 | // \\comptime { | |
| 132 | // \\ var d: *allowzero allowzero i32 = 0; | |
| 133 | // \\} | |
| 134 | //, "1.zig", 2, 23, "Extra align qualifier"); | |
| 135 | } |
test/stage2/test.zig+730-2| ... | ... | @@ -1,8 +1,736 @@ |
| 1 | const std = @import("std"); | |
| 1 | 2 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; |
| 2 | 3 | |
| 4 | // self-hosted does not yet support PE executable files / COFF object files | |
| 5 | // or mach-o files. So we do these test cases cross compiling for x86_64-linux. | |
| 6 | const linux_x64 = std.zig.CrossTarget{ | |
| 7 | .cpu_arch = .x86_64, | |
| 8 | .os_tag = .linux, | |
| 9 | }; | |
| 10 | ||
| 11 | const macosx_x64 = std.zig.CrossTarget{ | |
| 12 | .cpu_arch = .x86_64, | |
| 13 | .os_tag = .macosx, | |
| 14 | }; | |
| 15 | ||
| 16 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 17 | .cpu_arch = .riscv64, | |
| 18 | .os_tag = .linux, | |
| 19 | }; | |
| 20 | ||
| 21 | const wasi = std.zig.CrossTarget{ | |
| 22 | .cpu_arch = .wasm32, | |
| 23 | .os_tag = .wasi, | |
| 24 | }; | |
| 25 | ||
| 3 | 26 | pub fn addCases(ctx: *TestContext) !void { |
| 4 | try @import("compile_errors.zig").addCases(ctx); | |
| 5 | try @import("compare_output.zig").addCases(ctx); | |
| 6 | 27 | try @import("zir.zig").addCases(ctx); |
| 7 | 28 | try @import("cbe.zig").addCases(ctx); |
| 29 | { | |
| 30 | var case = ctx.exe("hello world with updates", linux_x64); | |
| 31 | ||
| 32 | case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); | |
| 33 | ||
| 34 | // Incorrect return type | |
| 35 | case.addError( | |
| 36 | \\export fn _start() noreturn { | |
| 37 | \\} | |
| 38 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); | |
| 39 | ||
| 40 | // Regular old hello world | |
| 41 | case.addCompareOutput( | |
| 42 | \\export fn _start() noreturn { | |
| 43 | \\ print(); | |
| 44 | \\ | |
| 45 | \\ exit(); | |
| 46 | \\} | |
| 47 | \\ | |
| 48 | \\fn print() void { | |
| 49 | \\ asm volatile ("syscall" | |
| 50 | \\ : | |
| 51 | \\ : [number] "{rax}" (1), | |
| 52 | \\ [arg1] "{rdi}" (1), | |
| 53 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), | |
| 54 | \\ [arg3] "{rdx}" (14) | |
| 55 | \\ : "rcx", "r11", "memory" | |
| 56 | \\ ); | |
| 57 | \\ return; | |
| 58 | \\} | |
| 59 | \\ | |
| 60 | \\fn exit() noreturn { | |
| 61 | \\ asm volatile ("syscall" | |
| 62 | \\ : | |
| 63 | \\ : [number] "{rax}" (231), | |
| 64 | \\ [arg1] "{rdi}" (0) | |
| 65 | \\ : "rcx", "r11", "memory" | |
| 66 | \\ ); | |
| 67 | \\ unreachable; | |
| 68 | \\} | |
| 69 | , | |
| 70 | "Hello, World!\n", | |
| 71 | ); | |
| 72 | // Now change the message only | |
| 73 | case.addCompareOutput( | |
| 74 | \\export fn _start() noreturn { | |
| 75 | \\ print(); | |
| 76 | \\ | |
| 77 | \\ exit(); | |
| 78 | \\} | |
| 79 | \\ | |
| 80 | \\fn print() void { | |
| 81 | \\ asm volatile ("syscall" | |
| 82 | \\ : | |
| 83 | \\ : [number] "{rax}" (1), | |
| 84 | \\ [arg1] "{rdi}" (1), | |
| 85 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | |
| 86 | \\ [arg3] "{rdx}" (104) | |
| 87 | \\ : "rcx", "r11", "memory" | |
| 88 | \\ ); | |
| 89 | \\ return; | |
| 90 | \\} | |
| 91 | \\ | |
| 92 | \\fn exit() noreturn { | |
| 93 | \\ asm volatile ("syscall" | |
| 94 | \\ : | |
| 95 | \\ : [number] "{rax}" (231), | |
| 96 | \\ [arg1] "{rdi}" (0) | |
| 97 | \\ : "rcx", "r11", "memory" | |
| 98 | \\ ); | |
| 99 | \\ unreachable; | |
| 100 | \\} | |
| 101 | , | |
| 102 | "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", | |
| 103 | ); | |
| 104 | // Now we print it twice. | |
| 105 | case.addCompareOutput( | |
| 106 | \\export fn _start() noreturn { | |
| 107 | \\ print(); | |
| 108 | \\ print(); | |
| 109 | \\ | |
| 110 | \\ exit(); | |
| 111 | \\} | |
| 112 | \\ | |
| 113 | \\fn print() void { | |
| 114 | \\ asm volatile ("syscall" | |
| 115 | \\ : | |
| 116 | \\ : [number] "{rax}" (1), | |
| 117 | \\ [arg1] "{rdi}" (1), | |
| 118 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | |
| 119 | \\ [arg3] "{rdx}" (104) | |
| 120 | \\ : "rcx", "r11", "memory" | |
| 121 | \\ ); | |
| 122 | \\ return; | |
| 123 | \\} | |
| 124 | \\ | |
| 125 | \\fn exit() noreturn { | |
| 126 | \\ asm volatile ("syscall" | |
| 127 | \\ : | |
| 128 | \\ : [number] "{rax}" (231), | |
| 129 | \\ [arg1] "{rdi}" (0) | |
| 130 | \\ : "rcx", "r11", "memory" | |
| 131 | \\ ); | |
| 132 | \\ unreachable; | |
| 133 | \\} | |
| 134 | , | |
| 135 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | |
| 136 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | |
| 137 | \\ | |
| 138 | ); | |
| 139 | } | |
| 140 | ||
| 141 | { | |
| 142 | var case = ctx.exe("hello world", macosx_x64); | |
| 143 | case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); | |
| 144 | } | |
| 145 | ||
| 146 | { | |
| 147 | var case = ctx.exe("hello world", linux_riscv64); | |
| 148 | // Regular old hello world | |
| 149 | case.addCompareOutput( | |
| 150 | \\export fn _start() noreturn { | |
| 151 | \\ print(); | |
| 152 | \\ | |
| 153 | \\ exit(); | |
| 154 | \\} | |
| 155 | \\ | |
| 156 | \\fn print() void { | |
| 157 | \\ asm volatile ("ecall" | |
| 158 | \\ : | |
| 159 | \\ : [number] "{a7}" (64), | |
| 160 | \\ [arg1] "{a0}" (1), | |
| 161 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | |
| 162 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | |
| 163 | \\ : "rcx", "r11", "memory" | |
| 164 | \\ ); | |
| 165 | \\ return; | |
| 166 | \\} | |
| 167 | \\ | |
| 168 | \\fn exit() noreturn { | |
| 169 | \\ asm volatile ("ecall" | |
| 170 | \\ : | |
| 171 | \\ : [number] "{a7}" (94), | |
| 172 | \\ [arg1] "{a0}" (0) | |
| 173 | \\ : "rcx", "r11", "memory" | |
| 174 | \\ ); | |
| 175 | \\ unreachable; | |
| 176 | \\} | |
| 177 | , | |
| 178 | "Hello, World!\n", | |
| 179 | ); | |
| 180 | } | |
| 181 | ||
| 182 | { | |
| 183 | var case = ctx.exe("adding numbers at comptime", linux_x64); | |
| 184 | case.addCompareOutput( | |
| 185 | \\export fn _start() noreturn { | |
| 186 | \\ asm volatile ("syscall" | |
| 187 | \\ : | |
| 188 | \\ : [number] "{rax}" (1), | |
| 189 | \\ [arg1] "{rdi}" (1), | |
| 190 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), | |
| 191 | \\ [arg3] "{rdx}" (10 + 4) | |
| 192 | \\ : "rcx", "r11", "memory" | |
| 193 | \\ ); | |
| 194 | \\ asm volatile ("syscall" | |
| 195 | \\ : | |
| 196 | \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), | |
| 197 | \\ [arg1] "{rdi}" (0) | |
| 198 | \\ : "rcx", "r11", "memory" | |
| 199 | \\ ); | |
| 200 | \\ unreachable; | |
| 201 | \\} | |
| 202 | , | |
| 203 | "Hello, World!\n", | |
| 204 | ); | |
| 205 | } | |
| 206 | ||
| 207 | { | |
| 208 | var case = ctx.exe("adding numbers at runtime", linux_x64); | |
| 209 | case.addCompareOutput( | |
| 210 | \\export fn _start() noreturn { | |
| 211 | \\ add(3, 4); | |
| 212 | \\ | |
| 213 | \\ exit(); | |
| 214 | \\} | |
| 215 | \\ | |
| 216 | \\fn add(a: u32, b: u32) void { | |
| 217 | \\ if (a + b != 7) unreachable; | |
| 218 | \\} | |
| 219 | \\ | |
| 220 | \\fn exit() noreturn { | |
| 221 | \\ asm volatile ("syscall" | |
| 222 | \\ : | |
| 223 | \\ : [number] "{rax}" (231), | |
| 224 | \\ [arg1] "{rdi}" (0) | |
| 225 | \\ : "rcx", "r11", "memory" | |
| 226 | \\ ); | |
| 227 | \\ unreachable; | |
| 228 | \\} | |
| 229 | , | |
| 230 | "", | |
| 231 | ); | |
| 232 | } | |
| 233 | ||
| 234 | { | |
| 235 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | |
| 236 | case.addCompareOutput( | |
| 237 | \\export fn _start() noreturn { | |
| 238 | \\ sub(7, 4); | |
| 239 | \\ | |
| 240 | \\ exit(); | |
| 241 | \\} | |
| 242 | \\ | |
| 243 | \\fn sub(a: u32, b: u32) void { | |
| 244 | \\ if (a - b != 3) unreachable; | |
| 245 | \\} | |
| 246 | \\ | |
| 247 | \\fn exit() noreturn { | |
| 248 | \\ asm volatile ("syscall" | |
| 249 | \\ : | |
| 250 | \\ : [number] "{rax}" (231), | |
| 251 | \\ [arg1] "{rdi}" (0) | |
| 252 | \\ : "rcx", "r11", "memory" | |
| 253 | \\ ); | |
| 254 | \\ unreachable; | |
| 255 | \\} | |
| 256 | , | |
| 257 | "", | |
| 258 | ); | |
| 259 | } | |
| 260 | ||
| 261 | { | |
| 262 | var case = ctx.exe("assert function", linux_x64); | |
| 263 | case.addCompareOutput( | |
| 264 | \\export fn _start() noreturn { | |
| 265 | \\ add(3, 4); | |
| 266 | \\ | |
| 267 | \\ exit(); | |
| 268 | \\} | |
| 269 | \\ | |
| 270 | \\fn add(a: u32, b: u32) void { | |
| 271 | \\ assert(a + b == 7); | |
| 272 | \\} | |
| 273 | \\ | |
| 274 | \\pub fn assert(ok: bool) void { | |
| 275 | \\ if (!ok) unreachable; // assertion failure | |
| 276 | \\} | |
| 277 | \\ | |
| 278 | \\fn exit() noreturn { | |
| 279 | \\ asm volatile ("syscall" | |
| 280 | \\ : | |
| 281 | \\ : [number] "{rax}" (231), | |
| 282 | \\ [arg1] "{rdi}" (0) | |
| 283 | \\ : "rcx", "r11", "memory" | |
| 284 | \\ ); | |
| 285 | \\ unreachable; | |
| 286 | \\} | |
| 287 | , | |
| 288 | "", | |
| 289 | ); | |
| 290 | ||
| 291 | // Tests copying a register. For the `c = a + b`, it has to | |
| 292 | // preserve both a and b, because they are both used later. | |
| 293 | case.addCompareOutput( | |
| 294 | \\export fn _start() noreturn { | |
| 295 | \\ add(3, 4); | |
| 296 | \\ | |
| 297 | \\ exit(); | |
| 298 | \\} | |
| 299 | \\ | |
| 300 | \\fn add(a: u32, b: u32) void { | |
| 301 | \\ const c = a + b; // 7 | |
| 302 | \\ const d = a + c; // 10 | |
| 303 | \\ const e = d + b; // 14 | |
| 304 | \\ assert(e == 14); | |
| 305 | \\} | |
| 306 | \\ | |
| 307 | \\pub fn assert(ok: bool) void { | |
| 308 | \\ if (!ok) unreachable; // assertion failure | |
| 309 | \\} | |
| 310 | \\ | |
| 311 | \\fn exit() noreturn { | |
| 312 | \\ asm volatile ("syscall" | |
| 313 | \\ : | |
| 314 | \\ : [number] "{rax}" (231), | |
| 315 | \\ [arg1] "{rdi}" (0) | |
| 316 | \\ : "rcx", "r11", "memory" | |
| 317 | \\ ); | |
| 318 | \\ unreachable; | |
| 319 | \\} | |
| 320 | , | |
| 321 | "", | |
| 322 | ); | |
| 323 | ||
| 324 | // More stress on the liveness detection. | |
| 325 | case.addCompareOutput( | |
| 326 | \\export fn _start() noreturn { | |
| 327 | \\ add(3, 4); | |
| 328 | \\ | |
| 329 | \\ exit(); | |
| 330 | \\} | |
| 331 | \\ | |
| 332 | \\fn add(a: u32, b: u32) void { | |
| 333 | \\ const c = a + b; // 7 | |
| 334 | \\ const d = a + c; // 10 | |
| 335 | \\ const e = d + b; // 14 | |
| 336 | \\ const f = d + e; // 24 | |
| 337 | \\ const g = e + f; // 38 | |
| 338 | \\ const h = f + g; // 62 | |
| 339 | \\ const i = g + h; // 100 | |
| 340 | \\ assert(i == 100); | |
| 341 | \\} | |
| 342 | \\ | |
| 343 | \\pub fn assert(ok: bool) void { | |
| 344 | \\ if (!ok) unreachable; // assertion failure | |
| 345 | \\} | |
| 346 | \\ | |
| 347 | \\fn exit() noreturn { | |
| 348 | \\ asm volatile ("syscall" | |
| 349 | \\ : | |
| 350 | \\ : [number] "{rax}" (231), | |
| 351 | \\ [arg1] "{rdi}" (0) | |
| 352 | \\ : "rcx", "r11", "memory" | |
| 353 | \\ ); | |
| 354 | \\ unreachable; | |
| 355 | \\} | |
| 356 | , | |
| 357 | "", | |
| 358 | ); | |
| 359 | ||
| 360 | // Requires a second move. The register allocator should figure out to re-use rax. | |
| 361 | case.addCompareOutput( | |
| 362 | \\export fn _start() noreturn { | |
| 363 | \\ add(3, 4); | |
| 364 | \\ | |
| 365 | \\ exit(); | |
| 366 | \\} | |
| 367 | \\ | |
| 368 | \\fn add(a: u32, b: u32) void { | |
| 369 | \\ const c = a + b; // 7 | |
| 370 | \\ const d = a + c; // 10 | |
| 371 | \\ const e = d + b; // 14 | |
| 372 | \\ const f = d + e; // 24 | |
| 373 | \\ const g = e + f; // 38 | |
| 374 | \\ const h = f + g; // 62 | |
| 375 | \\ const i = g + h; // 100 | |
| 376 | \\ const j = i + d; // 110 | |
| 377 | \\ assert(j == 110); | |
| 378 | \\} | |
| 379 | \\ | |
| 380 | \\pub fn assert(ok: bool) void { | |
| 381 | \\ if (!ok) unreachable; // assertion failure | |
| 382 | \\} | |
| 383 | \\ | |
| 384 | \\fn exit() noreturn { | |
| 385 | \\ asm volatile ("syscall" | |
| 386 | \\ : | |
| 387 | \\ : [number] "{rax}" (231), | |
| 388 | \\ [arg1] "{rdi}" (0) | |
| 389 | \\ : "rcx", "r11", "memory" | |
| 390 | \\ ); | |
| 391 | \\ unreachable; | |
| 392 | \\} | |
| 393 | , | |
| 394 | "", | |
| 395 | ); | |
| 396 | ||
| 397 | // Now we test integer return values. | |
| 398 | case.addCompareOutput( | |
| 399 | \\export fn _start() noreturn { | |
| 400 | \\ assert(add(3, 4) == 7); | |
| 401 | \\ assert(add(20, 10) == 30); | |
| 402 | \\ | |
| 403 | \\ exit(); | |
| 404 | \\} | |
| 405 | \\ | |
| 406 | \\fn add(a: u32, b: u32) u32 { | |
| 407 | \\ return a + b; | |
| 408 | \\} | |
| 409 | \\ | |
| 410 | \\pub fn assert(ok: bool) void { | |
| 411 | \\ if (!ok) unreachable; // assertion failure | |
| 412 | \\} | |
| 413 | \\ | |
| 414 | \\fn exit() noreturn { | |
| 415 | \\ asm volatile ("syscall" | |
| 416 | \\ : | |
| 417 | \\ : [number] "{rax}" (231), | |
| 418 | \\ [arg1] "{rdi}" (0) | |
| 419 | \\ : "rcx", "r11", "memory" | |
| 420 | \\ ); | |
| 421 | \\ unreachable; | |
| 422 | \\} | |
| 423 | , | |
| 424 | "", | |
| 425 | ); | |
| 426 | ||
| 427 | // Local mutable variables. | |
| 428 | case.addCompareOutput( | |
| 429 | \\export fn _start() noreturn { | |
| 430 | \\ assert(add(3, 4) == 7); | |
| 431 | \\ assert(add(20, 10) == 30); | |
| 432 | \\ | |
| 433 | \\ exit(); | |
| 434 | \\} | |
| 435 | \\ | |
| 436 | \\fn add(a: u32, b: u32) u32 { | |
| 437 | \\ var x: u32 = undefined; | |
| 438 | \\ x = 0; | |
| 439 | \\ x += a; | |
| 440 | \\ x += b; | |
| 441 | \\ return x; | |
| 442 | \\} | |
| 443 | \\ | |
| 444 | \\pub fn assert(ok: bool) void { | |
| 445 | \\ if (!ok) unreachable; // assertion failure | |
| 446 | \\} | |
| 447 | \\ | |
| 448 | \\fn exit() noreturn { | |
| 449 | \\ asm volatile ("syscall" | |
| 450 | \\ : | |
| 451 | \\ : [number] "{rax}" (231), | |
| 452 | \\ [arg1] "{rdi}" (0) | |
| 453 | \\ : "rcx", "r11", "memory" | |
| 454 | \\ ); | |
| 455 | \\ unreachable; | |
| 456 | \\} | |
| 457 | , | |
| 458 | "", | |
| 459 | ); | |
| 460 | ||
| 461 | // Optionals | |
| 462 | case.addCompareOutput( | |
| 463 | \\export fn _start() noreturn { | |
| 464 | \\ const a: u32 = 2; | |
| 465 | \\ const b: ?u32 = a; | |
| 466 | \\ const c = b.?; | |
| 467 | \\ if (c != 2) unreachable; | |
| 468 | \\ | |
| 469 | \\ exit(); | |
| 470 | \\} | |
| 471 | \\ | |
| 472 | \\fn exit() noreturn { | |
| 473 | \\ asm volatile ("syscall" | |
| 474 | \\ : | |
| 475 | \\ : [number] "{rax}" (231), | |
| 476 | \\ [arg1] "{rdi}" (0) | |
| 477 | \\ : "rcx", "r11", "memory" | |
| 478 | \\ ); | |
| 479 | \\ unreachable; | |
| 480 | \\} | |
| 481 | , | |
| 482 | "", | |
| 483 | ); | |
| 484 | ||
| 485 | // While loops | |
| 486 | case.addCompareOutput( | |
| 487 | \\export fn _start() noreturn { | |
| 488 | \\ var i: u32 = 0; | |
| 489 | \\ while (i < 4) : (i += 1) print(); | |
| 490 | \\ assert(i == 4); | |
| 491 | \\ | |
| 492 | \\ exit(); | |
| 493 | \\} | |
| 494 | \\ | |
| 495 | \\fn print() void { | |
| 496 | \\ asm volatile ("syscall" | |
| 497 | \\ : | |
| 498 | \\ : [number] "{rax}" (1), | |
| 499 | \\ [arg1] "{rdi}" (1), | |
| 500 | \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), | |
| 501 | \\ [arg3] "{rdx}" (6) | |
| 502 | \\ : "rcx", "r11", "memory" | |
| 503 | \\ ); | |
| 504 | \\ return; | |
| 505 | \\} | |
| 506 | \\ | |
| 507 | \\pub fn assert(ok: bool) void { | |
| 508 | \\ if (!ok) unreachable; // assertion failure | |
| 509 | \\} | |
| 510 | \\ | |
| 511 | \\fn exit() noreturn { | |
| 512 | \\ asm volatile ("syscall" | |
| 513 | \\ : | |
| 514 | \\ : [number] "{rax}" (231), | |
| 515 | \\ [arg1] "{rdi}" (0) | |
| 516 | \\ : "rcx", "r11", "memory" | |
| 517 | \\ ); | |
| 518 | \\ unreachable; | |
| 519 | \\} | |
| 520 | , | |
| 521 | "hello\nhello\nhello\nhello\n", | |
| 522 | ); | |
| 523 | ||
| 524 | // Labeled blocks (no conditional branch) | |
| 525 | case.addCompareOutput( | |
| 526 | \\export fn _start() noreturn { | |
| 527 | \\ assert(add(3, 4) == 20); | |
| 528 | \\ | |
| 529 | \\ exit(); | |
| 530 | \\} | |
| 531 | \\ | |
| 532 | \\fn add(a: u32, b: u32) u32 { | |
| 533 | \\ const x: u32 = blk: { | |
| 534 | \\ const c = a + b; // 7 | |
| 535 | \\ const d = a + c; // 10 | |
| 536 | \\ const e = d + b; // 14 | |
| 537 | \\ break :blk e; | |
| 538 | \\ }; | |
| 539 | \\ const y = x + a; // 17 | |
| 540 | \\ const z = y + a; // 20 | |
| 541 | \\ return z; | |
| 542 | \\} | |
| 543 | \\ | |
| 544 | \\pub fn assert(ok: bool) void { | |
| 545 | \\ if (!ok) unreachable; // assertion failure | |
| 546 | \\} | |
| 547 | \\ | |
| 548 | \\fn exit() noreturn { | |
| 549 | \\ asm volatile ("syscall" | |
| 550 | \\ : | |
| 551 | \\ : [number] "{rax}" (231), | |
| 552 | \\ [arg1] "{rdi}" (0) | |
| 553 | \\ : "rcx", "r11", "memory" | |
| 554 | \\ ); | |
| 555 | \\ unreachable; | |
| 556 | \\} | |
| 557 | , | |
| 558 | "", | |
| 559 | ); | |
| 560 | ||
| 561 | // This catches a possible bug in the logic for re-using dying operands. | |
| 562 | case.addCompareOutput( | |
| 563 | \\export fn _start() noreturn { | |
| 564 | \\ assert(add(3, 4) == 116); | |
| 565 | \\ | |
| 566 | \\ exit(); | |
| 567 | \\} | |
| 568 | \\ | |
| 569 | \\fn add(a: u32, b: u32) u32 { | |
| 570 | \\ const x: u32 = blk: { | |
| 571 | \\ const c = a + b; // 7 | |
| 572 | \\ const d = a + c; // 10 | |
| 573 | \\ const e = d + b; // 14 | |
| 574 | \\ const f = d + e; // 24 | |
| 575 | \\ const g = e + f; // 38 | |
| 576 | \\ const h = f + g; // 62 | |
| 577 | \\ const i = g + h; // 100 | |
| 578 | \\ const j = i + d; // 110 | |
| 579 | \\ break :blk j; | |
| 580 | \\ }; | |
| 581 | \\ const y = x + a; // 113 | |
| 582 | \\ const z = y + a; // 116 | |
| 583 | \\ return z; | |
| 584 | \\} | |
| 585 | \\ | |
| 586 | \\pub fn assert(ok: bool) void { | |
| 587 | \\ if (!ok) unreachable; // assertion failure | |
| 588 | \\} | |
| 589 | \\ | |
| 590 | \\fn exit() noreturn { | |
| 591 | \\ asm volatile ("syscall" | |
| 592 | \\ : | |
| 593 | \\ : [number] "{rax}" (231), | |
| 594 | \\ [arg1] "{rdi}" (0) | |
| 595 | \\ : "rcx", "r11", "memory" | |
| 596 | \\ ); | |
| 597 | \\ unreachable; | |
| 598 | \\} | |
| 599 | , | |
| 600 | "", | |
| 601 | ); | |
| 602 | ||
| 603 | // Character literals and multiline strings. | |
| 604 | case.addCompareOutput( | |
| 605 | \\export fn _start() noreturn { | |
| 606 | \\ const ignore = | |
| 607 | \\ \\ cool thx | |
| 608 | \\ \\ | |
| 609 | \\ ; | |
| 610 | \\ add('ぁ', '\x03'); | |
| 611 | \\ | |
| 612 | \\ exit(); | |
| 613 | \\} | |
| 614 | \\ | |
| 615 | \\fn add(a: u32, b: u32) void { | |
| 616 | \\ assert(a + b == 12356); | |
| 617 | \\} | |
| 618 | \\ | |
| 619 | \\pub fn assert(ok: bool) void { | |
| 620 | \\ if (!ok) unreachable; // assertion failure | |
| 621 | \\} | |
| 622 | \\ | |
| 623 | \\fn exit() noreturn { | |
| 624 | \\ asm volatile ("syscall" | |
| 625 | \\ : | |
| 626 | \\ : [number] "{rax}" (231), | |
| 627 | \\ [arg1] "{rdi}" (0) | |
| 628 | \\ : "rcx", "r11", "memory" | |
| 629 | \\ ); | |
| 630 | \\ unreachable; | |
| 631 | \\} | |
| 632 | , | |
| 633 | "", | |
| 634 | ); | |
| 635 | ||
| 636 | // Global const. | |
| 637 | case.addCompareOutput( | |
| 638 | \\export fn _start() noreturn { | |
| 639 | \\ add(aa, bb); | |
| 640 | \\ | |
| 641 | \\ exit(); | |
| 642 | \\} | |
| 643 | \\ | |
| 644 | \\const aa = 'ぁ'; | |
| 645 | \\const bb = '\x03'; | |
| 646 | \\ | |
| 647 | \\fn add(a: u32, b: u32) void { | |
| 648 | \\ assert(a + b == 12356); | |
| 649 | \\} | |
| 650 | \\ | |
| 651 | \\pub fn assert(ok: bool) void { | |
| 652 | \\ if (!ok) unreachable; // assertion failure | |
| 653 | \\} | |
| 654 | \\ | |
| 655 | \\fn exit() noreturn { | |
| 656 | \\ asm volatile ("syscall" | |
| 657 | \\ : | |
| 658 | \\ : [number] "{rax}" (231), | |
| 659 | \\ [arg1] "{rdi}" (0) | |
| 660 | \\ : "rcx", "r11", "memory" | |
| 661 | \\ ); | |
| 662 | \\ unreachable; | |
| 663 | \\} | |
| 664 | , | |
| 665 | "", | |
| 666 | ); | |
| 667 | } | |
| 668 | ||
| 669 | { | |
| 670 | var case = ctx.exe("wasm function calls", wasi); | |
| 671 | ||
| 672 | case.addCompareOutput( | |
| 673 | \\export fn _start() u32 { | |
| 674 | \\ foo(); | |
| 675 | \\ bar(); | |
| 676 | \\ return 42; | |
| 677 | \\} | |
| 678 | \\fn foo() void { | |
| 679 | \\ bar(); | |
| 680 | \\ bar(); | |
| 681 | \\} | |
| 682 | \\fn bar() void {} | |
| 683 | , | |
| 684 | "42\n", | |
| 685 | ); | |
| 686 | ||
| 687 | case.addCompareOutput( | |
| 688 | \\export fn _start() i64 { | |
| 689 | \\ bar(); | |
| 690 | \\ foo(); | |
| 691 | \\ foo(); | |
| 692 | \\ bar(); | |
| 693 | \\ foo(); | |
| 694 | \\ bar(); | |
| 695 | \\ return 42; | |
| 696 | \\} | |
| 697 | \\fn foo() void { | |
| 698 | \\ bar(); | |
| 699 | \\} | |
| 700 | \\fn bar() void {} | |
| 701 | , | |
| 702 | "42\n", | |
| 703 | ); | |
| 704 | ||
| 705 | case.addCompareOutput( | |
| 706 | \\export fn _start() f32 { | |
| 707 | \\ bar(); | |
| 708 | \\ foo(); | |
| 709 | \\ return 42.0; | |
| 710 | \\} | |
| 711 | \\fn foo() void { | |
| 712 | \\ bar(); | |
| 713 | \\ bar(); | |
| 714 | \\ bar(); | |
| 715 | \\} | |
| 716 | \\fn bar() void {} | |
| 717 | , | |
| 718 | // This is what you get when you take the bits of the IEE-754 | |
| 719 | // representation of 42.0 and reinterpret them as an unsigned | |
| 720 | // integer. Guess that's a bug in wasmtime. | |
| 721 | "1109917696\n", | |
| 722 | ); | |
| 723 | } | |
| 724 | ||
| 725 | ctx.compileError("function redefinition", linux_x64, | |
| 726 | \\fn entry() void {} | |
| 727 | \\fn entry() void {} | |
| 728 | , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); | |
| 729 | ||
| 730 | ctx.compileError("extern variable has no type", linux_x64, | |
| 731 | \\comptime { | |
| 732 | \\ _ = foo; | |
| 733 | \\} | |
| 734 | \\extern var foo; | |
| 735 | , &[_][]const u8{":4:1: error: unable to infer variable type"}); | |
| 8 | 736 | } |
test/standalone/global_linkage/obj1.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | extern var internal_integer: usize = 1; | |
| 2 | extern var obj1_integer: usize = 421; | |
| 1 | var internal_integer: usize = 1; | |
| 2 | var obj1_integer: usize = 421; | |
| 3 | 3 | |
| 4 | 4 | comptime { |
| 5 | 5 | @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); |
test/standalone/global_linkage/obj2.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | extern var internal_integer: usize = 2; | |
| 2 | extern var obj2_integer: usize = 422; | |
| 1 | var internal_integer: usize = 2; | |
| 2 | var obj2_integer: usize = 422; | |
| 3 | 3 | |
| 4 | 4 | comptime { |
| 5 | 5 | @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); |
test/translate_c.zig+18-3| ... | ... | @@ -3,6 +3,20 @@ const std = @import("std"); |
| 3 | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 6 | cases.add("extern variable in block scope", | |
| 7 | \\float bar; | |
| 8 | \\int foo() { | |
| 9 | \\ _Thread_local static int bar = 2; | |
| 10 | \\} | |
| 11 | , &[_][]const u8{ | |
| 12 | \\pub export var bar: f32 = @import("std").mem.zeroes(f32); | |
| 13 | \\threadlocal var bar_1: c_int = 2; | |
| 14 | \\pub export fn foo() c_int { | |
| 15 | \\ _ = bar_1; | |
| 16 | \\ return 0; | |
| 17 | \\} | |
| 18 | }); | |
| 19 | ||
| 6 | 20 | cases.add("missing return stmt", |
| 7 | 21 | \\int foo() {} |
| 8 | 22 | \\int bar() { |
| ... | ... | @@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 466 | 480 | , &[_][]const u8{ |
| 467 | 481 | \\pub extern var extern_var: c_int; |
| 468 | 482 | \\pub const int_var: c_int = 13; |
| 469 | \\pub export var foo: c_int = undefined; | |
| 483 | \\pub export var foo: c_int = @import("std").mem.zeroes(c_int); | |
| 470 | 484 | }); |
| 471 | 485 | |
| 472 | 486 | cases.add("const ptr initializer", |
| ... | ... | @@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 480 | 494 | \\ static const char v2[] = "2.2.2"; |
| 481 | 495 | \\} |
| 482 | 496 | , &[_][]const u8{ |
| 497 | \\const v2: [*c]const u8 = "2.2.2"; | |
| 483 | 498 | \\pub export fn foo() void { |
| 484 | \\ const v2: [*c]const u8 = "2.2.2"; | |
| 499 | \\ _ = v2; | |
| 485 | 500 | \\} |
| 486 | 501 | }); |
| 487 | 502 | |
| ... | ... | @@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1327 | 1342 | \\static char arr1[] = "hello"; |
| 1328 | 1343 | \\char arr2[] = "hello"; |
| 1329 | 1344 | , &[_][]const u8{ |
| 1330 | \\pub extern var arr0: [*c]u8 = "hello"; | |
| 1345 | \\pub export var arr0: [*c]u8 = "hello"; | |
| 1331 | 1346 | \\pub var arr1: [*c]u8 = "hello"; |
| 1332 | 1347 | \\pub export var arr2: [*c]u8 = "hello"; |
| 1333 | 1348 | }); |
tools/process_headers.zig+1-1| ... | ... | @@ -313,7 +313,7 @@ pub fn main() !void { |
| 313 | 313 | var max_bytes_saved: usize = 0; |
| 314 | 314 | var total_bytes: usize = 0; |
| 315 | 315 | |
| 316 | var hasher = std.crypto.Sha256.init(); | |
| 316 | var hasher = std.crypto.hash.sha2.Sha256.init(.{}); | |
| 317 | 317 | |
| 318 | 318 | for (libc_targets) |libc_target| { |
| 319 | 319 | const dest_target = DestTarget{ |