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