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 5823 2006-10-24 23:24:19Z edwin $
45 #include "vm/global.h"
47 #include "mm/memory.h"
48 #include "native/include/java_lang_String.h"
50 #if defined(ENABLE_THREADS)
51 # include "threads/native/lock.h"
53 # include "threads/none/lock.h"
56 #include "vm/builtin.h"
57 #include "vm/exceptions.h"
58 #include "vm/loader.h"
59 #include "vm/options.h"
60 #include "vm/stringlocal.h"
64 /* global variables ***********************************************************/
66 /* hashsize must be power of 2 */
68 #define HASHTABLE_STRING_SIZE 2048 /* initial size of javastring-hash */
70 hashtable hashtable_string; /* hashtable for javastrings */
72 #if defined(ENABLE_THREADS)
73 static java_objectheader *lock_hashtable_string;
77 /* global string definitions **************************************************/
79 /* exception/error super class */
81 const char *string_java_lang_Throwable =
82 "java/lang/Throwable";
84 const char *string_java_lang_VMThrowable =
85 "java/lang/VMThrowable";
88 /* specify some exception strings for code generation */
90 const char *string_java_lang_ArithmeticException =
91 "java/lang/ArithmeticException";
93 const char *string_java_lang_ArithmeticException_message =
96 const char *string_java_lang_ArrayIndexOutOfBoundsException =
97 "java/lang/ArrayIndexOutOfBoundsException";
99 const char *string_java_lang_ArrayStoreException =
100 "java/lang/ArrayStoreException";
102 const char *string_java_lang_ClassCastException =
103 "java/lang/ClassCastException";
105 const char *string_java_lang_ClassNotFoundException =
106 "java/lang/ClassNotFoundException";
108 const char *string_java_lang_CloneNotSupportedException =
109 "java/lang/CloneNotSupportedException";
111 const char *string_java_lang_Exception =
112 "java/lang/Exception";
114 const char *string_java_lang_IllegalAccessException =
115 "java/lang/IllegalAccessException";
117 const char *string_java_lang_IllegalArgumentException =
118 "java/lang/IllegalArgumentException";
120 const char *string_java_lang_IllegalMonitorStateException =
121 "java/lang/IllegalMonitorStateException";
123 const char *string_java_lang_IndexOutOfBoundsException =
124 "java/lang/IndexOutOfBoundsException";
126 const char *string_java_lang_InstantiationException =
127 "java/lang/InstantiationException";
129 const char *string_java_lang_InterruptedException =
130 "java/lang/InterruptedException";
132 const char *string_java_lang_NegativeArraySizeException =
133 "java/lang/NegativeArraySizeException";
135 const char *string_java_lang_NoSuchFieldException =
136 "java/lang/NoSuchFieldException";
138 const char *string_java_lang_NoSuchMethodException =
139 "java/lang/NoSuchMethodException";
141 const char *string_java_lang_NullPointerException =
142 "java/lang/NullPointerException";
144 const char *string_java_lang_StringIndexOutOfBoundsException =
145 "java/lang/StringIndexOutOfBoundsException";
147 const char *string_java_lang_reflect_InvocationTargetException =
148 "java/lang/reflect/InvocationTargetException";
151 /* specify some error strings for code generation */
153 const char *string_java_lang_AbstractMethodError =
154 "java/lang/AbstractMethodError";
156 const char *string_java_lang_ClassCircularityError =
157 "java/lang/ClassCircularityError";
159 const char *string_java_lang_ClassFormatError =
160 "java/lang/ClassFormatError";
162 const char *string_java_lang_Error =
165 const char *string_java_lang_ExceptionInInitializerError =
166 "java/lang/ExceptionInInitializerError";
168 const char *string_java_lang_IncompatibleClassChangeError =
169 "java/lang/IncompatibleClassChangeError";
171 const char *string_java_lang_InstantiationError =
172 "java/lang/InstantiationError";
174 const char *string_java_lang_InternalError =
175 "java/lang/InternalError";
177 const char *string_java_lang_LinkageError =
178 "java/lang/LinkageError";
180 const char *string_java_lang_NoClassDefFoundError =
181 "java/lang/NoClassDefFoundError";
183 const char *string_java_lang_NoSuchFieldError =
184 "java/lang/NoSuchFieldError";
186 const char *string_java_lang_NoSuchMethodError =
187 "java/lang/NoSuchMethodError";
189 const char *string_java_lang_OutOfMemoryError =
190 "java/lang/OutOfMemoryError";
192 const char *string_java_lang_UnsatisfiedLinkError =
193 "java/lang/UnsatisfiedLinkError";
195 const char *string_java_lang_UnsupportedClassVersionError =
196 "java/lang/UnsupportedClassVersionError";
198 const char *string_java_lang_VerifyError =
199 "java/lang/VerifyError";
201 const char *string_java_lang_VirtualMachineError =
202 "java/lang/VirtualMachineError";
205 /* string_init *****************************************************************
207 Initialize the string hashtable lock.
209 *******************************************************************************/
211 bool string_init(void)
213 /* create string (javastring) hashtable */
215 hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
217 #if defined(ENABLE_THREADS)
218 /* create string hashtable lock object */
220 lock_hashtable_string = NEW(java_objectheader);
222 lock_init_object_lock(lock_hashtable_string);
225 /* everything's ok */
231 /* stringtable_update **********************************************************
233 Traverses the javastring hashtable and sets the vftbl-entries of
234 javastrings which were temporarily set to NULL, because
235 java.lang.Object was not yet loaded.
237 *******************************************************************************/
239 void stringtable_update(void)
241 java_lang_String *js;
243 literalstring *s; /* hashtable entry */
246 for (i = 0; i < hashtable_string.size; i++) {
247 s = hashtable_string.ptr[i];
251 js = (java_lang_String *) s->string;
253 if (!js || !js->value) {
254 /* error in hashtable found */
255 log_text("invalid literalstring in hashtable");
261 if (!js->header.vftbl)
262 /* vftbl of javastring is NULL */
263 js->header.vftbl = class_java_lang_String->vftbl;
265 if (!a->header.objheader.vftbl)
266 /* vftbl of character-array is NULL */
267 a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
269 /* follow link in external hash chain */
277 /* javastring_new_from_utf_buffer **********************************************
279 Create a new object of type java/lang/String with the text from
280 the specified utf8 buffer.
283 buffer.......points to first char in the buffer
284 blength......number of bytes to read from the buffer
287 the java.lang.String object, or
288 NULL if an exception has been thrown
290 *******************************************************************************/
292 java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength)
294 const char *utf_ptr; /* current utf character in utf string */
295 u4 utflength; /* length of utf-string if uncompressed */
296 java_lang_String *s; /* result-string */
302 utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
304 s = (java_lang_String *) builtin_new(class_java_lang_String);
305 a = builtin_newarray_char(utflength);
307 /* javastring or character-array could not be created */
311 /* decompress utf-string */
313 for (i = 0; i < utflength; i++)
314 a->data[i] = utf_nextu2((char **)&utf_ptr);
316 /* set fields of the javastring-object */
319 s->count = utflength;
325 /* javastring_safe_new_from_utf8 ***********************************************
327 Create a new object of type java/lang/String with the text from
328 the specified UTF-8 string. This function is safe for invalid UTF-8.
329 (Invalid characters will be replaced by U+fffd.)
332 text.........the UTF-8 string, zero-terminated.
335 the java.lang.String object, or
336 NULL if an exception has been thrown
338 *******************************************************************************/
340 java_lang_String *javastring_safe_new_from_utf8(const char *text)
342 java_lang_String *s; /* result-string */
349 /* Get number of bytes. We need this to completely emulate the messy */
350 /* behaviour of the RI. :( */
352 nbytes = strlen(text);
354 /* calculate number of Java characters */
356 len = utf8_safe_number_of_u2s(text, nbytes);
358 /* allocate the String object and the char array */
360 s = (java_lang_String *) builtin_new(class_java_lang_String);
361 a = builtin_newarray_char(len);
363 /* javastring or character-array could not be created? */
368 /* decompress UTF-8 string */
370 utf8_safe_convert_to_u2s(text, nbytes, a->data);
372 /* set fields of the String object */
382 /* javastring_new_from_utf_string **********************************************
384 Create a new object of type java/lang/String with the text from
385 the specified zero-terminated utf8 string.
388 buffer.......points to first char in the buffer
389 blength......number of bytes to read from the buffer
392 the java.lang.String object, or
393 NULL if an exception has been thrown
395 *******************************************************************************/
397 java_lang_String *javastring_new_from_utf_string(const char *utfstr)
401 return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
405 /* javastring_new **************************************************************
407 creates a new object of type java/lang/String with the text of
408 the specified utf8-string
410 return: pointer to the string or NULL if memory is exhausted.
412 *******************************************************************************/
414 java_lang_String *javastring_new(utf *u)
416 char *utf_ptr; /* current utf character in utf string */
417 u4 utflength; /* length of utf-string if uncompressed */
418 java_lang_String *s; /* result-string */
423 exceptions_throw_nullpointerexception();
428 utflength = utf_get_number_of_u2s(u);
430 s = (java_lang_String *) builtin_new(class_java_lang_String);
431 a = builtin_newarray_char(utflength);
433 /* javastring or character-array could not be created */
437 /* decompress utf-string */
438 for (i = 0; i < utflength; i++)
439 a->data[i] = utf_nextu2(&utf_ptr);
441 /* set fields of the javastring-object */
444 s->count = utflength;
449 /* javastring_new_slash_to_dot *************************************************
451 creates a new object of type java/lang/String with the text of
452 the specified utf8-string with slashes changed to dots
454 return: pointer to the string or NULL if memory is exhausted.
456 *******************************************************************************/
458 java_lang_String *javastring_new_slash_to_dot(utf *u)
460 char *utf_ptr; /* current utf character in utf string */
461 u4 utflength; /* length of utf-string if uncompressed */
462 java_lang_String *s; /* result-string */
468 exceptions_throw_nullpointerexception();
473 utflength = utf_get_number_of_u2s(u);
475 s = (java_lang_String *) builtin_new(class_java_lang_String);
476 a = builtin_newarray_char(utflength);
478 /* javastring or character-array could not be created */
482 /* decompress utf-string */
483 for (i = 0; i < utflength; i++) {
484 ch = utf_nextu2(&utf_ptr);
490 /* set fields of the javastring-object */
493 s->count = utflength;
499 /* javastring_new_from_ascii ***************************************************
501 creates a new java/lang/String object which contains the given ASCII
502 C-string converted to UTF-16.
505 text.........string of ASCII characters
508 the java.lang.String object, or
509 NULL if an exception has been thrown.
511 *******************************************************************************/
513 java_lang_String *javastring_new_from_ascii(const char *text)
516 s4 len; /* length of the string */
517 java_lang_String *s; /* result-string */
521 exceptions_throw_nullpointerexception();
527 s = (java_lang_String *) builtin_new(class_java_lang_String);
528 a = builtin_newarray_char(len);
530 /* javastring or character-array could not be created */
535 for (i = 0; i < len; i++)
536 a->data[i] = text[i];
538 /* set fields of the javastring-object */
547 /* javastring_tochar ***********************************************************
549 converts a Java string into a C string.
551 return: pointer to C string
553 Caution: calling method MUST release the allocated memory!
555 *******************************************************************************/
557 char *javastring_tochar(java_objectheader *so)
559 java_lang_String *s = (java_lang_String *) so;
572 buf = MNEW(char, s->count + 1);
574 for (i = 0; i < s->count; i++)
575 buf[i] = a->data[s->offset + i];
583 /* javastring_toutf ************************************************************
585 Make utf symbol from javastring.
587 *******************************************************************************/
589 utf *javastring_toutf(java_lang_String *s, bool isclassname)
594 return utf_new_u2(s->value->data + s->offset, s->count, isclassname);
598 /* javastring_strlen ***********************************************************
600 Returns the length of the Java string.
602 *******************************************************************************/
604 s4 javastring_strlen(java_lang_String *s)
613 /* literalstring_u2 ************************************************************
615 Searches for the javastring with the specified u2-array in the
616 string hashtable, if there is no such string a new one is created.
618 If copymode is true a copy of the u2-array is made.
620 *******************************************************************************/
622 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
625 literalstring *s; /* hashtable element */
626 java_lang_String *js; /* u2-array wrapped in javastring */
627 java_chararray *stringdata; /* copy of u2-array */
632 LOCK_MONITOR_ENTER(lock_hashtable_string);
634 /* find location in hashtable */
636 key = unicode_hashkey(a->data + offset, length);
637 slot = key & (hashtable_string.size - 1);
638 s = hashtable_string.ptr[slot];
641 js = (java_lang_String *) s->string;
643 if (length == js->count) {
646 for (i = 0; i < length; i++)
647 if (a->data[offset + i] != js->value->data[i])
650 /* string already in hashtable, free memory */
653 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
655 LOCK_MONITOR_EXIT(lock_hashtable_string);
657 return (java_objectheader *) js;
661 /* follow link in external hash chain */
666 /* create copy of u2-array for new javastring */
667 u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
668 stringdata = mem_alloc(arraysize);
669 /* memcpy(stringdata, a, arraysize); */
670 memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
671 memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
677 /* location in hashtable found, complete arrayheader */
679 stringdata->header.objheader.vftbl =
680 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
681 stringdata->header.size = length;
683 assert(class_java_lang_String);
684 assert(class_java_lang_String->state & CLASS_LOADED);
686 /* if we use eager loading, we have to check loaded String class */
689 list_add_first(&unlinkedclasses, class_java_lang_String);
691 /* create new javastring */
693 js = NEW(java_lang_String);
695 #if defined(ENABLE_THREADS)
696 lock_init_object_lock(&js->header);
699 js->header.vftbl = class_java_lang_String->vftbl;
700 js->value = stringdata;
704 /* create new literalstring */
706 s = NEW(literalstring);
707 s->hashlink = hashtable_string.ptr[slot];
708 s->string = (java_objectheader *) js;
709 hashtable_string.ptr[slot] = s;
711 /* update number of hashtable entries */
713 hashtable_string.entries++;
715 /* reorganization of hashtable */
717 if (hashtable_string.entries > (hashtable_string.size * 2)) {
718 /* reorganization of hashtable, average length of the external
719 chains is approx. 2 */
723 literalstring *nexts;
724 java_lang_String *tmpjs;
725 hashtable newhash; /* the new hashtable */
727 /* create new hashtable, double the size */
729 hashtable_create(&newhash, hashtable_string.size * 2);
730 newhash.entries = hashtable_string.entries;
732 /* transfer elements to new hashtable */
734 for (i = 0; i < hashtable_string.size; i++) {
735 s = hashtable_string.ptr[i];
739 tmpjs = (java_lang_String *) s->string;
740 slot = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
742 s->hashlink = newhash.ptr[slot];
743 newhash.ptr[slot] = s;
745 /* follow link in external hash chain */
750 /* dispose old table */
752 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
753 hashtable_string = newhash;
756 LOCK_MONITOR_EXIT(lock_hashtable_string);
758 return (java_objectheader *) js;
762 /* literalstring_new ***********************************************************
764 Creates a new javastring with the text of the utf-symbol and inserts it into
765 the string hashtable.
767 *******************************************************************************/
769 java_objectheader *literalstring_new(utf *u)
771 char *utf_ptr; /* pointer to current unicode character */
773 u4 utflength; /* length of utf-string if uncompressed */
774 java_chararray *a; /* u2-array constructed from utf string */
778 utflength = utf_get_number_of_u2s(u);
780 /* allocate memory */
781 a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
783 /* convert utf-string to u2-array */
784 for (i = 0; i < utflength; i++)
785 a->data[i] = utf_nextu2(&utf_ptr);
787 return literalstring_u2(a, utflength, 0, false);
791 /* literalstring_free **********************************************************
793 Removes a javastring from memory.
795 *******************************************************************************/
797 void literalstring_free(java_objectheader* sobj)
802 s = (java_lang_String *) sobj;
805 /* dispose memory of java.lang.String object */
806 FREE(s, java_lang_String);
808 /* dispose memory of java-characterarray */
809 FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
814 * These are local overrides for various environment variables in Emacs.
815 * Please do not remove this and leave it at the end of the file, where
816 * Emacs will automagically detect them.
817 * ---------------------------------------------------------------------
820 * indent-tabs-mode: t
824 * vim:noexpandtab:sw=4:ts=4: