changeset 18472:de179c27cad3

Add support for stable array constants
author Andreas Woess <andreas.woess@jku.at>
date Thu, 20 Nov 2014 13:22:12 +0100
parents 7b60f8334af0
children 54b0c8ab4668
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java
diffstat 4 files changed, 126 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Wed Nov 19 17:45:40 2014 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java	Thu Nov 20 13:22:12 2014 +0100
@@ -56,6 +56,13 @@
     JavaConstant readArrayElement(JavaConstant array, int index);
 
     /**
+     * Reads a value from the given array at the given index if it is a stable array. Returns
+     * {@code null} if the constant is not a stable array, if it is a default value, if the index is
+     * out of bounds, or if the value is not available at this point.
+     */
+    JavaConstant readConstantArrayElement(JavaConstant array, int index);
+
+    /**
      * Gets the constant value of this field. Note that a {@code static final} field may not be
      * considered constant if its declaring class is not yet initialized or if it is a well known
      * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}).
@@ -68,10 +75,11 @@
     JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver);
 
     /**
-     * Gets the current value of this field for a given object, if available. There is no guarantee
-     * that the same value will be returned by this method for a field unless the field is
-     * considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) constant} by
-     * the runtime.
+     * Gets the current value of this field for a given object, if available.
+     *
+     * There is no guarantee that the same value will be returned by this method for a field unless
+     * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant)
+     * constant} by the runtime.
      *
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
@@ -81,6 +89,22 @@
     JavaConstant readFieldValue(JavaField field, JavaConstant receiver);
 
     /**
+     * Gets the current value of this field for a given object, if available. Like
+     * {@link #readFieldValue(JavaField, JavaConstant)} but treats array fields as stable.
+     *
+     * There is no guarantee that the same value will be returned by this method for a field unless
+     * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant)
+     * constant} by the runtime.
+     *
+     * @param receiver object from which this field's value is to be read. This value is ignored if
+     *            this field is static.
+     * @param isDefaultStable if {@code true}, default values are considered stable
+     * @return the value of this field or {@code null} if the value is not available (e.g., because
+     *         the field holder is not yet initialized).
+     */
+    JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable);
+
+    /**
      * Reads a value of this kind using a base address and a displacement. No bounds checking or
      * type checking is performed. Returns {@code null} if the value is not available at this point.
      *
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Wed Nov 19 17:45:40 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Thu Nov 20 13:22:12 2014 +0100
@@ -81,6 +81,16 @@
         return Array.getLength(arrayObject);
     }
 
+    public JavaConstant readConstantArrayElement(JavaConstant array, int index) {
+        if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
+            JavaConstant element = readArrayElement(array, index);
+            if (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind()) {
+                return element;
+            }
+        }
+        return null;
+    }
+
     private static long readRawValue(Constant baseConstant, long initialDisplacement, int bits) {
         Object base;
         long displacement;
@@ -227,7 +237,12 @@
         }
 
         if (a instanceof Object[]) {
-            return HotSpotObjectConstantImpl.forObject(((Object[]) a)[index]);
+            Object element = ((Object[]) a)[index];
+            if (((HotSpotObjectConstantImpl) array).getStableDimension() > 1) {
+                return HotSpotObjectConstantImpl.forStableArray(element, ((HotSpotObjectConstantImpl) array).getStableDimension() - 1, ((HotSpotObjectConstantImpl) array).isDefaultStable());
+            } else {
+                return HotSpotObjectConstantImpl.forObject(element);
+            }
         } else {
             return JavaConstant.forBoxedPrimitive(Array.get(a, index));
         }
@@ -334,7 +349,15 @@
 
     public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) {
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
+        if (!hotspotField.isStable()) {
+            return readNonStableFieldValue(field, receiver);
+        } else {
+            return readStableFieldValue(field, receiver, false);
+        }
+    }
 
+    private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) {
+        HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
         if (receiver == null) {
             assert hotspotField.isStatic();
             HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
@@ -349,6 +372,25 @@
         }
     }
 
+    public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
+        JavaConstant fieldValue = readNonStableFieldValue(field, receiver);
+        JavaType declaredType = field.getType();
+        if (declaredType.getComponentType() != null) {
+            int stableDimension = getArrayDimension(declaredType);
+            return HotSpotObjectConstantImpl.forStableArray(((HotSpotObjectConstantImpl) fieldValue).object(), stableDimension, isDefaultStable);
+        }
+        return fieldValue;
+    }
+
+    private static int getArrayDimension(JavaType type) {
+        int dimensions = 0;
+        JavaType componentType = type;
+        while ((componentType = componentType.getComponentType()) != null) {
+            dimensions++;
+        }
+        return dimensions;
+    }
+
     /**
      * Compares two {@link StackTraceElement}s for equality, ignoring differences in
      * {@linkplain StackTraceElement#getLineNumber() line number}.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Wed Nov 19 17:45:40 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Nov 20 13:22:12 2014 +0100
@@ -51,6 +51,15 @@
         }
     }
 
+    public static JavaConstant forStableArray(Object object, int stableDimension, boolean isDefaultStable) {
+        if (object == null) {
+            return JavaConstant.NULL_OBJECT;
+        } else {
+            assert object.getClass().isArray();
+            return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable);
+        }
+    }
+
     public static JavaConstant forBoxedValue(Kind kind, Object value) {
         if (kind == Kind.Object) {
             return HotSpotObjectConstantImpl.forObject(value);
@@ -71,12 +80,23 @@
 
     private final Object object;
     private final boolean compressed;
+    private final byte stableDimension;
+    private final boolean isDefaultStable;
 
-    private HotSpotObjectConstantImpl(Object object, boolean compressed) {
+    private HotSpotObjectConstantImpl(Object object, boolean compressed, int stableDimension, boolean isDefaultStable) {
         super(LIRKind.reference(compressed ? Kind.Int : Kind.Object));
         this.object = object;
         this.compressed = compressed;
+        this.stableDimension = (byte) stableDimension;
+        this.isDefaultStable = isDefaultStable;
         assert object != null;
+        assert stableDimension == 0 || (object != null && object.getClass().isArray());
+        assert stableDimension >= 0 && stableDimension <= 255;
+        assert !isDefaultStable || stableDimension > 0;
+    }
+
+    private HotSpotObjectConstantImpl(Object object, boolean compressed) {
+        this(object, compressed, 0, false);
     }
 
     /**
@@ -107,12 +127,12 @@
 
     public JavaConstant compress() {
         assert !compressed;
-        return new HotSpotObjectConstantImpl(object, true);
+        return new HotSpotObjectConstantImpl(object, true, stableDimension, isDefaultStable);
     }
 
     public JavaConstant uncompress() {
         assert compressed;
-        return new HotSpotObjectConstantImpl(object, false);
+        return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable);
     }
 
     public JavaConstant getClassLoader() {
@@ -236,7 +256,7 @@
             return true;
         } else if (o instanceof HotSpotObjectConstantImpl) {
             HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o;
-            return super.equals(o) && object == other.object && compressed == other.compressed;
+            return super.equals(o) && object == other.object && compressed == other.compressed && stableDimension == other.stableDimension && isDefaultStable == other.isDefaultStable;
         }
         return false;
     }
@@ -254,4 +274,19 @@
     public String toString() {
         return (compressed ? "NarrowOop" : getKind().getJavaName()) + "[" + Kind.Object.format(object) + "]";
     }
+
+    /**
+     * Number of stable dimensions if this constant is a stable array.
+     */
+    public int getStableDimension() {
+        return stableDimension & 0xff;
+    }
+
+    /**
+     * Returns {@code true} if this is a stable array constant and its elements should be considered
+     * as stable regardless of whether they are default values.
+     */
+    public boolean isDefaultStable() {
+        return isDefaultStable;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed Nov 19 17:45:40 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Thu Nov 20 13:22:12 2014 +0100
@@ -24,6 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,7 +35,7 @@
  * The {@code LoadIndexedNode} represents a read from an element of an array.
  */
 @NodeInfo
-public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable {
+public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable, Canonicalizable {
 
     /**
      * Creates a new LoadIndexedNode.
@@ -75,4 +77,17 @@
             }
         }
     }
+
+    public Node canonical(CanonicalizerTool tool) {
+        if (array().isConstant() && !array().isNullConstant() && index().isConstant()) {
+            JavaConstant arrayConstant = array().asJavaConstant();
+            if (arrayConstant != null) {
+                JavaConstant constant = tool.getConstantReflection().readConstantArrayElement(arrayConstant, index().asJavaConstant().asInt());
+                if (constant != null) {
+                    return ConstantNode.forConstant(constant, tool.getMetaAccess());
+                }
+            }
+        }
+        return this;
+    }
 }