e03bc962d444a68705fa149e6ce1fa6a4dea8749
[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 2148 2005-03-30 16:49:40Z twisti $
34
35 */
36
37
38 #include "config.h"
39 #include "types.h"
40
41 #include "vm/global.h"
42
43 #include "mm/memory.h"
44 #include "native/include/java_lang_String.h"
45 #include "vm/exceptions.h"
46 #include "vm/loader.h"
47 #include "vm/options.h"
48 #include "vm/stringlocal.h"
49 #include "vm/utf8.h"
50
51
52 /* stringtable_update **********************************************************
53
54    Traverses the javastring hashtable and sets the vftbl-entries of
55    javastrings which were temporarily set to NULL, because
56    java.lang.Object was not yet loaded.
57
58 *******************************************************************************/
59  
60 void stringtable_update(void)
61 {
62         java_lang_String *js;   
63         java_chararray *a;
64         literalstring *s;       /* hashtable entry */
65         int i;
66
67         for (i = 0; i < string_hash.size; i++) {
68                 s = string_hash.ptr[i];
69                 if (s) {
70                         while (s) {
71                                                                
72                                 js = (java_lang_String *) s->string;
73                                
74                                 if (!js || !js->value) 
75                                         /* error in hashtable found */
76                                         panic("invalid literalstring in hashtable");
77
78                                 a = js->value;
79
80                                 if (!js->header.vftbl) 
81                                         /* vftbl of javastring is NULL */ 
82                                         js->header.vftbl = class_java_lang_String->vftbl;
83
84                                 if (!a->header.objheader.vftbl) 
85                                         /* vftbl of character-array is NULL */ 
86                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
87
88                                 /* follow link in external hash chain */
89                                 s = s->hashlink;
90                         }       
91                 }               
92         }
93 }
94
95
96 /* javastring_new **************************************************************
97
98    creates a new object of type java/lang/String with the text of 
99    the specified utf8-string
100
101    return: pointer to the string or NULL if memory is exhausted.        
102
103 *******************************************************************************/
104
105 java_lang_String *javastring_new(utf *u)
106 {
107         char *utf_ptr;                  /* current utf character in utf string    */
108         u4 utflength;                   /* length of utf-string if uncompressed   */
109         java_lang_String *s;            /* result-string                          */
110         java_chararray *a;
111         s4 i;
112
113         if (!u) {
114                 *exceptionptr = new_nullpointerexception();
115                 return NULL;
116         }
117
118         utf_ptr = u->text;
119         utflength = utf_strlen(u);
120
121         s = (java_lang_String *) builtin_new(class_java_lang_String);
122         a = builtin_newarray_char(utflength);
123
124         /* javastring or character-array could not be created */
125         if (!a || !s)
126                 return NULL;
127
128         /* decompress utf-string */
129         for (i = 0; i < utflength; i++)
130                 a->data[i] = utf_nextu2(&utf_ptr);
131         
132         /* set fields of the javastring-object */
133         s->value  = a;
134         s->offset = 0;
135         s->count  = utflength;
136
137         return s;
138 }
139
140
141 /* javastring_new_char *********************************************************
142
143    creates a new java/lang/String object which contains the convertet
144    C-string passed via text.
145
146    return: the object pointer or NULL if memory is exhausted.
147
148 *******************************************************************************/
149
150 java_lang_String *javastring_new_char(const char *text)
151 {
152         s4 i;
153         s4 len;                             /* length of the string               */
154         java_lang_String *s;                /* result-string                      */
155         java_chararray *a;
156
157         if (!text) {
158                 *exceptionptr = new_nullpointerexception();
159                 return NULL;
160         }
161
162         len = strlen(text);
163
164         s = (java_lang_String *) builtin_new(class_java_lang_String);
165         a = builtin_newarray_char(len);
166
167         /* javastring or character-array could not be created */
168         if (!a || !s)
169                 return NULL;
170
171         /* copy text */
172         for (i = 0; i < len; i++)
173                 a->data[i] = text[i];
174         
175         /* set fields of the javastring-object */
176         s->value  = a;
177         s->offset = 0;
178         s->count  = len;
179
180         return s;
181 }
182
183
184 /* javastring_tochar ***********************************************************
185
186    converts a Java string into a C string.
187         
188    return: pointer to C string
189         
190    Caution: calling method MUST release the allocated memory!
191         
192 *******************************************************************************/
193
194 char *javastring_tochar(java_objectheader *so) 
195 {
196         java_lang_String *s = (java_lang_String *) so;
197         java_chararray *a;
198         char *buf;
199         s4 i;
200         
201         if (!s)
202                 return "";
203
204         a = s->value;
205
206         if (!a)
207                 return "";
208
209         buf = MNEW(char, s->count + 1);
210
211         for (i = 0; i < s->count; i++)
212                 buf[i] = a->data[s->offset + i];
213
214         buf[i] = '\0';
215
216         return buf;
217 }
218
219
220 /* javastring_toutf ************************************************************
221
222    Make utf symbol from javastring.
223
224 *******************************************************************************/
225
226 utf *javastring_toutf(java_lang_String *string, bool isclassname)
227 {
228         java_lang_String *str = (java_lang_String *) string;
229
230         return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
231 }
232
233
234 /* literalstring_u2 ************************************************************
235
236    Searches for the javastring with the specified u2-array in the
237    string hashtable, if there is no such string a new one is created.
238
239    If copymode is true a copy of the u2-array is made.
240
241 *******************************************************************************/
242
243 java_objectheader *literalstring_u2(java_chararray *a, u4 length, u4 offset,
244                                                                         bool copymode)
245 {
246     literalstring *s;                /* hashtable element */
247     java_lang_String *js;            /* u2-array wrapped in javastring */
248     java_chararray *stringdata;      /* copy of u2-array */      
249     u4 key;
250     u4 slot;
251     u2 i;
252
253     /* find location in hashtable */
254     key  = unicode_hashkey(a->data + offset, length);
255     slot = key & (string_hash.size - 1);
256     s    = string_hash.ptr[slot];
257
258     while (s) {
259                 js = (java_lang_String *) s->string;
260
261                 if (length == js->count) {
262                         /* compare text */
263                         for (i = 0; i < length; i++) {
264                                 if (a->data[offset + i] != js->value->data[i])
265                                         goto nomatch;
266                         }
267
268                         /* string already in hashtable, free memory */
269                         if (!copymode)
270                                 mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
271
272                         return (java_objectheader *) js;
273                 }
274
275         nomatch:
276                 /* follow link in external hash chain */
277                 s = s->hashlink;
278     }
279
280     if (copymode) {
281                 /* create copy of u2-array for new javastring */
282                 u4 arraysize = sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10;
283                 stringdata = mem_alloc(arraysize);
284 /*              memcpy(stringdata, a, arraysize); */
285                 memcpy(&(stringdata->header), &(a->header), sizeof(java_arrayheader));
286                 memcpy(&(stringdata->data), &(a->data) + offset, sizeof(u2) * (length - 1) + 10);
287
288     } else {
289                 stringdata = a;
290         }
291
292     /* location in hashtable found, complete arrayheader */
293     stringdata->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
294     stringdata->header.size = length;
295
296         /* if we use eager loading, we have to check loaded String class */
297         if (opt_eager) {
298                 if (!load_class_bootstrap(class_java_lang_String))
299                         return NULL;
300
301                 list_addfirst(&unlinkedclasses, class_java_lang_String);
302         }
303
304         /* create new javastring */
305         js = NEW(java_lang_String);
306 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
307         initObjectLock(&js->header);
308 #endif
309         js->header.vftbl = class_java_lang_String->vftbl;
310         js->value  = stringdata;
311         js->offset = 0;
312         js->count  = length;
313
314         /* create new literalstring */
315         s = NEW(literalstring);
316         s->hashlink = string_hash.ptr[slot];
317         s->string   = (java_objectheader *) js;
318         string_hash.ptr[slot] = s;
319
320         /* update number of hashtable entries */
321         string_hash.entries++;
322
323         /* reorganization of hashtable */       
324         if (string_hash.entries > (string_hash.size * 2)) {
325                 /* reorganization of hashtable, average length of 
326                    the external chains is approx. 2                */  
327
328                 u4 i;
329                 literalstring *s;
330                 hashtable newhash; /* the new hashtable */
331       
332                 /* create new hashtable, double the size */
333                 init_hashtable(&newhash, string_hash.size * 2);
334                 newhash.entries = string_hash.entries;
335       
336                 /* transfer elements to new hashtable */
337                 for (i = 0; i < string_hash.size; i++) {
338                         s = string_hash.ptr[i];
339                         while (s) {
340                                 literalstring *nexts = s->hashlink;
341                                 js   = (java_lang_String *) s->string;
342                                 slot = unicode_hashkey(js->value->data, js->count) & (newhash.size - 1);
343           
344                                 s->hashlink = newhash.ptr[slot];
345                                 newhash.ptr[slot] = s;
346         
347                                 /* follow link in external hash chain */  
348                                 s = nexts;
349                         }
350                 }
351         
352                 /* dispose old table */ 
353                 MFREE(string_hash.ptr, void*, string_hash.size);
354                 string_hash = newhash;
355         }
356
357         return (java_objectheader *) js;
358 }
359
360
361 /* literalstring_new ***********************************************************
362
363    Creates a new javastring with the text of the utf-symbol and inserts it into
364    the string hashtable.
365
366 *******************************************************************************/
367
368 java_objectheader *literalstring_new(utf *u)
369 {
370     char *utf_ptr;                   /* pointer to current unicode character  */
371                                          /* utf string                            */
372     u4 utflength;                    /* length of utf-string if uncompressed  */
373     java_chararray *a;               /* u2-array constructed from utf string  */
374     u4 i;
375
376         utf_ptr = u->text;
377         utflength = utf_strlen(u);
378
379     /* allocate memory */ 
380     a = mem_alloc(sizeof(java_chararray) + sizeof(u2) * (utflength - 1) + 10);
381
382     /* convert utf-string to u2-array */
383     for (i = 0; i < utflength; i++)
384                 a->data[i] = utf_nextu2(&utf_ptr);
385
386     return literalstring_u2(a, utflength, 0, false);
387 }
388
389
390 /* literalstring_free **********************************************************
391
392    Removes a javastring from memory.
393
394 *******************************************************************************/
395
396 void literalstring_free(java_objectheader* sobj)
397 {
398         java_lang_String *s;
399         java_chararray *a;
400
401         s = (java_lang_String *) sobj;
402         a = s->value;
403
404         /* dispose memory of java.lang.String object */
405         FREE(s, java_lang_String);
406
407         /* dispose memory of java-characterarray */
408         FREE(a, sizeof(java_chararray) + sizeof(u2) * (a->header.size - 1)); /* +10 ?? */
409 }
410
411
412 /*
413  * These are local overrides for various environment variables in Emacs.
414  * Please do not remove this and leave it at the end of the file, where
415  * Emacs will automagically detect them.
416  * ---------------------------------------------------------------------
417  * Local variables:
418  * mode: c
419  * indent-tabs-mode: t
420  * c-basic-offset: 4
421  * tab-width: 4
422  * End:
423  */