Class ResolutionMemo

java.lang.Object
org.ek9lang.compiler.symbols.ResolutionMemo
All Implemented Interfaces:
Serializable

public final class ResolutionMemo extends Object implements Serializable
Program-wide state for the per-phase symbol-resolution memo.

The memo lets a ModuleScope answer a resolution WITHOUT taking the global SharedThreadContext lock. Measured motivation: workers spend 90-94% of the front-end phases BLOCKED on that lock, and roughly half its cost is not the critical section at all but the handoff - waking a parked thread (SCALE-LAB-NOTEBOOK.md F29).

Only NEGATIVE results are memoised. A positive result would hand out a cached ISymbol reference, and symbols are plain mutable objects that later phases still populate; caching one widens the window in which a reader can observe a partially-built symbol. Negatives carry no such reference, so the only question is whether "absent" is still true - which is exactly what the generation counter answers. Negatives are also the bulk of the traffic: most resolutions fail (F30).

How a negative stays sound. Each module NAME has a generation counter, incremented whenever a symbol or reference is defined into a scope of that name. A negative entry records the generation of the scope its answer depended on, sampled before the locked lookup. A later reader discards the entry if that generation has moved. So:

  • in a phase that defines nothing into the scope, negatives stay valid for the whole phase;
  • in a phase that defines, they are invalidated the instant something could change the answer, degrading gracefully to no caching at all.

Sample the generation BEFORE the lookup, never after. Read it after and a define that lands during the lookup yields an entry tagged with a generation newer than the answer it holds - a stale negative that later readers would trust.

One instance per CompilableProgram, so concurrent compiles (the test suite runs many) cannot see each other's entries. Never static.

See Also:
  • Field Details

    • IMPLICIT_SCOPES

      public static final String IMPLICIT_SCOPES
      The scope key standing for the implicitly imported modules searched by every module (org.ek9.lang, org.ek9.math). A define into either bumps this too.
      See Also:
  • Constructor Details

    • ResolutionMemo

      public ResolutionMemo()
  • Method Details

    • statsEnabled

      public static boolean statsEnabled()
    • countHit

      public void countHit()
    • countMiss

      public void countMiss()
    • countStale

      public void countStale()
    • countNotMemoisable

      public void countNotMemoisable()
    • countFound

      public void countFound()
    • stats

      public String stats()
      Hit rate over the calls the memo was actually eligible to answer.
    • defined

      public void defined(String moduleName)
      Record that something was defined into a scope of this module name, invalidating any negative that was answered from it.
    • generation

      public long generation(String scopeKey)
      The current generation of a scope. Sample this BEFORE the locked lookup whose result you intend to memoise.
    • isActive

      public boolean isActive()
    • setActive

      public void setActive(boolean active)
      Enable or disable the memo. Callers clear their per-scope entries when this changes, because a negative recorded in one phase says nothing about the next.