diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/DelegatingReplacements.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/DelegatingReplacements.java index 8ea62aa73eb9..a23853a23085 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/DelegatingReplacements.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/DelegatingReplacements.java @@ -25,6 +25,7 @@ package jdk.graal.compiler.nodes.spi; import java.util.BitSet; +import java.util.Map; import jdk.graal.compiler.api.replacements.SnippetTemplateCache; import jdk.graal.compiler.bytecode.BytecodeProvider; @@ -38,6 +39,7 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.replacements.SnippetTemplate; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -137,4 +139,9 @@ public T getSnippetTemplateCache(Class templ public JavaKind getWordKind() { return delegate.getWordKind(); } + + @Override + public Map getTemplatesCache() { + return delegate.getTemplatesCache(); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/Replacements.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/Replacements.java index f5330aabc983..f049772ebc5a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/Replacements.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/Replacements.java @@ -25,6 +25,7 @@ package jdk.graal.compiler.nodes.spi; import java.util.BitSet; +import java.util.Map; import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.api.replacements.SnippetTemplateCache; @@ -39,6 +40,7 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.replacements.SnippetTemplate; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -55,6 +57,12 @@ public interface Replacements extends GeneratedPluginInjectionProvider { */ GraphBuilderConfiguration.Plugins getGraphBuilderPlugins(); + /** + * Least recently used cache for snippet templates. When a new element is added to this map, it + * evicts the least recently used element in case of full capacity. + */ + Map getTemplatesCache(); + /** * Gets the plugin type that intrinsifies calls to {@code method}. */ diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/ReplacementsImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/ReplacementsImpl.java index 8a50aac59c22..1ad7b05abc14 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/ReplacementsImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/ReplacementsImpl.java @@ -33,6 +33,8 @@ import static jdk.graal.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; import java.util.BitSet; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -111,6 +113,12 @@ public void setProviders(Providers providers) { public final TargetDescription target; protected GraphBuilderConfiguration.Plugins graphBuilderPlugins; private final DebugHandlersFactory debugHandlersFactory; + private final Map templatesCache; + + @Override + public Map getTemplatesCache() { + return templatesCache; + } /** * The preprocessed replacement graphs. This is keyed by a pair of a method and options because @@ -242,6 +250,7 @@ public ReplacementsImpl(DebugHandlersFactory debugHandlersFactory, Providers pro this.snippetTemplateCache = EconomicMap.create(Equivalence.DEFAULT); this.defaultBytecodeProvider = bytecodeProvider; this.debugHandlersFactory = debugHandlersFactory; + this.templatesCache = Collections.synchronizedMap(new SnippetTemplate.LRUCache<>()); } private static final TimerKey SnippetPreparationTime = DebugContext.timer("SnippetPreparationTime"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java index 7f3a60b24557..c58e80daa050 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java @@ -45,7 +45,6 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; @@ -799,7 +798,7 @@ public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider cons } } - static class CacheKey { + public static class CacheKey { private final ResolvedJavaMethod method; private final Object[] values; @@ -857,9 +856,6 @@ public int hashCode() { public static class Options { @Option(help = "Use a LRU cache for snippet templates.")// public static final OptionKey UseSnippetTemplateCache = new OptionKey<>(true); - - @Option(help = "")// - public static final OptionKey MaxTemplatesPerSnippet = new OptionKey<>(50); } /** @@ -869,7 +865,6 @@ public abstract static class AbstractTemplates implements SnippetTemplateCache { protected final OptionValues options; protected final SnippetReflectionProvider snippetReflection; - private final Map templates; private final boolean shouldTrackNodeSourcePosition; @@ -877,12 +872,6 @@ protected AbstractTemplates(OptionValues options, Providers providers) { this.options = options; this.snippetReflection = providers.getSnippetReflection(); this.shouldTrackNodeSourcePosition = providers.getCodeCache() != null && providers.getCodeCache().shouldDebugNonSafepoints(); - if (Options.UseSnippetTemplateCache.getValue(options)) { - int size = Options.MaxTemplatesPerSnippet.getValue(options); - this.templates = Collections.synchronizedMap(new LRUCache<>(size, size)); - } else { - this.templates = null; - } } public static ResolvedJavaMethod findMethod(MetaAccessProvider metaAccess, Class declaringClass, String methodName) { @@ -981,7 +970,7 @@ protected SnippetInfo snippet(Providers providers, public SnippetTemplate template(CoreProviders context, ValueNode replacee, final Arguments args) { StructuredGraph graph = replacee.graph(); DebugContext outer = graph.getDebug(); - SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? templates.get(args.cacheKey) : null; + SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? context.getReplacements().getTemplatesCache().get(args.cacheKey) : null; if (template == null || (graph.trackNodeSourcePosition() && !template.snippet.trackNodeSourcePosition())) { try (DebugContext debug = context.getReplacements().openSnippetDebugContext("SnippetTemplate_", args.cacheKey.method, outer, options)) { try (DebugCloseable a = SnippetTemplateCreationTime.start(outer); @@ -1002,7 +991,7 @@ public SnippetTemplate template(CoreProviders context, ValueNode replacee, final createMidTierPreLoweringPhases(), createMidTierPostLoweringPhases()); if (Options.UseSnippetTemplateCache.getValue(snippetOptions) && args.cacheable) { - templates.put(args.cacheKey, template); + context.getReplacements().getTemplatesCache().put(args.cacheKey, template); } if (outer.areMetricsEnabled()) { DebugContext.counter("SnippetTemplateNodeCount[%#s]", args).add(outer, template.nodes.size()); @@ -1037,11 +1026,21 @@ protected PhaseSuite createMidTierPostLoweringPhases() { public static final class LRUCache extends LinkedHashMap { private static final long serialVersionUID = 1L; + + /** + * Maximum capacity of the least-recently used snippet template cache. A higher number + * increases the total amount of memory used for snippet templates and a lower number + * increases the cache misses and thus decreases compilation speed. At a value of 64, the + * estimated misses are at 2% of lookups, at 80, they are at 1% of lookups, and at 100, they + * are at 0.5% of lookups. + */ + public static final int SNIPPET_CACHE_CAPACITY = 64; + private final int maxCacheSize; - public LRUCache(int initialCapacity, int maxCacheSize) { - super(initialCapacity, 0.75F, true); - this.maxCacheSize = maxCacheSize; + public LRUCache() { + super(SNIPPET_CACHE_CAPACITY, 0.75F, true); + this.maxCacheSize = SNIPPET_CACHE_CAPACITY; } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java index a9fb15beecdd..814e2ee991b8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java @@ -285,12 +285,11 @@ static final class HashMapBuiltin extends Builtin { HashMapBuiltin() { super(HashMap.class, IdentityHashMap.class, LinkedHashMap.class, SnippetTemplate.LRUCache.class); - int size = SnippetTemplate.Options.MaxTemplatesPerSnippet.getDefaultValue(); factories = Map.of( HashMap.class, HashMap::new, IdentityHashMap.class, IdentityHashMap::new, LinkedHashMap.class, LinkedHashMap::new, - SnippetTemplate.LRUCache.class, () -> new SnippetTemplate.LRUCache<>(size, size)); + SnippetTemplate.LRUCache.class, SnippetTemplate.LRUCache::new); } @Override diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java index 1595317f6512..95e8ab88a67d 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java index 2a73e1987aea..378901aba9d7 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java index bbed7e6eecda..ff51cb803ef8 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java index aa924d34adbb..95047107f205 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0