1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.generic; 23 24 25 import com.sun.org.apache.bcel.internal.Constants; 26 import com.sun.org.apache.bcel.internal.Repository; 27 import com.sun.org.apache.bcel.internal.classfile.JavaClass; 28 29 /** 30 * Super class for object and array types. 31 * 32 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 33 */ 34 public abstract class ReferenceType extends Type { 35 protected ReferenceType(byte t, String s) { 36 super(t, s); 37 } 38 39 /** Class is non-abstract but not instantiable from the outside 40 */ 41 ReferenceType() { 42 super(Constants.T_OBJECT, "<null object>"); 43 } 44 45 /** 46 * Return true iff this type is castable to another type t as defined in 47 * the JVM specification. The case where this is Type.NULL is not 48 * defined (see the CHECKCAST definition in the JVM specification). 49 * However, because e.g. CHECKCAST doesn't throw a 50 * ClassCastException when casting a null reference to any Object, 51 * true is returned in this case. 52 */ 53 public boolean isCastableTo(Type t) { 54 if (this.equals(Type.NULL)) 55 return true; // If this is ever changed in isAssignmentCompatible() 56 57 return isAssignmentCompatibleWith(t); 58 /* Yes, it's true: It's the same definition. 59 * See vmspec2 AASTORE / CHECKCAST definitions. 60 */ 61 } 62 63 /** 64 * Return true iff this is assignment compatible with another type t 65 * as defined in the JVM specification; see the AASTORE definition 66 * there. 67 */ 68 public boolean isAssignmentCompatibleWith(Type t) { 69 if (!(t instanceof ReferenceType)) 70 return false; 71 72 ReferenceType T = (ReferenceType) t; 73 74 if (this.equals(Type.NULL)) 75 return true; // This is not explicitely stated, but clear. Isn't it? 76 77 /* If this is a class type then 78 */ 79 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClass())) { 80 /* If T is a class type, then this must be the same class as T, 81 or this must be a subclass of T; 82 */ 83 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 84 if (this.equals(T)) 85 return true; 86 87 if (Repository.instanceOf(((ObjectType) this).getClassName(), 88 ((ObjectType) T).getClassName())) 89 return true; 90 } 91 92 /* If T is an interface type, this must implement interface T. 93 */ 94 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 95 if (Repository.implementationOf(((ObjectType) this).getClassName(), 96 ((ObjectType) T).getClassName())) 97 return true; 98 } 99 } 100 101 /* If this is an interface type, then: 102 */ 103 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterface())) { 104 /* If T is a class type, then T must be Object (2.4.7). 105 */ 106 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 107 if (T.equals(Type.OBJECT)) return true; 108 } 109 110 /* If T is an interface type, then T must be the same interface 111 * as this or a superinterface of this (2.13.2). 112 */ 113 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 114 if (this.equals(T)) return true; 115 if (Repository.implementationOf(((ObjectType) this).getClassName(), 116 ((ObjectType) T).getClassName())) 117 return true; 118 } 119 } 120 121 /* If this is an array type, namely, the type SC[], that is, an 122 * array of components of type SC, then: 123 */ 124 if (this instanceof ArrayType) { 125 /* If T is a class type, then T must be Object (2.4.7). 126 */ 127 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 128 if (T.equals(Type.OBJECT)) return true; 129 } 130 131 /* If T is an array type TC[], that is, an array of components 132 * of type TC, then one of the following must be true: 133 */ 134 if (T instanceof ArrayType) { 135 /* TC and SC are the same primitive type (2.4.1). 136 */ 137 Type sc = ((ArrayType) this).getElementType(); 138 Type tc = ((ArrayType) this).getElementType(); 139 140 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) 141 return true; 142 143 /* TC and SC are reference types (2.4.6), and type SC is 144 * assignable to TC by these runtime rules. 145 */ 146 if (tc instanceof ReferenceType && sc instanceof ReferenceType && 147 ((ReferenceType) sc).isAssignmentCompatibleWith((ReferenceType) tc)) 148 return true; 149 } 150 151 /* If T is an interface type, T must be one of the interfaces implemented by arrays (2.15). */ 152 // TODO: Check if this is still valid or find a way to dynamically find out which 153 // interfaces arrays implement. However, as of the JVM specification edition 2, there 154 // are at least two different pages where assignment compatibility is defined and 155 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or 156 // 'java.io.Serializable'" 157 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 158 for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) { 159 if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) return true; 160 } 161 } 162 } 163 return false; // default. 164 } 165 166 /** 167 * This commutative operation returns the first common superclass (narrowest ReferenceType 168 * referencing a class, not an interface). 169 * If one of the types is a superclass of the other, the former is returned. 170 * If "this" is Type.NULL, then t is returned. 171 * If t is Type.NULL, then "this" is returned. 172 * If "this" equals t ['this.equals(t)'] "this" is returned. 173 * If "this" or t is an ArrayType, then Type.OBJECT is returned; 174 * unless their dimensions match. Then an ArrayType of the same 175 * number of dimensions is returned, with its basic type being the 176 * first common super class of the basic types of "this" and t. 177 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 178 * If not all of the two classes' superclasses cannot be found, "null" is returned. 179 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 180 */ 181 public ReferenceType getFirstCommonSuperclass(ReferenceType t) { 182 if (this.equals(Type.NULL)) return t; 183 if (t.equals(Type.NULL)) return this; 184 if (this.equals(t)) return this; 185 /* 186 * TODO: Above sounds a little arbitrary. On the other hand, there is 187 * no object referenced by Type.NULL so we can also say all the objects 188 * referenced by Type.NULL were derived from java.lang.Object. 189 * However, the Java Language's "instanceof" operator proves us wrong: 190 * "null" is not referring to an instance of java.lang.Object :) 191 */ 192 193 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ 194 195 if ((this instanceof ArrayType) && (t instanceof ArrayType)) { 196 ArrayType arrType1 = (ArrayType) this; 197 ArrayType arrType2 = (ArrayType) t; 198 if ( 199 (arrType1.getDimensions() == arrType2.getDimensions()) && 200 arrType1.getBasicType() instanceof ObjectType && 201 arrType2.getBasicType() instanceof ObjectType) { 202 return new ArrayType( 203 ((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), 204 arrType1.getDimensions() 205 ); 206 207 } 208 } 209 210 if ((this instanceof ArrayType) || (t instanceof ArrayType)) 211 return Type.OBJECT; 212 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? 213 214 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || 215 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) 216 return Type.OBJECT; 217 // TODO: The above line is correct comparing to the vmspec2. But one could 218 // make class file verification a bit stronger here by using the notion of 219 // superinterfaces or even castability or assignment compatibility. 220 221 222 // this and t are ObjectTypes, see above. 223 ObjectType thiz = (ObjectType) this; 224 ObjectType other = (ObjectType) t; 225 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); 226 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); 227 228 if ((thiz_sups == null) || (other_sups == null)) { 229 return null; 230 } 231 232 // Waaahh... 233 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; 234 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; 235 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); 236 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); 237 this_sups[0] = Repository.lookupClass(thiz.getClassName()); 238 t_sups[0] = Repository.lookupClass(other.getClassName()); 239 240 for (int i = 0; i < t_sups.length; i++) { 241 for (int j = 0; j < this_sups.length; j++) { 242 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); 243 } 244 } 245 246 // Huh? Did you ask for Type.OBJECT's superclass?? 247 return null; 248 } 249 250 /** 251 * This commutative operation returns the first common superclass (narrowest ReferenceType 252 * referencing a class, not an interface). 253 * If one of the types is a superclass of the other, the former is returned. 254 * If "this" is Type.NULL, then t is returned. 255 * If t is Type.NULL, then "this" is returned. 256 * If "this" equals t ['this.equals(t)'] "this" is returned. 257 * If "this" or t is an ArrayType, then Type.OBJECT is returned. 258 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 259 * If not all of the two classes' superclasses cannot be found, "null" is returned. 260 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 261 * 262 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has 263 * slightly changed semantics. 264 */ 265 public ReferenceType firstCommonSuperclass(ReferenceType t) { 266 if (this.equals(Type.NULL)) return t; 267 if (t.equals(Type.NULL)) return this; 268 if (this.equals(t)) return this; 269 /* 270 * TODO: Above sounds a little arbitrary. On the other hand, there is 271 * no object referenced by Type.NULL so we can also say all the objects 272 * referenced by Type.NULL were derived from java.lang.Object. 273 * However, the Java Language's "instanceof" operator proves us wrong: 274 * "null" is not referring to an instance of java.lang.Object :) 275 */ 276 277 if ((this instanceof ArrayType) || (t instanceof ArrayType)) 278 return Type.OBJECT; 279 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? 280 281 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || 282 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) 283 return Type.OBJECT; 284 // TODO: The above line is correct comparing to the vmspec2. But one could 285 // make class file verification a bit stronger here by using the notion of 286 // superinterfaces or even castability or assignment compatibility. 287 288 289 // this and t are ObjectTypes, see above. 290 ObjectType thiz = (ObjectType) this; 291 ObjectType other = (ObjectType) t; 292 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); 293 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); 294 295 if ((thiz_sups == null) || (other_sups == null)) { 296 return null; 297 } 298 299 // Waaahh... 300 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; 301 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; 302 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); 303 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); 304 this_sups[0] = Repository.lookupClass(thiz.getClassName()); 305 t_sups[0] = Repository.lookupClass(other.getClassName()); 306 307 for (int i = 0; i < t_sups.length; i++) { 308 for (int j = 0; j < this_sups.length; j++) { 309 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); 310 } 311 } 312 313 // Huh? Did you ask for Type.OBJECT's superclass?? 314 return null; 315 } 316 }