Class IndyInvalidation
SwitchPoint invalidation for the Groovy MOP
(GROOVY-12191).
Domain: one SwitchPoint domain per Class, owned by its
ClassInfo and covering every MetaClass generation of that class
(pre-MetaClass link included). The domain outlives the MetaClass
object, so exact-class invalidation still reaches installed guards
after a soft/weak MetaClass has been collected. Monomorphic indy sites
install a single guardWithTest on the class-level domain observed
at link time.
Width policy (two axes only)
- Exact class —
invalidateClass(Class): stockMetaClassImpl/ EMC changes (includingClassInfo.incVersion(), registry replace, per-instance MetaClass). - All loaded — process-wide retire used for category enter/leave
(
invalidateCategory()), unattributed registry events (invalidateUnscoped()), and non-stock custom MetaClass kinds (invalidateBulk()).
MetaClass.invokeMethod / property miss and walks the hierarchy live
from the registry each call. Construction-time snapshots of ancestor expando
methods are pre-existing MOP behaviour and are not refreshed by SwitchPoint
retirement. See also MetaClassImpl.findMethodInClassHierarchy(java.lang.Class, java.lang.String, java.lang.Class[], groovy.lang.MetaClass).
Optional stats: -Dgroovy.indy.invalidation.stats=true.
Production guards: IndyInterface.applyMopSwitchPoints; tests may use
guardWithMopSwitchPoints(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.Object).
Layering
This class is the policy half of a two-level subsystem:SwitchPointInvalidator is the mechanism (one domain's SwitchPoint
lifecycle plus the process-wide live registry) and makes no policy
decisions; this class decides invalidation width, labels the reasons, owns
reclaim anchoring and — when the global ClassValue store reclaims values
(GROOVY-12281 soft mode) — per-Class domain continuity. The only other
supported consumer of the mechanism is ClassInfo, which owns domain
instances and performs the local operations (allocate, invalidate, detach)
directly. No other code should construct or invalidate
SwitchPointInvalidator instances; both classes are internal and may
change incompatibly.- Since:
- 6.0.0
-
Method Summary
Modifier and TypeMethodDescriptionstatic voidanchorClassDomain(ClassInfo owner, SwitchPointInvalidator domain) Anchors a reclaim reference for a ClassInfo-owned class domain: when the ClassInfo (and with it the class) becomes unreachable while the domain still has a live registered SwitchPoint, the reference is delivered by the sharedweak-bundlemanager and the domain is retired — installed guards keep only the SwitchPoint's internal invoker reachable, so retiring the orphan forces straggler sites to re-link, which is always safe.static voidanchorClassDomainToClass(Class<?> owner, SwitchPointInvalidator domain) Anchors a reclaim reference keyed to theClassrather than a ClassInfo instance: soft mode retires a domain only when the class dies (no receiver can reach an installed guard afterwards), because ClassInfo instances are replaceable and their successors adopt the same domain.static longNon-category process-wide bulk event count (invalidateBulk()/invalidateUnscoped()).static longCategory-style bulk invalidation count (invalidateCategory()).static SwitchPointInvalidatorclassDomainFor(Class<?> type, SwitchPointInvalidator candidate) Returns the canonical domain fortype, seeding the per-Class map withcandidateon first touch.static longExact-class invalidation event count (invalidateClass(Class)).static SwitchPointclassSwitchPointFor(Class<?> type) Returns the SwitchPoint for the given class at link time: the current generation of the ClassInfo-owned class domain (defineClass-safe — does not create or consult a MetaClass).static SwitchPointclassSwitchPointFor(Object receiver) Returns the class-level MetaClass SwitchPoint for the given receiver.static voidcollectLiveForClass(Class<?> type, List<SwitchPoint> out) Collects the live SwitchPoint (if any) oftype's class domain.static MethodHandleguardWithMopSwitchPoints(MethodHandle handle, MethodHandle fallback, Class<?> receiverClass) Installs a MetaClass SwitchPoint guard onhandle.static MethodHandleguardWithMopSwitchPoints(MethodHandle handle, MethodHandle fallback, Object receiver) Installs a MetaClass SwitchPoint guard onhandle.static voidProcess-wide bulk retirement for non-stock (custom) MetaClass registry events — correctness-first when selection may consult state outside the stock miss walk.static voidCategory enter/leave andVMPlugin.invalidateCallSites().static voidinvalidateClass(Class<?> type) Retires onlytype's MetaClass SwitchPoint domain (exact class; no subtype fan-out).static voidRegistry-driven invalidation: exact class for stock MetaClass kinds and per-instance changes; process-wide bulk for custom MetaClass kinds or unattributed events.static voidRetires the class domain ofmc's class (if a generation was allocated).static voidProcess-wide bulk retirement when a MetaClass registry event carries noClassattribution.static booleanWhethermcis a stock MOP MetaClass for which exact-class invalidation is sufficient:null, or unwrappedMetaClassImpl(includes EMC and subclasses).static booleanneedsBulkInvalidation(MetaClass oldMc, MetaClass newMc) Whether a class-level MetaClass change involvingoldMc/newMcrequires process-wide bulk invalidation.static voidResets process-wide counters (tests only).static Class<?>switchPointClassFor(Object receiver) Resolves the class used for the MetaClass SwitchPoint domain of a receiver.static SwitchPointReturns the class-domain SwitchPoint for a MetaClass.
-
Method Details
-
anchorClassDomain
Anchors a reclaim reference for a ClassInfo-owned class domain: when the ClassInfo (and with it the class) becomes unreachable while the domain still has a live registered SwitchPoint, the reference is delivered by the sharedweak-bundlemanager and the domain is retired — installed guards keep only the SwitchPoint's internal invoker reachable, so retiring the orphan forces straggler sites to re-link, which is always safe.Reachability: the live-SwitchPoint registry holds the invalidator strongly, and the invalidator holds the reclaim reference, so cleanup stays reachable exactly as long as there is something to clean; once the domain is retired the whole chain becomes collectable.
- Parameters:
owner- the ClassInfo owning the domain (must not benull)domain- the class-level domain (must not benull)
-
classDomainFor
public static SwitchPointInvalidator classDomainFor(Class<?> type, SwitchPointInvalidator candidate) Returns the canonical domain fortype, seeding the per-Class map withcandidateon first touch. Soft-mode only (callers gate).- Parameters:
type- the class whose domain is requested (must not benull)candidate- the caller-owned domain to install if none is mapped yet- Returns:
- the canonical per-Class domain
-
anchorClassDomainToClass
Anchors a reclaim reference keyed to theClassrather than a ClassInfo instance: soft mode retires a domain only when the class dies (no receiver can reach an installed guard afterwards), because ClassInfo instances are replaceable and their successors adopt the same domain.- Parameters:
owner- the class owning the domain (must not benull)domain- the class-level domain (must not benull)
-
invalidateClass
Retires onlytype's MetaClass SwitchPoint domain (exact class; no subtype fan-out). No-op whentypeisnull. Does not bumpClassInfo.getVersion().Used by
ClassInfo.incVersion(), stock registry MetaClass changes, and per-instance MetaClass changes. Non-stock MetaClass kinds useinvalidateBulk()instead.- Parameters:
type- the class whose MetaClass changed
-
invalidateCategory
public static void invalidateCategory()Category enter/leave andVMPlugin.invalidateCallSites(). Retires every loaded class-level domain so sites re-link under the new category state. No separate category SwitchPoint on the hot path. -
invalidateBulk
public static void invalidateBulk()Process-wide bulk retirement for non-stock (custom) MetaClass registry events — correctness-first when selection may consult state outside the stock miss walk. Rare. -
invalidateUnscoped
public static void invalidateUnscoped()Process-wide bulk retirement when a MetaClass registry event carries noClassattribution. -
invalidateForMetaClassChange
Registry-driven invalidation: exact class for stock MetaClass kinds and per-instance changes; process-wide bulk for custom MetaClass kinds or unattributed events. See class javadoc.- Parameters:
event- the registry change event (must not benull)
-
needsBulkInvalidation
Whether a class-level MetaClass change involvingoldMc/newMcrequires process-wide bulk invalidation.Bulk is reserved for non-stock MetaClass kinds: not
MetaClassImplafter adapter unwrap. Stock pairs stay exact-class.- Parameters:
oldMc- previous MetaClass (may benull)newMc- new MetaClass (may benullon remove)- Returns:
trueif bulk invalidation is required
-
isStockMetaClass
Whethermcis a stock MOP MetaClass for which exact-class invalidation is sufficient:null, or unwrappedMetaClassImpl(includes EMC and subclasses). Any other kind is non-stock and triggers bulk invalidation on registry replace.- Parameters:
mc- MetaClass to classify (may benull)- Returns:
trueif exact-class invalidation is sufficient
-
collectLiveForClass
Collects the live SwitchPoint (if any) oftype's class domain. Does not create a MetaClass and does not allocate a domain generation.- Parameters:
type- class to inspect (must not benull)out- destination list
-
switchPointClassFor
Resolves the class used for the MetaClass SwitchPoint domain of a receiver.nullmaps toNullObject; aClassreceiver uses itself.- Parameters:
receiver- the call receiver (may benull)- Returns:
- the class whose class-level MetaClass SwitchPoint guards this site
-
switchPointForMetaClass
Returns the class-domain SwitchPoint for a MetaClass. The domain belongs tothe class, not the MetaClass instance, so every generation (and every adapter wrapping) of a class's MetaClass shares one domain.- Parameters:
mc- MetaClass (must not benull)- Returns:
- the class-domain SwitchPoint
-
invalidateMetaClass
Retires the class domain ofmc's class (if a generation was allocated). Does not bump counters (local domain retire; width policy is separate).- Parameters:
mc- MetaClass (may benull)
-
classSwitchPointFor
Returns the class-level MetaClass SwitchPoint for the given receiver.- Parameters:
receiver- the call receiver (may benull)- Returns:
- the MetaClass-domain switch point
-
classSwitchPointFor
Returns the SwitchPoint for the given class at link time: the current generation of the ClassInfo-owned class domain (defineClass-safe — does not create or consult a MetaClass).- Parameters:
type- the class (must not benull)- Returns:
- the SwitchPoint for monomorphic MOP guards
-
guardWithMopSwitchPoints
public static MethodHandle guardWithMopSwitchPoints(MethodHandle handle, MethodHandle fallback, Object receiver) Installs a MetaClass SwitchPoint guard onhandle. Public entry for tests; production usesIndyInterface.applyMopSwitchPoints.- Parameters:
handle- the fast-path handlefallback- the re-link / fallback handlereceiver- the receiver used to select the MetaClass-domain switch point- Returns:
- the guarded handle
-
guardWithMopSwitchPoints
public static MethodHandle guardWithMopSwitchPoints(MethodHandle handle, MethodHandle fallback, Class<?> receiverClass) Installs a MetaClass SwitchPoint guard onhandle.- Parameters:
handle- the fast-path handlefallback- the re-link / fallback handlereceiverClass- the class whose class-level MetaClass domain guards this site- Returns:
- the guarded handle
-
classInvalidationCount
public static long classInvalidationCount()Exact-class invalidation event count (invalidateClass(Class)).- Returns:
- class invalidation count
-
bulkInvalidationCount
public static long bulkInvalidationCount()Non-category process-wide bulk event count (invalidateBulk()/invalidateUnscoped()).- Returns:
- bulk invalidation count
-
categoryInvalidationCount
public static long categoryInvalidationCount()Category-style bulk invalidation count (invalidateCategory()).- Returns:
- category invalidation count
-
resetCountersForTesting
public static void resetCountersForTesting()Resets process-wide counters (tests only). Does not reset live switch points.
-