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 85ec6d6920be..4c34416a1483 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 @@ -24,6 +24,8 @@ */ package org.graalvm.compiler.core.common.spi; +import java.lang.annotation.Annotation; + import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -42,6 +44,9 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider static class Options { @Option(help = "Determines whether to treat final fields with default values as constant.")// public static final OptionKey TrustFinalDefaultFields = new OptionKey<>(true); + + @Option(help = "Determines whether to treat scala companion objects as stable values.")// + public static final OptionKey ConsiderScalaCompanionObjectsStable = new OptionKey<>(false); } protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) { @@ -98,7 +103,6 @@ protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstan return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(tool.getOptions()); } - @SuppressWarnings("unused") protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool) { if (isSyntheticEnumSwitchMap(field)) { return true; @@ -109,9 +113,37 @@ protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool to if (field.equals(stringHashField)) { return true; } + if (Options.ConsiderScalaCompanionObjectsStable.getValue(tool.getOptions()) && + isScalaCompanionObjectField(field)) { + return true; + } return false; } + private static boolean isScalaCompanionObjectField(ResolvedJavaField field) { + ResolvedJavaType declaringClass = field.getDeclaringClass(); + String declaringClassName = declaringClass.toClassName(); + if (declaringClass.isInitialized() && field.getName().equals("MODULE$") && declaringClassName.endsWith("$")) { + try { + String companionInstanceClassName = declaringClassName.substring(0, declaringClassName.length() - 1); + Class companionInstanceClass = ClassLoader.getSystemClassLoader().loadClass(companionInstanceClassName); + return isScalaClass(companionInstanceClass); + } catch (ClassNotFoundException e) { + return false; + } + } + return false; + } + + private static boolean isScalaClass(Class cls) { + for (Annotation annotation : cls.getAnnotations()) { + if (annotation.annotationType().getName().equals("scala.reflect.ScalaSignature")) { + return true; + } + } + return (cls.getEnclosingClass() != null) ? isScalaClass(cls.getEnclosingClass()) : false; + } + protected boolean isDefaultStableField(ResolvedJavaField field, ConstantFieldTool tool) { assert isStableField(field, tool); if (isSyntheticEnumSwitchMap(field)) {