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}