# HG changeset patch # User Thomas Wuerthinger # Date 1427902986 -7200 # Node ID 81d08c81b2a71dc4b0746c64b317ea960cbcf444 # Parent 45d46b136777b44fb66ce3c6014742e3f2aae792 Introduce TypeCheckNode. diff -r 45d46b136777 -r 81d08c81b2a7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed Apr 01 16:36:28 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed Apr 01 17:43:06 2015 +0200 @@ -112,6 +112,10 @@ if (graph.getGuardsStage().areDeoptsFixed()) { instanceofSnippets.lower((InstanceOfNode) n, tool); } + } else if (n instanceof TypeCheckNode) { + if (graph.getGuardsStage().areDeoptsFixed()) { + instanceofSnippets.lower((TypeCheckNode) n, tool); + } } else if (n instanceof InstanceOfDynamicNode) { if (graph.getGuardsStage().areDeoptsFixed()) { instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); diff -r 45d46b136777 -r 81d08c81b2a7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Wed Apr 01 16:36:28 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Wed Apr 01 17:43:06 2015 +0200 @@ -267,6 +267,13 @@ } return args; + } else if (replacer.instanceOf instanceof TypeCheckNode) { + TypeCheckNode typeCheck = (TypeCheckNode) replacer.instanceOf; + ValueNode object = typeCheck.getValue(); + Arguments args = new Arguments(instanceofExact, typeCheck.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("object", object); + args.add("exactHub", ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) typeCheck.type()).klass(), providers.getMetaAccess(), typeCheck.graph())); + return args; } else if (replacer.instanceOf instanceof InstanceOfDynamicNode) { InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; ValueNode object = instanceOf.object(); diff -r 45d46b136777 -r 81d08c81b2a7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed Apr 01 17:43:06 2015 +0200 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2009, 2015, 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.api.meta.Assumptions.AssumptionResult; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +/** + * The {@code TypeCheckNode} represents a test equivalent to (o != null && o.getClass() == type). + */ +@NodeInfo +public final class TypeCheckNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { + public static final NodeClass TYPE = NodeClass.create(TypeCheckNode.class); + + protected final ResolvedJavaType type; + + protected TypeCheckNode(ResolvedJavaType type, ValueNode object) { + super(TYPE, object); + this.type = type; + assert type != null; + assert type.isConcrete(); + } + + public static LogicNode create(ResolvedJavaType type, ValueNode object) { + ObjectStamp objectStamp = (ObjectStamp) object.stamp(); + LogicNode constantValue = findSynonym(type, objectStamp.type(), objectStamp.nonNull(), objectStamp.isExactType()); + if (constantValue != null) { + return constantValue; + } else { + return new TypeCheckNode(type, object); + } + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { + if (!(forValue.stamp() instanceof ObjectStamp)) { + return this; + } + ObjectStamp objectStamp = (ObjectStamp) forValue.stamp(); + if (objectStamp.alwaysNull()) { + return LogicConstantNode.contradiction(); + } + + ResolvedJavaType stampType = objectStamp.type(); + if (stampType != null) { + ValueNode result = check(forValue, stampType, objectStamp.nonNull(), objectStamp.isExactType()); + if (result != null) { + return result; + } + Assumptions assumptions = graph().getAssumptions(); + if (assumptions != null) { + AssumptionResult leafConcreteSubtype = stampType.findLeafConcreteSubtype(); + if (leafConcreteSubtype != null) { + result = check(forValue, leafConcreteSubtype.getResult(), objectStamp.nonNull(), true); + if (result != null) { + assumptions.record(leafConcreteSubtype); + return result; + } + } + } + } + return this; + } + + private ValueNode check(ValueNode forValue, ResolvedJavaType inputType, boolean nonNull, boolean exactType) { + ValueNode result = findSynonym(type(), inputType, nonNull, exactType); + if (result != null) { + return result; + } + if (type().equals(inputType)) { + if (!nonNull) { + // the instanceof matches if the object is non-null, so return true + // depending on the null-ness. + return LogicNegationNode.create(new IsNullNode(forValue)); + } + } + return null; + } + + public static LogicNode findSynonym(ResolvedJavaType type, ResolvedJavaType inputType, boolean nonNull, boolean exactType) { + if (inputType == null) { + return null; + } + if (type.equals(inputType)) { + if (nonNull) { + // the type matches, so return true + return LogicConstantNode.tautology(); + } + } else { + if (exactType) { + // since this type check failed for an exact type we know that it can never + // succeed at run time. we also don't care about null values, since they will + // also make the check fail. + return LogicConstantNode.contradiction(); + } + } + return null; + } + + /** + * Gets the type being tested. + */ + public ResolvedJavaType type() { + return type; + } + + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(getValue()); + if (state != null) { + tool.replaceWithValue(LogicConstantNode.forBoolean(type().equals(state.getVirtualObject().type()), graph())); + } + } + + @Override + public Stamp getSucceedingStampForValue(boolean negated) { + if (negated) { + return null; + } else { + return StampFactory.exactNonNull(type); + } + } + + @Override + public TriState tryFold(Stamp valueStamp) { + if (valueStamp instanceof ObjectStamp) { + ObjectStamp objectStamp = (ObjectStamp) valueStamp; + if (objectStamp.alwaysNull()) { + return TriState.FALSE; + } + + ResolvedJavaType objectType = objectStamp.type(); + if (objectType != null) { + ResolvedJavaType instanceofType = type; + if (instanceofType.equals(objectType)) { + if (objectStamp.nonNull()) { + return TriState.TRUE; + } + } else { + if (objectStamp.isExactType()) { + return TriState.FALSE; + } + } + } + } + return TriState.UNKNOWN; + } +}