This is an automated email from the ASF dual-hosted git repository. blackdrag pushed a commit to branch feature/Cache_changes in repository https://gitbox.apache.org/repos/asf/groovy.git
commit b48a20670be45316886edd564428e3f33e9ee9a9 Author: Jochen Theodorou <[email protected]> AuthorDate: Wed May 20 11:05:07 2026 +0200 GROOVY-12023: adding documentation created by AI --- ARCHITECTURE.md | 20 +++++++++++++++++ .../groovy/vmplugin/v8/CacheableCallSite.java | 25 +++++++++++++++++++++- .../codehaus/groovy/vmplugin/v8/IndyInterface.java | 19 ++++++++++++---- .../codehaus/groovy/vmplugin/v8/package-info.java | 10 ++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a6534b926a..4fea015398 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -90,6 +90,26 @@ The phase enum is the right anchor for any documentation that talks about "when X happens during compilation". Quoting the phase names verbatim keeps the reference precise; paraphrasing tends to drift. +## Runtime: invokedynamic (Indy) + +Since Groovy 2.0, dynamic method dispatch can be performed using the `invokedynamic` +instruction. The core of this implementation lives in `org.codehaus.groovy.vmplugin.v8`. + +| Class | Role | +|---|---| +| `IndyInterface` | Bootstrap methods and optimization lifecycle management. | +| `CacheableCallSite` | The stateful call site holding the PIC chain, MRU entry, and LRU cache. | +| `Selector` | Logic for finding the target method/property and constructing the guarded `MethodHandle`. | +| `MethodHandleWrapper` | Combines a `MethodHandle` with metadata like hit counts and target description. | + +### Caching Hierarchy +To maximize performance, `CacheableCallSite` uses three levels of caching: +1. **PIC Chain (Level 1)**: A bounded chain of guarded handles in the call-site target (JIT-optimized). +2. **MRU Entry (Level 2)**: A lock-free volatile field for the most recent hit shape. +3. **LRU Cache (Level 3)**: A synchronized, soft-referenced map for megamorphic fallback. + +Detailed technical documentation of this hierarchy can be found in the Javadoc of `CacheableCallSite`. + ### Parser (phase 2) - Grammar lives in `src/antlr/GroovyLexer.g4` and diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java index 87ba5573f1..bd8309b5c1 100644 --- a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java +++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java @@ -37,7 +37,30 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * Represents a cacheable call site, which can reduce the cost of resolving methods + * Represents a cacheable call site, which manages a multi-level caching hierarchy for dynamic method dispatch. + * <p> + * To minimize the overhead of dynamic method selection and invocation, this class maintains three levels of caching: + * <ol> + * <li><b>Level 1: Polymorphic Inline Cache (PIC) Chain</b>: + * A site-local, bounded chain of guarded method handles (default size 4) stored directly in the {@link #getTarget() target}. + * This is the fastest path, allowing the JVM's JIT compiler to inline calls for the hottest receiver shapes. + * It is managed via {@link #getPicChain()} and updated by {@code IndyInterface.optimizeCallSite}. + * </li> + * <li><b>Level 2: Most Recently Used (MRU) Entry</b>: + * A {@code volatile} field {@link #mruEntry} that stores a single {@link MethodHandleWrapper} for the most recently successful hit. + * Accessed via {@link #get(Object)}, it provides a lock-free path for monomorphic or low-polymorphic call sites + * that fall through the PIC chain. It uses identity-based keys to avoid allocations. + * </li> + * <li><b>Level 3: Least Recently Used (LRU) Cache</b>: + * A synchronized {@link LinkedHashMap} {@link #lruCache} (default size 8) that stores {@link SoftReference}s to + * {@link MethodHandleWrapper}s. This serves as the megamorphic fallback, preventing full re-selection + * for shapes that have been seen before but are not currently in the PIC or MRU. + * </li> + * </ol> + * <p> + * <b>Leak-Awareness:</b> To prevent permanent ClassLoader leaks, Level 2 (MRU) uses strong references only when + * the target class belongs to a safe ClassLoader (same or parent). Level 3 (LRU) always uses {@link SoftReference}s + * to allow the JVM to reclaim Metaspace under memory pressure. * * @since 3.0.0 */ diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java index 6943533faa..bb952b1036 100644 --- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java +++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java @@ -40,10 +40,21 @@ import java.util.stream.Stream; /** * Bytecode level interface for bootstrap methods used by invokedynamic. - * This class provides a logging ability by using the boolean system property - * groovy.indy.logging. Other than that this class contains the - * interfacing methods with bytecode for invokedynamic as well as some helper - * methods and classes. + * <p> + * This class provides the core logic for the {@code invokedynamic} (Indy) support in Groovy. + * It handles the bootstrap process, method selection via {@link Selector}, and the + * optimization lifecycle of {@link CacheableCallSite}. + * <p> + * <b>Optimization Lifecycle:</b> + * <ol> + * <li><b>Bootstrap:</b> The JVM calls one of the bootstrap methods (e.g., {@code bootstrap}) when an {@code invokedynamic} instruction is first encountered.</li> + * <li><b>Initial Linkage:</b> The call site is initialized with a fallback target (adapter pointing to {@link #fromCacheHandle}).</li> + * <li><b>Execution & Selection:</b> On first execution, {@code fromCacheHandle} uses a {@link Selector} to find the target method and create a guarded {@link java.lang.invoke.MethodHandle}.</li> + * <li><b>Promotion & PIC:</b> After reaching {@link #INDY_OPTIMIZE_THRESHOLD} hits for a stable shape, {@link #optimizeCallSite} promotes the handle into a + * Polymorphic Inline Cache (PIC) chain directly in the call site target for maximum JIT optimization.</li> + * </ol> + * <p> + * Logging can be enabled using the system property {@code groovy.indy.logging=true}. */ public class IndyInterface { private static final long INDY_OPTIMIZE_THRESHOLD = SystemUtil.getLongSafe("groovy.indy.optimize.threshold", 1_000L); diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/package-info.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/package-info.java index e2ade9541b..5c78d5a160 100644 --- a/src/main/java/org/codehaus/groovy/vmplugin/v8/package-info.java +++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/package-info.java @@ -18,6 +18,14 @@ */ /** - * Java 8 VM plugin. Compatibility layer for Java 8 features (lambdas, streams). + * Java 8 VM plugin. Compatibility layer for Java 8 features and core implementation of {@code invokedynamic} (Indy) support. + * <p> + * This package contains the runtime infrastructure for Groovy's dynamic method dispatch using the {@code invokedynamic} + * instruction. Key components include: + * <ul> + * <li>{@link org.codehaus.groovy.vmplugin.v8.IndyInterface}: The entry point for bootstrap methods and call-site optimization logic.</li> + * <li>{@link org.codehaus.groovy.vmplugin.v8.CacheableCallSite}: Manages the multi-level caching hierarchy (PIC, MRU, LRU) to minimize dispatch overhead.</li> + * <li>{@link org.codehaus.groovy.vmplugin.v8.Selector}: Responsible for dynamic method selection, handle creation, and guard generation.</li> + * </ul> */ package org.codehaus.groovy.vmplugin.v8;
