| author | |
| committer | |
| log | d57d9448aa322c1818de110adeb3cc69ac5dbcd9 |
| tree | 9bef690df27fc49b002aef664725fb01a892351d |
| parent | 3c5d581ce35b137a7b80ac1431c1d9132e281fef |
block statements are now directly following the Block AST node rather
than a singly linked list. This had negligible impact on performance:
throughput: 72.3 MiB/s => 72.7 MiB/s
however it greatly improves the API since the statements are laid out in
a flat array in memory.3 files changed, 48 insertions(+), 18 deletions(-)
lib/std/zig/ast.zig+36-7| ... | @@ -804,6 +804,7 @@ pub const Node = struct { | ... | @@ -804,6 +804,7 @@ pub const Node = struct { |
| 804 | } | 804 | } |
| 805 | }; | 805 | }; |
| 806 | 806 | ||
| 807 | /// The fields and decls Node pointers directly follow this struct in memory. | ||
| 807 | pub const ContainerDecl = struct { | 808 | pub const ContainerDecl = struct { |
| 808 | base: Node = Node{ .id = .ContainerDecl }, | 809 | base: Node = Node{ .id = .ContainerDecl }, |
| 809 | kind_token: TokenIndex, | 810 | kind_token: TokenIndex, |
| ... | @@ -1188,23 +1189,37 @@ pub const Node = struct { | ... | @@ -1188,23 +1189,37 @@ pub const Node = struct { |
| 1188 | } | 1189 | } |
| 1189 | }; | 1190 | }; |
| 1190 | 1191 | ||
| 1192 | /// The statements of the block follow Block directly in memory. | ||
| 1191 | pub const Block = struct { | 1193 | pub const Block = struct { |
| 1192 | base: Node = Node{ .id = .Block }, | 1194 | base: Node = Node{ .id = .Block }, |
| 1193 | label: ?TokenIndex, | 1195 | statements_len: NodeIndex, |
| 1194 | lbrace: TokenIndex, | 1196 | lbrace: TokenIndex, |
| 1195 | statements: StatementList, | ||
| 1196 | rbrace: TokenIndex, | 1197 | rbrace: TokenIndex, |
| 1198 | label: ?TokenIndex, | ||
| 1197 | 1199 | ||
| 1198 | pub const StatementList = LinkedList(*Node); | 1200 | /// After this the caller must initialize the statements list. |
| 1201 | pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*Block { | ||
| 1202 | const bytes = try allocator.alignedAlloc(u8, @alignOf(Block), sizeInBytes(statements_len)); | ||
| 1203 | return @ptrCast(*Block, bytes.ptr); | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | pub fn free(self: *Block, allocator: *mem.Allocator) void { | ||
| 1207 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.statements_len)]; | ||
| 1208 | allocator.free(bytes); | ||
| 1209 | } | ||
| 1199 | 1210 | ||
| 1200 | pub fn iterate(self: *const Block) Node.Iterator { | 1211 | pub fn iterate(self: *const Block) Node.Iterator { |
| 1201 | return .{ .parent_node = &self.base, .index = 0, .node = self.statements.first }; | 1212 | return .{ .parent_node = &self.base, .index = 0, .node = null }; |
| 1202 | } | 1213 | } |
| 1203 | 1214 | ||
| 1204 | pub fn iterateNext(self: *const Block, it: *Node.Iterator) ?*Node { | 1215 | pub fn iterateNext(self: *const Block, it: *Node.Iterator) ?*Node { |
| 1205 | const child = it.node orelse return null; | 1216 | var i = it.index; |
| 1206 | it.node = child.next; | 1217 | it.index += 1; |
| 1207 | return child.data; | 1218 | |
| 1219 | if (i < self.statements_len) return self.statementsConst()[i]; | ||
| 1220 | i -= self.statements_len; | ||
| 1221 | |||
| 1222 | return null; | ||
| 1208 | } | 1223 | } |
| 1209 | 1224 | ||
| 1210 | pub fn firstToken(self: *const Block) TokenIndex { | 1225 | pub fn firstToken(self: *const Block) TokenIndex { |
| ... | @@ -1218,6 +1233,20 @@ pub const Node = struct { | ... | @@ -1218,6 +1233,20 @@ pub const Node = struct { |
| 1218 | pub fn lastToken(self: *const Block) TokenIndex { | 1233 | pub fn lastToken(self: *const Block) TokenIndex { |
| 1219 | return self.rbrace; | 1234 | return self.rbrace; |
| 1220 | } | 1235 | } |
| 1236 | |||
| 1237 | pub fn statements(self: *Block) []*Node { | ||
| 1238 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(Block); | ||
| 1239 | return @ptrCast([*]*Node, decls_start)[0..self.statements_len]; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | pub fn statementsConst(self: *const Block) []const *Node { | ||
| 1243 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Block); | ||
| 1244 | return @ptrCast([*]const *Node, decls_start)[0..self.statements_len]; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | fn sizeInBytes(statements_len: NodeIndex) usize { | ||
| 1248 | return @sizeOf(Block) + @sizeOf(*Node) * @as(usize, statements_len); | ||
| 1249 | } | ||
| 1221 | }; | 1250 | }; |
| 1222 | 1251 | ||
| 1223 | pub const Defer = struct { | 1252 | pub const Defer = struct { |
lib/std/zig/parse.zig+7-5| ... | @@ -1178,8 +1178,9 @@ const Parser = struct { | ... | @@ -1178,8 +1178,9 @@ const Parser = struct { |
| 1178 | fn parseBlock(p: *Parser) !?*Node { | 1178 | fn parseBlock(p: *Parser) !?*Node { |
| 1179 | const lbrace = p.eatToken(.LBrace) orelse return null; | 1179 | const lbrace = p.eatToken(.LBrace) orelse return null; |
| 1180 | 1180 | ||
| 1181 | var statements = Node.Block.StatementList{}; | 1181 | var statements = std.ArrayList(*Node).init(p.gpa); |
| 1182 | var statements_it = &statements.first; | 1182 | defer statements.deinit(); |
| 1183 | |||
| 1183 | while (true) { | 1184 | while (true) { |
| 1184 | const statement = (p.parseStatement() catch |err| switch (err) { | 1185 | const statement = (p.parseStatement() catch |err| switch (err) { |
| 1185 | error.OutOfMemory => return error.OutOfMemory, | 1186 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -1189,18 +1190,19 @@ const Parser = struct { | ... | @@ -1189,18 +1190,19 @@ const Parser = struct { |
| 1189 | continue; | 1190 | continue; |
| 1190 | }, | 1191 | }, |
| 1191 | }) orelse break; | 1192 | }) orelse break; |
| 1192 | statements_it = try p.llpush(*Node, statements_it, statement); | 1193 | try statements.append(statement); |
| 1193 | } | 1194 | } |
| 1194 | 1195 | ||
| 1195 | const rbrace = try p.expectToken(.RBrace); | 1196 | const rbrace = try p.expectToken(.RBrace); |
| 1196 | 1197 | ||
| 1197 | const block_node = try p.arena.allocator.create(Node.Block); | 1198 | const block_node = try Node.Block.alloc(&p.arena.allocator, statements.items.len); |
| 1198 | block_node.* = .{ | 1199 | block_node.* = .{ |
| 1199 | .label = null, | 1200 | .label = null, |
| 1200 | .lbrace = lbrace, | 1201 | .lbrace = lbrace, |
| 1201 | .statements = statements, | 1202 | .statements_len = statements.items.len, |
| 1202 | .rbrace = rbrace, | 1203 | .rbrace = rbrace, |
| 1203 | }; | 1204 | }; |
| 1205 | std.mem.copy(*Node, block_node.statements(), statements.items); | ||
| 1204 | 1206 | ||
| 1205 | return &block_node.base; | 1207 | return &block_node.base; |
| 1206 | } | 1208 | } |
lib/std/zig/render.zig+5-6| ... | @@ -358,21 +358,20 @@ fn renderExpression( | ... | @@ -358,21 +358,20 @@ fn renderExpression( |
| 358 | try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); | 358 | try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | if (block.statements.first == null) { | 361 | if (block.statements_len == 0) { |
| 362 | try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None); | 362 | try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None); |
| 363 | return renderToken(tree, stream, block.rbrace, indent, start_col, space); | 363 | return renderToken(tree, stream, block.rbrace, indent, start_col, space); |
| 364 | } else { | 364 | } else { |
| 365 | const block_indent = indent + indent_delta; | 365 | const block_indent = indent + indent_delta; |
| 366 | try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline); | 366 | try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline); |
| 367 | 367 | ||
| 368 | var it = block.statements.first; | 368 | const block_statements = block.statements(); |
| 369 | while (it) |statement_node| : (it = statement_node.next) { | 369 | for (block_statements) |statement, i| { |
| 370 | const statement = statement_node.data; | ||
| 371 | try stream.writeByteNTimes(' ', block_indent); | 370 | try stream.writeByteNTimes(' ', block_indent); |
| 372 | try renderStatement(allocator, stream, tree, block_indent, start_col, statement); | 371 | try renderStatement(allocator, stream, tree, block_indent, start_col, statement); |
| 373 | 372 | ||
| 374 | if (statement_node.next) |next_statement| { | 373 | if (i + 1 < block_statements.len) { |
| 375 | try renderExtraNewline(tree, stream, start_col, next_statement.data); | 374 | try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]); |
| 376 | } | 375 | } |
| 377 | } | 376 | } |
| 378 | 377 |