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