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