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