diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
| commit | 2ad60cfc28e14ee8f0bb038720836a4696c478ad (patch) | |
| tree | 19f1bb30ab7ff96f1e3e59a60b61dcd2aeddda93 /vm/Intern.c | |
| download | android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.tar.gz android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.tar.bz2 android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.zip | |
Initial Contribution
Diffstat (limited to 'vm/Intern.c')
| -rw-r--r-- | vm/Intern.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/vm/Intern.c b/vm/Intern.c new file mode 100644 index 000000000..85843335b --- /dev/null +++ b/vm/Intern.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * String interning. + */ +#include "Dalvik.h" + +#include <stdlib.h> + +#define INTERN_STRING_IMMORTAL_BIT (1<<0) +#define SET_IMMORTAL_BIT(strObj) \ + ((uintptr_t)(strObj) | INTERN_STRING_IMMORTAL_BIT) +#define STRIP_IMMORTAL_BIT(strObj) \ + ((uintptr_t)(strObj) & ~INTERN_STRING_IMMORTAL_BIT) +#define IS_IMMORTAL(strObj) \ + ((uintptr_t)(strObj) & INTERN_STRING_IMMORTAL_BIT) + + +/* + * Prep string interning. + */ +bool dvmStringInternStartup(void) +{ + gDvm.internedStrings = dvmHashTableCreate(256, NULL); + if (gDvm.internedStrings == NULL) + return false; + + return true; +} + +/* + * Chuck the intern list. + * + * The contents of the list are StringObjects that live on the GC heap. + */ +void dvmStringInternShutdown(void) +{ + dvmHashTableFree(gDvm.internedStrings); + gDvm.internedStrings = NULL; +} + + +/* + * Compare two string objects that may have INTERN_STRING_IMMORTAL_BIT + * set in their pointer values. + */ +static int hashcmpImmortalStrings(const void* vstrObj1, const void* vstrObj2) +{ + return dvmHashcmpStrings((const void*) STRIP_IMMORTAL_BIT(vstrObj1), + (const void*) STRIP_IMMORTAL_BIT(vstrObj2)); +} + +static StringObject* lookupInternedString(StringObject* strObj, bool immortal) +{ + StringObject* found; + u4 hash; + + assert(strObj != NULL); + hash = dvmComputeStringHash(strObj); + + if (false) { + char* debugStr = dvmCreateCstrFromString(strObj); + LOGV("+++ dvmLookupInternedString searching for '%s'\n", debugStr); + free(debugStr); + } + + if (immortal) { + strObj = (StringObject*) SET_IMMORTAL_BIT(strObj); + } + + dvmHashTableLock(gDvm.internedStrings); + + found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings, + hash, strObj, hashcmpImmortalStrings, true); + if (immortal && !IS_IMMORTAL(found)) { + /* Make this entry immortal. We have to use the existing object + * because, as an interned string, it's not allowed to change. + * + * There's no way to get a pointer to the actual hash table entry, + * so the only way to modify the existing entry is to remove, + * modify, and re-add it. + */ + dvmHashTableRemove(gDvm.internedStrings, hash, found); + found = (StringObject*) SET_IMMORTAL_BIT(found); + found = (StringObject*) dvmHashTableLookup(gDvm.internedStrings, + hash, found, hashcmpImmortalStrings, true); + assert(IS_IMMORTAL(found)); + } + + dvmHashTableUnlock(gDvm.internedStrings); + + //if (found == strObj) + // LOGVV("+++ added string\n"); + return (StringObject*) STRIP_IMMORTAL_BIT(found); +} + +/* + * Find an entry in the interned string list. + * + * If the string doesn't already exist, the StringObject is added to + * the list. Otherwise, the existing entry is returned. + */ +StringObject* dvmLookupInternedString(StringObject* strObj) +{ + return lookupInternedString(strObj, false); +} + +/* + * Same as dvmLookupInternedString(), but guarantees that the + * returned string is immortal. + */ +StringObject* dvmLookupImmortalInternedString(StringObject* strObj) +{ + return lookupInternedString(strObj, true); +} + +/* + * Mark all immortal interned string objects so that they don't + * get collected by the GC. Non-immortal strings may or may not + * get marked by other references. + */ +static int markStringObject(void* strObj, void* arg) +{ + UNUSED_PARAMETER(arg); + + if (IS_IMMORTAL(strObj)) { + dvmMarkObjectNonNull((Object*) STRIP_IMMORTAL_BIT(strObj)); + } + return 0; +} + +void dvmGcScanInternedStrings() +{ + /* It's possible for a GC to happen before dvmStringInternStartup() + * is called. + */ + if (gDvm.internedStrings != NULL) { + dvmHashTableLock(gDvm.internedStrings); + dvmHashForeach(gDvm.internedStrings, markStringObject, NULL); + dvmHashTableUnlock(gDvm.internedStrings); + } +} + +/* + * Called by the GC after all reachable objects have been + * marked. isUnmarkedObject is a function suitable for passing + * to dvmHashForeachRemove(); it must strip the low bits from + * its pointer argument to deal with the immortal bit, though. + */ +void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *)) +{ + /* It's possible for a GC to happen before dvmStringInternStartup() + * is called. + */ + if (gDvm.internedStrings != NULL) { + dvmHashTableLock(gDvm.internedStrings); + dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject); + dvmHashTableUnlock(gDvm.internedStrings); + } +} |
