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