Commit 9e6318a4ea

mlugg <mlugg@mlugg.co.uk>
2024-08-17 13:05:12
compiler: add some doc comments
1 parent 7f2466e
Changed files (2)
src/Zcu/PerThread.zig
@@ -1,3 +1,6 @@
+//! This type provides a wrapper around a `*Zcu` for uses which require a thread `Id`.
+//! Any operation which mutates `InternPool` state lives here rather than on `Zcu`.
+
 zcu: *Zcu,
 
 /// Dense, per-thread unique index.
src/InternPool.zig
@@ -62,10 +62,18 @@ const want_multi_threaded = true;
 /// Whether a single-threaded intern pool impl is in use.
 pub const single_threaded = builtin.single_threaded or !want_multi_threaded;
 
+/// A `TrackedInst.Index` provides a single, unchanging reference to a ZIR instruction across a whole
+/// compilation. From this index, you can acquire a `TrackedInst`, which containss a reference to both
+/// the file which the instruction lives in, and the instruction index itself, which is updated on
+/// incremental updates by `Zcu.updateZirRefs`.
 pub const TrackedInst = extern struct {
     file: FileIndex,
     inst: Zir.Inst.Index,
 
+    /// It is possible on an incremental update that we "lose" a ZIR instruction: some tracked `%x` in
+    /// the old ZIR failed to map to any `%y` in the new ZIR. For this reason, we actually store values
+    /// of type `MaybeLost`, which uses `ZirIndex.lost` to represent this case. `Index.resolve` etc
+    /// return `null` when the `TrackedInst` being resolved has been lost.
     pub const MaybeLost = extern struct {
         file: FileIndex,
         inst: ZirIndex,
@@ -244,14 +252,17 @@ pub fn trackZir(
     return index;
 }
 
+/// At the start of an incremental update, we update every entry in `tracked_insts` to include
+/// the new ZIR index. Once this is done, we must update the hashmap metadata so that lookups
+/// return correct entries where they already exist.
 pub fn rehashTrackedInsts(
     ip: *InternPool,
     gpa: Allocator,
-    /// TODO: maybe don't take this? it doesn't actually matter, only one thread is running at this point
     tid: Zcu.PerThread.Id,
 ) Allocator.Error!void {
+    assert(tid == .main); // we shouldn't have any other threads active right now
+
     // TODO: this function doesn't handle OOM well. What should it do?
-    //       Indeed, what should anyone do when they run out of memory?
 
     // We don't lock anything, as this function assumes that no other thread is
     // accessing `tracked_insts`. This is necessary because we're going to be
@@ -795,6 +806,14 @@ const Local = struct {
     /// This state is fully local to the owning thread and does not require any
     /// atomic access.
     mutate: struct {
+        /// When we need to allocate any long-lived buffer for mutating the `InternPool`, it is
+        /// allocated into this `arena` (for the `Id` of the thread performing the mutation). An
+        /// arena is used to avoid contention on the GPA, and to ensure that any code which retains
+        /// references to old state remains valid. For instance, when reallocing hashmap metadata,
+        /// a racing lookup on another thread may still retain a handle to the old metadata pointer,
+        /// so it must remain valid.
+        /// This arena's lifetime is tied to that of `Compilation`, although it can be cleared on
+        /// garbage collection (currently vaporware).
         arena: std.heap.ArenaAllocator.State,
 
         items: ListMutate,