| ... | ... | @@ -33,7 +33,9 @@ pub const Header = extern struct { |
| 33 | 33 | pub const Wip = struct { |
| 34 | 34 | gpa: Allocator, |
| 35 | 35 | string_table: StringTable = .empty, |
| 36 | | deps_table: DepsTable = .empty, |
| 36 | /// De-duplicates an array inside `extra` that has first element length |
| 37 | /// followed by length elements. |
| 38 | length_prefixed_table: LengthPrefixedTable = .empty, |
| 37 | 39 | targets_table: TargetsTable = .empty, |
| 38 | 40 | |
| 39 | 41 | string_bytes: std.ArrayList(u8) = .empty, |
| ... | ... | @@ -44,23 +46,23 @@ pub const Wip = struct { |
| 44 | 46 | path_deps: std.MultiArrayList(Path) = .empty, |
| 45 | 47 | extra: std.ArrayList(u32) = .empty, |
| 46 | 48 | |
| 47 | | const DepsTable = std.HashMapUnmanaged(Deps, void, DepsTableContext, std.hash_map.default_max_load_percentage); |
| 49 | const LengthPrefixedTable = std.HashMapUnmanaged(u32, void, LengthPrefixedContext, std.hash_map.default_max_load_percentage); |
| 48 | 50 | const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage); |
| 49 | 51 | |
| 50 | | const DepsTableContext = struct { |
| 52 | const LengthPrefixedContext = struct { |
| 51 | 53 | extra: []const u32, |
| 52 | 54 | |
| 53 | | pub fn eql(ctx: @This(), a: Deps, b: Deps) bool { |
| 54 | | const len_a = ctx.extra[@intFromEnum(a)]; |
| 55 | | const len_b = ctx.extra[@intFromEnum(b)]; |
| 56 | | const slice_a = ctx.extra[@intFromEnum(a) + 1 ..][0..len_a]; |
| 57 | | const slice_b = ctx.extra[@intFromEnum(b) + 1 ..][0..len_b]; |
| 55 | pub fn eql(ctx: @This(), a: u32, b: u32) bool { |
| 56 | const len_a = ctx.extra[a]; |
| 57 | const len_b = ctx.extra[b]; |
| 58 | const slice_a = ctx.extra[a + 1 ..][0..len_a]; |
| 59 | const slice_b = ctx.extra[b + 1 ..][0..len_b]; |
| 58 | 60 | return std.mem.eql(u32, slice_a, slice_b); |
| 59 | 61 | } |
| 60 | 62 | |
| 61 | | pub fn hash(ctx: @This(), key: Deps) u64 { |
| 62 | | const len = ctx.extra[@intFromEnum(key)]; |
| 63 | | const slice = ctx.extra[@intFromEnum(key) + 1 ..][0..len]; |
| 63 | pub fn hash(ctx: @This(), key: u32) u64 { |
| 64 | const len = ctx.extra[key]; |
| 65 | const slice = ctx.extra[key + 1 ..][0..len]; |
| 64 | 66 | return std.hash_map.hashString(@ptrCast(slice)); |
| 65 | 67 | } |
| 66 | 68 | }; |
| ... | ... | @@ -174,6 +176,10 @@ pub const Wip = struct { |
| 174 | 176 | return new_off; |
| 175 | 177 | } |
| 176 | 178 | |
| 179 | pub fn addOptionalString(wip: *Wip, bytes: ?[]const u8) Allocator.Error!OptionalString { |
| 180 | return .init(try addString(wip, bytes orelse return .none)); |
| 181 | } |
| 182 | |
| 177 | 183 | pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String { |
| 178 | 184 | var buffer: [256]u8 = undefined; |
| 179 | 185 | var writer: std.Io.Writer = .fixed(&buffer); |
| ... | ... | @@ -324,27 +330,32 @@ pub const Wip = struct { |
| 324 | 330 | } |
| 325 | 331 | } |
| 326 | 332 | |
| 327 | | pub fn prepareDeps(wip: *Wip, n: usize) Allocator.Error![]u32 { |
| 333 | pub fn reserveLengthPrefixed(wip: *Wip, n: usize) Allocator.Error![]u32 { |
| 328 | 334 | const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1); |
| 329 | 335 | slice[0] = @intCast(n); |
| 330 | 336 | return slice[1..]; |
| 331 | 337 | } |
| 332 | 338 | |
| 333 | | pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps { |
| 339 | pub fn dedupeLengthPrefixed(wip: *Wip, index: u32) Allocator.Error!u32 { |
| 340 | assert(wip.extra.items.len == index + wip.extra.items[index] + 1); |
| 334 | 341 | const gpa = wip.gpa; |
| 335 | | const gop = try wip.deps_table.getOrPutContext(gpa, deps, @as(DepsTableContext, .{ |
| 342 | const gop = try wip.length_prefixed_table.getOrPutContext(gpa, index, @as(LengthPrefixedContext, .{ |
| 336 | 343 | .extra = wip.extra.items, |
| 337 | 344 | })); |
| 338 | 345 | if (gop.found_existing) { |
| 339 | | wip.extra.items.len = @intFromEnum(deps); |
| 346 | wip.extra.items.len = index; |
| 340 | 347 | return gop.key_ptr.*; |
| 341 | 348 | } else { |
| 342 | | return deps; |
| 349 | return index; |
| 343 | 350 | } |
| 344 | 351 | } |
| 345 | 352 | |
| 353 | pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps { |
| 354 | return @enumFromInt(try dedupeLengthPrefixed(wip, @intFromEnum(deps))); |
| 355 | } |
| 356 | |
| 346 | 357 | pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 347 | | const extra_len = Storage.calculateExtraLenUpperBound(@TypeOf(extra)); |
| 358 | const extra_len = Storage.extraLen(extra); |
| 348 | 359 | try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); |
| 349 | 360 | return addExtraAssumeCapacity(wip, extra); |
| 350 | 361 | } |
| ... | ... | @@ -397,7 +408,7 @@ pub const Step = extern struct { |
| 397 | 408 | owner: Package.Index, |
| 398 | 409 | deps: Deps, |
| 399 | 410 | max_rss: MaxRss, |
| 400 | | extended: Storage.ExtendedIndex(Flags, union(Tag) { |
| 411 | extended: Storage.Extended(Flags, union(Tag) { |
| 401 | 412 | check_file: CheckFile, |
| 402 | 413 | check_object: CheckObject, |
| 403 | 414 | compile: Compile, |
| ... | ... | @@ -585,10 +596,10 @@ pub const Step = extern struct { |
| 585 | 596 | root_module: Module.Index, |
| 586 | 597 | root_name: String, |
| 587 | 598 | |
| 588 | | //filters: FlagLengthPrefixedList(.flags, .filters_len, String), |
| 589 | | //exec_cmd_args: FlagLengthPrefixedList(.flags, .exec_cmd_args_len, u32), |
| 590 | | //installed_headers: FlagLengthPrefixedList(.flags, .installed_headers_len, InstalledHeader), |
| 591 | | //force_undefined_symbols: FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), |
| 599 | filters: Storage.FlagLengthPrefixedList(.flags, .filters_len, String), |
| 600 | exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString), |
| 601 | installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)), |
| 602 | force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), |
| 592 | 603 | //exacts: EnumConditionalPrefixedList(.flags4, .expect_errors, .exact, String), |
| 593 | 604 | linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath), |
| 594 | 605 | version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath), |
| ... | ... | @@ -612,6 +623,46 @@ pub const Step = extern struct { |
| 612 | 623 | error_limit: Storage.FlagOptional(.flags4, .error_limit, u32), |
| 613 | 624 | build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String), |
| 614 | 625 | |
| 626 | pub const InstalledHeader = union(@This().Tag) { |
| 627 | file: File, |
| 628 | directory: Directory, |
| 629 | |
| 630 | pub const Flags = packed struct(u32) { |
| 631 | tag: InstalledHeader.Tag, |
| 632 | _: u24 = 0, |
| 633 | }; |
| 634 | |
| 635 | pub const Tag = enum(u8) { |
| 636 | file, |
| 637 | directory, |
| 638 | }; |
| 639 | |
| 640 | pub const File = struct { |
| 641 | flags: @This().Flags = .{}, |
| 642 | source: LazyPath, |
| 643 | dest_sub_path: String, |
| 644 | |
| 645 | pub const Flags = packed struct(u32) { |
| 646 | tag: InstalledHeader.Tag = .file, |
| 647 | _: u24 = 0, |
| 648 | }; |
| 649 | }; |
| 650 | |
| 651 | pub const Directory = struct { |
| 652 | flags: @This().Flags, |
| 653 | source: LazyPath, |
| 654 | dest_sub_path: String, |
| 655 | exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String), |
| 656 | include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String), |
| 657 | |
| 658 | pub const Flags = packed struct(u32) { |
| 659 | tag: InstalledHeader.Tag = .directory, |
| 660 | exclude_extensions: bool, |
| 661 | include_extensions: bool, |
| 662 | _: u22 = 0, |
| 663 | }; |
| 664 | }; |
| 665 | }; |
| 615 | 666 | pub const ExpectErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none }; |
| 616 | 667 | pub const TestRunnerMode = enum(u2) { default, simple, server }; |
| 617 | 668 | pub const Entry = enum(u2) { default, disabled, enabled, symbol_name }; |
| ... | ... | @@ -1636,6 +1687,7 @@ pub const Storage = enum { |
| 1636 | 1687 | flag_optional, |
| 1637 | 1688 | enum_optional, |
| 1638 | 1689 | extended, |
| 1690 | flag_length_prefixed_list, |
| 1639 | 1691 | |
| 1640 | 1692 | /// The presence of the field is determined by a boolean within a packed |
| 1641 | 1693 | /// struct. |
| ... | ... | @@ -1674,16 +1726,7 @@ pub const Storage = enum { |
| 1674 | 1726 | |
| 1675 | 1727 | /// The field indexes into an auxilary buffer, with the first element being |
| 1676 | 1728 | /// a packed struct that contains the tag. |
| 1677 | | pub fn Extended(comptime U: type) type { |
| 1678 | | return struct { |
| 1679 | | value: U, |
| 1680 | | |
| 1681 | | pub const storage: Storage = .extended; |
| 1682 | | }; |
| 1683 | | } |
| 1684 | | |
| 1685 | | /// Equivalent to `Extended` but works in an `extern struct`. |
| 1686 | | pub fn ExtendedIndex(comptime BaseFlags: type, comptime U: type) type { |
| 1729 | pub fn Extended(comptime BaseFlags: type, comptime U: type) type { |
| 1687 | 1730 | return enum(u32) { |
| 1688 | 1731 | _, |
| 1689 | 1732 | |
| ... | ... | @@ -1699,6 +1742,30 @@ pub const Storage = enum { |
| 1699 | 1742 | }; |
| 1700 | 1743 | } |
| 1701 | 1744 | |
| 1745 | /// A field in flags determines whether the length is zero or nonzero. If the length is |
| 1746 | /// nonzero, then there is a length field followed by the list. |
| 1747 | /// |
| 1748 | /// When deserializing, the slice field is set. When serializing, the index |
| 1749 | /// field must be set. |
| 1750 | pub fn FlagLengthPrefixedList( |
| 1751 | comptime flags_arg: @EnumLiteral(), |
| 1752 | comptime flag_arg: @EnumLiteral(), |
| 1753 | comptime ValueArg: type, |
| 1754 | ) type { |
| 1755 | return struct { |
| 1756 | slice: []const Value, |
| 1757 | |
| 1758 | pub const storage: Storage = .flag_length_prefixed_list; |
| 1759 | pub const flags = flags_arg; |
| 1760 | pub const flag = flag_arg; |
| 1761 | pub const Value = ValueArg; |
| 1762 | |
| 1763 | pub fn initErased(s: []const u32) @This() { |
| 1764 | return .{ .slice = @ptrCast(s) }; |
| 1765 | } |
| 1766 | }; |
| 1767 | } |
| 1768 | |
| 1702 | 1769 | pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize { |
| 1703 | 1770 | var end = i; |
| 1704 | 1771 | _ = data(buffer, &end, S); |
| ... | ... | @@ -1769,6 +1836,15 @@ pub const Storage = enum { |
| 1769 | 1836 | }; |
| 1770 | 1837 | }, |
| 1771 | 1838 | .extended => @compileError("TODO"), |
| 1839 | .flag_length_prefixed_list => { |
| 1840 | const flags = @field(container, @tagName(Field.flags)); |
| 1841 | const flag = @field(flags, @tagName(Field.flag)); |
| 1842 | if (!flag) return .{ .slice = &.{} }; |
| 1843 | const data_start = i.* + 1; |
| 1844 | const len = buffer[data_start - 1]; |
| 1845 | defer i.* = data_start + len; |
| 1846 | return .{ .slice = @ptrCast(buffer[data_start..][0..len]) }; |
| 1847 | }, |
| 1772 | 1848 | }, |
| 1773 | 1849 | }, |
| 1774 | 1850 | .@"extern" => comptime unreachable, |
| ... | ... | @@ -1787,11 +1863,36 @@ pub const Storage = enum { |
| 1787 | 1863 | return i; |
| 1788 | 1864 | } |
| 1789 | 1865 | |
| 1790 | | fn calculateExtraLenUpperBound(comptime Extra: type) comptime_int { |
| 1791 | | var i = 0; |
| 1792 | | const fields = @typeInfo(Extra).@"struct".fields; |
| 1866 | fn extraFieldLen(field: anytype) usize { |
| 1867 | const Field = @TypeOf(field); |
| 1868 | return switch (@typeInfo(Field)) { |
| 1869 | .int => |info| switch (info.bits) { |
| 1870 | 32 => 1, |
| 1871 | 64 => 2, |
| 1872 | else => comptime unreachable, |
| 1873 | }, |
| 1874 | .@"enum" => 1, |
| 1875 | .@"struct" => |info| switch (info.layout) { |
| 1876 | .@"packed" => switch (info.backing_integer.?) { |
| 1877 | u32 => 1, |
| 1878 | u64 => 2, |
| 1879 | else => comptime unreachable, |
| 1880 | }, |
| 1881 | .auto => switch (Field.storage) { |
| 1882 | .flag_optional, .enum_optional, .extended => 1, |
| 1883 | .flag_length_prefixed_list => field.slice.len + 1, |
| 1884 | }, |
| 1885 | .@"extern" => comptime unreachable, |
| 1886 | }, |
| 1887 | else => @compileError("bad type: " ++ @typeName(Field)), |
| 1888 | }; |
| 1889 | } |
| 1890 | |
| 1891 | fn extraLen(extra: anytype) usize { |
| 1892 | const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; |
| 1893 | var i: usize = 0; |
| 1793 | 1894 | inline for (fields) |field| { |
| 1794 | | i += calculateExtraFieldLenUpperBound(field.type); |
| 1895 | i += Storage.extraFieldLen(@field(extra, field.name)); |
| 1795 | 1896 | } |
| 1796 | 1897 | return i; |
| 1797 | 1898 | } |
| ... | ... | @@ -1836,6 +1937,13 @@ pub const Storage = enum { |
| 1836 | 1937 | return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0; |
| 1837 | 1938 | }, |
| 1838 | 1939 | .extended => @compileError("TODO"), |
| 1940 | .flag_length_prefixed_list => { |
| 1941 | const len: u32 = @intCast(value.slice.len); |
| 1942 | if (len == 0) return 0; |
| 1943 | buffer[i] = len; |
| 1944 | @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice))); |
| 1945 | return len + 1; |
| 1946 | }, |
| 1839 | 1947 | }, |
| 1840 | 1948 | }, |
| 1841 | 1949 | .@"extern" => comptime unreachable, |
| ... | ... | @@ -1843,29 +1951,6 @@ pub const Storage = enum { |
| 1843 | 1951 | else => @compileError("bad field type: " ++ @typeName(Field)), |
| 1844 | 1952 | } |
| 1845 | 1953 | } |
| 1846 | | |
| 1847 | | fn calculateExtraFieldLenUpperBound(comptime Field: type) comptime_int { |
| 1848 | | return switch (@typeInfo(Field)) { |
| 1849 | | .int => |info| switch (info.bits) { |
| 1850 | | 32 => 1, |
| 1851 | | 64 => 2, |
| 1852 | | else => comptime unreachable, |
| 1853 | | }, |
| 1854 | | .@"enum" => 1, |
| 1855 | | .@"struct" => |info| switch (info.layout) { |
| 1856 | | .@"packed" => switch (info.backing_integer.?) { |
| 1857 | | u32 => 1, |
| 1858 | | u64 => 2, |
| 1859 | | else => comptime unreachable, |
| 1860 | | }, |
| 1861 | | .auto => switch (Field.storage) { |
| 1862 | | .flag_optional, .enum_optional, .extended => 1, |
| 1863 | | }, |
| 1864 | | .@"extern" => comptime unreachable, |
| 1865 | | }, |
| 1866 | | else => comptime unreachable, |
| 1867 | | }; |
| 1868 | | } |
| 1869 | 1954 | }; |
| 1870 | 1955 | |
| 1871 | 1956 | pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T { |