Home | History | Annotate | Download | only in oo
      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  */
     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  */
     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  */
     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     /*
     94      * Find a field with a matching name and signature.  As with instance
     95      * fields, the VM allows you to have two fields with the same name so
     96      * long as they have different types.
     97      */
     98     pField = clazz->sfields;
     99     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
    100         if (strcmp(fieldName, pField->field.name) == 0 &&
    101             strcmp(signature, pField->field.signature) == 0)
    102         {
    103             return pField;
    104         }
    105     }
    106 
    107     return NULL;
    108 }
    109 
    110 /*
    111  * Find a matching field, in this class or a superclass.
    112  *
    113  * Returns NULL if the field can't be found.  (Does not throw an exception.)
    114  */
    115 StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
    116     const char* fieldName, const char* signature)
    117 {
    118     StaticField* pField;
    119 
    120     /*
    121      * Search for a match in the current class.
    122      */
    123     pField = dvmFindStaticField(clazz, fieldName, signature);
    124     if (pField != NULL)
    125         return pField;
    126 
    127     /*
    128      * See if it's in any of our interfaces.  We don't check interfaces
    129      * inherited from the superclass yet.
    130      *
    131      * (Note the set may have been stripped down because of redundancy with
    132      * the superclass; see notes in createIftable.)
    133      */
    134     int i = 0;
    135     if (clazz->super != NULL) {
    136         assert(clazz->iftableCount >= clazz->super->iftableCount);
    137         i = clazz->super->iftableCount;
    138     }
    139     for ( ; i < clazz->iftableCount; i++) {
    140         ClassObject* iface = clazz->iftable[i].clazz;
    141         pField = dvmFindStaticField(iface, fieldName, signature);
    142         if (pField != NULL)
    143             return pField;
    144     }
    145 
    146     if (clazz->super != NULL)
    147         return dvmFindStaticFieldHier(clazz->super, fieldName, signature);
    148     else
    149         return NULL;
    150 }
    151 
    152 /*
    153  * Find a matching field, in this class or a superclass.
    154  *
    155  * We scan both the static and instance field lists in the class.  If it's
    156  * not found there, we check the direct interfaces, and then recursively
    157  * scan the superclasses.  This is the order prescribed in the VM spec
    158  * (v2 5.4.3.2).
    159  *
    160  * In most cases we know that we're looking for either a static or an
    161  * instance field and there's no value in searching through both types.
    162  * During verification we need to recognize and reject certain unusual
    163  * situations, and we won't see them unless we walk the lists this way.
    164  */
    165 Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName,
    166     const char* signature)
    167 {
    168     Field* pField;
    169 
    170     /*
    171      * Search for a match in the current class.  Which set we scan first
    172      * doesn't really matter.
    173      */
    174     pField = (Field*) dvmFindStaticField(clazz, fieldName, signature);
    175     if (pField != NULL)
    176         return pField;
    177     pField = (Field*) dvmFindInstanceField(clazz, fieldName, signature);
    178     if (pField != NULL)
    179         return pField;
    180 
    181     /*
    182      * See if it's in any of our interfaces.  We don't check interfaces
    183      * inherited from the superclass yet.
    184      */
    185     int i = 0;
    186     if (clazz->super != NULL) {
    187         assert(clazz->iftableCount >= clazz->super->iftableCount);
    188         i = clazz->super->iftableCount;
    189     }
    190     for ( ; i < clazz->iftableCount; i++) {
    191         ClassObject* iface = clazz->iftable[i].clazz;
    192         pField = (Field*) dvmFindStaticField(iface, fieldName, signature);
    193         if (pField != NULL)
    194             return pField;
    195     }
    196 
    197     if (clazz->super != NULL)
    198         return dvmFindFieldHier(clazz->super, fieldName, signature);
    199     else
    200         return NULL;
    201 }
    202 
    203 
    204 /*
    205  * Compare the given name, return type, and argument types with the contents
    206  * of the given method. This returns 0 if they are equal and non-zero if not.
    207  */
    208 static inline int compareMethodHelper(Method* method, const char* methodName,
    209     const char* returnType, size_t argCount, const char** argTypes)
    210 {
    211     DexParameterIterator iterator;
    212     const DexProto* proto;
    213 
    214     if (strcmp(methodName, method->name) != 0) {
    215         return 1;
    216     }
    217 
    218     proto = &method->prototype;
    219 
    220     if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
    221         return 1;
    222     }
    223 
    224     if (dexProtoGetParameterCount(proto) != argCount) {
    225         return 1;
    226     }
    227 
    228     dexParameterIteratorInit(&iterator, proto);
    229 
    230     for (/*argCount*/; argCount != 0; argCount--, argTypes++) {
    231         const char* argType = *argTypes;
    232         const char* paramType = dexParameterIteratorNextDescriptor(&iterator);
    233 
    234         if (paramType == NULL) {
    235             /* Param list ended early; no match */
    236             break;
    237         } else if (strcmp(argType, paramType) != 0) {
    238             /* Types aren't the same; no match. */
    239             break;
    240         }
    241     }
    242 
    243     if (argCount == 0) {
    244         /* We ran through all the given arguments... */
    245         if (dexParameterIteratorNextDescriptor(&iterator) == NULL) {
    246             /* ...and through all the method's arguments; success! */
    247             return 0;
    248         }
    249     }
    250 
    251     return 1;
    252 }
    253 
    254 /*
    255  * Get the count of arguments in the given method descriptor string,
    256  * and also find a pointer to the return type.
    257  */
    258 static inline size_t countArgsAndFindReturnType(const char* descriptor,
    259     const char** pReturnType)
    260 {
    261     size_t count = 0;
    262     bool bogus = false;
    263     bool done = false;
    264 
    265     assert(*descriptor == '(');
    266     descriptor++;
    267 
    268     while (!done) {
    269         switch (*descriptor) {
    270             case 'B': case 'C': case 'D': case 'F':
    271             case 'I': case 'J': case 'S': case 'Z': {
    272                 count++;
    273                 break;
    274             }
    275             case '[': {
    276                 do {
    277                     descriptor++;
    278                 } while (*descriptor == '[');
    279                 /*
    280                  * Don't increment count, as it will be taken care of
    281                  * by the next iteration. Also, decrement descriptor
    282                  * to compensate for the increment below the switch.
    283                  */
    284                 descriptor--;
    285                 break;
    286             }
    287             case 'L': {
    288                 do {
    289                     descriptor++;
    290                 } while ((*descriptor != ';') && (*descriptor != '\0'));
    291                 count++;
    292                 if (*descriptor == '\0') {
    293                     /* Bogus descriptor. */
    294                     done = true;
    295                     bogus = true;
    296                 }
    297                 break;
    298             }
    299             case ')': {
    300                 /*
    301                  * Note: The loop will exit after incrementing descriptor
    302                  * one more time, so it then points at the return type.
    303                  */
    304                 done = true;
    305                 break;
    306             }
    307             default: {
    308                 /* Bogus descriptor. */
    309                 done = true;
    310                 bogus = true;
    311                 break;
    312             }
    313         }
    314 
    315         descriptor++;
    316     }
    317 
    318     if (bogus) {
    319         *pReturnType = NULL;
    320         return 0;
    321     }
    322 
    323     *pReturnType = descriptor;
    324     return count;
    325 }
    326 
    327 /*
    328  * Copy the argument types into the given array using the given buffer
    329  * for the contents.
    330  */
    331 static inline void copyTypes(char* buffer, const char** argTypes,
    332     size_t argCount, const char* descriptor)
    333 {
    334     size_t i;
    335     char c;
    336 
    337     /* Skip the '('. */
    338     descriptor++;
    339 
    340     for (i = 0; i < argCount; i++) {
    341         argTypes[i] = buffer;
    342 
    343         /* Copy all the array markers and one extra character. */
    344         do {
    345             c = *(descriptor++);
    346             *(buffer++) = c;
    347         } while (c == '[');
    348 
    349         if (c == 'L') {
    350             /* Copy the rest of a class name. */
    351             do {
    352                 c = *(descriptor++);
    353                 *(buffer++) = c;
    354             } while (c != ';');
    355         }
    356 
    357         *(buffer++) = '\0';
    358     }
    359 }
    360 
    361 /*
    362  * Look for a match in the given class. Returns the match if found
    363  * or NULL if not.
    364  */
    365 static Method* findMethodInListByDescriptor(const ClassObject* clazz,
    366     bool findVirtual, bool isHier, const char* name, const char* descriptor)
    367 {
    368     const char* returnType;
    369     size_t argCount = countArgsAndFindReturnType(descriptor, &returnType);
    370 
    371     if (returnType == NULL) {
    372         LOGW("Bogus method descriptor: %s\n", descriptor);
    373         return NULL;
    374     }
    375 
    376     /*
    377      * Make buffer big enough for all the argument type characters and
    378      * one '\0' per argument. The "- 2" is because "returnType -
    379      * descriptor" includes two parens.
    380      */
    381     char buffer[argCount + (returnType - descriptor) - 2];
    382     const char* argTypes[argCount];
    383 
    384     copyTypes(buffer, argTypes, argCount, descriptor);
    385 
    386     while (clazz != NULL) {
    387         Method* methods;
    388         size_t methodCount;
    389         size_t i;
    390 
    391         if (findVirtual) {
    392             methods = clazz->virtualMethods;
    393             methodCount = clazz->virtualMethodCount;
    394         } else {
    395             methods = clazz->directMethods;
    396             methodCount = clazz->directMethodCount;
    397         }
    398 
    399         for (i = 0; i < methodCount; i++) {
    400             Method* method = &methods[i];
    401             if (compareMethodHelper(method, name, returnType, argCount,
    402                             argTypes) == 0) {
    403                 return method;
    404             }
    405         }
    406 
    407         if (! isHier) {
    408             break;
    409         }
    410 
    411         clazz = clazz->super;
    412     }
    413 
    414     return NULL;
    415 }
    416 
    417 /*
    418  * Look for a match in the given clazz. Returns the match if found
    419  * or NULL if not.
    420  *
    421  * "wantedType" should be METHOD_VIRTUAL or METHOD_DIRECT to indicate the
    422  * list to search through.  If the match can come from either list, use
    423  * MATCH_UNKNOWN to scan both.
    424  */
    425 static Method* findMethodInListByProto(const ClassObject* clazz,
    426     MethodType wantedType, bool isHier, const char* name, const DexProto* proto)
    427 {
    428     while (clazz != NULL) {
    429         int i;
    430 
    431         /*
    432          * Check the virtual and/or direct method lists.
    433          */
    434         if (wantedType == METHOD_VIRTUAL || wantedType == METHOD_UNKNOWN) {
    435             for (i = 0; i < clazz->virtualMethodCount; i++) {
    436                 Method* method = &clazz->virtualMethods[i];
    437                 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
    438                     return method;
    439                 }
    440             }
    441         }
    442         if (wantedType == METHOD_DIRECT || wantedType == METHOD_UNKNOWN) {
    443             for (i = 0; i < clazz->directMethodCount; i++) {
    444                 Method* method = &clazz->directMethods[i];
    445                 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
    446                     return method;
    447                 }
    448             }
    449         }
    450 
    451         if (! isHier) {
    452             break;
    453         }
    454 
    455         clazz = clazz->super;
    456     }
    457 
    458     return NULL;
    459 }
    460 
    461 /*
    462  * Find a "virtual" method in a class.
    463  *
    464  * Does not chase into the superclass.
    465  *
    466  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    467  */
    468 Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
    469     const char* methodName, const char* descriptor)
    470 {
    471     return findMethodInListByDescriptor(clazz, true, false,
    472             methodName, descriptor);
    473 
    474     // TODO? - throw IncompatibleClassChangeError if a match is
    475     // found in the directMethods list, rather than NotFoundError.
    476     // Note we could have been called by dvmFindVirtualMethodHier though.
    477 }
    478 
    479 
    480 /*
    481  * Find a "virtual" method in a class, knowing only the name.  This is
    482  * only useful in limited circumstances, e.g. when searching for a member
    483  * of an annotation class.
    484  *
    485  * Does not chase into the superclass.
    486  *
    487  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    488  */
    489 Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
    490     const char* methodName)
    491 {
    492     Method* methods = clazz->virtualMethods;
    493     int methodCount = clazz->virtualMethodCount;
    494     int i;
    495 
    496     for (i = 0; i < methodCount; i++) {
    497         if (strcmp(methods[i].name, methodName) == 0)
    498             return &methods[i];
    499     }
    500 
    501     return NULL;
    502 }
    503 
    504 /*
    505  * Find a "virtual" method in a class.
    506  *
    507  * Does not chase into the superclass.
    508  *
    509  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    510  */
    511 Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
    512     const DexProto* proto)
    513 {
    514     return findMethodInListByProto(clazz, METHOD_VIRTUAL, false, methodName,
    515             proto);
    516 }
    517 
    518 /*
    519  * Find a "virtual" method in a class.  If we don't find it, try the
    520  * superclass.
    521  *
    522  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    523  */
    524 Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
    525     const char* methodName, const char* descriptor)
    526 {
    527     return findMethodInListByDescriptor(clazz, true, true,
    528             methodName, descriptor);
    529 }
    530 
    531 /*
    532  * Find a "virtual" method in a class.  If we don't find it, try the
    533  * superclass.
    534  *
    535  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    536  */
    537 Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
    538     const char* methodName, const DexProto* proto)
    539 {
    540     return findMethodInListByProto(clazz, METHOD_VIRTUAL, true, methodName,
    541             proto);
    542 }
    543 
    544 /*
    545  * Find a "direct" method (static, private, or "<*init>").
    546  *
    547  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    548  */
    549 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
    550     const char* methodName, const char* descriptor)
    551 {
    552     return findMethodInListByDescriptor(clazz, false, false,
    553             methodName, descriptor);
    554 }
    555 
    556 /*
    557  * Find a "direct" method.  If we don't find it, try the superclass.  This
    558  * is only appropriate for static methods, but will work for all direct
    559  * methods.
    560  *
    561  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    562  */
    563 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
    564     const char* methodName, const char* descriptor)
    565 {
    566     return findMethodInListByDescriptor(clazz, false, true,
    567             methodName, descriptor);
    568 }
    569 
    570 /*
    571  * Find a "direct" method (static or "<*init>").
    572  *
    573  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    574  */
    575 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
    576     const DexProto* proto)
    577 {
    578     return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName,
    579             proto);
    580 }
    581 
    582 /*
    583  * Find a "direct" method in a class.  If we don't find it, try the
    584  * superclass.
    585  *
    586  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    587  */
    588 Method* dvmFindDirectMethodHier(const ClassObject* clazz,
    589     const char* methodName, const DexProto* proto)
    590 {
    591     return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName,
    592             proto);
    593 }
    594 
    595 /*
    596  * Find a virtual or static method in a class.  If we don't find it, try the
    597  * superclass.  This is compatible with the VM spec (v2 5.4.3.3) method
    598  * search order, but it stops short of scanning through interfaces (which
    599  * should be done after this function completes).
    600  *
    601  * In most cases we know that we're looking for either a static or an
    602  * instance field and there's no value in searching through both types.
    603  * During verification we need to recognize and reject certain unusual
    604  * situations, and we won't see them unless we walk the lists this way.
    605  *
    606  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    607  */
    608 Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
    609     const DexProto* proto)
    610 {
    611     return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName,
    612             proto);
    613 }
    614 
    615 
    616 /*
    617  * We have a method pointer for a method in "clazz", but it might be
    618  * pointing to a method in a derived class.  We want to find the actual entry
    619  * from the class' vtable.  If "clazz" is an interface, we have to do a
    620  * little more digging.
    621  *
    622  * (This is used for reflection and JNI "call method" calls.)
    623  */
    624 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
    625     const Method* meth)
    626 {
    627     Method* actualMeth;
    628     int methodIndex;
    629 
    630     assert(!dvmIsStaticMethod(meth));
    631 
    632     if (dvmIsPrivateMethod(meth))   // no vtable entry for these
    633         return meth;
    634 
    635     /*
    636      * If the method was declared in an interface, we need to scan through
    637      * the class' list of interfaces for it, and find the vtable index
    638      * from that.
    639      *
    640      * TODO: use the interface cache.
    641      */
    642     if (dvmIsInterfaceClass(meth->clazz)) {
    643         int i;
    644 
    645         for (i = 0; i < clazz->iftableCount; i++) {
    646             if (clazz->iftable[i].clazz == meth->clazz)
    647                 break;
    648         }
    649         if (i == clazz->iftableCount) {
    650             dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
    651                 "invoking method from interface not implemented by class");
    652             return NULL;
    653         }
    654 
    655         methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
    656     } else {
    657         methodIndex = meth->methodIndex;
    658     }
    659 
    660     assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
    661     actualMeth = clazz->vtable[methodIndex];
    662 
    663     /*
    664      * Make sure there's code to execute.
    665      */
    666     if (dvmIsAbstractMethod(actualMeth)) {
    667         dvmThrowException("Ljava/lang/AbstractMethodError;", NULL);
    668         return NULL;
    669     }
    670     assert(!dvmIsMirandaMethod(actualMeth));
    671 
    672     return actualMeth;
    673 }
    674 
    675 /*
    676  * Get the source file for a method.
    677  */
    678 const char* dvmGetMethodSourceFile(const Method* meth)
    679 {
    680     /*
    681      * TODO: A method's debug info can override the default source
    682      * file for a class, so we should account for that possibility
    683      * here.
    684      */
    685     return meth->clazz->sourceFile;
    686 }
    687 
    688 /*
    689  * Dump some information about an object.
    690  */
    691 void dvmDumpObject(const Object* obj)
    692 {
    693     ClassObject* clazz;
    694     int i;
    695 
    696     if (obj == NULL || obj->clazz == NULL) {
    697         LOGW("Null or malformed object not dumped\n");
    698         return;
    699     }
    700 
    701     clazz = obj->clazz;
    702     LOGD("----- Object dump: %p (%s, %d bytes) -----\n",
    703         obj, clazz->descriptor, (int) clazz->objectSize);
    704     //printHexDump(obj, clazz->objectSize);
    705     LOGD("  Fields:\n");
    706     while (clazz != NULL) {
    707         LOGD("    -- %s\n", clazz->descriptor);
    708         for (i = 0; i < clazz->ifieldCount; i++) {
    709             const InstField* pField = &clazz->ifields[i];
    710             char type = pField->field.signature[0];
    711 
    712             if (type == 'F' || type == 'D') {
    713                 double dval;
    714 
    715                 if (type == 'F')
    716                     dval = dvmGetFieldFloat(obj, pField->byteOffset);
    717                 else
    718                     dval = dvmGetFieldDouble(obj, pField->byteOffset);
    719 
    720                 LOGD("    %2d: '%s' '%s' af=%04x off=%d %.3f\n", i,
    721                     pField->field.name, pField->field.signature,
    722                     pField->field.accessFlags, pField->byteOffset, dval);
    723             } else {
    724                 u8 lval;
    725 
    726                 if (type == 'J')
    727                     lval = dvmGetFieldLong(obj, pField->byteOffset);
    728                 else if (type == 'Z')
    729                     lval = dvmGetFieldBoolean(obj, pField->byteOffset);
    730                 else
    731                     lval = dvmGetFieldInt(obj, pField->byteOffset);
    732 
    733                 LOGD("    %2d: '%s' '%s' af=%04x off=%d 0x%08llx\n", i,
    734                     pField->field.name, pField->field.signature,
    735                     pField->field.accessFlags, pField->byteOffset, lval);
    736             }
    737         }
    738 
    739         clazz = clazz->super;
    740     }
    741 }
    742 
    743