001/*
002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.nodes.java;
024
025import jdk.internal.jvmci.meta.*;
026import jdk.internal.jvmci.meta.Assumptions.*;
027
028import com.oracle.graal.compiler.common.type.*;
029import com.oracle.graal.graph.*;
030import com.oracle.graal.graph.spi.*;
031import com.oracle.graal.nodeinfo.*;
032import com.oracle.graal.nodes.*;
033import com.oracle.graal.nodes.spi.*;
034
035/**
036 * The {@code TypeCheckNode} represents a test equivalent to {@code o.getClass() == type}. The node
037 * may only be used if {@code o != null} is known to be true as indicated by the object's stamp.
038 */
039@NodeInfo
040public final class TypeCheckNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
041    public static final NodeClass<TypeCheckNode> TYPE = NodeClass.create(TypeCheckNode.class);
042
043    protected final ResolvedJavaType type;
044
045    protected TypeCheckNode(ResolvedJavaType type, ValueNode object) {
046        super(TYPE, object);
047        this.type = type;
048        assert type != null;
049        assert type.isConcrete() || type.isArray();
050        assert ((ObjectStamp) object.stamp()).nonNull();
051    }
052
053    public static LogicNode create(ResolvedJavaType type, ValueNode object) {
054        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
055        assert objectStamp.nonNull() : object;
056        LogicNode constantValue = findSynonym(type, objectStamp.type(), true, objectStamp.isExactType());
057        if (constantValue != null) {
058            return constantValue;
059        } else {
060            return new TypeCheckNode(type, object);
061        }
062    }
063
064    @Override
065    public void lower(LoweringTool tool) {
066        tool.getLowerer().lower(this, tool);
067    }
068
069    @Override
070    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
071        if (!(forValue.stamp() instanceof ObjectStamp)) {
072            return this;
073        }
074        ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
075
076        ResolvedJavaType stampType = objectStamp.type();
077        if (stampType != null) {
078            ValueNode result = findSynonym(type(), stampType, true, objectStamp.isExactType());
079            if (result != null) {
080                return result;
081            }
082            Assumptions assumptions = graph() == null ? null : graph().getAssumptions();
083            if (assumptions != null) {
084                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = stampType.findLeafConcreteSubtype();
085                if (leafConcreteSubtype != null) {
086                    result = findSynonym(type(), leafConcreteSubtype.getResult(), true, true);
087                    if (result != null) {
088                        assumptions.record(leafConcreteSubtype);
089                        return result;
090                    }
091                }
092            }
093        }
094        return this;
095    }
096
097    public static LogicNode findSynonym(ResolvedJavaType type, ResolvedJavaType inputType, boolean nonNull, boolean exactType) {
098        if (inputType == null) {
099            return null;
100        }
101        if (type.equals(inputType)) {
102            if (nonNull && exactType) {
103                // the type matches, so return true
104                return LogicConstantNode.tautology();
105            }
106        } else {
107            if (exactType || !inputType.isAssignableFrom(type)) {
108                // since this type check failed for an exact type we know that it can never
109                // succeed at run time. we also don't care about null values, since they will
110                // also make the check fail.
111                return LogicConstantNode.contradiction();
112            }
113        }
114        return null;
115    }
116
117    /**
118     * Gets the type being tested.
119     */
120    public ResolvedJavaType type() {
121        return type;
122    }
123
124    @Override
125    public void virtualize(VirtualizerTool tool) {
126        ValueNode alias = tool.getAlias(getValue());
127        TriState state = tryFold(alias.stamp());
128        if (state != TriState.UNKNOWN) {
129            tool.replaceWithValue(LogicConstantNode.forBoolean(state.isTrue(), graph()));
130        }
131    }
132
133    @Override
134    public Stamp getSucceedingStampForValue(boolean negated) {
135        if (negated) {
136            return null;
137        } else {
138            return StampFactory.exactNonNull(type);
139        }
140    }
141
142    @Override
143    public TriState tryFold(Stamp valueStamp) {
144        if (valueStamp instanceof ObjectStamp) {
145            ObjectStamp objectStamp = (ObjectStamp) valueStamp;
146            if (objectStamp.alwaysNull()) {
147                return TriState.FALSE;
148            }
149
150            ResolvedJavaType objectType = objectStamp.type();
151            if (objectType != null) {
152                ResolvedJavaType instanceofType = type;
153                if (instanceofType.equals(objectType)) {
154                    if (objectStamp.nonNull() && (objectStamp.isExactType() || objectType.isLeaf())) {
155                        return TriState.TRUE;
156                    }
157                } else {
158                    if (objectStamp.isExactType()) {
159                        return TriState.FALSE;
160                    }
161                }
162            }
163        }
164        return TriState.UNKNOWN;
165    }
166}