View Javadoc
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 }