Class ConcurrentEntryPointPropagator

java.lang.Object
org.ek9lang.compiler.phase5.ConcurrentEntryPointPropagator

final class ConcurrentEntryPointPropagator extends Object
Propagates the CONCURRENT_ENTRY_POINT = "TRUE" squirrelled marker transitively along the call graph (Step 6b, slice 1).

After CallGraphCollector has populated the call graph, this pass starts from every callable already carrying the marker — the direct roots set by:

  • Step 6 — MarkMethodsAsConcurrentEntryPoint applied to service operations.
  • Step 5 — ConcurrentEntryPointMarker applied to TCP/Signals handlers and async stream-stage functions.

It then computes the set of all callables reachable from those roots via outgoing call edges and value references (CallGraph.getReachableIncludingReferences(Set, Function), fail-closed) and sets the marker on each. Constructors and operators are excluded — they're handled by the constructor exemption (E08250 prevents publication-during-construction) and the synthesised-operator path respectively.

Why reachability, not blanket class-level marking: a Component used only from a single-threaded program is not racy. The marker propagates only along ACTUAL call graph edges, so unused or single-threaded components stay unmarked and Step 7's data-race check never fires on them.

A lock's payload is not reached through its lock. A MutexKey body runs under the lock, and E08251 exempts it; so do the methods of its payload's type that it calls (lockedItem.add(...)): they run under the same lock. Propagation does not follow those edges (2026-10-31: once TCP handlers were marked, a correctly locked Room reached Roster.add through its MutexKey body and its field write was E08251). The same method called anywhere else from concurrent code is still reached and checked.

An aspect's advice runs where its component runs. The proxy an application registers calls each aspect's advice around every operation of the component, on the caller's thread; no call site names the advice. So when a method of a component registered with aspect of A() is reached, every method of A is reached with it (review 2026-11-02, H1: an aspect writing its own field compiled clean where the same write in the component was E08251).

Output is consumed by the phase-5 data-race check (E08251, Step 7).