7932edcae7746e31626291cd55d181b945cc3d10
[cacao.git] / src / vm / string.c
1 /* src/vm/string.c - java.lang.String related functions
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Reinhard Grafl
28             Roman Obermaisser
29             Andreas Krall
30
31    Changes: Christian Thalinger
32
33    $Id: string.c 4126 2006-01-10 20:55:41Z twisti $
34
35 */
36
37
38 #include <assert.h>
39
40 #include "config.h"
41 #include "vm/types.h"
42
43 #include "vm/global.h"
44
45 #include "mm/memory.h"
46 #include "native/include/java_lang_String.h"
47 #include "vm/exceptions.h"
48 #include "vm/loader.h"
49 #include "vm/options.h"
50 #include "vm/stringlocal.h"
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 hashtable hashtable_string;             /* hashtable for javastrings          */
61
62 #if defined(USE_THREADS)
63 static java_objectheader *lock_hashtable_string;
64 #endif
65
66
67 /* global string definitions **************************************************/
68
69 /* exception/error super class */
70
71 const char *string_java_lang_Throwable =
72     "java/lang/Throwable";
73
74 const char *string_java_lang_VMThrowable =
75     "java/lang/VMThrowable";
76
77
78 /* specify some exception strings for code generation */
79
80 const char *string_java_lang_ArithmeticException =
81     "java/lang/ArithmeticException";
82
83 const char *string_java_lang_ArithmeticException_message =
84     "/ by zero";
85
86 const char *string_java_lang_ArrayIndexOutOfBoundsException =
87     "java/lang/ArrayIndexOutOfBoundsException";
88
89 const char *string_java_lang_ArrayStoreException =
90     "java/lang/ArrayStoreException";
91
92 const char *string_java_lang_ClassCastException =
93     "java/lang/ClassCastException";
94
95 const char *string_java_lang_ClassNotFoundException =
96         "java/lang/ClassNotFoundException";
97
98 const char *string_java_lang_CloneNotSupportedException =
99     "java/lang/CloneNotSupportedException";
100
101 const char *string_java_lang_Exception =
102     "java/lang/Exception";
103
104 const char *string_java_lang_IllegalAccessException =
105     "java/lang/IllegalAccessException";
106
107 const char *string_java_lang_IllegalArgumentException =
108     "java/lang/IllegalArgumentException";
109
110 const char *string_java_lang_IllegalMonitorStateException =
111     "java/lang/IllegalMonitorStateException";
112
113 const char *string_java_lang_IndexOutOfBoundsException =
114     "java/lang/IndexOutOfBoundsException";
115
116 const char *string_java_lang_InstantiationException =
117     "java/lang/InstantiationException";
118
119 const char *string_java_lang_InterruptedException =
120     "java/lang/InterruptedException";
121
122 const char *string_java_lang_NegativeArraySizeException =
123     "java/lang/NegativeArraySizeException";
124
125 const char *string_java_lang_NoSuchFieldException =
126         "java/lang/NoSuchFieldException";
127
128 const char *string_java_lang_NoSuchMethodException =
129         "java/lang/NoSuchMethodException";
130
131 const char *string_java_lang_NullPointerException =
132     "java/lang/NullPointerException";
133
134 const char *string_java_lang_reflect_InvocationTargetException =
135     "java/lang/reflect/InvocationTargetException";
136
137
138 /* specify some error strings for code generation */
139
140 const char *string_java_lang_AbstractMethodError =
141     "java/lang/AbstractMethodError";
142
143 const char *string_java_lang_ClassCircularityError =
144     "java/lang/ClassCircularityError";
145
146 const char *string_java_lang_ClassFormatError =
147     "java/lang/ClassFormatError";
148
149 const char *string_java_lang_Error =
150     "java/lang/Error";
151
152 const char *string_java_lang_ExceptionInInitializerError =
153     "java/lang/ExceptionInInitializerError";
154
155 const char *string_java_lang_IncompatibleClassChangeError =
156     "java/lang/IncompatibleClassChangeError";
157
158 const char *string_java_lang_InstantiationError =
159     "java/lang/InstantiationError";
160
161 const char *string_java_lang_InternalError =
162     "java/lang/InternalError";
163
164 const char *string_java_lang_LinkageError =
165     "java/lang/LinkageError";
166
167 const char *string_java_lang_NoClassDefFoundError =
168     "java/lang/NoClassDefFoundError";
169
170 const char *string_java_lang_NoSuchFieldError =
171         "java/lang/NoSuchFieldError";
172
173 const char *string_java_lang_NoSuchMethodError =
174         "java/lang/NoSuchMethodError";
175
176 const char *string_java_lang_OutOfMemoryError =
177     "java/lang/OutOfMemoryError";
178
179 const char *string_java_lang_UnsatisfiedLinkError =
180     "java/lang/UnsatisfiedLinkError";
181
182 const char *string_java_lang_UnsupportedClassVersionError =
183     "java/lang/UnsupportedClassVersionError";
184
185 const char *string_java_lang_VerifyError =
186     "java/lang/VerifyError";
187
188 const char *string_java_lang_VirtualMachineError =
189     "java/lang/VirtualMachineError";
190
191
192 /* string_init *****************************************************************
193
194    Initialize the string hashtable lock.
195
196 *******************************************************************************/
197
198 bool string_init(void)
199 {
200         /* create string (javastring) hashtable */
201
202         hashtable_create(&hashtable_string, HASHTABLE_STRING_SIZE);
203
204 #if defined(USE_THREADS)
205         /* create string hashtable lock object */
206
207         lock_hashtable_string = NEW(java_objectheader);
208
209 # if defined(NATIVE_THREADS)
210         initObjectLock(lock_hashtable_string);
211 # endif
212 #endif
213
214         /* everything's ok */
215
216         return true;
217 }
218
219
220 /* stringtable_update **********************************************************
221
222    Traverses the javastring hashtable and sets the vftbl-entries of
223    javastrings which were temporarily set to NULL, because
224    java.lang.Object was not yet loaded.
225
226 *******************************************************************************/
227  
228 void stringtable_update(void)
229 {
230         java_lang_String *js;   
231         java_chararray *a;
232         literalstring *s;       /* hashtable entry */
233         int i;
234
235         for (i = 0; i < hashtable_string.size; i++) {
236                 s = hashtable_string.ptr[i];
237                 if (s) {
238                         while (s) {
239                                                                
240                                 js = (java_lang_String *) s->string;
241                                
242                                 if (!js || !js->value) {
243                                         /* error in hashtable found */
244                                         log_text("invalid literalstring in hashtable");
245                                         assert(0);
246                                 }
247
248                                 a = js->value;
249
250                                 if (!js->header.vftbl) 
251                                         /* vftbl of javastring is NULL */ 
252                                         js->header.vftbl = class_java_lang_String->vftbl;
253
254                                 if (!a->header.objheader.vftbl) 
255                                         /* vftbl of character-array is NULL */ 
256                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
257
258                                 /* follow link in external hash chain */
259                                 s = s->hashlink;
260                         }       
261                 }               
262         }
263 }
264
265
266 /* javastring_new **************************************************************
267
268    creates a new object of type java/lang/String with the text of 
269    the specified utf8-string
270
271    return: pointer to the string or NULL if memory is exhausted.        
272
273 *******************************************************************************/
274
275 java_lang_String *javastring_new(utf *u)
276 {
277         char *utf_ptr;                  /* current utf character in utf string    */
278         u4 utflength;                   /* length of utf-string if uncompressed   */
279         java_lang_String *s;            /* result-string                          */
280         java_chararray *a;
281         s4 i;
282
283         if (!u) {
284                 exceptions_throw_nullpointerexception();
285                 return NULL;
286         }
287
288         utf_ptr = u->text;
289         utflength = utf_strlen(u);
290
291         s = (java_lang_String *) builtin_new(class_java_lang_String);
292         a = builtin_newarray_char(utflength);
293
294         /* javastring or character-array could not be created */
295         if (!a || !s)
296                 return NULL;
297
298         /* decompress utf-string */
299         for (i = 0; i < utflength; i++)
300                 a->data[i] = utf_nextu2(&utf_ptr);
301         
302         /* set fields of the javastring-object */
303         s->value  = a;
304         s->offset = 0;
305         s->count  = utflength;
306
307         return s;
308 }
309
310 /* javastring_new_slash_to_dot *************************************************
311
312    creates a new object of type java/lang/String with the text of 
313    the specified utf8-string with slashes changed to dots
314
315    return: pointer to the string or NULL if memory is exhausted.        
316
317 *******************************************************************************/
318
319 java_lang_String *javastring_new_slash_to_dot(utf *u)
320 {
321         char *utf_ptr;                  /* current utf character in utf string    */
322         u4 utflength;                   /* length of utf-string if uncompressed   */
323         java_lang_String *s;            /* result-string                          */
324         java_chararray *a;
325         s4 i;
326         u2 ch;
327
328         if (!u) {
329                 exceptions_throw_nullpointerexception();
330                 return NULL;
331         }
332
333         utf_ptr = u->text;
334         utflength = utf_strlen(u);
335
336         s = (java_lang_String *) builtin_new(class_java_lang_String);
337         a = builtin_newarray_char(utflength);
338
339         /* javastring or character-array could not be created */
340         if (!a || !s)
341                 return NULL;
342
343         /* decompress utf-string */
344         for (i = 0; i < utflength; i++) {
345                 ch = utf_nextu2(&utf_ptr);
346                 if (ch == '/')
347                         ch = '.';
348                 a->data[i] = ch;
349         }
350         
351         /* set fields of the javastring-object */
352         s->value  = a;
353         s->offset = 0;
354         s->count  = utflength;
355
356         return s;
357 }
358
359
360 /* javastring_new_char *********************************************************
361
362    creates a new java/lang/String object which contains the convertet
363    C-string passed via text.
364
365    return: the object pointer or NULL if memory is exhausted.
366
367 *******************************************************************************/
368
369 java_lang_String *javastring_new_char(const char *text)
370 {
371         s4 i;
372         s4 len;                             /* length of the string               */
373         java_lang_String *s;                /* result-string                      */
374         java_chararray *a;
375
376         if (!text) {
377                 exceptions_throw_nullpointerexception();
378                 return NULL;
379         }
380
381         len = strlen(text);
382
383         s = (java_lang_String *) builtin_new(class_java_lang_String);
384         a = builtin_newarray_char(len);
385
386         /* javastring or character-array could not be created */
387         if (!a || !s)
388                 return NULL;
389
390         /* copy text */
391         for (i = 0; i < len; i++)
392                 a->data[i] = text[i];
393         
394         /* set fields of the javastring-object */
395         s->value  = a;
396         s->offset = 0;
397         s->count  = len;
398
399         return s;
400 }
401
402
403 /* javastring_tochar ***********************************************************
404
405    converts a Java string into a C string.
406         
407    return: pointer to C string
408         
409    Caution: calling method MUST release the allocated memory!
410         
411 *******************************************************************************/
412
413 char *javastring_tochar(java_objectheader *so) 
414 {
415         java_lang_String *s = (java_lang_String *) so;
416         java_chararray *a;
417         char *buf;
418         s4 i;
419         
420         if (!s)
421                 return "";
422
423         a = s->value;
424
425         if (!a)
426                 return "";
427
428         buf = MNEW(char, s->count + 1);
429
430         for (i = 0; i < s->count; i++)
431                 buf[i] = a->data[s->offset + i];
432
433         buf[i] = '\0';
434
435         return buf;
436 }
437
438
439 /* javastring_toutf ************************************************************
440
441    Make utf symbol from javastring.
442
443 *******************************************************************************/
444
445 utf *javastring_toutf(java_lang_String *string, bool isclassname)
446 {
447         java_lang_String *str = (java_lang_String *) string;
448
449         return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
450 }
451
452
453 /* javastring_strlen ***********************************************************
454
455    Returns the length of the Java string.
456         
457 *******************************************************************************/
458
459 s4 javastring_strlen(java_lang_String *s)
460 {
461         if (!s)
462                 return 0;
463
464         return s->count;
465 }
466
467
468 /* literalstring_u2 ************************************************************
469
470    Searches for the javastring with the specified u2-array in the
471    string hashtable, if there is no such string a new one is created.
472
473    If copymode is true a copy of the u2-array is made.
474
475 *******************************************************************************/
476
477 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
478                                                                         bool copymode)
479 {
480     literalstring    *s;                /* hashtable element                  */
481     java_lang_String *js;               /* u2-array wrapped in javastring     */
482     java_chararray   *stringdata;       /* copy of u2-array                   */
483     u4                key;
484     u4                slot;
485     u2                i;
486
487 #if defined(USE_THREADS)
488         builtin_monitorenter(lock_hashtable_string);
489 #endif
490
491     /* find location in hashtable */
492
493     key  = unicode_hashkey(a->data + offset, length);
494     slot = key & (hashtable_string.size - 1);
495     s    = hashtable_string.ptr[slot];
496
497     while (s) {
498                 js = (java_lang_String *) s->string;
499
500                 if (length == js->count) {
501                         /* compare text */
502
503                         for (i = 0; i < length; i++)
504                                 if (a->data[offset + i] != js->value->data[i])
505                                         goto nomatch;
506
507                         /* string already in hashtable, free memory */
508
509                         if (!copymode)
510                                 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
511
512 #if defined(USE_THREADS)
513                         builtin_monitorexit(lock_hashtable_string);
514 #endif
515
516                         return (java_objectheader *) js;
517                 }
518
519         nomatch:
520                 /* follow link in external hash chain */
521                 s = s->hashlink;
522     }
523
524     if (copymode) {
525                 /* create copy of u2-array for new javastring */
526                 u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
527                 stringdata = mem_alloc(arraysize);
528 /*              memcpy(stringdata, a, arraysize); */
529                 memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
530                 memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
531
532     } else {
533                 stringdata = a;
534         }
535
536     /* location in hashtable found, complete arrayheader */
537
538     stringdata->header.objheader.vftbl =
539                 primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
540     stringdata->header.size = length;
541
542         /* XXX TWISTI: is this necessary? */
543         if (!class_java_lang_String)
544                 class_java_lang_String = load_class_bootstrap(utf_java_lang_String);
545
546         assert(class_java_lang_String);
547         assert(class_java_lang_String->state & CLASS_LOADED);
548
549         /* if we use eager loading, we have to check loaded String class */
550
551         if (opt_eager)
552                 list_addfirst(&unlinkedclasses, class_java_lang_String);
553
554         /* create new javastring */
555
556         js = NEW(java_lang_String);
557
558 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
559         initObjectLock(&js->header);
560 #endif
561
562         js->header.vftbl = class_java_lang_String->vftbl;
563         js->value  = stringdata;
564         js->offset = 0;
565         js->count  = length;
566
567         /* create new literalstring */
568
569         s = NEW(literalstring);
570         s->hashlink = hashtable_string.ptr[slot];
571         s->string   = (java_objectheader *) js;
572         hashtable_string.ptr[slot] = s;
573
574         /* update number of hashtable entries */
575
576         hashtable_string.entries++;
577
578         /* reorganization of hashtable */       
579
580         if (hashtable_string.entries > (hashtable_string.size * 2)) {
581                 /* reorganization of hashtable, average length of the external
582                    chains is approx. 2 */
583
584                 u4                i;
585                 literalstring    *s;
586                 literalstring    *nexts;
587                 java_lang_String *tmpjs;
588                 hashtable         newhash;                       /* the new hashtable */
589       
590                 /* create new hashtable, double the size */
591
592                 hashtable_create(&newhash, hashtable_string.size * 2);
593                 newhash.entries = hashtable_string.entries;
594       
595                 /* transfer elements to new hashtable */
596
597                 for (i = 0; i < hashtable_string.size; i++) {
598                         s = hashtable_string.ptr[i];
599
600                         while (s) {
601                                 nexts = s->hashlink;
602                                 tmpjs = (java_lang_String *) s->string;
603                                 slot  = unicode_hashkey(tmpjs->value->data, tmpjs->count) & (newhash.size - 1);
604           
605                                 s->hashlink = newhash.ptr[slot];
606                                 newhash.ptr[slot] = s;
607         
608                                 /* follow link in external hash chain */
609                                 s = nexts;
610                         }
611                 }
612         
613                 /* dispose old table */
614
615                 MFREE(hashtable_string.ptr, void*, hashtable_string.size);
616                 hashtable_string = newhash;
617         }
618
619 #if defined(USE_THREADS)
620         builtin_monitorexit(lock_hashtable_string);
621 #endif
622
623         return (java_objectheader *) js;
624 }
625
626
627 /* literalstring_new ***********************************************************
628
629    Creates a new javastring with the text of the utf-symbol and inserts it into
630    the string hashtable.
631
632 *******************************************************************************/
633
634 java_objectheader *literalstring_new(utf *u)
635 {
636     char           *utf_ptr;         /* pointer to current unicode character  */
637                                          /* utf string                            */
638     u4              utflength;       /* length of utf-string if uncompressed  */
639     java_chararray *a;               /* u2-array constructed from utf string  */
640     u4              i;
641
642         utf_ptr = u->text;
643         utflength = utf_strlen(u);
644
645     /* allocate memory */ 
646     a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
647
648     /* convert utf-string to u2-array */
649     for (i = 0; i < utflength; i++)
650                 a->data[i] = utf_nextu2(&utf_ptr);
651
652     return literalstring_u2(a, utflength, 0, false);
653 }
654
655
656 /* literalstring_free **********************************************************
657
658    Removes a javastring from memory.
659
660 *******************************************************************************/
661
662 void literalstring_free(java_objectheader* sobj)
663 {
664         java_lang_String *s;
665         java_chararray *a;
666
667         s = (java_lang_String *) sobj;
668         a = s->value;
669
670         /* dispose memory of java.lang.String object */
671         FREE(s, java_lang_String);
672
673         /* dispose memory of java-characterarray */
674         FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
675 }
676
677
678 /*
679  * These are local overrides for various environment variables in Emacs.
680  * Please do not remove this and leave it at the end of the file, where
681  * Emacs will automagically detect them.
682  * ---------------------------------------------------------------------
683  * Local variables:
684  * mode: c
685  * indent-tabs-mode: t
686  * c-basic-offset: 4
687  * tab-width: 4
688  * End:
689  */