changeset 7278:346336325337

added intrinsification of Class.isInstance()
author Doug Simon <doug.simon@oracle.com>
date Wed, 19 Dec 2012 00:12:32 +0100
parents e3f23398d28e
children 9e27795a9d05 64f4195d0ecf
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java
diffstat 8 files changed, 267 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Dec 19 00:12:32 2012 +0100
@@ -676,6 +676,8 @@
             checkcastSnippets.lower((CheckCastDynamicNode) n);
         } else if (n instanceof InstanceOfNode) {
             instanceofSnippets.lower((InstanceOfNode) n, tool);
+        } else if (n instanceof InstanceOfDynamicNode) {
+            instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
         } else if (n instanceof NewInstanceNode) {
             newObjectSnippets.lower((NewInstanceNode) n, tool);
         } else if (n instanceof NewArrayNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java	Wed Dec 19 00:12:32 2012 +0100
@@ -27,6 +27,7 @@
 
 import java.lang.reflect.*;
 
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
 
@@ -107,4 +108,10 @@
         }
         return null;
     }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInstance(final Class<?> thisObj, Object obj) {
+        return MaterializeNode.isInstance(thisObj, obj);
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Wed Dec 19 00:12:32 2012 +0100
@@ -159,45 +159,83 @@
         return false;
     }
 
+    /**
+     * Type test used when the type being tested against is not known at compile time.
+     */
+    @Snippet
+    public static Object instanceofDynamic(
+                    @Parameter("mirror") Class mirror,
+                    @Parameter("object") Object object,
+                    @Parameter("trueValue") Object trueValue,
+                    @Parameter("falseValue") Object falseValue,
+                    @ConstantParameter("checkNull") boolean checkNull) {
+        if (checkNull && object == null) {
+            isNull.inc();
+            return falseValue;
+        }
+
+        Word hub = loadWordFromObject(mirror, klassOffset());
+        Word objectHub = loadHub(object);
+        if (!checkUnknownSubType(hub, objectHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
     public static class Templates extends InstanceOfSnippetsTemplates<InstanceOfSnippets> {
 
         private final ResolvedJavaMethod instanceofExact;
         private final ResolvedJavaMethod instanceofPrimary;
         private final ResolvedJavaMethod instanceofSecondary;
+        private final ResolvedJavaMethod instanceofDynamic;
 
         public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) {
             super(runtime, assumptions, target, InstanceOfSnippets.class);
             instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class);
             instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class);
             instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class);
+            instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class);
         }
 
         @Override
         protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) {
-            InstanceOfNode instanceOf = replacer.instanceOf;
-            ValueNode trueValue = replacer.trueValue;
-            ValueNode falseValue = replacer.falseValue;
-            ValueNode object = instanceOf.object();
-            TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
-            final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
-            ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph());
-            boolean checkNull = !object.stamp().nonNull();
-            Arguments arguments;
-            Key key;
-            if (hintInfo.exact) {
-                ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
-                assert hints.length == 1;
-                key = new Key(instanceofExact).add("checkNull", checkNull);
-                arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
-            } else if (type.isPrimaryType()) {
-                key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
-                arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+            if (replacer.instanceOf instanceof InstanceOfNode) {
+                InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
+                ValueNode trueValue = replacer.trueValue;
+                ValueNode falseValue = replacer.falseValue;
+                ValueNode object = instanceOf.object();
+                TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
+                final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
+                ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph());
+                boolean checkNull = !object.stamp().nonNull();
+                Arguments arguments;
+                Key key;
+                if (hintInfo.exact) {
+                    ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
+                    assert hints.length == 1;
+                    key = new Key(instanceofExact).add("checkNull", checkNull);
+                    arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
+                } else if (type.isPrimaryType()) {
+                    key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
+                    arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+                } else {
+                    ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
+                    key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull);
+                    arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
+                }
+                return new KeyAndArguments(key, arguments);
             } else {
-                ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
-                key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull);
-                arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
+                assert replacer.instanceOf instanceof InstanceOfDynamicNode;
+                InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf;
+                ValueNode trueValue = replacer.trueValue;
+                ValueNode falseValue = replacer.falseValue;
+                ValueNode object = instanceOf.object();
+                ValueNode mirror = instanceOf.mirror();
+                boolean checkNull = !object.stamp().nonNull();
+                Key key = new Key(instanceofDynamic).add("checkNull", checkNull);
+                Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+                return new KeyAndArguments(key, arguments);
             }
-            return new KeyAndArguments(key, arguments);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java	Wed Dec 19 00:12:32 2012 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 
 public final class MaterializeNode extends ConditionalNode {
 
@@ -37,6 +38,10 @@
         super(condition, trueValue, falseValue);
     }
 
+    private MaterializeNode(ValueNode type, ValueNode object) {
+        super(type.graph().add(new InstanceOfDynamicNode(type, object)), ConstantNode.forInt(1, type.graph()), ConstantNode.forInt(0, type.graph()));
+    }
+
     public static MaterializeNode create(BooleanNode condition, ValueNode trueValue, ValueNode falseValue) {
         Graph graph = condition.graph();
         MaterializeNode result = new MaterializeNode(condition, trueValue, falseValue);
@@ -53,4 +58,7 @@
 
     @NodeIntrinsic
     public static native boolean materialize(@ConstantNodeParameter Condition condition, long x, long y);
+
+    @NodeIntrinsic
+    public static native boolean isInstance(Class mirror, Object object);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Wed Dec 19 00:12:32 2012 +0100
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+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.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * The {@code InstanceOfDynamicNode} represents a type check where the type being checked
+ * is not known at compile time.
+ * This is used, for instance, to intrinsify {@link Class#isInstance(Object)}.
+ */
+public final class InstanceOfDynamicNode extends BooleanNode implements Canonicalizable, Lowerable {
+
+    @Input private ValueNode object;
+    @Input private ValueNode mirror;
+
+    /**
+     * Constructs a new InstanceOfNode.
+     *
+     * @param mirror the {@link Class} value representing the target target type of the instanceof check
+     * @param object the object being tested by the instanceof
+     */
+    public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
+        super(StampFactory.condition());
+        this.mirror = mirror;
+        this.object = object;
+        assert mirror.kind() == Kind.Object;
+        assert mirror.objectStamp().isExactType();
+        assert mirror.objectStamp().type().getName().equals("Ljava/lang/Class;");
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        assert object() != null : this;
+        if (mirror().isConstant()) {
+            Class clazz = (Class) mirror().asConstant().asObject();
+            ResolvedJavaType t = tool.runtime().lookupJavaType(clazz);
+            return graph().unique(new InstanceOfNode(t, object(), null));
+        }
+        return this;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode mirror() {
+        return mirror;
+    }
+
+    @Override
+    public boolean verify() {
+        for (Node usage : usages()) {
+            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
+        }
+        return super.verify();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java	Wed Dec 19 00:12:32 2012 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Tests for {@link InstanceOfDynamicNode}.
+ */
+public class InstanceOfDynamicTest extends GraalCompilerTest {
+
+    public static int id(int value) {
+        return value;
+    }
+
+    @Test
+    public void test100() {
+        final Object nul = null;
+        test("isStringDynamic", nul);
+        test("isStringDynamic", "object");
+        test("isStringDynamic", Object.class);
+    }
+
+    @Test
+    public void test101() {
+        final Object nul = null;
+        test("isStringIntDynamic", nul);
+        test("isStringIntDynamic", "object");
+        test("isStringIntDynamic", Object.class);
+    }
+
+    @Test
+    public void test103() {
+        test("isInstanceDynamic", String.class, null);
+        test("isInstanceDynamic", String.class, "object");
+        test("isInstanceDynamic", String.class, Object.class);
+    }
+
+    @Test
+    public void test104() {
+        test("isInstanceIntDynamic", String.class, null);
+        test("isInstanceIntDynamic", String.class, "object");
+        test("isInstanceIntDynamic", String.class, Object.class);
+    }
+
+    public static boolean isStringDynamic(Object o) {
+        return String.class.isInstance(o);
+    }
+
+    public static int isStringIntDynamic(Object o) {
+        if (String.class.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+
+    public static boolean isInstanceDynamic(Class c, Object o) {
+        return c.isInstance(o);
+    }
+
+    public static int isInstanceIntDynamic(Class c, Object o) {
+        if (c.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Wed Dec 19 00:12:32 2012 +0100
@@ -65,7 +65,7 @@
     @Test
     public void testClassIntrinsics() {
         test("getModifiersSnippet");
-//        test("isInstanceSnippet");
+        test("isInstanceSnippet");
         test("isInterfaceSnippet");
         test("isArraySnippet");
         test("isPrimitiveSnippet");
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Wed Dec 19 00:12:01 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Wed Dec 19 00:12:32 2012 +0100
@@ -77,7 +77,8 @@
      */
     protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool);
 
-    public void lower(InstanceOfNode instanceOf, LoweringTool tool) {
+    public void lower(FloatingNode instanceOf, LoweringTool tool) {
+        assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
         List<Node> usages = instanceOf.usages().snapshot();
         int nUsages = usages.size();
 
@@ -107,7 +108,7 @@
      * Gets the specific replacer object used to replace the usage of an instanceof node
      * with the result of an instantiated instanceof snippet.
      */
-    protected InstanceOfUsageReplacer createReplacer(InstanceOfNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
+    protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
         if (usage instanceof IfNode) {
             replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool);
@@ -175,15 +176,16 @@
     }
 
     /**
-     * Replaces a usage of an {@link InstanceOfNode}.
+     * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public abstract static class InstanceOfUsageReplacer implements UsageReplacer {
         public final Instantiation instantiation;
-        public final InstanceOfNode instanceOf;
+        public final FloatingNode instanceOf;
         public final ValueNode trueValue;
         public final ValueNode falseValue;
 
-        public InstanceOfUsageReplacer(Instantiation instantiation, InstanceOfNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+        public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+            assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
             this.instantiation = instantiation;
             this.instanceOf = instanceOf;
             this.trueValue = trueValue;
@@ -197,7 +199,7 @@
     }
 
     /**
-     * Replaces an {@link IfNode} usage of an {@link InstanceOfNode}.
+     * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public static class IfUsageReplacer extends InstanceOfUsageReplacer {
 
@@ -205,7 +207,7 @@
         private final IfNode usage;
         private final boolean sameBlock;
 
-        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) {
+        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf);
             this.solitaryUsage = solitaryUsage;
@@ -294,13 +296,13 @@
     }
 
     /**
-     * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode}.
+     * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer {
 
         public final ConditionalNode usage;
 
-        public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, ConditionalNode usage) {
+        public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.usage = usage;
         }