Skip to main content

Module effect_trace

Module effect_trace 

Source
Expand description

Ground-truth effect-atom recorder (issue #870, T2 effects epic, docs/effects-spec.md). The effects analogue of the oracle: this module records, per executing definition scope, the atomic effects the VM actually performs — cells read, cells written, external kinds called — so brink-test-harness can assert the statically-inferred effects(def) row (brink-db::ProjectDb::effects) covers every one of them for every def a real run executed. A purely structural inter-row consistency check (caller’s row ⊇ callee’s row) cannot catch an under-report where both rows silently agree on the wrong (too-small) answer — exactly the #866 ref-param-write regression this issue is named for. This is the independent, run-the-bytecode-and-look check that closes that gap.

Attribution mirrors the static analyzer’s own model exactly (brink_analyzer::infer::body::record_ref_param_writes), not naively “whichever def’s bytecode happens to be executing”: a ref argument’s pointer/projection is constructed exactly once, at the call site, inside the caller’s own bytecode (Opcode::PushVarPointer/Opcode:: MakeProjection — both are emitted only there, never for a plain read, confirmed against brink-codegen-inkb’s expr.rs). The eventual dereference deep inside the callee’s frame (SetTemp/GetTemp/ TakeTemp’s pointer/projection arms, ProjRead/ProjWrite) is deliberately not re-recorded — the callee’s own row is generic over whichever concrete cell a caller bound its ref parameter to, so the static model charges the write to the call site that names the concrete global, never to the callee. Recording at construction time reproduces that attribution for free: whichever def’s bytecode is running when the pointer/projection value is built is, by construction, the def the static analyzer also charges. See the call sites in vm.rs’s note_effect_* helpers for the exact opcodes instrumented.

Feature-gated exactly like the bench-counters module (issue #821): this module and every call site are compiled out entirely unless effect-trace is enabled (not part of default — no released consumer should ever turn it on), so an ordinary build pays exactly zero cost.

Structs§

ObservedRow
Atoms observed for one executed definition scope (docs/effects-spec.md §2) — the runtime counterpart of brink_analyzer::EffectRow’s {reads, writes, calls} (this module never constructs an opaque row: every atom the VM performs is concrete).

Functions§

is_tracked_fault
NS-A2 (issue #1108, from #1097): is this error one of the designed domain faults the faults row dimension tracks? The inventory mirrors the static harvest in brink-analyzer::infer::body exactly — every variant listed here must be raisable only by a construct that sets the static faults bit (indexing, //mod, the faulting stdlib intrinsics, conversions, ref projections, value calls), or the ground-truth harness would report a false under-report.
record_call
Record an external-kind call, attributed to def.
record_emit
NS-A2 (issue #1108): record a visible content emission, attributed to def.
record_fault
NS-A2: record a tracked turn-terminating fault, attributed to def (the definition scope executing when vm::step returned the fault).
record_read
Record a cell read, attributed to def (the definition scope executing when the read happened — see the module docs for what “attributed to” means for a pointer/projection-mediated access).
record_tag
NS-A2: record a tag-channel touch, attributed to def.
record_write
Record a cell write, attributed to def.
reset
Clear every recorded atom. Call before each measured run — the recorder is a single process-wide map, so a caller driving multiple programs (or multiple explored episodes of one program) in the same process must reset between the units it wants to compare independently.
snapshot
Snapshot every def’s observed atoms recorded since the last reset.