From 3f1a349ed1ea211e697bf335788b5fb9aa64e9d4 Mon Sep 17 00:00:00 2001 From: BREW <81044362+b-re-w@users.noreply.github.com> Date: Sat, 17 Oct 2026 15:33:04 +0900 Subject: [PATCH] Spec: N-12 elides refcounts and borrows field reads only on thread-local objects on 3.15t Refs #193 --- docs/SPEC.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/SPEC.md b/docs/SPEC.md index 6c8f6b9c7..912292431 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -614,7 +614,13 @@ All in `PM/commonTest`, so they run wherever the interpreter loads. without being passed it. At such a call every live virtual object is materialised, in allocation order. `is`, `type()` and `isinstance` on virtual objects are decided statically. An increment/decrement pair is elided only when another owned reference keeps the object alive throughout and no unknown code runs in - between, so every refcount that can be observed is exact. Virtual objects whose count is unbounded live in + between, so every refcount that can be observed is exact. **On free-threaded 3.15t (no GIL) both + borrowed field reads and pair elision apply only to objects proven thread-local** (never escaped to a + global, a container, another thread or unknown code; #193, decision D5): another thread could otherwise + write the slot and free the child between the read and its use. Every other field read takes a real + reference, or reads inside CPython's per-object critical section (`Py_BEGIN_CRITICAL_SECTION`) when a + sequence of reads must be consistent. A free-threaded stress test (one thread reading a field, another + replacing it) under ASan/TSan is part of N-12's tests. Virtual objects whose count is unbounded live in a region tied to one activation (the innermost scope that bounds their lifetime) and are freed together; real objects are never placed in a region. A failed region allocation raises `MemoryError` where CPython would. The verifier proves non-escape, materialisation before every observation point, a keeping