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
hprofStartup_Class()24 int hprofStartup_Class()
25 {
26 gClassHashTable = dvmHashTableCreate(128, NULL);
27 if (gClassHashTable == NULL) {
28 return UNIQUE_ERROR();
29 }
30 return 0;
31 }
32
hprofShutdown_Class()33 int hprofShutdown_Class()
34 {
35 dvmHashTableFree(gClassHashTable);
36
37 return 0;
38 }
39
computeClassHash(const ClassObject * clazz)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
classCmp(const void * v1,const void * v2)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
getPrettyClassNameId(const char * descriptor)68 static int getPrettyClassNameId(const char *descriptor) {
69 std::string name(dvmHumanReadableDescriptor(descriptor));
70 return hprofLookupStringId(name.c_str());
71 }
72
hprofLookupClassId(const ClassObject * clazz)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
hprofDumpClasses(hprof_context_t * ctx)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