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