* Removed all Id tags.
[cacao.git] / src / vm / string.c
index 6e3ddb90fb1ad343abbd94347c8b5d3446da4730..d8a1520b4e2d894a3c9c2d35359790459576d8f6 100644 (file)
@@ -1,9 +1,9 @@
 /* src/vm/string.c - java.lang.String related functions
 
-   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
-
-   Contact: cacao@complang.tuwien.ac.at
-
-   Authors: Reinhard Grafl
-            Roman Obermaisser
-            Andreas Krall
-
-   Changes: Christian Thalinger
-
-   $Id: string.c 2663 2005-06-13 14:20:15Z twisti $
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
 */
 
 
+#include "config.h"
+
 #include <assert.h>
 
-#include "config.h"
-#include "types.h"
+#include "vm/types.h"
 
 #include "vm/global.h"
 
 #include "mm/memory.h"
+
+#include "native/jni.h"
+#include "native/llni.h"
+
 #include "native/include/java_lang_String.h"
+
+#include "threads/lock-common.h"
+
+#include "vm/array.h"
+#include "vm/builtin.h"
 #include "vm/exceptions.h"
-#include "vm/loader.h"
-#include "vm/options.h"
+#include "vm/primitive.h"
 #include "vm/stringlocal.h"
-#include "vm/utf8.h"
+#include "vm/vm.h"
 
+#include "vmcore/options.h"
+#include "vmcore/statistics.h"
+#include "vmcore/utf8.h"
 
-/* global string definitions **************************************************/
 
-/* exception/error super class */
+/* global variables ***********************************************************/
 
-const char *string_java_lang_Throwable =
-    "java/lang/Throwable";
+/* hashsize must be power of 2 */
 
-const char *string_java_lang_VMThrowable =
-    "java/lang/VMThrowable";
+#define HASHTABLE_STRING_SIZE    2048   /* initial size of javastring-hash    */
 
+hashtable hashtable_string;             /* hashtable for javastrings          */
+
+#if defined(ENABLE_THREADS)
+static java_object_t *lock_hashtable_string;
+#endif
 
-/* specify some exception strings for code generation */
 
-const char *string_java_lang_ArithmeticException =
-    "java/lang/ArithmeticException";
+/* string_init *****************************************************************
 
-const char *string_java_lang_ArithmeticException_message =
-    "/ by zero";
+   Initialize the string hashtable lock.
 
-const char *string_java_lang_ArrayIndexOutOfBoundsException =
-    "java/lang/ArrayIndexOutOfBoundsException";
+*******************************************************************************/
 
-const char *string_java_lang_ArrayStoreException =
-    "java/lang/ArrayStoreException";
+bool string_init(void)
+{
+       /* create string (javastring) hashtable */
 
-const char *string_java_lang_ClassCastException =
-    "java/lang/ClassCastException";
+       hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
 
-const char *string_java_lang_ClassNotFoundException =
-       "java/lang/ClassNotFoundException";
+#if defined(ENABLE_THREADS)
+       /* create string hashtable lock object */
 
-const char *string_java_lang_CloneNotSupportedException =
-    "java/lang/CloneNotSupportedException";
+       lock_hashtable_string = NEW(java_object_t);
 
-const char *string_java_lang_Exception =
-    "java/lang/Exception";
+       LOCK_INIT_OBJECT_LOCK(lock_hashtable_string);
+#endif
 
-const char *string_java_lang_IllegalAccessException =
-    "java/lang/IllegalAccessException";
+       /* everything's ok */
 
-const char *string_java_lang_IllegalArgumentException =
-    "java/lang/IllegalArgumentException";
+       return true;
+}
+
+
+/* stringtable_update **********************************************************
+
+   Traverses the javastring hashtable and sets the vftbl-entries of
+   javastrings which were temporarily set to NULL, because
+   java.lang.Object was not yet loaded.
 
-const char *string_java_lang_IllegalMonitorStateException =
-    "java/lang/IllegalMonitorStateException";
+*******************************************************************************/
+void stringtable_update(void)
+{
+       java_lang_String *js;
+       java_chararray_t *a;
+       literalstring    *s;       /* hashtable entry */
+       int i;
 
-const char *string_java_lang_IndexOutOfBoundsException =
-    "java/lang/IndexOutOfBoundsException";
+       for (i = 0; i < hashtable_string.size; i++) {
+               s = hashtable_string.ptr[i];
+               if (s) {
+                       while (s) {
+                               js = (java_lang_String *) s->string;
+                               
+                               if ((js == NULL) || (js->value == NULL)) {
+                                       /* error in hashtable found */
 
-const char *string_java_lang_InstantiationException =
-    "java/lang/InstantiationException";
+                                       vm_abort("stringtable_update: invalid literalstring in hashtable");
+                               }
 
-const char *string_java_lang_InterruptedException =
-    "java/lang/InterruptedException";
+                               LLNI_field_get_ref(js, value, a);
 
-const char *string_java_lang_NegativeArraySizeException =
-    "java/lang/NegativeArraySizeException";
+                               if (!js->header.vftbl) 
+                                       /* vftbl of javastring is NULL */ 
+                                       js->header.vftbl = class_java_lang_String->vftbl;
 
-const char *string_java_lang_NoSuchFieldException =
-       "java/lang/NoSuchFieldException";
+                               if (!a->header.objheader.vftbl) 
+                                       /* vftbl of character-array is NULL */ 
+                                       a->header.objheader.vftbl =
+                                               primitive_arrayclass_get_by_type(ARRAYTYPE_CHAR)->vftbl;
 
-const char *string_java_lang_NoSuchMethodException =
-       "java/lang/NoSuchMethodException";
+                               /* follow link in external hash chain */
+                               s = s->hashlink;
+                       }       
+               }               
+       }
+}
 
-const char *string_java_lang_NullPointerException =
-    "java/lang/NullPointerException";
 
-const char *string_java_lang_reflect_InvocationTargetException =
-    "java/lang/reflect/InvocationTargetException";
+/* javastring_new_from_utf_buffer **********************************************
 
+   Create a new object of type java/lang/String with the text from
+   the specified utf8 buffer.
 
-/* specify some error strings for code generation */
+   IN:
+      buffer.......points to first char in the buffer
+         blength......number of bytes to read from the buffer
 
-const char *string_java_lang_AbstractMethodError =
-    "java/lang/AbstractMethodError";
+   RETURN VALUE:
+      the java.lang.String object, or
+      NULL if an exception has been thrown
 
-const char *string_java_lang_ClassCircularityError =
-    "java/lang/ClassCircularityError";
+*******************************************************************************/
 
-const char *string_java_lang_ClassFormatError =
-    "java/lang/ClassFormatError";
+static java_handle_t *javastring_new_from_utf_buffer(const char *buffer,
+                                                                                                                u4 blength)
+{
+       const char *utf_ptr;            /* current utf character in utf string    */
+       u4 utflength;                   /* length of utf-string if uncompressed   */
+       java_handle_t     *o;
+       java_lang_String  *s;           /* result-string                          */
+       java_handle_chararray_t *a;
+       u4 i;
 
-const char *string_java_lang_Error =
-    "java/lang/Error";
+       assert(buffer);
 
-const char *string_java_lang_ExceptionInInitializerError =
-    "java/lang/ExceptionInInitializerError";
+       utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
 
-const char *string_java_lang_IncompatibleClassChangeError =
-    "java/lang/IncompatibleClassChangeError";
+       o = builtin_new(class_java_lang_String);
+       a = builtin_newarray_char(utflength);
 
-const char *string_java_lang_InternalError =
-    "java/lang/InternalError";
+       /* javastring or character-array could not be created */
 
-const char *string_java_lang_LinkageError =
-    "java/lang/LinkageError";
+       if ((o == NULL) || (a == NULL))
+               return NULL;
 
-const char *string_java_lang_NoClassDefFoundError =
-    "java/lang/NoClassDefFoundError";
+       /* decompress utf-string */
 
-const char *string_java_lang_NoSuchFieldError =
-       "java/lang/NoSuchFieldError";
+       utf_ptr = buffer;
 
-const char *string_java_lang_NoSuchMethodError =
-       "java/lang/NoSuchMethodError";
+       for (i = 0; i < utflength; i++)
+               LLNI_array_direct(a, i) = utf_nextu2((char **) &utf_ptr);
+       
+       /* set fields of the javastring-object */
 
-const char *string_java_lang_OutOfMemoryError =
-    "java/lang/OutOfMemoryError";
+       s = (java_lang_String *) o;
 
-const char *string_java_lang_UnsatisfiedLinkError =
-    "java/lang/UnsatisfiedLinkError";
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , utflength);
 
-const char *string_java_lang_UnsupportedClassVersionError =
-    "java/lang/UnsupportedClassVersionError";
+       return o;
+}
 
-const char *string_java_lang_VerifyError =
-    "java/lang/VerifyError";
 
-const char *string_java_lang_VirtualMachineError =
-    "java/lang/VirtualMachineError";
+/* javastring_safe_new_from_utf8 ***********************************************
 
+   Create a new object of type java/lang/String with the text from
+   the specified UTF-8 string. This function is safe for invalid UTF-8.
+   (Invalid characters will be replaced by U+fffd.)
 
-/* stringtable_update **********************************************************
+   IN:
+      text.........the UTF-8 string, zero-terminated.
 
-   Traverses the javastring hashtable and sets the vftbl-entries of
-   javastrings which were temporarily set to NULL, because
-   java.lang.Object was not yet loaded.
+   RETURN VALUE:
+      the java.lang.String object, or
+      NULL if an exception has been thrown
 
 *******************************************************************************/
-void stringtable_update(void)
+
+java_handle_t *javastring_safe_new_from_utf8(const char *text)
 {
-       java_lang_String *js;   
-       java_chararray *a;
-       literalstring *s;       /* hashtable entry */
-       int i;
+       java_handle_t           *o;
+       java_handle_chararray_t *a;
+       java_lang_String        *s;
+       s4 nbytes;
+       s4 len;
 
-       for (i = 0; i < string_hash.size; i++) {
-               s = string_hash.ptr[i];
-               if (s) {
-                       while (s) {
-                                                               
-                               js = (java_lang_String *) s->string;
-                               
-                               if (!js || !js->value) {
-                                       /* error in hashtable found */
-                                       log_text("invalid literalstring in hashtable");
-                                       assert(0);
-                               }
+       assert(text);
 
-                               a = js->value;
+       /* Get number of bytes. We need this to completely emulate the messy */
+       /* behaviour of the RI. :(                                           */
 
-                               if (!js->header.vftbl) 
-                                       /* vftbl of javastring is NULL */ 
-                                       js->header.vftbl = class_java_lang_String->vftbl;
+       nbytes = strlen(text);
 
-                               if (!a->header.objheader.vftbl) 
-                                       /* vftbl of character-array is NULL */ 
-                                       a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
+       /* calculate number of Java characters */
 
-                               /* follow link in external hash chain */
-                               s = s->hashlink;
-                       }       
-               }               
-       }
+       len = utf8_safe_number_of_u2s(text, nbytes);
+
+       /* allocate the String object and the char array */
+
+       o = builtin_new(class_java_lang_String);
+       a = builtin_newarray_char(len);
+
+       /* javastring or character-array could not be created? */
+
+       if ((o == NULL) || (a == NULL))
+               return NULL;
+
+       /* decompress UTF-8 string */
+
+       utf8_safe_convert_to_u2s(text, nbytes, a->data);
+
+       /* set fields of the String object */
+
+       s = (java_lang_String *) o;
+
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , len);
+
+       return o;
+}
+
+
+/* javastring_new_from_utf_string **********************************************
+
+   Create a new object of type java/lang/String with the text from
+   the specified zero-terminated utf8 string.
+
+   IN:
+      buffer.......points to first char in the buffer
+         blength......number of bytes to read from the buffer
+
+   RETURN VALUE:
+      the java.lang.String object, or
+      NULL if an exception has been thrown
+
+*******************************************************************************/
+
+java_handle_t *javastring_new_from_utf_string(const char *utfstr)
+{
+       assert(utfstr);
+
+       return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
 }
 
 
@@ -228,41 +287,48 @@ void stringtable_update(void)
 
 *******************************************************************************/
 
-java_lang_String *javastring_new(utf *u)
+java_handle_t *javastring_new(utf *u)
 {
        char *utf_ptr;                  /* current utf character in utf string    */
        u4 utflength;                   /* length of utf-string if uncompressed   */
-       java_lang_String *s;            /* result-string                          */
-       java_chararray *a;
+       java_handle_t           *o;
+       java_handle_chararray_t *a;
+       java_lang_String        *s;
        s4 i;
 
-       if (!u) {
-               *exceptionptr = new_nullpointerexception();
+       if (u == NULL) {
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
        utf_ptr = u->text;
-       utflength = utf_strlen(u);
+       utflength = utf_get_number_of_u2s(u);
 
-       s = (java_lang_String *) builtin_new(class_java_lang_String);
+       o = builtin_new(class_java_lang_String);
        a = builtin_newarray_char(utflength);
 
        /* javastring or character-array could not be created */
-       if (!a || !s)
+
+       if ((o == NULL) || (a == NULL))
                return NULL;
 
        /* decompress utf-string */
+
        for (i = 0; i < utflength; i++)
-               a->data[i] = utf_nextu2(&utf_ptr);
+               LLNI_array_direct(a, i) = utf_nextu2(&utf_ptr);
        
        /* set fields of the javastring-object */
-       s->value  = a;
-       s->offset = 0;
-       s->count  = utflength;
 
-       return s;
+       s = (java_lang_String *) o;
+
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , utflength);
+
+       return o;
 }
 
+
 /* javastring_new_slash_to_dot *************************************************
 
    creates a new object of type java/lang/String with the text of 
@@ -272,87 +338,103 @@ java_lang_String *javastring_new(utf *u)
 
 *******************************************************************************/
 
-java_lang_String *javastring_new_slash_to_dot(utf *u)
+java_handle_t *javastring_new_slash_to_dot(utf *u)
 {
        char *utf_ptr;                  /* current utf character in utf string    */
        u4 utflength;                   /* length of utf-string if uncompressed   */
-       java_lang_String *s;            /* result-string                          */
-       java_chararray *a;
+       java_handle_t           *o;
+       java_handle_chararray_t *a;
+       java_lang_String        *s;
        s4 i;
        u2 ch;
 
-       if (!u) {
-               *exceptionptr = new_nullpointerexception();
+       if (u == NULL) {
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
        utf_ptr = u->text;
-       utflength = utf_strlen(u);
+       utflength = utf_get_number_of_u2s(u);
 
-       s = (java_lang_String *) builtin_new(class_java_lang_String);
+       o = builtin_new(class_java_lang_String);
        a = builtin_newarray_char(utflength);
 
        /* javastring or character-array could not be created */
-       if (!a || !s)
+       if ((o == NULL) || (a == NULL))
                return NULL;
 
        /* decompress utf-string */
+
        for (i = 0; i < utflength; i++) {
                ch = utf_nextu2(&utf_ptr);
                if (ch == '/')
                        ch = '.';
-               a->data[i] = ch;
+               LLNI_array_direct(a, i) = ch;
        }
        
        /* set fields of the javastring-object */
-       s->value  = a;
-       s->offset = 0;
-       s->count  = utflength;
 
-       return s;
+       s = (java_lang_String *) o;
+
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , utflength);
+
+       return o;
 }
 
 
-/* javastring_new_char *********************************************************
+/* javastring_new_from_ascii ***************************************************
 
-   creates a new java/lang/String object which contains the convertet
-   C-string passed via text.
+   creates a new java/lang/String object which contains the given ASCII
+   C-string converted to UTF-16.
 
-   return: the object pointer or NULL if memory is exhausted.
+   IN:
+      text.........string of ASCII characters
+
+   RETURN VALUE:
+      the java.lang.String object, or 
+      NULL if an exception has been thrown.
 
 *******************************************************************************/
 
-java_lang_String *javastring_new_char(const char *text)
+java_handle_t *javastring_new_from_ascii(const char *text)
 {
        s4 i;
        s4 len;                             /* length of the string               */
-       java_lang_String *s;                /* result-string                      */
-       java_chararray *a;
+       java_handle_t           *o;
+       java_lang_String        *s;
+       java_handle_chararray_t *a;
 
-       if (!text) {
-               *exceptionptr = new_nullpointerexception();
+       if (text == NULL) {
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
        len = strlen(text);
 
-       s = (java_lang_String *) builtin_new(class_java_lang_String);
+       o = builtin_new(class_java_lang_String);
        a = builtin_newarray_char(len);
 
        /* javastring or character-array could not be created */
-       if (!a || !s)
+
+       if ((o == NULL) || (a == NULL))
                return NULL;
 
        /* copy text */
+
        for (i = 0; i < len; i++)
-               a->data[i] = text[i];
+               LLNI_array_direct(a, i) = text[i];
        
        /* set fields of the javastring-object */
-       s->value  = a;
-       s->offset = 0;
-       s->count  = len;
 
-       return s;
+       s = (java_lang_String *) o;
+
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , len);
+
+       return o;
 }
 
 
@@ -366,25 +448,25 @@ java_lang_String *javastring_new_char(const char *text)
        
 *******************************************************************************/
 
-char *javastring_tochar(java_objectheader *so) 
+char *javastring_tochar(java_handle_t *so) 
 {
-       java_lang_String *s = (java_lang_String *) so;
-       java_chararray *a;
+       java_lang_String        *s = (java_lang_String *) so;
+       java_handle_chararray_t *a;
        char *buf;
        s4 i;
        
        if (!s)
                return "";
 
-       a = s->value;
+       LLNI_field_get_ref(s, value, a);
 
        if (!a)
                return "";
 
-       buf = MNEW(char, s->count + 1);
+       buf = MNEW(char, LLNI_field_direct(s, count) + 1);
 
-       for (i = 0; i < s->count; i++)
-               buf[i] = a->data[s->offset + i];
+       for (i = 0; i < LLNI_field_direct(s, count); i++)
+               buf[i] = a->data[LLNI_field_direct(s, offset) + i];
 
        buf[i] = '\0';
 
@@ -398,28 +480,16 @@ char *javastring_tochar(java_objectheader *so)
 
 *******************************************************************************/
 
-utf *javastring_toutf(java_lang_String *string, bool isclassname)
+utf *javastring_toutf(java_handle_t *string, bool isclassname)
 {
-       java_lang_String *str = (java_lang_String *) string;
-
-       return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
-}
-
+       java_lang_String *s;
 
-/* javastring_strlen ***********************************************************
+       s = (java_lang_String *) string;
 
-   Returns the length of the Java string.
-       
-*******************************************************************************/
+       if (s == NULL)
+               return utf_null;
 
-s4 javastring_strlen(java_objectheader *so)
-{
-       java_lang_String *s = (java_lang_String *) so;
-       
-       if (!s)
-               return 0;
-
-       return s->count;
+       return utf_new_u2(LLNI_field_direct(s, value)->data + LLNI_field_direct(s, offset), LLNI_field_direct(s, count), isclassname);
 }
 
 
@@ -432,36 +502,42 @@ s4 javastring_strlen(java_objectheader *so)
 
 *******************************************************************************/
 
-java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
-                                                                       bool copymode)
+java_object_t *literalstring_u2(java_chararray_t *a, u4 length, u4 offset,
+                                                               bool copymode)
 {
-    literalstring *s;                /* hashtable element */
-    java_lang_String *js;            /* u2-array wrapped in javastring */
-    java_chararray *stringdata;      /* copy of u2-array */      
-    u4 key;
-    u4 slot;
-    u2 i;
+    literalstring    *s;                /* hashtable element                  */
+    java_lang_String *js;               /* u2-array wrapped in javastring     */
+    java_chararray_t *ca;               /* copy of u2-array                   */
+    u4                key;
+    u4                slot;
+    u2                i;
+
+       LOCK_MONITOR_ENTER(lock_hashtable_string);
 
     /* find location in hashtable */
+
     key  = unicode_hashkey(a->data + offset, length);
-    slot = key & (string_hash.size - 1);
-    s    = string_hash.ptr[slot];
+    slot = key & (hashtable_string.size - 1);
+    s    = hashtable_string.ptr[slot];
 
     while (s) {
                js = (java_lang_String *) s->string;
 
                if (length == js->count) {
                        /* compare text */
-                       for (i = 0; i < length; i++) {
+
+                       for (i = 0; i < length; i++)
                                if (a->data[offset + i] != js->value->data[i])
                                        goto nomatch;
-                       }
 
                        /* string already in hashtable, free memory */
+
                        if (!copymode)
-                               mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
+                               mem_free(a, sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10);
+
+                       LOCK_MONITOR_EXIT(lock_hashtable_string);
 
-                       return (java_objectheader *) js;
+                       return (java_object_t *) js;
                }
 
        nomatch:
@@ -471,89 +547,104 @@ java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
 
     if (copymode) {
                /* create copy of u2-array for new javastring */
-               u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
-               stringdata = mem_alloc(arraysize);
-/*             memcpy(stringdata, a, arraysize); */
-               memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
-               memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
+               u4 arraysize = sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10;
+               ca = mem_alloc(arraysize);
+/*             memcpy(ca, a, arraysize); */
+               memcpy(&(ca->header), &(a->header), sizeof(java_array_t));
+               memcpy(&(ca->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
 
     } else {
-               stringdata = a;
+               ca = a;
        }
 
     /* location in hashtable found, complete arrayheader */
 
-    stringdata->header.objheader.vftbl =
-               primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
-    stringdata->header.size = length;
-
-       /* XXX TWISTI: is this necessary? */
-       if (!class_java_lang_String)
-               class_java_lang_String = load_class_bootstrap(utf_java_lang_String);
+    ca->header.objheader.vftbl =
+               primitive_arrayclass_get_by_type(ARRAYTYPE_CHAR)->vftbl;
+    ca->header.size            = length;
 
        assert(class_java_lang_String);
-       assert(class_java_lang_String->loaded);
-
-       /* if we use eager loading, we have to check loaded String class */
-
-       if (opt_eager)
-               list_addfirst(&unlinkedclasses, class_java_lang_String);
+       assert(class_java_lang_String->state & CLASS_LOADED);
 
        /* create new javastring */
 
        js = NEW(java_lang_String);
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       initObjectLock(&js->header);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_string += sizeof(java_lang_String);
+#endif
+
+#if defined(ENABLE_THREADS)
+       lock_init_object_lock(&js->header);
 #endif
+
        js->header.vftbl = class_java_lang_String->vftbl;
-       js->value  = stringdata;
+       js->value  = ca;
        js->offset = 0;
        js->count  = length;
 
        /* create new literalstring */
+
        s = NEW(literalstring);
-       s->hashlink = string_hash.ptr[slot];
-       s->string   = (java_objectheader *) js;
-       string_hash.ptr[slot] = s;
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_string += sizeof(literalstring);
+#endif
+
+       s->hashlink = hashtable_string.ptr[slot];
+       s->string   = (java_object_t *) js;
+       hashtable_string.ptr[slot] = s;
 
        /* update number of hashtable entries */
-       string_hash.entries++;
+
+       hashtable_string.entries++;
 
        /* reorganization of hashtable */       
-       if (string_hash.entries > (string_hash.size * 2)) {
-               /* reorganization of hashtable, average length of 
-                  the external chains is approx. 2                */  
 
-               u4 i;
-               literalstring *s;
-               hashtable newhash; /* the new hashtable */
+       if (hashtable_string.entries > (hashtable_string.size * 2)) {
+               /* reorganization of hashtable, average length of the external
+                  chains is approx. 2 */
+
+               u4                i;
+               literalstring    *s;
+               literalstring    *nexts;
+               java_lang_String *tmpjs;
+               hashtable         newhash;                       /* the new hashtable */
       
                /* create new hashtable, double the size */
-               init_hashtable(&newhash, string_hash.size * 2);
-               newhash.entries = string_hash.entries;
+
+               hashtable_create(&newhash, hashtable_string.size * 2);
+               newhash.entries = hashtable_string.entries;
       
                /* transfer elements to new hashtable */
-               for (i = 0; i < string_hash.size; i++) {
-                       s = string_hash.ptr[i];
+
+               for (i = 0; i < hashtable_string.size; i++) {
+                       s = hashtable_string.ptr[i];
+
                        while (s) {
-                               literalstring *nexts = s->hashlink;
-                               js   = (java_lang_String *) s->string;
-                               slot = unicode_hashkey(js->value->data, js->count) & (newhash.size - 1);
+                               nexts = s->hashlink;
+                               tmpjs = (java_lang_String *) s->string;
+                               slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
          
                                s->hashlink = newhash.ptr[slot];
                                newhash.ptr[slot] = s;
        
-                               /* follow link in external hash chain */  
+                               /* follow link in external hash chain */
                                s = nexts;
                        }
                }
        
-               /* dispose old table */ 
-               MFREE(string_hash.ptr, void*, string_hash.size);
-               string_hash = newhash;
+               /* dispose old table */
+
+               MFREE(hashtable_string.ptr, void*, hashtable_string.size);
+               hashtable_string = newhash;
        }
 
-       return (java_objectheader *) js;
+       LOCK_MONITOR_EXIT(lock_hashtable_string);
+
+       return (java_object_t *) js;
 }
 
 
@@ -564,19 +655,19 @@ java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
 
 *******************************************************************************/
 
-java_objectheader *literalstring_new(utf *u)
+java_object_t *literalstring_new(utf *u)
 {
-    char *utf_ptr;                   /* pointer to current unicode character  */
+    char             *utf_ptr;       /* pointer to current unicode character  */
                                         /* utf string                            */
-    u4 utflength;                    /* length of utf-string if uncompressed  */
-    java_chararray *a;               /* u2-array constructed from utf string  */
-    u4 i;
+    u4                utflength;     /* length of utf-string if uncompressed  */
+    java_chararray_t *a;             /* u2-array constructed from utf string  */
+    u4                i;
 
        utf_ptr = u->text;
-       utflength = utf_strlen(u);
+       utflength = utf_get_number_of_u2s(u);
 
     /* allocate memory */ 
-    a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
+    a = mem_alloc(sizeof(java_chararray_t) + sizeof(u2) * (utflength - 1) + 10);
 
     /* convert utf-string to u2-array */
     for (i = 0; i < utflength; i++)
@@ -592,19 +683,74 @@ java_objectheader *literalstring_new(utf *u)
 
 *******************************************************************************/
 
-void literalstring_free(java_objectheader* sobj)
+void literalstring_free(java_object_t* string)
 {
        java_lang_String *s;
-       java_chararray *a;
+       java_chararray_t *a;
 
-       s = (java_lang_String *) sobj;
+       s = (java_lang_String *) string;
        a = s->value;
 
        /* dispose memory of java.lang.String object */
        FREE(s, java_lang_String);
 
        /* dispose memory of java-characterarray */
-       FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
+       FREE(a, sizeof(java_chararray_t) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
+}
+
+
+/* javastring_intern ***********************************************************
+
+   Intern the given Java string.
+
+*******************************************************************************/
+
+java_handle_t *javastring_intern(java_handle_t *s)
+{
+       java_lang_String *so;
+       java_chararray_t *value;
+       int32_t           count;
+       int32_t           offset;
+/*     java_lang_String *o; */
+       java_object_t    *o;
+
+       so = (java_lang_String *) s;
+
+       value  = LLNI_field_direct(so, value);
+       count  = LLNI_field_direct(so, count);
+       offset = LLNI_field_direct(so, offset);
+
+       o = literalstring_u2(value, count, offset, true);
+
+       return o;
+}
+
+
+/* javastring_print ************************************************************
+
+   Print the given Java string.
+
+*******************************************************************************/
+
+void javastring_print(java_handle_t *s)
+{
+       java_lang_String *so;
+       java_chararray_t *value;
+       int32_t           count;
+       int32_t           offset;
+       uint16_t          c;
+       int               i;
+
+       so = (java_lang_String *) s;
+
+       value  = LLNI_field_direct(so, value);
+       count  = LLNI_field_direct(so, count);
+       offset = LLNI_field_direct(so, offset);
+
+       for (i = offset; i < offset + count; i++) {
+               c = LLNI_array_direct(value, i);
+               putchar(c);
+       }
 }
 
 
@@ -619,4 +765,5 @@ void literalstring_free(java_objectheader* sobj)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */