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