java/lang/String.intern() should always return the same reference for
equal strings. Therefore we must keep track of them in the VM.  We
maintain a global hash map of string literals. Whenever new string
object is created by the VM, vm_string_intern() should be called on it.

Currently it only need to be put in vm_object_alloc_string_from_utf8()
and vm_object_alloc_string_from_c().

We must provide our own implementation of VMString class because
VMString.intern() is not a native method.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 Makefile                       |    4 +-
 include/vm/string.h            |    9 +++
 regression/jvm/StringTest.java |    8 +++
 vm/jato.c                      |    9 +++-
 vm/object.c                    |    8 ++-
 vm/string.c                    |  119 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+), 5 deletions(-)
 create mode 100644 include/vm/string.h
 create mode 100644 vm/string.c

diff --git a/Makefile b/Makefile
index 993725e..ef3b34b 100644
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,7 @@ VM_OBJS = \
        vm/stack.o              \
        vm/stack-trace.o        \
        vm/static.o             \
+       vm/string.o             \
        vm/thread.o             \
        vm/trace.o              \
        vm/types.o              \
@@ -162,7 +163,8 @@ JATO_OBJS = $(ARCH_OBJS) $(JIT_OBJS) $(VM_OBJS) $(LIB_OBJS) 
$(CAFEBABE_OBJS)
 
 OBJS = $(JAMVM_OBJS) $(JATO_OBJS)
 
-RUNTIME_CLASSES =
+RUNTIME_CLASSES = \
+       runtime/java/lang/VMString.class
 
 CC             := gcc
 MONOBURG       := ./tools/monoburg/monoburg
diff --git a/include/vm/string.h b/include/vm/string.h
new file mode 100644
index 0000000..f5428ff
--- /dev/null
+++ b/include/vm/string.h
@@ -0,0 +1,9 @@
+#ifndef JATO_LITERALS_H
+#define JATO_LITERALS_H
+
+struct vm_object;
+
+void literals_init(void);
+struct vm_object *vm_string_intern(struct vm_object *string);
+
+#endif
diff --git a/regression/jvm/StringTest.java b/regression/jvm/StringTest.java
index 0d08a06..cdde37b 100644
--- a/regression/jvm/StringTest.java
+++ b/regression/jvm/StringTest.java
@@ -24,8 +24,16 @@ public class StringTest extends TestCase {
         assertObjectEquals("123abcd", a + b);
     }
 
+       public static String test_string = "Test";
+
+       public static void testStringIntern() {
+               String s1 = new String("Test");
+               assertEquals(s1.intern(), test_string);
+       }
+
     public static void main(String args[]) {
         testUnicode();
         testStringConcatenation();
+       testStringIntern();
     }
 }
diff --git a/vm/jato.c b/vm/jato.c
index 4792039..bff5c23 100644
--- a/vm/jato.c
+++ b/vm/jato.c
@@ -71,6 +71,7 @@
 #include "vm/signal.h"
 #include "vm/stack-trace.h"
 #include "vm/static.h"
+#include "vm/string.h"
 #include "vm/system.h"
 #include "vm/thread.h"
 #include "vm/vm.h"
@@ -850,6 +851,11 @@ native_vmclass_isinterface(struct vm_object *clazz)
        return vm_class_is_interface(class);
 }
 
+static struct vm_object *native_vmstring_intern(struct vm_object *str)
+{
+       return vm_string_intern(str);
+}
+
 static struct vm_native natives[] = {
        DEFINE_NATIVE("gnu/classpath/VMStackWalker", "getClassContext", 
&native_vmstackwalker_getclasscontext),
        DEFINE_NATIVE("gnu/classpath/VMSystemProperties", "preInit", 
&native_vmsystemproperties_preinit),
@@ -885,6 +891,7 @@ static struct vm_native natives[] = {
        DEFINE_NATIVE("java/lang/VMRuntime", "mapLibraryName", 
&native_vmruntime_maplibraryname),
        DEFINE_NATIVE("java/lang/VMRuntime", "nativeLoad", 
&native_vmruntime_native_load),
        DEFINE_NATIVE("java/lang/VMRuntime", "runFinalizationForExit", 
&native_vmruntime_run_finalization_for_exit),
+       DEFINE_NATIVE("java/lang/VMString", "intern", &native_vmstring_intern),
        DEFINE_NATIVE("java/lang/VMSystem", "arraycopy", 
&native_vmsystem_arraycopy),
        DEFINE_NATIVE("java/lang/VMSystem", "identityHashCode", 
&native_vmsystem_identityhashcode),
        DEFINE_NATIVE("java/lang/VMSystem", "nanoTime", 
&native_vmsystem_nano_time),
@@ -1296,7 +1303,7 @@ main(int argc, char *argv[])
 #endif
 
        arch_init();
-
+       literals_init();
        init_system_properties();
 
        parse_options(argc, argv);
diff --git a/vm/object.c b/vm/object.c
index 15abb54..0946c8d 100644
--- a/vm/object.c
+++ b/vm/object.c
@@ -15,10 +15,12 @@
 #include "vm/preload.h"
 #include "vm/object.h"
 #include "vm/stdlib.h"
-#include "lib/string.h"
+#include "vm/string.h"
 #include "vm/types.h"
 #include "vm/utf8.h"
 
+#include "lib/string.h"
+
 static pthread_mutexattr_t obj_mutexattr;
 
 int init_vm_objects(void)
@@ -299,7 +301,7 @@ vm_object_alloc_string_from_utf8(const uint8_t bytes[], 
unsigned int length)
        field_set_int(string, vm_java_lang_String_count, array->array_length);
        field_set_object(string, vm_java_lang_String_value, array);
 
-       return string;
+       return vm_string_intern(string);
 }
 
 struct vm_object *
@@ -332,7 +334,7 @@ vm_object_alloc_string_from_c(const char *bytes)
        field_set_int(string, vm_java_lang_String_count, array->array_length);
        field_set_object(string, vm_java_lang_String_value, array);
 
-       return string;
+       return vm_string_intern(string);
 }
 
 typedef void (*exception_init_fn)(struct vm_object *, struct vm_object *);
diff --git a/vm/string.c b/vm/string.c
new file mode 100644
index 0000000..6236525
--- /dev/null
+++ b/vm/string.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2009 Tomasz Grabiec
+ *
+ * This file is released under the GPL version 2 with the following
+ * clarification and special exception:
+ *
+ *     Linking this library statically or dynamically with other modules is
+ *     making a combined work based on this library. Thus, the terms and
+ *     conditions of the GNU General Public License cover the whole
+ *     combination.
+ *
+ *     As a special exception, the copyright holders of this library give you
+ *     permission to link this library with independent modules to produce an
+ *     executable, regardless of the license terms of these independent
+ *     modules, and to copy and distribute the resulting executable under terms
+ *     of your choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module. An
+ *     independent module is a module which is not derived from or based on
+ *     this library. If you modify this library, you may extend this exception
+ *     to your version of the library, but you are not obligated to do so. If
+ *     you do not wish to do so, delete this exception statement from your
+ *     version.
+ *
+ * Please refer to the file LICENSE for details.
+ */
+
+#include "vm/die.h"
+#include "vm/object.h"
+#include "vm/preload.h"
+#include "vm/string.h"
+
+#include "lib/hash-map.h"
+
+#include <pthread.h>
+#include <memory.h>
+
+static struct hash_map *literals;
+pthread_rwlock_t literals_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+static int string_obj_comparator(const void *key1, const void *key2)
+{
+       struct vm_object *array1, *array2;
+       jint offset1, offset2;
+       jint count1, count2;
+
+       count1 = field_get_int(key1, vm_java_lang_String_count);
+       count2 = field_get_int(key2, vm_java_lang_String_count);
+
+       if (count1 != count2)
+               return -1;
+
+       offset1 = field_get_int(key1, vm_java_lang_String_offset);
+       offset2 = field_get_int(key2, vm_java_lang_String_offset);
+
+       array1 = field_get_object(key1, vm_java_lang_String_value);
+       array2 = field_get_object(key2, vm_java_lang_String_value);
+
+       int fsize = get_vmtype_size(J_CHAR);
+
+       return memcmp(array1->fields + offset1 * fsize,
+                     array2->fields + offset2 * fsize,
+                     count1 * fsize);
+}
+
+static unsigned long string_obj_hash(const void *key, unsigned long size)
+{
+       struct vm_object *array;
+       unsigned long hash;
+       jint offset;
+       jint count;
+
+       offset = field_get_int(key, vm_java_lang_String_offset);
+       count = field_get_int(key, vm_java_lang_String_count);
+       array = field_get_object(key, vm_java_lang_String_value);
+
+       hash = 0;
+
+       for (jint i = 0; i < count; i++)
+               hash += 31 * hash + array_get_field_char(array, i + offset);
+
+       return hash % size;
+}
+
+void literals_init(void)
+{
+       literals = alloc_hash_map(1000, string_obj_hash, string_obj_comparator);
+       if (!literals)
+               error("failed to initialize literals hash map");
+}
+
+struct vm_object *vm_string_intern(struct vm_object *string)
+{
+       struct vm_object *intern;
+
+       pthread_rwlock_rdlock(&literals_rwlock);
+
+       if (hash_map_get(literals, string, (void **) &intern) == 0) {
+               pthread_rwlock_unlock(&literals_rwlock);
+               return intern;
+       }
+
+       pthread_rwlock_unlock(&literals_rwlock);
+       pthread_rwlock_wrlock(&literals_rwlock);
+
+       /*
+        * XXX: we should notify GC here that we store a reference to
+        * string here (both as a key and a value). It should be
+        * marked as a weak reference.
+        */
+       intern = string;
+       if (hash_map_put(literals, string, intern)) {
+               NOT_IMPLEMENTED;
+               intern = NULL;
+       }
+
+       pthread_rwlock_unlock(&literals_rwlock);
+
+       return intern;
+}
-- 
1.6.0.6


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to