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
22static HashTable *gClassHashTable;
23
24int hprofStartup_Class()
25{
26    gClassHashTable = dvmHashTableCreate(128, NULL);
27    if (gClassHashTable == NULL) {
28        return UNIQUE_ERROR();
29    }
30    return 0;
31}
32
33int hprofShutdown_Class()
34{
35    dvmHashTableFree(gClassHashTable);
36
37    return 0;
38}
39
40static 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
55static 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
68static int getPrettyClassNameId(const char *descriptor) {
69    std::string name(dvmHumanReadableDescriptor(descriptor));
70    return hprofLookupStringId(name.c_str());
71}
72
73hprof_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
105int 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