# HG changeset patch # User Doug Simon # Date 1355872352 -3600 # Node ID 3463363253372daaabdb34433872870b218d65f1 # Parent e3f23398d28edc0fe4cdaf08f75669f79137cfd1 added intrinsification of Class.isInstance() diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- 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) { diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java --- 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); + } + } diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java --- 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 { 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); } } diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java --- 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); } diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- /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(); + } +} diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java --- /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(); + } +} diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java --- 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"); diff -r e3f23398d28e -r 346336325337 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java --- 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 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; }