From 6a9a918fbe4adc23dd7d7573c6f1e499f4be074e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 14 May 2023 20:37:22 -0700 Subject: stage2: encode one-possible-value tuple specially Anonymous structs and anonymous tuples can be stored via a only_possible_value tag because their type encodings, by definition, will have every value specified, which can be used to populate the fields slice in `Key.Aggregate`. Also fix `isTupleOrAnonStruct`. --- src/InternPool.zig | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'src/InternPool.zig') diff --git a/src/InternPool.zig b/src/InternPool.zig index 74cc452176..2435e0ad31 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) { /// Module.Struct object allocated for it. /// data is Module.Namespace.Index. type_struct_ns, - /// An AnonStructType which stores types, names, and values for each field. + /// An AnonStructType which stores types, names, and values for fields. /// data is extra index of `TypeStructAnon`. type_struct_anon, - /// An AnonStructType which has only types and values for each field. + /// An AnonStructType which has only types and values for fields. /// data is extra index of `TypeStructAnon`. type_tuple_anon, /// A tagged union type. @@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) { /// only one possible value. Not all only-possible-values are encoded this way; /// for example structs which have all comptime fields are not encoded this way. /// The set of values that are encoded this way is: - /// * A struct which has 0 fields. + /// * An array or vector which has length 0. + /// * A struct which has all fields comptime-known. /// data is Index of the type, which is known to be zero bits at runtime. only_possible_value, /// data is extra index to Key.Union. @@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { .only_possible_value => { const ty = @intToEnum(Index, data); return switch (ip.indexToKey(ty)) { + // TODO: migrate structs to properly use the InternPool rather + // than using the SegmentedList trick, then the struct type will + // have a slice of comptime values that can be used here for when + // the struct has one possible value due to all fields comptime (same + // as the tuple case below). .struct_type => .{ .aggregate = .{ .ty = ty, .fields = &.{}, } }, + // There is only one possible value precisely due to the + // fact that this values slice is fully populated! + .anon_struct_type => |anon_struct_type| .{ .aggregate = .{ + .ty = ty, + .fields = anon_struct_type.values, + } }, else => unreachable, }; }, @@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .aggregate => |aggregate| { assert(aggregate.ty != .none); for (aggregate.fields) |elem| assert(elem != .none); - if (aggregate.fields.len != ip.aggregateTypeLen(aggregate.ty)) { - std.debug.print("aggregate fields len = {d}, type len = {d}\n", .{ - aggregate.fields.len, - ip.aggregateTypeLen(aggregate.ty), - }); - } assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty)); if (aggregate.fields.len == 0) { @@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { return @intToEnum(Index, ip.items.len - 1); } + switch (ip.indexToKey(aggregate.ty)) { + .anon_struct_type => |anon_struct_type| { + if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) { + // This encoding works thanks to the fact that, as we just verified, + // the type itself contains a slice of values that can be provided + // in the aggregate fields. + ip.items.appendAssumeCapacity(.{ + .tag = .only_possible_value, + .data = @enumToInt(aggregate.ty), + }); + return @intToEnum(Index, ip.items.len - 1); + } + }, + else => {}, + } + try ip.extra.ensureUnusedCapacity( gpa, @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len, @@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { } }; counts.sort(SortContext{ .map = &counts }); - const len = @min(50, counts.count()); - std.debug.print(" top 50 tags:\n", .{}); + const len = @min(25, counts.count()); + std.debug.print(" top 25 tags:\n", .{}); for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| { std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{ @tagName(tag), stats.count, stats.bytes, -- cgit v1.2.3