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