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