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