• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * instanceof, checkcast, etc.
18  */
19 #include "Dalvik.h"
20 
21 #include <stdlib.h>
22 
23 /*
24  * I think modern C mandates that the results of a boolean expression are
25  * 0 or 1.  If not, or we suddenly turn into C++ and bool != int, use this.
26  */
27 #define BOOL_TO_INT(x)  (x)
28 //#define BOOL_TO_INT(x)  ((x) ? 1 : 0)
29 
30 /*
31  * Number of entries in instanceof cache.  MUST be a power of 2.
32  */
33 #define INSTANCEOF_CACHE_SIZE   1024
34 
35 
36 /*
37  * Allocate cache.
38  */
dvmInstanceofStartup(void)39 bool dvmInstanceofStartup(void)
40 {
41     gDvm.instanceofCache = dvmAllocAtomicCache(INSTANCEOF_CACHE_SIZE);
42     if (gDvm.instanceofCache == NULL)
43         return false;
44     return true;
45 }
46 
47 /*
48  * Discard the cache.
49  */
dvmInstanceofShutdown(void)50 void dvmInstanceofShutdown(void)
51 {
52     dvmFreeAtomicCache(gDvm.instanceofCache);
53 }
54 
55 
56 /*
57  * Determine whether "sub" is an instance of "clazz", where both of these
58  * are array classes.
59  *
60  * Consider an array class, e.g. Y[][], where Y is a subclass of X.
61  *   Y[][] instanceof Y[][]        --> true (identity)
62  *   Y[][] instanceof X[][]        --> true (element superclass)
63  *   Y[][] instanceof Y            --> false
64  *   Y[][] instanceof Y[]          --> false
65  *   Y[][] instanceof Object       --> true (everything is an object)
66  *   Y[][] instanceof Object[]     --> true
67  *   Y[][] instanceof Object[][]   --> true
68  *   Y[][] instanceof Object[][][] --> false (too many []s)
69  *   Y[][] instanceof Serializable     --> true (all arrays are Serializable)
70  *   Y[][] instanceof Serializable[]   --> true
71  *   Y[][] instanceof Serializable[][] --> false (unless Y is Serializable)
72  *
73  * Don't forget about primitive types.
74  *   int[] instanceof Object[]     --> false
75  *
76  * "subElemClass" is sub->elementClass.
77  *
78  * "subDim" is usually just sub->dim, but for some kinds of checks we want
79  * to pass in a non-array class and pretend that it's an array.
80  */
isArrayInstanceOfArray(const ClassObject * subElemClass,int subDim,const ClassObject * clazz)81 static int isArrayInstanceOfArray(const ClassObject* subElemClass, int subDim,
82     const ClassObject* clazz)
83 {
84     //assert(dvmIsArrayClass(sub));
85     assert(dvmIsArrayClass(clazz));
86 
87     /* "If T is an array type TC[]... one of the following must be true:
88      *   TC and SC are the same primitive type.
89      *   TC and SC are reference types and type SC can be cast to TC [...]."
90      *
91      * We need the class objects for the array elements.  For speed we
92      * tucked them into the class object.
93      */
94     assert(subDim > 0 && clazz->arrayDim > 0);
95     if (subDim == clazz->arrayDim) {
96         /*
97          * See if "sub" is an instance of "clazz".  This handles the
98          * interfaces, java.lang.Object, superclassing, etc.
99          */
100         return dvmInstanceof(subElemClass, clazz->elementClass);
101     } else if (subDim > clazz->arrayDim) {
102         /*
103          * The thing we might be an instance of has fewer dimensions.  It
104          * must be an Object or array of Object, or a standard array
105          * interface or array of standard array interfaces (the standard
106          * interfaces being java/lang/Cloneable and java/io/Serializable).
107          */
108         if (dvmIsInterfaceClass(clazz->elementClass)) {
109             /*
110              * See if the class implements its base element.  We know the
111              * base element is an interface; if the array class implements
112              * it, we know it's a standard array interface.
113              */
114             return dvmImplements(clazz, clazz->elementClass);
115         } else {
116             /*
117              * See if this is an array of Object, Object[], etc.  We know
118              * that the superclass of an array is always Object, so we
119              * just compare the element type to that.
120              */
121             return (clazz->elementClass == clazz->super);
122         }
123     } else {
124         /*
125          * Too many []s.
126          */
127         return false;
128     }
129 }
130 
131 /*
132  * Determine whether "sub" is a sub-class of "clazz", where "sub" is an
133  * array class.
134  *
135  * "clazz" could be an array class, interface, or simple class.
136  */
isArrayInstanceOf(const ClassObject * sub,const ClassObject * clazz)137 static int isArrayInstanceOf(const ClassObject* sub, const ClassObject* clazz)
138 {
139     assert(dvmIsArrayClass(sub));
140 
141     /* "If T is an interface type, T must be one of the interfaces
142      * implemented by arrays."
143      *
144      * I'm not checking that here, because dvmInstanceof tests for
145      * interfaces first, and the generic dvmImplements stuff should
146      * work correctly.
147      */
148     assert(!dvmIsInterfaceClass(clazz));     /* make sure */
149 
150     /* "If T is a class type, then T must be Object."
151      *
152      * The superclass of an array is always java.lang.Object, so just
153      * compare against that.
154      */
155     if (!dvmIsArrayClass(clazz))
156         return BOOL_TO_INT(clazz == sub->super);
157 
158     /*
159      * If T is an array type TC[] ...
160      */
161     return isArrayInstanceOfArray(sub->elementClass, sub->arrayDim, clazz);
162 }
163 
164 
165 /*
166  * Returns 1 (true) if "clazz" is an implementation of "interface".
167  *
168  * "clazz" could be a class or an interface.
169  */
dvmImplements(const ClassObject * clazz,const ClassObject * interface)170 int dvmImplements(const ClassObject* clazz, const ClassObject* interface)
171 {
172     int i;
173 
174     assert(dvmIsInterfaceClass(interface));
175 
176     /*
177      * All interfaces implemented directly and by our superclass, and
178      * recursively all super-interfaces of those interfaces, are listed
179      * in "iftable", so we can just do a linear scan through that.
180      */
181     for (i = 0; i < clazz->iftableCount; i++) {
182         if (clazz->iftable[i].clazz == interface)
183             return 1;
184     }
185 
186     return 0;
187 }
188 
189 /*
190  * Determine whether or not we can put an object into an array, based on
191  * the class hierarchy.  The object might itself by an array, which means
192  * we have to pay attention to the array instanceof rules.
193  *
194  * Note that "objectClass" could be an array, but objectClass->elementClass
195  * is always a non-array type.
196  */
dvmCanPutArrayElement(const ClassObject * objectClass,const ClassObject * arrayClass)197 bool dvmCanPutArrayElement(const ClassObject* objectClass,
198     const ClassObject* arrayClass)
199 {
200     if (dvmIsArrayClass(objectClass)) {
201         /*
202          * We're stuffing an array into an array.  We want to see if the
203          * elements of "arrayClass" are compatible with "objectClass".
204          * We bump up the number of dimensions in "objectClass" so that we
205          * can compare the two directly.
206          */
207         return isArrayInstanceOfArray(objectClass->elementClass,
208                     objectClass->arrayDim + 1, arrayClass);
209     } else {
210         /*
211          * We're putting a non-array element into an array.  We need to
212          * test to see if the elements are compatible.  The easiest way
213          * to do that is to "arrayify" it and use the standard array
214          * compatibility check.
215          */
216         return isArrayInstanceOfArray(objectClass, 1, arrayClass);
217     }
218 }
219 
220 
221 /*
222  * Perform the instanceof calculation.
223  */
isInstanceof(const ClassObject * instance,const ClassObject * clazz)224 static inline int isInstanceof(const ClassObject* instance,
225     const ClassObject* clazz)
226 {
227     if (dvmIsInterfaceClass(clazz)) {
228         return dvmImplements(instance, clazz);
229     } else if (dvmIsArrayClass(instance)) {
230         return isArrayInstanceOf(instance, clazz);
231     } else {
232         return dvmIsSubClass(instance, clazz);
233     }
234 }
235 
236 
237 /*
238  * Do the instanceof calculation, pulling the result from the cache if
239  * possible.
240  */
dvmInstanceofNonTrivial(const ClassObject * instance,const ClassObject * clazz)241 int dvmInstanceofNonTrivial(const ClassObject* instance,
242     const ClassObject* clazz)
243 {
244 #define ATOMIC_CACHE_CALC isInstanceof(instance, clazz)
245     return ATOMIC_CACHE_LOOKUP(gDvm.instanceofCache,
246                 INSTANCEOF_CACHE_SIZE, instance, clazz);
247 #undef ATOMIC_CACHE_CALC
248 }
249 
250