| ... | @@ -33,9 +33,8 @@ pub const Header = extern struct { | ... | @@ -33,9 +33,8 @@ pub const Header = extern struct { |
| 33 | pub const Wip = struct { | 33 | pub const Wip = struct { |
| 34 | gpa: Allocator, | 34 | gpa: Allocator, |
| 35 | string_table: StringTable = .empty, | 35 | string_table: StringTable = .empty, |
| 36 | /// De-duplicates an array inside `extra` that has first element length | 36 | /// De-duplicates an array inside `extra`. |
| 37 | /// followed by length elements. | 37 | dedupe_table: DedupeTable = .empty, |
| 38 | length_prefixed_table: LengthPrefixedTable = .empty, | | |
| 39 | targets_table: TargetsTable = .empty, | 38 | targets_table: TargetsTable = .empty, |
| 40 | | 39 | |
| 41 | string_bytes: std.ArrayList(u8) = .empty, | 40 | string_bytes: std.ArrayList(u8) = .empty, |
| ... | @@ -46,25 +45,27 @@ pub const Wip = struct { | ... | @@ -46,25 +45,27 @@ pub const Wip = struct { |
| 46 | path_deps: std.MultiArrayList(Path) = .empty, | 45 | path_deps: std.MultiArrayList(Path) = .empty, |
| 47 | extra: std.ArrayList(u32) = .empty, | 46 | extra: std.ArrayList(u32) = .empty, |
| 48 | | 47 | |
| 49 | const LengthPrefixedTable = std.HashMapUnmanaged(u32, void, LengthPrefixedContext, std.hash_map.default_max_load_percentage); | 48 | const DedupeTable = std.HashMapUnmanaged(ExtraSlice, void, ExtraSlice.Context, std.hash_map.default_max_load_percentage); |
| 50 | const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage); | 49 | const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage); |
| 51 | | 50 | |
| 52 | const LengthPrefixedContext = struct { | 51 | const ExtraSlice = struct { |
| 53 | extra: []const u32, | 52 | index: u32, |
| | 53 | len: u32, |
| 54 | | 54 | |
| 55 | pub fn eql(ctx: @This(), a: u32, b: u32) bool { | 55 | const Context = struct { |
| 56 | const len_a = ctx.extra[a]; | 56 | extra: []const u32, |
| 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]; | | |
| 60 | return std.mem.eql(u32, slice_a, slice_b); | | |
| 61 | } | | |
| 62 | | 57 | |
| 63 | pub fn hash(ctx: @This(), key: u32) u64 { | 58 | pub fn eql(ctx: @This(), a: ExtraSlice, b: ExtraSlice) bool { |
| 64 | const len = ctx.extra[key]; | 59 | const slice_a = ctx.extra[a.index..][0..a.len]; |
| 65 | const slice = ctx.extra[key + 1 ..][0..len]; | 60 | const slice_b = ctx.extra[b.index..][0..b.len]; |
| 66 | return std.hash_map.hashString(@ptrCast(slice)); | 61 | return std.mem.eql(u32, slice_a, slice_b); |
| 67 | } | 62 | } |
| | 63 | |
| | 64 | pub fn hash(ctx: @This(), key: ExtraSlice) u64 { |
| | 65 | const slice = ctx.extra[key.index..][0..key.len]; |
| | 66 | return std.hash_map.hashString(@ptrCast(slice)); |
| | 67 | } |
| | 68 | }; |
| 68 | }; | 69 | }; |
| 69 | | 70 | |
| 70 | const TargetsTableContext = struct { | 71 | const TargetsTableContext = struct { |
| ... | @@ -323,34 +324,33 @@ pub const Wip = struct { | ... | @@ -323,34 +324,33 @@ pub const Wip = struct { |
| 323 | } | 324 | } |
| 324 | } | 325 | } |
| 325 | | 326 | |
| 326 | pub fn reserveLengthPrefixed(wip: *Wip, n: usize) Allocator.Error![]u32 { | 327 | pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 327 | const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1); | 328 | const extra_len = Storage.extraLen(extra); |
| 328 | slice[0] = @intCast(n); | 329 | try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); |
| 329 | return slice[1..]; | 330 | return addExtraAssumeCapacity(wip, extra); |
| 330 | } | 331 | } |
| 331 | | 332 | |
| 332 | pub fn dedupeLengthPrefixed(wip: *Wip, index: u32) Allocator.Error!u32 { | 333 | /// Same as `addExtra` but uses a hash map to possibly return an already |
| 333 | assert(wip.extra.items.len == index + wip.extra.items[index] + 1); | 334 | /// existing index instead of appending to `extra`. |
| | 335 | pub fn addDeduped(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 334 | const gpa = wip.gpa; | 336 | const gpa = wip.gpa; |
| 335 | const gop = try wip.length_prefixed_table.getOrPutContext(gpa, index, @as(LengthPrefixedContext, .{ | 337 | const revert_index = wip.extra.items.len; |
| 336 | .extra = wip.extra.items, | 338 | const extra_len = Storage.extraLen(extra); |
| 337 | })); | 339 | try wip.extra.ensureUnusedCapacity(gpa, extra_len); |
| | 340 | const new_index = addExtraAssumeCapacity(wip, extra); |
| | 341 | const len: u32 = @intCast(wip.extra.items.len - new_index); |
| | 342 | |
| | 343 | const gop = try wip.dedupe_table.getOrPutContext(gpa, .{ |
| | 344 | .index = new_index, |
| | 345 | .len = len, |
| | 346 | }, @as(ExtraSlice.Context, .{ .extra = wip.extra.items })); |
| | 347 | |
| 338 | if (gop.found_existing) { | 348 | if (gop.found_existing) { |
| 339 | wip.extra.items.len = index; | 349 | wip.extra.items.len = revert_index; |
| 340 | return gop.key_ptr.*; | 350 | return gop.key_ptr.index; |
| 341 | } else { | | |
| 342 | return index; | | |
| 343 | } | 351 | } |
| 344 | } | | |
| 345 | | 352 | |
| 346 | pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps { | 353 | return new_index; |
| 347 | return @enumFromInt(try dedupeLengthPrefixed(wip, @intFromEnum(deps))); | | |
| 348 | } | | |
| 349 | | | |
| 350 | pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { | | |
| 351 | const extra_len = Storage.extraLen(extra); | | |
| 352 | try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); | | |
| 353 | return addExtraAssumeCapacity(wip, extra); | | |
| 354 | } | 354 | } |
| 355 | | 355 | |
| 356 | pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 { | 356 | pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 { |
| ... | @@ -399,7 +399,7 @@ pub const AvailableOption = extern struct { | ... | @@ -399,7 +399,7 @@ pub const AvailableOption = extern struct { |
| 399 | pub const Step = extern struct { | 399 | pub const Step = extern struct { |
| 400 | name: String, | 400 | name: String, |
| 401 | owner: Package.Index, | 401 | owner: Package.Index, |
| 402 | deps: Deps, | 402 | deps: Deps.Index, |
| 403 | max_rss: MaxRss, | 403 | max_rss: MaxRss, |
| 404 | extended: Storage.Extended(Flags, union(Tag) { | 404 | extended: Storage.Extended(Flags, union(Tag) { |
| 405 | check_file: CheckFile, | 405 | check_file: CheckFile, |
| ... | @@ -1074,14 +1074,12 @@ pub const Package = struct { | ... | @@ -1074,14 +1074,12 @@ pub const Package = struct { |
| 1074 | }; | 1074 | }; |
| 1075 | }; | 1075 | }; |
| 1076 | | 1076 | |
| 1077 | /// Trailing: | | |
| 1078 | /// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set | | |
| 1079 | pub const Module = struct { | 1077 | pub const Module = struct { |
| 1080 | flags: Flags, | 1078 | flags: Flags, |
| 1081 | flags2: Flags2, | 1079 | flags2: Flags2, |
| | 1080 | import_table: ImportTable.Index, |
| 1082 | owner: Package.Index, | 1081 | owner: Package.Index, |
| 1083 | root_source_file: OptionalLazyPath, | 1082 | root_source_file: OptionalLazyPath, |
| 1084 | import_table: ImportTable, | | |
| 1085 | resolved_target: ResolvedTarget.OptionalIndex, | 1083 | resolved_target: ResolvedTarget.OptionalIndex, |
| 1086 | c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), | 1084 | c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), |
| 1087 | lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath), | 1085 | lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath), |
| ... | @@ -1089,6 +1087,7 @@ pub const Module = struct { | ... | @@ -1089,6 +1087,7 @@ pub const Module = struct { |
| 1089 | include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir), | 1087 | include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir), |
| 1090 | rpaths: Storage.UnionList(.flags, .rpaths, RPath), | 1088 | rpaths: Storage.UnionList(.flags, .rpaths, RPath), |
| 1091 | link_objects: Storage.UnionList(.flags, .link_objects, LinkObject), | 1089 | link_objects: Storage.UnionList(.flags, .link_objects, LinkObject), |
| | 1090 | frameworks: Storage.FlagLengthPrefixedList(.flags, .frameworks, Framework), |
| 1092 | | 1091 | |
| 1093 | pub const Optimize = enum(u3) { | 1092 | pub const Optimize = enum(u3) { |
| 1094 | debug, | 1093 | debug, |
| ... | @@ -1220,28 +1219,47 @@ pub const Module = struct { | ... | @@ -1220,28 +1219,47 @@ pub const Module = struct { |
| 1220 | win32_resource_file: RcSourceFile.Index, | 1219 | win32_resource_file: RcSourceFile.Index, |
| 1221 | }; | 1220 | }; |
| 1222 | | 1221 | |
| 1223 | pub const FrameworkFlags = packed struct(u2) { | 1222 | pub const Framework = struct { |
| 1224 | needed: bool, | 1223 | flags: @This().Flags, |
| 1225 | weak: bool, | 1224 | name: String, |
| | 1225 | |
| | 1226 | pub const Flags = packed struct(u32) { |
| | 1227 | needed: bool, |
| | 1228 | weak: bool, |
| | 1229 | _: u30 = 0, |
| | 1230 | }; |
| 1226 | }; | 1231 | }; |
| 1227 | }; | 1232 | }; |
| 1228 | | 1233 | |
| 1229 | /// Points into `extra`, first element is len, then: | 1234 | pub const ImportTable = struct { |
| 1230 | /// * import_name: String, // for each len | 1235 | imports: Storage.MultiList(Import), |
| 1231 | /// * Module.Index, // for each len | 1236 | |
| 1232 | pub const ImportTable = enum(u32) { | 1237 | pub const Import = struct { |
| 1233 | _, | 1238 | name: String, |
| | 1239 | module: Module.Index, |
| | 1240 | }; |
| | 1241 | |
| | 1242 | /// Points into `extra`. |
| | 1243 | pub const Index = enum(u32) { |
| | 1244 | invalid = maxInt(u32), |
| | 1245 | _, |
| | 1246 | }; |
| 1234 | }; | 1247 | }; |
| 1235 | | 1248 | |
| 1236 | /// Points into `extra`, where the first element is count of deps, following | 1249 | pub const Deps = struct { |
| 1237 | /// elements is `Step.Index` per count. | 1250 | steps: Storage.LengthPrefixedList(Step.Index), |
| 1238 | pub const Deps = enum(u32) { | | |
| 1239 | _, | | |
| 1240 | | 1251 | |
| 1241 | pub fn slice(deps: Deps, c: *const Configuration) []Step.Index { | 1252 | pub const Index = enum(u32) { |
| 1242 | const len = c.extra[@intFromEnum(deps)]; | 1253 | _, |
| 1243 | return @ptrCast(c.extra[@intFromEnum(deps) + 1 ..][0..len]); | 1254 | |
| 1244 | } | 1255 | pub fn get(this: @This(), c: *const Configuration) Deps { |
| | 1256 | return extraData(c, Deps, @intFromEnum(this)); |
| | 1257 | } |
| | 1258 | |
| | 1259 | pub fn slice(this: @This(), c: *const Configuration) []const Step.Index { |
| | 1260 | return get(this, c).steps.slice; |
| | 1261 | } |
| | 1262 | }; |
| 1245 | }; | 1263 | }; |
| 1246 | | 1264 | |
| 1247 | /// Points into `extra`, where the first element is count of strings, following | 1265 | /// Points into `extra`, where the first element is count of strings, following |
| ... | @@ -1760,6 +1778,7 @@ pub const Storage = enum { | ... | @@ -1760,6 +1778,7 @@ pub const Storage = enum { |
| 1760 | flag_length_prefixed_list, | 1778 | flag_length_prefixed_list, |
| 1761 | union_list, | 1779 | union_list, |
| 1762 | flag_union, | 1780 | flag_union, |
| | 1781 | multi_list, |
| 1763 | | 1782 | |
| 1764 | /// The presence of the field is determined by a boolean within a packed | 1783 | /// The presence of the field is determined by a boolean within a packed |
| 1765 | /// struct. | 1784 | /// struct. |
| ... | @@ -1853,7 +1872,8 @@ pub const Storage = enum { | ... | @@ -1853,7 +1872,8 @@ pub const Storage = enum { |
| 1853 | }; | 1872 | }; |
| 1854 | } | 1873 | } |
| 1855 | | 1874 | |
| 1856 | /// The field contains a u32 length followed by that many items. | 1875 | /// The field contains a u32 length followed by that many items, each |
| | 1876 | /// element bitcastable to u32. |
| 1857 | pub fn LengthPrefixedList(comptime ElemArg: type) type { | 1877 | pub fn LengthPrefixedList(comptime ElemArg: type) type { |
| 1858 | return struct { | 1878 | return struct { |
| 1859 | slice: []const Elem, | 1879 | slice: []const Elem, |
| ... | @@ -1867,6 +1887,17 @@ pub const Storage = enum { | ... | @@ -1867,6 +1887,17 @@ pub const Storage = enum { |
| 1867 | }; | 1887 | }; |
| 1868 | } | 1888 | } |
| 1869 | | 1889 | |
| | 1890 | /// The field contains a u32 length followed by that many items for the |
| | 1891 | /// first field, that many items for the second field, etc. |
| | 1892 | pub fn MultiList(comptime ElemArg: type) type { |
| | 1893 | return struct { |
| | 1894 | mal: std.MultiArrayList(Elem), |
| | 1895 | |
| | 1896 | pub const storage: Storage = .multi_list; |
| | 1897 | pub const Elem = ElemArg; |
| | 1898 | }; |
| | 1899 | } |
| | 1900 | |
| 1870 | /// `UnionArg` is a tagged union with a small integer for the enum tag. | 1901 | /// `UnionArg` is a tagged union with a small integer for the enum tag. |
| 1871 | /// | 1902 | /// |
| 1872 | /// A field in flags determines whether the metadata is present. | 1903 | /// A field in flags determines whether the metadata is present. |
| ... | @@ -2028,6 +2059,16 @@ pub const Storage = enum { | ... | @@ -2028,6 +2059,16 @@ pub const Storage = enum { |
| 2028 | defer i.* = data_start + len; | 2059 | defer i.* = data_start + len; |
| 2029 | return .{ .slice = @ptrCast(buffer[data_start..][0..len]) }; | 2060 | return .{ .slice = @ptrCast(buffer[data_start..][0..len]) }; |
| 2030 | }, | 2061 | }, |
| | 2062 | .multi_list => { |
| | 2063 | const data_start = i.* + 1; |
| | 2064 | const len = buffer[data_start - 1]; |
| | 2065 | defer i.* = data_start + len * @typeInfo(Field.Elem).@"struct".fields.len; |
| | 2066 | return .{ .mal = .{ |
| | 2067 | .bytes = @ptrCast(buffer[data_start..][0..len]), |
| | 2068 | .len = len, |
| | 2069 | .capacity = len, |
| | 2070 | } }; |
| | 2071 | }, |
| 2031 | .union_list => { | 2072 | .union_list => { |
| 2032 | const flags = @field(container, @tagName(Field.flags)); | 2073 | const flags = @field(container, @tagName(Field.flags)); |
| 2033 | const flag = @field(flags, @tagName(Field.flag)); | 2074 | const flag = @field(flags, @tagName(Field.flag)); |
| ... | @@ -2082,6 +2123,7 @@ pub const Storage = enum { | ... | @@ -2082,6 +2123,7 @@ pub const Storage = enum { |
| 2082 | .auto => switch (Field.storage) { | 2123 | .auto => switch (Field.storage) { |
| 2083 | .flag_optional, .enum_optional, .extended => 1, | 2124 | .flag_optional, .enum_optional, .extended => 1, |
| 2084 | .length_prefixed_list, .flag_length_prefixed_list => field.slice.len + 1, | 2125 | .length_prefixed_list, .flag_length_prefixed_list => field.slice.len + 1, |
| | 2126 | .multi_list => 1 + field.mal.len * @typeInfo(Field.Elem).@"struct".fields.len, |
| 2085 | .union_list => Field.extraLen(field.len), | 2127 | .union_list => Field.extraLen(field.len), |
| 2086 | .flag_union => switch (field.u) { | 2128 | .flag_union => switch (field.u) { |
| 2087 | inline else => |v| extraFieldLen(v), | 2129 | inline else => |v| extraFieldLen(v), |
| ... | @@ -2153,6 +2195,17 @@ pub const Storage = enum { | ... | @@ -2153,6 +2195,17 @@ pub const Storage = enum { |
| 2153 | @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice))); | 2195 | @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice))); |
| 2154 | return len + 1; | 2196 | return len + 1; |
| 2155 | }, | 2197 | }, |
| | 2198 | .multi_list => { |
| | 2199 | const len: u32 = @intCast(value.mal.len); |
| | 2200 | if (len == 0) return 0; |
| | 2201 | buffer[i] = len; |
| | 2202 | const fields = @typeInfo(Field.Elem).@"struct".fields; |
| | 2203 | inline for (0..fields.len) |field_i| @memcpy( |
| | 2204 | buffer[i + 1 + field_i * len ..][0..len], |
| | 2205 | @as([]const u32, @ptrCast(value.mal.items(@enumFromInt(field_i)))), |
| | 2206 | ); |
| | 2207 | return 1 + fields.len * len; |
| | 2208 | }, |
| 2156 | .union_list => { | 2209 | .union_list => { |
| 2157 | if (value.len == 0) return 0; | 2210 | if (value.len == 0) return 0; |
| 2158 | const Tag = @typeInfo(Field.Union).@"union".tag_type.?; | 2211 | const Tag = @typeInfo(Field.Union).@"union".tag_type.?; |