• 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 /*
18  * Operations on an Object.
19  */
20 #include "Dalvik.h"
21 
22 /*
23  * Find a matching field, in the current class only.
24  *
25  * Returns NULL if the field can't be found.  (Does not throw an exception.)
26  */
dvmFindInstanceField(const ClassObject * clazz,const char * fieldName,const char * signature)27 InstField* dvmFindInstanceField(const ClassObject* clazz,
28     const char* fieldName, const char* signature)
29 {
30     InstField* pField;
31     int i;
32 
33     assert(clazz != NULL);
34 
35     /*
36      * Find a field with a matching name and signature.  The Java programming
37      * language does not allow you to have two fields with the same name
38      * and different types, but the Java VM spec does allow it, so we can't
39      * bail out early when the name matches.
40      */
41     pField = clazz->ifields;
42     for (i = 0; i < clazz->ifieldCount; i++, pField++) {
43         if (strcmp(fieldName, pField->field.name) == 0 &&
44             strcmp(signature, pField->field.signature) == 0)
45         {
46             return pField;
47         }
48     }
49 
50     return NULL;
51 }
52 
53 /*
54  * Find a matching field, in this class or a superclass.
55  *
56  * Searching through interfaces isn't necessary, because interface fields
57  * are inherently public/static/final.
58  *
59  * Returns NULL if the field can't be found.  (Does not throw an exception.)
60  */
dvmFindInstanceFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)61 InstField* dvmFindInstanceFieldHier(const ClassObject* clazz,
62     const char* fieldName, const char* signature)
63 {
64     InstField* pField;
65 
66     /*
67      * Search for a match in the current class.
68      */
69     pField = dvmFindInstanceField(clazz, fieldName, signature);
70     if (pField != NULL)
71         return pField;
72 
73     if (clazz->super != NULL)
74         return dvmFindInstanceFieldHier(clazz->super, fieldName, signature);
75     else
76         return NULL;
77 }
78 
79 
80 /*
81  * Find a matching field, in this class or an interface.
82  *
83  * Returns NULL if the field can't be found.  (Does not throw an exception.)
84  */
dvmFindStaticField(const ClassObject * clazz,const char * fieldName,const char * signature)85 StaticField* dvmFindStaticField(const ClassObject* clazz,
86     const char* fieldName, const char* signature)
87 {
88     StaticField* pField;
89     int i;
90 
91     assert(clazz != NULL);
92 
93     pField = clazz->sfields;
94     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
95         if (strcmp(fieldName, pField->field.name) == 0) {
96             /*
97              * The name matches.  Unlike methods, we can't have two fields
98              * with the same names but differing types.
99              */
100             if (strcmp(signature, pField->field.signature) != 0) {
101                 LOGW("Found field '%s', but sig is '%s' not '%s'\n",
102                     fieldName, pField->field.signature, signature);
103                 return NULL;
104             }
105             return pField;
106         }
107     }
108 
109     return NULL;
110 }
111 
112 /*
113  * Find a matching field, in this class or a superclass.
114  *
115  * Returns NULL if the field can't be found.  (Does not throw an exception.)
116  */
dvmFindStaticFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)117 StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
118     const char* fieldName, const char* signature)
119 {
120     StaticField* pField;
121 
122     /*
123      * Search for a match in the current class.
124      */
125     pField = dvmFindStaticField(clazz, fieldName, signature);
126     if (pField != NULL)
127         return pField;
128 
129     /*
130      * See if it's in any of our interfaces.  We don't check interfaces
131      * inherited from the superclass yet.
132      *
133      * (Note the set may have been stripped down because of redundancy with
134      * the superclass; see notes in createIftable.)
135      */
136     int i = 0;
137     if (clazz->super != NULL) {
138         assert(clazz->iftableCount >= clazz->super->iftableCount);
139         i = clazz->super->iftableCount;
140     }
141     for ( ; i < clazz->iftableCount; i++) {
142         ClassObject* iface = clazz->iftable[i].clazz;
143         pField = dvmFindStaticField(iface, fieldName, signature);
144         if (pField != NULL)
145             return pField;
146     }
147 
148     if (clazz->super != NULL)
149         return dvmFindStaticFieldHier(clazz->super, fieldName, signature);
150     else
151         return NULL;
152 }
153 
154 /*
155  * Compare the given name, return type, and argument types with the contents
156  * of the given method. This returns 0 if they are equal and non-zero if not.
157  */
compareMethodHelper(Method * method,const char * methodName,const char * returnType,size_t argCount,const char ** argTypes)158 static inline int compareMethodHelper(Method* method, const char* methodName,
159     const char* returnType, size_t argCount, const char** argTypes)
160 {
161     DexParameterIterator iterator;
162     const DexProto* proto;
163 
164     if (strcmp(methodName, method->name) != 0) {
165         return 1;
166     }
167 
168     proto = &method->prototype;
169 
170     if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
171         return 1;
172     }
173 
174     if (dexProtoGetParameterCount(proto) != argCount) {
175         return 1;
176     }
177 
178     dexParameterIteratorInit(&iterator, proto);
179 
180     for (/*argCount*/; argCount != 0; argCount--, argTypes++) {
181         const char* argType = *argTypes;
182         const char* paramType = dexParameterIteratorNextDescriptor(&iterator);
183 
184         if (paramType == NULL) {
185             /* Param list ended early; no match */
186             break;
187         } else if (strcmp(argType, paramType) != 0) {
188             /* Types aren't the same; no match. */
189             break;
190         }
191     }
192 
193     if (argCount == 0) {
194         /* We ran through all the given arguments... */
195         if (dexParameterIteratorNextDescriptor(&iterator) == NULL) {
196             /* ...and through all the method's arguments; success! */
197             return 0;
198         }
199     }
200 
201     return 1;
202 }
203 
204 /*
205  * Get the count of arguments in the given method descriptor string,
206  * and also find a pointer to the return type.
207  */
countArgsAndFindReturnType(const char * descriptor,const char ** pReturnType)208 static inline size_t countArgsAndFindReturnType(const char* descriptor,
209     const char** pReturnType)
210 {
211     size_t count = 0;
212     bool bogus = false;
213     bool done = false;
214 
215     assert(*descriptor == '(');
216     descriptor++;
217 
218     while (!done) {
219         switch (*descriptor) {
220             case 'B': case 'C': case 'D': case 'F':
221             case 'I': case 'J': case 'S': case 'Z': {
222                 count++;
223                 break;
224             }
225             case '[': {
226                 do {
227                     descriptor++;
228                 } while (*descriptor == '[');
229                 /*
230                  * Don't increment count, as it will be taken care of
231                  * by the next iteration. Also, decrement descriptor
232                  * to compensate for the increment below the switch.
233                  */
234                 descriptor--;
235                 break;
236             }
237             case 'L': {
238                 do {
239                     descriptor++;
240                 } while ((*descriptor != ';') && (*descriptor != '\0'));
241                 count++;
242                 if (*descriptor == '\0') {
243                     /* Bogus descriptor. */
244                     done = true;
245                     bogus = true;
246                 }
247                 break;
248             }
249             case ')': {
250                 /*
251                  * Note: The loop will exit after incrementing descriptor
252                  * one more time, so it then points at the return type.
253                  */
254                 done = true;
255                 break;
256             }
257             default: {
258                 /* Bogus descriptor. */
259                 done = true;
260                 bogus = true;
261                 break;
262             }
263         }
264 
265         descriptor++;
266     }
267 
268     if (bogus) {
269         *pReturnType = NULL;
270         return 0;
271     }
272 
273     *pReturnType = descriptor;
274     return count;
275 }
276 
277 /*
278  * Copy the argument types into the given array using the given buffer
279  * for the contents.
280  */
copyTypes(char * buffer,const char ** argTypes,size_t argCount,const char * descriptor)281 static inline void copyTypes(char* buffer, const char** argTypes,
282     size_t argCount, const char* descriptor)
283 {
284     size_t i;
285     char c;
286 
287     /* Skip the '('. */
288     descriptor++;
289 
290     for (i = 0; i < argCount; i++) {
291         argTypes[i] = buffer;
292 
293         /* Copy all the array markers and one extra character. */
294         do {
295             c = *(descriptor++);
296             *(buffer++) = c;
297         } while (c == '[');
298 
299         if (c == 'L') {
300             /* Copy the rest of a class name. */
301             do {
302                 c = *(descriptor++);
303                 *(buffer++) = c;
304             } while (c != ';');
305         }
306 
307         *(buffer++) = '\0';
308     }
309 }
310 
311 /*
312  * Look for a match in the given class. Returns the match if found
313  * or NULL if not.
314  */
findMethodInListByDescriptor(const ClassObject * clazz,bool findVirtual,bool isHier,const char * name,const char * descriptor)315 static Method* findMethodInListByDescriptor(const ClassObject* clazz,
316     bool findVirtual, bool isHier, const char* name, const char* descriptor)
317 {
318     const char* returnType;
319     size_t argCount = countArgsAndFindReturnType(descriptor, &returnType);
320 
321     if (returnType == NULL) {
322         LOGW("Bogus method descriptor: %s\n", descriptor);
323         return NULL;
324     }
325 
326     /*
327      * Make buffer big enough for all the argument type characters and
328      * one '\0' per argument. The "- 2" is because "returnType -
329      * descriptor" includes two parens.
330      */
331     char buffer[argCount + (returnType - descriptor) - 2];
332     const char* argTypes[argCount];
333 
334     copyTypes(buffer, argTypes, argCount, descriptor);
335 
336     while (clazz != NULL) {
337         Method* methods;
338         size_t methodCount;
339         size_t i;
340 
341         if (findVirtual) {
342             methods = clazz->virtualMethods;
343             methodCount = clazz->virtualMethodCount;
344         } else {
345             methods = clazz->directMethods;
346             methodCount = clazz->directMethodCount;
347         }
348 
349         for (i = 0; i < methodCount; i++) {
350             Method* method = &methods[i];
351             if (compareMethodHelper(method, name, returnType, argCount,
352                             argTypes) == 0) {
353                 return method;
354             }
355         }
356 
357         if (! isHier) {
358             break;
359         }
360 
361         clazz = clazz->super;
362     }
363 
364     return NULL;
365 }
366 
367 /*
368  * Look for a match in the given clazz. Returns the match if found
369  * or NULL if not.
370  */
findMethodInListByProto(const ClassObject * clazz,bool findVirtual,bool isHier,const char * name,const DexProto * proto)371 static Method* findMethodInListByProto(const ClassObject* clazz,
372     bool findVirtual, bool isHier, const char* name, const DexProto* proto)
373 {
374     while (clazz != NULL) {
375         Method* methods;
376         size_t methodCount;
377         size_t i;
378 
379         if (findVirtual) {
380             methods = clazz->virtualMethods;
381             methodCount = clazz->virtualMethodCount;
382         } else {
383             methods = clazz->directMethods;
384             methodCount = clazz->directMethodCount;
385         }
386 
387         for (i = 0; i < methodCount; i++) {
388             Method* method = &methods[i];
389             if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
390                 return method;
391             }
392         }
393 
394         if (! isHier) {
395             break;
396         }
397 
398         clazz = clazz->super;
399     }
400 
401     return NULL;
402 }
403 
404 /*
405  * Find a "virtual" method in a class.
406  *
407  * Does not chase into the superclass.
408  *
409  * Returns NULL if the method can't be found.  (Does not throw an exception.)
410  */
dvmFindVirtualMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)411 Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
412     const char* methodName, const char* descriptor)
413 {
414     return findMethodInListByDescriptor(clazz, true, false,
415             methodName, descriptor);
416 
417     // TODO? - throw IncompatibleClassChangeError if a match is
418     // found in the directMethods list, rather than NotFoundError.
419     // Note we could have been called by dvmFindVirtualMethodHier though.
420 }
421 
422 
423 /*
424  * Find a "virtual" method in a class, knowing only the name.  This is
425  * only useful in limited circumstances, e.g. when searching for a member
426  * of an annotation class.
427  *
428  * Does not chase into the superclass.
429  *
430  * Returns NULL if the method can't be found.  (Does not throw an exception.)
431  */
dvmFindVirtualMethodByName(const ClassObject * clazz,const char * methodName)432 Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
433     const char* methodName)
434 {
435     Method* methods = clazz->virtualMethods;
436     int methodCount = clazz->virtualMethodCount;
437     int i;
438 
439     for (i = 0; i < methodCount; i++) {
440         if (strcmp(methods[i].name, methodName) == 0)
441             return &methods[i];
442     }
443 
444     return NULL;
445 }
446 
447 /*
448  * Find a "virtual" method in a class.
449  *
450  * Does not chase into the superclass.
451  *
452  * Returns NULL if the method can't be found.  (Does not throw an exception.)
453  */
dvmFindVirtualMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)454 Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
455     const DexProto* proto)
456 {
457     return findMethodInListByProto(clazz, true, false, methodName, proto);
458 }
459 
460 /*
461  * Find a "virtual" method in a class.  If we don't find it, try the
462  * superclass.
463  *
464  * Returns NULL if the method can't be found.  (Does not throw an exception.)
465  */
dvmFindVirtualMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)466 Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
467     const char* methodName, const char* descriptor)
468 {
469     return findMethodInListByDescriptor(clazz, true, true,
470             methodName, descriptor);
471 }
472 
473 /*
474  * Find a "virtual" method in a class.  If we don't find it, try the
475  * superclass.
476  *
477  * Returns NULL if the method can't be found.  (Does not throw an exception.)
478  */
dvmFindVirtualMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)479 Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
480     const char* methodName, const DexProto* proto)
481 {
482     return findMethodInListByProto(clazz, true, true, methodName, proto);
483 }
484 
485 /*
486  * Find a "direct" method (static, private, or "<*init>").
487  *
488  * Returns NULL if the method can't be found.  (Does not throw an exception.)
489  */
dvmFindDirectMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)490 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
491     const char* methodName, const char* descriptor)
492 {
493     return findMethodInListByDescriptor(clazz, false, false,
494             methodName, descriptor);
495 }
496 
497 /*
498  * Find a "direct" method.  If we don't find it, try the superclass.  This
499  * is only appropriate for static methods, but will work for all direct
500  * methods.
501  *
502  * Returns NULL if the method can't be found.  (Does not throw an exception.)
503  */
dvmFindDirectMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)504 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
505     const char* methodName, const char* descriptor)
506 {
507     return findMethodInListByDescriptor(clazz, false, true,
508             methodName, descriptor);
509 }
510 
511 /*
512  * Find a "direct" method (static or "<*init>").
513  *
514  * Returns NULL if the method can't be found.  (Does not throw an exception.)
515  */
dvmFindDirectMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)516 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
517     const DexProto* proto)
518 {
519     return findMethodInListByProto(clazz, false, false, methodName, proto);
520 }
521 
522 /*
523  * Find a "direct" method in a class.  If we don't find it, try the
524  * superclass.
525  *
526  * Returns NULL if the method can't be found.  (Does not throw an exception.)
527  */
dvmFindDirectMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)528 Method* dvmFindDirectMethodHier(const ClassObject* clazz,
529     const char* methodName, const DexProto* proto)
530 {
531     return findMethodInListByProto(clazz, false, true, methodName, proto);
532 }
533 
534 /*
535  * We have a method pointer for a method in "clazz", but it might be
536  * pointing to a method in a derived class.  We want to find the actual entry
537  * from the class' vtable.  If "clazz" is an interface, we have to do a
538  * little more digging.
539  *
540  * (This is used for reflection and JNI "call method" calls.)
541  */
dvmGetVirtualizedMethod(const ClassObject * clazz,const Method * meth)542 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
543     const Method* meth)
544 {
545     Method* actualMeth;
546     int methodIndex;
547 
548     assert(!dvmIsStaticMethod(meth));
549 
550     if (dvmIsPrivateMethod(meth))   // no vtable entry for these
551         return meth;
552 
553     /*
554      * If the method was declared in an interface, we need to scan through
555      * the class' list of interfaces for it, and find the vtable index
556      * from that.
557      *
558      * TODO: use the interface cache.
559      */
560     if (dvmIsInterfaceClass(meth->clazz)) {
561         int i;
562 
563         for (i = 0; i < clazz->iftableCount; i++) {
564             if (clazz->iftable[i].clazz == meth->clazz)
565                 break;
566         }
567         if (i == clazz->iftableCount) {
568             dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
569                 "invoking method from interface not implemented by class");
570             return NULL;
571         }
572 
573         methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
574     } else {
575         methodIndex = meth->methodIndex;
576     }
577 
578     assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
579     actualMeth = clazz->vtable[methodIndex];
580 
581     /*
582      * Make sure there's code to execute.
583      */
584     if (dvmIsAbstractMethod(actualMeth)) {
585         dvmThrowException("Ljava/lang/AbstractMethodError;", NULL);
586         return NULL;
587     }
588     assert(!dvmIsMirandaMethod(actualMeth));
589 
590     return actualMeth;
591 }
592 
593 /*
594  * Get the source file for a method.
595  */
dvmGetMethodSourceFile(const Method * meth)596 const char* dvmGetMethodSourceFile(const Method* meth)
597 {
598     /*
599      * TODO: A method's debug info can override the default source
600      * file for a class, so we should account for that possibility
601      * here.
602      */
603     return meth->clazz->sourceFile;
604 }
605 
606 /*
607  * Dump some information about an object.
608  */
dvmDumpObject(const Object * obj)609 void dvmDumpObject(const Object* obj)
610 {
611     ClassObject* clazz;
612     int i;
613 
614     if (obj == NULL || obj->clazz == NULL) {
615         LOGW("Null or malformed object not dumped\n");
616         return;
617     }
618 
619     clazz = obj->clazz;
620     LOGV("----- Object dump: %p (%s, %d bytes) -----\n",
621         obj, clazz->descriptor, (int) clazz->objectSize);
622     //printHexDump(obj, clazz->objectSize);
623     LOGV("  Fields:\n");
624     for (i = 0; i < clazz->ifieldCount; i++) {
625         const InstField* pField = &clazz->ifields[i];
626         char type = pField->field.signature[0];
627 
628         if (type == 'F' || type == 'D') {
629             double dval;
630 
631             if (type == 'F')
632                 dval = dvmGetFieldFloat(obj, pField->byteOffset);
633             else
634                 dval = dvmGetFieldDouble(obj, pField->byteOffset);
635 
636             LOGV("  %2d: '%s' '%s' flg=%04x %.3f\n", i, pField->field.name,
637                 pField->field.signature, pField->field.accessFlags, dval);
638         } else {
639             long long lval;
640 
641             if (pField->field.signature[0] == 'J')
642                 lval = dvmGetFieldLong(obj, pField->byteOffset);
643             else if (pField->field.signature[0] == 'Z')
644                 lval = dvmGetFieldBoolean(obj, pField->byteOffset);
645             else
646                 lval = dvmGetFieldInt(obj, pField->byteOffset);
647 
648             LOGV("  %2d: '%s' '%s' af=%04x 0x%llx\n", i, pField->field.name,
649                 pField->field.signature, pField->field.accessFlags, lval);
650         }
651     }
652 }
653 
654