Home | History | Annotate | Download | only in hprof
      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  * Class object pool
     18  */
     19 
     20 #include "Hprof.h"
     21 
     22 static HashTable *gClassHashTable;
     23 
     24 int
     25 hprofStartup_Class()
     26 {
     27     gClassHashTable = dvmHashTableCreate(128, NULL);
     28     if (gClassHashTable == NULL) {
     29         return UNIQUE_ERROR();
     30     }
     31     return 0;
     32 }
     33 
     34 int
     35 hprofShutdown_Class()
     36 {
     37     dvmHashTableFree(gClassHashTable);
     38 
     39     return 0;
     40 }
     41 
     42 static u4
     43 computeClassHash(const ClassObject *clazz)
     44 {
     45     u4 hash;
     46     const char *cp;
     47     char c;
     48 
     49     cp = clazz->descriptor;
     50     hash = (u4)clazz->classLoader;
     51     while ((c = *cp++) != '\0') {
     52         hash = hash * 31 + c;
     53     }
     54 
     55     return hash;
     56 }
     57 
     58 static int
     59 classCmp(const void *v1, const void *v2)
     60 {
     61     const ClassObject *c1 = (const ClassObject *)v1;
     62     const ClassObject *c2 = (const ClassObject *)v2;
     63     intptr_t diff;
     64 
     65     diff = (uintptr_t)c1->classLoader - (uintptr_t)c2->classLoader;
     66     if (diff == 0) {
     67         return strcmp(c1->descriptor, c2->descriptor);
     68     }
     69     return diff;
     70 }
     71 
     72 static int
     73 getPrettyClassNameId(const char *descriptor)
     74 {
     75     hprof_string_id classNameId;
     76     char *dotName = dvmDescriptorToDot(descriptor);
     77 
     78     /* Hprof suggests that array class names be converted from, e.g.,
     79      * "[[[I" to "int[][][]" and "[Lorg.blort.Spaz;" to
     80      * "org.blort.Spaz[]".
     81      */
     82     if (dotName[0] == '[') {
     83         const char *c;
     84         char *newName;
     85         char *nc;
     86         size_t dim;
     87         size_t newLen;
     88 
     89         c = dotName;
     90         dim = 0;
     91         while (*c == '[') {
     92             dim++;
     93             c++;
     94         }
     95         if (*c == 'L') {
     96             c++;
     97         } else {
     98             /* It's a primitive type;  we should use a pretty name.
     99              * Add semicolons to make all strings have the format
    100              * of object class names.
    101              */
    102             switch (*c) {
    103             case 'Z': c = "boolean;";    break;
    104             case 'C': c = "char;";       break;
    105             case 'F': c = "float;";      break;
    106             case 'D': c = "double;";     break;
    107             case 'B': c = "byte;";       break;
    108             case 'S': c = "short;";      break;
    109             case 'I': c = "int;";        break;
    110             case 'J': c = "long;";       break;
    111             default: assert(false); c = "UNKNOWN;"; break;
    112             }
    113         }
    114 
    115         /* We have a string of the form "name;" and
    116          * we want to replace the semicolon with as many
    117          * "[]" pairs as is in dim.
    118          */
    119         newLen = strlen(c)-1 + dim*2;
    120         newName = malloc(newLen + 1);
    121         if (newName == NULL) {
    122             return -1;
    123         }
    124         strcpy(newName, c);
    125         newName[newLen] = '\0';
    126 
    127         /* Point nc to the semicolon.
    128          */
    129         nc = newName + newLen - dim*2;
    130         assert(*nc == ';');
    131 
    132         while (dim--) {
    133             *nc++ = '[';
    134             *nc++ = ']';
    135         }
    136         assert(*nc == '\0');
    137 
    138         classNameId = hprofLookupStringId(newName);
    139         free(newName);
    140     } else {
    141         classNameId = hprofLookupStringId(dotName);
    142     }
    143 
    144     free(dotName);
    145     return classNameId;
    146 }
    147 
    148 
    149 hprof_class_object_id
    150 hprofLookupClassId(const ClassObject *clazz)
    151 {
    152     void *val;
    153 
    154     if (clazz == NULL) {
    155         /* Someone's probably looking up the superclass
    156          * of java.lang.Object or of a primitive class.
    157          */
    158         return (hprof_class_object_id)0;
    159     }
    160 
    161     dvmHashTableLock(gClassHashTable);
    162 
    163     /* We're using the hash table as a list.
    164      * TODO: replace the hash table with a more suitable structure
    165      */
    166     val = dvmHashTableLookup(gClassHashTable, computeClassHash(clazz),
    167             (void *)clazz, classCmp, true);
    168     assert(val != NULL);
    169 
    170     dvmHashTableUnlock(gClassHashTable);
    171 
    172     /* Make sure that the class's name is in the string table.
    173      * This is a bunch of extra work that we only have to do
    174      * because of the order of tables in the output file
    175      * (strings need to be dumped before classes).
    176      */
    177     getPrettyClassNameId(clazz->descriptor);
    178 
    179     return (hprof_class_object_id)clazz;
    180 }
    181 
    182 int
    183 hprofDumpClasses(hprof_context_t *ctx)
    184 {
    185     HashIter iter;
    186     hprof_record_t *rec = &ctx->curRec;
    187     int err;
    188 
    189     dvmHashTableLock(gClassHashTable);
    190 
    191     for (err = 0, dvmHashIterBegin(gClassHashTable, &iter);
    192          err == 0 && !dvmHashIterDone(&iter);
    193          dvmHashIterNext(&iter))
    194     {
    195         err = hprofStartNewRecord(ctx, HPROF_TAG_LOAD_CLASS, HPROF_TIME);
    196         if (err == 0) {
    197             const ClassObject *clazz;
    198 
    199             clazz = (const ClassObject *)dvmHashIterData(&iter);
    200             assert(clazz != NULL);
    201 
    202             /* LOAD CLASS format:
    203              *
    204              * u4:     class serial number (always > 0)
    205              * ID:     class object ID
    206              * u4:     stack trace serial number
    207              * ID:     class name string ID
    208              *
    209              * We use the address of the class object structure as its ID.
    210              */
    211             hprofAddU4ToRecord(rec, clazz->serialNumber);
    212             hprofAddIdToRecord(rec, (hprof_class_object_id)clazz);
    213             hprofAddU4ToRecord(rec, HPROF_NULL_STACK_TRACE);
    214             hprofAddIdToRecord(rec, getPrettyClassNameId(clazz->descriptor));
    215         }
    216     }
    217 
    218     dvmHashTableUnlock(gClassHashTable);
    219 
    220     return err;
    221 }
    222