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 hprofStartup_Class()
     25 {
     26     gClassHashTable = dvmHashTableCreate(128, NULL);
     27     if (gClassHashTable == NULL) {
     28         return UNIQUE_ERROR();
     29     }
     30     return 0;
     31 }
     32 
     33 int hprofShutdown_Class()
     34 {
     35     dvmHashTableFree(gClassHashTable);
     36 
     37     return 0;
     38 }
     39 
     40 static u4 computeClassHash(const ClassObject *clazz)
     41 {
     42     u4 hash;
     43     const char *cp;
     44     char c;
     45 
     46     cp = clazz->descriptor;
     47     hash = (u4)clazz->classLoader;
     48     while ((c = *cp++) != '\0') {
     49         hash = hash * 31 + c;
     50     }
     51 
     52     return hash;
     53 }
     54 
     55 static int classCmp(const void *v1, const void *v2)
     56 {
     57     const ClassObject *c1 = (const ClassObject *)v1;
     58     const ClassObject *c2 = (const ClassObject *)v2;
     59     intptr_t diff;
     60 
     61     diff = (uintptr_t)c1->classLoader - (uintptr_t)c2->classLoader;
     62     if (diff == 0) {
     63         return strcmp(c1->descriptor, c2->descriptor);
     64     }
     65     return diff;
     66 }
     67 
     68 static int getPrettyClassNameId(const char *descriptor) {
     69     std::string name(dvmHumanReadableDescriptor(descriptor));
     70     return hprofLookupStringId(name.c_str());
     71 }
     72 
     73 hprof_class_object_id hprofLookupClassId(const ClassObject *clazz)
     74 {
     75     void *val;
     76 
     77     if (clazz == NULL) {
     78         /* Someone's probably looking up the superclass
     79          * of java.lang.Object or of a primitive class.
     80          */
     81         return (hprof_class_object_id)0;
     82     }
     83 
     84     dvmHashTableLock(gClassHashTable);
     85 
     86     /* We're using the hash table as a list.
     87      * TODO: replace the hash table with a more suitable structure
     88      */
     89     val = dvmHashTableLookup(gClassHashTable, computeClassHash(clazz),
     90             (void *)clazz, classCmp, true);
     91     assert(val != NULL);
     92 
     93     dvmHashTableUnlock(gClassHashTable);
     94 
     95     /* Make sure that the class's name is in the string table.
     96      * This is a bunch of extra work that we only have to do
     97      * because of the order of tables in the output file
     98      * (strings need to be dumped before classes).
     99      */
    100     getPrettyClassNameId(clazz->descriptor);
    101 
    102     return (hprof_class_object_id)clazz;
    103 }
    104 
    105 int hprofDumpClasses(hprof_context_t *ctx)
    106 {
    107     HashIter iter;
    108     hprof_record_t *rec = &ctx->curRec;
    109     int err;
    110 
    111     dvmHashTableLock(gClassHashTable);
    112 
    113     for (err = 0, dvmHashIterBegin(gClassHashTable, &iter);
    114          err == 0 && !dvmHashIterDone(&iter);
    115          dvmHashIterNext(&iter))
    116     {
    117         err = hprofStartNewRecord(ctx, HPROF_TAG_LOAD_CLASS, HPROF_TIME);
    118         if (err == 0) {
    119             const ClassObject *clazz;
    120 
    121             clazz = (const ClassObject *)dvmHashIterData(&iter);
    122             assert(clazz != NULL);
    123 
    124             /* LOAD CLASS format:
    125              *
    126              * u4:     class serial number (always > 0)
    127              * ID:     class object ID
    128              * u4:     stack trace serial number
    129              * ID:     class name string ID
    130              *
    131              * We use the address of the class object structure as its ID.
    132              */
    133             hprofAddU4ToRecord(rec, clazz->serialNumber);
    134             hprofAddIdToRecord(rec, (hprof_class_object_id)clazz);
    135             hprofAddU4ToRecord(rec, HPROF_NULL_STACK_TRACE);
    136             hprofAddIdToRecord(rec, getPrettyClassNameId(clazz->descriptor));
    137         }
    138     }
    139 
    140     dvmHashTableUnlock(gClassHashTable);
    141 
    142     return err;
    143 }
    144