1 /* src/vm/string.c - java.lang.String related functions
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Reinhard Grafl
31 Changes: Christian Thalinger
34 $Id: string.c 4908 2006-05-12 16:49:50Z edwin $
45 #include "vm/global.h"
47 #include "mm/memory.h"
48 #include "native/include/java_lang_String.h"
49 #include "vm/exceptions.h"
50 #include "vm/loader.h"
51 #include "vm/options.h"
52 #include "vm/stringlocal.h"
56 /* global variables ***********************************************************/
58 /* hashsize must be power of 2 */
60 #define HASHTABLE_STRING_SIZE 2048 /* initial size of javastring-hash */
62 hashtable hashtable_string; /* hashtable for javastrings */
64 #if defined(USE_THREADS)
65 static java_objectheader *lock_hashtable_string;
69 /* global string definitions **************************************************/
71 /* exception/error super class */
73 const char *string_java_lang_Throwable =
74 "java/lang/Throwable";
76 const char *string_java_lang_VMThrowable =
77 "java/lang/VMThrowable";
80 /* specify some exception strings for code generation */
82 const char *string_java_lang_ArithmeticException =
83 "java/lang/ArithmeticException";
85 const char *string_java_lang_ArithmeticException_message =
88 const char *string_java_lang_ArrayIndexOutOfBoundsException =
89 "java/lang/ArrayIndexOutOfBoundsException";
91 const char *string_java_lang_ArrayStoreException =
92 "java/lang/ArrayStoreException";
94 const char *string_java_lang_ClassCastException =
95 "java/lang/ClassCastException";
97 const char *string_java_lang_ClassNotFoundException =
98 "java/lang/ClassNotFoundException";
100 const char *string_java_lang_CloneNotSupportedException =
101 "java/lang/CloneNotSupportedException";
103 const char *string_java_lang_Exception =
104 "java/lang/Exception";
106 const char *string_java_lang_IllegalAccessException =
107 "java/lang/IllegalAccessException";
109 const char *string_java_lang_IllegalArgumentException =
110 "java/lang/IllegalArgumentException";
112 const char *string_java_lang_IllegalMonitorStateException =
113 "java/lang/IllegalMonitorStateException";
115 const char *string_java_lang_IndexOutOfBoundsException =
116 "java/lang/IndexOutOfBoundsException";
118 const char *string_java_lang_InstantiationException =
119 "java/lang/InstantiationException";
121 const char *string_java_lang_InterruptedException =
122 "java/lang/InterruptedException";
124 const char *string_java_lang_NegativeArraySizeException =
125 "java/lang/NegativeArraySizeException";
127 const char *string_java_lang_NoSuchFieldException =
128 "java/lang/NoSuchFieldException";
130 const char *string_java_lang_NoSuchMethodException =
131 "java/lang/NoSuchMethodException";
133 const char *string_java_lang_NullPointerException =
134 "java/lang/NullPointerException";
136 const char *string_java_lang_StringIndexOutOfBoundsException =
137 "java/lang/StringIndexOutOfBoundsException";
139 const char *string_java_lang_reflect_InvocationTargetException =
140 "java/lang/reflect/InvocationTargetException";
143 /* specify some error strings for code generation */
145 const char *string_java_lang_AbstractMethodError =
146 "java/lang/AbstractMethodError";
148 const char *string_java_lang_ClassCircularityError =
149 "java/lang/ClassCircularityError";
151 const char *string_java_lang_ClassFormatError =
152 "java/lang/ClassFormatError";
154 const char *string_java_lang_Error =
157 const char *string_java_lang_ExceptionInInitializerError =
158 "java/lang/ExceptionInInitializerError";
160 const char *string_java_lang_IncompatibleClassChangeError =
161 "java/lang/IncompatibleClassChangeError";
163 const char *string_java_lang_InstantiationError =
164 "java/lang/InstantiationError";
166 const char *string_java_lang_InternalError =
167 "java/lang/InternalError";
169 const char *string_java_lang_LinkageError =
170 "java/lang/LinkageError";
172 const char *string_java_lang_NoClassDefFoundError =
173 "java/lang/NoClassDefFoundError";
175 const char *string_java_lang_NoSuchFieldError =
176 "java/lang/NoSuchFieldError";
178 const char *string_java_lang_NoSuchMethodError =
179 "java/lang/NoSuchMethodError";
181 const char *string_java_lang_OutOfMemoryError =
182 "java/lang/OutOfMemoryError";
184 const char *string_java_lang_UnsatisfiedLinkError =
185 "java/lang/UnsatisfiedLinkError";
187 const char *string_java_lang_UnsupportedClassVersionError =
188 "java/lang/UnsupportedClassVersionError";
190 const char *string_java_lang_VerifyError =
191 "java/lang/VerifyError";
193 const char *string_java_lang_VirtualMachineError =
194 "java/lang/VirtualMachineError";
197 /* string_init *****************************************************************
199 Initialize the string hashtable lock.
201 *******************************************************************************/
203 bool string_init(void)
205 /* create string (javastring) hashtable */
207 hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
209 #if defined(USE_THREADS)
210 /* create string hashtable lock object */
212 lock_hashtable_string = NEW(java_objectheader);
214 # if defined(NATIVE_THREADS)
215 lock_init_object_lock(lock_hashtable_string);
219 /* everything's ok */
225 /* stringtable_update **********************************************************
227 Traverses the javastring hashtable and sets the vftbl-entries of
228 javastrings which were temporarily set to NULL, because
229 java.lang.Object was not yet loaded.
231 *******************************************************************************/
233 void stringtable_update(void)
235 java_lang_String *js;
237 literalstring *s; /* hashtable entry */
240 for (i = 0; i < hashtable_string.size; i++) {
241 s = hashtable_string.ptr[i];
245 js = (java_lang_String *) s->string;
247 if (!js || !js->value) {
248 /* error in hashtable found */
249 log_text("invalid literalstring in hashtable");
255 if (!js->header.vftbl)
256 /* vftbl of javastring is NULL */
257 js->header.vftbl = class_java_lang_String->vftbl;
259 if (!a->header.objheader.vftbl)
260 /* vftbl of character-array is NULL */
261 a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
263 /* follow link in external hash chain */
271 /* javastring_new_from_utf_buffer **********************************************
273 Create a new object of type java/lang/String with the text from
274 the specified utf8 buffer.
277 buffer.......points to first char in the buffer
278 blength......number of bytes to read from the buffer
281 the java.lang.String object, or
282 NULL if an exception has been thrown
284 *******************************************************************************/
286 java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength)
288 const char *utf_ptr; /* current utf character in utf string */
289 u4 utflength; /* length of utf-string if uncompressed */
290 java_lang_String *s; /* result-string */
296 utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
298 s = (java_lang_String *) builtin_new(class_java_lang_String);
299 a = builtin_newarray_char(utflength);
301 /* javastring or character-array could not be created */
305 /* decompress utf-string */
307 for (i = 0; i < utflength; i++)
308 a->data[i] = utf_nextu2((char **)&utf_ptr);
310 /* set fields of the javastring-object */
313 s->count = utflength;
319 /* javastring_new_from_utf_string **********************************************
321 Create a new object of type java/lang/String with the text from
322 the specified zero-terminated utf8 string.
325 buffer.......points to first char in the buffer
326 blength......number of bytes to read from the buffer
329 the java.lang.String object, or
330 NULL if an exception has been thrown
332 *******************************************************************************/
334 java_lang_String *javastring_new_from_utf_string(const char *utfstr)
338 return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
342 /* javastring_new **************************************************************
344 creates a new object of type java/lang/String with the text of
345 the specified utf8-string
347 return: pointer to the string or NULL if memory is exhausted.
349 *******************************************************************************/
351 java_lang_String *javastring_new(utf *u)
353 char *utf_ptr; /* current utf character in utf string */
354 u4 utflength; /* length of utf-string if uncompressed */
355 java_lang_String *s; /* result-string */
360 exceptions_throw_nullpointerexception();
365 utflength = utf_get_number_of_u2s(u);
367 s = (java_lang_String *) builtin_new(class_java_lang_String);
368 a = builtin_newarray_char(utflength);
370 /* javastring or character-array could not be created */
374 /* decompress utf-string */
375 for (i = 0; i < utflength; i++)
376 a->data[i] = utf_nextu2(&utf_ptr);
378 /* set fields of the javastring-object */
381 s->count = utflength;
386 /* javastring_new_slash_to_dot *************************************************
388 creates a new object of type java/lang/String with the text of
389 the specified utf8-string with slashes changed to dots
391 return: pointer to the string or NULL if memory is exhausted.
393 *******************************************************************************/
395 java_lang_String *javastring_new_slash_to_dot(utf *u)
397 char *utf_ptr; /* current utf character in utf string */
398 u4 utflength; /* length of utf-string if uncompressed */
399 java_lang_String *s; /* result-string */
405 exceptions_throw_nullpointerexception();
410 utflength = utf_get_number_of_u2s(u);
412 s = (java_lang_String *) builtin_new(class_java_lang_String);
413 a = builtin_newarray_char(utflength);
415 /* javastring or character-array could not be created */
419 /* decompress utf-string */
420 for (i = 0; i < utflength; i++) {
421 ch = utf_nextu2(&utf_ptr);
427 /* set fields of the javastring-object */
430 s->count = utflength;
436 /* javastring_new_from_ascii ***************************************************
438 creates a new java/lang/String object which contains the given ASCII
439 C-string converted to UTF-16.
442 text.........string of ASCII characters
445 the java.lang.String object, or
446 NULL if an exception has been thrown.
448 *******************************************************************************/
450 java_lang_String *javastring_new_from_ascii(const char *text)
453 s4 len; /* length of the string */
454 java_lang_String *s; /* result-string */
458 exceptions_throw_nullpointerexception();
464 s = (java_lang_String *) builtin_new(class_java_lang_String);
465 a = builtin_newarray_char(len);
467 /* javastring or character-array could not be created */
472 for (i = 0; i < len; i++)
473 a->data[i] = text[i];
475 /* set fields of the javastring-object */
484 /* javastring_tochar ***********************************************************
486 converts a Java string into a C string.
488 return: pointer to C string
490 Caution: calling method MUST release the allocated memory!
492 *******************************************************************************/
494 char *javastring_tochar(java_objectheader *so)
496 java_lang_String *s = (java_lang_String *) so;
509 buf = MNEW(char, s->count + 1);
511 for (i = 0; i < s->count; i++)
512 buf[i] = a->data[s->offset + i];
520 /* javastring_toutf ************************************************************
522 Make utf symbol from javastring.
524 *******************************************************************************/
526 utf *javastring_toutf(java_lang_String *string, bool isclassname)
528 java_lang_String *str = (java_lang_String *) string;
530 return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
534 /* javastring_strlen ***********************************************************
536 Returns the length of the Java string.
538 *******************************************************************************/
540 s4 javastring_strlen(java_lang_String *s)
549 /* literalstring_u2 ************************************************************
551 Searches for the javastring with the specified u2-array in the
552 string hashtable, if there is no such string a new one is created.
554 If copymode is true a copy of the u2-array is made.
556 *******************************************************************************/
558 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
561 literalstring *s; /* hashtable element */
562 java_lang_String *js; /* u2-array wrapped in javastring */
563 java_chararray *stringdata; /* copy of u2-array */
568 #if defined(USE_THREADS)
569 builtin_monitorenter(lock_hashtable_string);
572 /* find location in hashtable */
574 key = unicode_hashkey(a->data + offset, length);
575 slot = key & (hashtable_string.size - 1);
576 s = hashtable_string.ptr[slot];
579 js = (java_lang_String *) s->string;
581 if (length == js->count) {
584 for (i = 0; i < length; i++)
585 if (a->data[offset + i] != js->value->data[i])
588 /* string already in hashtable, free memory */
591 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
593 #if defined(USE_THREADS)
594 builtin_monitorexit(lock_hashtable_string);
597 return (java_objectheader *) js;
601 /* follow link in external hash chain */
606 /* create copy of u2-array for new javastring */
607 u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
608 stringdata = mem_alloc(arraysize);
609 /* memcpy(stringdata, a, arraysize); */
610 memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
611 memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
617 /* location in hashtable found, complete arrayheader */
619 stringdata->header.objheader.vftbl =
620 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
621 stringdata->header.size = length;
623 assert(class_java_lang_String);
624 assert(class_java_lang_String->state & CLASS_LOADED);
626 /* if we use eager loading, we have to check loaded String class */
629 list_addfirst(&unlinkedclasses, class_java_lang_String);
631 /* create new javastring */
633 js = NEW(java_lang_String);
635 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
636 lock_init_object_lock(&js->header);
639 js->header.vftbl = class_java_lang_String->vftbl;
640 js->value = stringdata;
644 /* create new literalstring */
646 s = NEW(literalstring);
647 s->hashlink = hashtable_string.ptr[slot];
648 s->string = (java_objectheader *) js;
649 hashtable_string.ptr[slot] = s;
651 /* update number of hashtable entries */
653 hashtable_string.entries++;
655 /* reorganization of hashtable */
657 if (hashtable_string.entries > (hashtable_string.size * 2)) {
658 /* reorganization of hashtable, average length of the external
659 chains is approx. 2 */
663 literalstring *nexts;
664 java_lang_String *tmpjs;
665 hashtable newhash; /* the new hashtable */
667 /* create new hashtable, double the size */
669 hashtable_create(&newhash, hashtable_string.size * 2);
670 newhash.entries = hashtable_string.entries;
672 /* transfer elements to new hashtable */
674 for (i = 0; i < hashtable_string.size; i++) {
675 s = hashtable_string.ptr[i];
679 tmpjs = (java_lang_String *) s->string;
680 slot = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
682 s->hashlink = newhash.ptr[slot];
683 newhash.ptr[slot] = s;
685 /* follow link in external hash chain */
690 /* dispose old table */
692 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
693 hashtable_string = newhash;
696 #if defined(USE_THREADS)
697 builtin_monitorexit(lock_hashtable_string);
700 return (java_objectheader *) js;
704 /* literalstring_new ***********************************************************
706 Creates a new javastring with the text of the utf-symbol and inserts it into
707 the string hashtable.
709 *******************************************************************************/
711 java_objectheader *literalstring_new(utf *u)
713 char *utf_ptr; /* pointer to current unicode character */
715 u4 utflength; /* length of utf-string if uncompressed */
716 java_chararray *a; /* u2-array constructed from utf string */
720 utflength = utf_get_number_of_u2s(u);
722 /* allocate memory */
723 a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
725 /* convert utf-string to u2-array */
726 for (i = 0; i < utflength; i++)
727 a->data[i] = utf_nextu2(&utf_ptr);
729 return literalstring_u2(a, utflength, 0, false);
733 /* literalstring_free **********************************************************
735 Removes a javastring from memory.
737 *******************************************************************************/
739 void literalstring_free(java_objectheader* sobj)
744 s = (java_lang_String *) sobj;
747 /* dispose memory of java.lang.String object */
748 FREE(s, java_lang_String);
750 /* dispose memory of java-characterarray */
751 FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
756 * These are local overrides for various environment variables in Emacs.
757 * Please do not remove this and leave it at the end of the file, where
758 * Emacs will automagically detect them.
759 * ---------------------------------------------------------------------
762 * indent-tabs-mode: t
766 * vim:noexpandtab:sw=4:ts=4: