authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 10:48:02-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-12 10:48:02-05:00
log491d818f17aa94b94998da51ebce6d153491744b
tree0bffe308c399b4ec9a4bae95349fea47f8387f94
parentef6260b3a7ed09e5dc5d8383ad20f229411bd9ff
parentec0846a00fd3d0ae0b7b94961f855b8ab6c938db

Merge remote-tracking branch 'origin/master' into llvm6


14 files changed, 373 insertions(+), 187 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/debug/index.zig+1-1
...@@ -1078,5 +1078,5 @@ fn readILeb128(in_stream: var) !i64 {...@@ -1078,5 +1078,5 @@ fn readILeb128(in_stream: var) !i64 {
1078}1078}
10791079
1080pub const global_allocator = &global_fixed_allocator.allocator;1080pub const global_allocator = &global_fixed_allocator.allocator;
1081var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);1081var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
1082var global_allocator_mem: [100 * 1024]u8 = undefined;1082var global_allocator_mem: [100 * 1024]u8 = undefined;
std/heap.zig+250-51
...@@ -17,7 +17,8 @@ var c_allocator_state = Allocator {...@@ -17,7 +17,8 @@ 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 assert(alignment <= @alignOf(c_longdouble));
21 return if (c.malloc(n)) |buf|
21 @ptrCast(&u8, buf)[0..n]22 @ptrCast(&u8, buf)[0..n]
22 else23 else
23 error.OutOfMemory;24 error.OutOfMemory;
...@@ -39,82 +40,256 @@ fn cFree(self: &Allocator, old_mem: []u8) void {...@@ -39,82 +40,256 @@ fn cFree(self: &Allocator, old_mem: []u8) void {
39 c.free(old_ptr);40 c.free(old_ptr);
40}41}
4142
42pub const IncrementingAllocator = struct {43/// This allocator makes a syscall directly for every allocation and free.
44pub const DirectAllocator = struct {
43 allocator: Allocator,45 allocator: Allocator,
44 bytes: []u8,46 heap_handle: ?HeapHandle,
45 end_index: usize,47
46 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,48 const HeapHandle = if (builtin.os == Os.windows) os.windows.HANDLE else void;
49
50 //pub const canary_bytes = []u8 {48, 239, 128, 46, 18, 49, 147, 9, 195, 59, 203, 3, 245, 54, 9, 122};
51 //pub const want_safety = switch (builtin.mode) {
52 // builtin.Mode.Debug => true,
53 // builtin.Mode.ReleaseSafe => true,
54 // else => false,
55 //};
56
57 pub fn init() DirectAllocator {
58 return DirectAllocator {
59 .allocator = Allocator {
60 .allocFn = alloc,
61 .reallocFn = realloc,
62 .freeFn = free,
63 },
64 .heap_handle = if (builtin.os == Os.windows) null else {},
65 };
66 }
67
68 pub fn deinit(self: &DirectAllocator) void {
69 switch (builtin.os) {
70 Os.windows => if (self.heap_handle) |heap_handle| {
71 _ = os.windows.HeapDestroy(heap_handle);
72 },
73 else => {},
74 }
75 }
76
77 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
78 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
4779
48 fn init(capacity: usize) !IncrementingAllocator {
49 switch (builtin.os) {80 switch (builtin.os) {
50 Os.linux, Os.macosx, Os.ios => {81 Os.linux, Os.macosx, Os.ios => {
82 assert(alignment <= os.page_size);
51 const p = os.posix;83 const p = os.posix;
52 const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE,84 const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE,
53 p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0);85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
54 if (addr == p.MAP_FAILED) {86 if (addr == p.MAP_FAILED) {
55 return error.OutOfMemory;87 return error.OutOfMemory;
56 }88 }
57 return IncrementingAllocator {89 return @intToPtr(&u8, addr)[0..n];
58 .allocator = Allocator {90 },
59 .allocFn = alloc,91 Os.windows => {
60 .reallocFn = realloc,92 const amt = n + alignment + @sizeOf(usize);
61 .freeFn = free,93 const heap_handle = self.heap_handle ?? blk: {
62 },94 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
63 .bytes = @intToPtr(&u8, addr)[0..capacity],95 self.heap_handle = hh;
64 .end_index = 0,96 break :blk hh;
65 .heap_handle = {},
66 };97 };
98 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) ?? return error.OutOfMemory;
99 const root_addr = @ptrToInt(ptr);
100 const rem = @rem(root_addr, alignment);
101 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
102 const adjusted_addr = root_addr + march_forward_bytes;
103 const record_addr = adjusted_addr + n;
104 *@intToPtr(&align(1) usize, record_addr) = root_addr;
105 return @intToPtr(&u8, adjusted_addr)[0..n];
106 },
107 else => @compileError("Unsupported OS"),
108 }
109 }
110
111 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
112 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
113
114 switch (builtin.os) {
115 Os.linux, Os.macosx, Os.ios => {
116 if (new_size <= old_mem.len) {
117 const base_addr = @ptrToInt(old_mem.ptr);
118 const old_addr_end = base_addr + old_mem.len;
119 const new_addr_end = base_addr + new_size;
120 const rem = @rem(new_addr_end, os.page_size);
121 const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem);
122 if (old_addr_end > new_addr_end_rounded) {
123 _ = os.posix.munmap(@intToPtr(&u8, new_addr_end_rounded), old_addr_end - new_addr_end_rounded);
124 }
125 return old_mem[0..new_size];
126 }
127
128 const result = try alloc(allocator, new_size, alignment);
129 mem.copy(u8, result, old_mem);
130 return result;
67 },131 },
68 Os.windows => {132 Os.windows => {
69 const heap_handle = os.windows.GetProcessHeap() ?? return error.OutOfMemory;133 const old_adjusted_addr = @ptrToInt(old_mem.ptr);
70 const ptr = os.windows.HeapAlloc(heap_handle, 0, capacity) ?? return error.OutOfMemory;134 const old_record_addr = old_adjusted_addr + old_mem.len;
71 return IncrementingAllocator {135 const root_addr = *@intToPtr(&align(1) usize, old_record_addr);
72 .allocator = Allocator {136 const old_ptr = @intToPtr(os.windows.LPVOID, root_addr);
73 .allocFn = alloc,137 const amt = new_size + alignment + @sizeOf(usize);
74 .reallocFn = realloc,138 const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: {
75 .freeFn = free,139 if (new_size > old_mem.len) return error.OutOfMemory;
76 },140 const new_record_addr = old_record_addr - new_size + old_mem.len;
77 .bytes = @ptrCast(&u8, ptr)[0..capacity],141 *@intToPtr(&align(1) usize, new_record_addr) = root_addr;
78 .end_index = 0,142 return old_mem[0..new_size];
79 .heap_handle = heap_handle,
80 };143 };
144 const offset = old_adjusted_addr - root_addr;
145 const new_root_addr = @ptrToInt(new_ptr);
146 const new_adjusted_addr = new_root_addr + offset;
147 assert(new_adjusted_addr % alignment == 0);
148 const new_record_addr = new_adjusted_addr + new_size;
149 *@intToPtr(&align(1) usize, new_record_addr) = new_root_addr;
150 return @intToPtr(&u8, new_adjusted_addr)[0..new_size];
81 },151 },
82 else => @compileError("Unsupported OS"),152 else => @compileError("Unsupported OS"),
83 }153 }
84 }154 }
85155
86 fn deinit(self: &IncrementingAllocator) void {156 fn free(allocator: &Allocator, bytes: []u8) void {
157 const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
158
87 switch (builtin.os) {159 switch (builtin.os) {
88 Os.linux, Os.macosx, Os.ios => {160 Os.linux, Os.macosx, Os.ios => {
89 _ = os.posix.munmap(self.bytes.ptr, self.bytes.len);161 _ = os.posix.munmap(bytes.ptr, bytes.len);
90 },162 },
91 Os.windows => {163 Os.windows => {
92 _ = os.windows.HeapFree(self.heap_handle, 0, @ptrCast(os.windows.LPVOID, self.bytes.ptr));164 const record_addr = @ptrToInt(bytes.ptr) + bytes.len;
165 const root_addr = *@intToPtr(&align(1) usize, record_addr);
166 const ptr = @intToPtr(os.windows.LPVOID, root_addr);
167 _ = os.windows.HeapFree(??self.heap_handle, 0, ptr);
93 },168 },
94 else => @compileError("Unsupported OS"),169 else => @compileError("Unsupported OS"),
95 }170 }
96 }171 }
172};
173
174/// This allocator takes an existing allocator, wraps it, and provides an interface
175/// where you can allocate without freeing, and then free it all together.
176pub const ArenaAllocator = struct {
177 pub allocator: Allocator,
178
179 child_allocator: &Allocator,
180 buffer_list: std.LinkedList([]u8),
181 end_index: usize,
182
183 const BufNode = std.LinkedList([]u8).Node;
184
185 pub fn init(child_allocator: &Allocator) ArenaAllocator {
186 return ArenaAllocator {
187 .allocator = Allocator {
188 .allocFn = alloc,
189 .reallocFn = realloc,
190 .freeFn = free,
191 },
192 .child_allocator = child_allocator,
193 .buffer_list = std.LinkedList([]u8).init(),
194 .end_index = 0,
195 };
196 }
197
198 pub fn deinit(self: &ArenaAllocator) void {
199 var it = self.buffer_list.first;
200 while (it) |node| {
201 // this has to occur before the free because the free frees node
202 it = node.next;
203
204 self.child_allocator.free(node.data);
205 }
206 }
97207
98 fn reset(self: &IncrementingAllocator) void {208 fn createNode(self: &ArenaAllocator, prev_len: usize, minimum_size: usize) !&BufNode {
209 const actual_min_size = minimum_size + @sizeOf(BufNode);
210 var len = prev_len;
211 while (true) {
212 len += len / 2;
213 len += os.page_size - @rem(len, os.page_size);
214 if (len >= actual_min_size) break;
215 }
216 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
217 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
218 const buf_node = &buf_node_slice[0];
219 *buf_node = BufNode {
220 .data = buf,
221 .prev = null,
222 .next = null,
223 };
224 self.buffer_list.append(buf_node);
99 self.end_index = 0;225 self.end_index = 0;
226 return buf_node;
227 }
228
229 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
230 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
231
232 var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment);
233 while (true) {
234 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
235 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
236 const rem = @rem(addr, alignment);
237 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
238 const adjusted_index = self.end_index + march_forward_bytes;
239 const new_end_index = adjusted_index + n;
240 if (new_end_index > cur_buf.len) {
241 cur_node = try self.createNode(cur_buf.len, n + alignment);
242 continue;
243 }
244 const result = cur_buf[adjusted_index .. new_end_index];
245 self.end_index = new_end_index;
246 return result;
247 }
100 }248 }
101249
102 fn bytesLeft(self: &const IncrementingAllocator) usize {250 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
103 return self.bytes.len - self.end_index;251 if (new_size <= old_mem.len) {
252 return old_mem[0..new_size];
253 } else {
254 const result = try alloc(allocator, new_size, alignment);
255 mem.copy(u8, result, old_mem);
256 return result;
257 }
258 }
259
260 fn free(allocator: &Allocator, bytes: []u8) void { }
261};
262
263pub const FixedBufferAllocator = struct {
264 allocator: Allocator,
265 end_index: usize,
266 buffer: []u8,
267
268 pub fn init(buffer: []u8) FixedBufferAllocator {
269 return FixedBufferAllocator {
270 .allocator = Allocator {
271 .allocFn = alloc,
272 .reallocFn = realloc,
273 .freeFn = free,
274 },
275 .buffer = buffer,
276 .end_index = 0,
277 };
104 }278 }
105279
106 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {280 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
107 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);281 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
108 const addr = @ptrToInt(&self.bytes[self.end_index]);282 const addr = @ptrToInt(&self.buffer[self.end_index]);
109 const rem = @rem(addr, alignment);283 const rem = @rem(addr, alignment);
110 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);284 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
111 const adjusted_index = self.end_index + march_forward_bytes;285 const adjusted_index = self.end_index + march_forward_bytes;
112 const new_end_index = adjusted_index + n;286 const new_end_index = adjusted_index + n;
113 if (new_end_index > self.bytes.len) {287 if (new_end_index > self.buffer.len) {
114 return error.OutOfMemory;288 return error.OutOfMemory;
115 }289 }
116 const result = self.bytes[adjusted_index .. new_end_index];290 const result = self.buffer[adjusted_index .. new_end_index];
117 self.end_index = new_end_index;291 self.end_index = new_end_index;
292
118 return result;293 return result;
119 }294 }
120295
...@@ -128,11 +303,11 @@ pub const IncrementingAllocator = struct {...@@ -128,11 +303,11 @@ pub const IncrementingAllocator = struct {
128 }303 }
129 }304 }
130305
131 fn free(allocator: &Allocator, bytes: []u8) void {306 fn free(allocator: &Allocator, bytes: []u8) void { }
132 // Do nothing. That's the point of an incrementing allocator.
133 }
134};307};
135308
309
310
136test "c_allocator" {311test "c_allocator" {
137 if (builtin.link_libc) {312 if (builtin.link_libc) {
138 var slice = c_allocator.alloc(u8, 50) catch return;313 var slice = c_allocator.alloc(u8, 50) catch return;
...@@ -141,23 +316,47 @@ test "c_allocator" {...@@ -141,23 +316,47 @@ test "c_allocator" {
141 }316 }
142}317}
143318
144test "IncrementingAllocator" {319test "DirectAllocator" {
145 const total_bytes = 100 * 1024 * 1024;320 var direct_allocator = DirectAllocator.init();
146 var inc_allocator = try IncrementingAllocator.init(total_bytes);321 defer direct_allocator.deinit();
147 defer inc_allocator.deinit();322
323 const allocator = &direct_allocator.allocator;
324 try testAllocator(allocator);
325}
148326
149 const allocator = &inc_allocator.allocator;327test "ArenaAllocator" {
150 const slice = try allocator.alloc(&i32, 100);328 var direct_allocator = DirectAllocator.init();
329 defer direct_allocator.deinit();
330
331 var arena_allocator = ArenaAllocator.init(&direct_allocator.allocator);
332 defer arena_allocator.deinit();
333
334 try testAllocator(&arena_allocator.allocator);
335}
336
337var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
338test "FixedBufferAllocator" {
339 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
340
341 try testAllocator(&fixed_buffer_allocator.allocator);
342}
343
344fn testAllocator(allocator: &mem.Allocator) !void {
345 var slice = try allocator.alloc(&i32, 100);
151346
152 for (slice) |*item, i| {347 for (slice) |*item, i| {
153 *item = try allocator.create(i32);348 *item = try allocator.create(i32);
154 **item = i32(i);349 **item = i32(i);
155 }350 }
156351
157 assert(inc_allocator.bytesLeft() == total_bytes - @sizeOf(i32) * 100 - @sizeOf(usize) * 100);352 for (slice) |item, i| {
353 allocator.destroy(item);
354 }
158355
159 inc_allocator.reset();356 slice = try allocator.realloc(&i32, slice, 20000);
357 slice = try allocator.realloc(&i32, slice, 50);
358 slice = try allocator.realloc(&i32, slice, 25);
359 slice = try allocator.realloc(&i32, slice, 10);
160360
161 assert(inc_allocator.bytesLeft() == total_bytes);361 allocator.free(slice);
162}362}
163
std/mem.zig+8-49
...@@ -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
...@@ -106,52 +111,6 @@ pub const Allocator = struct {...@@ -106,52 +111,6 @@ pub const Allocator = struct {
106 }111 }
107};112};
108113
109pub const FixedBufferAllocator = struct {
110 allocator: Allocator,
111 end_index: usize,
112 buffer: []u8,
113
114 pub fn init(buffer: []u8) FixedBufferAllocator {
115 return FixedBufferAllocator {
116 .allocator = Allocator {
117 .allocFn = alloc,
118 .reallocFn = realloc,
119 .freeFn = free,
120 },
121 .buffer = buffer,
122 .end_index = 0,
123 };
124 }
125
126 fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 {
127 const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
128 const addr = @ptrToInt(&self.buffer[self.end_index]);
129 const rem = @rem(addr, alignment);
130 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
131 const adjusted_index = self.end_index + march_forward_bytes;
132 const new_end_index = adjusted_index + n;
133 if (new_end_index > self.buffer.len) {
134 return error.OutOfMemory;
135 }
136 const result = self.buffer[adjusted_index .. new_end_index];
137 self.end_index = new_end_index;
138 return result;
139 }
140
141 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
142 if (new_size <= old_mem.len) {
143 return old_mem[0..new_size];
144 } else {
145 const result = try alloc(allocator, new_size, alignment);
146 copy(u8, result, old_mem);
147 return result;
148 }
149 }
150
151 fn free(allocator: &Allocator, bytes: []u8) void { }
152};
153
154
155/// Copy all of source into dest at position 0.114/// Copy all of source into dest at position 0.
156/// dest.len must be >= source.len.115/// dest.len must be >= source.len.
157pub fn copy(comptime T: type, dest: []T, source: []const T) void {116pub fn copy(comptime T: type, dest: []T, source: []const T) void {
std/os/child_process.zig+2-2
...@@ -363,7 +363,7 @@ pub const ChildProcess = struct {...@@ -363,7 +363,7 @@ pub const ChildProcess = struct {
363 const dev_null_fd = if (any_ignore) blk: {363 const dev_null_fd = if (any_ignore) blk: {
364 const dev_null_path = "/dev/null";364 const dev_null_path = "/dev/null";
365 var fixed_buffer_mem: [dev_null_path.len + 1]u8 = undefined;365 var fixed_buffer_mem: [dev_null_path.len + 1]u8 = undefined;
366 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);366 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
367 break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0);367 break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0);
368 } else blk: {368 } else blk: {
369 break :blk undefined;369 break :blk undefined;
...@@ -472,7 +472,7 @@ pub const ChildProcess = struct {...@@ -472,7 +472,7 @@ pub const ChildProcess = struct {
472 const nul_handle = if (any_ignore) blk: {472 const nul_handle = if (any_ignore) blk: {
473 const nul_file_path = "NUL";473 const nul_file_path = "NUL";
474 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;474 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
475 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);475 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
476 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,476 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
477 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);477 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
478 } else blk: {478 } else blk: {
std/os/index.zig+2-2
...@@ -1702,12 +1702,12 @@ pub fn openSelfExe() !os.File {...@@ -1702,12 +1702,12 @@ pub fn openSelfExe() !os.File {
1702 Os.linux => {1702 Os.linux => {
1703 const proc_file_path = "/proc/self/exe";1703 const proc_file_path = "/proc/self/exe";
1704 var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined;1704 var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined;
1705 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1705 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1706 return os.File.openRead(&fixed_allocator.allocator, proc_file_path);1706 return os.File.openRead(&fixed_allocator.allocator, proc_file_path);
1707 },1707 },
1708 Os.macosx, Os.ios => {1708 Os.macosx, Os.ios => {
1709 var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;1709 var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;
1710 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1710 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1711 const self_exe_path = try selfExePath(&fixed_allocator.allocator);1711 const self_exe_path = try selfExePath(&fixed_allocator.allocator);
1712 return os.File.openRead(&fixed_allocator.allocator, self_exe_path);1712 return os.File.openRead(&fixed_allocator.allocator, self_exe_path);
1713 },1713 },
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/sort.zig+1-1
...@@ -1094,7 +1094,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;...@@ -1094,7 +1094,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined;
10941094
1095fn fuzzTest(rng: &std.rand.Rand) void {1095fn fuzzTest(rng: &std.rand.Rand) void {
1096 const array_size = rng.range(usize, 0, 1000);1096 const array_size = rng.range(usize, 0, 1000);
1097 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1097 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1098 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;1098 var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable;
1099 // populate with random data1099 // populate with random data
1100 for (array) |*item, index| {1100 for (array) |*item, index| {
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+66-63
...@@ -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);
...@@ -1057,7 +1060,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {...@@ -1057,7 +1060,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1057fn testCanonical(source: []const u8) !void {1060fn testCanonical(source: []const u8) !void {
1058 const needed_alloc_count = x: {1061 const needed_alloc_count = x: {
1059 // Try it once with unlimited memory, make sure it works1062 // Try it once with unlimited memory, make sure it works
1060 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1063 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1061 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));1064 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
1062 const result_source = try testParse(source, &failing_allocator.allocator);1065 const result_source = try testParse(source, &failing_allocator.allocator);
1063 if (!mem.eql(u8, result_source, source)) {1066 if (!mem.eql(u8, result_source, source)) {
...@@ -1074,7 +1077,7 @@ fn testCanonical(source: []const u8) !void {...@@ -1074,7 +1077,7 @@ fn testCanonical(source: []const u8) !void {
10741077
1075 var fail_index: usize = 0;1078 var fail_index: usize = 0;
1076 while (fail_index < needed_alloc_count) : (fail_index += 1) {1079 while (fail_index < needed_alloc_count) : (fail_index += 1) {
1077 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1080 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1078 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);1081 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1079 if (testParse(source, &failing_allocator.allocator)) |_| {1082 if (testParse(source, &failing_allocator.allocator)) |_| {
1080 return error.NondeterministicMemoryUsage;1083 return error.NondeterministicMemoryUsage;
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();