Package org.apache.groovy.runtime.indy

# Class SwitchPointInvalidator

java.lang.Object
org.apache.groovy.runtime.indy.SwitchPointInvalidator

public final class SwitchPointInvalidator extends Object
Lazily allocates a `SwitchPoint` and retires it on demand.

Call sites install the switch point returned by `getSwitchPoint()` in `guardWithTest` chains. `invalidate()` retires the live switch point so linked sites fall back and re-link; the next `getSwitchPoint()` allocates a fresh one.

Bulk paths (category enter/leave, custom MetaClass events) should prefer `detachLive()` and a single `SwitchPoint.invalidateAll(SwitchPoint[])` over many individual `invalidate()` calls.

There is no permanent failover: stock invalidation is scoped to a single class, so deopt storms from a process-wide SwitchPoint do not apply and a simple replace-on-invalidate model is sufficient.

A process-wide registry tracks every live SwitchPoint so bulk retirement is O(live domains), and is skipped entirely while the registry is empty — e.g. classic-only bytecode never links an indy MOP guard. Registration precedes publication, so an empty (or entry-less) observation proves no guard chain holds a live SwitchPoint that the observer could have needed to retire.

Registry entries hold their invalidator strongly; the invalidator's owner is responsible for retiring the domain when it is discarded (see the reclaim anchor on `ClassInfo`'s class-level domain), which is what removes the entry. A guard chain keeps only the SwitchPoint's internal invoker alive, not the SwitchPoint object, so the registry entry is what keeps a still-installed guard retirable until its domain is explicitly retired.

## Layering

This is the mechanism half of the MOP invalidation subsystem and makes no policy decisions. It has exactly two supported consumers: `ClassInfo`, which owns domain instances (allocation, local invalidate, detach), and `IndyInvalidation`, which owns invalidation width policy, reclaim anchoring and per-Class domain continuity. On its own this class guarantees only the single-domain lifecycle documented above (single-use SwitchPoints; registration precedes publication); guarantees about domain identity across ClassInfo recreation exist only under `IndyInvalidation`'s management. It is not an extension point and may change incompatibly.

Since:
  6.0.0

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `SwitchPointInvalidator()`
  Creates an invalidator with no live SwitchPoint until the first `getSwitchPoint()` call.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `SwitchPoint`
  `detachLive()`
  Atomically detaches the live switch point for bulk `SwitchPoint.invalidateAll(java.lang.invoke.SwitchPoint[])` without invalidating it yet.
  `int`
  `getRetirementCount()`
  Returns how many live switch points have been retired.
  `SwitchPoint`
  `getSwitchPoint()`
  Returns a live switch point to install in a call-site guard chain.
  `void`
  `invalidate()`
  Invalidates the current live switch point (if any) so linked sites re-link.
  `static void`
  `invalidateIfLive(SwitchPoint sp)`
  Invalidates `sp` when non-null and still valid.
  `void`
  `setReclaimAnchor(Object anchor)`
  Parks `anchor` so it stays strongly reachable while this invalidator is reachable.

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Constructor Details

  - ### SwitchPointInvalidator

    public SwitchPointInvalidator()
    Creates an invalidator with no live SwitchPoint until the first `getSwitchPoint()` call. Field initializers own all state.

- ## Method Details

  - ### setReclaimAnchor

    public void setReclaimAnchor(Object anchor)
    Parks `anchor` so it stays strongly reachable while this invalidator is reachable. See `reclaimAnchor`.
    Parameters:
      `anchor` - the object to keep reachable (may be `null` to clear)

  - ### getSwitchPoint

    public SwitchPoint getSwitchPoint()
    Returns a live switch point to install in a call-site guard chain. Lazily allocates on first use after construction or after retirement.
    Returns:
      a live switch point (never `null`)

  - ### invalidate

    public void invalidate()
    Invalidates the current live switch point (if any) so linked sites re-link. A subsequent `getSwitchPoint()` allocates a fresh switch point.

  - ### detachLive

    public SwitchPoint detachLive()
    Atomically detaches the live switch point for bulk `SwitchPoint.invalidateAll(java.lang.invoke.SwitchPoint[])` without invalidating it yet. The caller must invalidate any non-null return value.
    Returns:
      the detached live switch point, or `null` if none was live

  - ### getRetirementCount

    public int getRetirementCount()
    Returns how many live switch points have been retired.
    Returns:
      the retirement count

  - ### invalidateIfLive

    public static void invalidateIfLive(SwitchPoint sp)
    Invalidates `sp` when non-null and still valid.
    Parameters:
      `sp` - candidate switch point (may be `null`)