authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 10:43:51-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 11:20:08-04:00
logf290b54f891a67af456529da0f4f824a1e27b4ef
treedb471701e43acc6f640643fab8ba529162daa69f
parent8f292431b03055e789f75aa98888c0f49520e268

InternPool: make `files` more thread-safe


4 files changed, 61 insertions(+), 52 deletions(-)

src/Compilation.zig+4-4
...@@ -2784,7 +2784,7 @@ const Header = extern struct {...@@ -2784,7 +2784,7 @@ const Header = extern struct {
2784 first_dependency_len: u32,2784 first_dependency_len: u32,
2785 dep_entries_len: u32,2785 dep_entries_len: u32,
2786 free_dep_entries_len: u32,2786 free_dep_entries_len: u32,
2787 files_len: u32,2787 //files_len: u32,
2788 },2788 },
2789};2789};
27902790
...@@ -2813,7 +2813,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2813,7 +2813,7 @@ pub fn saveState(comp: *Compilation) !void {
2813 .first_dependency_len = @intCast(ip.first_dependency.count()),2813 .first_dependency_len = @intCast(ip.first_dependency.count()),
2814 .dep_entries_len = @intCast(ip.dep_entries.items.len),2814 .dep_entries_len = @intCast(ip.dep_entries.items.len),
2815 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len),2815 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len),
2816 .files_len = @intCast(ip.files.entries.len),2816 //.files_len = @intCast(ip.files.entries.len),
2817 },2817 },
2818 };2818 };
2819 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));2819 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
...@@ -2838,8 +2838,8 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2838,8 +2838,8 @@ pub fn saveState(comp: *Compilation) !void {
2838 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items));2838 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items));
2839 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items));2839 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items));
28402840
2841 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.keys()));2841 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.keys()));
2842 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.values()));2842 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.values()));
28432843
2844 // TODO: compilation errors2844 // TODO: compilation errors
2845 // TODO: namespaces2845 // TODO: namespaces
src/InternPool.zig+24-23
...@@ -59,17 +59,6 @@ dep_entries: std.ArrayListUnmanaged(DepEntry) = .{},...@@ -59,17 +59,6 @@ dep_entries: std.ArrayListUnmanaged(DepEntry) = .{},
59/// garbage collection pass.59/// garbage collection pass.
60free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},60free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},
6161
62/// Elements are ordered identically to the `import_table` field of `Zcu`.
63///
64/// Unlike `import_table`, this data is serialized as part of incremental
65/// compilation state.
66///
67/// Key is the hash of the path to this file, used to store
68/// `InternPool.TrackedInst`.
69///
70/// Value is the `Decl` of the struct that represents this `File`.
71files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{},
72
73/// Whether a multi-threaded intern pool is useful.62/// Whether a multi-threaded intern pool is useful.
74/// Currently `false` until the intern pool is actually accessed63/// Currently `false` until the intern pool is actually accessed
75/// from multiple threads to reduce the cost of this data structure.64/// from multiple threads to reduce the cost of this data structure.
...@@ -346,7 +335,7 @@ const Local = struct {...@@ -346,7 +335,7 @@ const Local = struct {
346 extra: Extra,335 extra: Extra,
347 limbs: Limbs,336 limbs: Limbs,
348 strings: Strings,337 strings: Strings,
349 files: Files,338 files: List(File),
350339
351 decls: Decls,340 decls: Decls,
352 namespaces: Namespaces,341 namespaces: Namespaces,
...@@ -367,7 +356,6 @@ const Local = struct {...@@ -367,7 +356,6 @@ const Local = struct {
367 else => @compileError("unsupported host"),356 else => @compileError("unsupported host"),
368 };357 };
369 const Strings = List(struct { u8 });358 const Strings = List(struct { u8 });
370 const Files = List(struct { *Zcu.File });
371359
372 const decls_bucket_width = 8;360 const decls_bucket_width = 8;
373 const decls_bucket_mask = (1 << decls_bucket_width) - 1;361 const decls_bucket_mask = (1 << decls_bucket_width) - 1;
...@@ -600,7 +588,7 @@ const Local = struct {...@@ -600,7 +588,7 @@ const Local = struct {
600 const View = std.MultiArrayList(Elem);588 const View = std.MultiArrayList(Elem);
601589
602 /// Must be called when accessing from another thread.590 /// Must be called when accessing from another thread.
603 fn acquire(list: *const ListSelf) ListSelf {591 pub fn acquire(list: *const ListSelf) ListSelf {
604 return .{ .bytes = @atomicLoad([*]align(@alignOf(Elem)) u8, &list.bytes, .acquire) };592 return .{ .bytes = @atomicLoad([*]align(@alignOf(Elem)) u8, &list.bytes, .acquire) };
605 }593 }
606 fn release(list: *ListSelf, new_list: ListSelf) void {594 fn release(list: *ListSelf, new_list: ListSelf) void {
...@@ -614,7 +602,7 @@ const Local = struct {...@@ -614,7 +602,7 @@ const Local = struct {
614 return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset);602 return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset);
615 }603 }
616604
617 fn view(list: ListSelf) View {605 pub fn view(list: ListSelf) View {
618 const capacity = list.header().capacity;606 const capacity = list.header().capacity;
619 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`607 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
620 return .{608 return .{
...@@ -675,7 +663,16 @@ const Local = struct {...@@ -675,7 +663,16 @@ const Local = struct {
675 };663 };
676 }664 }
677665
678 pub fn getMutableFiles(local: *Local, gpa: std.mem.Allocator) Files.Mutable {666 /// Elements are ordered identically to the `import_table` field of `Zcu`.
667 ///
668 /// Unlike `import_table`, this data is serialized as part of incremental
669 /// compilation state.
670 ///
671 /// Key is the hash of the path to this file, used to store
672 /// `InternPool.TrackedInst`.
673 ///
674 /// Value is the `Decl` of the struct that represents this `File`.
675 pub fn getMutableFiles(local: *Local, gpa: std.mem.Allocator) List(File).Mutable {
679 return .{676 return .{
680 .gpa = gpa,677 .gpa = gpa,
681 .arena = &local.mutate.arena,678 .arena = &local.mutate.arena,
...@@ -957,7 +954,7 @@ pub const FileIndex = enum(u32) {...@@ -957,7 +954,7 @@ pub const FileIndex = enum(u32) {
957 unwrapped.index);954 unwrapped.index);
958 }955 }
959 };956 };
960 fn unwrap(file_index: FileIndex, ip: *const InternPool) Unwrapped {957 pub fn unwrap(file_index: FileIndex, ip: *const InternPool) Unwrapped {
961 return .{958 return .{
962 .tid = @enumFromInt(@intFromEnum(file_index) >> ip.tid_shift_32 & ip.getTidMask()),959 .tid = @enumFromInt(@intFromEnum(file_index) >> ip.tid_shift_32 & ip.getTidMask()),
963 .index = @intFromEnum(file_index) & ip.getIndexMask(u32),960 .index = @intFromEnum(file_index) & ip.getIndexMask(u32),
...@@ -965,6 +962,12 @@ pub const FileIndex = enum(u32) {...@@ -965,6 +962,12 @@ pub const FileIndex = enum(u32) {
965 }962 }
966};963};
967964
965const File = struct {
966 bin_digest: Cache.BinDigest,
967 file: *Zcu.File,
968 root_decl: OptionalDeclIndex,
969};
970
968/// An index into `strings`.971/// An index into `strings`.
969pub const String = enum(u32) {972pub const String = enum(u32) {
970 /// An empty string.973 /// An empty string.
...@@ -5237,7 +5240,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5237,7 +5240,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5237 .extra = Local.Extra.empty,5240 .extra = Local.Extra.empty,
5238 .limbs = Local.Limbs.empty,5241 .limbs = Local.Limbs.empty,
5239 .strings = Local.Strings.empty,5242 .strings = Local.Strings.empty,
5240 .files = Local.Files.empty,5243 .files = Local.List(File).empty,
52415244
5242 .decls = Local.Decls.empty,5245 .decls = Local.Decls.empty,
5243 .namespaces = Local.Namespaces.empty,5246 .namespaces = Local.Namespaces.empty,
...@@ -5321,8 +5324,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -5321,8 +5324,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
5321 ip.dep_entries.deinit(gpa);5324 ip.dep_entries.deinit(gpa);
5322 ip.free_dep_entries.deinit(gpa);5325 ip.free_dep_entries.deinit(gpa);
53235326
5324 ip.files.deinit(gpa);
5325
5326 gpa.free(ip.shards);5327 gpa.free(ip.shards);
5327 for (ip.locals) |*local| {5328 for (ip.locals) |*local| {
5328 const buckets_len = local.mutate.namespaces.buckets_list.len;5329 const buckets_len = local.mutate.namespaces.buckets_list.len;
...@@ -9790,21 +9791,21 @@ pub fn destroyNamespace(...@@ -9790,21 +9791,21 @@ pub fn destroyNamespace(
9790pub fn filePtr(ip: *InternPool, file_index: FileIndex) *Zcu.File {9791pub fn filePtr(ip: *InternPool, file_index: FileIndex) *Zcu.File {
9791 const file_index_unwrapped = file_index.unwrap(ip);9792 const file_index_unwrapped = file_index.unwrap(ip);
9792 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();9793 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
9793 return files.view().items(.@"0")[file_index_unwrapped.index];9794 return files.view().items(.file)[file_index_unwrapped.index];
9794}9795}
97959796
9796pub fn createFile(9797pub fn createFile(
9797 ip: *InternPool,9798 ip: *InternPool,
9798 gpa: Allocator,9799 gpa: Allocator,
9799 tid: Zcu.PerThread.Id,9800 tid: Zcu.PerThread.Id,
9800 file: *Zcu.File,9801 file: File,
9801) Allocator.Error!FileIndex {9802) Allocator.Error!FileIndex {
9802 const files = ip.getLocal(tid).getMutableFiles(gpa);9803 const files = ip.getLocal(tid).getMutableFiles(gpa);
9803 const file_index_unwrapped: FileIndex.Unwrapped = .{9804 const file_index_unwrapped: FileIndex.Unwrapped = .{
9804 .tid = tid,9805 .tid = tid,
9805 .index = files.mutate.len,9806 .index = files.mutate.len,
9806 };9807 };
9807 try files.append(.{file});9808 try files.append(file);
9808 return file_index_unwrapped.wrap(ip);9809 return file_index_unwrapped.wrap(ip);
9809}9810}
98109811
src/Zcu.zig+15-11
...@@ -2406,8 +2406,7 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2406,8 +2406,7 @@ pub fn deinit(zcu: *Zcu) void {
2406 for (zcu.import_table.keys()) |key| {2406 for (zcu.import_table.keys()) |key| {
2407 gpa.free(key);2407 gpa.free(key);
2408 }2408 }
2409 for (0..zcu.import_table.entries.len) |file_index_usize| {2409 for (zcu.import_table.values()) |file_index| {
2410 const file_index: File.Index = @enumFromInt(file_index_usize);
2411 pt.destroyFile(file_index);2410 pt.destroyFile(file_index);
2412 }2411 }
2413 zcu.import_table.deinit(gpa);2412 zcu.import_table.deinit(gpa);
...@@ -3537,23 +3536,28 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, Resolved...@@ -3537,23 +3536,28 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, Resolved
3537 return result;3536 return result;
3538}3537}
35393538
3540pub fn fileByIndex(zcu: *Zcu, i: File.Index) *File {3539pub fn fileByIndex(zcu: *Zcu, file_index: File.Index) *File {
3541 const ip = &zcu.intern_pool;3540 return zcu.intern_pool.filePtr(file_index);
3542 return ip.filePtr(i);
3543}3541}
35443542
3545/// Returns the `Decl` of the struct that represents this `File`.3543/// Returns the `Decl` of the struct that represents this `File`.
3546pub fn fileRootDecl(zcu: *const Zcu, i: File.Index) Decl.OptionalIndex {3544pub fn fileRootDecl(zcu: *const Zcu, file_index: File.Index) Decl.OptionalIndex {
3547 const ip = &zcu.intern_pool;3545 const ip = &zcu.intern_pool;
3548 return ip.files.values()[@intFromEnum(i)];3546 const file_index_unwrapped = file_index.unwrap(ip);
3547 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
3548 return files.view().items(.root_decl)[file_index_unwrapped.index];
3549}3549}
35503550
3551pub fn setFileRootDecl(zcu: *Zcu, i: File.Index, root_decl: Decl.OptionalIndex) void {3551pub fn setFileRootDecl(zcu: *Zcu, file_index: File.Index, root_decl: Decl.OptionalIndex) void {
3552 const ip = &zcu.intern_pool;3552 const ip = &zcu.intern_pool;
3553 ip.files.values()[@intFromEnum(i)] = root_decl;3553 const file_index_unwrapped = file_index.unwrap(ip);
3554 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
3555 files.view().items(.root_decl)[file_index_unwrapped.index] = root_decl;
3554}3556}
35553557
3556pub fn filePathDigest(zcu: *const Zcu, i: File.Index) Cache.BinDigest {3558pub fn filePathDigest(zcu: *const Zcu, file_index: File.Index) Cache.BinDigest {
3557 const ip = &zcu.intern_pool;3559 const ip = &zcu.intern_pool;
3558 return ip.files.keys()[@intFromEnum(i)];3560 const file_index_unwrapped = file_index.unwrap(ip);
3561 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
3562 return files.view().items(.bin_digest)[file_index_unwrapped.index];
3559}3563}
src/Zcu/PerThread.zig+18-14
...@@ -1386,15 +1386,16 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -1386,15 +1386,16 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1386 }1386 }
13871387
1388 const ip = &zcu.intern_pool;1388 const ip = &zcu.intern_pool;
1389 try ip.files.ensureUnusedCapacity(gpa, 1);
1390
1391 if (mod.builtin_file) |builtin_file| {1389 if (mod.builtin_file) |builtin_file| {
1392 const file_index = try ip.createFile(gpa, pt.tid, builtin_file);1390 const path_digest = Zcu.computePathDigest(zcu, mod, builtin_file.sub_file_path);
1391 const file_index = try ip.createFile(gpa, pt.tid, .{
1392 .bin_digest = path_digest,
1393 .file = builtin_file,
1394 .root_decl = .none,
1395 });
1393 keep_resolved_path = true; // It's now owned by import_table.1396 keep_resolved_path = true; // It's now owned by import_table.
1394 gop.value_ptr.* = file_index;1397 gop.value_ptr.* = file_index;
1395 try builtin_file.addReference(zcu, .{ .root = mod });1398 try builtin_file.addReference(zcu, .{ .root = mod });
1396 const path_digest = Zcu.computePathDigest(zcu, mod, builtin_file.sub_file_path);
1397 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1398 return .{1399 return .{
1399 .file = builtin_file,1400 .file = builtin_file,
1400 .file_index = file_index,1401 .file_index = file_index,
...@@ -1409,7 +1410,12 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -1409,7 +1410,12 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1409 const new_file = try gpa.create(Zcu.File);1410 const new_file = try gpa.create(Zcu.File);
1410 errdefer gpa.destroy(new_file);1411 errdefer gpa.destroy(new_file);
14111412
1412 const new_file_index = try ip.createFile(gpa, pt.tid, new_file);1413 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1414 const new_file_index = try ip.createFile(gpa, pt.tid, .{
1415 .bin_digest = path_digest,
1416 .file = new_file,
1417 .root_decl = .none,
1418 });
1413 keep_resolved_path = true; // It's now owned by import_table.1419 keep_resolved_path = true; // It's now owned by import_table.
1414 gop.value_ptr.* = new_file_index;1420 gop.value_ptr.* = new_file_index;
1415 new_file.* = .{1421 new_file.* = .{
...@@ -1425,10 +1431,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -1425,10 +1431,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1425 .mod = mod,1431 .mod = mod,
1426 };1432 };
14271433
1428 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1429
1430 try new_file.addReference(zcu, .{ .root = mod });1434 try new_file.addReference(zcu, .{ .root = mod });
1431 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1432 return .{1435 return .{
1433 .file = new_file,1436 .file = new_file,
1434 .file_index = new_file_index,1437 .file_index = new_file_index,
...@@ -1489,8 +1492,6 @@ pub fn importFile(...@@ -1489,8 +1492,6 @@ pub fn importFile(
14891492
1490 const ip = &zcu.intern_pool;1493 const ip = &zcu.intern_pool;
14911494
1492 try ip.files.ensureUnusedCapacity(gpa, 1);
1493
1494 const new_file = try gpa.create(Zcu.File);1495 const new_file = try gpa.create(Zcu.File);
1495 errdefer gpa.destroy(new_file);1496 errdefer gpa.destroy(new_file);
14961497
...@@ -1515,7 +1516,12 @@ pub fn importFile(...@@ -1515,7 +1516,12 @@ pub fn importFile(
1515 resolved_root_path, resolved_path, sub_file_path, import_string,1516 resolved_root_path, resolved_path, sub_file_path, import_string,
1516 });1517 });
15171518
1518 const new_file_index = try ip.createFile(gpa, pt.tid, new_file);1519 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1520 const new_file_index = try ip.createFile(gpa, pt.tid, .{
1521 .bin_digest = path_digest,
1522 .file = new_file,
1523 .root_decl = .none,
1524 });
1519 keep_resolved_path = true; // It's now owned by import_table.1525 keep_resolved_path = true; // It's now owned by import_table.
1520 gop.value_ptr.* = new_file_index;1526 gop.value_ptr.* = new_file_index;
1521 new_file.* = .{1527 new_file.* = .{
...@@ -1531,8 +1537,6 @@ pub fn importFile(...@@ -1531,8 +1537,6 @@ pub fn importFile(
1531 .mod = mod,1537 .mod = mod,
1532 };1538 };
15331539
1534 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1535 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1536 return .{1540 return .{
1537 .file = new_file,1541 .file = new_file,
1538 .file_index = new_file_index,1542 .file_index = new_file_index,