InternPool: implement and use thread-safe list for items

This commit is contained in:
Jacob Young
2024-07-04 03:33:23 -04:00
parent 8293ff94cf
commit 92ddb959a7
6 changed files with 851 additions and 729 deletions

View File

@@ -2745,7 +2745,7 @@ pub fn makeBinFileWritable(comp: *Compilation) !void {
const Header = extern struct {
intern_pool: extern struct {
items_len: u32,
//items_len: u32,
extra_len: u32,
limbs_len: u32,
//string_bytes_len: u32,
@@ -2774,7 +2774,7 @@ pub fn saveState(comp: *Compilation) !void {
const ip = &zcu.intern_pool;
const header: Header = .{
.intern_pool = .{
.items_len = @intCast(ip.items.len),
//.items_len = @intCast(ip.items.len),
.extra_len = @intCast(ip.extra.items.len),
.limbs_len = @intCast(ip.limbs.items.len),
//.string_bytes_len = @intCast(ip.string_bytes.items.len),
@@ -2792,8 +2792,8 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.limbs.items));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.extra.items));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));
//addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));
//addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));
//addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));

File diff suppressed because it is too large Load Diff

View File

@@ -2717,10 +2717,11 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
/// Given an `InternPool.WipNamespaceType` or `InternPool.WipEnumType`, apply
/// `sema.builtin_type_target_index` to it if necessary.
fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) {
const pt = sema.pt;
if (sema.builtin_type_target_index == .none) return wip_ty;
var new = wip_ty;
new.index = sema.builtin_type_target_index;
sema.pt.zcu.intern_pool.resolveBuiltinType(new.index, wip_ty.index);
pt.zcu.intern_pool.resolveBuiltinType(pt.tid, new.index, wip_ty.index);
return new;
}
@@ -2740,7 +2741,7 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
if (!was_outdated) return false;
_ = zcu.outdated_ready.swapRemove(decl_as_depender);
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
zcu.intern_pool.remove(ty);
zcu.intern_pool.remove(pt.tid, ty);
zcu.declPtr(decl_index).analysis = .dependency_failure;
try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
return true;
@@ -2819,7 +2820,7 @@ fn zirStructDecl(
},
.wip => |wip| wip,
});
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -3056,7 +3057,7 @@ fn zirEnumDecl(
// have finished constructing the type and are in the process of analyzing it.
var done = false;
errdefer if (!done) wip_ty.cancel(ip);
errdefer if (!done) wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -3324,7 +3325,7 @@ fn zirUnionDecl(
},
.wip => |wip| wip,
});
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -3414,7 +3415,7 @@ fn zirOpaqueDecl(
},
.wip => |wip| wip,
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -21705,7 +21706,7 @@ fn zirReify(
.existing => |ty| return Air.internedToRef(ty),
.wip => |wip| wip,
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -21901,7 +21902,7 @@ fn reifyEnum(
.wip => |wip| wip,
.existing => |ty| return Air.internedToRef(ty),
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
if (tag_ty.zigTypeTag(mod) != .Int) {
return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
@@ -22052,7 +22053,7 @@ fn reifyUnion(
.wip => |wip| wip,
.existing => |ty| return Air.internedToRef(ty),
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(
block,
@@ -22158,7 +22159,7 @@ fn reifyUnion(
const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index));
break :tag_ty .{ enum_tag_ty, false };
};
errdefer if (!has_explicit_tag) ip.remove(enum_tag_ty); // remove generated tag type on error
errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error
for (field_types) |field_ty_ip| {
const field_ty = Type.fromInterned(field_ty_ip);
@@ -22305,7 +22306,7 @@ fn reifyStruct(
.wip => |wip| wip,
.existing => |ty| return Air.internedToRef(ty),
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
if (is_tuple) switch (layout) {
.@"extern" => return sema.fail(block, src, "extern tuples are not supported", .{}),
@@ -36924,7 +36925,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.none,
=> unreachable,
_ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
_ => switch (ty.toIntern().getTag(ip)) {
.removed => unreachable,
.type_int_signed, // i0 handled above

View File

@@ -3686,7 +3686,7 @@ pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void {
.empty_struct => unreachable,
.generic_poison => unreachable,
else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
else => switch (ty_ip.getTag(ip)) {
.type_struct,
.type_struct_packed,
.type_struct_packed_inits,

View File

@@ -3071,42 +3071,6 @@ pub const SemaDeclResult = packed struct {
invalidate_decl_ref: bool,
};
pub fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
const decl = zcu.declPtr(decl_index);
assert(decl.has_tv);
assert(decl.owns_tv);
log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)});
switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
.Fn => @panic("TODO: update fn instance"),
.Type => {},
else => unreachable,
}
// We are the owner Decl of a type, and we were marked as outdated. That means the *structure*
// of this type changed; not just its namespace. Therefore, we need a new InternPool index.
//
// However, as soon as we make that, the context that created us will require re-analysis anyway
// (as it depends on this Decl's value), meaning the `struct_decl` (or equivalent) instruction
// will be analyzed again. Since Sema already needs to be able to reconstruct types like this,
// why should we bother implementing it here too when the Sema logic will be hit right after?
//
// So instead, let's just mark this Decl as failed - so that any remaining Decls which genuinely
// reference it (via `@This`) end up silently erroring too - and we'll let Sema make a new type
// with a new Decl.
//
// Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
zcu.intern_pool.remove(decl.val.toIntern());
decl.analysis = .dependency_failure;
return .{
.invalidate_decl_val = true,
.invalidate_decl_ref = true,
};
}
pub const ImportFileResult = struct {
file: *File,
file_index: File.Index,

View File

@@ -574,7 +574,7 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
if (decl.val.ip_index != func_index) {
try zcu.markDependeeOutdated(.{ .func_ies = func_index });
ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index }));
ip.remove(func_index);
ip.remove(pt.tid, func_index);
@panic("TODO: remove orphaned function from binary");
}
@@ -823,7 +823,7 @@ fn getFileRootStruct(
.existing => unreachable, // we wouldn't be analysing the file root if this type existed
.wip => |wip| wip,
};
errdefer wip_ty.cancel(ip);
errdefer wip_ty.cancel(ip, pt.tid);
if (zcu.comp.debug_incremental) {
try ip.addDependency(
@@ -885,7 +885,7 @@ fn semaFileUpdate(pt: Zcu.PerThread, file_index: Zcu.File.Index, type_outdated:
ip.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{
.decl = file_root_decl,
}));
ip.remove(decl.val.toIntern());
ip.remove(pt.tid, decl.val.toIntern());
decl.val = undefined;
_ = try pt.getFileRootStruct(file_root_decl, decl.src_namespace, file_index);
return true;
@@ -959,7 +959,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
assert(file.zir_loaded);
const struct_ty = try pt.getFileRootStruct(new_decl_index, new_namespace_index, file_index);
errdefer zcu.intern_pool.remove(struct_ty);
errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
switch (zcu.comp.cache_use) {
.whole => |whole| if (whole.cache_manifest) |man| {
@@ -1002,7 +1002,7 @@ fn semaDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {
if (decl.zir_decl_index == .none and decl.owns_tv) {
// We are re-analyzing an anonymous owner Decl (for a function or a namespace type).
return zcu.semaAnonOwnerDecl(decl_index);
return pt.semaAnonOwnerDecl(decl_index);
}
log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
@@ -1270,6 +1270,43 @@ fn semaDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {
return result;
}
pub fn semaAnonOwnerDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {
const zcu = pt.zcu;
const decl = zcu.declPtr(decl_index);
assert(decl.has_tv);
assert(decl.owns_tv);
log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)});
switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
.Fn => @panic("TODO: update fn instance"),
.Type => {},
else => unreachable,
}
// We are the owner Decl of a type, and we were marked as outdated. That means the *structure*
// of this type changed; not just its namespace. Therefore, we need a new InternPool index.
//
// However, as soon as we make that, the context that created us will require re-analysis anyway
// (as it depends on this Decl's value), meaning the `struct_decl` (or equivalent) instruction
// will be analyzed again. Since Sema already needs to be able to reconstruct types like this,
// why should we bother implementing it here too when the Sema logic will be hit right after?
//
// So instead, let's just mark this Decl as failed - so that any remaining Decls which genuinely
// reference it (via `@This`) end up silently erroring too - and we'll let Sema make a new type
// with a new Decl.
//
// Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
zcu.intern_pool.remove(pt.tid, decl.val.toIntern());
decl.analysis = .dependency_failure;
return .{
.invalidate_decl_val = true,
.invalidate_decl_ref = true,
};
}
pub fn embedFile(
pt: Zcu.PerThread,
cur_file: *Zcu.File,