* src/threads/native/threads.c: The Big Thread Cleanup. No functional changes,
[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 4908 2006-05-12 16:49:50Z 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 #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(USE_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(USE_THREADS)
210         /* create string hashtable lock object */
211
212         lock_hashtable_string = NEW(java_objectheader);
213
214 # if defined(NATIVE_THREADS)
215         lock_init_object_lock(lock_hashtable_string);
216 # endif
217 #endif
218
219         /* everything's ok */
220
221         return true;
222 }
223
224
225 /* stringtable_update **********************************************************
226
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.
230
231 *******************************************************************************/
232  
233 void stringtable_update(void)
234 {
235         java_lang_String *js;   
236         java_chararray *a;
237         literalstring *s;       /* hashtable entry */
238         int i;
239
240         for (i = 0; i < hashtable_string.size; i++) {
241                 s = hashtable_string.ptr[i];
242                 if (s) {
243                         while (s) {
244                                                                
245                                 js = (java_lang_String *) s->string;
246                                
247                                 if (!js || !js->value) {
248                                         /* error in hashtable found */
249                                         log_text("invalid literalstring in hashtable");
250                                         assert(0);
251                                 }
252
253                                 a = js->value;
254
255                                 if (!js->header.vftbl) 
256                                         /* vftbl of javastring is NULL */ 
257                                         js->header.vftbl = class_java_lang_String->vftbl;
258
259                                 if (!a->header.objheader.vftbl) 
260                                         /* vftbl of character-array is NULL */ 
261                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
262
263                                 /* follow link in external hash chain */
264                                 s = s->hashlink;
265                         }       
266                 }               
267         }
268 }
269
270
271 /* javastring_new_from_utf_buffer **********************************************
272
273    Create a new object of type java/lang/String with the text from
274    the specified utf8 buffer.
275
276    IN:
277       buffer.......points to first char in the buffer
278           blength......number of bytes to read from the buffer
279
280    RETURN VALUE:
281       the java.lang.String object, or
282       NULL if an exception has been thrown
283
284 *******************************************************************************/
285
286 java_lang_String *javastring_new_from_utf_buffer(const char *buffer, u4 blength)
287 {
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                          */
291         java_chararray *a;
292         u4 i;
293
294         assert(buffer);
295
296         utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
297
298         s = (java_lang_String *) builtin_new(class_java_lang_String);
299         a = builtin_newarray_char(utflength);
300
301         /* javastring or character-array could not be created */
302         if (!a || !s)
303                 return NULL;
304
305         /* decompress utf-string */
306         utf_ptr = buffer;
307         for (i = 0; i < utflength; i++)
308                 a->data[i] = utf_nextu2((char **)&utf_ptr);
309         
310         /* set fields of the javastring-object */
311         s->value  = a;
312         s->offset = 0;
313         s->count  = utflength;
314
315         return s;
316 }
317
318
319 /* javastring_new_from_utf_string **********************************************
320
321    Create a new object of type java/lang/String with the text from
322    the specified zero-terminated utf8 string.
323
324    IN:
325       buffer.......points to first char in the buffer
326           blength......number of bytes to read from the buffer
327
328    RETURN VALUE:
329       the java.lang.String object, or
330       NULL if an exception has been thrown
331
332 *******************************************************************************/
333
334 java_lang_String *javastring_new_from_utf_string(const char *utfstr)
335 {
336         assert(utfstr);
337
338         return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
339 }
340
341
342 /* javastring_new **************************************************************
343
344    creates a new object of type java/lang/String with the text of 
345    the specified utf8-string
346
347    return: pointer to the string or NULL if memory is exhausted.        
348
349 *******************************************************************************/
350
351 java_lang_String *javastring_new(utf *u)
352 {
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                          */
356         java_chararray *a;
357         s4 i;
358
359         if (!u) {
360                 exceptions_throw_nullpointerexception();
361                 return NULL;
362         }
363
364         utf_ptr = u->text;
365         utflength = utf_get_number_of_u2s(u);
366
367         s = (java_lang_String *) builtin_new(class_java_lang_String);
368         a = builtin_newarray_char(utflength);
369
370         /* javastring or character-array could not be created */
371         if (!a || !s)
372                 return NULL;
373
374         /* decompress utf-string */
375         for (i = 0; i < utflength; i++)
376                 a->data[i] = utf_nextu2(&utf_ptr);
377         
378         /* set fields of the javastring-object */
379         s->value  = a;
380         s->offset = 0;
381         s->count  = utflength;
382
383         return s;
384 }
385
386 /* javastring_new_slash_to_dot *************************************************
387
388    creates a new object of type java/lang/String with the text of 
389    the specified utf8-string with slashes changed to dots
390
391    return: pointer to the string or NULL if memory is exhausted.        
392
393 *******************************************************************************/
394
395 java_lang_String *javastring_new_slash_to_dot(utf *u)
396 {
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                          */
400         java_chararray *a;
401         s4 i;
402         u2 ch;
403
404         if (!u) {
405                 exceptions_throw_nullpointerexception();
406                 return NULL;
407         }
408
409         utf_ptr = u->text;
410         utflength = utf_get_number_of_u2s(u);
411
412         s = (java_lang_String *) builtin_new(class_java_lang_String);
413         a = builtin_newarray_char(utflength);
414
415         /* javastring or character-array could not be created */
416         if (!a || !s)
417                 return NULL;
418
419         /* decompress utf-string */
420         for (i = 0; i < utflength; i++) {
421                 ch = utf_nextu2(&utf_ptr);
422                 if (ch == '/')
423                         ch = '.';
424                 a->data[i] = ch;
425         }
426         
427         /* set fields of the javastring-object */
428         s->value  = a;
429         s->offset = 0;
430         s->count  = utflength;
431
432         return s;
433 }
434
435
436 /* javastring_new_from_ascii ***************************************************
437
438    creates a new java/lang/String object which contains the given ASCII
439    C-string converted to UTF-16.
440
441    IN:
442       text.........string of ASCII characters
443
444    RETURN VALUE:
445       the java.lang.String object, or 
446       NULL if an exception has been thrown.
447
448 *******************************************************************************/
449
450 java_lang_String *javastring_new_from_ascii(const char *text)
451 {
452         s4 i;
453         s4 len;                             /* length of the string               */
454         java_lang_String *s;                /* result-string                      */
455         java_chararray *a;
456
457         if (!text) {
458                 exceptions_throw_nullpointerexception();
459                 return NULL;
460         }
461
462         len = strlen(text);
463
464         s = (java_lang_String *) builtin_new(class_java_lang_String);
465         a = builtin_newarray_char(len);
466
467         /* javastring or character-array could not be created */
468         if (!a || !s)
469                 return NULL;
470
471         /* copy text */
472         for (i = 0; i < len; i++)
473                 a->data[i] = text[i];
474         
475         /* set fields of the javastring-object */
476         s->value  = a;
477         s->offset = 0;
478         s->count  = len;
479
480         return s;
481 }
482
483
484 /* javastring_tochar ***********************************************************
485
486    converts a Java string into a C string.
487         
488    return: pointer to C string
489         
490    Caution: calling method MUST release the allocated memory!
491         
492 *******************************************************************************/
493
494 char *javastring_tochar(java_objectheader *so) 
495 {
496         java_lang_String *s = (java_lang_String *) so;
497         java_chararray *a;
498         char *buf;
499         s4 i;
500         
501         if (!s)
502                 return "";
503
504         a = s->value;
505
506         if (!a)
507                 return "";
508
509         buf = MNEW(char, s->count + 1);
510
511         for (i = 0; i < s->count; i++)
512                 buf[i] = a->data[s->offset + i];
513
514         buf[i] = '\0';
515
516         return buf;
517 }
518
519
520 /* javastring_toutf ************************************************************
521
522    Make utf symbol from javastring.
523
524 *******************************************************************************/
525
526 utf *javastring_toutf(java_lang_String *string, bool isclassname)
527 {
528         java_lang_String *str = (java_lang_String *) string;
529
530         return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
531 }
532
533
534 /* javastring_strlen ***********************************************************
535
536    Returns the length of the Java string.
537         
538 *******************************************************************************/
539
540 s4 javastring_strlen(java_lang_String *s)
541 {
542         if (!s)
543                 return 0;
544
545         return s->count;
546 }
547
548
549 /* literalstring_u2 ************************************************************
550
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.
553
554    If copymode is true a copy of the u2-array is made.
555
556 *******************************************************************************/
557
558 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
559                                                                         bool copymode)
560 {
561     literalstring    *s;                /* hashtable element                  */
562     java_lang_String *js;               /* u2-array wrapped in javastring     */
563     java_chararray   *stringdata;       /* copy of u2-array                   */
564     u4                key;
565     u4                slot;
566     u2                i;
567
568 #if defined(USE_THREADS)
569         builtin_monitorenter(lock_hashtable_string);
570 #endif
571
572     /* find location in hashtable */
573
574     key  = unicode_hashkey(a->data + offset, length);
575     slot = key & (hashtable_string.size - 1);
576     s    = hashtable_string.ptr[slot];
577
578     while (s) {
579                 js = (java_lang_String *) s->string;
580
581                 if (length == js->count) {
582                         /* compare text */
583
584                         for (i = 0; i < length; i++)
585                                 if (a->data[offset + i] != js->value->data[i])
586                                         goto nomatch;
587
588                         /* string already in hashtable, free memory */
589
590                         if (!copymode)
591                                 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
592
593 #if defined(USE_THREADS)
594                         builtin_monitorexit(lock_hashtable_string);
595 #endif
596
597                         return (java_objectheader *) js;
598                 }
599
600         nomatch:
601                 /* follow link in external hash chain */
602                 s = s->hashlink;
603     }
604
605     if (copymode) {
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);
612
613     } else {
614                 stringdata = a;
615         }
616
617     /* location in hashtable found, complete arrayheader */
618
619     stringdata->header.objheader.vftbl =
620                 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
621     stringdata->header.size = length;
622
623         assert(class_java_lang_String);
624         assert(class_java_lang_String->state & CLASS_LOADED);
625
626         /* if we use eager loading, we have to check loaded String class */
627
628         if (opt_eager)
629                 list_addfirst(&unlinkedclasses, class_java_lang_String);
630
631         /* create new javastring */
632
633         js = NEW(java_lang_String);
634
635 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
636         lock_init_object_lock(&js->header);
637 #endif
638
639         js->header.vftbl = class_java_lang_String->vftbl;
640         js->value  = stringdata;
641         js->offset = 0;
642         js->count  = length;
643
644         /* create new literalstring */
645
646         s = NEW(literalstring);
647         s->hashlink = hashtable_string.ptr[slot];
648         s->string   = (java_objectheader *) js;
649         hashtable_string.ptr[slot] = s;
650
651         /* update number of hashtable entries */
652
653         hashtable_string.entries++;
654
655         /* reorganization of hashtable */       
656
657         if (hashtable_string.entries > (hashtable_string.size * 2)) {
658                 /* reorganization of hashtable, average length of the external
659                    chains is approx. 2 */
660
661                 u4                i;
662                 literalstring    *s;
663                 literalstring    *nexts;
664                 java_lang_String *tmpjs;
665                 hashtable         newhash;                       /* the new hashtable */
666       
667                 /* create new hashtable, double the size */
668
669                 hashtable_create(&newhash, hashtable_string.size * 2);
670                 newhash.entries = hashtable_string.entries;
671       
672                 /* transfer elements to new hashtable */
673
674                 for (i = 0; i < hashtable_string.size; i++) {
675                         s = hashtable_string.ptr[i];
676
677                         while (s) {
678                                 nexts = s->hashlink;
679                                 tmpjs = (java_lang_String *) s->string;
680                                 slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
681           
682                                 s->hashlink = newhash.ptr[slot];
683                                 newhash.ptr[slot] = s;
684         
685                                 /* follow link in external hash chain */
686                                 s = nexts;
687                         }
688                 }
689         
690                 /* dispose old table */
691
692                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
693                 hashtable_string = newhash;
694         }
695
696 #if defined(USE_THREADS)
697         builtin_monitorexit(lock_hashtable_string);
698 #endif
699
700         return (java_objectheader *) js;
701 }
702
703
704 /* literalstring_new ***********************************************************
705
706    Creates a new javastring with the text of the utf-symbol and inserts it into
707    the string hashtable.
708
709 *******************************************************************************/
710
711 java_objectheader *literalstring_new(utf *u)
712 {
713     char           *utf_ptr;         /* pointer to current unicode character  */
714                                          /* utf string                            */
715     u4              utflength;       /* length of utf-string if uncompressed  */
716     java_chararray *a;               /* u2-array constructed from utf string  */
717     u4              i;
718
719         utf_ptr = u->text;
720         utflength = utf_get_number_of_u2s(u);
721
722     /* allocate memory */ 
723     a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
724
725     /* convert utf-string to u2-array */
726     for (i = 0; i < utflength; i++)
727                 a->data[i] = utf_nextu2(&utf_ptr);
728
729     return literalstring_u2(a, utflength, 0, false);
730 }
731
732
733 /* literalstring_free **********************************************************
734
735    Removes a javastring from memory.
736
737 *******************************************************************************/
738
739 void literalstring_free(java_objectheader* sobj)
740 {
741         java_lang_String *s;
742         java_chararray *a;
743
744         s = (java_lang_String *) sobj;
745         a = s->value;
746
747         /* dispose memory of java.lang.String object */
748         FREE(s, java_lang_String);
749
750         /* dispose memory of java-characterarray */
751         FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
752 }
753
754
755 /*
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  * ---------------------------------------------------------------------
760  * Local variables:
761  * mode: c
762  * indent-tabs-mode: t
763  * c-basic-offset: 4
764  * tab-width: 4
765  * End:
766  * vim:noexpandtab:sw=4:ts=4:
767  */