From 0e1efbf1a5211d4344ad5d98ac8a765c024b96ce Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 30 Mar 2023 13:05:10 +0200 Subject: [PATCH] do not intrinsify boxing if box type is uninitialized (GR-44739) --- .../common/spi/JavaConstantFieldProvider.java | 7 ++-- .../compiler/replacements/BoxingSnippets.java | 27 +++++++++------ .../StandardGraphBuilderPlugins.java | 34 +++++++++++++++++-- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java index f7b124816d152..2149108b39e07 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/JavaConstantFieldProvider.java @@ -132,8 +132,11 @@ protected boolean isPrimitiveBoxingCacheField(ResolvedJavaField field) { if (isArray(field) && field.isFinal() && field.getName().equals("cache")) { ResolvedJavaType type = field.getDeclaringClass(); String typeName = type.getName(); - if (typeName.equals("Ljava/lang/Character$CharacterCache;") || typeName.equals("Ljava/lang/Byte$ByteCache;") || typeName.equals("Ljava/lang/Short$ShortCache;") || - typeName.equals("Ljava/lang/Integer$IntegerCache;") || typeName.equals("Ljava/lang/Long$LongCache;")) { + if (typeName.equals("Ljava/lang/Character$CharacterCache;") || + typeName.equals("Ljava/lang/Byte$ByteCache;") || + typeName.equals("Ljava/lang/Short$ShortCache;") || + typeName.equals("Ljava/lang/Integer$IntegerCache;") || + typeName.equals("Ljava/lang/Long$LongCache;")) { return true; } } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java index 93cacbe508bb6..2f78eb03a8271 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java @@ -230,19 +230,24 @@ public Templates(OptionValues options, Group.Factory factory, Providers provider valueCounter = new SnippetCounter(group, "Value", "unbox intrinsification"); } - private static LocationIdentity getCacheLocation(CoreProviders providers, JavaKind kind) { + static Class getCacheClass(JavaKind kind) { Class[] innerClasses = null; - try { - innerClasses = kind.toBoxedJavaClass().getDeclaredClasses(); - if (innerClasses == null || innerClasses.length == 0) { - throw GraalError.shouldNotReachHere("Inner classes must exist"); // ExcludeFromJacocoGeneratedReport + innerClasses = kind.toBoxedJavaClass().getDeclaredClasses(); + for (Class innerClass : innerClasses) { + if (innerClass.getSimpleName().equals(kind.toBoxedJavaClass().getSimpleName() + "Cache")) { + return innerClass; } - for (Class innerClass : innerClasses) { - if (innerClass.getName().endsWith("Cache")) { - return new FieldLocationIdentity(providers.getMetaAccess().lookupJavaField(innerClass.getDeclaredField("cache"))); - } - } - throw GraalError.shouldNotReachHere("No cache inner class found"); // ExcludeFromJacocoGeneratedReport + } + return null; + } + + private static LocationIdentity getCacheLocation(CoreProviders providers, JavaKind kind) { + Class cacheClass = getCacheClass(kind); + if (cacheClass == null) { + throw GraalError.shouldNotReachHere(String.format("Cache class for %s not found", kind)); // ExcludeFromJacocoGeneratedReport + } + try { + return new FieldLocationIdentity(providers.getMetaAccess().lookupJavaField(cacheClass.getDeclaredField("cache"))); } catch (Throwable e) { throw GraalError.shouldNotReachHere(e); // ExcludeFromJacocoGeneratedReport } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index e6cc81e3ca37d..5439cafd59e16 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -33,6 +33,7 @@ import static org.graalvm.compiler.core.common.memory.MemoryOrderMode.RELEASE; import static org.graalvm.compiler.core.common.memory.MemoryOrderMode.VOLATILE; import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION; +import static org.graalvm.compiler.replacements.BoxingSnippets.Templates.getCacheClass; import static org.graalvm.compiler.replacements.nodes.AESNode.CryptMode.DECRYPT; import static org.graalvm.compiler.replacements.nodes.AESNode.CryptMode.ENCRYPT; @@ -41,6 +42,8 @@ import java.lang.reflect.Type; import java.math.BigInteger; import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; import java.util.Objects; import java.util.function.BiFunction; @@ -1310,17 +1313,44 @@ public static class BoxPlugin extends InvocationPlugin { this.kind = kind; } + static final Map> boxClassToCacheClass = new EnumMap<>(Map.of( + JavaKind.Boolean, Boolean.class, + JavaKind.Char, getCacheClass(JavaKind.Char), + JavaKind.Byte, getCacheClass(JavaKind.Byte), + JavaKind.Short, getCacheClass(JavaKind.Short), + JavaKind.Int, getCacheClass(JavaKind.Int), + JavaKind.Long, getCacheClass(JavaKind.Long))); + + private boolean isCacheTypeInitialized(MetaAccessProvider metaAccess) { + Class cacheClass = boxClassToCacheClass.get(kind); + if (cacheClass != null) { + ResolvedJavaType cacheType = metaAccess.lookupJavaType(cacheClass); + if (!cacheType.isInitialized()) { + return false; + } + } + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + MetaAccessProvider metaAccess = b.getMetaAccess(); if (b.parsingIntrinsic()) { ResolvedJavaMethod rootMethod = b.getGraph().method(); - if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { + if (metaAccess.lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { // Disable invocation plugins for boxing snippets so that the // original JDK methods are inlined return false; } } - ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); + ResolvedJavaType resultType = metaAccess.lookupJavaType(kind.toBoxedJavaClass()); + + // Cannot perform boxing if the box type or its cache (if any) is not initialized + // or failed during initialization (e.g. StackOverflowError in LongCache.). + if (!resultType.isInitialized() || !isCacheTypeInitialized(metaAccess)) { + return false; + } + b.addPush(JavaKind.Object, BoxNode.create(value, resultType, kind)); return true; }