1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 package com.sun.org.apache.bcel.internal.generic; 6 7 /* ==================================================================== 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 2001 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, 26 * if any, must include the following acknowledgment: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowledgment may appear in the software itself, 30 * if and wherever such third-party acknowledgments normally appear. 31 * 32 * 4. The names "Apache" and "Apache Software Foundation" and 33 * "Apache BCEL" must not be used to endorse or promote products 34 * derived from this software without prior written permission. For 35 * written permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache", 38 * "Apache BCEL", nor may "Apache" appear in their name, without 39 * prior written permission of the Apache Software Foundation. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>. 59 */ 60 61 import com.sun.org.apache.bcel.internal.Constants; 62 import com.sun.org.apache.bcel.internal.Repository; 63 import com.sun.org.apache.bcel.internal.classfile.JavaClass; 64 65 /** 66 * Super class for object and array types. 67 * 68 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 69 */ 70 public abstract class ReferenceType extends Type { 71 protected ReferenceType(byte t, String s) { 72 super(t, s); 73 } 74 75 /** Class is non-abstract but not instantiable from the outside 76 */ 77 ReferenceType() { 78 super(Constants.T_OBJECT, "<null object>"); 79 } 80 81 /** 82 * Return true iff this type is castable to another type t as defined in 83 * the JVM specification. The case where this is Type.NULL is not 84 * defined (see the CHECKCAST definition in the JVM specification). 85 * However, because e.g. CHECKCAST doesn't throw a 86 * ClassCastException when casting a null reference to any Object, 87 * true is returned in this case. 88 */ 89 public boolean isCastableTo(Type t) { 90 if (this.equals(Type.NULL)) 91 return true; // If this is ever changed in isAssignmentCompatible() 92 93 return isAssignmentCompatibleWith(t); 94 /* Yes, it's true: It's the same definition. 95 * See vmspec2 AASTORE / CHECKCAST definitions. 96 */ 97 } 98 99 /** 100 * Return true iff this is assignment compatible with another type t 101 * as defined in the JVM specification; see the AASTORE definition 102 * there. 103 */ 104 public boolean isAssignmentCompatibleWith(Type t) { 105 if (!(t instanceof ReferenceType)) 106 return false; 107 108 ReferenceType T = (ReferenceType) t; 109 110 if (this.equals(Type.NULL)) 111 return true; // This is not explicitely stated, but clear. Isn't it? 112 113 /* If this is a class type then 114 */ 115 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClass())) { 116 /* If T is a class type, then this must be the same class as T, 117 or this must be a subclass of T; 118 */ 119 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 120 if (this.equals(T)) 121 return true; 122 123 if (Repository.instanceOf(((ObjectType) this).getClassName(), 124 ((ObjectType) T).getClassName())) 125 return true; 126 } 127 128 /* If T is an interface type, this must implement interface T. 129 */ 130 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 131 if (Repository.implementationOf(((ObjectType) this).getClassName(), 132 ((ObjectType) T).getClassName())) 133 return true; 134 } 135 } 136 137 /* If this is an interface type, then: 138 */ 139 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterface())) { 140 /* If T is a class type, then T must be Object (2.4.7). 141 */ 142 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 143 if (T.equals(Type.OBJECT)) return true; 144 } 145 146 /* If T is an interface type, then T must be the same interface 147 * as this or a superinterface of this (2.13.2). 148 */ 149 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 150 if (this.equals(T)) return true; 151 if (Repository.implementationOf(((ObjectType) this).getClassName(), 152 ((ObjectType) T).getClassName())) 153 return true; 154 } 155 } 156 157 /* If this is an array type, namely, the type SC[], that is, an 158 * array of components of type SC, then: 159 */ 160 if (this instanceof ArrayType) { 161 /* If T is a class type, then T must be Object (2.4.7). 162 */ 163 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 164 if (T.equals(Type.OBJECT)) return true; 165 } 166 167 /* If T is an array type TC[], that is, an array of components 168 * of type TC, then one of the following must be true: 169 */ 170 if (T instanceof ArrayType) { 171 /* TC and SC are the same primitive type (2.4.1). 172 */ 173 Type sc = ((ArrayType) this).getElementType(); 174 Type tc = ((ArrayType) this).getElementType(); 175 176 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) 177 return true; 178 179 /* TC and SC are reference types (2.4.6), and type SC is 180 * assignable to TC by these runtime rules. 181 */ 182 if (tc instanceof ReferenceType && sc instanceof ReferenceType && 183 ((ReferenceType) sc).isAssignmentCompatibleWith((ReferenceType) tc)) 184 return true; 185 } 186 187 /* If T is an interface type, T must be one of the interfaces implemented by arrays (2.15). */ 188 // TODO: Check if this is still valid or find a way to dynamically find out which 189 // interfaces arrays implement. However, as of the JVM specification edition 2, there 190 // are at least two different pages where assignment compatibility is defined and 191 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or 192 // 'java.io.Serializable'" 193 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 194 for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) { 195 if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) return true; 196 } 197 } 198 } 199 return false; // default. 200 } 201 202 /** 203 * This commutative operation returns the first common superclass (narrowest ReferenceType 204 * referencing a class, not an interface). 205 * If one of the types is a superclass of the other, the former is returned. 206 * If "this" is Type.NULL, then t is returned. 207 * If t is Type.NULL, then "this" is returned. 208 * If "this" equals t ['this.equals(t)'] "this" is returned. 209 * If "this" or t is an ArrayType, then Type.OBJECT is returned; 210 * unless their dimensions match. Then an ArrayType of the same 211 * number of dimensions is returned, with its basic type being the 212 * first common super class of the basic types of "this" and t. 213 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 214 * If not all of the two classes' superclasses cannot be found, "null" is returned. 215 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 216 */ 217 public ReferenceType getFirstCommonSuperclass(ReferenceType t) { 218 if (this.equals(Type.NULL)) return t; 219 if (t.equals(Type.NULL)) return this; 220 if (this.equals(t)) return this; 221 /* 222 * TODO: Above sounds a little arbitrary. On the other hand, there is 223 * no object referenced by Type.NULL so we can also say all the objects 224 * referenced by Type.NULL were derived from java.lang.Object. 225 * However, the Java Language's "instanceof" operator proves us wrong: 226 * "null" is not referring to an instance of java.lang.Object :) 227 */ 228 229 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ 230 231 if ((this instanceof ArrayType) && (t instanceof ArrayType)) { 232 ArrayType arrType1 = (ArrayType) this; 233 ArrayType arrType2 = (ArrayType) t; 234 if ( 235 (arrType1.getDimensions() == arrType2.getDimensions()) && 236 arrType1.getBasicType() instanceof ObjectType && 237 arrType2.getBasicType() instanceof ObjectType) { 238 return new ArrayType( 239 ((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), 240 arrType1.getDimensions() 241 ); 242 243 } 244 } 245 246 if ((this instanceof ArrayType) || (t instanceof ArrayType)) 247 return Type.OBJECT; 248 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? 249 250 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || 251 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) 252 return Type.OBJECT; 253 // TODO: The above line is correct comparing to the vmspec2. But one could 254 // make class file verification a bit stronger here by using the notion of 255 // superinterfaces or even castability or assignment compatibility. 256 257 258 // this and t are ObjectTypes, see above. 259 ObjectType thiz = (ObjectType) this; 260 ObjectType other = (ObjectType) t; 261 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); 262 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); 263 264 if ((thiz_sups == null) || (other_sups == null)) { 265 return null; 266 } 267 268 // Waaahh... 269 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; 270 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; 271 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); 272 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); 273 this_sups[0] = Repository.lookupClass(thiz.getClassName()); 274 t_sups[0] = Repository.lookupClass(other.getClassName()); 275 276 for (int i = 0; i < t_sups.length; i++) { 277 for (int j = 0; j < this_sups.length; j++) { 278 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); 279 } 280 } 281 282 // Huh? Did you ask for Type.OBJECT's superclass?? 283 return null; 284 } 285 286 /** 287 * This commutative operation returns the first common superclass (narrowest ReferenceType 288 * referencing a class, not an interface). 289 * If one of the types is a superclass of the other, the former is returned. 290 * If "this" is Type.NULL, then t is returned. 291 * If t is Type.NULL, then "this" is returned. 292 * If "this" equals t ['this.equals(t)'] "this" is returned. 293 * If "this" or t is an ArrayType, then Type.OBJECT is returned. 294 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 295 * If not all of the two classes' superclasses cannot be found, "null" is returned. 296 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 297 * 298 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has 299 * slightly changed semantics. 300 */ 301 public ReferenceType firstCommonSuperclass(ReferenceType t) { 302 if (this.equals(Type.NULL)) return t; 303 if (t.equals(Type.NULL)) return this; 304 if (this.equals(t)) return this; 305 /* 306 * TODO: Above sounds a little arbitrary. On the other hand, there is 307 * no object referenced by Type.NULL so we can also say all the objects 308 * referenced by Type.NULL were derived from java.lang.Object. 309 * However, the Java Language's "instanceof" operator proves us wrong: 310 * "null" is not referring to an instance of java.lang.Object :) 311 */ 312 313 if ((this instanceof ArrayType) || (t instanceof ArrayType)) 314 return Type.OBJECT; 315 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? 316 317 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || 318 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) 319 return Type.OBJECT; 320 // TODO: The above line is correct comparing to the vmspec2. But one could 321 // make class file verification a bit stronger here by using the notion of 322 // superinterfaces or even castability or assignment compatibility. 323 324 325 // this and t are ObjectTypes, see above. 326 ObjectType thiz = (ObjectType) this; 327 ObjectType other = (ObjectType) t; 328 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); 329 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); 330 331 if ((thiz_sups == null) || (other_sups == null)) { 332 return null; 333 } 334 335 // Waaahh... 336 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; 337 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; 338 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); 339 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); 340 this_sups[0] = Repository.lookupClass(thiz.getClassName()); 341 t_sups[0] = Repository.lookupClass(other.getClassName()); 342 343 for (int i = 0; i < t_sups.length; i++) { 344 for (int j = 0; j < this_sups.length; j++) { 345 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); 346 } 347 } 348 349 // Huh? Did you ask for Type.OBJECT's superclass?? 350 return null; 351 } 352 }