* src/vm/jit/i386/darwin/md-os.c (md_replace_executionstate_read):
[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 "vm/types.h"
31
32 #include "vm/global.h"
33
34 #include "mm/memory.h"
35
36 #include "native/jni.h"
37 #include "native/llni.h"
38
39 #include "native/include/java_lang_String.h"
40
41 #include "threads/lock-common.h"
42
43 #include "vm/array.h"
44 #include "vm/builtin.h"
45 #include "vm/exceptions.h"
46 #include "vm/primitive.h"
47 #include "vm/stringlocal.h"
48 #include "vm/vm.h"
49
50 #include "vmcore/options.h"
51 #include "vmcore/statistics.h"
52 #include "vmcore/utf8.h"
53
54
55 /* global variables ***********************************************************/
56
57 /* hashsize must be power of 2 */
58
59 #define HASHTABLE_STRING_SIZE    2048   /* initial size of javastring-hash    */
60
61 hashtable hashtable_string;             /* hashtable for javastrings          */
62
63 #if defined(ENABLE_THREADS)
64 static java_object_t *lock_hashtable_string;
65 #endif
66
67
68 /* XXX preliminary typedef, will be removed once string.c and utf8.c are
69    unified. */
70
71 #if defined(ENABLE_HANDLES)
72 typedef heap_java_lang_String heapstring_t;
73 #else
74 typedef java_lang_String heapstring_t;
75 #endif
76
77
78 /* string_init *****************************************************************
79
80    Initialize the string hashtable lock.
81
82 *******************************************************************************/
83
84 bool string_init(void)
85 {
86         TRACESUBSYSTEMINITIALIZATION("string_init");
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
512         if (value == NULL)
513                 return utf_null;
514
515         LLNI_field_get_val(s, count, count);
516         LLNI_field_get_val(s, offset, offset);
517
518         return utf_new_u2(LLNI_array_data(value) + offset, count, isclassname);
519 }
520
521
522 /* literalstring_u2 ************************************************************
523
524    Searches for the literalstring with the specified u2-array in the
525    string hashtable, if there is no such string a new one is created.
526
527    If copymode is true a copy of the u2-array is made.
528
529 *******************************************************************************/
530
531 static java_object_t *literalstring_u2(java_chararray_t *a, u4 length,
532                                                                            u4 offset, bool copymode)
533 {
534     literalstring    *s;                /* hashtable element                  */
535     heapstring_t     *js;               /* u2-array wrapped in javastring     */
536     java_chararray_t *ca;               /* copy of u2-array                   */
537     u4                key;
538     u4                slot;
539     u2                i;
540
541         LOCK_MONITOR_ENTER(lock_hashtable_string);
542
543     /* find location in hashtable */
544
545     key  = unicode_hashkey(a->data + offset, length);
546     slot = key & (hashtable_string.size - 1);
547     s    = hashtable_string.ptr[slot];
548
549     while (s) {
550                 js = (heapstring_t *) s->string;
551
552                 if (length == js->count) {
553                         /* compare text */
554
555                         for (i = 0; i < length; i++)
556                                 if (a->data[offset + i] != js->value->data[i])
557                                         goto nomatch;
558
559                         /* string already in hashtable, free memory */
560
561                         if (!copymode)
562                                 mem_free(a, sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10);
563
564                         LOCK_MONITOR_EXIT(lock_hashtable_string);
565
566                         return (java_object_t *) js;
567                 }
568
569         nomatch:
570                 /* follow link in external hash chain */
571                 s = s->hashlink;
572     }
573
574     if (copymode) {
575                 /* create copy of u2-array for new javastring */
576                 u4 arraysize = sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10;
577                 ca = mem_alloc(arraysize);
578 /*              memcpy(ca, a, arraysize); */
579                 memcpy(&(ca->header), &(a->header), sizeof(java_array_t));
580                 memcpy(&(ca->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
581
582     } else {
583                 ca = a;
584         }
585
586     /* location in hashtable found, complete arrayheader */
587
588     ca->header.objheader.vftbl =
589                 primitive_arrayclass_get_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 = 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 = 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 = 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 = 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_print ************************************************************
763
764    Print the given Java string.
765
766 *******************************************************************************/
767
768 void javastring_print(java_handle_t *s)
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                 putchar(c);
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  */