2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #define INTERN_STRING_IMMORTAL_BIT (1<<0)
24 #define SET_IMMORTAL_BIT(strObj) \
25 ((uintptr_t)(strObj) | INTERN_STRING_IMMORTAL_BIT)
26 #define STRIP_IMMORTAL_BIT(strObj) \
27 ((uintptr_t)(strObj) & ~INTERN_STRING_IMMORTAL_BIT)
28 #define IS_IMMORTAL(strObj) \
29 ((uintptr_t)(strObj) & INTERN_STRING_IMMORTAL_BIT)
33 * Prep string interning.
35 bool dvmStringInternStartup(void)
37 gDvm.internedStrings = dvmHashTableCreate(256, NULL);
38 if (gDvm.internedStrings == NULL)
45 * Chuck the intern list.
47 * The contents of the list are StringObjects that live on the GC heap.
49 void dvmStringInternShutdown(void)
51 dvmHashTableFree(gDvm.internedStrings);
52 gDvm.internedStrings = NULL;
57 * Compare two string objects that may have INTERN_STRING_IMMORTAL_BIT
58 * set in their pointer values.
60 static int hashcmpImmortalStrings(const void* vstrObj1, const void* vstrObj2)
62 return dvmHashcmpStrings((const void*) STRIP_IMMORTAL_BIT(vstrObj1),
63 (const void*) STRIP_IMMORTAL_BIT(vstrObj2));
66 static StringObject* lookupInternedString(StringObject* strObj, bool immortal)
71 assert(strObj != NULL);
72 hash = dvmComputeStringHash(strObj);
75 char* debugStr = dvmCreateCstrFromString(strObj);
76 LOGV("+++ dvmLookupInternedString searching for '%s'\n", debugStr);
81 strObj = (StringObject*) SET_IMMORTAL_BIT(strObj);
84 dvmHashTableLock(gDvm.internedStrings);
86 found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings,
87 hash, strObj, hashcmpImmortalStrings, true);
88 if (immortal && !IS_IMMORTAL(found)) {
89 /* Make this entry immortal. We have to use the existing object
90 * because, as an interned string, it's not allowed to change.
92 * There's no way to get a pointer to the actual hash table entry,
93 * so the only way to modify the existing entry is to remove,
94 * modify, and re-add it.
96 dvmHashTableRemove(gDvm.internedStrings, hash, found);
97 found = (StringObject*) SET_IMMORTAL_BIT(found);
98 found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings,
99 hash, found, hashcmpImmortalStrings, true);
100 assert(IS_IMMORTAL(found));
103 dvmHashTableUnlock(gDvm.internedStrings);
105 //if (found == strObj)
106 // LOGVV("+++ added string\n");
107 return (StringObject*) STRIP_IMMORTAL_BIT(found);
111 * Find an entry in the interned string list.
113 * If the string doesn't already exist, the StringObject is added to
114 * the list. Otherwise, the existing entry is returned.
116 StringObject* dvmLookupInternedString(StringObject* strObj)
118 return lookupInternedString(strObj, false);
122 * Same as dvmLookupInternedString(), but guarantees that the
123 * returned string is immortal.
125 StringObject* dvmLookupImmortalInternedString(StringObject* strObj)
127 return lookupInternedString(strObj, true);
131 * Mark all immortal interned string objects so that they don't
132 * get collected by the GC. Non-immortal strings may or may not
133 * get marked by other references.
135 static int markStringObject(void* strObj, void* arg)
137 UNUSED_PARAMETER(arg);
139 if (IS_IMMORTAL(strObj)) {
140 dvmMarkObjectNonNull((Object*) STRIP_IMMORTAL_BIT(strObj));
145 void dvmGcScanInternedStrings()
147 /* It's possible for a GC to happen before dvmStringInternStartup()
150 if (gDvm.internedStrings != NULL) {
151 dvmHashTableLock(gDvm.internedStrings);
152 dvmHashForeach(gDvm.internedStrings, markStringObject, NULL);
153 dvmHashTableUnlock(gDvm.internedStrings);
158 * Called by the GC after all reachable objects have been
159 * marked. isUnmarkedObject is a function suitable for passing
160 * to dvmHashForeachRemove(); it must strip the low bits from
161 * its pointer argument to deal with the immortal bit, though.
163 void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *))
165 /* It's possible for a GC to happen before dvmStringInternStartup()
168 if (gDvm.internedStrings != NULL) {
169 dvmHashTableLock(gDvm.internedStrings);
170 dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject);
171 dvmHashTableUnlock(gDvm.internedStrings);