# HG changeset patch # User Andreas Woess # Date 1416486132 -3600 # Node ID de179c27cad3b21aaa408ec41f87a3f0c0cee281 # Parent 7b60f8334af0b969bca1f24efbb11f75765310e2 Add support for stable array constants diff -r 7b60f8334af0 -r de179c27cad3 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java --- 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. * diff -r 7b60f8334af0 -r de179c27cad3 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- 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}. diff -r 7b60f8334af0 -r de179c27cad3 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java --- 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; + } } diff -r 7b60f8334af0 -r de179c27cad3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- 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; + } }