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