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