aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-01-15 00:17:25 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-01-15 00:17:25 -0700
commita5c7742ba6fc793608b8bb7ba058e33eccd9cfec (patch)
tree29bf43a0bb915e35244d457514885baca2a5916b /src
parent41f3799bf0cfc8241f458094781ba45967e2576e (diff)
downloadzig-a5c7742ba6fc793608b8bb7ba058e33eccd9cfec.tar.gz
zig-a5c7742ba6fc793608b8bb7ba058e33eccd9cfec.zip
stage2: fix Decl garbage collection not marking enough
It is the job of codegen backends to mark Decls that are referenced as alive so that the frontend does not sweep them with the garbage. This commit unifies the code between the backends with an added method on Decl. The implementation is more complete than before, switching on the Decl val tag and recursing into sub-values. As a result, two more array tests are passing.
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig10
-rw-r--r--src/arch/wasm/CodeGen.zig17
-rw-r--r--src/codegen.zig15
-rw-r--r--src/codegen/c.zig15
-rw-r--r--src/codegen/llvm.zig26
-rw-r--r--src/value.zig49
6 files changed, 67 insertions, 65 deletions
diff --git a/src/Module.zig b/src/Module.zig
index e93fe2549c..a464ac83de 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -783,6 +783,16 @@ pub const Decl = struct {
return decl.ty.abiAlignment(target);
}
}
+
+ pub fn markAlive(decl: *Decl) void {
+ if (decl.alive) return;
+ decl.alive = true;
+
+ // This is the first time we are marking this Decl alive. We must
+ // therefore recurse into its value and mark any Decl it references
+ // as also alive, so that any Decl referenced does not get garbage collected.
+ decl.val.markReferencedDeclsAlive();
+ }
};
/// This state is attached to every Decl when Module emit_h is non-null.
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 97b43b3067..7a8efdfcc2 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1037,7 +1037,7 @@ fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerErro
const offset = @intCast(u32, self.code.items.len);
const atom = &self.decl.link.wasm;
const target_sym_index = decl.link.wasm.sym_index;
- markDeclAlive(decl);
+ decl.markAlive();
if (decl.ty.zigTypeTag() == .Fn) {
// We found a function pointer, so add it to our table,
// as function pointers are not allowed to be stored inside the data section,
@@ -1935,7 +1935,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
try self.emitConstant(slice.data.len, Type.usize);
} else if (val.castTag(.decl_ref)) |payload| {
const decl = payload.data;
- markDeclAlive(decl);
+ decl.markAlive();
// Function pointers use a table index, rather than a memory address
if (decl.ty.zigTypeTag() == .Fn) {
const target_sym_index = decl.link.wasm.sym_index;
@@ -2101,19 +2101,6 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
}
}
-fn markDeclAlive(decl: *Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
-}
-
fn emitUndefined(self: *Self, ty: Type) InnerError!void {
switch (ty.zigTypeTag()) {
.Int => switch (ty.intInfo(self.target).bits) {
diff --git a/src/codegen.zig b/src/codegen.zig
index 1d20c4bc74..65b0318e9e 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -464,7 +464,7 @@ fn lowerDeclRef(
}
if (decl.analysis != .complete) return error.AnalysisFail;
- markDeclAlive(decl);
+ decl.markAlive();
const vaddr = vaddr: {
if (bin_file.cast(link.File.MachO)) |macho_file| {
break :vaddr try macho_file.getDeclVAddrWithReloc(decl, code.items.len);
@@ -484,16 +484,3 @@ fn lowerDeclRef(
return Result{ .appended = {} };
}
-
-fn markDeclAlive(decl: *Module.Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
-}
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 58bf919b1f..3f3147ca80 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -215,7 +215,7 @@ pub const DeclGen = struct {
val: Value,
decl: *Decl,
) error{ OutOfMemory, AnalysisFail }!void {
- markDeclAlive(decl);
+ decl.markAlive();
if (ty.isSlice()) {
try writer.writeByte('(');
@@ -253,19 +253,6 @@ pub const DeclGen = struct {
try dg.renderDeclName(decl, writer);
}
- fn markDeclAlive(decl: *Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
- }
-
fn renderInt128(
writer: anytype,
int_val: anytype,
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 7858fa76fa..d8c9589213 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1224,7 +1224,7 @@ pub const DeclGen = struct {
.decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
.variable => {
const decl = tv.val.castTag(.variable).?.data.owner_decl;
- dg.markDeclAlive(decl);
+ decl.markAlive();
const val = try dg.resolveGlobalDecl(decl);
const llvm_var_type = try dg.llvmType(tv.ty);
const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
@@ -1373,7 +1373,7 @@ pub const DeclGen = struct {
.function => tv.val.castTag(.function).?.data.owner_decl,
else => unreachable,
};
- dg.markDeclAlive(fn_decl);
+ fn_decl.markAlive();
return dg.resolveLlvmFunction(fn_decl);
},
.ErrorSet => {
@@ -1681,7 +1681,7 @@ pub const DeclGen = struct {
ptr_val: Value,
decl: *Module.Decl,
) Error!ParentPtr {
- dg.markDeclAlive(decl);
+ decl.markAlive();
var ptr_ty_payload: Type.Payload.ElemType = .{
.base = .{ .tag = .single_mut_pointer },
.data = decl.ty,
@@ -1763,7 +1763,7 @@ pub const DeclGen = struct {
return self.lowerPtrToVoid(tv.ty);
}
- self.markDeclAlive(decl);
+ decl.markAlive();
const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
try self.resolveLlvmFunction(decl)
@@ -1774,24 +1774,6 @@ pub const DeclGen = struct {
return llvm_val.constBitCast(llvm_type);
}
- fn markDeclAlive(dg: *DeclGen, decl: *Module.Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- log.debug("{*} ({s}) marked alive by {*} ({s})", .{
- decl, decl.name,
- dg.decl, dg.decl.name,
- });
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return dg.markDeclAlive(pointee);
- }
- }
-
fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*const llvm.Value {
const target = dg.module.getTarget();
const alignment = ptr_ty.ptrAlignment(target);
diff --git a/src/value.zig b/src/value.zig
index 1993a853cd..1836a14ce0 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1746,6 +1746,55 @@ pub const Value = extern union {
};
}
+ pub fn markReferencedDeclsAlive(val: Value) void {
+ switch (val.tag()) {
+ .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),
+ .extern_fn, .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
+ .function => return val.castTag(.function).?.data.owner_decl.markAlive(),
+ .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),
+
+ .repeated,
+ .eu_payload,
+ .eu_payload_ptr,
+ .opt_payload,
+ .opt_payload_ptr,
+ .empty_array_sentinel,
+ => return markReferencedDeclsAlive(val.cast(Payload.SubValue).?.data),
+
+ .array => {
+ for (val.cast(Payload.Array).?.data) |elem_val| {
+ markReferencedDeclsAlive(elem_val);
+ }
+ },
+ .slice => {
+ const slice = val.cast(Payload.Slice).?.data;
+ markReferencedDeclsAlive(slice.ptr);
+ markReferencedDeclsAlive(slice.len);
+ },
+
+ .elem_ptr => {
+ const elem_ptr = val.cast(Payload.ElemPtr).?.data;
+ return markReferencedDeclsAlive(elem_ptr.array_ptr);
+ },
+ .field_ptr => {
+ const field_ptr = val.cast(Payload.FieldPtr).?.data;
+ return markReferencedDeclsAlive(field_ptr.container_ptr);
+ },
+ .@"struct" => {
+ for (val.cast(Payload.Struct).?.data) |field_val| {
+ markReferencedDeclsAlive(field_val);
+ }
+ },
+ .@"union" => {
+ const data = val.cast(Payload.Union).?.data;
+ markReferencedDeclsAlive(data.tag);
+ markReferencedDeclsAlive(data.val);
+ },
+
+ else => {},
+ }
+ }
+
pub fn slicePtr(val: Value) Value {
return switch (val.tag()) {
.slice => val.castTag(.slice).?.data.ptr,