hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java
changeset 46344 694c102fd8ed
parent 43972 1ade39b8381b
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java	Mon Dec 12 16:16:27 2016 +0300
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraalConstantFieldProvider.java	Wed Mar 22 13:42:45 2017 -0700
@@ -23,8 +23,6 @@
 package org.graalvm.compiler.hotspot.meta;
 
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
-import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.ImmutableCodeLazy.isCalledForSnippets;
-import static org.graalvm.compiler.hotspot.stubs.SnippetStub.SnippetGraphUnderConstruction;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -32,18 +30,13 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.options.StableOptionValue;
-import org.graalvm.compiler.replacements.ReplacementsImpl;
+import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.SnippetCounter;
-import org.graalvm.compiler.replacements.SnippetTemplate;
-import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.runtime.JVMCI;
 
 /**
  * Extends {@link HotSpotConstantFieldProvider} to override the implementation of
@@ -57,25 +50,55 @@
     }
 
     @Override
-    public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) {
-        assert !ImmutableCode.getValue() || isCalledForSnippets(metaAccess) || SnippetGraphUnderConstruction.get() != null ||
-                        FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : tool.getReceiver();
-        if (!field.isStatic() && field.getName().equals("value")) {
-            if (getStableOptionValueType().isInstance(tool.getReceiver())) {
-                JavaConstant ret = tool.readValue();
-                return tool.foldConstant(ret);
-            }
-        }
-
-        return super.readConstantField(field, tool);
+    protected boolean isStaticFieldConstant(ResolvedJavaField field, OptionValues options) {
+        return super.isStaticFieldConstant(field, options) && (!ImmutableCode.getValue(options) || isEmbeddableField(field));
     }
 
     /**
-     * In AOT mode, some fields should never be embedded even for snippets/replacements.
+     * The set of fields whose values cannot be constant folded in ImmutableCode mode. This is
+     * volatile to support double-checked locking lazy initialization.
      */
-    @Override
-    protected boolean isStaticFieldConstant(ResolvedJavaField field) {
-        return super.isStaticFieldConstant(field) && (!ImmutableCode.getValue() || ImmutableCodeLazy.isEmbeddable(field));
+    private volatile List<ResolvedJavaField> nonEmbeddableFields;
+
+    protected boolean isEmbeddableField(ResolvedJavaField field) {
+        if (nonEmbeddableFields == null) {
+            synchronized (this) {
+                if (nonEmbeddableFields == null) {
+                    List<ResolvedJavaField> fields = new ArrayList<>();
+                    try {
+                        fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE")));
+                        fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE")));
+
+                        Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
+                        assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName());
+                        fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache")));
+
+                        Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
+                        assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName());
+                        fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache")));
+
+                        Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0];
+                        assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName());
+                        fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache")));
+
+                        Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0];
+                        assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName());
+                        fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache")));
+
+                        Class<?> longCacheClass = Long.class.getDeclaredClasses()[0];
+                        assert "java.lang.Long$LongCache".equals(longCacheClass.getName());
+                        fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache")));
+
+                        fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK")));
+                        fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL")));
+                    } catch (SecurityException | NoSuchFieldException e) {
+                        throw new GraalError(e);
+                    }
+                    nonEmbeddableFields = fields;
+                }
+            }
+        }
+        return !nonEmbeddableFields.contains(field);
     }
 
     @Override
@@ -112,18 +135,10 @@
 
     private final MetaAccessProvider metaAccess;
 
-    private ResolvedJavaType cachedStableOptionValueType;
     private ResolvedJavaType cachedHotSpotVMConfigType;
     private ResolvedJavaType cachedSnippetCounterType;
     private ResolvedJavaType cachedNodeClassType;
 
-    private ResolvedJavaType getStableOptionValueType() {
-        if (cachedStableOptionValueType == null) {
-            cachedStableOptionValueType = metaAccess.lookupJavaType(StableOptionValue.class);
-        }
-        return cachedStableOptionValueType;
-    }
-
     private ResolvedJavaType getHotSpotVMConfigType() {
         if (cachedHotSpotVMConfigType == null) {
             cachedHotSpotVMConfigType = metaAccess.lookupJavaType(GraalHotSpotVMConfig.class);
@@ -144,102 +159,4 @@
         }
         return cachedNodeClassType;
     }
-
-    @SuppressWarnings("all")
-    private static boolean assertionsEnabled() {
-        boolean enabled = false;
-        assert enabled = true;
-        return enabled;
-    }
-
-    public static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = assertionsEnabled() ? new ThreadLocal<>() : null;
-
-    /**
-     * Compares two {@link StackTraceElement}s for equality, ignoring differences in
-     * {@linkplain StackTraceElement#getLineNumber() line number}.
-     */
-    private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) {
-        return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName());
-    }
-
-    /**
-     * Separate out the static initialization of {@linkplain #isEmbeddable(ResolvedJavaField)
-     * embeddable fields} to eliminate cycles between clinit and other locks that could lead to
-     * deadlock. Static code that doesn't call back into type or field machinery is probably ok but
-     * anything else should be made lazy.
-     */
-    static class ImmutableCodeLazy {
-
-        /**
-         * If the compiler is configured for AOT mode, {@link #readConstantField} should be only
-         * called for snippets or replacements.
-         */
-        static boolean isCalledForSnippets(MetaAccessProvider metaAccess) {
-            assert ImmutableCode.getValue();
-            ResolvedJavaMethod makeGraphMethod = null;
-            ResolvedJavaMethod initMethod = null;
-            try {
-                Class<?> rjm = ResolvedJavaMethod.class;
-                makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm));
-                initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
-            } catch (NoSuchMethodException | SecurityException e) {
-                throw new GraalError(e);
-            }
-            StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0);
-            StackTraceElement initSTE = initMethod.asStackTraceElement(0);
-
-            StackTraceElement[] stackTrace = new Exception().getStackTrace();
-            for (StackTraceElement element : stackTrace) {
-                // Ignoring line numbers should not weaken this check too much while at
-                // the same time making it more robust against source code changes
-                if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Determine if it's ok to embed the value of {@code field}.
-         */
-        static boolean isEmbeddable(ResolvedJavaField field) {
-            assert ImmutableCode.getValue();
-            return !embeddableFields.contains(field);
-        }
-
-        private static final List<ResolvedJavaField> embeddableFields = new ArrayList<>();
-        static {
-            try {
-                MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
-                embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE")));
-                embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE")));
-
-                Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
-                assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName());
-                embeddableFields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache")));
-
-                Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
-                assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName());
-                embeddableFields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache")));
-
-                Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0];
-                assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName());
-                embeddableFields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache")));
-
-                Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0];
-                assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName());
-                embeddableFields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache")));
-
-                Class<?> longCacheClass = Long.class.getDeclaredClasses()[0];
-                assert "java.lang.Long$LongCache".equals(longCacheClass.getName());
-                embeddableFields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache")));
-
-                embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK")));
-                embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL")));
-            } catch (SecurityException | NoSuchFieldException e) {
-                throw new GraalError(e);
-            }
-        }
-    }
-
 }