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