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