Skip to content

Commit a016809

Browse files
committed
Phase 4.X-full X3b (Batch 96): Environment::references_ → PhxPtrSet — E-1+E-2+E-3 DISCHARGED
Per supervisor 04:26:00Z X3b dispatch + theologian 04:26:18Z watchpoints + pre-analysis docs/tier7-phase4x-x3-preanalysis-2026-05-01.md §2 §4. X3b is the codegen-touching Environment migration consuming X3a substrate (PhxPtrSet + phx_threaded_ref bridges). Discharges 3 stay-C++ exceptions in single batch: - E-1 (Environment dtor STL clear via ~ThreadedRef destructor chain) - E-2 (Environment addReference STL emplace via ThreadedRef::create+incref) - E-3 (Environment::references() std::unordered_set return type) Phase 4.X-full inventory 7→4 stay-C++ exceptions remaining. Pre-author substrate-grep per supervisor instruction: confirmed Environment is the sole consumer of std::unordered_set<ThreadedRef<>>; single external caller of references() at gen_asm.cpp:1412 (range-for); HirEnvironment opaque-blob layout pinned at hir_instr_c.h:165 + HirEnvironmentLayoutVerifier static_asserts at verify.cpp:123-133. Pre-commit chat-recheck applied (latest shepard 04:31:51Z verbosity flag at supervisor, no reversal). Migration (+59 LOC across 5 files): (1) hir.h (+9 LOC): #include phx_ptr_set.h; ReferenceSet typedef std::unordered_set<ThreadedRef<>> → PhxPtrSet; references_{} value-init for POD struct (was default-init via std::unordered_set ctor) (2) hir.cpp (+28 LOC): #include phx_ptr_set.h + phx_threaded_ref.h. - ~Environment: ThreadedCompileSerialize guard retained (Phoenix concurrency-infra class, stays C++); iterate raw slots via phx_ptr_set_at + phx_threaded_decref each + phx_ptr_set_destroy (theologian watchpoint python#2) - addReference(PyObject*): contains-check BEFORE phx_threaded_incref (theologian watchpoint python#1: dedup semantic preserved; prevents double-incref on duplicate adds — matches prior unordered_set:: emplace dedup which would discard the temporary ThreadedRef on dup hit, balancing create's incref against ~ThreadedRef's decref) - addReference(Ref<>): unchanged (delegates) - references(): direct PhxPtrSet& return (no opaque-blob bridge cast) (3) hir_instr_c.h (+7 LOC): HirEnvironment.references_opaque[56] → references_entries (void*) + references_count (size_t) + references_capacity (size_t) = sizeof(PhxPtrSet) = 24 bytes on 64-bit. Block-comment documents the X3b layout migration. (4) hir_instr_c_verify.cpp (+1 LOC): HirEnvironmentLayoutVerifier offsetof(references_opaque) → offsetof(references_entries) == offsetof(Environment, references_); rest of static_asserts unchanged (sizeof + other field offsets intact since PhxPtrSet matches std:: unordered_set bucket-array sizeof on the typical libstdc++ impl). (5) gen_asm.cpp (+10/-3 LOC): range-for over std::unordered_set< ThreadedRef<>> → raw-slot iteration via phx_ptr_set_capacity + phx_ptr_set_at; cast PyObject* per code_rt->addReference signature (theologian watchpoint python#3 + supervisor watchpoint python#3 §4.4 falsifier: code_runtime.h:112 takes PyObject* directly). ThreadedCompileSerialize retained at all sites (Phoenix concurrency-infra class, OUT of stay-C++ exception inventory per supervisor 04:04:50Z Q-X3-3); thin extern "C" phx_threaded_incref/decref bridges (X3a) provide GIL-correct refcount paths via jit::ThreadedRef<>::incref/decref. Falsifier (V5): - Existing batch92 (PhxPtrSet) verifier covers C-side substrate - HirEnvironmentLayoutVerifier static_asserts pin field offsets - Py_REF_DEBUG ARM64 pydebug runtime test (theologian watchpoint python#4 + supervisor §4.2 falsifier) provides primary refcount-balance verification via testkeeper integration - E-1+E-2+E-3 behavior exercised by every JIT compile + teardown in test_phoenix.sh suite Cumulative-drift watch counter: 16/5+ (17/20 toward next cap-check). Codegen-touching but X3a substrate is empirically variance-class on this session arc; expected within forward-watch tolerance. nqueens advisory cleared X2c→X3a +2.9pp; func_calls sawtooth flat. Phase 4.X-full progress: X1 (E-8) / X2 (E-5 full + E-7 partial) / X3a substrate / X3b (this, E-1+E-2+E-3 discharge) — 5 of 9 original stay-C++ exceptions discharged this session arc. X3c (E-6 BlockCanonicalizer migration) next. Per supervisor M-slate dispatch D-1777572112 + Phase 4.X-full ENTRY + X3b dispatch (LEAD: generalist, STRUCT codegen-touching tier per pre-analysis §5).
1 parent 3772abf commit a016809

5 files changed

Lines changed: 59 additions & 22 deletions

File tree

Python/jit/codegen/gen_asm.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,8 +1409,16 @@ void* NativeGenerator::getVectorcallEntry() {
14091409
env_.code_rt->setReifier(func->reifier);
14101410
#endif
14111411

1412-
for (auto& ref : func->env.references()) {
1413-
env_.code_rt->addReference(ref);
1412+
/* X3b: Environment::references() now returns const PhxPtrSet&;
1413+
* range-for replaced with raw-slot iteration. code_rt->addReference
1414+
* accepts PyObject* directly per signature at code_runtime.h:112
1415+
* (X3b §4.4 falsifier verified). */
1416+
const auto& refs = func->env.references();
1417+
for (size_t i = 0; i < phx_ptr_set_capacity(&refs); i++) {
1418+
void *p = phx_ptr_set_at(&refs, i);
1419+
if (p != nullptr) {
1420+
env_.code_rt->addReference(static_cast<PyObject *>(p));
1421+
}
14141422
}
14151423

14161424
lir::LIRGenerator lirgen(GetFunction(), &env_);

Python/jit/hir/hir.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "cinderx/Jit/hir/hir_instr_info_c.h"
99
#include "cinderx/Jit/hir/hir_operand_types_c.h"
1010
#include "cinderx/Jit/hir/typed_argument_c.h"
11+
#include "cinderx/Jit/hir/phx_ptr_set.h" /* X3b Environment::references_ */
12+
#include "cinderx/Jit/hir/phx_threaded_ref.h" /* X3b incref/decref bridges */
1113
#include "cinderx/Jit/threaded_compile.h"
1214

1315
#include <algorithm>
@@ -779,15 +781,20 @@ unsigned long TypedArgument::threadSafeTpFlags() const {
779781
}
780782

781783
Environment::~Environment() {
782-
// Phase 4.A W7d Batch 76: STAY C++ per Q-W7-3 stay-C++ exception
783-
// (ThreadedCompileSerialize RAII + std::unordered_set::clear + delete
784-
// on Register* — all genuinely-can't-port surface). The references_
785-
// teardown calls ThreadedRef destructors which run Py_DECREF inside
786-
// STL clear; porting requires exposing both the serialize guard +
787-
// the ThreadedRef container as C bridges, out of scope for W7d.
788-
// Documented as W7d EXCEPTION in commit body.
784+
/* X3b (Batch 96) E-1+E-2+E-3 DISCHARGE: references_ migrated from
785+
* std::unordered_set<ThreadedRef<>> to PhxPtrSet (X2b void*-keyed
786+
* open-address hash). Teardown: serialize guard (ThreadedCompileSerialize
787+
* stays C++ per Phoenix concurrency-infra class) + iterate raw slots +
788+
* phx_threaded_decref each + phx_ptr_set_destroy. Replaces the prior
789+
* STL-clear-via-~ThreadedRef path. */
789790
ThreadedCompileSerialize guard;
790-
references_.clear();
791+
for (size_t i = 0; i < phx_ptr_set_capacity(&references_); i++) {
792+
void *obj = phx_ptr_set_at(&references_, i);
793+
if (obj != NULL) {
794+
phx_threaded_decref(static_cast<PyObject *>(obj));
795+
}
796+
}
797+
phx_ptr_set_destroy(&references_);
791798
for (size_t i = 0; i < reg_count_; i++) {
792799
delete reg_data_[i];
793800
}
@@ -808,13 +815,18 @@ Register* Environment::addRegister(std::unique_ptr<Register> reg) {
808815
}
809816

810817
PyObject* Environment::addReference(PyObject* obj) {
811-
// Phase 4.A W7d Batch 76: STAY C++ per Q-W7-3 stay-C++ exception.
812-
// ThreadedRef<> + std::unordered_set::emplace are genuinely-can't-port
813-
// (RAII + STL container insertion); porting requires exposing both as
814-
// C bridges, out of scope for W7d. Serialize as we modify the ref-count
815-
// to obj which may be widely accessible. Documented as W7d EXCEPTION.
818+
/* X3b (Batch 96) E-1+E-2+E-3 DISCHARGE: references_ now PhxPtrSet
819+
* (void*-keyed). Dedup semantic preserved via contains-check BEFORE
820+
* phx_threaded_incref (theologian 04:25:09Z watchpoint #1: prevent
821+
* double-incref on duplicate adds; matches prior unordered_set::emplace
822+
* dedup which would discard the new ThreadedRef temporary on dup hit).
823+
* Serialize guard retained for ThreadedRef-class refcount safety. */
816824
ThreadedCompileSerialize guard;
817-
return references_.emplace(ThreadedRef<>::create(obj)).first->get();
825+
if (!phx_ptr_set_contains(&references_, obj)) {
826+
phx_threaded_incref(obj);
827+
phx_ptr_set_insert(&references_, obj);
828+
}
829+
return obj;
818830
}
819831

820832
PyObject* Environment::addReference(Ref<> obj) {
@@ -825,8 +837,11 @@ PyObject* Environment::addReference(Ref<> obj) {
825837
}
826838

827839
const Environment::ReferenceSet& Environment::references() const {
828-
return *reinterpret_cast<const ReferenceSet*>(
829-
hir_c_env_references(const_cast<Environment*>(this)));
840+
/* X3b: ReferenceSet now PhxPtrSet (POD); direct reference return,
841+
* no opaque-blob bridge cast needed. hir_c_env_references at
842+
* hir_instr_c.h:265 still exposes the field address as void* for
843+
* C-side consumers (offset preserved by HirEnvironmentLayoutVerifier). */
844+
return references_;
830845
}
831846

832847
bool usesRuntimeFunc([[maybe_unused]] PyCodeObject* code) {

Python/jit/hir/hir.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "cinderx/Jit/hir/frame_state.h"
99
#include "cinderx/Jit/hir/hir_instr_c.h"
1010
#include "cinderx/Jit/hir/hir_ops.h"
11+
#include "cinderx/Jit/hir/phx_ptr_set.h" /* X3b Environment::references_ migration */
1112
#include "cinderx/Jit/hir/register.h"
1213
#include "cinderx/Jit/hir/type.h"
1314
#include "cinderx/Jit/intrusive_list.h"
@@ -3668,7 +3669,11 @@ class BasicBlock {
36683669

36693670
class Environment {
36703671
public:
3671-
using ReferenceSet = std::unordered_set<ThreadedRef<>>;
3672+
/* X3b: ReferenceSet migrated from std::unordered_set<ThreadedRef<>>
3673+
* to PhxPtrSet (void*-keyed open-address hash). E-1+E-2+E-3 discharge.
3674+
* Lifecycle: addReference does contains-check + phx_threaded_incref + insert
3675+
* (dedup-safe); ~Environment iterates + phx_threaded_decref each + destroys. */
3676+
using ReferenceSet = PhxPtrSet;
36723677

36733678
Environment() = default;
36743679
~Environment();
@@ -3720,7 +3725,9 @@ class Environment {
37203725
Register** reg_data_{nullptr};
37213726
size_t reg_count_{0};
37223727
size_t reg_capacity_{0};
3723-
ReferenceSet references_;
3728+
/* X3b: PhxPtrSet zero-init via aggregate-init (POD struct;
3729+
* matches phx_ptr_set_init(NULL/0/0) semantic). */
3730+
ReferenceSet references_{};
37243731
int next_register_id_{0};
37253732
int next_load_type_attr_cache_{0};
37263733
int next_load_type_method_cache_{0};

Python/jit/hir/hir_instr_c.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,13 @@ typedef struct HirEnvironment {
162162
void **reg_data; /* Register** flat array */
163163
size_t reg_count; /* number of slots (may have NULL gaps) */
164164
size_t reg_capacity; /* allocated capacity */
165-
char references_opaque[56]; /* opaque: std::unordered_set<ThreadedRef<>> */
165+
/* X3b (Batch 96): references_ migrated std::unordered_set<ThreadedRef<>>
166+
* → PhxPtrSet. Field is now 3 size_t (entries/count/capacity) =
167+
* sizeof(PhxPtrSet) = 24 bytes on 64-bit. Layout pinned by
168+
* HirEnvironmentLayoutVerifier static_asserts. */
169+
void *references_entries; /* PhxPtrSet.entries */
170+
size_t references_count; /* PhxPtrSet.count */
171+
size_t references_capacity; /* PhxPtrSet.capacity */
166172
int next_register_id;
167173
int next_load_type_attr_cache;
168174
int next_load_type_method_cache;

Python/jit/hir/hir_instr_c_verify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ struct HirEnvironmentLayoutVerifier {
126126
static_assert(offsetof(HirEnvironment, reg_data) == offsetof(Environment, reg_data_));
127127
static_assert(offsetof(HirEnvironment, reg_count) == offsetof(Environment, reg_count_));
128128
static_assert(offsetof(HirEnvironment, reg_capacity) == offsetof(Environment, reg_capacity_));
129-
static_assert(offsetof(HirEnvironment, references_opaque) == offsetof(Environment, references_));
129+
static_assert(offsetof(HirEnvironment, references_entries) == offsetof(Environment, references_),
130+
"X3b: PhxPtrSet entries field aligns with C++ Environment::references_ start");
130131
static_assert(offsetof(HirEnvironment, next_register_id) == offsetof(Environment, next_register_id_));
131132
static_assert(offsetof(HirEnvironment, next_load_type_attr_cache) == offsetof(Environment, next_load_type_attr_cache_));
132133
static_assert(offsetof(HirEnvironment, next_load_type_method_cache) == offsetof(Environment, next_load_type_method_cache_));

0 commit comments

Comments
 (0)