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 24 import com.sun.org.apache.bcel.internal.Constants; 25 import com.sun.org.apache.bcel.internal.Repository; 26 import com.sun.org.apache.bcel.internal.classfile.JavaClass; 27 28 /** 29 * Super class for object and array types. 30 * 31 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 32 */ 33 public abstract class ReferenceType extends Type { 34 protected ReferenceType(byte t, String s) { 35 super(t, s); 36 } 37 38 /** Class is non-abstract but not instantiable from the outside 39 */ 40 ReferenceType() { 41 super(Constants.T_OBJECT, "<null object>"); 42 } 43 44 /** 45 * Return true iff this type is castable to another type t as defined in 46 * the JVM specification. The case where this is Type.NULL is not 47 * defined (see the CHECKCAST definition in the JVM specification). 48 * However, because e.g. CHECKCAST doesn't throw a 49 * ClassCastException when casting a null reference to any Object, 50 * true is returned in this case. 51 */ 52 public boolean isCastableTo(Type t) { 53 if (this.equals(Type.NULL)) 54 return true; // If this is ever changed in isAssignmentCompatible() 55 56 return isAssignmentCompatibleWith(t); 57 /* Yes, it's true: It's the same definition. 58 * See vmspec2 AASTORE / CHECKCAST definitions. 59 */ 60 } 61 62 /** 63 * Return true iff this is assignment compatible with another type t 64 * as defined in the JVM specification; see the AASTORE definition 65 * there. 66 */ 67 public boolean isAssignmentCompatibleWith(Type t) { 68 if (!(t instanceof ReferenceType)) 69 return false; 70 71 ReferenceType T = (ReferenceType) t; 72 73 if (this.equals(Type.NULL)) 74 return true; // This is not explicitely stated, but clear. Isn't it? 75 76 /* If this is a class type then 77 */ 78 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClass())) { 79 /* If T is a class type, then this must be the same class as T, 80 or this must be a subclass of T; 81 */ 82 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 83 if (this.equals(T)) 84 return true; 85 86 if (Repository.instanceOf(((ObjectType) this).getClassName(), 87 ((ObjectType) T).getClassName())) 88 return true; 89 } 90 91 /* If T is an interface type, this must implement interface T. 92 */ 93 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 94 if (Repository.implementationOf(((ObjectType) this).getClassName(), 95 ((ObjectType) T).getClassName())) 96 return true; 97 } 98 } 99 100 /* If this is an interface type, then: 101 */ 102 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterface())) { 103 /* If T is a class type, then T must be Object (2.4.7). 104 */ 105 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 106 if (T.equals(Type.OBJECT)) return true; 107 } 108 109 /* If T is an interface type, then T must be the same interface 110 * as this or a superinterface of this (2.13.2). 111 */ 112 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 113 if (this.equals(T)) return true; 114 if (Repository.implementationOf(((ObjectType) this).getClassName(), 115 ((ObjectType) T).getClassName())) 116 return true; 117 } 118 } 119 120 /* If this is an array type, namely, the type SC[], that is, an 121 * array of components of type SC, then: 122 */ 123 if (this instanceof ArrayType) { 124 /* If T is a class type, then T must be Object (2.4.7). 125 */ 126 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { 127 if (T.equals(Type.OBJECT)) return true; 128 } 129 130 /* If T is an array type TC[], that is, an array of components 131 * of type TC, then one of the following must be true: 132 */ 133 if (T instanceof ArrayType) { 134 /* TC and SC are the same primitive type (2.4.1). 135 */ 136 Type sc = ((ArrayType) this).getElementType(); 137 Type tc = ((ArrayType) this).getElementType(); 138 139 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) 140 return true; 141 142 /* TC and SC are reference types (2.4.6), and type SC is 143 * assignable to TC by these runtime rules. 144 */ 145 if (tc instanceof ReferenceType && sc instanceof ReferenceType && 146 ((ReferenceType) sc).isAssignmentCompatibleWith((ReferenceType) tc)) 147 return true; 148 } 149 150 /* If T is an interface type, T must be one of the interfaces implemented by arrays (2.15). */ 151 // TODO: Check if this is still valid or find a way to dynamically find out which 152 // interfaces arrays implement. However, as of the JVM specification edition 2, there 153 // are at least two different pages where assignment compatibility is defined and 154 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or 155 // 'java.io.Serializable'" 156 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { 157 for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) { 158 if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) return true; 159 } 160 } 161 } 162 return false; // default. 163 } 164 165 /** 166 * This commutative operation returns the first common superclass (narrowest ReferenceType 167 * referencing a class, not an interface). 168 * If one of the types is a superclass of the other, the former is returned. 169 * If "this" is Type.NULL, then t is returned. 170 * If t is Type.NULL, then "this" is returned. 171 * If "this" equals t ['this.equals(t)'] "this" is returned. 172 * If "this" or t is an ArrayType, then Type.OBJECT is returned; 173 * unless their dimensions match. Then an ArrayType of the same 174 * number of dimensions is returned, with its basic type being the 175 * first common super class of the basic types of "this" and t. 176 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 177 * If not all of the two classes' superclasses cannot be found, "null" is returned. 178 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 179 */ 180 public ReferenceType getFirstCommonSuperclass(ReferenceType t) { 181 if (this.equals(Type.NULL)) return t; 182 if (t.equals(Type.NULL)) return this; 183 if (this.equals(t)) return this; 184 /* 185 * TODO: Above sounds a little arbitrary. On the other hand, there is 186 * no object referenced by Type.NULL so we can also say all the objects 187 * referenced by Type.NULL were derived from java.lang.Object. 188 * However, the Java Language's "instanceof" operator proves us wrong: 189 * "null" is not referring to an instance of java.lang.Object :) 190 */ 191 192 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ 193 194 if ((this instanceof ArrayType) && (t instanceof ArrayType)) { 195 ArrayType arrType1 = (ArrayType) this; 196 ArrayType arrType2 = (ArrayType) t; 197 if ( 198 (arrType1.getDimensions() == arrType2.getDimensions()) && 199 arrType1.getBasicType() instanceof ObjectType && 200 arrType2.getBasicType() instanceof ObjectType) { 201 return new ArrayType( 202 ((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), 203 arrType1.getDimensions() 204 ); 205 206 } 207 } 208 209 if ((this instanceof ArrayType) || (t instanceof ArrayType)) 210 return Type.OBJECT; 211 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? 212 213 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || 214 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) 215 return Type.OBJECT; 216 // TODO: The above line is correct comparing to the vmspec2. But one could 217 // make class file verification a bit stronger here by using the notion of 218 // superinterfaces or even castability or assignment compatibility. 219 220 221 // this and t are ObjectTypes, see above. 222 ObjectType thiz = (ObjectType) this; 223 ObjectType other = (ObjectType) t; 224 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); 225 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); 226 227 if ((thiz_sups == null) || (other_sups == null)) { 228 return null; 229 } 230 231 // Waaahh... 232 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; 233 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; 234 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); 235 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); 236 this_sups[0] = Repository.lookupClass(thiz.getClassName()); 237 t_sups[0] = Repository.lookupClass(other.getClassName()); 238 239 for (int i = 0; i < t_sups.length; i++) { 240 for (int j = 0; j < this_sups.length; j++) { 241 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); 242 } 243 } 244 245 // Huh? Did you ask for Type.OBJECT's superclass?? 246 return null; 247 } 248 249 /** 250 * This commutative operation returns the first common superclass (narrowest ReferenceType 251 * referencing a class, not an interface). 252 * If one of the types is a superclass of the other, the former is returned. 253 * If "this" is Type.NULL, then t is returned. 254 * If t is Type.NULL, then "this" is returned. 255 * If "this" equals t ['this.equals(t)'] "this" is returned. 256 * If "this" or t is an ArrayType, then Type.OBJECT is returned. 257 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. 258 * If not all of the two classes' superclasses cannot be found, "null" is returned. 259 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". 260 * 261 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has 262 * slightly changed semantics. 263 */ 264 @Deprecated 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 }