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