001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.generic; 020 021import org.apache.bcel.Const; 022import org.apache.bcel.Repository; 023import org.apache.bcel.classfile.JavaClass; 024 025/** 026 * Super class for object and array types. 027 */ 028public abstract class ReferenceType extends Type { 029 030 /** 031 * Class is non-abstract but not instantiable from the outside. 032 */ 033 ReferenceType() { 034 super(Const.T_OBJECT, "<null object>"); 035 } 036 037 /** 038 * Constructs a ReferenceType. 039 * 040 * @param t The type. 041 * @param s The signature. 042 */ 043 protected ReferenceType(final byte t, final String s) { 044 super(t, s); 045 } 046 047 /** 048 * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an 049 * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t 050 * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If 051 * "this" or t is an ArrayType, then {@link #OBJECT} is returned. If "this" or t is a ReferenceType referencing an 052 * interface, then {@link #OBJECT} is returned. If not all of the two classes' superclasses cannot be found, "null" is 053 * returned. See the JVM specification edition 2, "�4.9.2 The Bytecode Verifier". 054 * 055 * @param t The other type. 056 * @return The first common superclass. 057 * @throws ClassNotFoundException Thrown on failure to find superclasses of this type, or the type passed as a parameter. 058 * @deprecated Use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics. 059 */ 060 @Deprecated 061 public ReferenceType firstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { 062 if (equals(NULL)) { 063 return t; 064 } 065 if (t.equals(NULL) || equals(t)) { 066 return this; 067 /* 068 * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also 069 * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's 070 * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) 071 */ 072 } 073 if (this instanceof ArrayType || t instanceof ArrayType) { 074 return OBJECT; 075 // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? 076 } 077 return getFirstCommonSuperclassInternal(t); 078 } 079 080 /** 081 * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an 082 * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t 083 * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If 084 * "this" or t is an ArrayType, then {@link #OBJECT} is returned; unless their dimensions match. Then an ArrayType of the 085 * same number of dimensions is returned, with its basic type being the first common super class of the basic types of 086 * "this" and t. If "this" or t is a ReferenceType referencing an interface, then {@link #OBJECT} is returned. If not all of 087 * the two classes' superclasses cannot be found, "null" is returned. See the JVM specification edition 2, "�4.9.2 The 088 * Bytecode Verifier". 089 * 090 * @param t The other type. 091 * @return The first common superclass. 092 * @throws ClassNotFoundException Thrown on failure to find superclasses of this type, or the type passed as a parameter. 093 */ 094 public ReferenceType getFirstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { 095 if (equals(NULL)) { 096 return t; 097 } 098 if (t.equals(NULL) || equals(t)) { 099 return this; 100 /* 101 * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also 102 * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's 103 * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) 104 */ 105 } 106 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ 107 if (this instanceof ArrayType && t instanceof ArrayType) { 108 final ArrayType arrType1 = (ArrayType) this; 109 final ArrayType arrType2 = (ArrayType) t; 110 if (arrType1.getDimensions() == arrType2.getDimensions() && arrType1.getBasicType() instanceof ObjectType 111 && arrType2.getBasicType() instanceof ObjectType) { 112 return new ArrayType(((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), 113 arrType1.getDimensions()); 114 } 115 } 116 if (this instanceof ArrayType || t instanceof ArrayType) { 117 return OBJECT; 118 // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? 119 } 120 return getFirstCommonSuperclassInternal(t); 121 } 122 123 private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) throws ClassNotFoundException { 124 if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact() 125 || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) { 126 return OBJECT; 127 // TODO: The above line is correct comparing to the vmspec2. But one could 128 // make class file verification a bit stronger here by using the notion of 129 // superinterfaces or even castability or assignment compatibility. 130 } 131 // this and t are ObjectTypes, see above. 132 final ObjectType thiz = (ObjectType) this; 133 final ObjectType other = (ObjectType) t; 134 final JavaClass[] thizSups = Repository.getSuperClasses(thiz.getClassName()); 135 final JavaClass[] otherSups = Repository.getSuperClasses(other.getClassName()); 136 if (thizSups == null || otherSups == null) { 137 return null; 138 } 139 // Waaahh... 140 final JavaClass[] thisSups = new JavaClass[thizSups.length + 1]; 141 final JavaClass[] tSups = new JavaClass[otherSups.length + 1]; 142 System.arraycopy(thizSups, 0, thisSups, 1, thizSups.length); 143 System.arraycopy(otherSups, 0, tSups, 1, otherSups.length); 144 thisSups[0] = Repository.lookupClass(thiz.getClassName()); 145 tSups[0] = Repository.lookupClass(other.getClassName()); 146 for (final JavaClass tSup : tSups) { 147 for (final JavaClass thisSup : thisSups) { 148 if (thisSup.equals(tSup)) { 149 return ObjectType.getInstance(thisSup.getClassName()); 150 } 151 } 152 } 153 // Huh? Did you ask for OBJECT's superclass?? 154 return null; 155 } 156 157 /** 158 * Return true iff this is assignment compatible with another type t as defined in the JVM specification; see the 159 * AASTORE definition there. 160 * 161 * @param t The other type. 162 * @return true iff this is assignment compatible with another type t. 163 * @throws ClassNotFoundException Thrown if any classes or interfaces required to determine assignment compatibility can't be 164 * found. 165 */ 166 public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundException { 167 if (!(t instanceof ReferenceType)) { 168 return false; 169 } 170 final ReferenceType T = (ReferenceType) t; 171 if (equals(NULL)) { 172 return true; // This is not explicitly stated, but clear. Isn't it? 173 } 174 /* 175 * If this is a class type then 176 */ 177 if (this instanceof ObjectType && ((ObjectType) this).referencesClassExact()) { 178 /* 179 * If T is a class type, then this must be the same class as T, or this must be a subclass of T; 180 */ 181 if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() 182 && (equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { 183 return true; 184 } 185 /* 186 * If T is an interface type, this must implement interface T. 187 */ 188 if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact() 189 && Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName())) { 190 return true; 191 } 192 } 193 /* 194 * If this is an interface type, then: 195 */ 196 if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact()) { 197 /* 198 * If T is a class type, then T must be Object (�2.4.7). 199 */ 200 if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { 201 return true; 202 } 203 /* 204 * If T is an interface type, then T must be the same interface as this or a superinterface of this (�2.13.2). 205 */ 206 if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact() 207 && (equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { 208 return true; 209 } 210 } 211 /* 212 * If this is an array type, namely, the type SC[], that is, an array of components of type SC, then: 213 */ 214 if (this instanceof ArrayType) { 215 /* 216 * If T is a class type, then T must be Object (�2.4.7). 217 */ 218 if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { 219 return true; 220 } 221 /* 222 * If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true: 223 */ 224 if (T instanceof ArrayType) { 225 /* 226 * TC and SC are the same primitive type (�2.4.1). 227 */ 228 final Type sc = ((ArrayType) this).getElementType(); 229 final Type tc = ((ArrayType) T).getElementType(); 230 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) { 231 return true; 232 } 233 /* 234 * TC and SC are reference types (�2.4.6), and type SC is assignable to TC by these runtime rules. 235 */ 236 if (tc instanceof ReferenceType && sc instanceof ReferenceType && ((ReferenceType) sc).isAssignmentCompatibleWith(tc)) { 237 return true; 238 } 239 } 240 /* If T is an interface type, T must be one of the interfaces implemented by arrays (�2.15). */ 241 // TODO: Check if this is still valid or find a way to dynamically find out which 242 // interfaces arrays implement. However, as of the JVM specification edition 2, there 243 // are at least two different pages where assignment compatibility is defined and 244 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or 245 // 'java.io.Serializable'" 246 if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact()) { 247 for (final String element : Const.getInterfacesImplementedByArrays()) { 248 if (T.equals(ObjectType.getInstance(element))) { 249 return true; 250 } 251 } 252 } 253 } 254 return false; // default. 255 } 256 257 /** 258 * Return true iff this type is castable to another type t as defined in the JVM specification. The case where this is 259 * {@link #NULL} is not defined (see the CHECKCAST definition in the JVM specification). However, because for example CHECKCAST 260 * doesn't throw a ClassCastException when casting a null reference to any Object, true is returned in this case. 261 * 262 * @param t The other type. 263 * @return true iff this type is castable to another type t. 264 * @throws ClassNotFoundException Thrown if any classes or interfaces required to determine assignment compatibility can't be 265 * found. 266 */ 267 public boolean isCastableTo(final Type t) throws ClassNotFoundException { 268 if (equals(NULL)) { 269 return t instanceof ReferenceType; // If this is ever changed in isAssignmentCompatible() 270 } 271 return isAssignmentCompatibleWith(t); 272 /* 273 * Yes, it's true: It's the same definition. See vmspec2 AASTORE / CHECKCAST definitions. 274 */ 275 } 276}