1d127f76f57c0248bdaf7d18043a187bc915e6ac
[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 7813 2007-04-25 19:20:13Z 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 java_objectheader *javastring_new_from_utf_buffer(const char *buffer, u4 blength)
156 {
157         const char *utf_ptr;            /* current utf character in utf string    */
158         u4 utflength;                   /* length of utf-string if uncompressed   */
159         java_objectheader *o;
160         java_lang_String  *s;           /* result-string                          */
161         java_chararray    *a;
162         u4 i;
163
164         assert(buffer);
165
166         utflength = utf_get_number_of_u2s_for_buffer(buffer,blength);
167
168         o = builtin_new(class_java_lang_String);
169         a = builtin_newarray_char(utflength);
170
171         /* javastring or character-array could not be created */
172
173         if ((o == NULL) || (a == NULL))
174                 return NULL;
175
176         /* decompress utf-string */
177
178         utf_ptr = buffer;
179
180         for (i = 0; i < utflength; i++)
181                 a->data[i] = utf_nextu2((char **) &utf_ptr);
182         
183         /* set fields of the javastring-object */
184
185         s = (java_lang_String *) o;
186
187         s->value  = a;
188         s->offset = 0;
189         s->count  = utflength;
190
191         return o;
192 }
193
194
195 /* javastring_safe_new_from_utf8 ***********************************************
196
197    Create a new object of type java/lang/String with the text from
198    the specified UTF-8 string. This function is safe for invalid UTF-8.
199    (Invalid characters will be replaced by U+fffd.)
200
201    IN:
202       text.........the UTF-8 string, zero-terminated.
203
204    RETURN VALUE:
205       the java.lang.String object, or
206       NULL if an exception has been thrown
207
208 *******************************************************************************/
209
210 java_objectheader *javastring_safe_new_from_utf8(const char *text)
211 {
212         java_objectheader *o;
213         java_chararray    *a;
214         java_lang_String  *s;
215         s4 nbytes;
216         s4 len;
217
218         assert(text);
219
220         /* Get number of bytes. We need this to completely emulate the messy */
221         /* behaviour of the RI. :(                                           */
222
223         nbytes = strlen(text);
224
225         /* calculate number of Java characters */
226
227         len = utf8_safe_number_of_u2s(text, nbytes);
228
229         /* allocate the String object and the char array */
230
231         o = builtin_new(class_java_lang_String);
232         a = builtin_newarray_char(len);
233
234         /* javastring or character-array could not be created? */
235
236         if ((o == NULL) || (a == NULL))
237                 return NULL;
238
239         /* decompress UTF-8 string */
240
241         utf8_safe_convert_to_u2s(text, nbytes, a->data);
242
243         /* set fields of the String object */
244
245         s = (java_lang_String *) o;
246
247         s->value  = a;
248         s->offset = 0;
249         s->count  = len;
250
251         return o;
252 }
253
254
255 /* javastring_new_from_utf_string **********************************************
256
257    Create a new object of type java/lang/String with the text from
258    the specified zero-terminated utf8 string.
259
260    IN:
261       buffer.......points to first char in the buffer
262           blength......number of bytes to read from the buffer
263
264    RETURN VALUE:
265       the java.lang.String object, or
266       NULL if an exception has been thrown
267
268 *******************************************************************************/
269
270 java_objectheader *javastring_new_from_utf_string(const char *utfstr)
271 {
272         assert(utfstr);
273
274         return javastring_new_from_utf_buffer(utfstr, strlen(utfstr));
275 }
276
277
278 /* javastring_new **************************************************************
279
280    creates a new object of type java/lang/String with the text of 
281    the specified utf8-string
282
283    return: pointer to the string or NULL if memory is exhausted.        
284
285 *******************************************************************************/
286
287 java_objectheader *javastring_new(utf *u)
288 {
289         char *utf_ptr;                  /* current utf character in utf string    */
290         u4 utflength;                   /* length of utf-string if uncompressed   */
291         java_objectheader *o;
292         java_chararray    *a;
293         java_lang_String  *s;
294         s4 i;
295
296         if (u == NULL) {
297                 exceptions_throw_nullpointerexception();
298                 return NULL;
299         }
300
301         utf_ptr = u->text;
302         utflength = utf_get_number_of_u2s(u);
303
304         o = builtin_new(class_java_lang_String);
305         a = builtin_newarray_char(utflength);
306
307         /* javastring or character-array could not be created */
308
309         if ((o == NULL) || (a == NULL))
310                 return NULL;
311
312         /* decompress utf-string */
313
314         for (i = 0; i < utflength; i++)
315                 a->data[i] = utf_nextu2(&utf_ptr);
316         
317         /* set fields of the javastring-object */
318
319         s = (java_lang_String *) o;
320
321         s->value  = a;
322         s->offset = 0;
323         s->count  = utflength;
324
325         return o;
326 }
327
328
329 /* javastring_new_slash_to_dot *************************************************
330
331    creates a new object of type java/lang/String with the text of 
332    the specified utf8-string with slashes changed to dots
333
334    return: pointer to the string or NULL if memory is exhausted.        
335
336 *******************************************************************************/
337
338 java_objectheader *javastring_new_slash_to_dot(utf *u)
339 {
340         char *utf_ptr;                  /* current utf character in utf string    */
341         u4 utflength;                   /* length of utf-string if uncompressed   */
342         java_objectheader *o;
343         java_chararray    *a;
344         java_lang_String  *s;
345         s4 i;
346         u2 ch;
347
348         if (u == NULL) {
349                 exceptions_throw_nullpointerexception();
350                 return NULL;
351         }
352
353         utf_ptr = u->text;
354         utflength = utf_get_number_of_u2s(u);
355
356         o = builtin_new(class_java_lang_String);
357         a = builtin_newarray_char(utflength);
358
359         /* javastring or character-array could not be created */
360         if ((o == NULL) || (a == NULL))
361                 return NULL;
362
363         /* decompress utf-string */
364
365         for (i = 0; i < utflength; i++) {
366                 ch = utf_nextu2(&utf_ptr);
367                 if (ch == '/')
368                         ch = '.';
369                 a->data[i] = ch;
370         }
371         
372         /* set fields of the javastring-object */
373
374         s = (java_lang_String *) o;
375
376         s->value  = a;
377         s->offset = 0;
378         s->count  = utflength;
379
380         return o;
381 }
382
383
384 /* javastring_new_from_ascii ***************************************************
385
386    creates a new java/lang/String object which contains the given ASCII
387    C-string converted to UTF-16.
388
389    IN:
390       text.........string of ASCII characters
391
392    RETURN VALUE:
393       the java.lang.String object, or 
394       NULL if an exception has been thrown.
395
396 *******************************************************************************/
397
398 java_objectheader *javastring_new_from_ascii(const char *text)
399 {
400         s4 i;
401         s4 len;                             /* length of the string               */
402         java_objectheader *o;
403         java_lang_String  *s;
404         java_chararray    *a;
405
406         if (text == NULL) {
407                 exceptions_throw_nullpointerexception();
408                 return NULL;
409         }
410
411         len = strlen(text);
412
413         o = builtin_new(class_java_lang_String);
414         a = builtin_newarray_char(len);
415
416         /* javastring or character-array could not be created */
417
418         if ((o == NULL) || (a == NULL))
419                 return NULL;
420
421         /* copy text */
422
423         for (i = 0; i < len; i++)
424                 a->data[i] = text[i];
425         
426         /* set fields of the javastring-object */
427
428         s = (java_lang_String *) o;
429
430         s->value  = a;
431         s->offset = 0;
432         s->count  = len;
433
434         return o;
435 }
436
437
438 /* javastring_tochar ***********************************************************
439
440    converts a Java string into a C string.
441         
442    return: pointer to C string
443         
444    Caution: calling method MUST release the allocated memory!
445         
446 *******************************************************************************/
447
448 char *javastring_tochar(java_objectheader *so) 
449 {
450         java_lang_String *s = (java_lang_String *) so;
451         java_chararray *a;
452         char *buf;
453         s4 i;
454         
455         if (!s)
456                 return "";
457
458         a = s->value;
459
460         if (!a)
461                 return "";
462
463         buf = MNEW(char, s->count + 1);
464
465         for (i = 0; i < s->count; i++)
466                 buf[i] = a->data[s->offset + i];
467
468         buf[i] = '\0';
469
470         return buf;
471 }
472
473
474 /* javastring_toutf ************************************************************
475
476    Make utf symbol from javastring.
477
478 *******************************************************************************/
479
480 utf *javastring_toutf(java_objectheader *string, bool isclassname)
481 {
482         java_lang_String *s;
483
484         s = (java_lang_String *) string;
485
486         if (s == NULL)
487                 return utf_null;
488
489         return utf_new_u2(s->value->data + s->offset, s->count, isclassname);
490 }
491
492
493 /* literalstring_u2 ************************************************************
494
495    Searches for the javastring with the specified u2-array in the
496    string hashtable, if there is no such string a new one is created.
497
498    If copymode is true a copy of the u2-array is made.
499
500 *******************************************************************************/
501
502 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
503                                                                         bool copymode)
504 {
505     literalstring    *s;                /* hashtable element                  */
506     java_lang_String *js;               /* u2-array wrapped in javastring     */
507     java_chararray   *stringdata;       /* copy of u2-array                   */
508     u4                key;
509     u4                slot;
510     u2                i;
511
512         LOCK_MONITOR_ENTER(lock_hashtable_string);
513
514     /* find location in hashtable */
515
516     key  = unicode_hashkey(a->data + offset, length);
517     slot = key & (hashtable_string.size - 1);
518     s    = hashtable_string.ptr[slot];
519
520     while (s) {
521                 js = (java_lang_String *) s->string;
522
523                 if (length == js->count) {
524                         /* compare text */
525
526                         for (i = 0; i < length; i++)
527                                 if (a->data[offset + i] != js->value->data[i])
528                                         goto nomatch;
529
530                         /* string already in hashtable, free memory */
531
532                         if (!copymode)
533                                 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
534
535                         LOCK_MONITOR_EXIT(lock_hashtable_string);
536
537                         return (java_objectheader *) js;
538                 }
539
540         nomatch:
541                 /* follow link in external hash chain */
542                 s = s->hashlink;
543     }
544
545     if (copymode) {
546                 /* create copy of u2-array for new javastring */
547                 u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
548                 stringdata = mem_alloc(arraysize);
549 /*              memcpy(stringdata, a, arraysize); */
550                 memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
551                 memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
552
553     } else {
554                 stringdata = a;
555         }
556
557     /* location in hashtable found, complete arrayheader */
558
559     stringdata->header.objheader.vftbl =
560                 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
561     stringdata->header.size = length;
562
563         assert(class_java_lang_String);
564         assert(class_java_lang_String->state & CLASS_LOADED);
565
566         /* if we use eager loading, we have to check loaded String class */
567
568         if (opt_eager)
569                 list_add_first(&unlinkedclasses, class_java_lang_String);
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  = stringdata;
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_objectheader *) 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_objectheader *) 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_objectheader *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 *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) + 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_objectheader* string)
689 {
690         java_lang_String *s;
691         java_chararray *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) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
701 }
702
703
704 /*
705  * These are local overrides for various environment variables in Emacs.
706  * Please do not remove this and leave it at the end of the file, where
707  * Emacs will automagically detect them.
708  * ---------------------------------------------------------------------
709  * Local variables:
710  * mode: c
711  * indent-tabs-mode: t
712  * c-basic-offset: 4
713  * tab-width: 4
714  * End:
715  * vim:noexpandtab:sw=4:ts=4:
716  */