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