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