• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 hprofStartup_Class()
26 {
27     gClassHashTable = dvmHashTableCreate(128, NULL);
28     if (gClassHashTable == NULL) {
29         return UNIQUE_ERROR();
30     }
31     return 0;
32 }
33 
34 int
hprofShutdown_Class()35 hprofShutdown_Class()
36 {
37     dvmHashTableFree(gClassHashTable);
38 
39     return 0;
40 }
41 
42 static u4
computeClassHash(const ClassObject * clazz)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
classCmp(const void * v1,const void * v2)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
getPrettyClassNameId(const char * descriptor)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
hprofLookupClassId(const ClassObject * clazz)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
hprofDumpClasses(hprof_context_t * ctx)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