001/* 002 * Copyright (c) 2012, 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.compiler.common.type; 024 025import java.util.*; 026 027import jdk.internal.jvmci.meta.*; 028 029/** 030 * Type describing all pointers to Java objects. 031 */ 032public abstract class AbstractObjectStamp extends AbstractPointerStamp { 033 034 private final ResolvedJavaType type; 035 private final boolean exactType; 036 037 protected AbstractObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { 038 super(nonNull, alwaysNull); 039 this.type = type; 040 if (!exactType && type != null && type.isLeaf()) { 041 this.exactType = true; 042 } else { 043 this.exactType = exactType; 044 } 045 } 046 047 protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull); 048 049 @Override 050 protected final AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { 051 return copyWith(type, exactType, newNonNull, newAlwaysNull); 052 } 053 054 @Override 055 public Stamp unrestricted() { 056 return copyWith(null, false, false, false); 057 } 058 059 @Override 060 public Stamp empty() { 061 return copyWith(null, true, true, false); 062 } 063 064 @Override 065 public Stamp constant(Constant c, MetaAccessProvider meta) { 066 JavaConstant jc = (JavaConstant) c; 067 ResolvedJavaType constType = jc.isNull() ? null : meta.lookupJavaType(jc); 068 return copyWith(constType, jc.isNonNull(), jc.isNonNull(), jc.isNull()); 069 } 070 071 @Override 072 public boolean hasValues() { 073 return !exactType || (type != null && (isConcreteType(type))); 074 } 075 076 @Override 077 public Kind getStackKind() { 078 return Kind.Object; 079 } 080 081 @Override 082 public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { 083 if (type != null) { 084 return type; 085 } 086 return metaAccess.lookupJavaType(Object.class); 087 } 088 089 public ResolvedJavaType type() { 090 return type; 091 } 092 093 public boolean isExactType() { 094 return exactType; 095 } 096 097 protected void appendString(StringBuilder str) { 098 if (this.isEmpty()) { 099 str.append(" empty"); 100 } else { 101 str.append(nonNull() ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull() ? " NULL" : ""); 102 } 103 } 104 105 @Override 106 public Stamp meet(Stamp otherStamp) { 107 if (this == otherStamp) { 108 return this; 109 } 110 AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; 111 if (isEmpty()) { 112 return other; 113 } else if (other.isEmpty()) { 114 return this; 115 } 116 ResolvedJavaType meetType; 117 boolean meetExactType; 118 boolean meetNonNull; 119 boolean meetAlwaysNull; 120 if (other.alwaysNull()) { 121 meetType = type(); 122 meetExactType = exactType; 123 meetNonNull = false; 124 meetAlwaysNull = alwaysNull(); 125 } else if (alwaysNull()) { 126 meetType = other.type(); 127 meetExactType = other.exactType; 128 meetNonNull = false; 129 meetAlwaysNull = other.alwaysNull(); 130 } else { 131 meetType = meetTypes(type(), other.type()); 132 meetExactType = exactType && other.exactType; 133 if (meetExactType && type != null && other.type != null) { 134 // meeting two valid exact types may result in a non-exact type 135 meetExactType = Objects.equals(meetType, type) && Objects.equals(meetType, other.type); 136 } 137 meetNonNull = nonNull() && other.nonNull(); 138 meetAlwaysNull = false; 139 } 140 141 if (Objects.equals(meetType, type) && meetExactType == exactType && meetNonNull == nonNull() && meetAlwaysNull == alwaysNull()) { 142 return this; 143 } else if (Objects.equals(meetType, other.type) && meetExactType == other.exactType && meetNonNull == other.nonNull() && meetAlwaysNull == other.alwaysNull()) { 144 return other; 145 } else { 146 return copyWith(meetType, meetExactType, meetNonNull, meetAlwaysNull); 147 } 148 } 149 150 @Override 151 public Stamp join(Stamp otherStamp) { 152 return join0(otherStamp, false); 153 } 154 155 /** 156 * Returns the stamp representing the type of this stamp after a cast to the type represented by 157 * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case 158 * where both types are not obviously related, the cast operation will prefer the type of the 159 * {@code to} stamp. This is necessary as long as ObjectStamps are not able to accurately 160 * represent intersection types. 161 * 162 * For example when joining the {@link RandomAccess} type with the {@link AbstractList} type, 163 * without intersection types, this would result in the most generic type ({@link Object} ). For 164 * this reason, in some cases a {@code castTo} operation is preferable in order to keep at least 165 * the {@link AbstractList} type. 166 * 167 * @param other the stamp this stamp should be casted to 168 * @return the new improved stamp or {@code null} if this stamp cannot be improved 169 */ 170 @Override 171 public Stamp improveWith(Stamp other) { 172 return join0(other, true); 173 } 174 175 private Stamp join0(Stamp otherStamp, boolean improve) { 176 if (this == otherStamp) { 177 return this; 178 } 179 AbstractObjectStamp other = (AbstractObjectStamp) otherStamp; 180 if (isEmpty()) { 181 return this; 182 } else if (other.isEmpty()) { 183 return other; 184 } 185 186 ResolvedJavaType joinType; 187 boolean joinAlwaysNull = alwaysNull() || other.alwaysNull(); 188 boolean joinNonNull = nonNull() || other.nonNull(); 189 boolean joinExactType = exactType || other.exactType; 190 if (Objects.equals(type, other.type)) { 191 joinType = type; 192 } else if (type == null && other.type == null) { 193 joinType = null; 194 } else if (type == null) { 195 joinType = other.type; 196 } else if (other.type == null) { 197 joinType = type; 198 } else { 199 // both types are != null and different 200 if (type.isAssignableFrom(other.type)) { 201 joinType = other.type; 202 if (exactType) { 203 joinAlwaysNull = true; 204 } 205 } else if (other.type.isAssignableFrom(type)) { 206 joinType = type; 207 if (other.exactType) { 208 joinAlwaysNull = true; 209 } 210 } else { 211 if (improve) { 212 joinType = type; 213 joinExactType = exactType; 214 } else { 215 joinType = null; 216 } 217 218 if (joinExactType || (!isInterfaceOrArrayOfInterface(type) && !isInterfaceOrArrayOfInterface(other.type))) { 219 joinAlwaysNull = true; 220 } 221 } 222 } 223 if (joinAlwaysNull) { 224 joinType = null; 225 joinExactType = false; 226 } 227 if (joinExactType && joinType == null) { 228 return empty(); 229 } 230 if (joinAlwaysNull && joinNonNull) { 231 return empty(); 232 } else if (joinExactType && !isConcreteType(joinType)) { 233 return empty(); 234 } 235 if (Objects.equals(joinType, type) && joinExactType == exactType && joinNonNull == nonNull() && joinAlwaysNull == alwaysNull()) { 236 return this; 237 } else if (Objects.equals(joinType, other.type) && joinExactType == other.exactType && joinNonNull == other.nonNull() && joinAlwaysNull == other.alwaysNull()) { 238 return other; 239 } else { 240 return copyWith(joinType, joinExactType, joinNonNull, joinAlwaysNull); 241 } 242 } 243 244 private static boolean isInterfaceOrArrayOfInterface(ResolvedJavaType t) { 245 return t.isInterface() || (t.isArray() && t.getElementalType().isInterface()); 246 } 247 248 public static boolean isConcreteType(ResolvedJavaType type) { 249 return !(type.isAbstract() && !type.isArray()); 250 } 251 252 private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) { 253 if (Objects.equals(a, b)) { 254 return a; 255 } else if (a == null || b == null) { 256 return null; 257 } else { 258 return a.findLeastCommonAncestor(b); 259 } 260 } 261 262 @Override 263 public int hashCode() { 264 final int prime = 31; 265 int result = 1; 266 result = prime * result + super.hashCode(); 267 result = prime * result + (exactType ? 1231 : 1237); 268 result = prime * result + ((type == null || type.isJavaLangObject()) ? 0 : type.hashCode()); 269 return result; 270 } 271 272 @Override 273 public boolean equals(Object obj) { 274 if (this == obj) { 275 return true; 276 } 277 if (obj == null || getClass() != obj.getClass()) { 278 return false; 279 } 280 AbstractObjectStamp other = (AbstractObjectStamp) obj; 281 if (exactType != other.exactType) { 282 return false; 283 } 284 // null == java.lang.Object 285 if (type == null) { 286 if (other.type != null && !other.type.isJavaLangObject()) { 287 return false; 288 } 289 } else if (other.type == null) { 290 if (type != null && !type.isJavaLangObject()) { 291 return false; 292 } 293 } else if (!type.equals(other.type)) { 294 return false; 295 } 296 return super.equals(other); 297 } 298}