* src/vm/jit/patcher-common.h (patcher_patch_code): Added prototype.
[cacao.git] / src / vm / string.c
index 64b0bf5f89b50e73ac53515f30b67fdad0318c2c..d8a1520b4e2d894a3c9c2d35359790459576d8f6 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/string.c - java.lang.String related functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   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
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Reinhard Grafl
-            Roman Obermaisser
-            Andreas Krall
-
-   Changes: Christian Thalinger
-
-   $Id: string.c 4357 2006-01-22 23:33:38Z twisti $
-
 */
 
 
+#include "config.h"
+
 #include <assert.h>
 
-#include "config.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 variables ***********************************************************/
 
 hashtable hashtable_string;             /* hashtable for javastrings          */
 
-#if defined(USE_THREADS)
-static java_objectheader *lock_hashtable_string;
+#if defined(ENABLE_THREADS)
+static java_object_t *lock_hashtable_string;
 #endif
 
 
-/* global string definitions **************************************************/
+/* string_init *****************************************************************
 
-/* exception/error super class */
+   Initialize the string hashtable lock.
 
-const char *string_java_lang_Throwable =
-    "java/lang/Throwable";
+*******************************************************************************/
 
-const char *string_java_lang_VMThrowable =
-    "java/lang/VMThrowable";
+bool string_init(void)
+{
+       /* create string (javastring) hashtable */
 
+       hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
 
-/* specify some exception strings for code generation */
+#if defined(ENABLE_THREADS)
+       /* create string hashtable lock object */
 
-const char *string_java_lang_ArithmeticException =
-    "java/lang/ArithmeticException";
+       lock_hashtable_string = NEW(java_object_t);
 
-const char *string_java_lang_ArithmeticException_message =
-    "/ by zero";
+       LOCK_INIT_OBJECT_LOCK(lock_hashtable_string);
+#endif
 
-const char *string_java_lang_ArrayIndexOutOfBoundsException =
-    "java/lang/ArrayIndexOutOfBoundsException";
+       /* everything's ok */
 
-const char *string_java_lang_ArrayStoreException =
-    "java/lang/ArrayStoreException";
+       return true;
+}
 
-const char *string_java_lang_ClassCastException =
-    "java/lang/ClassCastException";
 
-const char *string_java_lang_ClassNotFoundException =
-       "java/lang/ClassNotFoundException";
+/* stringtable_update **********************************************************
 
-const char *string_java_lang_CloneNotSupportedException =
-    "java/lang/CloneNotSupportedException";
+   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_Exception =
-    "java/lang/Exception";
+*******************************************************************************/
+void stringtable_update(void)
+{
+       java_lang_String *js;
+       java_chararray_t *a;
+       literalstring    *s;       /* hashtable entry */
+       int i;
 
-const char *string_java_lang_IllegalAccessException =
-    "java/lang/IllegalAccessException";
+       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_IllegalArgumentException =
-    "java/lang/IllegalArgumentException";
+                                       vm_abort("stringtable_update: invalid literalstring in hashtable");
+                               }
 
-const char *string_java_lang_IllegalMonitorStateException =
-    "java/lang/IllegalMonitorStateException";
+                               LLNI_field_get_ref(js, value, a);
 
-const char *string_java_lang_IndexOutOfBoundsException =
-    "java/lang/IndexOutOfBoundsException";
+                               if (!js->header.vftbl) 
+                                       /* vftbl of javastring is NULL */ 
+                                       js->header.vftbl = class_java_lang_String->vftbl;
 
-const char *string_java_lang_InstantiationException =
-    "java/lang/InstantiationException";
+                               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_InterruptedException =
-    "java/lang/InterruptedException";
+                               /* follow link in external hash chain */
+                               s = s->hashlink;
+                       }       
+               }               
+       }
+}
 
-const char *string_java_lang_NegativeArraySizeException =
-    "java/lang/NegativeArraySizeException";
 
-const char *string_java_lang_NoSuchFieldException =
-       "java/lang/NoSuchFieldException";
+/* javastring_new_from_utf_buffer **********************************************
 
-const char *string_java_lang_NoSuchMethodException =
-       "java/lang/NoSuchMethodException";
+   Create a new object of type java/lang/String with the text from
+   the specified utf8 buffer.
 
-const char *string_java_lang_NullPointerException =
-    "java/lang/NullPointerException";
+   IN:
+      buffer.......points to first char in the buffer
+         blength......number of bytes to read from the buffer
 
-const char *string_java_lang_reflect_InvocationTargetException =
-    "java/lang/reflect/InvocationTargetException";
+   RETURN VALUE:
+      the java.lang.String object, or
+      NULL if an exception has been thrown
 
+*******************************************************************************/
 
-/* specify some error strings for code generation */
+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_AbstractMethodError =
-    "java/lang/AbstractMethodError";
+       assert(buffer);
 
-const char *string_java_lang_ClassCircularityError =
-    "java/lang/ClassCircularityError";
+       utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
 
-const char *string_java_lang_ClassFormatError =
-    "java/lang/ClassFormatError";
+       o = builtin_new(class_java_lang_String);
+       a = builtin_newarray_char(utflength);
 
-const char *string_java_lang_Error =
-    "java/lang/Error";
+       /* javastring or character-array could not be created */
 
-const char *string_java_lang_ExceptionInInitializerError =
-    "java/lang/ExceptionInInitializerError";
+       if ((o == NULL) || (a == NULL))
+               return NULL;
 
-const char *string_java_lang_IncompatibleClassChangeError =
-    "java/lang/IncompatibleClassChangeError";
+       /* decompress utf-string */
 
-const char *string_java_lang_InstantiationError =
-    "java/lang/InstantiationError";
+       utf_ptr = buffer;
 
-const char *string_java_lang_InternalError =
-    "java/lang/InternalError";
+       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_LinkageError =
-    "java/lang/LinkageError";
+       s = (java_lang_String *) o;
 
-const char *string_java_lang_NoClassDefFoundError =
-    "java/lang/NoClassDefFoundError";
+       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_NoSuchFieldError =
-       "java/lang/NoSuchFieldError";
+       return o;
+}
 
-const char *string_java_lang_NoSuchMethodError =
-       "java/lang/NoSuchMethodError";
 
-const char *string_java_lang_OutOfMemoryError =
-    "java/lang/OutOfMemoryError";
+/* javastring_safe_new_from_utf8 ***********************************************
 
-const char *string_java_lang_UnsatisfiedLinkError =
-    "java/lang/UnsatisfiedLinkError";
+   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.)
 
-const char *string_java_lang_UnsupportedClassVersionError =
-    "java/lang/UnsupportedClassVersionError";
+   IN:
+      text.........the UTF-8 string, zero-terminated.
 
-const char *string_java_lang_VerifyError =
-    "java/lang/VerifyError";
+   RETURN VALUE:
+      the java.lang.String object, or
+      NULL if an exception has been thrown
 
-const char *string_java_lang_VirtualMachineError =
-    "java/lang/VirtualMachineError";
+*******************************************************************************/
 
+java_handle_t *javastring_safe_new_from_utf8(const char *text)
+{
+       java_handle_t           *o;
+       java_handle_chararray_t *a;
+       java_lang_String        *s;
+       s4 nbytes;
+       s4 len;
 
-/* string_init *****************************************************************
+       assert(text);
 
-   Initialize the string hashtable lock.
+       /* Get number of bytes. We need this to completely emulate the messy */
+       /* behaviour of the RI. :(                                           */
 
-*******************************************************************************/
+       nbytes = strlen(text);
 
-bool string_init(void)
-{
-       /* create string (javastring) hashtable */
+       /* calculate number of Java characters */
 
-       hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
+       len = utf8_safe_number_of_u2s(text, nbytes);
 
-#if defined(USE_THREADS)
-       /* create string hashtable lock object */
+       /* allocate the String object and the char array */
 
-       lock_hashtable_string = NEW(java_objectheader);
+       o = builtin_new(class_java_lang_String);
+       a = builtin_newarray_char(len);
 
-# if defined(NATIVE_THREADS)
-       initObjectLock(lock_hashtable_string);
-# endif
-#endif
+       /* javastring or character-array could not be created? */
 
-       /* everything's ok */
+       if ((o == NULL) || (a == NULL))
+               return NULL;
 
-       return true;
-}
+       /* decompress UTF-8 string */
 
+       utf8_safe_convert_to_u2s(text, nbytes, a->data);
 
-/* stringtable_update **********************************************************
+       /* set fields of the String object */
 
-   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.
+       s = (java_lang_String *) o;
 
-*******************************************************************************/
-void stringtable_update(void)
-{
-       java_lang_String *js;   
-       java_chararray *a;
-       literalstring *s;       /* hashtable entry */
-       int i;
+       LLNI_field_set_ref(s, value , a);
+       LLNI_field_set_val(s, offset, 0);
+       LLNI_field_set_val(s, count , len);
 
-       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 || !js->value) {
-                                       /* error in hashtable found */
-                                       log_text("invalid literalstring in hashtable");
-                                       assert(0);
-                               }
+       return o;
+}
 
-                               a = js->value;
 
-                               if (!js->header.vftbl) 
-                                       /* vftbl of javastring is NULL */ 
-                                       js->header.vftbl = class_java_lang_String->vftbl;
+/* javastring_new_from_utf_string **********************************************
 
-                               if (!a->header.objheader.vftbl) 
-                                       /* vftbl of character-array is NULL */ 
-                                       a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
+   Create a new object of type java/lang/String with the text from
+   the specified zero-terminated utf8 string.
 
-                               /* follow link in external hash chain */
-                               s = s->hashlink;
-                       }       
-               }               
-       }
+   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));
 }
 
 
@@ -272,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) {
+       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 
@@ -316,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) {
+       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) {
+       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;
 }
 
 
@@ -410,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';
 
@@ -442,26 +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;
 
+       s = (java_lang_String *) string;
 
-/* javastring_strlen ***********************************************************
+       if (s == NULL)
+               return utf_null;
 
-   Returns the length of the Java string.
-       
-*******************************************************************************/
-
-s4 javastring_strlen(java_lang_String *s)
-{
-       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);
 }
 
 
@@ -474,19 +502,17 @@ s4 javastring_strlen(java_lang_String *s)
 
 *******************************************************************************/
 
-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                   */
+    java_chararray_t *ca;               /* copy of u2-array                   */
     u4                key;
     u4                slot;
     u2                i;
 
-#if defined(USE_THREADS)
-       builtin_monitorenter(lock_hashtable_string);
-#endif
+       LOCK_MONITOR_ENTER(lock_hashtable_string);
 
     /* find location in hashtable */
 
@@ -507,13 +533,11 @@ java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
                        /* 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);
 
-#if defined(USE_THREADS)
-                       builtin_monitorexit(lock_hashtable_string);
-#endif
+                       LOCK_MONITOR_EXIT(lock_hashtable_string);
 
-                       return (java_objectheader *) js;
+                       return (java_object_t *) js;
                }
 
        nomatch:
@@ -523,52 +547,54 @@ 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->state & CLASS_LOADED);
 
-       /* if we use eager loading, we have to check loaded String class */
-
-       if (opt_eager)
-               list_addfirst(&unlinkedclasses, class_java_lang_String);
-
        /* 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);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_string += sizeof(literalstring);
+#endif
+
        s->hashlink = hashtable_string.ptr[slot];
-       s->string   = (java_objectheader *) js;
+       s->string   = (java_object_t *) js;
        hashtable_string.ptr[slot] = s;
 
        /* update number of hashtable entries */
@@ -616,11 +642,9 @@ java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
                hashtable_string = newhash;
        }
 
-#if defined(USE_THREADS)
-       builtin_monitorexit(lock_hashtable_string);
-#endif
+       LOCK_MONITOR_EXIT(lock_hashtable_string);
 
-       return (java_objectheader *) js;
+       return (java_object_t *) js;
 }
 
 
@@ -631,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++)
@@ -659,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);
+       }
 }
 
 
@@ -686,4 +765,5 @@ void literalstring_free(java_objectheader* sobj)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */