changeset 9478:fb22b4d5f475

Allow distinction between ClassCastException and ArrayStoreException. Add more canonicalizations for check casts.
author Christian Wimmer <christian.wimmer@oracle.com>
date Wed, 01 May 2013 09:21:35 -0700
parents 3b02fe9e1983
children fd2e12d41d18
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java
diffstat 5 files changed, 59 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed May 01 09:13:34 2013 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed May 01 09:21:35 2013 -0700
@@ -706,7 +706,7 @@
                 if (arrayType != null && array.objectStamp().isExactType()) {
                     ResolvedJavaType elementType = arrayType.getComponentType();
                     if (!MetaUtil.isJavaLangObject(elementType)) {
-                        CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null));
+                        CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null, true));
                         graph.addBeforeFixed(storeIndexed, checkcast);
                         value = checkcast;
                     }
@@ -714,7 +714,7 @@
                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
                     LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
-                    CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value));
+                    CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
                     graph.addBeforeFixed(storeIndexed, checkcast);
                     graph.addBeforeFixed(checkcast, arrayClass);
                     value = checkcast;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 01 09:13:34 2013 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 01 09:21:35 2013 -0700
@@ -803,7 +803,7 @@
         ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck));
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false));
             append(checkCast);
             frameState.apush(checkCast);
         } else {
@@ -1661,7 +1661,7 @@
         if (typeInstruction != null) {
             Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1);
             ValueNode exception = frameState.stackAt(0);
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null));
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false));
             frameState.apop();
             frameState.push(Kind.Object, checkCast);
             FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Wed May 01 09:13:34 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Wed May 01 09:21:35 2013 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,13 +38,27 @@
     @Input private ValueNode type;
 
     /**
+     * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
+     * if false; {@link ArrayStoreException} if true.
+     */
+    private final boolean forStoreCheck;
+
+    /**
      * @param type the type being cast to
      * @param object the instruction producing the object
      */
-    public CheckCastDynamicNode(ValueNode type, ValueNode object) {
+    public CheckCastDynamicNode(ValueNode type, ValueNode object, boolean forStoreCheck) {
         super(object.stamp());
         this.type = type;
         this.object = object;
+        this.forStoreCheck = forStoreCheck;
+        assert type.kind() == Kind.Object;
+        assert type.objectStamp().isExactType();
+        assert type.objectStamp().type().getName().equals("Ljava/lang/Class;");
+    }
+
+    public boolean isForStoreCheck() {
+        return forStoreCheck;
     }
 
     @Override
@@ -67,6 +82,11 @@
         if (object().objectStamp().alwaysNull()) {
             return object();
         }
+        if (type().isConstant()) {
+            Class clazz = (Class) type().asConstant().asObject();
+            ResolvedJavaType t = tool.runtime().lookupJavaType(clazz);
+            return graph().add(new CheckCastNode(t, object(), null, forStoreCheck));
+        }
         return this;
     }
 
@@ -80,4 +100,7 @@
     public ValueNode type() {
         return type;
     }
+
+    @NodeIntrinsic
+    public static native <T> T checkCastDynamic(Class<T> type, Object object, @ConstantNodeParameter boolean forStoreCheck);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed May 01 09:13:34 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed May 01 09:21:35 2013 -0700
@@ -38,17 +38,28 @@
     private final JavaTypeProfile profile;
 
     /**
+     * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
+     * if false; {@link ArrayStoreException} if true.
+     */
+    private final boolean forStoreCheck;
+
+    /**
      * Creates a new CheckCast instruction.
      * 
      * @param type the type being cast to
      * @param object the instruction producing the object
      */
-    public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+    public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
         super(StampFactory.declared(type));
         assert type != null;
         this.type = type;
         this.object = object;
         this.profile = profile;
+        this.forStoreCheck = forStoreCheck;
+    }
+
+    public boolean isForStoreCheck() {
+        return forStoreCheck;
     }
 
     @Override
@@ -68,26 +79,31 @@
     public ValueNode canonical(CanonicalizerTool tool) {
         assert object() != null : this;
 
-        if (type != null) {
-            ResolvedJavaType objectType = object().objectStamp().type();
-            if (objectType != null && type.isAssignableFrom(objectType)) {
-                // we don't have to check for null types here because they will also pass the
-                // checkcast.
+        ResolvedJavaType objectType = object().objectStamp().type();
+        if (objectType != null && type.isAssignableFrom(objectType)) {
+            // we don't have to check for null types here because they will also pass the
+            // checkcast.
+            return object();
+        }
+        // remove checkcast if the only usage is a more specific checkcast
+        if (usages().count() == 1) {
+            CheckCastNode ccn = usages().filter(CheckCastNode.class).first();
+            if (ccn != null && ccn.type() != null && type.isAssignableFrom(ccn.type())) {
                 return object();
             }
-
-            // remove checkcast if the only usage is a more specific checkcast
-            if (usages().count() == 1) {
-                CheckCastNode ccn = usages().filter(CheckCastNode.class).first();
-                if (ccn != null && ccn.type() != null && type.isAssignableFrom(ccn.type())) {
-                    return object();
-                }
-            }
         }
 
         if (object().objectStamp().alwaysNull()) {
             return object();
         }
+        if (tool.assumptions().useOptimisticAssumptions()) {
+            ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
+            if (exactType != null && exactType != type) {
+                // Propagate more precise type information to usages of the checkcast.
+                tool.assumptions().recordConcreteSubtype(type, exactType);
+                return graph().add(new CheckCastNode(exactType, object, profile, forStoreCheck));
+            }
+        }
 
         return this;
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Wed May 01 09:13:34 2013 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Wed May 01 09:21:35 2013 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.replacements.test;
 
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.test.*;
 import com.oracle.graal.nodes.*;
@@ -37,7 +36,7 @@
     protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
         CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
         if (ccn != null) {
-            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile));
+            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile, false));
             graph.replaceFixedWithFixed(ccn, ccnNew);
         }
     }