authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-20 22:40:08-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-20 22:40:08-07:00
log7598a00f34e91375bc8d4f57e8f5ecbc0d1b4d14
tree75338d2cf30fb9092692d0b447d8e2cd610d3023
parentd8692b8bdb4630f2bb2763cdbe609de7d73b28d8

stage2: fix memory management of ZIR code

* free Module.Fn ZIR code when destroying the owner Decl * unreachable_safe and unreachable_unsafe are collapsed into one ZIR instruction with a safety flag. * astgen: emit an unreachable instruction for unreachable literals * don't forget to call deinit on ZIR code * astgen: implement some builtin functions

5 files changed, 114 insertions(+), 84 deletions(-)

src/Module.zig+23-10
......@@ -224,6 +224,10 @@ pub const Decl = struct {
224224 const gpa = module.gpa;
225225 gpa.free(mem.spanZ(decl.name));
226226 if (decl.typedValueManaged()) |tvm| {
227 if (tvm.typed_value.val.castTag(.function)) |payload| {
228 const func = payload.data;
229 func.deinit(gpa);
230 }
227231 tvm.deinit(gpa);
228232 }
229233 decl.dependants.deinit(gpa);
......@@ -334,7 +338,7 @@ pub const EmitH = struct {
334338 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
335339};
336340
337/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
341/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
338342/// Extern functions do not have this data structure; they are represented by
339343/// the `Decl` only, with a `Value` tag of `extern_fn`.
340344pub const Fn = struct {
......@@ -347,6 +351,7 @@ pub const Fn = struct {
347351 /// The number of parameters is determined by referring to the type.
348352 /// The first N elements of `extra` are indexes into `string_bytes` to
349353 /// a null-terminated string.
354 /// This memory is managed with gpa, must be freed when the function is freed.
350355 zir: zir.Code,
351356 /// undefined unless analysis state is `success`.
352357 body: ir.Body,
......@@ -370,6 +375,10 @@ pub const Fn = struct {
370375 pub fn dump(func: *Fn, mod: Module) void {
371376 ir.dumpFn(mod, func);
372377 }
378
379 pub fn deinit(func: *Fn, gpa: *Allocator) void {
380 func.zir.deinit(gpa);
381 }
373382};
374383
375384pub const Var = struct {
......@@ -1502,8 +1511,7 @@ pub const WipZirCode = struct {
15021511 .ret_node,
15031512 .ret_tok,
15041513 .ret_coerce,
1505 .unreachable_unsafe,
1506 .unreachable_safe,
1514 .@"unreachable",
15071515 .loop,
15081516 .suspend_block,
15091517 .suspend_block_one,
......@@ -1521,6 +1529,7 @@ pub const WipZirCode = struct {
15211529 pub fn deinit(wzc: *WipZirCode) void {
15221530 wzc.instructions.deinit(wzc.gpa);
15231531 wzc.extra.deinit(wzc.gpa);
1532 wzc.string_bytes.deinit(wzc.gpa);
15241533 }
15251534};
15261535
......@@ -2078,7 +2087,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
20782087 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
20792088 defer analysis_arena.deinit();
20802089
2081 const code: zir.Code = blk: {
2090 var code: zir.Code = blk: {
20822091 var wip_zir_code: WipZirCode = .{
20832092 .decl = decl,
20842093 .arena = &analysis_arena.allocator,
......@@ -2102,6 +2111,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
21022111 }
21032112 break :blk code;
21042113 };
2114 defer code.deinit(mod.gpa);
21052115
21062116 var sema: Sema = .{
21072117 .mod = mod,
......@@ -2154,17 +2164,17 @@ fn astgenAndSemaFn(
21542164 var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
21552165 defer fn_type_scope_arena.deinit();
21562166
2157 var fn_type_wip_zir_exec: WipZirCode = .{
2167 var fn_type_wip_zir_code: WipZirCode = .{
21582168 .decl = decl,
21592169 .arena = &fn_type_scope_arena.allocator,
21602170 .gpa = mod.gpa,
21612171 };
2162 defer fn_type_wip_zir_exec.deinit();
2172 defer fn_type_wip_zir_code.deinit();
21632173
21642174 var fn_type_scope: Scope.GenZir = .{
21652175 .force_comptime = true,
21662176 .parent = &decl.container.base,
2167 .zir_code = &fn_type_wip_zir_exec,
2177 .zir_code = &fn_type_wip_zir_code,
21682178 };
21692179 defer fn_type_scope.instructions.deinit(mod.gpa);
21702180
......@@ -2317,7 +2327,8 @@ fn astgenAndSemaFn(
23172327 errdefer decl_arena.deinit();
23182328 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
23192329
2320 const fn_type_code = try fn_type_scope.finish();
2330 var fn_type_code = try fn_type_scope.finish();
2331 defer fn_type_code.deinit(mod.gpa);
23212332 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
23222333 fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {};
23232334 }
......@@ -2621,7 +2632,8 @@ fn astgenAndSemaVarDecl(
26212632 init_result_loc,
26222633 var_decl.ast.init_node,
26232634 );
2624 const code = try gen_scope.finish();
2635 var code = try gen_scope.finish();
2636 defer code.deinit(mod.gpa);
26252637 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
26262638 code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
26272639 }
......@@ -2683,7 +2695,8 @@ fn astgenAndSemaVarDecl(
26832695 defer type_scope.instructions.deinit(mod.gpa);
26842696
26852697 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);
2686 const code = try type_scope.finish();
2698 var code = try type_scope.finish();
2699 defer code.deinit(mod.gpa);
26872700 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
26882701 code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
26892702 }
src/Sema.zig+5-10
......@@ -137,8 +137,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
137137 .as_node => try sema.zirAsNode(block, zir_inst),
138138 .@"asm" => try sema.zirAsm(block, zir_inst, false),
139139 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
140 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
141 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
140 .@"unreachable" => try sema.zirUnreachable(block, zir_inst),
142141 .ret_coerce => try sema.zirRetTok(block, zir_inst, true),
143142 .ret_tok => try sema.zirRetTok(block, zir_inst, false),
144143 .ret_node => try sema.zirRetNode(block, zir_inst),
......@@ -2852,17 +2851,13 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne
28522851 return parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body);
28532852}
28542853
2855fn zirUnreachable(
2856 sema: *Sema,
2857 block: *Scope.Block,
2858 inst: zir.Inst.Index,
2859 safety_check: bool,
2860) InnerError!*Inst {
2854fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
28612855 const tracy = trace(@src());
28622856 defer tracy.end();
28632857
2864 const src_node = sema.code.instructions.items(.data)[inst].node;
2865 const src: LazySrcLoc = .{ .node_offset = src_node };
2858 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
2859 const src = inst_data.src();
2860 const safety_check = inst_data.safety;
28662861 try sema.requireRuntimeBlock(block, src);
28672862 // TODO Add compile error for @optimizeFor occurring too late in a scope.
28682863 if (safety_check and block.wantSafety()) {
src/astgen.zig+40-31
......@@ -415,10 +415,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
415415 return callExpr(mod, scope, rl, node, tree.callFull(node));
416416 },
417417
418 .unreachable_literal => {
419 const result = @enumToInt(zir.Const.unreachable_value);
420 return rvalue(mod, scope, rl, result, node);
421 },
418 .unreachable_literal => return gz.add(.{
419 .tag = .@"unreachable",
420 .data = .{ .@"unreachable" = .{
421 .safety = true,
422 .src_node = gz.zir_code.decl.nodeIndexToRelative(node),
423 } },
424 }),
422425 .@"return" => return ret(mod, scope, node),
423426 .field_access => return fieldAccess(mod, scope, rl, node),
424427 .float_literal => return floatLiteral(mod, scope, rl, node),
......@@ -3012,10 +3015,11 @@ fn as(
30123015 scope: *Scope,
30133016 rl: ResultLoc,
30143017 builtin_token: ast.TokenIndex,
3015 src: usize,
3018 node: ast.Node.Index,
30163019 lhs: ast.Node.Index,
30173020 rhs: ast.Node.Index,
30183021) InnerError!zir.Inst.Ref {
3022 if (true) @panic("TODO update for zir-memory-layout");
30193023 const dest_type = try typeExpr(mod, scope, lhs);
30203024 switch (rl) {
30213025 .none, .discard, .ref, .ty => {
......@@ -3090,10 +3094,11 @@ fn bitCast(
30903094 scope: *Scope,
30913095 rl: ResultLoc,
30923096 builtin_token: ast.TokenIndex,
3093 src: usize,
3097 node: ast.Node.Index,
30943098 lhs: ast.Node.Index,
30953099 rhs: ast.Node.Index,
30963100) InnerError!zir.Inst.Ref {
3101 if (true) @panic("TODO update for zir-memory-layout");
30973102 const dest_type = try typeExpr(mod, scope, lhs);
30983103 switch (rl) {
30993104 .none => {
......@@ -3138,9 +3143,10 @@ fn typeOf(
31383143 scope: *Scope,
31393144 rl: ResultLoc,
31403145 builtin_token: ast.TokenIndex,
3141 src: usize,
3146 node: ast.Node.Index,
31423147 params: []const ast.Node.Index,
31433148) InnerError!zir.Inst.Ref {
3149 if (true) @panic("TODO update for zir-memory-layout");
31443150 if (params.len < 1) {
31453151 return mod.failTok(scope, builtin_token, "expected at least 1 argument, found 0", .{});
31463152 }
......@@ -3158,14 +3164,13 @@ fn builtinCall(
31583164 mod: *Module,
31593165 scope: *Scope,
31603166 rl: ResultLoc,
3161 call: ast.Node.Index,
3167 node: ast.Node.Index,
31623168 params: []const ast.Node.Index,
31633169) InnerError!zir.Inst.Ref {
3164 if (true) @panic("TODO update for zir-memory-layout");
31653170 const tree = scope.tree();
31663171 const main_tokens = tree.nodes.items(.main_token);
31673172
3168 const builtin_token = main_tokens[call];
3173 const builtin_token = main_tokens[node];
31693174 const builtin_name = tree.tokenSlice(builtin_token);
31703175
31713176 // We handle the different builtins manually because they have different semantics depending
......@@ -3187,56 +3192,60 @@ fn builtinCall(
31873192 }
31883193 }
31893194
3195 const gz = scope.getGenZir();
3196
31903197 switch (info.tag) {
31913198 .ptr_to_int => {
31923199 const operand = try expr(mod, scope, .none, params[0]);
3193 const result = try addZIRUnOp(mod, scope, src, .ptrtoint, operand);
3194 return rvalue(mod, scope, rl, result);
3200 const result = try gz.addUnNode(.ptrtoint, operand, node);
3201 return rvalue(mod, scope, rl, result, node);
31953202 },
31963203 .float_cast => {
3204 if (true) @panic("TODO update for zir-memory-layout");
31973205 const dest_type = try typeExpr(mod, scope, params[0]);
31983206 const rhs = try expr(mod, scope, .none, params[1]);
31993207 const result = try addZIRBinOp(mod, scope, src, .floatcast, dest_type, rhs);
3200 return rvalue(mod, scope, rl, result);
3208 return rvalue(mod, scope, rl, result, node);
32013209 },
32023210 .int_cast => {
3211 if (true) @panic("TODO update for zir-memory-layout");
32033212 const dest_type = try typeExpr(mod, scope, params[0]);
32043213 const rhs = try expr(mod, scope, .none, params[1]);
32053214 const result = try addZIRBinOp(mod, scope, src, .intcast, dest_type, rhs);
3206 return rvalue(mod, scope, rl, result);
3215 return rvalue(mod, scope, rl, result, node);
32073216 },
32083217 .breakpoint => {
3218 if (true) @panic("TODO update for zir-memory-layout");
32093219 const result = try addZIRNoOp(mod, scope, src, .breakpoint);
3210 return rvalue(mod, scope, rl, result);
3220 return rvalue(mod, scope, rl, result, node);
32113221 },
32123222 .import => {
32133223 const target = try expr(mod, scope, .none, params[0]);
3214 const result = try addZIRUnOp(mod, scope, src, .import, target);
3215 return rvalue(mod, scope, rl, result);
3224 const result = try gz.addUnNode(.import, target, node);
3225 return rvalue(mod, scope, rl, result, node);
32163226 },
32173227 .compile_error => {
32183228 const target = try expr(mod, scope, .none, params[0]);
3219 const result = try addZIRUnOp(mod, scope, src, .compile_error, target);
3220 return rvalue(mod, scope, rl, result);
3229 const result = try gz.addUnNode(.compile_error, target, node);
3230 return rvalue(mod, scope, rl, result, node);
32213231 },
32223232 .set_eval_branch_quota => {
3223 const u32_type = try addZIRInstConst(mod, scope, src, .{
3224 .ty = Type.initTag(.type),
3225 .val = Value.initTag(.u32_type),
3226 });
3227 const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]);
3228 const result = try addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota);
3229 return rvalue(mod, scope, rl, result);
3233 const u32_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.u32_type) };
3234 const quota = try expr(mod, scope, u32_rl, params[0]);
3235 const result = try gz.addUnNode(.set_eval_branch_quota, quota, node);
3236 return rvalue(mod, scope, rl, result, node);
32303237 },
32313238 .compile_log => {
3239 if (true) @panic("TODO update for zir-memory-layout");
32323240 const arena = scope.arena();
32333241 var targets = try arena.alloc(zir.Inst.Ref, params.len);
32343242 for (params) |param, param_i|
32353243 targets[param_i] = try expr(mod, scope, .none, param);
32363244 const result = try addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{});
3237 return rvalue(mod, scope, rl, result);
3245 return rvalue(mod, scope, rl, result, node);
32383246 },
32393247 .field => {
3248 if (true) @panic("TODO update for zir-memory-layout");
32403249 const string_type = try addZIRInstConst(mod, scope, src, .{
32413250 .ty = Type.initTag(.type),
32423251 .val = Value.initTag(.const_slice_u8_type),
......@@ -3252,11 +3261,11 @@ fn builtinCall(
32523261 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{
32533262 .object = try expr(mod, scope, .none, params[0]),
32543263 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
3255 }));
3264 }), node);
32563265 },
3257 .as => return as(mod, scope, rl, builtin_token, src, params[0], params[1]),
3258 .bit_cast => return bitCast(mod, scope, rl, builtin_token, src, params[0], params[1]),
3259 .TypeOf => return typeOf(mod, scope, rl, builtin_token, src, params),
3266 .as => return as(mod, scope, rl, builtin_token, node, params[0], params[1]),
3267 .bit_cast => return bitCast(mod, scope, rl, builtin_token, node, params[0], params[1]),
3268 .TypeOf => return typeOf(mod, scope, rl, builtin_token, node, params),
32603269
32613270 .add_with_overflow,
32623271 .align_cast,
src/main.zig+13-20
......@@ -1750,15 +1750,12 @@ fn buildOutputType(
17501750 }
17511751
17521752 const self_exe_path = try fs.selfExePathAlloc(arena);
1753 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir|
1754 .{
1755 .path = lib_dir,
1756 .handle = try fs.cwd().openDir(lib_dir, .{}),
1757 }
1758 else
1759 introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
1760 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
1761 };
1753 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
1754 .path = lib_dir,
1755 .handle = try fs.cwd().openDir(lib_dir, .{}),
1756 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
1757 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
1758 };
17621759 defer zig_lib_directory.handle.close();
17631760
17641761 var thread_pool: ThreadPool = undefined;
......@@ -2461,15 +2458,12 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
24612458 }
24622459 }
24632460
2464 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir|
2465 .{
2466 .path = lib_dir,
2467 .handle = try fs.cwd().openDir(lib_dir, .{}),
2468 }
2469 else
2470 introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
2471 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
2472 };
2461 var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
2462 .path = lib_dir,
2463 .handle = try fs.cwd().openDir(lib_dir, .{}),
2464 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
2465 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
2466 };
24732467 defer zig_lib_directory.handle.close();
24742468
24752469 const std_special = "std" ++ fs.path.sep_str ++ "special";
......@@ -3281,8 +3275,7 @@ pub const ClangArgIterator = struct {
32813275 self.zig_equivalent = clang_arg.zig_equivalent;
32823276 break :find_clang_arg;
32833277 },
3284 }
3285 else {
3278 } else {
32863279 fatal("Unknown Clang option: '{s}'", .{arg});
32873280 }
32883281 }
src/zir.zig+33-13
......@@ -67,6 +67,13 @@ pub const Code = struct {
6767 return code.string_bytes[index..end :0];
6868 }
6969
70 pub fn deinit(code: *Code, gpa: *Allocator) void {
71 code.instructions.deinit(gpa);
72 gpa.free(code.string_bytes);
73 gpa.free(code.extra);
74 code.* = undefined;
75 }
76
7077 /// For debugging purposes, like dumpFn but for unanalyzed zir blocks
7178 pub fn dump(
7279 code: Code,
......@@ -737,15 +744,9 @@ pub const Inst = struct {
737744 /// of one or more params.
738745 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
739746 typeof_peer,
740 /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler
741 /// will assume the correctness of this instruction.
742 /// Uses the `node` union field.
743 unreachable_unsafe,
744 /// Asserts control-flow will not reach this instruction. In safety-checked modes,
745 /// this will generate a call to the panic function unless it can be proven unreachable
746 /// by the compiler.
747 /// Uses the `node` union field.
748 unreachable_safe,
747 /// Asserts control-flow will not reach this instruction (`unreachable`).
748 /// Uses the `unreachable` union field.
749 @"unreachable",
749750 /// Bitwise XOR. `^`
750751 xor,
751752 /// Create an optional type '?T'
......@@ -989,8 +990,7 @@ pub const Inst = struct {
989990 .ret_node,
990991 .ret_tok,
991992 .ret_coerce,
992 .unreachable_unsafe,
993 .unreachable_safe,
993 .@"unreachable",
994994 .loop,
995995 .suspend_block,
996996 .suspend_block_one,
......@@ -1131,6 +1131,20 @@ pub const Inst = struct {
11311131 callee: Ref,
11321132 param_index: u32,
11331133 },
1134 @"unreachable": struct {
1135 /// Offset from Decl AST node index.
1136 /// `Tag` determines which kind of AST node this points to.
1137 src_node: i32,
1138 /// `false`: Not safety checked - the compiler will assume the
1139 /// correctness of this instruction.
1140 /// `true`: In safety-checked modes, this will generate a call
1141 /// to the panic function unless it can be proven unreachable by the compiler.
1142 safety: bool,
1143
1144 pub fn src(self: @This()) LazySrcLoc {
1145 return .{ .node_offset = self.src_node };
1146 }
1147 },
11341148
11351149 // Make sure we don't accidentally add a field to make this union
11361150 // bigger than expected. Note that in Debug builds, Zig is allowed
......@@ -1408,8 +1422,6 @@ const Writer = struct {
14081422 .dbg_stmt_node,
14091423 .ret_ptr,
14101424 .ret_type,
1411 .unreachable_unsafe,
1412 .unreachable_safe,
14131425 => try self.writeNode(stream, inst),
14141426
14151427 .decl_ref,
......@@ -1424,6 +1436,7 @@ const Writer = struct {
14241436 .fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
14251437 .fn_type_var_args => try self.writeFnType(stream, inst, true),
14261438 .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
1439 .@"unreachable" => try self.writeUnreachable(stream, inst),
14271440
14281441 .enum_literal_small => try self.writeSmallStr(stream, inst),
14291442
......@@ -1612,6 +1625,13 @@ const Writer = struct {
16121625 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
16131626 }
16141627
1628 fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1629 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
1630 const safety_str = if (inst_data.safety) "safe" else "unsafe";
1631 try stream.print("{s}) ", .{safety_str});
1632 try self.writeSrc(stream, inst_data.src());
1633 }
1634
16151635 fn writeFnTypeCommon(
16161636 self: *Writer,
16171637 stream: anytype,