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