1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * String interning.
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
21bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro#include <stddef.h>
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Prep string interning.
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
261e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmStringInternStartup()
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
28bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    dvmInitMutex(&gDvm.internLock);
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.internedStrings = dvmHashTableCreate(256, NULL);
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.internedStrings == NULL)
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
32bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    gDvm.literalStrings = dvmHashTableCreate(256, NULL);
33bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    if (gDvm.literalStrings == NULL)
34bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        return false;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Chuck the intern list.
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The contents of the list are StringObjects that live on the GC heap.
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
431e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmStringInternShutdown()
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
45bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    if (gDvm.internedStrings != NULL || gDvm.literalStrings != NULL) {
46bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        dvmDestroyMutex(&gDvm.internLock);
47bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    }
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHashTableFree(gDvm.internedStrings);
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.internedStrings = NULL;
50bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    dvmHashTableFree(gDvm.literalStrings);
51bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    gDvm.literalStrings = NULL;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapirostatic StringObject* lookupString(HashTable* table, u4 key, StringObject* value)
55dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro{
56dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    void* entry = dvmHashTableLookup(table, key, (void*)value,
57dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro                                     dvmHashcmpStrings, false);
58dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    return (StringObject*)entry;
59dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro}
60dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro
61dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapirostatic StringObject* insertString(HashTable* table, u4 key, StringObject* value)
62dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro{
63dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    if (dvmIsNonMovingObject(value) == false) {
64dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro        value = (StringObject*)dvmCloneObject(value, ALLOC_NON_MOVING);
65dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    }
66dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    void* entry = dvmHashTableLookup(table, key, (void*)value,
67dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro                                     dvmHashcmpStrings, true);
68dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    return (StringObject*)entry;
69dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro}
70dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro
71bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapirostatic StringObject* lookupInternedString(StringObject* strObj, bool isLiteral)
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    StringObject* found;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(strObj != NULL);
76dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    u4 key = dvmComputeStringHash(strObj);
77bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    dvmLockMutex(&gDvm.internLock);
78bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    if (isLiteral) {
792e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro        /*
802e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro         * Check the literal table for a match.
812e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro         */
82dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro        StringObject* literal = lookupString(gDvm.literalStrings, key, strObj);
832e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro        if (literal != NULL) {
842e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            /*
852e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             * A match was found in the literal table, the easy case.
862e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             */
872e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            found = literal;
882e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro        } else {
892e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            /*
902e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             * There is no match in the literal table, check the
912e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             * interned string table.
922e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             */
93dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro            StringObject* interned = lookupString(gDvm.internedStrings, key, strObj);
942e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            if (interned != NULL) {
952e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                /*
962e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 * A match was found in the interned table.  Move the
972e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 * matching string to the literal table.
982e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 */
99dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro                dvmHashTableRemove(gDvm.internedStrings, key, interned);
100dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro                found = insertString(gDvm.literalStrings, key, interned);
1014e738a719ef872cce9a99f539dd18394f94790feCarl Shapiro                assert(found == interned);
1022e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            } else {
1032e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                /*
1042e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 * No match in the literal table or the interned
1052e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 * table.  Insert into the literal table.
1062e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro                 */
107dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro                found = insertString(gDvm.literalStrings, key, strObj);
1084e738a719ef872cce9a99f539dd18394f94790feCarl Shapiro                assert(found == strObj);
1092e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            }
110bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        }
111bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    } else {
1122e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro        /*
1132e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro         * Check the literal table for a match.
1142e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro         */
115dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro        found = lookupString(gDvm.literalStrings, key, strObj);
116bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        if (found == NULL) {
1172e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro            /*
1182e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             * No match was found in the literal table.  Insert into
1194e738a719ef872cce9a99f539dd18394f94790feCarl Shapiro             * the intern table if it does not already exist.
1202e3ec7160b265d520cd755f8c20163410d822373Carl Shapiro             */
121dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro            found = insertString(gDvm.internedStrings, key, strObj);
122bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
124bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    assert(found != NULL);
125bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    dvmUnlockMutex(&gDvm.internLock);
126bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro    return found;
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
130bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro * Find an entry in the interned string table.
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If the string doesn't already exist, the StringObject is added to
133bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro * the table.  Otherwise, the existing entry is returned.
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectStringObject* dvmLookupInternedString(StringObject* strObj)
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return lookupInternedString(strObj, false);
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Same as dvmLookupInternedString(), but guarantees that the
142bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro * returned string is a literal.
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectStringObject* dvmLookupImmortalInternedString(StringObject* strObj)
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return lookupInternedString(strObj, true);
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1495ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro/*
1505ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro * Returns true if the object is a weak interned string.  Any string
1515ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro * interned by the user is weak.
1525ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro */
153dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapirobool dvmIsWeakInternedString(StringObject* strObj)
1545ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro{
1555ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    assert(strObj != NULL);
1565ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    if (gDvm.internedStrings == NULL) {
1575ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        return false;
1585ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    }
1595ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    dvmLockMutex(&gDvm.internLock);
160dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    u4 key = dvmComputeStringHash(strObj);
161dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    StringObject* found = lookupString(gDvm.internedStrings, key, strObj);
1625ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    dvmUnlockMutex(&gDvm.internLock);
1635ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro    return found == strObj;
1645ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro}
1655ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
167bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro * Clear white references from the intern table.
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *))
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* It's possible for a GC to happen before dvmStringInternStartup()
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is called.
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.internedStrings != NULL) {
175bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        dvmLockMutex(&gDvm.internLock);
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject);
177bb1e0e904b8dc159ad6ca680419b00c5938cd2b8Carl Shapiro        dvmUnlockMutex(&gDvm.internLock);
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
180