* src/vm/utf8.h, src/vm/utf8.c (utf8_safe_number_of_u2s): Modified to
[cacao.git] / src / vm / string.c
1 /* src/vm/string.c - java.lang.String related functions
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Reinhard Grafl
28             Roman Obermaisser
29             Andreas Krall
30
31    Changes: Christian Thalinger
32                         Edwin Steiner
33
34    $Id: string.c 5823 2006-10-24 23:24:19Z edwin $
35
36 */
37
38
39 #include "config.h"
40
41 #include <assert.h>
42
43 #include "vm/types.h"
44
45 #include "vm/global.h"
46
47 #include "mm/memory.h"
48 #include "native/include/java_lang_String.h"
49
50 #if defined(ENABLE_THREADS)
51 # include "threads/native/lock.h"
52 #else
53 # include "threads/none/lock.h"
54 #endif
55
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"
61 #include "vm/utf8.h"
62
63
64 /* global variables ***********************************************************/
65
66 /* hashsize must be power of 2 */
67
68 #define HASHTABLE_STRING_SIZE    2048   /* initial size of javastring-hash    */
69
70 hashtable hashtable_string;             /* hashtable for javastrings          */
71
72 #if defined(ENABLE_THREADS)
73 static java_objectheader *lock_hashtable_string;
74 #endif
75
76
77 /* global string definitions **************************************************/
78
79 /* exception/error super class */
80
81 const char *string_java_lang_Throwable =
82     "java/lang/Throwable";
83
84 const char *string_java_lang_VMThrowable =
85     "java/lang/VMThrowable";
86
87
88 /* specify some exception strings for code generation */
89
90 const char *string_java_lang_ArithmeticException =
91     "java/lang/ArithmeticException";
92
93 const char *string_java_lang_ArithmeticException_message =
94     "/ by zero";
95
96 const char *string_java_lang_ArrayIndexOutOfBoundsException =
97     "java/lang/ArrayIndexOutOfBoundsException";
98
99 const char *string_java_lang_ArrayStoreException =
100     "java/lang/ArrayStoreException";
101
102 const char *string_java_lang_ClassCastException =
103     "java/lang/ClassCastException";
104
105 const char *string_java_lang_ClassNotFoundException =
106         "java/lang/ClassNotFoundException";
107
108 const char *string_java_lang_CloneNotSupportedException =
109     "java/lang/CloneNotSupportedException";
110
111 const char *string_java_lang_Exception =
112     "java/lang/Exception";
113
114 const char *string_java_lang_IllegalAccessException =
115     "java/lang/IllegalAccessException";
116
117 const char *string_java_lang_IllegalArgumentException =
118     "java/lang/IllegalArgumentException";
119
120 const char *string_java_lang_IllegalMonitorStateException =
121     "java/lang/IllegalMonitorStateException";
122
123 const char *string_java_lang_IndexOutOfBoundsException =
124     "java/lang/IndexOutOfBoundsException";
125
126 const char *string_java_lang_InstantiationException =
127     "java/lang/InstantiationException";
128
129 const char *string_java_lang_InterruptedException =
130     "java/lang/InterruptedException";
131
132 const char *string_java_lang_NegativeArraySizeException =
133     "java/lang/NegativeArraySizeException";
134
135 const char *string_java_lang_NoSuchFieldException =
136         "java/lang/NoSuchFieldException";
137
138 const char *string_java_lang_NoSuchMethodException =
139         "java/lang/NoSuchMethodException";
140
141 const char *string_java_lang_NullPointerException =
142     "java/lang/NullPointerException";
143
144 const char *string_java_lang_StringIndexOutOfBoundsException =
145     "java/lang/StringIndexOutOfBoundsException";
146
147 const char *string_java_lang_reflect_InvocationTargetException =
148     "java/lang/reflect/InvocationTargetException";
149
150
151 /* specify some error strings for code generation */
152
153 const char *string_java_lang_AbstractMethodError =
154     "java/lang/AbstractMethodError";
155
156 const char *string_java_lang_ClassCircularityError =
157     "java/lang/ClassCircularityError";
158
159 const char *string_java_lang_ClassFormatError =
160     "java/lang/ClassFormatError";
161
162 const char *string_java_lang_Error =
163     "java/lang/Error";
164
165 const char *string_java_lang_ExceptionInInitializerError =
166     "java/lang/ExceptionInInitializerError";
167
168 const char *string_java_lang_IncompatibleClassChangeError =
169     "java/lang/IncompatibleClassChangeError";
170
171 const char *string_java_lang_InstantiationError =
172     "java/lang/InstantiationError";
173
174 const char *string_java_lang_InternalError =
175     "java/lang/InternalError";
176
177 const char *string_java_lang_LinkageError =
178     "java/lang/LinkageError";
179
180 const char *string_java_lang_NoClassDefFoundError =
181     "java/lang/NoClassDefFoundError";
182
183 const char *string_java_lang_NoSuchFieldError =
184         "java/lang/NoSuchFieldError";
185
186 const char *string_java_lang_NoSuchMethodError =
187         "java/lang/NoSuchMethodError";
188
189 const char *string_java_lang_OutOfMemoryError =
190     "java/lang/OutOfMemoryError";
191
192 const char *string_java_lang_UnsatisfiedLinkError =
193     "java/lang/UnsatisfiedLinkError";
194
195 const char *string_java_lang_UnsupportedClassVersionError =
196     "java/lang/UnsupportedClassVersionError";
197
198 const char *string_java_lang_VerifyError =
199     "java/lang/VerifyError";
200
201 const char *string_java_lang_VirtualMachineError =
202     "java/lang/VirtualMachineError";
203
204
205 /* string_init *****************************************************************
206
207    Initialize the string hashtable lock.
208
209 *******************************************************************************/
210
211 bool string_init(void)
212 {
213         /* create string (javastring) hashtable */
214
215         hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
216
217 #if defined(ENABLE_THREADS)
218         /* create string hashtable lock object */
219
220         lock_hashtable_string = NEW(java_objectheader);
221
222         lock_init_object_lock(lock_hashtable_string);
223 #endif
224
225         /* everything's ok */
226
227         return true;
228 }
229
230
231 /* stringtable_update **********************************************************
232
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.
236
237 *******************************************************************************/
238  
239 void stringtable_update(void)
240 {
241         java_lang_String *js;   
242         java_chararray *a;
243         literalstring *s;       /* hashtable entry */
244         int i;
245
246         for (i = 0; i < hashtable_string.size; i++) {
247                 s = hashtable_string.ptr[i];
248                 if (s) {
249                         while (s) {
250                                                                
251                                 js = (java_lang_String *) s->string;
252                                
253                                 if (!js || !js->value) {
254                                         /* error in hashtable found */
255                                         log_text("invalid literalstring in hashtable");
256                                         assert(0);
257                                 }
258
259                                 a = js->value;
260
261                                 if (!js->header.vftbl) 
262                                         /* vftbl of javastring is NULL */ 
263                                         js->header.vftbl = class_java_lang_String->vftbl;
264
265                                 if (!a->header.objheader.vftbl) 
266                                         /* vftbl of character-array is NULL */ 
267                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
268
269                                 /* follow link in external hash chain */
270                                 s = s->hashlink;
271                         }       
272                 }               
273         }
274 }
275
276
277 /* javastring_new_from_utf_buffer **********************************************
278
279    Create a new object of type java/lang/String with the text from
280    the specified utf8 buffer.
281
282    IN:
283       buffer.......points to first char in the buffer
284           blength......number of bytes to read from the buffer
285
286    RETURN VALUE:
287       the java.lang.String object, or
288       NULL if an exception has been thrown
289
290 *******************************************************************************/
291
292 java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength)
293 {
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                          */
297         java_chararray *a;
298         u4 i;
299
300         assert(buffer);
301
302         utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
303
304         s = (java_lang_String *) builtin_new(class_java_lang_String);
305         a = builtin_newarray_char(utflength);
306
307         /* javastring or character-array could not be created */
308         if (!a || !s)
309                 return NULL;
310
311         /* decompress utf-string */
312         utf_ptr = buffer;
313         for (i = 0; i < utflength; i++)
314                 a->data[i] = utf_nextu2((char **)&utf_ptr);
315         
316         /* set fields of the javastring-object */
317         s->value  = a;
318         s->offset = 0;
319         s->count  = utflength;
320
321         return s;
322 }
323
324
325 /* javastring_safe_new_from_utf8 ***********************************************
326
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.)
330
331    IN:
332       text.........the UTF-8 string, zero-terminated.
333
334    RETURN VALUE:
335       the java.lang.String object, or
336       NULL if an exception has been thrown
337
338 *******************************************************************************/
339
340 java_lang_String *javastring_safe_new_from_utf8(const char *text)
341 {
342         java_lang_String *s;            /* result-string                          */
343         java_chararray *a;
344         s4 nbytes;
345         s4 len;
346
347         assert(text);
348
349         /* Get number of bytes. We need this to completely emulate the messy */
350         /* behaviour of the RI. :(                                           */
351
352         nbytes = strlen(text);
353
354         /* calculate number of Java characters */
355
356         len = utf8_safe_number_of_u2s(text, nbytes);
357
358         /* allocate the String object and the char array */
359
360         s = (java_lang_String *) builtin_new(class_java_lang_String);
361         a = builtin_newarray_char(len);
362
363         /* javastring or character-array could not be created? */
364
365         if (!a || !s)
366                 return NULL;
367
368         /* decompress UTF-8 string */
369
370         utf8_safe_convert_to_u2s(text, nbytes, a->data);
371
372         /* set fields of the String object */
373
374         s->value  = a;
375         s->offset = 0;
376         s->count  = len;
377
378         return s;
379 }
380
381
382 /* javastring_new_from_utf_string **********************************************
383
384    Create a new object of type java/lang/String with the text from
385    the specified zero-terminated utf8 string.
386
387    IN:
388       buffer.......points to first char in the buffer
389           blength......number of bytes to read from the buffer
390
391    RETURN VALUE:
392       the java.lang.String object, or
393       NULL if an exception has been thrown
394
395 *******************************************************************************/
396
397 java_lang_String *javastring_new_from_utf_string(const char *utfstr)
398 {
399         assert(utfstr);
400
401         return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
402 }
403
404
405 /* javastring_new **************************************************************
406
407    creates a new object of type java/lang/String with the text of 
408    the specified utf8-string
409
410    return: pointer to the string or NULL if memory is exhausted.        
411
412 *******************************************************************************/
413
414 java_lang_String *javastring_new(utf *u)
415 {
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                          */
419         java_chararray *a;
420         s4 i;
421
422         if (!u) {
423                 exceptions_throw_nullpointerexception();
424                 return NULL;
425         }
426
427         utf_ptr = u->text;
428         utflength = utf_get_number_of_u2s(u);
429
430         s = (java_lang_String *) builtin_new(class_java_lang_String);
431         a = builtin_newarray_char(utflength);
432
433         /* javastring or character-array could not be created */
434         if (!a || !s)
435                 return NULL;
436
437         /* decompress utf-string */
438         for (i = 0; i < utflength; i++)
439                 a->data[i] = utf_nextu2(&utf_ptr);
440         
441         /* set fields of the javastring-object */
442         s->value  = a;
443         s->offset = 0;
444         s->count  = utflength;
445
446         return s;
447 }
448
449 /* javastring_new_slash_to_dot *************************************************
450
451    creates a new object of type java/lang/String with the text of 
452    the specified utf8-string with slashes changed to dots
453
454    return: pointer to the string or NULL if memory is exhausted.        
455
456 *******************************************************************************/
457
458 java_lang_String *javastring_new_slash_to_dot(utf *u)
459 {
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                          */
463         java_chararray *a;
464         s4 i;
465         u2 ch;
466
467         if (!u) {
468                 exceptions_throw_nullpointerexception();
469                 return NULL;
470         }
471
472         utf_ptr = u->text;
473         utflength = utf_get_number_of_u2s(u);
474
475         s = (java_lang_String *) builtin_new(class_java_lang_String);
476         a = builtin_newarray_char(utflength);
477
478         /* javastring or character-array could not be created */
479         if (!a || !s)
480                 return NULL;
481
482         /* decompress utf-string */
483         for (i = 0; i < utflength; i++) {
484                 ch = utf_nextu2(&utf_ptr);
485                 if (ch == '/')
486                         ch = '.';
487                 a->data[i] = ch;
488         }
489         
490         /* set fields of the javastring-object */
491         s->value  = a;
492         s->offset = 0;
493         s->count  = utflength;
494
495         return s;
496 }
497
498
499 /* javastring_new_from_ascii ***************************************************
500
501    creates a new java/lang/String object which contains the given ASCII
502    C-string converted to UTF-16.
503
504    IN:
505       text.........string of ASCII characters
506
507    RETURN VALUE:
508       the java.lang.String object, or 
509       NULL if an exception has been thrown.
510
511 *******************************************************************************/
512
513 java_lang_String *javastring_new_from_ascii(const char *text)
514 {
515         s4 i;
516         s4 len;                             /* length of the string               */
517         java_lang_String *s;                /* result-string                      */
518         java_chararray *a;
519
520         if (!text) {
521                 exceptions_throw_nullpointerexception();
522                 return NULL;
523         }
524
525         len = strlen(text);
526
527         s = (java_lang_String *) builtin_new(class_java_lang_String);
528         a = builtin_newarray_char(len);
529
530         /* javastring or character-array could not be created */
531         if (!a || !s)
532                 return NULL;
533
534         /* copy text */
535         for (i = 0; i < len; i++)
536                 a->data[i] = text[i];
537         
538         /* set fields of the javastring-object */
539         s->value  = a;
540         s->offset = 0;
541         s->count  = len;
542
543         return s;
544 }
545
546
547 /* javastring_tochar ***********************************************************
548
549    converts a Java string into a C string.
550         
551    return: pointer to C string
552         
553    Caution: calling method MUST release the allocated memory!
554         
555 *******************************************************************************/
556
557 char *javastring_tochar(java_objectheader *so) 
558 {
559         java_lang_String *s = (java_lang_String *) so;
560         java_chararray *a;
561         char *buf;
562         s4 i;
563         
564         if (!s)
565                 return "";
566
567         a = s->value;
568
569         if (!a)
570                 return "";
571
572         buf = MNEW(char, s->count + 1);
573
574         for (i = 0; i < s->count; i++)
575                 buf[i] = a->data[s->offset + i];
576
577         buf[i] = '\0';
578
579         return buf;
580 }
581
582
583 /* javastring_toutf ************************************************************
584
585    Make utf symbol from javastring.
586
587 *******************************************************************************/
588
589 utf *javastring_toutf(java_lang_String *s, bool isclassname)
590 {
591         if (s == NULL)
592                 return utf_null;
593
594         return utf_new_u2(s->value->data + s->offset, s->count, isclassname);
595 }
596
597
598 /* javastring_strlen ***********************************************************
599
600    Returns the length of the Java string.
601         
602 *******************************************************************************/
603
604 s4 javastring_strlen(java_lang_String *s)
605 {
606         if (s == NULL)
607                 return 0;
608
609         return s->count;
610 }
611
612
613 /* literalstring_u2 ************************************************************
614
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.
617
618    If copymode is true a copy of the u2-array is made.
619
620 *******************************************************************************/
621
622 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
623                                                                         bool copymode)
624 {
625     literalstring    *s;                /* hashtable element                  */
626     java_lang_String *js;               /* u2-array wrapped in javastring     */
627     java_chararray   *stringdata;       /* copy of u2-array                   */
628     u4                key;
629     u4                slot;
630     u2                i;
631
632         LOCK_MONITOR_ENTER(lock_hashtable_string);
633
634     /* find location in hashtable */
635
636     key  = unicode_hashkey(a->data + offset, length);
637     slot = key & (hashtable_string.size - 1);
638     s    = hashtable_string.ptr[slot];
639
640     while (s) {
641                 js = (java_lang_String *) s->string;
642
643                 if (length == js->count) {
644                         /* compare text */
645
646                         for (i = 0; i < length; i++)
647                                 if (a->data[offset + i] != js->value->data[i])
648                                         goto nomatch;
649
650                         /* string already in hashtable, free memory */
651
652                         if (!copymode)
653                                 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
654
655                         LOCK_MONITOR_EXIT(lock_hashtable_string);
656
657                         return (java_objectheader *) js;
658                 }
659
660         nomatch:
661                 /* follow link in external hash chain */
662                 s = s->hashlink;
663     }
664
665     if (copymode) {
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);
672
673     } else {
674                 stringdata = a;
675         }
676
677     /* location in hashtable found, complete arrayheader */
678
679     stringdata->header.objheader.vftbl =
680                 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
681     stringdata->header.size = length;
682
683         assert(class_java_lang_String);
684         assert(class_java_lang_String->state & CLASS_LOADED);
685
686         /* if we use eager loading, we have to check loaded String class */
687
688         if (opt_eager)
689                 list_add_first(&unlinkedclasses, class_java_lang_String);
690
691         /* create new javastring */
692
693         js = NEW(java_lang_String);
694
695 #if defined(ENABLE_THREADS)
696         lock_init_object_lock(&js->header);
697 #endif
698
699         js->header.vftbl = class_java_lang_String->vftbl;
700         js->value  = stringdata;
701         js->offset = 0;
702         js->count  = length;
703
704         /* create new literalstring */
705
706         s = NEW(literalstring);
707         s->hashlink = hashtable_string.ptr[slot];
708         s->string   = (java_objectheader *) js;
709         hashtable_string.ptr[slot] = s;
710
711         /* update number of hashtable entries */
712
713         hashtable_string.entries++;
714
715         /* reorganization of hashtable */       
716
717         if (hashtable_string.entries > (hashtable_string.size * 2)) {
718                 /* reorganization of hashtable, average length of the external
719                    chains is approx. 2 */
720
721                 u4                i;
722                 literalstring    *s;
723                 literalstring    *nexts;
724                 java_lang_String *tmpjs;
725                 hashtable         newhash;                       /* the new hashtable */
726       
727                 /* create new hashtable, double the size */
728
729                 hashtable_create(&newhash, hashtable_string.size * 2);
730                 newhash.entries = hashtable_string.entries;
731       
732                 /* transfer elements to new hashtable */
733
734                 for (i = 0; i < hashtable_string.size; i++) {
735                         s = hashtable_string.ptr[i];
736
737                         while (s) {
738                                 nexts = s->hashlink;
739                                 tmpjs = (java_lang_String *) s->string;
740                                 slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
741           
742                                 s->hashlink = newhash.ptr[slot];
743                                 newhash.ptr[slot] = s;
744         
745                                 /* follow link in external hash chain */
746                                 s = nexts;
747                         }
748                 }
749         
750                 /* dispose old table */
751
752                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
753                 hashtable_string = newhash;
754         }
755
756         LOCK_MONITOR_EXIT(lock_hashtable_string);
757
758         return (java_objectheader *) js;
759 }
760
761
762 /* literalstring_new ***********************************************************
763
764    Creates a new javastring with the text of the utf-symbol and inserts it into
765    the string hashtable.
766
767 *******************************************************************************/
768
769 java_objectheader *literalstring_new(utf *u)
770 {
771     char           *utf_ptr;         /* pointer to current unicode character  */
772                                          /* utf string                            */
773     u4              utflength;       /* length of utf-string if uncompressed  */
774     java_chararray *a;               /* u2-array constructed from utf string  */
775     u4              i;
776
777         utf_ptr = u->text;
778         utflength = utf_get_number_of_u2s(u);
779
780     /* allocate memory */ 
781     a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
782
783     /* convert utf-string to u2-array */
784     for (i = 0; i < utflength; i++)
785                 a->data[i] = utf_nextu2(&utf_ptr);
786
787     return literalstring_u2(a, utflength, 0, false);
788 }
789
790
791 /* literalstring_free **********************************************************
792
793    Removes a javastring from memory.
794
795 *******************************************************************************/
796
797 void literalstring_free(java_objectheader* sobj)
798 {
799         java_lang_String *s;
800         java_chararray *a;
801
802         s = (java_lang_String *) sobj;
803         a = s->value;
804
805         /* dispose memory of java.lang.String object */
806         FREE(s, java_lang_String);
807
808         /* dispose memory of java-characterarray */
809         FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
810 }
811
812
813 /*
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  * ---------------------------------------------------------------------
818  * Local variables:
819  * mode: c
820  * indent-tabs-mode: t
821  * c-basic-offset: 4
822  * tab-width: 4
823  * End:
824  * vim:noexpandtab:sw=4:ts=4:
825  */