Commit 19de259936

Andrew Kelley <andrew@ziglang.org>
2020-05-22 04:52:45
stage2 parser: arrays and structs directly in memory after the node
Slightly reduced memory usage. Roughly the same API and perf.
1 parent 9377af9
Changed files (3)
lib/std/zig/ast.zig
@@ -2067,11 +2067,23 @@ pub const Node = struct {
         }
     };
 
+    /// Elements occur directly in memory after ArrayInitializer.
     pub const ArrayInitializer = struct {
         base: Node = Node{ .id = .ArrayInitializer },
         rtoken: TokenIndex,
+        list_len: NodeIndex,
         lhs: *Node,
-        list: []*Node,
+
+        /// After this the caller must initialize the fields_and_decls list.
+        pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializer {
+            const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializer), sizeInBytes(list_len));
+            return @ptrCast(*ArrayInitializer, bytes.ptr);
+        }
+
+        pub fn free(self: *ArrayInitializer, allocator: *mem.Allocator) void {
+            const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
+            allocator.free(bytes);
+        }
 
         pub fn iterate(self: *const ArrayInitializer) Node.Iterator {
             return .{ .parent_node = &self.base, .index = 0, .node = null };
@@ -2084,8 +2096,8 @@ pub const Node = struct {
             if (i < 1) return self.lhs;
             i -= 1;
 
-            if (i < self.list.len) return self.list[i];
-            i -= self.list.len;
+            if (i < self.list_len) return self.listConst()[i];
+            i -= self.list_len;
 
             return null;
         }
@@ -2097,13 +2109,39 @@ pub const Node = struct {
         pub fn lastToken(self: *const ArrayInitializer) TokenIndex {
             return self.rtoken;
         }
+
+        pub fn list(self: *ArrayInitializer) []*Node {
+            const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializer);
+            return @ptrCast([*]*Node, decls_start)[0..self.list_len];
+        }
+
+        pub fn listConst(self: *const ArrayInitializer) []const *Node {
+            const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializer);
+            return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
+        }
+
+        fn sizeInBytes(list_len: NodeIndex) usize {
+            return @sizeOf(ArrayInitializer) + @sizeOf(*Node) * @as(usize, list_len);
+        }
     };
 
+    /// Elements occur directly in memory after ArrayInitializerDot.
     pub const ArrayInitializerDot = struct {
         base: Node = Node{ .id = .ArrayInitializerDot },
         dot: TokenIndex,
         rtoken: TokenIndex,
-        list: []*Node,
+        list_len: NodeIndex,
+
+        /// After this the caller must initialize the fields_and_decls list.
+        pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializerDot {
+            const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializerDot), sizeInBytes(list_len));
+            return @ptrCast(*ArrayInitializerDot, bytes.ptr);
+        }
+
+        pub fn free(self: *ArrayInitializerDot, allocator: *mem.Allocator) void {
+            const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
+            allocator.free(bytes);
+        }
 
         pub fn iterate(self: *const ArrayInitializerDot) Node.Iterator {
             return .{ .parent_node = &self.base, .index = 0, .node = null };
@@ -2113,8 +2151,8 @@ pub const Node = struct {
             var i = it.index;
             it.index += 1;
 
-            if (i < self.list.len) return self.list[i];
-            i -= self.list.len;
+            if (i < self.list_len) return self.listConst()[i];
+            i -= self.list_len;
 
             return null;
         }
@@ -2126,13 +2164,39 @@ pub const Node = struct {
         pub fn lastToken(self: *const ArrayInitializerDot) TokenIndex {
             return self.rtoken;
         }
+
+        pub fn list(self: *ArrayInitializerDot) []*Node {
+            const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializerDot);
+            return @ptrCast([*]*Node, decls_start)[0..self.list_len];
+        }
+
+        pub fn listConst(self: *const ArrayInitializerDot) []const *Node {
+            const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializerDot);
+            return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
+        }
+
+        fn sizeInBytes(list_len: NodeIndex) usize {
+            return @sizeOf(ArrayInitializerDot) + @sizeOf(*Node) * @as(usize, list_len);
+        }
     };
 
+    /// Elements occur directly in memory after StructInitializer.
     pub const StructInitializer = struct {
         base: Node = Node{ .id = .StructInitializer },
         rtoken: TokenIndex,
+        list_len: NodeIndex,
         lhs: *Node,
-        list: []*Node,
+
+        /// After this the caller must initialize the fields_and_decls list.
+        pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializer {
+            const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializer), sizeInBytes(list_len));
+            return @ptrCast(*StructInitializer, bytes.ptr);
+        }
+
+        pub fn free(self: *StructInitializer, allocator: *mem.Allocator) void {
+            const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
+            allocator.free(bytes);
+        }
 
         pub fn iterate(self: *const StructInitializer) Node.Iterator {
             return .{ .parent_node = &self.base, .index = 0, .node = null };
@@ -2145,8 +2209,8 @@ pub const Node = struct {
             if (i < 1) return self.lhs;
             i -= 1;
 
-            if (i < self.list.len) return self.list[i];
-            i -= self.list.len;
+            if (i < self.list_len) return self.listConst()[i];
+            i -= self.list_len;
 
             return null;
         }
@@ -2158,13 +2222,39 @@ pub const Node = struct {
         pub fn lastToken(self: *const StructInitializer) TokenIndex {
             return self.rtoken;
         }
+
+        pub fn list(self: *StructInitializer) []*Node {
+            const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializer);
+            return @ptrCast([*]*Node, decls_start)[0..self.list_len];
+        }
+
+        pub fn listConst(self: *const StructInitializer) []const *Node {
+            const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializer);
+            return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
+        }
+
+        fn sizeInBytes(list_len: NodeIndex) usize {
+            return @sizeOf(StructInitializer) + @sizeOf(*Node) * @as(usize, list_len);
+        }
     };
 
+    /// Elements occur directly in memory after StructInitializerDot.
     pub const StructInitializerDot = struct {
         base: Node = Node{ .id = .StructInitializerDot },
         dot: TokenIndex,
         rtoken: TokenIndex,
-        list: []*Node,
+        list_len: NodeIndex,
+
+        /// After this the caller must initialize the fields_and_decls list.
+        pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializerDot {
+            const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializerDot), sizeInBytes(list_len));
+            return @ptrCast(*StructInitializerDot, bytes.ptr);
+        }
+
+        pub fn free(self: *StructInitializerDot, allocator: *mem.Allocator) void {
+            const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)];
+            allocator.free(bytes);
+        }
 
         pub fn iterate(self: *const StructInitializerDot) Node.Iterator {
             return .{ .parent_node = &self.base, .index = 0, .node = null };
@@ -2174,8 +2264,8 @@ pub const Node = struct {
             var i = it.index;
             it.index += 1;
 
-            if (i < self.list.len) return self.list[i];
-            i -= self.list.len;
+            if (i < self.list_len) return self.listConst()[i];
+            i -= self.list_len;
 
             return null;
         }
@@ -2187,6 +2277,20 @@ pub const Node = struct {
         pub fn lastToken(self: *const StructInitializerDot) TokenIndex {
             return self.rtoken;
         }
+
+        pub fn list(self: *StructInitializerDot) []*Node {
+            const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializerDot);
+            return @ptrCast([*]*Node, decls_start)[0..self.list_len];
+        }
+
+        pub fn listConst(self: *const StructInitializerDot) []const *Node {
+            const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializerDot);
+            return @ptrCast([*]const *Node, decls_start)[0..self.list_len];
+        }
+
+        fn sizeInBytes(list_len: NodeIndex) usize {
+            return @sizeOf(StructInitializerDot) + @sizeOf(*Node) * @as(usize, list_len);
+        }
     };
 
     /// Parameter nodes directly follow Call in memory.
lib/std/zig/parse.zig
@@ -1318,12 +1318,13 @@ const Parser = struct {
                 const next = (try p.parseFieldInit()) orelse break;
                 try init_list.append(next);
             }
-            const node = try p.arena.allocator.create(Node.StructInitializer);
+            const node = try Node.StructInitializer.alloc(&p.arena.allocator, init_list.items.len);
             node.* = .{
                 .lhs = lhs,
                 .rtoken = try p.expectToken(.RBrace),
-                .list = try p.arena.allocator.dupe(*Node, init_list.items),
+                .list_len = init_list.items.len,
             };
+            std.mem.copy(*Node, node.list(), init_list.items);
             return &node.base;
         }
 
@@ -1333,12 +1334,13 @@ const Parser = struct {
                 const next = (try p.parseExpr()) orelse break;
                 try init_list.append(next);
             }
-            const node = try p.arena.allocator.create(Node.ArrayInitializer);
+            const node = try Node.ArrayInitializer.alloc(&p.arena.allocator, init_list.items.len);
             node.* = .{
                 .lhs = lhs,
                 .rtoken = try p.expectToken(.RBrace),
-                .list = try p.arena.allocator.dupe(*Node, init_list.items),
+                .list_len = init_list.items.len,
             };
+            std.mem.copy(*Node, node.list(), init_list.items);
             return &node.base;
         }
 
@@ -1346,7 +1348,7 @@ const Parser = struct {
         node.* = .{
             .lhs = lhs,
             .rtoken = try p.expectToken(.RBrace),
-            .list = &[0]*Node{},
+            .list_len = 0,
         };
         return &node.base;
     }
@@ -1366,12 +1368,13 @@ const Parser = struct {
                 const next = (try p.parseFieldInit()) orelse break;
                 try init_list.append(next);
             }
-            const node = try p.arena.allocator.create(Node.StructInitializerDot);
+            const node = try Node.StructInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
             node.* = .{
                 .dot = dot,
                 .rtoken = try p.expectToken(.RBrace),
-                .list = try p.arena.allocator.dupe(*Node, init_list.items),
+                .list_len = init_list.items.len,
             };
+            std.mem.copy(*Node, node.list(), init_list.items);
             return &node.base;
         }
 
@@ -1381,12 +1384,13 @@ const Parser = struct {
                 const next = (try p.parseExpr()) orelse break;
                 try init_list.append(next);
             }
-            const node = try p.arena.allocator.create(Node.ArrayInitializerDot);
+            const node = try Node.ArrayInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
             node.* = .{
                 .dot = dot,
                 .rtoken = try p.expectToken(.RBrace),
-                .list = try p.arena.allocator.dupe(*Node, init_list.items),
+                .list_len = init_list.items.len,
             };
+            std.mem.copy(*Node, node.list(), init_list.items);
             return &node.base;
         }
 
@@ -1394,7 +1398,7 @@ const Parser = struct {
         node.* = .{
             .dot = dot,
             .rtoken = try p.expectToken(.RBrace),
-            .list = &[0]*Node{},
+            .list_len = 0,
         };
         return &node.base;
     }
lib/std/zig/render.zig
@@ -620,13 +620,13 @@ fn renderExpression(
                 .ArrayInitializerDot => blk: {
                     const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
                     rtoken = casted.rtoken;
-                    exprs = casted.list;
+                    exprs = casted.list();
                     break :blk .{ .dot = casted.dot };
                 },
                 .ArrayInitializer => blk: {
                     const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base);
                     rtoken = casted.rtoken;
-                    exprs = casted.list;
+                    exprs = casted.list();
                     break :blk .{ .node = casted.lhs };
                 },
                 else => unreachable,
@@ -784,13 +784,13 @@ fn renderExpression(
                 .StructInitializerDot => blk: {
                     const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
                     rtoken = casted.rtoken;
-                    field_inits = casted.list;
+                    field_inits = casted.list();
                     break :blk .{ .dot = casted.dot };
                 },
                 .StructInitializer => blk: {
                     const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
                     rtoken = casted.rtoken;
-                    field_inits = casted.list;
+                    field_inits = casted.list();
                     break :blk .{ .node = casted.lhs };
                 },
                 else => unreachable,