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