changeset 5469:7a0d58000ae0

checkcasts against restricted primary types no longer use hints added checkcast snippet for a test against an exact (i.e. effectively final and unique) type
author Doug Simon <doug.simon@oracle.com>
date Fri, 01 Jun 2012 16:29:04 +0200
parents 08620ddf859c
children fa979ebe0186
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java
diffstat 1 files changed, 83 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Jun 01 16:25:01 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Jun 01 16:29:04 2012 +0200
@@ -59,10 +59,44 @@
 public class CheckCastSnippets implements SnippetsInterface {
 
     /**
-     * Type test used when the type being tested against is a restricted primary type.
+     * Type test used when the type being tested against is a final type.
      */
     @Snippet
-    public static Object checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset) {
+    public static Object checkcastExact(Object object, Object exactHub, boolean checkNull) {
+        if (checkNull && object == null) {
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
+        if (objectHub != exactHub) {
+            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        }
+        return object;
+    }
+
+    /**
+     * Type test used when the type being tested against is a restricted primary type.
+     *
+     * This test ignores use of hints altogether as the display-based type check only
+     * involves one extra load where the second load should hit the same cache line as the
+     * first.
+     */
+    @Snippet
+    public static Object checkcastPrimary(Object hub, Object object, boolean checkNull, int superCheckOffset) {
+        if (checkNull && object == null) {
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
+        if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) {
+            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        }
+        return object;
+    }
+
+    /**
+     * Type test used when the type being tested against is a restricted secondary type.
+     */
+    @Snippet
+    public static Object checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean checkNull) {
         if (checkNull && object == null) {
             return object;
         }
@@ -75,21 +109,18 @@
                 return object;
             }
         }
-        if (hintsAreExact) {
+        if (!checkSecondarySubType(hub, objectHub)) {
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-        } else {
-            if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) {
-                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-            }
         }
         return object;
     }
 
     /**
-     * Type test used when the type being tested against is a restricted secondary type.
+     * Type test used when the type being tested against is not known at compile time (e.g. the type test
+     * in an object array store check).
      */
     @Snippet
-    public static Object checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) {
+    public static Object checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean checkNull) {
         if (checkNull && object == null) {
             return object;
         }
@@ -102,40 +133,8 @@
                 return object;
             }
         }
-        if (hintsAreExact) {
+        if (!checkUnknownSubType(hub, objectHub)) {
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-        } else {
-            if (!checkSecondarySubType(hub, objectHub)) {
-                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-            }
-        }
-        return object;
-    }
-
-    /**
-     * Type test used when the type being tested against is not known at compile time (e.g. the type test
-     * in an object array store check).
-     */
-    @Snippet
-    public static Object checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) {
-        if (checkNull && object == null) {
-            return object;
-        }
-        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
-        // if we get an exact match: succeed immediately
-        ExplodeLoopNode.explodeLoop();
-        for (int i = 0; i < hintHubs.length; i++) {
-            Object hintHub = hintHubs[i];
-            if (hintHub == objectHub) {
-                return object;
-            }
-        }
-        if (hintsAreExact) {
-            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-        } else {
-            if (!checkUnknownSubType(hub, objectHub)) {
-                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-            }
         }
         return object;
     }
@@ -206,7 +205,7 @@
     public enum Counter {
         hintsHit("hit a hint type"),
         hintsMissed("missed the hint types"),
-        exact("tested type is (statically) final"),
+        exactType("tested type is (statically) final"),
         noHints("profile information is not used"),
         isNull("object tested is null"),
         exception("type test failed with a ClassCastException");
@@ -267,7 +266,7 @@
                 Object hintHub = hintHubs[i];
                 if (hintHub == objectHub) {
                     if (hintsAreExact) {
-                        exact.inc();
+                        exactType.inc();
                     } else {
                         hintsHit.inc();
                     }
@@ -381,19 +380,21 @@
     public static class Templates {
 
         private final ConcurrentHashMap<Integer, SnippetTemplate> templates;
-        private final RiResolvedMethod counters;
+        private final RiResolvedMethod exact;
         private final RiResolvedMethod primary;
         private final RiResolvedMethod secondary;
         private final RiResolvedMethod unknown;
+        private final RiResolvedMethod counters;
         private final RiRuntime runtime;
 
         public Templates(RiRuntime runtime) {
             this.runtime = runtime;
             this.templates = new ConcurrentHashMap<>();
             try {
-                primary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, Object[].class, boolean.class, boolean.class, int.class));
-                secondary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class, boolean.class));
-                unknown = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class, boolean.class));
+                exact = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastExact", Object.class, Object.class, boolean.class));
+                primary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, boolean.class, int.class));
+                secondary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class));
+                unknown = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class));
                 counters = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastCounters", Object.class, Object.class, Object[].class, boolean.class));
             } catch (NoSuchMethodException e) {
                 throw new GraalInternalError(e);
@@ -428,6 +429,14 @@
             return result;
         }
 
+        private static HotSpotKlassOop[] createHintHubs(TypeCheckHints hints) {
+            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
+            for (int i = 0; i < hintHubs.length; i++) {
+                hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
+            }
+            return hintHubs;
+        }
+
         /**
          * Lowers a checkcast node.
          */
@@ -436,16 +445,13 @@
             ValueNode hub = checkcast.targetClassInstruction();
             ValueNode object = checkcast.object();
             TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
-            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
-            for (int i = 0; i < hintHubs.length; i++) {
-                hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
-            }
             Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
 
             final HotSpotTypeResolvedImpl target = (HotSpotTypeResolvedImpl) checkcast.targetClass();
-            int flags = EXACT_HINTS.bit(hints.exact) | CHECK_NULL.bit(!object.stamp().nonNull());
+            int flags = CHECK_NULL.bit(!object.stamp().nonNull());
             if (GraalOptions.CheckcastCounters) {
-                SnippetTemplate template = getTemplate(hintHubs.length, flags | COUNTERS.bit(), 0, new Factory() {
+                HotSpotKlassOop[] hintHubs = createHintHubs(hints);
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | EXACT_HINTS.bit(hints.exact) | COUNTERS.bit(), 0, new Factory() {
                     @SuppressWarnings("hiding")
                     @Override
                     SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
@@ -455,32 +461,46 @@
                 });
                 template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs, hints.exact);
             } else if (target == null) {
+                HotSpotKlassOop[] hintHubs = createHintHubs(hints);
                 SnippetTemplate template = getTemplate(hintHubs.length, flags | UNKNOWN_SUPER.bit(), 0, new Factory() {
                     @SuppressWarnings("hiding")
                     @Override
                     SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
-                        // checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull)
-                        return SnippetTemplate.create(runtime, unknown, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags));
+                        // checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean checkNull)
+                        return SnippetTemplate.create(runtime, unknown, _, _, hints, CHECK_NULL.bool(flags));
                     }
                 });
                 template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);
-            } else if (target.isPrimaryType()) {
-                SnippetTemplate template = getTemplate(hintHubs.length, flags | PRIMARY_SUPER.bit(), target.superCheckOffset(), new Factory() {
+            } else if (hints.exact) {
+                HotSpotKlassOop[] hintHubs = createHintHubs(hints);
+                assert hintHubs.length == 1;
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | EXACT_HINTS.bit(), 0, new Factory() {
                     @SuppressWarnings("hiding")
                     @Override
                     SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
-                        // checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset)
-                        return SnippetTemplate.create(runtime, primary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags), target.superCheckOffset());
+                        // checkcastExact(Object object, Object exactHub, boolean checkNull)
+                        return SnippetTemplate.create(runtime, exact, _, hints[0], CHECK_NULL.bool(flags));
                     }
                 });
-                template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);
+                template.instantiate(runtime, checkcast, checkcast, object, hintHubs[0]);
+            } else if (target.isPrimaryType()) {
+                SnippetTemplate template = getTemplate(0, flags | PRIMARY_SUPER.bit(), target.superCheckOffset(), new Factory() {
+                    @SuppressWarnings("hiding")
+                    @Override
+                    SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
+                        // checkcastPrimary(Object hub, Object object, boolean checkNull, int superCheckOffset)
+                        return SnippetTemplate.create(runtime, primary, _, _, CHECK_NULL.bool(flags), target.superCheckOffset());
+                    }
+                });
+                template.instantiate(runtime, checkcast, checkcast, hub, object);
             } else {
+                HotSpotKlassOop[] hintHubs = createHintHubs(hints);
                 SnippetTemplate template = getTemplate(hintHubs.length, flags | SECONDARY_SUPER.bit(), 0, new Factory() {
                     @SuppressWarnings("hiding")
                     @Override
                     SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
-                        // checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull)
-                        return SnippetTemplate.create(runtime, secondary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags));
+                        // checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean checkNull)
+                        return SnippetTemplate.create(runtime, secondary, _, _, hints, CHECK_NULL.bool(flags));
                     }
                 });
                 template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);