PR164: Get rid of mysterious 10 trailing bytes in literal strings.
[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, 2010
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
476         mutex->lock();
477
478         // XXX: Fix me!
479         CharArray ca(a);
480         uint16_t* ptr = (uint16_t*) ca.get_raw_data_ptr();
481
482         /* find location in hashtable */
483
484         key  = unicode_hashkey(ptr + offset, length);
485         slot = key & (hashtable_string.size - 1);
486         s    = (literalstring*) hashtable_string.ptr[slot];
487
488         while (s) {
489                 // FIXME
490                 java_lang_String js(LLNI_WRAP(s->string));
491
492                 if (length == js.get_count()) {
493                         /* compare text */
494
495                         for (int32_t i = 0; i < length; i++) {
496                                 // FIXME This is not handle capable!
497                                 CharArray jsca(js.get_value());
498                                 uint16_t* sptr = (uint16_t*) jsca.get_raw_data_ptr();
499                                 
500                                 if (ptr[offset + i] != sptr[i])
501                                         goto nomatch;
502                         }
503
504                         /* string already in hashtable, free memory */
505
506                         if (!copymode)
507                                 mem_free(a, sizeof(java_chararray_t) + sizeof(u2) * (length - 1));
508
509                         mutex->unlock();
510
511                         return js.get_handle();
512                 }
513
514         nomatch:
515                 /* follow link in external hash chain */
516                 s = s->hashlink;
517         }
518
519         java_chararray_t* acopy;
520         if (copymode) {
521                 /* create copy of u2-array for new javastring */
522                 u4 arraysize = sizeof(java_chararray_t) + sizeof(u2) * (length - 1);
523                 acopy = (java_chararray_t*) mem_alloc(arraysize);
524 /*              memcpy(ca, a, arraysize); */
525                 memcpy(&(acopy->header), &(((java_chararray_t*) a)->header), sizeof(java_array_t));
526                 memcpy(&(acopy->data), &(((java_chararray_t*) a)->data) + offset, sizeof(u2) * length);
527         }
528         else {
529                 acopy = (java_chararray_t*) a;
530         }
531
532         /* location in hashtable found, complete arrayheader */
533
534         acopy->header.objheader.vftbl = Primitive::get_arrayclass_by_type(ARRAYTYPE_CHAR)->vftbl;
535         acopy->header.size            = length;
536
537         assert(class_java_lang_String);
538         assert(class_java_lang_String->state & CLASS_LOADED);
539
540         // Create a new java.lang.String object on the system heap.
541         java_object_t* o = (java_object_t*) MNEW(uint8_t, class_java_lang_String->instancesize);
542
543 #if defined(ENABLE_STATISTICS)
544         if (opt_stat)
545                 size_string += sizeof(class_java_lang_String->instancesize);
546 #endif
547
548 #if defined(ENABLE_THREADS)
549         Lockword(o->lockword).init();
550 #endif
551
552         o->vftbl = class_java_lang_String->vftbl;
553
554         CharArray cacopy((java_handle_chararray_t*) acopy);
555         java_lang_String jls(o, cacopy.get_handle(), length);
556
557         /* create new literalstring */
558
559         s = NEW(literalstring);
560
561 #if defined(ENABLE_STATISTICS)
562         if (opt_stat)
563                 size_string += sizeof(literalstring);
564 #endif
565
566         s->hashlink = (literalstring*) hashtable_string.ptr[slot];
567         s->string   = (java_object_t*) LLNI_UNWRAP(jls.get_handle());
568         hashtable_string.ptr[slot] = s;
569
570         /* update number of hashtable entries */
571
572         hashtable_string.entries++;
573
574         /* reorganization of hashtable */       
575
576         if (hashtable_string.entries > (hashtable_string.size * 2)) {
577                 /* reorganization of hashtable, average length of the external
578                    chains is approx. 2 */
579
580                 u4             i;
581                 literalstring *s;
582                 literalstring *nexts;
583                 hashtable      newhash;                          /* the new hashtable */
584       
585                 /* create new hashtable, double the size */
586
587                 hashtable_create(&newhash, hashtable_string.size * 2);
588                 newhash.entries = hashtable_string.entries;
589       
590                 /* transfer elements to new hashtable */
591
592                 for (i = 0; i < hashtable_string.size; i++) {
593                         s = (literalstring*) hashtable_string.ptr[i];
594
595                         while (s) {
596                                 nexts = s->hashlink;
597                                 java_lang_String tmpjls(LLNI_WRAP(s->string));
598                                 // FIXME This is not handle capable!
599                                 slot  = unicode_hashkey(((java_chararray_t*) LLNI_UNWRAP(tmpjls.get_value()))->data, tmpjls.get_count()) & (newhash.size - 1);
600           
601                                 s->hashlink = (literalstring*) newhash.ptr[slot];
602                                 newhash.ptr[slot] = s;
603         
604                                 /* follow link in external hash chain */
605                                 s = nexts;
606                         }
607                 }
608         
609                 /* dispose old table */
610
611                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
612                 hashtable_string = newhash;
613         }
614
615         mutex->unlock();
616
617         return (java_object_t*) LLNI_UNWRAP(jls.get_handle());
618 }
619
620
621 /* literalstring_new ***********************************************************
622
623    Creates a new literalstring with the text of the utf-symbol and inserts
624    it into the string hashtable.
625
626 *******************************************************************************/
627
628 java_object_t *literalstring_new(utf *u)
629 {
630         char             *utf_ptr;       /* pointer to current unicode character  */
631                                          /* utf string                            */
632         int32_t           utflength;     /* length of utf-string if uncompressed  */
633         java_chararray_t *a;             /* u2-array constructed from utf string  */
634
635         utf_ptr = u->text;
636         utflength = utf_get_number_of_u2s(u);
637
638         /* allocate memory */ 
639         a = (java_chararray_t*) mem_alloc(sizeof(java_chararray_t) + sizeof(u2) * (utflength - 1));
640
641         /* convert utf-string to u2-array */
642         for (int32_t i = 0; i < utflength; i++)
643                 a->data[i] = utf_nextu2(&utf_ptr);
644
645         return literalstring_u2((java_handle_chararray_t*) a, utflength, 0, false);
646 }
647
648
649 /* literalstring_free **********************************************************
650
651    Removes a literalstring from memory.
652
653 *******************************************************************************/
654
655 #if 0
656 /* TWISTI This one is currently not used. */
657
658 static void literalstring_free(java_object_t* string)
659 {
660         heapstring_t     *s;
661         java_chararray_t *a;
662
663         s = (heapstring_t *) string;
664         a = s->value;
665
666         /* dispose memory of java.lang.String object */
667         FREE(s, heapstring_t);
668
669         /* dispose memory of java-characterarray */
670         FREE(a, sizeof(java_chararray_t) + sizeof(u2) * (a->header.size - 1));
671 }
672 #endif
673
674
675 /* javastring_intern ***********************************************************
676
677    Intern the given Java string.
678
679 *******************************************************************************/
680
681 java_handle_t *javastring_intern(java_handle_t *string)
682 {
683         java_lang_String jls(string);
684
685         CharArray ca(jls.get_value());
686
687         int32_t count  = jls.get_count();
688         int32_t offset = jls.get_offset();
689
690         java_handle_t* o = literalstring_u2(ca.get_handle(), count, offset, true);
691
692         return o;
693 }
694
695
696 /* javastring_fprint ***********************************************************
697
698    Print the given Java string to the given stream.
699
700 *******************************************************************************/
701
702 void javastring_fprint(java_handle_t *s, FILE *stream)
703 {
704         java_lang_String jls(s);
705
706         CharArray ca(jls.get_value());
707
708         int32_t count  = jls.get_count();
709         int32_t offset = jls.get_offset();
710
711         // XXX: Fix me!
712         uint16_t* ptr = (uint16_t*) ca.get_raw_data_ptr();
713
714         for (int32_t i = offset; i < offset + count; i++) {
715                 uint16_t c = ptr[i];
716                 fputc(c, stream);
717         }
718 }
719
720
721 /*
722  * These are local overrides for various environment variables in Emacs.
723  * Please do not remove this and leave it at the end of the file, where
724  * Emacs will automagically detect them.
725  * ---------------------------------------------------------------------
726  * Local variables:
727  * mode: c++
728  * indent-tabs-mode: t
729  * c-basic-offset: 4
730  * tab-width: 4
731  * End:
732  * vim:noexpandtab:sw=4:ts=4:
733  */