| author | |
| committer | |
| log | 491d818f17aa94b94998da51ebce6d153491744b |
| tree | 0bffe308c399b4ec9a4bae95349fea47f8387f94 |
| parent | ef6260b3a7ed09e5dc5d8383ad20f229411bd9ff |
| parent | ec0846a00fd3d0ae0b7b94961f855b8ab6c938db |
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 | 13 | const tmp_dir_name = "docgen_tmp"; |
| 14 | 14 | |
| 15 | 15 | pub fn main() !void { |
| 16 | // TODO use a more general purpose allocator here | |
| 17 | var inc_allocator = try std.heap.IncrementingAllocator.init(max_doc_file_size); | |
| 18 | defer inc_allocator.deinit(); | |
| 19 | const allocator = &inc_allocator.allocator; | |
| 16 | var direct_allocator = std.heap.DirectAllocator.init(); | |
| 17 | defer direct_allocator.deinit(); | |
| 18 | ||
| 19 | var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); | |
| 20 | defer arena.deinit(); | |
| 21 | ||
| 22 | const allocator = &arena.allocator; | |
| 20 | 23 | |
| 21 | 24 | var args_it = os.args(); |
| 22 | 25 |
src-self-hosted/main.zig+1-1| ... | ... | @@ -575,7 +575,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 575 | 575 | var parser = std.zig.Parser.init(&tokenizer, allocator, file_path); |
| 576 | 576 | defer parser.deinit(); |
| 577 | 577 | |
| 578 | const tree = try parser.parse(); | |
| 578 | var tree = try parser.parse(); | |
| 579 | 579 | defer tree.deinit(); |
| 580 | 580 | |
| 581 | 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 | 241 | var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path); |
| 242 | 242 | defer parser.deinit(); |
| 243 | 243 | |
| 244 | const tree = try parser.parse(); | |
| 244 | var tree = try parser.parse(); | |
| 245 | 245 | defer tree.deinit(); |
| 246 | 246 | |
| 247 | 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 | 45 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; |
| 46 | 46 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; |
| 47 | 47 | |
| 48 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void; | |
| 48 | 49 | pub extern "c" fn malloc(usize) ?&c_void; |
| 49 | 50 | pub extern "c" fn realloc(&c_void, usize) ?&c_void; |
| 50 | 51 | pub extern "c" fn free(&c_void) void; |
std/debug/index.zig+1-1| ... | ... | @@ -1078,5 +1078,5 @@ fn readILeb128(in_stream: var) !i64 { |
| 1078 | 1078 | } |
| 1079 | 1079 | |
| 1080 | 1080 | pub const global_allocator = &global_fixed_allocator.allocator; |
| 1081 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); | |
| 1081 | var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]); | |
| 1082 | 1082 | var global_allocator_mem: [100 * 1024]u8 = undefined; |
std/heap.zig+250-51| ... | ... | @@ -17,7 +17,8 @@ var c_allocator_state = Allocator { |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | fn 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 | 22 | @ptrCast(&u8, buf)[0..n] |
| 22 | 23 | else |
| 23 | 24 | error.OutOfMemory; |
| ... | ... | @@ -39,82 +40,256 @@ fn cFree(self: &Allocator, old_mem: []u8) void { |
| 39 | 40 | c.free(old_ptr); |
| 40 | 41 | } |
| 41 | 42 | |
| 42 | pub const IncrementingAllocator = struct { | |
| 43 | /// This allocator makes a syscall directly for every allocation and free. | |
| 44 | pub const DirectAllocator = struct { | |
| 43 | 45 | allocator: Allocator, |
| 44 | bytes: []u8, | |
| 45 | end_index: usize, | |
| 46 | heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void, | |
| 46 | heap_handle: ?HeapHandle, | |
| 47 | ||
| 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); | |
| 47 | 79 | |
| 48 | fn init(capacity: usize) !IncrementingAllocator { | |
| 49 | 80 | switch (builtin.os) { |
| 50 | 81 | Os.linux, Os.macosx, Os.ios => { |
| 82 | assert(alignment <= os.page_size); | |
| 51 | 83 | const p = os.posix; |
| 52 | const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE, | |
| 53 | p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0); | |
| 84 | const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE, | |
| 85 | p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0); | |
| 54 | 86 | if (addr == p.MAP_FAILED) { |
| 55 | 87 | return error.OutOfMemory; |
| 56 | 88 | } |
| 57 | return IncrementingAllocator { | |
| 58 | .allocator = Allocator { | |
| 59 | .allocFn = alloc, | |
| 60 | .reallocFn = realloc, | |
| 61 | .freeFn = free, | |
| 62 | }, | |
| 63 | .bytes = @intToPtr(&u8, addr)[0..capacity], | |
| 64 | .end_index = 0, | |
| 65 | .heap_handle = {}, | |
| 89 | return @intToPtr(&u8, addr)[0..n]; | |
| 90 | }, | |
| 91 | Os.windows => { | |
| 92 | const amt = n + alignment + @sizeOf(usize); | |
| 93 | const heap_handle = self.heap_handle ?? blk: { | |
| 94 | const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory; | |
| 95 | self.heap_handle = hh; | |
| 96 | break :blk hh; | |
| 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 | 132 | Os.windows => { |
| 69 | const heap_handle = os.windows.GetProcessHeap() ?? return error.OutOfMemory; | |
| 70 | const ptr = os.windows.HeapAlloc(heap_handle, 0, capacity) ?? return error.OutOfMemory; | |
| 71 | return IncrementingAllocator { | |
| 72 | .allocator = Allocator { | |
| 73 | .allocFn = alloc, | |
| 74 | .reallocFn = realloc, | |
| 75 | .freeFn = free, | |
| 76 | }, | |
| 77 | .bytes = @ptrCast(&u8, ptr)[0..capacity], | |
| 78 | .end_index = 0, | |
| 79 | .heap_handle = heap_handle, | |
| 133 | const old_adjusted_addr = @ptrToInt(old_mem.ptr); | |
| 134 | const old_record_addr = old_adjusted_addr + old_mem.len; | |
| 135 | const root_addr = *@intToPtr(&align(1) usize, old_record_addr); | |
| 136 | const old_ptr = @intToPtr(os.windows.LPVOID, root_addr); | |
| 137 | const amt = new_size + alignment + @sizeOf(usize); | |
| 138 | const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: { | |
| 139 | if (new_size > old_mem.len) return error.OutOfMemory; | |
| 140 | const new_record_addr = old_record_addr - new_size + old_mem.len; | |
| 141 | *@intToPtr(&align(1) usize, new_record_addr) = root_addr; | |
| 142 | return old_mem[0..new_size]; | |
| 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 | 152 | else => @compileError("Unsupported OS"), |
| 83 | 153 | } |
| 84 | 154 | } |
| 85 | 155 | |
| 86 | fn deinit(self: &IncrementingAllocator) void { | |
| 156 | fn free(allocator: &Allocator, bytes: []u8) void { | |
| 157 | const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); | |
| 158 | ||
| 87 | 159 | switch (builtin.os) { |
| 88 | 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 | 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 | 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. | |
| 176 | pub 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 | } | |
| 97 | 207 | |
| 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 | 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 | } |
| 101 | 249 | |
| 102 | fn bytesLeft(self: &const IncrementingAllocator) usize { | |
| 103 | return self.bytes.len - self.end_index; | |
| 250 | fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { | |
| 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 | ||
| 263 | pub 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 | } |
| 105 | 279 | |
| 106 | 280 | fn alloc(allocator: &Allocator, n: usize, alignment: u29) ![]u8 { |
| 107 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | |
| 108 | const addr = @ptrToInt(&self.bytes[self.end_index]); | |
| 281 | const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator); | |
| 282 | const addr = @ptrToInt(&self.buffer[self.end_index]); | |
| 109 | 283 | const rem = @rem(addr, alignment); |
| 110 | 284 | const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); |
| 111 | 285 | const adjusted_index = self.end_index + march_forward_bytes; |
| 112 | 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 | 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 | 291 | self.end_index = new_end_index; |
| 292 | ||
| 118 | 293 | return result; |
| 119 | 294 | } |
| 120 | 295 | |
| ... | ... | @@ -128,11 +303,11 @@ pub const IncrementingAllocator = struct { |
| 128 | 303 | } |
| 129 | 304 | } |
| 130 | 305 | |
| 131 | fn free(allocator: &Allocator, bytes: []u8) void { | |
| 132 | // Do nothing. That's the point of an incrementing allocator. | |
| 133 | } | |
| 306 | fn free(allocator: &Allocator, bytes: []u8) void { } | |
| 134 | 307 | }; |
| 135 | 308 | |
| 309 | ||
| 310 | ||
| 136 | 311 | test "c_allocator" { |
| 137 | 312 | if (builtin.link_libc) { |
| 138 | 313 | var slice = c_allocator.alloc(u8, 50) catch return; |
| ... | ... | @@ -141,23 +316,47 @@ test "c_allocator" { |
| 141 | 316 | } |
| 142 | 317 | } |
| 143 | 318 | |
| 144 | test "IncrementingAllocator" { | |
| 145 | const total_bytes = 100 * 1024 * 1024; | |
| 146 | var inc_allocator = try IncrementingAllocator.init(total_bytes); | |
| 147 | defer inc_allocator.deinit(); | |
| 319 | test "DirectAllocator" { | |
| 320 | var direct_allocator = DirectAllocator.init(); | |
| 321 | defer direct_allocator.deinit(); | |
| 322 | ||
| 323 | const allocator = &direct_allocator.allocator; | |
| 324 | try testAllocator(allocator); | |
| 325 | } | |
| 148 | 326 | |
| 149 | const allocator = &inc_allocator.allocator; | |
| 150 | const slice = try allocator.alloc(&i32, 100); | |
| 327 | test "ArenaAllocator" { | |
| 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 | ||
| 337 | var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined; | |
| 338 | test "FixedBufferAllocator" { | |
| 339 | var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); | |
| 340 | ||
| 341 | try testAllocator(&fixed_buffer_allocator.allocator); | |
| 342 | } | |
| 343 | ||
| 344 | fn testAllocator(allocator: &mem.Allocator) !void { | |
| 345 | var slice = try allocator.alloc(&i32, 100); | |
| 151 | 346 | |
| 152 | 347 | for (slice) |*item, i| { |
| 153 | 348 | *item = try allocator.create(i32); |
| 154 | 349 | **item = i32(i); |
| 155 | 350 | } |
| 156 | 351 | |
| 157 | assert(inc_allocator.bytesLeft() == total_bytes - @sizeOf(i32) * 100 - @sizeOf(usize) * 100); | |
| 352 | for (slice) |item, i| { | |
| 353 | allocator.destroy(item); | |
| 354 | } | |
| 158 | 355 | |
| 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); | |
| 160 | 360 | |
| 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 | 44 | { |
| 45 | 45 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 46 | 46 | const byte_slice = try self.allocFn(self, byte_count, alignment); |
| 47 | assert(byte_slice.len == byte_count); | |
| 47 | 48 | // This loop should get optimized out in ReleaseFast mode |
| 48 | 49 | for (byte_slice) |*byte| { |
| 49 | 50 | *byte = undefined; |
| ... | ... | @@ -65,9 +66,12 @@ pub const Allocator = struct { |
| 65 | 66 | const old_byte_slice = ([]u8)(old_mem); |
| 66 | 67 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 67 | 68 | const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment); |
| 68 | // This loop should get optimized out in ReleaseFast mode | |
| 69 | for (byte_slice[old_byte_slice.len..]) |*byte| { | |
| 70 | *byte = undefined; | |
| 69 | assert(byte_slice.len == byte_count); | |
| 70 | if (n > old_mem.len) { | |
| 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 | 76 | return ([]T)(@alignCast(alignment, byte_slice)); |
| 73 | 77 | } |
| ... | ... | @@ -94,6 +98,7 @@ pub const Allocator = struct { |
| 94 | 98 | const byte_count = @sizeOf(T) * n; |
| 95 | 99 | |
| 96 | 100 | const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable; |
| 101 | assert(byte_slice.len == byte_count); | |
| 97 | 102 | return ([]align(alignment) T)(@alignCast(alignment, byte_slice)); |
| 98 | 103 | } |
| 99 | 104 | |
| ... | ... | @@ -106,52 +111,6 @@ pub const Allocator = struct { |
| 106 | 111 | } |
| 107 | 112 | }; |
| 108 | 113 | |
| 109 | pub 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 | 114 | /// Copy all of source into dest at position 0. |
| 156 | 115 | /// dest.len must be >= source.len. |
| 157 | 116 | pub 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 | 363 | const dev_null_fd = if (any_ignore) blk: { |
| 364 | 364 | const dev_null_path = "/dev/null"; |
| 365 | 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 | 367 | break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0); |
| 368 | 368 | } else blk: { |
| 369 | 369 | break :blk undefined; |
| ... | ... | @@ -472,7 +472,7 @@ pub const ChildProcess = struct { |
| 472 | 472 | const nul_handle = if (any_ignore) blk: { |
| 473 | 473 | const nul_file_path = "NUL"; |
| 474 | 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 | 476 | break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, |
| 477 | 477 | windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL); |
| 478 | 478 | } else blk: { |
std/os/index.zig+2-2| ... | ... | @@ -1702,12 +1702,12 @@ pub fn openSelfExe() !os.File { |
| 1702 | 1702 | Os.linux => { |
| 1703 | 1703 | const proc_file_path = "/proc/self/exe"; |
| 1704 | 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 | 1706 | return os.File.openRead(&fixed_allocator.allocator, proc_file_path); |
| 1707 | 1707 | }, |
| 1708 | 1708 | Os.macosx, Os.ios => { |
| 1709 | 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 | 1711 | const self_exe_path = try selfExePath(&fixed_allocator.allocator); |
| 1712 | 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 | 22 | |
| 23 | 23 | pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lpCommandLine: LPSTR, |
| 24 | 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 | 26 | lpProcessInformation: &PROCESS_INFORMATION) BOOL; |
| 27 | 27 | |
| 28 | 28 | pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR, |
| ... | ... | @@ -61,16 +61,24 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz |
| 61 | 61 | |
| 62 | 62 | pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE; |
| 63 | 63 | |
| 64 | pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE; | |
| 65 | pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL; | |
| 66 | pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void; | |
| 67 | pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) SIZE_T; | |
| 68 | pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: &const c_void) BOOL; | |
| 69 | pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T; | |
| 70 | pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL; | |
| 71 | ||
| 64 | 72 | pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE; |
| 65 | 73 | |
| 66 | pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?LPVOID; | |
| 74 | pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?&c_void; | |
| 67 | 75 | |
| 68 | pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) BOOL; | |
| 76 | pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void) BOOL; | |
| 69 | 77 | |
| 70 | 78 | pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, |
| 71 | 79 | dwFlags: DWORD) BOOL; |
| 72 | 80 | |
| 73 | pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID, | |
| 81 | pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void, | |
| 74 | 82 | in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD, |
| 75 | 83 | in_out_lpOverlapped: ?&OVERLAPPED) BOOL; |
| 76 | 84 | |
| ... | ... | @@ -201,7 +209,7 @@ pub const VOLUME_NAME_NT = 0x2; |
| 201 | 209 | |
| 202 | 210 | pub const SECURITY_ATTRIBUTES = extern struct { |
| 203 | 211 | nLength: DWORD, |
| 204 | lpSecurityDescriptor: ?LPVOID, | |
| 212 | lpSecurityDescriptor: ?&c_void, | |
| 205 | 213 | bInheritHandle: BOOL, |
| 206 | 214 | }; |
| 207 | 215 | pub const PSECURITY_ATTRIBUTES = &SECURITY_ATTRIBUTES; |
| ... | ... | @@ -296,3 +304,7 @@ pub const MOVEFILE_WRITE_THROUGH = 8; |
| 296 | 304 | pub const FILE_BEGIN = 0; |
| 297 | 305 | pub const FILE_CURRENT = 1; |
| 298 | 306 | pub const FILE_END = 2; |
| 307 | ||
| 308 | pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000; | |
| 309 | pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004; | |
| 310 | pub const HEAP_NO_SERIALIZE = 0x00000001; |
std/sort.zig+1-1| ... | ... | @@ -1094,7 +1094,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined; |
| 1094 | 1094 | |
| 1095 | 1095 | fn fuzzTest(rng: &std.rand.Rand) void { |
| 1096 | 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 | 1098 | var array = fixed_allocator.allocator.alloc(IdAndValue, array_size) catch unreachable; |
| 1099 | 1099 | // populate with random data |
| 1100 | 1100 | for (array) |*item, index| { |
std/special/build_runner.zig+10-4| ... | ... | @@ -12,11 +12,17 @@ const warn = std.debug.warn; |
| 12 | 12 | pub fn main() !void { |
| 13 | 13 | var arg_it = os.args(); |
| 14 | 14 | |
| 15 | // TODO use a more general purpose allocator here | |
| 16 | var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024); | |
| 17 | defer inc_allocator.deinit(); | |
| 15 | // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived, | |
| 16 | // one shot program. We don't need to waste time freeing memory and finding places to squish | |
| 17 | // bytes into. So we free everything all at once at the very end. | |
| 18 | 18 | |
| 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; | |
| 20 | 26 | |
| 21 | 27 | |
| 22 | 28 | // skip my own exe name |
std/zig/parser.zig+66-63| ... | ... | @@ -13,7 +13,7 @@ const io = std.io; |
| 13 | 13 | const warn = std.debug.warn; |
| 14 | 14 | |
| 15 | 15 | pub const Parser = struct { |
| 16 | allocator: &mem.Allocator, | |
| 16 | util_allocator: &mem.Allocator, | |
| 17 | 17 | tokenizer: &Tokenizer, |
| 18 | 18 | put_back_tokens: [2]Token, |
| 19 | 19 | put_back_count: usize, |
| ... | ... | @@ -21,9 +21,10 @@ pub const Parser = struct { |
| 21 | 21 | |
| 22 | 22 | pub const Tree = struct { |
| 23 | 23 | root_node: &ast.NodeRoot, |
| 24 | arena_allocator: std.heap.ArenaAllocator, | |
| 24 | 25 | |
| 25 | pub fn deinit(self: &const Tree) void { | |
| 26 | // TODO free the whole arena | |
| 26 | pub fn deinit(self: &Tree) void { | |
| 27 | self.arena_allocator.deinit(); | |
| 27 | 28 | } |
| 28 | 29 | }; |
| 29 | 30 | |
| ... | ... | @@ -33,12 +34,10 @@ pub const Parser = struct { |
| 33 | 34 | const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } ); |
| 34 | 35 | utility_bytes: []align(utility_bytes_align) u8, |
| 35 | 36 | |
| 36 | /// `allocator` should be an arena allocator. Parser never calls free on anything. After you're | |
| 37 | /// done with a Parser, free the arena. After the arena is freed, no member functions of Parser | |
| 38 | /// may be called. | |
| 37 | /// allocator must outlive the returned Parser and all the parse trees you create with it. | |
| 39 | 38 | pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) Parser { |
| 40 | 39 | return Parser { |
| 41 | .allocator = allocator, | |
| 40 | .util_allocator = allocator, | |
| 42 | 41 | .tokenizer = tokenizer, |
| 43 | 42 | .put_back_tokens = undefined, |
| 44 | 43 | .put_back_count = 0, |
| ... | ... | @@ -48,7 +47,7 @@ pub const Parser = struct { |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | 49 | pub fn deinit(self: &Parser) void { |
| 51 | self.allocator.free(self.utility_bytes); | |
| 50 | self.util_allocator.free(self.utility_bytes); | |
| 52 | 51 | } |
| 53 | 52 | |
| 54 | 53 | const TopLevelDeclCtx = struct { |
| ... | ... | @@ -101,8 +100,11 @@ pub const Parser = struct { |
| 101 | 100 | var stack = self.initUtilityArrayList(State); |
| 102 | 101 | defer self.deinitUtilityArrayList(stack); |
| 103 | 102 | |
| 104 | const root_node = try self.createRoot(); | |
| 105 | // TODO errdefer arena free root node | |
| 103 | var arena_allocator = std.heap.ArenaAllocator.init(self.util_allocator); | |
| 104 | errdefer arena_allocator.deinit(); | |
| 105 | ||
| 106 | const arena = &arena_allocator.allocator; | |
| 107 | const root_node = try self.createRoot(arena); | |
| 106 | 108 | |
| 107 | 109 | try stack.append(State.TopLevel); |
| 108 | 110 | |
| ... | ... | @@ -130,7 +132,7 @@ pub const Parser = struct { |
| 130 | 132 | stack.append(State { .TopLevelExtern = token }) catch unreachable; |
| 131 | 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 | 136 | else => { |
| 135 | 137 | self.putBackToken(token); |
| 136 | 138 | stack.append(State { .TopLevelExtern = null }) catch unreachable; |
| ... | ... | @@ -164,7 +166,7 @@ pub const Parser = struct { |
| 164 | 166 | Token.Id.Keyword_var, Token.Id.Keyword_const => { |
| 165 | 167 | stack.append(State.TopLevel) catch unreachable; |
| 166 | 168 | // 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 | 170 | token, (?Token)(null), ctx.extern_token); |
| 169 | 171 | try stack.append(State { .VarDecl = var_decl_node }); |
| 170 | 172 | continue; |
| ... | ... | @@ -172,7 +174,7 @@ pub const Parser = struct { |
| 172 | 174 | Token.Id.Keyword_fn => { |
| 173 | 175 | stack.append(State.TopLevel) catch unreachable; |
| 174 | 176 | // 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 | 178 | ctx.extern_token, (?Token)(null), (?Token)(null), (?Token)(null)); |
| 177 | 179 | try stack.append(State { .FnDef = fn_proto }); |
| 178 | 180 | try stack.append(State { .FnProto = fn_proto }); |
| ... | ... | @@ -185,7 +187,7 @@ pub const Parser = struct { |
| 185 | 187 | stack.append(State.TopLevel) catch unreachable; |
| 186 | 188 | const fn_token = try self.eatToken(Token.Id.Keyword_fn); |
| 187 | 189 | // 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 | 191 | ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null)); |
| 190 | 192 | try stack.append(State { .FnDef = fn_proto }); |
| 191 | 193 | try stack.append(State { .FnProto = fn_proto }); |
| ... | ... | @@ -253,13 +255,13 @@ pub const Parser = struct { |
| 253 | 255 | const token = self.getNextToken(); |
| 254 | 256 | switch (token.id) { |
| 255 | 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 | 259 | ast.NodePrefixOp.PrefixOp.Return) }); |
| 258 | 260 | try stack.append(State.ExpectOperand); |
| 259 | 261 | continue; |
| 260 | 262 | }, |
| 261 | 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 | 265 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { |
| 264 | 266 | .align_expr = null, |
| 265 | 267 | .bit_offset_start_token = null, |
| ... | ... | @@ -275,21 +277,21 @@ pub const Parser = struct { |
| 275 | 277 | }, |
| 276 | 278 | Token.Id.Identifier => { |
| 277 | 279 | try stack.append(State { |
| 278 | .Operand = &(try self.createIdentifier(token)).base | |
| 280 | .Operand = &(try self.createIdentifier(arena, token)).base | |
| 279 | 281 | }); |
| 280 | 282 | try stack.append(State.AfterOperand); |
| 281 | 283 | continue; |
| 282 | 284 | }, |
| 283 | 285 | Token.Id.IntegerLiteral => { |
| 284 | 286 | try stack.append(State { |
| 285 | .Operand = &(try self.createIntegerLiteral(token)).base | |
| 287 | .Operand = &(try self.createIntegerLiteral(arena, token)).base | |
| 286 | 288 | }); |
| 287 | 289 | try stack.append(State.AfterOperand); |
| 288 | 290 | continue; |
| 289 | 291 | }, |
| 290 | 292 | Token.Id.FloatLiteral => { |
| 291 | 293 | try stack.append(State { |
| 292 | .Operand = &(try self.createFloatLiteral(token)).base | |
| 294 | .Operand = &(try self.createFloatLiteral(arena, token)).base | |
| 293 | 295 | }); |
| 294 | 296 | try stack.append(State.AfterOperand); |
| 295 | 297 | continue; |
| ... | ... | @@ -306,14 +308,14 @@ pub const Parser = struct { |
| 306 | 308 | switch (token.id) { |
| 307 | 309 | Token.Id.EqualEqual => { |
| 308 | 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 | 313 | try stack.append(State.ExpectOperand); |
| 312 | 314 | continue; |
| 313 | 315 | }, |
| 314 | 316 | Token.Id.BangEqual => { |
| 315 | 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 | 320 | try stack.append(State.ExpectOperand); |
| 319 | 321 | continue; |
| ... | ... | @@ -421,7 +423,7 @@ pub const Parser = struct { |
| 421 | 423 | if (token.id == Token.Id.RParen) { |
| 422 | 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 | 427 | if (token.id == Token.Id.Keyword_comptime) { |
| 426 | 428 | param_decl.comptime_token = token; |
| 427 | 429 | token = self.getNextToken(); |
| ... | ... | @@ -470,7 +472,7 @@ pub const Parser = struct { |
| 470 | 472 | const token = self.getNextToken(); |
| 471 | 473 | switch(token.id) { |
| 472 | 474 | Token.Id.LBrace => { |
| 473 | const block = try self.createBlock(token); | |
| 475 | const block = try self.createBlock(arena, token); | |
| 474 | 476 | fn_proto.body_node = &block.base; |
| 475 | 477 | stack.append(State { .Block = block }) catch unreachable; |
| 476 | 478 | continue; |
| ... | ... | @@ -504,7 +506,7 @@ pub const Parser = struct { |
| 504 | 506 | const mut_token = self.getNextToken(); |
| 505 | 507 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { |
| 506 | 508 | // 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 | 510 | mut_token, (?Token)(comptime_token), (?Token)(null)); |
| 509 | 511 | try stack.append(State { .VarDecl = var_decl }); |
| 510 | 512 | continue; |
| ... | ... | @@ -518,7 +520,7 @@ pub const Parser = struct { |
| 518 | 520 | const mut_token = self.getNextToken(); |
| 519 | 521 | if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) { |
| 520 | 522 | // 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 | 524 | mut_token, (?Token)(null), (?Token)(null)); |
| 523 | 525 | try stack.append(State { .VarDecl = var_decl }); |
| 524 | 526 | continue; |
| ... | ... | @@ -541,20 +543,20 @@ pub const Parser = struct { |
| 541 | 543 | } |
| 542 | 544 | } |
| 543 | 545 | |
| 544 | fn createRoot(self: &Parser) !&ast.NodeRoot { | |
| 545 | const node = try self.allocator.create(ast.NodeRoot); | |
| 546 | fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot { | |
| 547 | const node = try arena.create(ast.NodeRoot); | |
| 546 | 548 | |
| 547 | 549 | *node = ast.NodeRoot { |
| 548 | 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 | 553 | return node; |
| 552 | 554 | } |
| 553 | 555 | |
| 554 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, | |
| 555 | extern_token: &const ?Token) !&ast.NodeVarDecl | |
| 556 | fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token, | |
| 557 | 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); | |
| 558 | 560 | |
| 559 | 561 | *node = ast.NodeVarDecl { |
| 560 | 562 | .base = ast.Node {.id = ast.Node.Id.VarDecl}, |
| ... | ... | @@ -573,17 +575,17 @@ pub const Parser = struct { |
| 573 | 575 | return node; |
| 574 | 576 | } |
| 575 | 577 | |
| 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 | 579 | 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); | |
| 580 | 582 | |
| 581 | 583 | *node = ast.NodeFnProto { |
| 582 | 584 | .base = ast.Node {.id = ast.Node.Id.FnProto}, |
| 583 | 585 | .visib_token = *visib_token, |
| 584 | 586 | .name_token = null, |
| 585 | 587 | .fn_token = *fn_token, |
| 586 | .params = ArrayList(&ast.Node).init(self.allocator), | |
| 588 | .params = ArrayList(&ast.Node).init(arena), | |
| 587 | 589 | .return_type = undefined, |
| 588 | 590 | .var_args_token = null, |
| 589 | 591 | .extern_token = *extern_token, |
| ... | ... | @@ -596,8 +598,8 @@ pub const Parser = struct { |
| 596 | 598 | return node; |
| 597 | 599 | } |
| 598 | 600 | |
| 599 | fn createParamDecl(self: &Parser) !&ast.NodeParamDecl { | |
| 600 | const node = try self.allocator.create(ast.NodeParamDecl); | |
| 601 | fn createParamDecl(self: &Parser, arena: &mem.Allocator) !&ast.NodeParamDecl { | |
| 602 | const node = try arena.create(ast.NodeParamDecl); | |
| 601 | 603 | |
| 602 | 604 | *node = ast.NodeParamDecl { |
| 603 | 605 | .base = ast.Node {.id = ast.Node.Id.ParamDecl}, |
| ... | ... | @@ -610,20 +612,20 @@ pub const Parser = struct { |
| 610 | 612 | return node; |
| 611 | 613 | } |
| 612 | 614 | |
| 613 | fn createBlock(self: &Parser, begin_token: &const Token) !&ast.NodeBlock { | |
| 614 | const node = try self.allocator.create(ast.NodeBlock); | |
| 615 | fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock { | |
| 616 | const node = try arena.create(ast.NodeBlock); | |
| 615 | 617 | |
| 616 | 618 | *node = ast.NodeBlock { |
| 617 | 619 | .base = ast.Node {.id = ast.Node.Id.Block}, |
| 618 | 620 | .begin_token = *begin_token, |
| 619 | 621 | .end_token = undefined, |
| 620 | .statements = ArrayList(&ast.Node).init(self.allocator), | |
| 622 | .statements = ArrayList(&ast.Node).init(arena), | |
| 621 | 623 | }; |
| 622 | 624 | return node; |
| 623 | 625 | } |
| 624 | 626 | |
| 625 | fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp { | |
| 626 | const node = try self.allocator.create(ast.NodeInfixOp); | |
| 627 | fn createInfixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp { | |
| 628 | const node = try arena.create(ast.NodeInfixOp); | |
| 627 | 629 | |
| 628 | 630 | *node = ast.NodeInfixOp { |
| 629 | 631 | .base = ast.Node {.id = ast.Node.Id.InfixOp}, |
| ... | ... | @@ -635,8 +637,8 @@ pub const Parser = struct { |
| 635 | 637 | return node; |
| 636 | 638 | } |
| 637 | 639 | |
| 638 | fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp { | |
| 639 | const node = try self.allocator.create(ast.NodePrefixOp); | |
| 640 | fn createPrefixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp { | |
| 641 | const node = try arena.create(ast.NodePrefixOp); | |
| 640 | 642 | |
| 641 | 643 | *node = ast.NodePrefixOp { |
| 642 | 644 | .base = ast.Node {.id = ast.Node.Id.PrefixOp}, |
| ... | ... | @@ -647,8 +649,8 @@ pub const Parser = struct { |
| 647 | 649 | return node; |
| 648 | 650 | } |
| 649 | 651 | |
| 650 | fn createIdentifier(self: &Parser, name_token: &const Token) !&ast.NodeIdentifier { | |
| 651 | const node = try self.allocator.create(ast.NodeIdentifier); | |
| 652 | fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier { | |
| 653 | const node = try arena.create(ast.NodeIdentifier); | |
| 652 | 654 | |
| 653 | 655 | *node = ast.NodeIdentifier { |
| 654 | 656 | .base = ast.Node {.id = ast.Node.Id.Identifier}, |
| ... | ... | @@ -657,8 +659,8 @@ pub const Parser = struct { |
| 657 | 659 | return node; |
| 658 | 660 | } |
| 659 | 661 | |
| 660 | fn createIntegerLiteral(self: &Parser, token: &const Token) !&ast.NodeIntegerLiteral { | |
| 661 | const node = try self.allocator.create(ast.NodeIntegerLiteral); | |
| 662 | fn createIntegerLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeIntegerLiteral { | |
| 663 | const node = try arena.create(ast.NodeIntegerLiteral); | |
| 662 | 664 | |
| 663 | 665 | *node = ast.NodeIntegerLiteral { |
| 664 | 666 | .base = ast.Node {.id = ast.Node.Id.IntegerLiteral}, |
| ... | ... | @@ -667,8 +669,8 @@ pub const Parser = struct { |
| 667 | 669 | return node; |
| 668 | 670 | } |
| 669 | 671 | |
| 670 | fn createFloatLiteral(self: &Parser, token: &const Token) !&ast.NodeFloatLiteral { | |
| 671 | const node = try self.allocator.create(ast.NodeFloatLiteral); | |
| 672 | fn createFloatLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeFloatLiteral { | |
| 673 | const node = try arena.create(ast.NodeFloatLiteral); | |
| 672 | 674 | |
| 673 | 675 | *node = ast.NodeFloatLiteral { |
| 674 | 676 | .base = ast.Node {.id = ast.Node.Id.FloatLiteral}, |
| ... | ... | @@ -677,31 +679,32 @@ pub const Parser = struct { |
| 677 | 679 | return node; |
| 678 | 680 | } |
| 679 | 681 | |
| 680 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier { | |
| 681 | const node = try self.createIdentifier(name_token); | |
| 682 | fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier { | |
| 683 | const node = try self.createIdentifier(arena, name_token); | |
| 682 | 684 | try dest_ptr.store(&node.base); |
| 683 | 685 | return node; |
| 684 | 686 | } |
| 685 | 687 | |
| 686 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl { | |
| 687 | const node = try self.createParamDecl(); | |
| 688 | fn createAttachParamDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl { | |
| 689 | const node = try self.createParamDecl(arena); | |
| 688 | 690 | try list.append(&node.base); |
| 689 | 691 | return node; |
| 690 | 692 | } |
| 691 | 693 | |
| 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 | 695 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, |
| 694 | 696 | 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 | 699 | try list.append(&node.base); |
| 698 | 700 | return node; |
| 699 | 701 | } |
| 700 | 702 | |
| 701 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&ast.Node), visib_token: &const ?Token, | |
| 702 | mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl | |
| 703 | fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), | |
| 704 | 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 | 708 | try list.append(&node.base); |
| 706 | 709 | return node; |
| 707 | 710 | } |
| ... | ... | @@ -1018,10 +1021,10 @@ pub const Parser = struct { |
| 1018 | 1021 | |
| 1019 | 1022 | fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) { |
| 1020 | 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 | 1025 | const typed_slice = ([]T)(self.utility_bytes); |
| 1023 | 1026 | return ArrayList(T) { |
| 1024 | .allocator = self.allocator, | |
| 1027 | .allocator = self.util_allocator, | |
| 1025 | 1028 | .items = typed_slice, |
| 1026 | 1029 | .len = 0, |
| 1027 | 1030 | }; |
| ... | ... | @@ -1043,7 +1046,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 { |
| 1043 | 1046 | var parser = Parser.init(&tokenizer, allocator, "(memory buffer)"); |
| 1044 | 1047 | defer parser.deinit(); |
| 1045 | 1048 | |
| 1046 | const tree = try parser.parse(); | |
| 1049 | var tree = try parser.parse(); | |
| 1047 | 1050 | defer tree.deinit(); |
| 1048 | 1051 | |
| 1049 | 1052 | var buffer = try std.Buffer.initSize(allocator, 0); |
| ... | ... | @@ -1057,7 +1060,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 { |
| 1057 | 1060 | fn testCanonical(source: []const u8) !void { |
| 1058 | 1061 | const needed_alloc_count = x: { |
| 1059 | 1062 | // 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 | 1064 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize)); |
| 1062 | 1065 | const result_source = try testParse(source, &failing_allocator.allocator); |
| 1063 | 1066 | if (!mem.eql(u8, result_source, source)) { |
| ... | ... | @@ -1074,7 +1077,7 @@ fn testCanonical(source: []const u8) !void { |
| 1074 | 1077 | |
| 1075 | 1078 | var fail_index: usize = 0; |
| 1076 | 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 | 1081 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); |
| 1079 | 1082 | if (testParse(source, &failing_allocator.allocator)) |_| { |
| 1080 | 1083 | return error.NondeterministicMemoryUsage; |
test/standalone/brace_expansion/main.zig+6-3| ... | ... | @@ -182,10 +182,13 @@ pub fn main() !void { |
| 182 | 182 | var stdin_file = try io.getStdIn(); |
| 183 | 183 | var stdout_file = try io.getStdOut(); |
| 184 | 184 | |
| 185 | var inc_allocator = try std.heap.IncrementingAllocator.init(2 * 1024 * 1024); | |
| 186 | defer inc_allocator.deinit(); | |
| 185 | var direct_allocator = std.heap.DirectAllocator.init(); | |
| 186 | defer direct_allocator.deinit(); | |
| 187 | 187 | |
| 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; | |
| 189 | 192 | |
| 190 | 193 | var stdin_buf = try Buffer.initSize(global_allocator, 0); |
| 191 | 194 | defer stdin_buf.deinit(); |