* src/cacaoh/headers.h (literalstring_free): Removed obsolete prototype.
[cacao.git] / src / vm / string.c
1 /* src/vm/string.c - java.lang.String related functions
2
3    Copyright (C) 1996-2005, 2006, 2007 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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31
32 #include "vm/types.h"
33
34 #include "vm/global.h"
35
36 #include "mm/memory.h"
37
38 #include "native/jni.h"
39 #include "native/llni.h"
40
41 #include "native/include/java_lang_String.h"
42
43 #include "threads/lock-common.h"
44
45 #include "vm/array.h"
46 #include "vm/builtin.h"
47 #include "vm/exceptions.h"
48 #include "vm/primitive.h"
49 #include "vm/stringlocal.h"
50 #include "vm/vm.h"
51
52 #include "vmcore/options.h"
53 #include "vmcore/statistics.h"
54 #include "vmcore/utf8.h"
55
56
57 /* global variables ***********************************************************/
58
59 /* hashsize must be power of 2 */
60
61 #define HASHTABLE_STRING_SIZE    2048   /* initial size of javastring-hash    */
62
63 hashtable hashtable_string;             /* hashtable for javastrings          */
64
65 #if defined(ENABLE_THREADS)
66 static java_object_t *lock_hashtable_string;
67 #endif
68
69
70 /* XXX preliminary typedef, will be removed once string.c and utf8.c are
71    unified. */
72
73 #if defined(ENABLE_HANDLES)
74 typedef heap_java_lang_String heapstring_t;
75 #else
76 typedef java_lang_String heapstring_t;
77 #endif
78
79
80 /* string_init *****************************************************************
81
82    Initialize the string hashtable lock.
83
84 *******************************************************************************/
85
86 bool string_init(void)
87 {
88         /* create string (javastring) hashtable */
89
90         hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
91
92 #if defined(ENABLE_THREADS)
93         /* create string hashtable lock object */
94
95         lock_hashtable_string = NEW(java_object_t);
96
97         LOCK_INIT_OBJECT_LOCK(lock_hashtable_string);
98 #endif
99
100         /* everything's ok */
101
102         return true;
103 }
104
105
106 /* stringtable_update **********************************************************
107
108    Traverses the javastring hashtable and sets the vftbl-entries of
109    javastrings which were temporarily set to NULL, because
110    java.lang.Object was not yet loaded.
111
112 *******************************************************************************/
113  
114 void stringtable_update(void)
115 {
116         heapstring_t     *js;
117         java_chararray_t *a;
118         literalstring    *s;       /* hashtable entry */
119         int i;
120
121         for (i = 0; i < hashtable_string.size; i++) {
122                 s = hashtable_string.ptr[i];
123                 if (s) {
124                         while (s) {
125                                 js = (heapstring_t *) s->string;
126                                
127                                 if ((js == NULL) || (js->value == NULL)) {
128                                         /* error in hashtable found */
129
130                                         vm_abort("stringtable_update: invalid literalstring in hashtable");
131                                 }
132
133                                 a = js->value;
134
135                                 if (!js->header.vftbl) 
136                                         /* vftbl of javastring is NULL */ 
137                                         js->header.vftbl = class_java_lang_String->vftbl;
138
139                                 if (!a->header.objheader.vftbl) 
140                                         /* vftbl of character-array is NULL */ 
141                                         a->header.objheader.vftbl =
142                                                 primitive_arrayclass_get_by_type(ARRAYTYPE_CHAR)->vftbl;
143
144                                 /* follow link in external hash chain */
145                                 s = s->hashlink;
146                         }       
147                 }               
148         }
149 }
150
151
152 /* javastring_new_from_utf_buffer **********************************************
153
154    Create a new object of type java/lang/String with the text from
155    the specified utf8 buffer.
156
157    IN:
158       buffer.......points to first char in the buffer
159           blength......number of bytes to read from the buffer
160
161    RETURN VALUE:
162       the java.lang.String object, or
163       NULL if an exception has been thrown
164
165 *******************************************************************************/
166
167 static java_handle_t *javastring_new_from_utf_buffer(const char *buffer,
168                                                                                                                  u4 blength)
169 {
170         const char *utf_ptr;            /* current utf character in utf string    */
171         u4 utflength;                   /* length of utf-string if uncompressed   */
172         java_handle_t     *o;
173         java_lang_String  *s;           /* result-string                          */
174         java_handle_chararray_t *a;
175         u4 i;
176
177         assert(buffer);
178
179         utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
180
181         o = builtin_new(class_java_lang_String);
182         a = builtin_newarray_char(utflength);
183
184         /* javastring or character-array could not be created */
185
186         if ((o == NULL) || (a == NULL))
187                 return NULL;
188
189         /* decompress utf-string */
190
191         utf_ptr = buffer;
192
193         for (i = 0; i < utflength; i++)
194                 LLNI_array_direct(a, i) = utf_nextu2((char **) &utf_ptr);
195         
196         /* set fields of the javastring-object */
197
198         s = (java_lang_String *) o;
199
200         LLNI_field_set_ref(s, value , a);
201         LLNI_field_set_val(s, offset, 0);
202         LLNI_field_set_val(s, count , utflength);
203
204         return o;
205 }
206
207
208 /* javastring_safe_new_from_utf8 ***********************************************
209
210    Create a new object of type java/lang/String with the text from
211    the specified UTF-8 string. This function is safe for invalid UTF-8.
212    (Invalid characters will be replaced by U+fffd.)
213
214    IN:
215       text.........the UTF-8 string, zero-terminated.
216
217    RETURN VALUE:
218       the java.lang.String object, or
219       NULL if an exception has been thrown
220
221 *******************************************************************************/
222
223 java_handle_t *javastring_safe_new_from_utf8(const char *text)
224 {
225         java_handle_t           *o;
226         java_handle_chararray_t *a;
227         java_lang_String        *s;
228         s4 nbytes;
229         s4 len;
230
231         assert(text);
232
233         /* Get number of bytes. We need this to completely emulate the messy */
234         /* behaviour of the RI. :(                                           */
235
236         nbytes = strlen(text);
237
238         /* calculate number of Java characters */
239
240         len = utf8_safe_number_of_u2s(text, nbytes);
241
242         /* allocate the String object and the char array */
243
244         o = builtin_new(class_java_lang_String);
245         a = builtin_newarray_char(len);
246
247         /* javastring or character-array could not be created? */
248
249         if ((o == NULL) || (a == NULL))
250                 return NULL;
251
252         /* decompress UTF-8 string */
253
254         utf8_safe_convert_to_u2s(text, nbytes, LLNI_array_data(a));
255
256         /* set fields of the String object */
257
258         s = (java_lang_String *) o;
259
260         LLNI_field_set_ref(s, value , a);
261         LLNI_field_set_val(s, offset, 0);
262         LLNI_field_set_val(s, count , len);
263
264         return o;
265 }
266
267
268 /* javastring_new_from_utf_string **********************************************
269
270    Create a new object of type java/lang/String with the text from
271    the specified zero-terminated utf8 string.
272
273    IN:
274       buffer.......points to first char in the buffer
275           blength......number of bytes to read from the buffer
276
277    RETURN VALUE:
278       the java.lang.String object, or
279       NULL if an exception has been thrown
280
281 *******************************************************************************/
282
283 java_handle_t *javastring_new_from_utf_string(const char *utfstr)
284 {
285         assert(utfstr);
286
287         return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
288 }
289
290
291 /* javastring_new **************************************************************
292
293    creates a new object of type java/lang/String with the text of 
294    the specified utf8-string
295
296    return: pointer to the string or NULL if memory is exhausted.        
297
298 *******************************************************************************/
299
300 java_handle_t *javastring_new(utf *u)
301 {
302         char *utf_ptr;                  /* current utf character in utf string    */
303         u4 utflength;                   /* length of utf-string if uncompressed   */
304         java_handle_t           *o;
305         java_handle_chararray_t *a;
306         java_lang_String        *s;
307         s4 i;
308
309         if (u == NULL) {
310                 exceptions_throw_nullpointerexception();
311                 return NULL;
312         }
313
314         utf_ptr = u->text;
315         utflength = utf_get_number_of_u2s(u);
316
317         o = builtin_new(class_java_lang_String);
318         a = builtin_newarray_char(utflength);
319
320         /* javastring or character-array could not be created */
321
322         if ((o == NULL) || (a == NULL))
323                 return NULL;
324
325         /* decompress utf-string */
326
327         for (i = 0; i < utflength; i++)
328                 LLNI_array_direct(a, i) = utf_nextu2(&utf_ptr);
329         
330         /* set fields of the javastring-object */
331
332         s = (java_lang_String *) o;
333
334         LLNI_field_set_ref(s, value , a);
335         LLNI_field_set_val(s, offset, 0);
336         LLNI_field_set_val(s, count , utflength);
337
338         return o;
339 }
340
341
342 /* javastring_new_slash_to_dot *************************************************
343
344    creates a new object of type java/lang/String with the text of 
345    the specified utf8-string with slashes changed to dots
346
347    return: pointer to the string or NULL if memory is exhausted.        
348
349 *******************************************************************************/
350
351 java_handle_t *javastring_new_slash_to_dot(utf *u)
352 {
353         char *utf_ptr;                  /* current utf character in utf string    */
354         u4 utflength;                   /* length of utf-string if uncompressed   */
355         java_handle_t           *o;
356         java_handle_chararray_t *a;
357         java_lang_String        *s;
358         s4 i;
359         u2 ch;
360
361         if (u == NULL) {
362                 exceptions_throw_nullpointerexception();
363                 return NULL;
364         }
365
366         utf_ptr = u->text;
367         utflength = utf_get_number_of_u2s(u);
368
369         o = builtin_new(class_java_lang_String);
370         a = builtin_newarray_char(utflength);
371
372         /* javastring or character-array could not be created */
373         if ((o == NULL) || (a == NULL))
374                 return NULL;
375
376         /* decompress utf-string */
377
378         for (i = 0; i < utflength; i++) {
379                 ch = utf_nextu2(&utf_ptr);
380                 if (ch == '/')
381                         ch = '.';
382                 LLNI_array_direct(a, i) = ch;
383         }
384         
385         /* set fields of the javastring-object */
386
387         s = (java_lang_String *) o;
388
389         LLNI_field_set_ref(s, value , a);
390         LLNI_field_set_val(s, offset, 0);
391         LLNI_field_set_val(s, count , utflength);
392
393         return o;
394 }
395
396
397 /* javastring_new_from_ascii ***************************************************
398
399    creates a new java/lang/String object which contains the given ASCII
400    C-string converted to UTF-16.
401
402    IN:
403       text.........string of ASCII characters
404
405    RETURN VALUE:
406       the java.lang.String object, or 
407       NULL if an exception has been thrown.
408
409 *******************************************************************************/
410
411 java_handle_t *javastring_new_from_ascii(const char *text)
412 {
413         s4 i;
414         s4 len;                             /* length of the string               */
415         java_handle_t           *o;
416         java_lang_String        *s;
417         java_handle_chararray_t *a;
418
419         if (text == NULL) {
420                 exceptions_throw_nullpointerexception();
421                 return NULL;
422         }
423
424         len = strlen(text);
425
426         o = builtin_new(class_java_lang_String);
427         a = builtin_newarray_char(len);
428
429         /* javastring or character-array could not be created */
430
431         if ((o == NULL) || (a == NULL))
432                 return NULL;
433
434         /* copy text */
435
436         for (i = 0; i < len; i++)
437                 LLNI_array_direct(a, i) = text[i];
438         
439         /* set fields of the javastring-object */
440
441         s = (java_lang_String *) o;
442
443         LLNI_field_set_ref(s, value , a);
444         LLNI_field_set_val(s, offset, 0);
445         LLNI_field_set_val(s, count , len);
446
447         return o;
448 }
449
450
451 /* javastring_tochar ***********************************************************
452
453    converts a Java string into a C string.
454         
455    return: pointer to C string
456         
457    Caution: calling method MUST release the allocated memory!
458         
459 *******************************************************************************/
460
461 char *javastring_tochar(java_handle_t *so) 
462 {
463         java_lang_String        *s = (java_lang_String *) so;
464         java_handle_chararray_t *a;
465         int32_t                  count;
466         int32_t                  offset;
467         char *buf;
468         s4 i;
469         
470         if (!s)
471                 return "";
472
473         LLNI_field_get_ref(s, value, a);
474
475         if (!a)
476                 return "";
477
478         LLNI_field_get_val(s, count, count);
479         LLNI_field_get_val(s, offset, offset);
480
481         buf = MNEW(char, count + 1);
482
483         for (i = 0; i < count; i++)
484                 buf[i] = LLNI_array_direct(a, offset + i);
485
486         buf[i] = '\0';
487
488         return buf;
489 }
490
491
492 /* javastring_toutf ************************************************************
493
494    Make utf symbol from javastring.
495
496 *******************************************************************************/
497
498 utf *javastring_toutf(java_handle_t *string, bool isclassname)
499 {
500         java_lang_String        *s;
501         java_handle_chararray_t *value;
502         int32_t                  count;
503         int32_t                  offset;
504
505         s = (java_lang_String *) string;
506
507         if (s == NULL)
508                 return utf_null;
509
510         LLNI_field_get_ref(s, value, value);
511         LLNI_field_get_val(s, count, count);
512         LLNI_field_get_val(s, offset, offset);
513
514         return utf_new_u2(LLNI_array_data(value) + offset, count, isclassname);
515 }
516
517
518 /* literalstring_u2 ************************************************************
519
520    Searches for the literalstring with the specified u2-array in the
521    string hashtable, if there is no such string a new one is created.
522
523    If copymode is true a copy of the u2-array is made.
524
525 *******************************************************************************/
526
527 static java_object_t *literalstring_u2(java_chararray_t *a, u4 length,
528                                                                            u4 offset, bool copymode)
529 {
530     literalstring    *s;                /* hashtable element                  */
531     heapstring_t     *js;               /* u2-array wrapped in javastring     */
532     java_chararray_t *ca;               /* copy of u2-array                   */
533     u4                key;
534     u4                slot;
535     u2                i;
536
537         LOCK_MONITOR_ENTER(lock_hashtable_string);
538
539     /* find location in hashtable */
540
541     key  = unicode_hashkey(a->data + offset, length);
542     slot = key & (hashtable_string.size - 1);
543     s    = hashtable_string.ptr[slot];
544
545     while (s) {
546                 js = (heapstring_t *) s->string;
547
548                 if (length == js->count) {
549                         /* compare text */
550
551                         for (i = 0; i < length; i++)
552                                 if (a->data[offset + i] != js->value->data[i])
553                                         goto nomatch;
554
555                         /* string already in hashtable, free memory */
556
557                         if (!copymode)
558                                 mem_free(a, sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10);
559
560                         LOCK_MONITOR_EXIT(lock_hashtable_string);
561
562                         return (java_object_t *) js;
563                 }
564
565         nomatch:
566                 /* follow link in external hash chain */
567                 s = s->hashlink;
568     }
569
570     if (copymode) {
571                 /* create copy of u2-array for new javastring */
572                 u4 arraysize = sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10;
573                 ca = mem_alloc(arraysize);
574 /*              memcpy(ca, a, arraysize); */
575                 memcpy(&(ca->header), &(a->header), sizeof(java_array_t));
576                 memcpy(&(ca->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
577
578     } else {
579                 ca = a;
580         }
581
582     /* location in hashtable found, complete arrayheader */
583
584     ca->header.objheader.vftbl =
585                 primitive_arrayclass_get_by_type(ARRAYTYPE_CHAR)->vftbl;
586     ca->header.size            = length;
587
588         assert(class_java_lang_String);
589         assert(class_java_lang_String->state & CLASS_LOADED);
590
591         /* create new javastring */
592
593         js = NEW(heapstring_t);
594
595 #if defined(ENABLE_STATISTICS)
596         if (opt_stat)
597                 size_string += sizeof(heapstring_t);
598 #endif
599
600 #if defined(ENABLE_THREADS)
601         lock_init_object_lock(&js->header);
602 #endif
603
604         js->header.vftbl = class_java_lang_String->vftbl;
605         js->value  = ca;
606         js->offset = 0;
607         js->count  = length;
608
609         /* create new literalstring */
610
611         s = NEW(literalstring);
612
613 #if defined(ENABLE_STATISTICS)
614         if (opt_stat)
615                 size_string += sizeof(literalstring);
616 #endif
617
618         s->hashlink = hashtable_string.ptr[slot];
619         s->string   = (java_object_t *) js;
620         hashtable_string.ptr[slot] = s;
621
622         /* update number of hashtable entries */
623
624         hashtable_string.entries++;
625
626         /* reorganization of hashtable */       
627
628         if (hashtable_string.entries > (hashtable_string.size * 2)) {
629                 /* reorganization of hashtable, average length of the external
630                    chains is approx. 2 */
631
632                 u4             i;
633                 literalstring *s;
634                 literalstring *nexts;
635                 heapstring_t  *tmpjs;
636                 hashtable      newhash;                          /* the new hashtable */
637       
638                 /* create new hashtable, double the size */
639
640                 hashtable_create(&newhash, hashtable_string.size * 2);
641                 newhash.entries = hashtable_string.entries;
642       
643                 /* transfer elements to new hashtable */
644
645                 for (i = 0; i < hashtable_string.size; i++) {
646                         s = hashtable_string.ptr[i];
647
648                         while (s) {
649                                 nexts = s->hashlink;
650                                 tmpjs = (heapstring_t *) s->string;
651                                 slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
652           
653                                 s->hashlink = newhash.ptr[slot];
654                                 newhash.ptr[slot] = s;
655         
656                                 /* follow link in external hash chain */
657                                 s = nexts;
658                         }
659                 }
660         
661                 /* dispose old table */
662
663                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
664                 hashtable_string = newhash;
665         }
666
667         LOCK_MONITOR_EXIT(lock_hashtable_string);
668
669         return (java_object_t *) js;
670 }
671
672
673 /* literalstring_new ***********************************************************
674
675    Creates a new literalstring with the text of the utf-symbol and inserts
676    it into the string hashtable.
677
678 *******************************************************************************/
679
680 java_object_t *literalstring_new(utf *u)
681 {
682     char             *utf_ptr;       /* pointer to current unicode character  */
683                                          /* utf string                            */
684     u4                utflength;     /* length of utf-string if uncompressed  */
685     java_chararray_t *a;             /* u2-array constructed from utf string  */
686     u4                i;
687
688         utf_ptr = u->text;
689         utflength = utf_get_number_of_u2s(u);
690
691     /* allocate memory */ 
692     a = mem_alloc(sizeof(java_chararray_t) + sizeof(u2) * (utflength - 1) + 10);
693
694     /* convert utf-string to u2-array */
695     for (i = 0; i < utflength; i++)
696                 a->data[i] = utf_nextu2(&utf_ptr);
697
698     return literalstring_u2(a, utflength, 0, false);
699 }
700
701
702 /* literalstring_free **********************************************************
703
704    Removes a literalstring from memory.
705
706 *******************************************************************************/
707
708 static void literalstring_free(java_object_t* string)
709 {
710         heapstring_t     *s;
711         java_chararray_t *a;
712
713         s = (heapstring_t *) string;
714         a = s->value;
715
716         /* dispose memory of java.lang.String object */
717         FREE(s, heapstring_t);
718
719         /* dispose memory of java-characterarray */
720         FREE(a, sizeof(java_chararray_t) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
721 }
722
723
724 /* javastring_intern ***********************************************************
725
726    Intern the given Java string.
727
728    XXX NOTE: Literal Strings are direct references since they are not placed
729    onto the GC-Heap. That's why this function looks so "different".
730
731 *******************************************************************************/
732
733 java_handle_t *javastring_intern(java_handle_t *s)
734 {
735         java_lang_String *so;
736         java_chararray_t *value;
737         int32_t           count;
738         int32_t           offset;
739 /*      java_lang_String *o; */
740         java_object_t    *o; /* XXX see note above */
741
742         so = (java_lang_String *) s;
743
744         value  = LLNI_field_direct(so, value); /* XXX see note above */
745         LLNI_field_get_val(so, count, count);
746         LLNI_field_get_val(so, offset, offset);
747
748         o = literalstring_u2(value, count, offset, true);
749
750         return LLNI_WRAP(o); /* XXX see note above */
751 }
752
753
754 /* javastring_print ************************************************************
755
756    Print the given Java string.
757
758 *******************************************************************************/
759
760 void javastring_print(java_handle_t *s)
761 {
762         java_lang_String        *so;
763         java_handle_chararray_t *value;
764         int32_t                  count;
765         int32_t                  offset;
766         uint16_t                 c;
767         int                      i;
768
769         so = (java_lang_String *) s;
770
771         LLNI_field_get_ref(so, value, value);
772         LLNI_field_get_val(so, count, count);
773         LLNI_field_get_val(so, offset, offset);
774
775         for (i = offset; i < offset + count; i++) {
776                 c = LLNI_array_direct(value, i);
777                 putchar(c);
778         }
779 }
780
781
782 /*
783  * These are local overrides for various environment variables in Emacs.
784  * Please do not remove this and leave it at the end of the file, where
785  * Emacs will automagically detect them.
786  * ---------------------------------------------------------------------
787  * Local variables:
788  * mode: c
789  * indent-tabs-mode: t
790  * c-basic-offset: 4
791  * tab-width: 4
792  * End:
793  * vim:noexpandtab:sw=4:ts=4:
794  */