This is an automated email from the ASF dual-hosted git repository. sunlan pushed a commit to branch GROOVY-11640 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 89b72209f0e34eebeed4fa1e62a67ff38370234c Author: Daniel Sun <sun...@apache.org> AuthorDate: Sat May 24 11:37:44 2025 +0900 GROOVY-11640: GC pause by Metadata GC Threshold for weeks then turned to Full GC --- .../org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java | 6 ++++++ .../java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) 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 58a6dfac5f..e93e423633 100644 --- a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java +++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java @@ -47,6 +47,7 @@ public class CacheableCallSite extends MutableCallSite { private final MethodHandles.Lookup lookup; private volatile SoftReference<MethodHandleWrapper> latestHitMethodHandleWrapperSoftReference = null; private final AtomicLong fallbackCount = new AtomicLong(); + private final AtomicLong fallbackRound = new AtomicLong(); private MethodHandle defaultTarget; private MethodHandle fallbackTarget; private final Map<String, SoftReference<MethodHandleWrapper>> lruCache = @@ -119,6 +120,11 @@ public class CacheableCallSite extends MutableCallSite { public void resetFallbackCount() { fallbackCount.set(0); + fallbackRound.incrementAndGet(); + } + + public AtomicLong getFallbackRound() { + return fallbackRound; } public MethodHandle getDefaultTarget() { 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 606328a1ea..647aff2e27 100644 --- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java +++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java @@ -50,6 +50,8 @@ import java.util.stream.Stream; public class IndyInterface { private static final long INDY_OPTIMIZE_THRESHOLD = SystemUtil.getLongSafe("groovy.indy.optimize.threshold", 10_000L); private static final long INDY_FALLBACK_THRESHOLD = SystemUtil.getLongSafe("groovy.indy.fallback.threshold", 10_000L); + private static final long INDY_FALLBACK_CUTOFF = SystemUtil.getLongSafe("groovy.indy.fallback.cutoff", 1_000L); + /** * flags for method and property calls @@ -327,8 +329,15 @@ public class IndyInterface { } if (mhw.isCanSetTarget() && (callSite.getTarget() != mhw.getTargetMethodHandle()) && (mhw.getLatestHitCount() > INDY_OPTIMIZE_THRESHOLD)) { - callSite.setTarget(mhw.getTargetMethodHandle()); - if (LOG_ENABLED) LOG.info("call site target set, preparing outside invocation"); + if (callSite.getFallbackRound().get() > INDY_FALLBACK_CUTOFF) { + if (callSite.getTarget() != callSite.getDefaultTarget()) { + // reset the call site target to default forever to avoid JIT optimizing and deoptimizing frequently + callSite.setTarget(callSite.getDefaultTarget()); + } + } else { + callSite.setTarget(mhw.getTargetMethodHandle()); + if (LOG_ENABLED) LOG.info("call site target set, preparing outside invocation"); + } mhw.resetLatestHitCount(); }