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