OSDN Git Service

Fix class loader interning following a String.intern.
authorCarl Shapiro <cshapiro@google.com>
Wed, 20 Oct 2010 00:27:13 +0000 (17:27 -0700)
committerCarl Shapiro <cshapiro@google.com>
Wed, 20 Oct 2010 03:28:37 +0000 (20:28 -0700)
Strings can be intered by the class loader, in the case of string
literals, or by the user, through String.intern.  Literal strings
exist for the life of their referencing classes.  User strings are
weak and may be garbage collected when unreferenced.  These two
classes of strings are kept in seprate tables for the conveniance of
the garbage collector during root traversal.

When a class loader interns a string that was already interned by the
user the runtime must move the string from the intern table to the
literal table to increase the reference strength.  Previously, this
was implemented by inserting the incoming string into the literal
table and removing any matching strings in the intern table.  This
transition lost pointer equality.  With this change we first insert
the exact string from the intern table into the literal table and
secondly remove its reference from the intern table.  By moving the
string between tables pointer equality is preserved.

At this point lookupInternedString should be split into two functions,
possibly by pulled up the relevant bits into the public interface
functions.  Since this change will be merged to gingerbread I will
leave the clean up to a separate change.

Bug: 3098960

vm/Intern.c

index bb8fb18..8bc38b8 100644 (file)
@@ -60,17 +60,67 @@ static StringObject* lookupInternedString(StringObject* strObj, bool isLiteral)
     hash = dvmComputeStringHash(strObj);
     dvmLockMutex(&gDvm.internLock);
     if (isLiteral) {
-        found = dvmHashTableLookup(gDvm.literalStrings, hash, strObj,
-                                   dvmHashcmpStrings, true);
-        if (found == strObj) {
-            dvmHashTableRemove(gDvm.internedStrings, hash, strObj);
+        /*
+         * Check the literal table for a match.
+         */
+        StringObject* literal = dvmHashTableLookup(gDvm.literalStrings,
+                                                   hash, strObj,
+                                                   dvmHashcmpStrings,
+                                                   false);
+        if (literal != NULL) {
+            /*
+             * A match was found in the literal table, the easy case.
+             */
+            found = literal;
+        } else {
+            /*
+             * There is no match in the literal table, check the
+             * interned string table.
+             */
+            StringObject* interned = dvmHashTableLookup(gDvm.internedStrings,
+                                                        hash, strObj,
+                                                        dvmHashcmpStrings,
+                                                        false);
+            if (interned != NULL) {
+                /*
+                 * A match was found in the interned table.  Move the
+                 * matching string to the literal table.
+                 */
+                dvmHashTableRemove(gDvm.internedStrings, hash, interned);
+                found = dvmHashTableLookup(gDvm.literalStrings,
+                                           hash, interned,
+                                           dvmHashcmpStrings,
+                                           true);
+                assert(found == interned);
+            } else {
+                /*
+                 * No match in the literal table or the interned
+                 * table.  Insert into the literal table.
+                 */
+                found = dvmHashTableLookup(gDvm.literalStrings,
+                                           hash, strObj,
+                                           dvmHashcmpStrings,
+                                           true);
+                assert(found == strObj);
+            }
         }
     } else {
-        found = dvmHashTableLookup(gDvm.literalStrings, hash, strObj,
-                                   dvmHashcmpStrings, false);
+        /*
+         * Check the literal table for a match.
+         */
+        found = dvmHashTableLookup(gDvm.literalStrings,
+                                   hash, strObj,
+                                   dvmHashcmpStrings,
+                                   false);
         if (found == NULL) {
-            found = dvmHashTableLookup(gDvm.internedStrings, hash, strObj,
-                                       dvmHashcmpStrings, true);
+            /*
+             * No match was found in the literal table.  Insert into
+             * the intern table.
+             */
+            found = dvmHashTableLookup(gDvm.internedStrings,
+                                       hash, strObj,
+                                       dvmHashcmpStrings,
+                                       true);
         }
     }
     assert(found != NULL);