You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gs...@apache.org on 2007/06/07 15:53:35 UTC

svn commit: r545183 - in /harmony/enhanced/drlvm/trunk/vm: tests/smoke/stress/ vmcore/include/ vmcore/src/class_support/ vmcore/src/init/ vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/ vmcore/src/kernel_classes/native/ vmcore/src/util/

Author: gshimansky
Date: Thu Jun  7 06:53:34 2007
New Revision: 545183

URL: http://svn.apache.org/viewvc?view=rev&rev=545183
Log:
Apply patch from HARMONY-1016 [drlvm][kernel] Make interned strings garbage collectable


Added:
    harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java   (with props)
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java   (with props)
Modified:
    harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h
    harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_strings.h
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/String_Pool.cpp
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/vm_init.cpp
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_kernel_vm_VM.cpp
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/vm_strings.cpp

Added: harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java?view=auto&rev=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java (added)
+++ harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java Thu Jun  7 06:53:34 2007
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  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.
+ */
+package stress;
+
+/**
+ * Tests the correctness of string interning.
+ *
+ * @keyword XXX_stress
+ */
+public class Intern {
+    public static void main(String[] args) {
+        String s = "abc";
+        for (int i = 0; i < 100000; i++) {
+            s = (s + i + s).intern();
+            if (s.length() > 65536) s = "abc" + i;
+            if (i % 1000 == 0) trace(".");
+        }
+    }
+
+    public static void trace(Object o) {
+        System.out.print(o);
+        System.out.flush();
+    }
+}

Propchange: harmony/enhanced/drlvm/trunk/vm/tests/smoke/stress/Intern.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h Thu Jun  7 06:53:34 2007
@@ -157,6 +157,11 @@
     String* InitCauseDescriptor_String;
 
     /**
+     * Preloaded methods
+     */
+    Method* VM_intern;
+
+    /**
      * Preloaded classes
      */
     Class* Boolean_Class;

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_strings.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_strings.h?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_strings.h (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_strings.h Thu Jun  7 06:53:34 2007
@@ -33,20 +33,6 @@
  * Exported functons.
  */
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Interns a string.
- */
-VMEXPORT jstring
-string_intern(JNIEnv*, jobject string);
-
-#ifdef __cplusplus
-}
-#endif
-
 VMEXPORT // temporary solution for interpreter unplug
 Java_java_lang_String *vm_instantiate_cp_string_resolved(String*);
 

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/String_Pool.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/String_Pool.cpp?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/String_Pool.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/String_Pool.cpp Thu Jun  7 06:53:34 2007
@@ -19,26 +19,24 @@
  * @version $Revision: 1.1.2.1.4.4 $
  */  
 
-#include "platform_lowlevel.h"
-
-//MVM
-#include <iostream>
-using namespace std;
-
 #include <assert.h>
 #include <apr_atomic.h>
 #include <apr_pools.h>
 #include <apr_hash.h>
 #include <apr_time.h>
 
-#include "String_Pool.h"
-#include "environment.h"
 #include "open/hythread.h"
 #include "open/vm_util.h"
 #include "open/gc.h"
+
+#include "platform_lowlevel.h"
+#include "String_Pool.h"
+#include "environment.h"
 #include "atomics.h"
 #include "vm_strings.h"
 #include "vm_stats.h"
+#include "ini.h"
+#include "exceptions.h"
 #include "port_threadunsafe.h"
 
 #define LOG_DOMIAN "vm.strings"
@@ -326,19 +324,30 @@
 // NOTE: it is safe to call this function in multiple threads BUT
 // don't iterate through interned strings while other threads do interning
 ManagedObject * String_Pool::intern(String * str) {
+    jobject string = oh_allocate_local_handle();
     ManagedObject* lang_string = string_create_from_utf8(str->bytes, str->len);
     
     if (!lang_string) { // if OutOfMemory
         return NULL;
     }
+    string->object = lang_string;
     assert(!hythread_is_suspend_enabled());
 
+    Global_Env* env = VM_Global_State::loader_env;
+    jvalue args[1];
+    args[0].l = string;
+    assert(env->VM_intern);
+    vm_execute_java_method_array((jmethodID)env->VM_intern,
+        (jvalue*)&string, args);
+    assert(!exn_raised());
+    assert(string);
+    assert(string->object);
+
     // Atomically update the string structure since some other thread might be trying to make the same update.
     // The GC won't be able to enumerate here since GC is disabled, so there are no race conditions with GC.
     if (VM_Global_State::loader_env->compress_references) {
         COMPRESSED_REFERENCE compressed_lang_string =
-            (COMPRESSED_REFERENCE)((POINTER_SIZE_INT)lang_string
-            - (POINTER_SIZE_INT)VM_Global_State::loader_env->heap_base);
+            compress_reference(string->object);
         assert(is_compressed_reference(compressed_lang_string));     
         uint32 result = apr_atomic_cas32(
             /*destination*/ (volatile uint32 *)&str->intern.compressed_ref, 
@@ -348,7 +357,7 @@
             // Note the successful write of the object. 
             gc_heap_write_global_slot_compressed(
                 (COMPRESSED_REFERENCE *)&str->intern.compressed_ref,
-                (Managed_Object_Handle)lang_string);
+                (Managed_Object_Handle)string->object);
             // add this string to interned strings
             register_interned_string(str);
         }
@@ -358,18 +367,19 @@
         void *result =
             (void *)apr_atomic_casptr(
             /*destination*/ (volatile void **)&str->intern.raw_ref, 
-            /*exchange*/    (void *)lang_string, 
+            /*exchange*/    (void *)string->object, 
             /*comparand*/   (void *)NULL);    
         if (result == NULL) {
             // Note the successful write of the object. 
             gc_heap_write_global_slot(
                 (Managed_Object_Handle *)&str->intern.raw_ref,
-                (Managed_Object_Handle)lang_string);
+                (Managed_Object_Handle)string->object);
             // add this string to interned strings
             register_interned_string(str);
         }
         // Some other thread may have beaten us to the slot.
         lang_string = str->intern.raw_ref;
     }
+    oh_discard_local_handle(string);
     return lang_string;
 }

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/vm_init.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/vm_init.cpp?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/vm_init.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/vm_init.cpp Thu Jun  7 06:53:34 2007
@@ -369,6 +369,10 @@
         (class_lookup_field_recursive(vm_env->JavaLangString_Class, "bvalue", "[B") != NULL);
     vm_env->JavaLangString_VTable = vm_env->JavaLangString_Class->get_vtable();
 
+    Class* VM_class = preload_class(vm_env, "org/apache/harmony/kernel/vm/VM");
+    vm_env->VM_intern = class_lookup_method_recursive(VM_class, "intern",
+            "(Ljava/lang/String;)Ljava/lang/String;");
+
     TRACE2("init", "preloading exceptions");
     vm_env->java_lang_Throwable_Class =
         preload_class(vm_env, vm_env->JavaLangThrowable_String);

Added: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java?view=auto&rev=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java (added)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java Thu Jun  7 06:53:34 2007
@@ -0,0 +1,155 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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.
+ */
+
+package org.apache.harmony.kernel.vm;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+/**
+ * Implements weak hash map specialized for storing interned string pool.
+ * @see java.util.WeakHashMap
+ * @see WeakReference
+ */
+public class InternMap {
+
+    private final ReferenceQueue referenceQueue;
+
+    int elementCount;
+
+    Entry[] elementData;
+
+    private final int loadFactor;
+
+    private int threshold;
+
+    //Simple utility method to isolate unchecked cast for array creation
+    private static Entry[] newEntryArray(int size) {
+        return new Entry[size];
+    }
+
+    private static final class Entry/* extends WeakReference*/ {
+        int hash;
+        Entry next;
+        String key;
+        Entry(String key, ReferenceQueue queue) {
+            //super(key, queue);
+            this.key = key;
+            hash = key.hashCode();
+        }
+    }
+
+    public InternMap(int capacity) {
+        if (capacity >= 0) {
+            elementCount = 0;
+            elementData = newEntryArray(capacity == 0 ? 1 : capacity);
+            loadFactor = 7500; // Default load factor of 0.75
+            computeMaxSize();
+            referenceQueue = new ReferenceQueue();
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private void computeMaxSize() {
+        threshold = (int) ((long) elementData.length * loadFactor / 10000);
+    }
+
+    void poll()
+    {
+        /*
+        Entry toRemove;
+        while ((toRemove = (Entry)referenceQueue.poll()) != null) {
+                removeEntry(toRemove);
+        }
+        */
+    }
+
+    void removeEntry(Entry toRemove)
+    {
+        Entry entry, last = null;
+        int index = (toRemove.hash & 0x7FFFFFFF) % elementData.length;
+        entry = elementData[index];
+        // Ignore queued entries which cannot be found, the user could
+        // have removed them before they were queued, i.e. using clear()
+        while (entry != null) {
+            if (toRemove == entry) {
+                if (last == null) {
+                    elementData[index] = entry.next;
+                } else {
+                    last.next = entry.next;
+                }
+                elementCount--;
+                break;
+            }
+            last = entry;
+            entry = entry.next;
+        }
+    }
+
+    public String intern(String key)
+    {
+        int index = 0;
+        Entry entry;
+        String interned = null;
+        if (key == null) 
+            return null;
+        int hash = key.hashCode();
+        int length = elementData.length;
+        index = (hash & 0x7FFFFFFF) % length;
+        entry = elementData[index];
+        while (entry != null && !key.equals(interned = (String)entry.key/*get()*/)) {
+            entry = entry.next;
+        }
+
+        // if we found the entry, return it
+        if (entry != null) {
+            return interned;
+        }
+
+        // no interned string found, put a new entry for it
+        if (++elementCount > threshold) {
+            rehash();
+            index = (key.hashCode() & 0x7FFFFFFF) % elementData.length;
+        }
+        entry = new Entry(key, referenceQueue);
+        entry.next = elementData[index];
+        elementData[index] = entry;
+        return key;
+    }
+
+    private void rehash()
+    {
+        poll();
+        int length = elementData.length << 1;
+        if (length == 0) {
+            length = 1;
+        }
+        Entry[] newData = newEntryArray(length);
+        for (int i = 0; i < elementData.length; i++) {
+            Entry entry = elementData[i];
+            while (entry != null) {
+                int index = (entry.hash & 0x7FFFFFFF) % length;
+                Entry next = entry.next;
+                entry.next = newData[index];
+                newData[index] = entry;
+                entry = next;
+            }
+        }
+        elementData = newData;
+        computeMaxSize();
+    }
+}
+

Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/InternMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java Thu Jun  7 06:53:34 2007
@@ -22,6 +22,8 @@
 package org.apache.harmony.kernel.vm;
 
 import org.apache.harmony.vm.VMStack;
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
 
 public final class VM {
 
@@ -105,12 +107,20 @@
      *  @return String that has the same contents as 
      *    argument, but from internal pool
      */
-    public static String intern(String s) {
-        return intern0(s);
+    public static synchronized String intern(String s)
+    {
+        return internedStrings.intern(s);
     }
     
     /**
      * Invokes native string interning service.
      */
     private static native String intern0(String s);
+
+    private static InternMap internedStrings;
+
+    static {
+        // initialize the storage for interned strings
+        internedStrings = new InternMap(32768);
+    }
 }

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_kernel_vm_VM.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_kernel_vm_VM.cpp?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_kernel_vm_VM.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_kernel_vm_VM.cpp Thu Jun  7 06:53:34 2007
@@ -38,10 +38,3 @@
     // reuse similar method in VMClassRegistry
     return Java_java_lang_VMClassRegistry_getClassLoader0(jenv, NULL, clazz);
 }
-
-JNIEXPORT jstring JNICALL
-Java_org_apache_harmony_kernel_vm_VM_intern0(JNIEnv *jenv, jclass, jstring str)
-{
-    // call corresponding VM internal function
-    return string_intern(jenv, str);
-}

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/vm_strings.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/vm_strings.cpp?view=diff&rev=545183&r1=545182&r2=545183
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/vm_strings.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/vm_strings.cpp Thu Jun  7 06:53:34 2007
@@ -565,19 +565,6 @@
 
 // Interning of strings
 
-VMEXPORT jstring string_intern(JNIEnv *jenv, jobject jstr_obj)
-{
-    ASSERT_RAISE_AREA;
-    jboolean is_copy;
-    const char* val = jenv->GetStringUTFChars(jstr_obj, &is_copy);
-    String* str = VM_Global_State::loader_env->string_pool.lookup(val);
-    if (is_copy == JNI_TRUE) {
-        jenv->ReleaseStringUTFChars(jstr_obj, val);
-    }
-
-    return String_to_interned_jstring(str);
-}
-
 jstring String_to_interned_jstring(String* str)
 {
     ASSERT_RAISE_AREA;