* src/vm/vm.c, src/vm/vm.h: Moved to .cpp.
[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/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         TRACESUBSYSTEMINITIALIZATION("string_init");
89
90         /* create string (javastring) hashtable */
91
92         hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
93
94 #if defined(ENABLE_THREADS)
95         /* create string hashtable lock object */
96
97         lock_hashtable_string = NEW(java_object_t);
98
99         LOCK_INIT_OBJECT_LOCK(lock_hashtable_string);
100 #endif
101
102         /* everything's ok */
103
104         return true;
105 }
106
107
108 /* stringtable_update **********************************************************
109
110    Traverses the javastring hashtable and sets the vftbl-entries of
111    javastrings which were temporarily set to NULL, because
112    java.lang.Object was not yet loaded.
113
114 *******************************************************************************/
115  
116 void stringtable_update(void)
117 {
118         heapstring_t     *js;
119         java_chararray_t *a;
120         literalstring    *s;       /* hashtable entry */
121         int i;
122
123         for (i = 0; i < hashtable_string.size; i++) {
124                 s = hashtable_string.ptr[i];
125                 if (s) {
126                         while (s) {
127                                 js = (heapstring_t *) s->string;
128                                
129                                 if ((js == NULL) || (js->value == NULL)) {
130                                         /* error in hashtable found */
131
132                                         vm_abort("stringtable_update: invalid literalstring in hashtable");
133                                 }
134
135                                 a = js->value;
136
137                                 if (!js->header.vftbl) 
138                                         /* vftbl of javastring is NULL */ 
139                                         js->header.vftbl = class_java_lang_String->vftbl;
140
141                                 if (!a->header.objheader.vftbl) 
142                                         /* vftbl of character-array is NULL */ 
143                                         a->header.objheader.vftbl =
144                                                 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         u4 utflength;                   /* length of utf-string if uncompressed   */
307         java_handle_t           *o;
308         java_handle_chararray_t *a;
309         java_lang_String        *s;
310         s4 i;
311
312         if (u == NULL) {
313                 exceptions_throw_nullpointerexception();
314                 return NULL;
315         }
316
317         utf_ptr = u->text;
318         utflength = utf_get_number_of_u2s(u);
319
320         o = builtin_new(class_java_lang_String);
321         a = builtin_newarray_char(utflength);
322
323         /* javastring or character-array could not be created */
324
325         if ((o == NULL) || (a == NULL))
326                 return NULL;
327
328         /* decompress utf-string */
329
330         for (i = 0; i < utflength; i++)
331                 LLNI_array_direct(a, i) = utf_nextu2(&utf_ptr);
332         
333         /* set fields of the javastring-object */
334
335         s = (java_lang_String *) o;
336
337         LLNI_field_set_ref(s, value , a);
338         LLNI_field_set_val(s, offset, 0);
339         LLNI_field_set_val(s, count , utflength);
340
341         return o;
342 }
343
344
345 /* javastring_new_slash_to_dot *************************************************
346
347    creates a new object of type java/lang/String with the text of 
348    the specified utf8-string with slashes changed to dots
349
350    return: pointer to the string or NULL if memory is exhausted.        
351
352 *******************************************************************************/
353
354 java_handle_t *javastring_new_slash_to_dot(utf *u)
355 {
356         char *utf_ptr;                  /* current utf character in utf string    */
357         u4 utflength;                   /* length of utf-string if uncompressed   */
358         java_handle_t           *o;
359         java_handle_chararray_t *a;
360         java_lang_String        *s;
361         s4 i;
362         u2 ch;
363
364         if (u == NULL) {
365                 exceptions_throw_nullpointerexception();
366                 return NULL;
367         }
368
369         utf_ptr = u->text;
370         utflength = utf_get_number_of_u2s(u);
371
372         o = builtin_new(class_java_lang_String);
373         a = builtin_newarray_char(utflength);
374
375         /* javastring or character-array could not be created */
376         if ((o == NULL) || (a == NULL))
377                 return NULL;
378
379         /* decompress utf-string */
380
381         for (i = 0; i < utflength; i++) {
382                 ch = utf_nextu2(&utf_ptr);
383                 if (ch == '/')
384                         ch = '.';
385                 LLNI_array_direct(a, i) = ch;
386         }
387         
388         /* set fields of the javastring-object */
389
390         s = (java_lang_String *) o;
391
392         LLNI_field_set_ref(s, value , a);
393         LLNI_field_set_val(s, offset, 0);
394         LLNI_field_set_val(s, count , utflength);
395
396         return o;
397 }
398
399
400 /* javastring_new_from_ascii ***************************************************
401
402    creates a new java/lang/String object which contains the given ASCII
403    C-string converted to UTF-16.
404
405    IN:
406       text.........string of ASCII characters
407
408    RETURN VALUE:
409       the java.lang.String object, or 
410       NULL if an exception has been thrown.
411
412 *******************************************************************************/
413
414 java_handle_t *javastring_new_from_ascii(const char *text)
415 {
416         s4 i;
417         s4 len;                             /* length of the string               */
418         java_handle_t           *o;
419         java_lang_String        *s;
420         java_handle_chararray_t *a;
421
422         if (text == NULL) {
423                 exceptions_throw_nullpointerexception();
424                 return NULL;
425         }
426
427         len = strlen(text);
428
429         o = builtin_new(class_java_lang_String);
430         a = builtin_newarray_char(len);
431
432         /* javastring or character-array could not be created */
433
434         if ((o == NULL) || (a == NULL))
435                 return NULL;
436
437         /* copy text */
438
439         for (i = 0; i < len; i++)
440                 LLNI_array_direct(a, i) = text[i];
441         
442         /* set fields of the javastring-object */
443
444         s = (java_lang_String *) o;
445
446         LLNI_field_set_ref(s, value , a);
447         LLNI_field_set_val(s, offset, 0);
448         LLNI_field_set_val(s, count , len);
449
450         return o;
451 }
452
453
454 /* javastring_tochar ***********************************************************
455
456    converts a Java string into a C string.
457         
458    return: pointer to C string
459         
460    Caution: calling method MUST release the allocated memory!
461         
462 *******************************************************************************/
463
464 char *javastring_tochar(java_handle_t *so) 
465 {
466         java_lang_String        *s = (java_lang_String *) so;
467         java_handle_chararray_t *a;
468         int32_t                  count;
469         int32_t                  offset;
470         char *buf;
471         s4 i;
472         
473         if (!s)
474                 return "";
475
476         LLNI_field_get_ref(s, value, a);
477
478         if (!a)
479                 return "";
480
481         LLNI_field_get_val(s, count, count);
482         LLNI_field_get_val(s, offset, offset);
483
484         buf = MNEW(char, count + 1);
485
486         for (i = 0; i < count; i++)
487                 buf[i] = LLNI_array_direct(a, offset + i);
488
489         buf[i] = '\0';
490
491         return buf;
492 }
493
494
495 /* javastring_toutf ************************************************************
496
497    Make utf symbol from javastring.
498
499 *******************************************************************************/
500
501 utf *javastring_toutf(java_handle_t *string, bool isclassname)
502 {
503         java_lang_String        *s;
504         java_handle_chararray_t *value;
505         int32_t                  count;
506         int32_t                  offset;
507
508         s = (java_lang_String *) string;
509
510         if (s == NULL)
511                 return utf_null;
512
513         LLNI_field_get_ref(s, value, value);
514
515         if (value == NULL)
516                 return utf_null;
517
518         LLNI_field_get_val(s, count, count);
519         LLNI_field_get_val(s, offset, offset);
520
521         return utf_new_u2(LLNI_array_data(value) + offset, count, isclassname);
522 }
523
524
525 /* literalstring_u2 ************************************************************
526
527    Searches for the literalstring with the specified u2-array in the
528    string hashtable, if there is no such string a new one is created.
529
530    If copymode is true a copy of the u2-array is made.
531
532 *******************************************************************************/
533
534 static java_object_t *literalstring_u2(java_chararray_t *a, u4 length,
535                                                                            u4 offset, bool copymode)
536 {
537     literalstring    *s;                /* hashtable element                  */
538     heapstring_t     *js;               /* u2-array wrapped in javastring     */
539     java_chararray_t *ca;               /* copy of u2-array                   */
540     u4                key;
541     u4                slot;
542     u2                i;
543
544         LOCK_MONITOR_ENTER(lock_hashtable_string);
545
546     /* find location in hashtable */
547
548     key  = unicode_hashkey(a->data + offset, length);
549     slot = key & (hashtable_string.size - 1);
550     s    = hashtable_string.ptr[slot];
551
552     while (s) {
553                 js = (heapstring_t *) s->string;
554
555                 if (length == js->count) {
556                         /* compare text */
557
558                         for (i = 0; i < length; i++)
559                                 if (a->data[offset + i] != js->value->data[i])
560                                         goto nomatch;
561
562                         /* string already in hashtable, free memory */
563
564                         if (!copymode)
565                                 mem_free(a, sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10);
566
567                         LOCK_MONITOR_EXIT(lock_hashtable_string);
568
569                         return (java_object_t *) js;
570                 }
571
572         nomatch:
573                 /* follow link in external hash chain */
574                 s = s->hashlink;
575     }
576
577     if (copymode) {
578                 /* create copy of u2-array for new javastring */
579                 u4 arraysize = sizeof(java_chararray_t) + sizeof(u2) * (length - 1) + 10;
580                 ca = mem_alloc(arraysize);
581 /*              memcpy(ca, a, arraysize); */
582                 memcpy(&(ca->header), &(a->header), sizeof(java_array_t));
583                 memcpy(&(ca->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
584
585     } else {
586                 ca = a;
587         }
588
589     /* location in hashtable found, complete arrayheader */
590
591     ca->header.objheader.vftbl =
592                 Primitive_get_arrayclass_by_type(ARRAYTYPE_CHAR)->vftbl;
593     ca->header.size            = length;
594
595         assert(class_java_lang_String);
596         assert(class_java_lang_String->state & CLASS_LOADED);
597
598         /* create new javastring */
599
600         js = NEW(heapstring_t);
601
602 #if defined(ENABLE_STATISTICS)
603         if (opt_stat)
604                 size_string += sizeof(heapstring_t);
605 #endif
606
607 #if defined(ENABLE_THREADS)
608         lock_init_object_lock(&js->header);
609 #endif
610
611         js->header.vftbl = class_java_lang_String->vftbl;
612         js->value  = ca;
613         js->offset = 0;
614         js->count  = length;
615
616         /* create new literalstring */
617
618         s = NEW(literalstring);
619
620 #if defined(ENABLE_STATISTICS)
621         if (opt_stat)
622                 size_string += sizeof(literalstring);
623 #endif
624
625         s->hashlink = hashtable_string.ptr[slot];
626         s->string   = (java_object_t *) js;
627         hashtable_string.ptr[slot] = s;
628
629         /* update number of hashtable entries */
630
631         hashtable_string.entries++;
632
633         /* reorganization of hashtable */       
634
635         if (hashtable_string.entries > (hashtable_string.size * 2)) {
636                 /* reorganization of hashtable, average length of the external
637                    chains is approx. 2 */
638
639                 u4             i;
640                 literalstring *s;
641                 literalstring *nexts;
642                 heapstring_t  *tmpjs;
643                 hashtable      newhash;                          /* the new hashtable */
644       
645                 /* create new hashtable, double the size */
646
647                 hashtable_create(&newhash, hashtable_string.size * 2);
648                 newhash.entries = hashtable_string.entries;
649       
650                 /* transfer elements to new hashtable */
651
652                 for (i = 0; i < hashtable_string.size; i++) {
653                         s = hashtable_string.ptr[i];
654
655                         while (s) {
656                                 nexts = s->hashlink;
657                                 tmpjs = (heapstring_t *) s->string;
658                                 slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
659           
660                                 s->hashlink = newhash.ptr[slot];
661                                 newhash.ptr[slot] = s;
662         
663                                 /* follow link in external hash chain */
664                                 s = nexts;
665                         }
666                 }
667         
668                 /* dispose old table */
669
670                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
671                 hashtable_string = newhash;
672         }
673
674         LOCK_MONITOR_EXIT(lock_hashtable_string);
675
676         return (java_object_t *) js;
677 }
678
679
680 /* literalstring_new ***********************************************************
681
682    Creates a new literalstring with the text of the utf-symbol and inserts
683    it into the string hashtable.
684
685 *******************************************************************************/
686
687 java_object_t *literalstring_new(utf *u)
688 {
689     char             *utf_ptr;       /* pointer to current unicode character  */
690                                          /* utf string                            */
691     u4                utflength;     /* length of utf-string if uncompressed  */
692     java_chararray_t *a;             /* u2-array constructed from utf string  */
693     u4                i;
694
695         utf_ptr = u->text;
696         utflength = utf_get_number_of_u2s(u);
697
698     /* allocate memory */ 
699     a = mem_alloc(sizeof(java_chararray_t) + sizeof(u2) * (utflength - 1) + 10);
700
701     /* convert utf-string to u2-array */
702     for (i = 0; i < utflength; i++)
703                 a->data[i] = utf_nextu2(&utf_ptr);
704
705     return literalstring_u2(a, utflength, 0, false);
706 }
707
708
709 /* literalstring_free **********************************************************
710
711    Removes a literalstring from memory.
712
713 *******************************************************************************/
714
715 #if 0
716 /* TWISTI This one is currently not used. */
717
718 static void literalstring_free(java_object_t* string)
719 {
720         heapstring_t     *s;
721         java_chararray_t *a;
722
723         s = (heapstring_t *) string;
724         a = s->value;
725
726         /* dispose memory of java.lang.String object */
727         FREE(s, heapstring_t);
728
729         /* dispose memory of java-characterarray */
730         FREE(a, sizeof(java_chararray_t) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
731 }
732 #endif
733
734
735 /* javastring_intern ***********************************************************
736
737    Intern the given Java string.
738
739    XXX NOTE: Literal Strings are direct references since they are not placed
740    onto the GC-Heap. That's why this function looks so "different".
741
742 *******************************************************************************/
743
744 java_handle_t *javastring_intern(java_handle_t *s)
745 {
746         java_lang_String *so;
747         java_chararray_t *value;
748         int32_t           count;
749         int32_t           offset;
750 /*      java_lang_String *o; */
751         java_object_t    *o; /* XXX see note above */
752
753         so = (java_lang_String *) s;
754
755         value  = LLNI_field_direct(so, value); /* XXX see note above */
756         LLNI_field_get_val(so, count, count);
757         LLNI_field_get_val(so, offset, offset);
758
759         o = literalstring_u2(value, count, offset, true);
760
761         return LLNI_WRAP(o); /* XXX see note above */
762 }
763
764
765 /* javastring_fprint ***********************************************************
766
767    Print the given Java string to the given stream.
768
769 *******************************************************************************/
770
771 void javastring_fprint(java_handle_t *s, FILE *stream)
772 {
773         java_lang_String        *so;
774         java_handle_chararray_t *value;
775         int32_t                  count;
776         int32_t                  offset;
777         uint16_t                 c;
778         int                      i;
779
780         so = (java_lang_String *) s;
781
782         LLNI_field_get_ref(so, value, value);
783         LLNI_field_get_val(so, count, count);
784         LLNI_field_get_val(so, offset, offset);
785
786         for (i = offset; i < offset + count; i++) {
787                 c = LLNI_array_direct(value, i);
788                 fputc(c, stream);
789         }
790 }
791
792
793 /*
794  * These are local overrides for various environment variables in Emacs.
795  * Please do not remove this and leave it at the end of the file, where
796  * Emacs will automagically detect them.
797  * ---------------------------------------------------------------------
798  * Local variables:
799  * mode: c
800  * indent-tabs-mode: t
801  * c-basic-offset: 4
802  * tab-width: 4
803  * End:
804  * vim:noexpandtab:sw=4:ts=4:
805  */