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