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