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->name) == 0 &&
     44             strcmp(signature, pField->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     const 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[0];
     99     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
    100         if (strcmp(fieldName, pField->name) == 0 &&
    101             strcmp(signature, pField->signature) == 0)
    102         {
    103             return (StaticField*) 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", 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.  Does not examine interfaces.
    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.  Does not examine interfaces.
    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 method in an interface.  Searches superinterfaces.
    546  *
    547  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    548  */
    549 Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
    550     const char* methodName, const char* descriptor)
    551 {
    552     Method* resMethod = dvmFindVirtualMethodByDescriptor(iface,
    553         methodName, descriptor);
    554     if (resMethod == NULL) {
    555         /* scan superinterfaces and superclass interfaces */
    556         int i;
    557         for (i = 0; i < iface->iftableCount; i++) {
    558             resMethod = dvmFindVirtualMethodByDescriptor(iface->iftable[i].clazz,
    559                 methodName, descriptor);
    560             if (resMethod != NULL)
    561                 break;
    562         }
    563     }
    564     return resMethod;
    565 }
    566 
    567 /*
    568  * Find a method in an interface.  Searches superinterfaces.
    569  *
    570  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    571  */
    572 Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
    573     const char* methodName, const DexProto* proto)
    574 {
    575     Method* resMethod = dvmFindVirtualMethod(iface, methodName, proto);
    576     if (resMethod == NULL) {
    577         /* scan superinterfaces and superclass interfaces */
    578         int i;
    579         for (i = 0; i < iface->iftableCount; i++) {
    580             resMethod = dvmFindVirtualMethod(iface->iftable[i].clazz,
    581                 methodName, proto);
    582             if (resMethod != NULL)
    583                 break;
    584         }
    585     }
    586     return resMethod;
    587 }
    588 
    589 /*
    590  * Find a "direct" method (static, private, or "<*init>").
    591  *
    592  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    593  */
    594 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
    595     const char* methodName, const char* descriptor)
    596 {
    597     return findMethodInListByDescriptor(clazz, false, false,
    598             methodName, descriptor);
    599 }
    600 
    601 /*
    602  * Find a "direct" method.  If we don't find it, try the superclass.  This
    603  * is only appropriate for static methods, but will work for all direct
    604  * methods.
    605  *
    606  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    607  */
    608 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
    609     const char* methodName, const char* descriptor)
    610 {
    611     return findMethodInListByDescriptor(clazz, false, true,
    612             methodName, descriptor);
    613 }
    614 
    615 /*
    616  * Find a "direct" method (static or "<*init>").
    617  *
    618  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    619  */
    620 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
    621     const DexProto* proto)
    622 {
    623     return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName,
    624             proto);
    625 }
    626 
    627 /*
    628  * Find a "direct" method in a class.  If we don't find it, try the
    629  * superclass.
    630  *
    631  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    632  */
    633 Method* dvmFindDirectMethodHier(const ClassObject* clazz,
    634     const char* methodName, const DexProto* proto)
    635 {
    636     return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName,
    637             proto);
    638 }
    639 
    640 /*
    641  * Find a virtual or static method in a class.  If we don't find it, try the
    642  * superclass.  This is compatible with the VM spec (v2 5.4.3.3) method
    643  * search order, but it stops short of scanning through interfaces (which
    644  * should be done after this function completes).
    645  *
    646  * In most cases we know that we're looking for either a static or an
    647  * instance field and there's no value in searching through both types.
    648  * During verification we need to recognize and reject certain unusual
    649  * situations, and we won't see them unless we walk the lists this way.
    650  *
    651  * Returns NULL if the method can't be found.  (Does not throw an exception.)
    652  */
    653 Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
    654     const DexProto* proto)
    655 {
    656     return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName,
    657             proto);
    658 }
    659 
    660 
    661 /*
    662  * We have a method pointer for a method in "clazz", but it might be
    663  * pointing to a method in a derived class.  We want to find the actual entry
    664  * from the class' vtable.  If "clazz" is an interface, we have to do a
    665  * little more digging.
    666  *
    667  * For "direct" methods (private / constructor), we just return the
    668  * original Method.
    669  *
    670  * (This is used for reflection and JNI "call method" calls.)
    671  */
    672 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
    673     const Method* meth)
    674 {
    675     Method* actualMeth;
    676     int methodIndex;
    677 
    678     if (dvmIsDirectMethod(meth)) {
    679         /* no vtable entry for these */
    680         assert(!dvmIsStaticMethod(meth));
    681         return meth;
    682     }
    683 
    684     /*
    685      * If the method was declared in an interface, we need to scan through
    686      * the class' list of interfaces for it, and find the vtable index
    687      * from that.
    688      *
    689      * TODO: use the interface cache.
    690      */
    691     if (dvmIsInterfaceClass(meth->clazz)) {
    692         int i;
    693 
    694         for (i = 0; i < clazz->iftableCount; i++) {
    695             if (clazz->iftable[i].clazz == meth->clazz)
    696                 break;
    697         }
    698         if (i == clazz->iftableCount) {
    699             dvmThrowIncompatibleClassChangeError(
    700                 "invoking method from interface not implemented by class");
    701             return NULL;
    702         }
    703 
    704         methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
    705     } else {
    706         methodIndex = meth->methodIndex;
    707     }
    708 
    709     assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
    710     actualMeth = clazz->vtable[methodIndex];
    711 
    712     /*
    713      * Make sure there's code to execute.
    714      */
    715     if (dvmIsAbstractMethod(actualMeth)) {
    716         dvmThrowAbstractMethodError(NULL);
    717         return NULL;
    718     }
    719     assert(!dvmIsMirandaMethod(actualMeth));
    720 
    721     return actualMeth;
    722 }
    723 
    724 /*
    725  * Get the source file for a method.
    726  */
    727 const char* dvmGetMethodSourceFile(const Method* meth)
    728 {
    729     /*
    730      * TODO: A method's debug info can override the default source
    731      * file for a class, so we should account for that possibility
    732      * here.
    733      */
    734     return meth->clazz->sourceFile;
    735 }
    736 
    737 /*
    738  * Dump some information about an object.
    739  */
    740 void dvmDumpObject(const Object* obj)
    741 {
    742     ClassObject* clazz;
    743     int i;
    744 
    745     if (obj == NULL || obj->clazz == NULL) {
    746         LOGW("Null or malformed object not dumped");
    747         return;
    748     }
    749 
    750     clazz = obj->clazz;
    751     LOGD("----- Object dump: %p (%s, %d bytes) -----",
    752         obj, clazz->descriptor, (int) clazz->objectSize);
    753     //printHexDump(obj, clazz->objectSize);
    754     LOGD("  Fields:");
    755     while (clazz != NULL) {
    756         LOGD("    -- %s", clazz->descriptor);
    757         for (i = 0; i < clazz->ifieldCount; i++) {
    758             const InstField* pField = &clazz->ifields[i];
    759             char type = pField->signature[0];
    760 
    761             if (type == 'F' || type == 'D') {
    762                 double dval;
    763 
    764                 if (type == 'F')
    765                     dval = dvmGetFieldFloat(obj, pField->byteOffset);
    766                 else
    767                     dval = dvmGetFieldDouble(obj, pField->byteOffset);
    768 
    769                 LOGD("    %2d: '%s' '%s' af=%04x off=%d %.3f", i,
    770                     pField->name, pField->signature,
    771                     pField->accessFlags, pField->byteOffset, dval);
    772             } else {
    773                 u8 lval;
    774 
    775                 if (type == 'J')
    776                     lval = dvmGetFieldLong(obj, pField->byteOffset);
    777                 else if (type == 'Z')
    778                     lval = dvmGetFieldBoolean(obj, pField->byteOffset);
    779                 else
    780                     lval = dvmGetFieldInt(obj, pField->byteOffset);
    781 
    782                 LOGD("    %2d: '%s' '%s' af=%04x off=%d 0x%08llx", i,
    783                     pField->name, pField->signature,
    784                     pField->accessFlags, pField->byteOffset, lval);
    785             }
    786         }
    787 
    788         clazz = clazz->super;
    789     }
    790     if (dvmIsClassObject(obj)) {
    791         LOGD("  Static fields:");
    792         const StaticField* sfields = &((ClassObject *)obj)->sfields[0];
    793         for (i = 0; i < ((ClassObject *)obj)->sfieldCount; ++i) {
    794             const StaticField* pField = &sfields[i];
    795             size_t byteOffset = (size_t)pField - (size_t)sfields;
    796             char type = pField->signature[0];
    797 
    798             if (type == 'F' || type == 'D') {
    799                 double dval;
    800 
    801                 if (type == 'F')
    802                     dval = pField->value.f;
    803                 else
    804                     dval = pField->value.d;
    805 
    806                 LOGD("    %2d: '%s' '%s' af=%04x off=%zd %.3f", i,
    807                      pField->name, pField->signature,
    808                      pField->accessFlags, byteOffset, dval);
    809             } else {
    810                 u8 lval;
    811 
    812                 if (type == 'J')
    813                     lval = pField->value.j;
    814                 else if (type == 'Z')
    815                     lval = pField->value.z;
    816                 else
    817                     lval = pField->value.i;
    818 
    819                 LOGD("    %2d: '%s' '%s' af=%04x off=%zd 0x%08llx", i,
    820                      pField->name, pField->signature,
    821                      pField->accessFlags, byteOffset, lval);
    822             }
    823         }
    824     }
    825 }
    826