# HG changeset patch # User Bernhard Urban # Date 1416843028 -3600 # Node ID f39180e681b87f1abe2c5935b23c3e4a1235ac07 # Parent 8d9c1a018e77eb8c4d4f365aced79f4905ab112d ClassSubstitutions: macro for Class.isAssignable diff -r 8d9c1a018e77 -r f39180e681b8 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java Mon Nov 24 15:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java Mon Nov 24 16:30:28 2014 +0100 @@ -127,6 +127,58 @@ return true; } + private static class A { + } + + private static class B extends A { + } + + private static class C { + } + + private static final A a = new A(); + private static final B b = new B(); + private static final C c = new C(); + + public boolean classIsAssignable1() { + return a.getClass().isAssignableFrom(a.getClass()); + } + + public boolean classIsAssignable2() { + return a.getClass().isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable3() { + return a.getClass().isAssignableFrom(c.getClass()); + } + + public boolean classIsAssignable4() { + return b.getClass().isAssignableFrom(a.getClass()); + } + + public boolean classIsAssignable5() { + return c.getClass().isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable6() { + return int.class.isAssignableFrom(b.getClass()); + } + + public boolean classIsAssignable7() { + return int.class.isAssignableFrom(int.class); + } + + @Test + public void testClassIsAssignable() { + testConstantReturn("classIsAssignable1", 1); + testConstantReturn("classIsAssignable2", 1); + testConstantReturn("classIsAssignable3", 0); + testConstantReturn("classIsAssignable4", 0); + testConstantReturn("classIsAssignable5", 0); + testConstantReturn("classIsAssignable6", 0); + testConstantReturn("classIsAssignable7", 1); + } + private void testConstantReturn(String name, Object value) { StructuredGraph result = test(name); ReturnNode ret = result.getNodes(ReturnNode.class).first(); diff -r 8d9c1a018e77 -r f39180e681b8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsAssignableFromNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsAssignableFromNode.java Mon Nov 24 16:30:28 2014 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, 2014, 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.hotspot.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * {@link MacroNode Macro node} for {@link Class#isAssignableFrom(Class)}. + * + * @see ClassSubstitutions#isAssignableFrom(Class, Class) + */ +@NodeInfo +public class ClassIsAssignableFromNode extends MacroStateSplitNode implements Canonicalizable { + public static ClassIsAssignableFromNode create(Invoke invoke) { + return new ClassIsAssignableFromNode(invoke); + } + + protected ClassIsAssignableFromNode(Invoke invoke) { + super(invoke); + } + + private ValueNode getJavaClass() { + return arguments.get(0); + } + + private ValueNode getOtherClass() { + return arguments.get(1); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ValueNode javaClass = getJavaClass(); + ValueNode otherClass = getOtherClass(); + if (javaClass.isConstant() && otherClass.isConstant()) { + ConstantReflectionProvider constantReflection = tool.getConstantReflection(); + ResolvedJavaType thisType = constantReflection.asJavaType(javaClass.asJavaConstant()); + ResolvedJavaType otherType = constantReflection.asJavaType(otherClass.asJavaConstant()); + if (thisType != null && otherType != null) { + return ConstantNode.forBoolean(thisType.isAssignableFrom(otherType)); + } + } + return this; + } +} diff -r 8d9c1a018e77 -r f39180e681b8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Mon Nov 24 15:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Mon Nov 24 16:30:28 2014 +0100 @@ -27,10 +27,13 @@ import java.lang.reflect.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.word.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; @@ -130,6 +133,26 @@ return ConditionalNode.materializeIsInstance(thisObj, obj); } + @MacroSubstitution(macro = ClassIsAssignableFromNode.class, isStatic = false) + @MethodSubstitution(isStatic = false) + public static boolean isAssignableFrom(Class thisClass, Class otherClass) { + if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, otherClass == null)) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); + return false; + } + GuardingNode anchorNode = SnippetAnchorNode.anchor(); + KlassPointer thisHub = ClassGetHubNode.readClass(thisClass, anchorNode); + KlassPointer otherHub = ClassGetHubNode.readClass(otherClass, anchorNode); + if (thisHub.isNull() || otherHub.isNull()) { + // primitive types, only true if equal. + return thisClass == otherClass; + } + if (!TypeCheckSnippetUtils.checkUnknownSubType(thisHub.asWord(), otherHub.asWord())) { + return false; + } + return true; + } + @MacroSubstitution(macro = ClassCastNode.class, isStatic = false) public static native Object cast(final Class thisObj, Object obj); }