authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 02:14:44-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 02:14:44-05:00
log445b03384a5ffcace11927aa9dd5f21604527f5c
tree9cab533e7ac95f74d0aad7e986f86d0f7a2c307e
parentf2d601661d286b135293373a83ce1a8628272379

introduce std.heap.ArenaAllocator and std.heap.DirectAllocator

* DirectAllocator does the underlying syscall for every allocation. * ArenaAllocator takes another allocator as an argument and allocates bytes up front, falling back to DirectAllocator with increasingly large allocation sizes, to avoid calling it too often. Then the entire arena can be freed at once. The self hosted parser is updated to take advantage of ArenaAllocator for the AST that it returns. This significantly reduces the complexity of cleanup code. docgen and build runner are updated to use the combination of ArenaAllocator and DirectAllocator instead of IncrementingAllocator, which is now deprecated in favor of FixedBufferAllocator combined with DirectAllocator. The C allocator calls aligned_alloc instead of malloc, in order to respect the alignment parameter. Added asserts in Allocator to ensure that implementors of the interface return slices of the correct size. Fixed a bug in Allocator when you call realloc to grow the allocation.

10 files changed, 395 insertions(+), 130 deletions(-)

doc/docgen.zig+7-4
...@@ -13,10 +13,13 @@ const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();...@@ -13,10 +13,13 @@ const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
13const tmp_dir_name = "docgen_tmp";13const tmp_dir_name = "docgen_tmp";
1414
15pub fn main() !void {15pub fn main() !void {
16 // TODO use a more general purpose allocator here16 var direct_allocator = std.heap.DirectAllocator.init();
17 var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size);17 defer direct_allocator.deinit();
18 defer inc_allocator.deinit();18
19 const allocator = &inc_allocator.allocator;19 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
20 defer arena.deinit();
21
22 const allocator = &arena.allocator;
2023
21 var args_it = os.args();24 var args_it = os.args();
2225
src-self-hosted/main.zig+1-1
...@@ -575,7 +575,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {...@@ -575,7 +575,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
575 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);575 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
576 defer parser.deinit();576 defer parser.deinit();
577577
578 const tree = try parser.parse();578 var tree = try parser.parse();
579 defer tree.deinit();579 defer tree.deinit();
580580
581 const baf = try io.BufferedAtomicFile.create(allocator, file_path);581 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
src-self-hosted/module.zig+1-1
...@@ -241,7 +241,7 @@ pub const Module = struct {...@@ -241,7 +241,7 @@ pub const Module = struct {
241 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);241 var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
242 defer parser.deinit();242 defer parser.deinit();
243243
244 const tree = try parser.parse();244 var tree = try parser.parse();
245 defer tree.deinit();245 defer tree.deinit();
246246
247 var stderr_file = try std.io.getStdErr();247 var stderr_file = try std.io.getStdErr();
std/c/index.zig+1
...@@ -45,6 +45,7 @@ pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;...@@ -45,6 +45,7 @@ pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
4747
48pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
48pub extern "c" fn malloc(usize) ?&c_void;49pub extern "c" fn malloc(usize) ?&c_void;
49pub extern "c" fn realloc(&c_void, usize) ?&c_void;50pub extern "c" fn realloc(&c_void, usize) ?&c_void;
50pub extern "c" fn free(&c_void) void;51pub extern "c" fn free(&c_void) void;
std/heap.zig+280-47
...@@ -17,7 +17,7 @@ var c_allocator_state = Allocator {...@@ -17,7 +17,7 @@ var c_allocator_state = Allocator {
17};17};
1818
19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {19fn cAlloc(self: &Allocator, n: usize, alignment: u29) ![]u8 {
20 return if (c.malloc(usize(n))) |buf|20 return if (c.aligned_alloc(alignment, n)) |buf|
21 @ptrCast(&u8, buf)[0..n]21 @ptrCast(&u8, buf)[0..n]
22 else22 else
23 error.OutOfMemory;23 error.OutOfMemory;
...@@ -39,83 +39,279 @@ fn cFree(self: &Allocator, old_mem: []u8) void {...@@ -39,83 +39,279 @@ fn cFree(self: &Allocator, old_mem: []u8) void {
39 c.free(old_ptr);39 c.free(old_ptr);
40}40}
4141
42/// Use this allocator when you want to allocate completely up front and guarantee that individual
43/// allocations will never make syscalls.
42pub const IncrementingAllocator = struct {44pub const IncrementingAllocator = struct {
43 allocator: Allocator,45 allocator: Allocator,
44 bytes: []u8,46 bytes: []u8,
45 end_index: usize,47 end_index: usize,
46 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,48 direct_allocator: DirectAllocator,
49
50 pub fn init(capacity: usize) !IncrementingAllocator {
51 var direct_allocator = DirectAllocator.init();
52 const bytes = try direct_allocator.allocator.alloc(u8, capacity);
53 errdefer direct_allocator.allocator.free(bytes);
54
55 return IncrementingAllocator {
56 .allocator = Allocator {
57 .allocFn = alloc,
58 .reallocFn = realloc,
59 .freeFn = free,
60 },
61 .bytes = bytes,
62 .direct_allocator = direct_allocator,
63 .end_index = 0,
64 };
65 }
66
67 pub fn deinit(self: &IncrementingAllocator) void {
68 self.direct_allocator.allocator.free(self.bytes);
69 self.direct_allocator.deinit();
70 }
71
72 fn reset(self: &IncrementingAllocator) void {
73 self.end_index = 0;
74 }
75
76 fn bytesLeft(self: &const IncrementingAllocator) usize {
77 return self.bytes.len - self.end_index;
78 }
79
80 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
81 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
82 const addr = @ptrToInt(&self.bytes[self.end_index]);
83 const rem = @rem(addr, alignment);
84 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
85 const adjusted_index = self.end_index + march_forward_bytes;
86 const new_end_index = adjusted_index + n;
87 if (new_end_index > self.bytes.len) {
88 return error.OutOfMemory;
89 }
90 const result = self.bytes[adjusted_index .. new_end_index];
91 self.end_index = new_end_index;
92 return result;
93 }
94
95 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
96 if (new_size <= old_mem.len) {
97 return old_mem[0..new_size];
98 } else {
99 const result = try alloc(allocator, new_size, alignment);
100 mem.copy(u8, result, old_mem);
101 return result;
102 }
103 }
104
105 fn free(allocator: &Allocator, bytes: []u8) void {
106 // Do nothing. That's the point of an incrementing allocator.
107 }
108};
109
110/// This allocator makes a syscall directly for every allocation and free.
111pub const DirectAllocator = struct {
112 allocator: Allocator,
113 heap_handle: ?HeapHandle,
114
115 const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
116
117 //pub const canary_bytes = []u8 {48, 239, 128, 46, 18, 49, 147, 9, 195, 59, 203, 3, 245, 54, 9, 122};
118 //pub const want_safety = switch (builtin.mode) {
119 // builtin.Mode.Debug => true,
120 // builtin.Mode.ReleaseSafe => true,
121 // else => false,
122 //};
123
124 pub fn init() DirectAllocator {
125 return DirectAllocator {
126 .allocator = Allocator {
127 .allocFn = alloc,
128 .reallocFn = realloc,
129 .freeFn = free,
130 },
131 .heap_handle = if (builtin.os == Os.windows) null else {},
132 };
133 }
134
135 pub fn deinit(self: &DirectAllocator) void {
136 switch (builtin.os) {
137 Os.windows => if (self.heap_handle) |heap_handle| {
138 _ = os.windows.HeapDestroy(heap_handle);
139 },
140 else => {},
141 }
142 }
143
144 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
145 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
47146
48 fn init(capacity: usize) !IncrementingAllocator {
49 switch (builtin.os) {147 switch (builtin.os) {
50 Os.linux, Os.macosx, Os.ios => {148 Os.linux, Os.macosx, Os.ios => {
149 assert(alignment <= os.page_size);
51 const p = os.posix;150 const p = os.posix;
52 const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE,151 const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE,
53 p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0);152 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
54 if (addr == p.MAP_FAILED) {153 if (addr == p.MAP_FAILED) {
55 return error.OutOfMemory;154 return error.OutOfMemory;
56 }155 }
57 return IncrementingAllocator {156 return @intToPtr(&u8, addr)[0..n];
58 .allocator = Allocator {157 },
59 .allocFn = alloc,158 Os.windows => {
60 .reallocFn = realloc,159 const amt = n + alignment + @sizeOf(usize);
61 .freeFn = free,160 const heap_handle = self.heap_handle ?? blk: {
62 },161 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
63 .bytes = @intToPtr(&u8, addr)[0..capacity],162 self.heap_handle = hh;
64 .end_index = 0,163 break :blk hh;
65 .heap_handle = {},
66 };164 };
165 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) ?? return error.OutOfMemory;
166 const root_addr = @ptrToInt(ptr);
167 const rem = @rem(root_addr, alignment);
168 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
169 const adjusted_addr = root_addr + march_forward_bytes;
170 const record_addr = adjusted_addr + n;
171 *@intToPtr(&align(1) usize, record_addr) = root_addr;
172 return @intToPtr(&u8, adjusted_addr)[0..n];
173 },
174 else => @compileError("Unsupported OS"),
175 }
176 }
177
178 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
179 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
180
181 switch (builtin.os) {
182 Os.linux, Os.macosx, Os.ios => {
183 if (new_size <= old_mem.len) {
184 const base_addr = @ptrToInt(old_mem.ptr);
185 const old_addr_end = base_addr + old_mem.len;
186 const new_addr_end = base_addr + new_size;
187 const rem = @rem(new_addr_end, os.page_size);
188 const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem);
189 if (old_addr_end > new_addr_end_rounded) {
190 _ = os.posix.munmap(@intToPtr(&u8, new_addr_end_rounded), old_addr_end - new_addr_end_rounded);
191 }
192 return old_mem[0..new_size];
193 }
194
195 const result = try alloc(allocator, new_size, alignment);
196 mem.copy(u8, result, old_mem);
197 return result;
67 },198 },
68 Os.windows => {199 Os.windows => {
69 const heap_handle = os.windows.GetProcessHeap() ?? return error.OutOfMemory;200 const old_adjusted_addr = @ptrToInt(old_mem.ptr);
70 const ptr = os.windows.HeapAlloc(heap_handle, 0, capacity) ?? return error.OutOfMemory;201 const old_record_addr = old_adjusted_addr + old_mem.len;
71 return IncrementingAllocator {202 const root_addr = *@intToPtr(&align(1) usize, old_record_addr);
72 .allocator = Allocator {203 const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
73 .allocFn = alloc,204 const amt = new_size + alignment + @sizeOf(usize);
74 .reallocFn = realloc,205 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
75 .freeFn = free,206 if (new_size > old_mem.len) return error.OutOfMemory;
76 },207 const new_record_addr = old_record_addr - new_size + old_mem.len;
77 .bytes = @ptrCast(&u8, ptr)[0..capacity],208 *@intToPtr(&align(1) usize, new_record_addr) = root_addr;
78 .end_index = 0,209 return old_mem[0..new_size];
79 .heap_handle = heap_handle,
80 };210 };
211 const offset = old_adjusted_addr - root_addr;
212 const new_root_addr = @ptrToInt(new_ptr);
213 const new_adjusted_addr = new_root_addr + offset;
214 assert(new_adjusted_addr % alignment == 0);
215 const new_record_addr = new_adjusted_addr + new_size;
216 *@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;
217 return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
81 },218 },
82 else => @compileError("Unsupported OS"),219 else => @compileError("Unsupported OS"),
83 }220 }
84 }221 }
85222
86 fn deinit(self: &IncrementingAllocator) void {223 fn free(allocator: &Allocator, bytes: []u8) void {
224 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
225
87 switch (builtin.os) {226 switch (builtin.os) {
88 Os.linux, Os.macosx, Os.ios => {227 Os.linux, Os.macosx, Os.ios => {
89 _ = os.posix.munmap(self.bytes.ptr, self.bytes.len);228 _ = os.posix.munmap(bytes.ptr, bytes.len);
90 },229 },
91 Os.windows => {230 Os.windows => {
92 _ = os.windows.HeapFree(self.heap_handle, 0, @ptrCast(os.windows.LPVOID, self.bytes.ptr));231 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
232 const root_addr = *@intToPtr(&align(1) usize, record_addr);
233 const ptr = @intToPtr(os.windows.LPVOID, root_addr);
234 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
93 },235 },
94 else => @compileError("Unsupported OS"),236 else => @compileError("Unsupported OS"),
95 }237 }
96 }238 }
239};
97240
98 fn reset(self: &IncrementingAllocator) void {241/// This allocator takes an existing allocator, wraps it, and provides an interface
99 self.end_index = 0;242/// where you can allocate without freeing, and then free it all together.
243pub const ArenaAllocator = struct {
244 pub allocator: Allocator,
245
246 child_allocator: &Allocator,
247 buffer_list: std.LinkedList([]u8),
248 end_index: usize,
249
250 const BufNode = std.LinkedList([]u8).Node;
251
252 pub fn init(child_allocator: &Allocator) ArenaAllocator {
253 return ArenaAllocator {
254 .allocator = Allocator {
255 .allocFn = alloc,
256 .reallocFn = realloc,
257 .freeFn = free,
258 },
259 .child_allocator = child_allocator,
260 .buffer_list = std.LinkedList([]u8).init(),
261 .end_index = 0,
262 };
100 }263 }
101264
102 fn bytesLeft(self: &const IncrementingAllocator) usize {265 pub fn deinit(self: &ArenaAllocator) void {
103 return self.bytes.len - self.end_index;266 var it = self.buffer_list.first;
267 while (it) |node| {
268 // this has to occur before the free because the free frees node
269 it = node.next;
270
271 self.child_allocator.free(node.data);
272 }
273 }
274
275 fn createNode(self: &ArenaAllocator, prev_len: usize, minimum_size: usize) !&BufNode {
276 const actual_min_size = minimum_size + @sizeOf(BufNode);
277 var len = prev_len;
278 while (true) {
279 len += len / 2;
280 len += os.page_size - @rem(len, os.page_size);
281 if (len >= actual_min_size) break;
282 }
283 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
284 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
285 const buf_node = &buf_node_slice[0];
286 *buf_node = BufNode {
287 .data = buf,
288 .prev = null,
289 .next = null,
290 };
291 self.buffer_list.append(buf_node);
292 self.end_index = 0;
293 return buf_node;
104 }294 }
105295
106 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {296 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
107 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);297 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
108 const addr = @ptrToInt(&self.bytes[self.end_index]);298
109 const rem = @rem(addr, alignment);299 var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment);
110 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);300 while (true) {
111 const adjusted_index = self.end_index + march_forward_bytes;301 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
112 const new_end_index = adjusted_index + n;302 const addr = @ptrToInt(&cur_buf[self.end_index]);
113 if (new_end_index > self.bytes.len) {303 const rem = @rem(addr, alignment);
114 return error.OutOfMemory;304 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
305 const adjusted_index = self.end_index + march_forward_bytes;
306 const new_end_index = adjusted_index + n;
307 if (new_end_index > cur_buf.len) {
308 cur_node = try self.createNode(cur_buf.len, n + alignment);
309 continue;
310 }
311 const result = cur_buf[adjusted_index .. new_end_index];
312 self.end_index = new_end_index;
313 return result;
115 }314 }
116 const result = self.bytes[adjusted_index .. new_end_index];
117 self.end_index = new_end_index;
118 return result;
119 }315 }
120316
121 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {317 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
...@@ -128,11 +324,11 @@ pub const IncrementingAllocator = struct {...@@ -128,11 +324,11 @@ pub const IncrementingAllocator = struct {
128 }324 }
129 }325 }
130326
131 fn free(allocator: &Allocator, bytes: []u8) void {327 fn free(allocator: &Allocator, bytes: []u8) void { }
132 // Do nothing. That's the point of an incrementing allocator.
133 }
134};328};
135329
330
331
136test "c_allocator" {332test "c_allocator" {
137 if (builtin.link_libc) {333 if (builtin.link_libc) {
138 var slice = c_allocator.alloc(u8, 50) catch return;334 var slice = c_allocator.alloc(u8, 50) catch return;
...@@ -142,7 +338,7 @@ test "c_allocator" {...@@ -142,7 +338,7 @@ test "c_allocator" {
142}338}
143339
144test "IncrementingAllocator" {340test "IncrementingAllocator" {
145 const total_bytes = 100 * 1024 * 1024;341 const total_bytes = 10 * 1024 * 1024;
146 var inc_allocator = try IncrementingAllocator.init(total_bytes);342 var inc_allocator = try IncrementingAllocator.init(total_bytes);
147 defer inc_allocator.deinit();343 defer inc_allocator.deinit();
148344
...@@ -161,3 +357,40 @@ test "IncrementingAllocator" {...@@ -161,3 +357,40 @@ test "IncrementingAllocator" {
161 assert(inc_allocator.bytesLeft() == total_bytes);357 assert(inc_allocator.bytesLeft() == total_bytes);
162}358}
163359
360test "DirectAllocator" {
361 var direct_allocator = DirectAllocator.init();
362 defer direct_allocator.deinit();
363
364 const allocator = &direct_allocator.allocator;
365 try testAllocator(allocator);
366}
367
368test "ArenaAllocator" {
369 var direct_allocator = DirectAllocator.init();
370 defer direct_allocator.deinit();
371
372 var arena_allocator = ArenaAllocator.init(&direct_allocator.allocator);
373 defer arena_allocator.deinit();
374
375 try testAllocator(&arena_allocator.allocator);
376}
377
378fn testAllocator(allocator: &mem.Allocator) !void {
379 var slice = try allocator.alloc(&i32, 100);
380
381 for (slice) |*item, i| {
382 *item = try allocator.create(i32);
383 **item = i32(i);
384 }
385
386 for (slice) |item, i| {
387 allocator.destroy(item);
388 }
389
390 slice = try allocator.realloc(&i32, slice, 20000);
391 slice = try allocator.realloc(&i32, slice, 50);
392 slice = try allocator.realloc(&i32, slice, 25);
393 slice = try allocator.realloc(&i32, slice, 10);
394
395 allocator.free(slice);
396}
std/mem.zig+8-4
...@@ -44,6 +44,7 @@ pub const Allocator = struct {...@@ -44,6 +44,7 @@ pub const Allocator = struct {
44 {44 {
45 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;45 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
46 const byte_slice = try self.allocFn(self, byte_count, alignment);46 const byte_slice = try self.allocFn(self, byte_count, alignment);
47 assert(byte_slice.len == byte_count);
47 // This loop should get optimized out in ReleaseFast mode48 // This loop should get optimized out in ReleaseFast mode
48 for (byte_slice) |*byte| {49 for (byte_slice) |*byte| {
49 *byte = undefined;50 *byte = undefined;
...@@ -65,9 +66,12 @@ pub const Allocator = struct {...@@ -65,9 +66,12 @@ pub const Allocator = struct {
65 const old_byte_slice = ([]u8)(old_mem);66 const old_byte_slice = ([]u8)(old_mem);
66 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;67 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
67 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);68 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
68 // This loop should get optimized out in ReleaseFast mode69 assert(byte_slice.len == byte_count);
69 for (byte_slice[old_byte_slice.len..]) |*byte| {70 if (n > old_mem.len) {
70 *byte = undefined;71 // This loop should get optimized out in ReleaseFast mode
72 for (byte_slice[old_byte_slice.len..]) |*byte| {
73 *byte = undefined;
74 }
71 }75 }
72 return ([]T)(@alignCast(alignment, byte_slice));76 return ([]T)(@alignCast(alignment, byte_slice));
73 }77 }
...@@ -94,6 +98,7 @@ pub const Allocator = struct {...@@ -94,6 +98,7 @@ pub const Allocator = struct {
94 const byte_count = @sizeOf(T) * n;98 const byte_count = @sizeOf(T) * n;
9599
96 const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;100 const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;
101 assert(byte_slice.len == byte_count);
97 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));102 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
98 }103 }
99104
...@@ -151,7 +156,6 @@ pub const FixedBufferAllocator = struct {...@@ -151,7 +156,6 @@ pub const FixedBufferAllocator = struct {
151 fn free(allocator: &Allocator, bytes: []u8) void { }156 fn free(allocator: &Allocator, bytes: []u8) void { }
152};157};
153158
154
155/// Copy all of source into dest at position 0.159/// Copy all of source into dest at position 0.
156/// dest.len must be >= source.len.160/// dest.len must be >= source.len.
157pub fn copy(comptime T: type, dest: []T, source: []const T) void {161pub fn copy(comptime T: type, dest: []T, source: []const T) void {
std/os/windows/index.zig+17-5
...@@ -22,7 +22,7 @@ pub extern "kernel32" stdcallcc fn CreatePipe(hReadPipe: &HANDLE, hWritePipe: &H...@@ -22,7 +22,7 @@ pub extern "kernel32" stdcallcc fn CreatePipe(hReadPipe: &HANDLE, hWritePipe: &H
2222
23pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lpCommandLine: LPSTR,23pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lpCommandLine: LPSTR,
24 lpProcessAttributes: ?&SECURITY_ATTRIBUTES, lpThreadAttributes: ?&SECURITY_ATTRIBUTES, bInheritHandles: BOOL,24 lpProcessAttributes: ?&SECURITY_ATTRIBUTES, lpThreadAttributes: ?&SECURITY_ATTRIBUTES, bInheritHandles: BOOL,
25 dwCreationFlags: DWORD, lpEnvironment: ?LPVOID, lpCurrentDirectory: ?LPCSTR, lpStartupInfo: &STARTUPINFOA,25 dwCreationFlags: DWORD, lpEnvironment: ?&c_void, lpCurrentDirectory: ?LPCSTR, lpStartupInfo: &STARTUPINFOA,
26 lpProcessInformation: &PROCESS_INFORMATION) BOOL;26 lpProcessInformation: &PROCESS_INFORMATION) BOOL;
2727
28pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR,28pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR,
...@@ -61,16 +61,24 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz...@@ -61,16 +61,24 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz
6161
62pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;62pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
6363
64pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
65pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
66pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void;
67pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) SIZE_T;
68pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) BOOL;
69pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
70pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
71
64pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;72pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
6573
66pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?LPVOID;74pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?&c_void;
6775
68pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) BOOL;76pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void) BOOL;
6977
70pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,78pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
71 dwFlags: DWORD) BOOL;79 dwFlags: DWORD) BOOL;
7280
73pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID,81pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
74 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,82 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
75 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;83 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
7684
...@@ -201,7 +209,7 @@ pub const VOLUME_NAME_NT = 0x2;...@@ -201,7 +209,7 @@ pub const VOLUME_NAME_NT = 0x2;
201209
202pub const SECURITY_ATTRIBUTES = extern struct {210pub const SECURITY_ATTRIBUTES = extern struct {
203 nLength: DWORD,211 nLength: DWORD,
204 lpSecurityDescriptor: ?LPVOID,212 lpSecurityDescriptor: ?&c_void,
205 bInheritHandle: BOOL,213 bInheritHandle: BOOL,
206};214};
207pub const PSECURITY_ATTRIBUTES = &SECURITY_ATTRIBUTES;215pub const PSECURITY_ATTRIBUTES = &SECURITY_ATTRIBUTES;
...@@ -296,3 +304,7 @@ pub const MOVEFILE_WRITE_THROUGH = 8;...@@ -296,3 +304,7 @@ pub const MOVEFILE_WRITE_THROUGH = 8;
296pub const FILE_BEGIN = 0;304pub const FILE_BEGIN = 0;
297pub const FILE_CURRENT = 1;305pub const FILE_CURRENT = 1;
298pub const FILE_END = 2;306pub const FILE_END = 2;
307
308pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
309pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
310pub const HEAP_NO_SERIALIZE = 0x00000001;
std/special/build_runner.zig+10-4
...@@ -12,11 +12,17 @@ const warn = std.debug.warn;...@@ -12,11 +12,17 @@ const warn = std.debug.warn;
12pub fn main() !void {12pub fn main() !void {
13 var arg_it = os.args();13 var arg_it = os.args();
1414
15 // TODO use a more general purpose allocator here15 // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
16 var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024);16 // one shot program. We don't need to waste time freeing memory and finding places to squish
17 defer inc_allocator.deinit();17 // bytes into. So we free everything all at once at the very end.
1818
19 const allocator = &inc_allocator.allocator;19 var direct_allocator = std.heap.DirectAllocator.init();
20 defer direct_allocator.deinit();
21
22 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
23 defer arena.deinit();
24
25 const allocator = &arena.allocator;
2026
2127
22 // skip my own exe name28 // skip my own exe name
std/zig/parser.zig+64-61
...@@ -13,7 +13,7 @@ const io = std.io;...@@ -13,7 +13,7 @@ const io = std.io;
13const warn = std.debug.warn;13const warn = std.debug.warn;
1414
15pub const Parser = struct {15pub const Parser = struct {
16 allocator: &mem.Allocator,16 util_allocator: &mem.Allocator,
17 tokenizer: &Tokenizer,17 tokenizer: &Tokenizer,
18 put_back_tokens: [2]Token,18 put_back_tokens: [2]Token,
19 put_back_count: usize,19 put_back_count: usize,
...@@ -21,9 +21,10 @@ pub const Parser = struct {...@@ -21,9 +21,10 @@ pub const Parser = struct {
2121
22 pub const Tree = struct {22 pub const Tree = struct {
23 root_node: &ast.NodeRoot,23 root_node: &ast.NodeRoot,
24 arena_allocator: std.heap.ArenaAllocator,
2425
25 pub fn deinit(self: &const Tree) void {26 pub fn deinit(self: &Tree) void {
26 // TODO free the whole arena27 self.arena_allocator.deinit();
27 }28 }
28 };29 };
2930
...@@ -33,12 +34,10 @@ pub const Parser = struct {...@@ -33,12 +34,10 @@ pub const Parser = struct {
33 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );34 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );
34 utility_bytes: []align(utility_bytes_align) u8,35 utility_bytes: []align(utility_bytes_align) u8,
3536
36 /// `allocator` should be an arena allocator. Parser never calls free on anything. After you're37 /// allocator must outlive the returned Parser and all the parse trees you create with it.
37 /// done with a Parser, free the arena. After the arena is freed, no member functions of Parser
38 /// may be called.
39 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser {38 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser {
40 return Parser {39 return Parser {
41 .allocator = allocator,40 .util_allocator = allocator,
42 .tokenizer = tokenizer,41 .tokenizer = tokenizer,
43 .put_back_tokens = undefined,42 .put_back_tokens = undefined,
44 .put_back_count = 0,43 .put_back_count = 0,
...@@ -48,7 +47,7 @@ pub const Parser = struct {...@@ -48,7 +47,7 @@ pub const Parser = struct {
48 }47 }
4948
50 pub fn deinit(self: &Parser) void {49 pub fn deinit(self: &Parser) void {
51 self.allocator.free(self.utility_bytes);50 self.util_allocator.free(self.utility_bytes);
52 }51 }
5352
54 const TopLevelDeclCtx = struct {53 const TopLevelDeclCtx = struct {
...@@ -101,8 +100,11 @@ pub const Parser = struct {...@@ -101,8 +100,11 @@ pub const Parser = struct {
101 var stack = self.initUtilityArrayList(State);100 var stack = self.initUtilityArrayList(State);
102 defer self.deinitUtilityArrayList(stack);101 defer self.deinitUtilityArrayList(stack);
103102
104 const root_node = try self.createRoot();103 var arena_allocator = std.heap.ArenaAllocator.init(self.util_allocator);
105 // TODO errdefer arena free root node104 errdefer arena_allocator.deinit();
105
106 const arena = &arena_allocator.allocator;
107 const root_node = try self.createRoot(arena);
106108
107 try stack.append(State.TopLevel);109 try stack.append(State.TopLevel);
108110
...@@ -130,7 +132,7 @@ pub const Parser = struct {...@@ -130,7 +132,7 @@ pub const Parser = struct {
130 stack.append(State { .TopLevelExtern = token }) catch unreachable;132 stack.append(State { .TopLevelExtern = token }) catch unreachable;
131 continue;133 continue;
132 },134 },
133 Token.Id.Eof => return Tree {.root_node = root_node},135 Token.Id.Eof => return Tree {.root_node = root_node, .arena_allocator = arena_allocator},
134 else => {136 else => {
135 self.putBackToken(token);137 self.putBackToken(token);
136 stack.append(State { .TopLevelExtern = null }) catch unreachable;138 stack.append(State { .TopLevelExtern = null }) catch unreachable;
...@@ -164,7 +166,7 @@ pub const Parser = struct {...@@ -164,7 +166,7 @@ pub const Parser = struct {
164 Token.Id.Keyword_var, Token.Id.Keyword_const => {166 Token.Id.Keyword_var, Token.Id.Keyword_const => {
165 stack.append(State.TopLevel) catch unreachable;167 stack.append(State.TopLevel) catch unreachable;
166 // TODO shouldn't need these casts168 // TODO shouldn't need these casts
167 const var_decl_node = try self.createAttachVarDecl(&root_node.decls, ctx.visib_token,169 const var_decl_node = try self.createAttachVarDecl(arena, &root_node.decls, ctx.visib_token,
168 token, (?Token)(null), ctx.extern_token);170 token, (?Token)(null), ctx.extern_token);
169 try stack.append(State { .VarDecl = var_decl_node });171 try stack.append(State { .VarDecl = var_decl_node });
170 continue;172 continue;
...@@ -172,7 +174,7 @@ pub const Parser = struct {...@@ -172,7 +174,7 @@ pub const Parser = struct {
172 Token.Id.Keyword_fn => {174 Token.Id.Keyword_fn => {
173 stack.append(State.TopLevel) catch unreachable;175 stack.append(State.TopLevel) catch unreachable;
174 // TODO shouldn't need these casts176 // TODO shouldn't need these casts
175 const fn_proto = try self.createAttachFnProto(&root_node.decls, token,177 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token,
176 ctx.extern_token, (?Token)(null), (?Token)(null), (?Token)(null));178 ctx.extern_token, (?Token)(null), (?Token)(null), (?Token)(null));
177 try stack.append(State { .FnDef = fn_proto });179 try stack.append(State { .FnDef = fn_proto });
178 try stack.append(State { .FnProto = fn_proto });180 try stack.append(State { .FnProto = fn_proto });
...@@ -185,7 +187,7 @@ pub const Parser = struct {...@@ -185,7 +187,7 @@ pub const Parser = struct {
185 stack.append(State.TopLevel) catch unreachable;187 stack.append(State.TopLevel) catch unreachable;
186 const fn_token = try self.eatToken(Token.Id.Keyword_fn);188 const fn_token = try self.eatToken(Token.Id.Keyword_fn);
187 // TODO shouldn't need this cast189 // TODO shouldn't need this cast
188 const fn_proto = try self.createAttachFnProto(&root_node.decls, fn_token,190 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, fn_token,
189 ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null));191 ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null));
190 try stack.append(State { .FnDef = fn_proto });192 try stack.append(State { .FnDef = fn_proto });
191 try stack.append(State { .FnProto = fn_proto });193 try stack.append(State { .FnProto = fn_proto });
...@@ -253,13 +255,13 @@ pub const Parser = struct {...@@ -253,13 +255,13 @@ pub const Parser = struct {
253 const token = self.getNextToken();255 const token = self.getNextToken();
254 switch (token.id) {256 switch (token.id) {
255 Token.Id.Keyword_return => {257 Token.Id.Keyword_return => {
256 try stack.append(State { .PrefixOp = try self.createPrefixOp(token,258 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,
257 ast.NodePrefixOp.PrefixOp.Return) });259 ast.NodePrefixOp.PrefixOp.Return) });
258 try stack.append(State.ExpectOperand);260 try stack.append(State.ExpectOperand);
259 continue;261 continue;
260 },262 },
261 Token.Id.Ampersand => {263 Token.Id.Ampersand => {
262 const prefix_op = try self.createPrefixOp(token, ast.NodePrefixOp.PrefixOp{264 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
263 .AddrOf = ast.NodePrefixOp.AddrOfInfo {265 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
264 .align_expr = null,266 .align_expr = null,
265 .bit_offset_start_token = null,267 .bit_offset_start_token = null,
...@@ -275,21 +277,21 @@ pub const Parser = struct {...@@ -275,21 +277,21 @@ pub const Parser = struct {
275 },277 },
276 Token.Id.Identifier => {278 Token.Id.Identifier => {
277 try stack.append(State {279 try stack.append(State {
278 .Operand = &(try self.createIdentifier(token)).base280 .Operand = &(try self.createIdentifier(arena, token)).base
279 });281 });
280 try stack.append(State.AfterOperand);282 try stack.append(State.AfterOperand);
281 continue;283 continue;
282 },284 },
283 Token.Id.IntegerLiteral => {285 Token.Id.IntegerLiteral => {
284 try stack.append(State {286 try stack.append(State {
285 .Operand = &(try self.createIntegerLiteral(token)).base287 .Operand = &(try self.createIntegerLiteral(arena, token)).base
286 });288 });
287 try stack.append(State.AfterOperand);289 try stack.append(State.AfterOperand);
288 continue;290 continue;
289 },291 },
290 Token.Id.FloatLiteral => {292 Token.Id.FloatLiteral => {
291 try stack.append(State {293 try stack.append(State {
292 .Operand = &(try self.createFloatLiteral(token)).base294 .Operand = &(try self.createFloatLiteral(arena, token)).base
293 });295 });
294 try stack.append(State.AfterOperand);296 try stack.append(State.AfterOperand);
295 continue;297 continue;
...@@ -306,14 +308,14 @@ pub const Parser = struct {...@@ -306,14 +308,14 @@ pub const Parser = struct {
306 switch (token.id) {308 switch (token.id) {
307 Token.Id.EqualEqual => {309 Token.Id.EqualEqual => {
308 try stack.append(State {310 try stack.append(State {
309 .InfixOp = try self.createInfixOp(token, ast.NodeInfixOp.InfixOp.EqualEqual)311 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.EqualEqual)
310 });312 });
311 try stack.append(State.ExpectOperand);313 try stack.append(State.ExpectOperand);
312 continue;314 continue;
313 },315 },
314 Token.Id.BangEqual => {316 Token.Id.BangEqual => {
315 try stack.append(State {317 try stack.append(State {
316 .InfixOp = try self.createInfixOp(token, ast.NodeInfixOp.InfixOp.BangEqual)318 .InfixOp = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BangEqual)
317 });319 });
318 try stack.append(State.ExpectOperand);320 try stack.append(State.ExpectOperand);
319 continue;321 continue;
...@@ -421,7 +423,7 @@ pub const Parser = struct {...@@ -421,7 +423,7 @@ pub const Parser = struct {
421 if (token.id == Token.Id.RParen) {423 if (token.id == Token.Id.RParen) {
422 continue;424 continue;
423 }425 }
424 const param_decl = try self.createAttachParamDecl(&fn_proto.params);426 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);
425 if (token.id == Token.Id.Keyword_comptime) {427 if (token.id == Token.Id.Keyword_comptime) {
426 param_decl.comptime_token = token;428 param_decl.comptime_token = token;
427 token = self.getNextToken();429 token = self.getNextToken();
...@@ -470,7 +472,7 @@ pub const Parser = struct {...@@ -470,7 +472,7 @@ pub const Parser = struct {
470 const token = self.getNextToken();472 const token = self.getNextToken();
471 switch(token.id) {473 switch(token.id) {
472 Token.Id.LBrace => {474 Token.Id.LBrace => {
473 const block = try self.createBlock(token);475 const block = try self.createBlock(arena, token);
474 fn_proto.body_node = &block.base;476 fn_proto.body_node = &block.base;
475 stack.append(State { .Block = block }) catch unreachable;477 stack.append(State { .Block = block }) catch unreachable;
476 continue;478 continue;
...@@ -504,7 +506,7 @@ pub const Parser = struct {...@@ -504,7 +506,7 @@ pub const Parser = struct {
504 const mut_token = self.getNextToken();506 const mut_token = self.getNextToken();
505 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {507 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
506 // TODO shouldn't need these casts508 // TODO shouldn't need these casts
507 const var_decl = try self.createAttachVarDecl(&block.statements, (?Token)(null),509 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
508 mut_token, (?Token)(comptime_token), (?Token)(null));510 mut_token, (?Token)(comptime_token), (?Token)(null));
509 try stack.append(State { .VarDecl = var_decl });511 try stack.append(State { .VarDecl = var_decl });
510 continue;512 continue;
...@@ -518,7 +520,7 @@ pub const Parser = struct {...@@ -518,7 +520,7 @@ pub const Parser = struct {
518 const mut_token = self.getNextToken();520 const mut_token = self.getNextToken();
519 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {521 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
520 // TODO shouldn't need these casts522 // TODO shouldn't need these casts
521 const var_decl = try self.createAttachVarDecl(&block.statements, (?Token)(null),523 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
522 mut_token, (?Token)(null), (?Token)(null));524 mut_token, (?Token)(null), (?Token)(null));
523 try stack.append(State { .VarDecl = var_decl });525 try stack.append(State { .VarDecl = var_decl });
524 continue;526 continue;
...@@ -541,20 +543,20 @@ pub const Parser = struct {...@@ -541,20 +543,20 @@ pub const Parser = struct {
541 }543 }
542 }544 }
543545
544 fn createRoot(self: &Parser) !&ast.NodeRoot {546 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {
545 const node = try self.allocator.create(ast.NodeRoot);547 const node = try arena.create(ast.NodeRoot);
546548
547 *node = ast.NodeRoot {549 *node = ast.NodeRoot {
548 .base = ast.Node {.id = ast.Node.Id.Root},550 .base = ast.Node {.id = ast.Node.Id.Root},
549 .decls = ArrayList(&ast.Node).init(self.allocator),551 .decls = ArrayList(&ast.Node).init(arena),
550 };552 };
551 return node;553 return node;
552 }554 }
553555
554 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,556 fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token,
555 extern_token: &const ?Token) !&ast.NodeVarDecl557 comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl
556 {558 {
557 const node = try self.allocator.create(ast.NodeVarDecl);559 const node = try arena.create(ast.NodeVarDecl);
558560
559 *node = ast.NodeVarDecl {561 *node = ast.NodeVarDecl {
560 .base = ast.Node {.id = ast.Node.Id.VarDecl},562 .base = ast.Node {.id = ast.Node.Id.VarDecl},
...@@ -573,17 +575,17 @@ pub const Parser = struct {...@@ -573,17 +575,17 @@ pub const Parser = struct {
573 return node;575 return node;
574 }576 }
575577
576 fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token,578 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
577 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto579 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
578 {580 {
579 const node = try self.allocator.create(ast.NodeFnProto);581 const node = try arena.create(ast.NodeFnProto);
580582
581 *node = ast.NodeFnProto {583 *node = ast.NodeFnProto {
582 .base = ast.Node {.id = ast.Node.Id.FnProto},584 .base = ast.Node {.id = ast.Node.Id.FnProto},
583 .visib_token = *visib_token,585 .visib_token = *visib_token,
584 .name_token = null,586 .name_token = null,
585 .fn_token = *fn_token,587 .fn_token = *fn_token,
586 .params = ArrayList(&ast.Node).init(self.allocator),588 .params = ArrayList(&ast.Node).init(arena),
587 .return_type = undefined,589 .return_type = undefined,
588 .var_args_token = null,590 .var_args_token = null,
589 .extern_token = *extern_token,591 .extern_token = *extern_token,
...@@ -596,8 +598,8 @@ pub const Parser = struct {...@@ -596,8 +598,8 @@ pub const Parser = struct {
596 return node;598 return node;
597 }599 }
598600
599 fn createParamDecl(self: &Parser) !&ast.NodeParamDecl {601 fn createParamDecl(self: &Parser, arena: &mem.Allocator) !&ast.NodeParamDecl {
600 const node = try self.allocator.create(ast.NodeParamDecl);602 const node = try arena.create(ast.NodeParamDecl);
601603
602 *node = ast.NodeParamDecl {604 *node = ast.NodeParamDecl {
603 .base = ast.Node {.id = ast.Node.Id.ParamDecl},605 .base = ast.Node {.id = ast.Node.Id.ParamDecl},
...@@ -610,20 +612,20 @@ pub const Parser = struct {...@@ -610,20 +612,20 @@ pub const Parser = struct {
610 return node;612 return node;
611 }613 }
612614
613 fn createBlock(self: &Parser, begin_token: &const Token) !&ast.NodeBlock {615 fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock {
614 const node = try self.allocator.create(ast.NodeBlock);616 const node = try arena.create(ast.NodeBlock);
615617
616 *node = ast.NodeBlock {618 *node = ast.NodeBlock {
617 .base = ast.Node {.id = ast.Node.Id.Block},619 .base = ast.Node {.id = ast.Node.Id.Block},
618 .begin_token = *begin_token,620 .begin_token = *begin_token,
619 .end_token = undefined,621 .end_token = undefined,
620 .statements = ArrayList(&ast.Node).init(self.allocator),622 .statements = ArrayList(&ast.Node).init(arena),
621 };623 };
622 return node;624 return node;
623 }625 }
624626
625 fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp {627 fn createInfixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp {
626 const node = try self.allocator.create(ast.NodeInfixOp);628 const node = try arena.create(ast.NodeInfixOp);
627629
628 *node = ast.NodeInfixOp {630 *node = ast.NodeInfixOp {
629 .base = ast.Node {.id = ast.Node.Id.InfixOp},631 .base = ast.Node {.id = ast.Node.Id.InfixOp},
...@@ -635,8 +637,8 @@ pub const Parser = struct {...@@ -635,8 +637,8 @@ pub const Parser = struct {
635 return node;637 return node;
636 }638 }
637639
638 fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp {640 fn createPrefixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp {
639 const node = try self.allocator.create(ast.NodePrefixOp);641 const node = try arena.create(ast.NodePrefixOp);
640642
641 *node = ast.NodePrefixOp {643 *node = ast.NodePrefixOp {
642 .base = ast.Node {.id = ast.Node.Id.PrefixOp},644 .base = ast.Node {.id = ast.Node.Id.PrefixOp},
...@@ -647,8 +649,8 @@ pub const Parser = struct {...@@ -647,8 +649,8 @@ pub const Parser = struct {
647 return node;649 return node;
648 }650 }
649651
650 fn createIdentifier(self: &Parser, name_token: &const Token) !&ast.NodeIdentifier {652 fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier {
651 const node = try self.allocator.create(ast.NodeIdentifier);653 const node = try arena.create(ast.NodeIdentifier);
652654
653 *node = ast.NodeIdentifier {655 *node = ast.NodeIdentifier {
654 .base = ast.Node {.id = ast.Node.Id.Identifier},656 .base = ast.Node {.id = ast.Node.Id.Identifier},
...@@ -657,8 +659,8 @@ pub const Parser = struct {...@@ -657,8 +659,8 @@ pub const Parser = struct {
657 return node;659 return node;
658 }660 }
659661
660 fn createIntegerLiteral(self: &Parser, token: &const Token) !&ast.NodeIntegerLiteral {662 fn createIntegerLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeIntegerLiteral {
661 const node = try self.allocator.create(ast.NodeIntegerLiteral);663 const node = try arena.create(ast.NodeIntegerLiteral);
662664
663 *node = ast.NodeIntegerLiteral {665 *node = ast.NodeIntegerLiteral {
664 .base = ast.Node {.id = ast.Node.Id.IntegerLiteral},666 .base = ast.Node {.id = ast.Node.Id.IntegerLiteral},
...@@ -667,8 +669,8 @@ pub const Parser = struct {...@@ -667,8 +669,8 @@ pub const Parser = struct {
667 return node;669 return node;
668 }670 }
669671
670 fn createFloatLiteral(self: &Parser, token: &const Token) !&ast.NodeFloatLiteral {672 fn createFloatLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeFloatLiteral {
671 const node = try self.allocator.create(ast.NodeFloatLiteral);673 const node = try arena.create(ast.NodeFloatLiteral);
672674
673 *node = ast.NodeFloatLiteral {675 *node = ast.NodeFloatLiteral {
674 .base = ast.Node {.id = ast.Node.Id.FloatLiteral},676 .base = ast.Node {.id = ast.Node.Id.FloatLiteral},
...@@ -677,31 +679,32 @@ pub const Parser = struct {...@@ -677,31 +679,32 @@ pub const Parser = struct {
677 return node;679 return node;
678 }680 }
679681
680 fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {682 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
681 const node = try self.createIdentifier(name_token);683 const node = try self.createIdentifier(arena, name_token);
682 try dest_ptr.store(&node.base);684 try dest_ptr.store(&node.base);
683 return node;685 return node;
684 }686 }
685687
686 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {688 fn createAttachParamDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {
687 const node = try self.createParamDecl();689 const node = try self.createParamDecl(arena);
688 try list.append(&node.base);690 try list.append(&node.base);
689 return node;691 return node;
690 }692 }
691693
692 fn createAttachFnProto(self: &Parser, list: &ArrayList(&ast.Node), fn_token: &const Token,694 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,
693 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,695 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
694 inline_token: &const ?Token) !&ast.NodeFnProto696 inline_token: &const ?Token) !&ast.NodeFnProto
695 {697 {
696 const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);698 const node = try self.createFnProto(arena, fn_token, extern_token, cc_token, visib_token, inline_token);
697 try list.append(&node.base);699 try list.append(&node.base);
698 return node;700 return node;
699 }701 }
700702
701 fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token,703 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
702 mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl704 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
705 extern_token: &const ?Token) !&ast.NodeVarDecl
703 {706 {
704 const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);707 const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token);
705 try list.append(&node.base);708 try list.append(&node.base);
706 return node;709 return node;
707 }710 }
...@@ -1018,10 +1021,10 @@ pub const Parser = struct {...@@ -1018,10 +1021,10 @@ pub const Parser = struct {
10181021
1019 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {1022 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
1020 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);1023 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
1021 self.utility_bytes = self.allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);1024 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
1022 const typed_slice = ([]T)(self.utility_bytes);1025 const typed_slice = ([]T)(self.utility_bytes);
1023 return ArrayList(T) {1026 return ArrayList(T) {
1024 .allocator = self.allocator,1027 .allocator = self.util_allocator,
1025 .items = typed_slice,1028 .items = typed_slice,
1026 .len = 0,1029 .len = 0,
1027 };1030 };
...@@ -1043,7 +1046,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {...@@ -1043,7 +1046,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1043 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");1046 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");
1044 defer parser.deinit();1047 defer parser.deinit();
10451048
1046 const tree = try parser.parse();1049 var tree = try parser.parse();
1047 defer tree.deinit();1050 defer tree.deinit();
10481051
1049 var buffer = try std.Buffer.initSize(allocator, 0);1052 var buffer = try std.Buffer.initSize(allocator, 0);
test/standalone/brace_expansion/main.zig+6-3
...@@ -182,10 +182,13 @@ pub fn main() !void {...@@ -182,10 +182,13 @@ pub fn main() !void {
182 var stdin_file = try io.getStdIn();182 var stdin_file = try io.getStdIn();
183 var stdout_file = try io.getStdOut();183 var stdout_file = try io.getStdOut();
184184
185 var inc_allocator = try std.heap.IncrementingAllocator.init(2 * 1024 * 1024);185 var direct_allocator = std.heap.DirectAllocator.init();
186 defer inc_allocator.deinit();186 defer direct_allocator.deinit();
187187
188 global_allocator = &inc_allocator.allocator;188 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
189 defer arena.deinit();
190
191 global_allocator = &arena.allocator;
189192
190 var stdin_buf = try Buffer.initSize(global_allocator, 0);193 var stdin_buf = try Buffer.initSize(global_allocator, 0);
191 defer stdin_buf.deinit();194 defer stdin_buf.deinit();