added data structures for parsed descriptors and class references
[cacao.git] / src / vm / class.c
1 /* vm/class.c - class 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
29    Changes: Mark Probst
30             Andreas Krall
31             Christian Thalinger
32
33    $Id: class.c 2078 2005-03-25 13:30:14Z edwin $
34
35 */
36
37
38 #include <string.h>
39
40 #include "config.h"
41 #include "types.h"
42
43 #include "mm/memory.h"
44
45 #if defined(USE_THREADS)
46 # if defined(NATIVE_THREADS)
47 #  include "threads/native/threads.h"
48 # else
49 #  include "threads/green/threads.h"
50 #  include "threads/green/locks.h"
51 # endif
52 #endif
53
54 #include "toolbox/logging.h"
55 #include "vm/class.h"
56 #include "vm/loader.h"
57 #include "vm/options.h"
58 #include "vm/statistics.h"
59 #include "vm/tables.h"
60 #include "vm/utf8.h"
61
62
63 /* global variables ***********************************************************/
64
65 hashtable class_hash;                   /* hashtable for classes              */
66
67 list unlinkedclasses;                   /* this is only used for eager class  */
68                                         /* loading                            */
69
70
71 /* frequently used classes ****************************************************/
72
73 /* important system classes */
74
75 classinfo *class_java_lang_Object;
76 classinfo *class_java_lang_Class;
77 classinfo *class_java_lang_ClassLoader;
78 classinfo *class_java_lang_Cloneable;
79 classinfo *class_java_lang_SecurityManager;
80 classinfo *class_java_lang_String;
81 classinfo *class_java_lang_System;
82 classinfo *class_java_io_Serializable;
83
84
85 /* system exception classes required in cacao */
86
87 classinfo *class_java_lang_Throwable;
88 classinfo *class_java_lang_VMThrowable;
89 classinfo *class_java_lang_Exception;
90 classinfo *class_java_lang_Error;
91 classinfo *class_java_lang_OutOfMemoryError;
92
93
94 classinfo *class_java_lang_Void;
95 classinfo *class_java_lang_Boolean;
96 classinfo *class_java_lang_Byte;
97 classinfo *class_java_lang_Character;
98 classinfo *class_java_lang_Short;
99 classinfo *class_java_lang_Integer;
100 classinfo *class_java_lang_Long;
101 classinfo *class_java_lang_Float;
102 classinfo *class_java_lang_Double;
103
104 /* some classes which may be used more often */
105
106 classinfo *class_java_util_Vector;
107
108
109 /* pseudo classes for the typechecker */
110
111 classinfo *pseudo_class_Arraystub;
112 classinfo *pseudo_class_Null;
113 classinfo *pseudo_class_New;
114
115
116 /* class_init ******************************************************************
117
118    Initialize the class subsystem.
119
120 *******************************************************************************/
121
122 void class_init_foo(void)
123 {
124         class_java_lang_Object          = class_new_intern(utf_java_lang_Object);
125
126         class_java_lang_Class           = class_new(utf_java_lang_Class);
127         class_java_lang_ClassLoader     = class_new(utf_java_lang_ClassLoader);
128         class_java_lang_Cloneable       = class_new(utf_java_lang_Cloneable);
129         class_java_lang_SecurityManager = class_new(utf_java_lang_SecurityManager);
130         class_java_lang_String          = class_new(utf_java_lang_String);
131         class_java_lang_System          = class_new(utf_java_lang_System);
132         class_java_io_Serializable      = class_new(utf_java_io_Serializable);
133
134         class_java_lang_Throwable       = class_new(utf_java_lang_Throwable);
135         class_java_lang_VMThrowable     = class_new(utf_java_lang_VMThrowable);
136         class_java_lang_Exception       = class_new(utf_java_lang_Exception);
137         class_java_lang_Error           = class_new(utf_java_lang_Error);
138         class_java_lang_OutOfMemoryError =
139                 class_new(utf_java_lang_OutOfMemoryError);
140
141         class_java_lang_Void            = class_new(utf_java_lang_Void);
142         class_java_lang_Boolean         = class_new(utf_java_lang_Boolean);
143         class_java_lang_Byte            = class_new(utf_java_lang_Byte);
144         class_java_lang_Character       = class_new(utf_java_lang_Character);
145         class_java_lang_Short           = class_new(utf_java_lang_Short);
146         class_java_lang_Integer         = class_new(utf_java_lang_Integer);
147         class_java_lang_Long            = class_new(utf_java_lang_Long);
148         class_java_lang_Float           = class_new(utf_java_lang_Float);
149         class_java_lang_Double          = class_new(utf_java_lang_Double);
150
151         class_java_util_Vector          = class_new(utf_java_util_Vector);
152
153     pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$"));
154         pseudo_class_Null      = class_new_intern(utf_new_char("$NULL$"));
155         pseudo_class_New       = class_new_intern(utf_new_char("$NEW$"));
156 }
157
158
159 /* class_new *******************************************************************
160
161    Searches for the class with the specified name in the classes
162    hashtable, if there is no such class a new classinfo structure is
163    created and inserted into the list of classes to be loaded.
164
165 *******************************************************************************/
166
167 classinfo *class_new(utf *classname)
168 {
169     classinfo *c;
170
171 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
172     tables_lock();
173 #endif
174
175     c = class_new_intern(classname);
176
177         /* we support eager class loading and linking on demand */
178
179         if (opt_eager) {
180                 classinfo *tc;
181                 classinfo *tmp;
182
183                 list_init(&unlinkedclasses, OFFSET(classinfo, listnode));
184
185                 if (!c->loaded) {
186                         if (!class_load(c)) {
187 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
188                                 tables_unlock();
189 #endif
190                                 return c;
191                         }
192                 }
193
194                 /* link all referenced classes */
195
196                 tc = list_first(&unlinkedclasses);
197
198                 while (tc) {
199                         /* skip the current loaded/linked class */
200                         if (tc != c) {
201                                 if (!class_link(tc)) {
202 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
203                                         tables_unlock();
204 #endif
205                                         return c;
206                                 }
207                         }
208
209                         /* we need a tmp variable here, because list_remove sets prev and
210                            next to NULL */
211                         tmp = list_next(&unlinkedclasses, tc);
212                         list_remove(&unlinkedclasses, tc);
213                         tc = tmp;
214                 }
215
216                 if (!c->linked) {
217                         if (!class_link(c)) {
218 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
219                                 tables_unlock();
220 #endif
221                                 return c;
222                         }
223                 }
224         }
225
226 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
227     tables_unlock();
228 #endif
229
230     return c;
231 }
232
233
234 classinfo *class_new_intern(utf *classname)
235 {
236         classinfo *c;     /* hashtable element */
237         u4 key;           /* hashkey computed from classname */
238         u4 slot;          /* slot in hashtable */
239         u2 i;
240
241         key  = utf_hashkey(classname->text, classname->blength);
242         slot = key & (class_hash.size - 1);
243         c    = class_hash.ptr[slot];
244
245         /* search external hash chain for the class */
246         while (c) {
247                 if (c->name->blength == classname->blength) {
248                         for (i = 0; i < classname->blength; i++)
249                                 if (classname->text[i] != c->name->text[i]) goto nomatch;
250                                                 
251                         /* class found in hashtable */
252                         return c;
253                 }
254                         
255         nomatch:
256                 c = c->hashlink; /* next element in external chain */
257         }
258
259         /* location in hashtable found, create new classinfo structure */
260
261 #if defined(STATISTICS)
262         if (opt_stat)
263                 count_class_infos += sizeof(classinfo);
264 #endif
265
266         if (initverbose) {
267                 char logtext[MAXLOGTEXT];
268                 sprintf(logtext, "Creating class: ");
269                 utf_sprint_classname(logtext + strlen(logtext), classname);
270                 log_text(logtext);
271         }
272
273         c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
274         /*c=NEW(classinfo);*/
275         c->vmClass = 0;
276         c->flags = 0;
277         c->name = classname;
278         c->packagename = NULL;
279         c->cpcount = 0;
280         c->cptags = NULL;
281         c->cpinfos = NULL;
282         c->classrefs = NULL;
283         c->classrefcount = 0;
284         c->parseddescs = NULL;
285         c->parseddescsize = 0;
286         c->super = NULL;
287         c->sub = NULL;
288         c->nextsub = NULL;
289         c->interfacescount = 0;
290         c->interfaces = NULL;
291         c->fieldscount = 0;
292         c->fields = NULL;
293         c->methodscount = 0;
294         c->methods = NULL;
295         c->linked = false;
296         c->loaded = false;
297         c->index = 0;
298         c->instancesize = 0;
299         c->header.vftbl = NULL;
300         c->innerclasscount = 0;
301         c->innerclass = NULL;
302         c->vftbl = NULL;
303         c->initialized = false;
304         c->initializing = false;
305         c->classvftbl = false;
306     c->classUsed = 0;
307     c->impldBy = NULL;
308         c->classloader = NULL;
309         c->sourcefile = NULL;
310         
311         /* insert class into the hashtable */
312         c->hashlink = class_hash.ptr[slot];
313         class_hash.ptr[slot] = c;
314
315         /* update number of hashtable-entries */
316         class_hash.entries++;
317
318         if (class_hash.entries > (class_hash.size * 2)) {
319
320                 /* reorganization of hashtable, average length of 
321                    the external chains is approx. 2                */  
322
323                 u4 i;
324                 classinfo *c;
325                 hashtable newhash;  /* the new hashtable */
326
327                 /* create new hashtable, double the size */
328                 init_hashtable(&newhash, class_hash.size * 2);
329                 newhash.entries = class_hash.entries;
330
331                 /* transfer elements to new hashtable */
332                 for (i = 0; i < class_hash.size; i++) {
333                         c = (classinfo *) class_hash.ptr[i];
334                         while (c) {
335                                 classinfo *nextc = c->hashlink;
336                                 u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
337                                                 
338                                 c->hashlink = newhash.ptr[slot];
339                                 newhash.ptr[slot] = c;
340
341                                 c = nextc;
342                         }
343                 }
344         
345                 /* dispose old table */ 
346                 MFREE(class_hash.ptr, void*, class_hash.size);
347                 class_hash = newhash;
348         }
349
350         /* Array classes need further initialization. */
351         if (c->name->text[0] == '[') {
352                 /* Array classes are not loaded from classfiles. */
353                 c->loaded = true;
354                 class_new_array(c);
355                 c->packagename = array_packagename;
356
357         } else {
358                 /* Find the package name */
359                 /* Classes in the unnamed package keep packagename == NULL. */
360                 char *p = utf_end(c->name) - 1;
361                 char *start = c->name->text;
362                 for (;p > start; --p) {
363                         if (*p == '/') {
364                                 c->packagename = utf_new (start, p - start);
365                                 break;
366                         }
367                 }
368         }
369
370 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
371         initObjectLock(&c->header);
372 #endif
373
374         return c;
375 }
376
377
378 /* class_get *******************************************************************
379
380    Searches for the class with the specified name in the classes
381    hashtable if there is no such class NULL is returned.
382
383 *******************************************************************************/
384
385 classinfo *class_get(utf *classname)
386 {
387         classinfo *c;  /* hashtable element */ 
388         u4 key;        /* hashkey computed from classname */   
389         u4 slot;       /* slot in hashtable */
390         u2 i;  
391
392         key  = utf_hashkey(classname->text, classname->blength);
393         slot = key & (class_hash.size-1);
394         c    = class_hash.ptr[slot];
395
396         /* search external hash-chain */
397         while (c) {
398                 if (c->name->blength == classname->blength) {
399                         /* compare classnames */
400                         for (i = 0; i < classname->blength; i++) 
401                                 if (classname->text[i] != c->name->text[i])
402                                         goto nomatch;
403
404                         /* class found in hashtable */                          
405                         return c;
406                 }
407                         
408         nomatch:
409                 c = c->hashlink;
410         }
411
412         /* class not found */
413         return NULL;
414 }
415
416
417 /* class_remove ****************************************************************
418
419    Removes the class entry wth the specified name in the classes
420    hashtable, furthermore the class' resources are freed if there is
421    no such class false is returned.
422
423 *******************************************************************************/
424
425 bool class_remove(classinfo *c)
426 {
427         classinfo *tc;                      /* hashtable element                  */
428         classinfo *pc;
429         u4 key;                             /* hashkey computed from classname    */
430         u4 slot;                            /* slot in hashtable                  */
431         u2 i;  
432
433         key  = utf_hashkey(c->name->text, c->name->blength);
434         slot = key & (class_hash.size - 1);
435         tc   = class_hash.ptr[slot];
436         pc   = NULL;
437
438         /* search external hash-chain */
439         while (tc) {
440                 if (tc->name->blength == c->name->blength) {
441                         
442                         /* compare classnames */
443                         for (i = 0; i < c->name->blength; i++)
444                                 if (tc->name->text[i] != c->name->text[i])
445                                         goto nomatch;
446
447                         /* class found in hashtable */
448                         if (!pc)
449                                 class_hash.ptr[slot] = tc->hashlink;
450                         else
451                                 pc->hashlink = tc->hashlink;
452
453                         class_free(tc);
454
455                         return true;
456                 }
457                         
458         nomatch:
459                 pc = tc;
460                 tc = tc->hashlink;
461         }
462
463         /* class not found */
464         return false;
465 }
466
467
468 /* class_array_of **************************************************************
469
470    Returns an array class with the given component class. The array
471    class is dynamically created if neccessary.
472
473 *******************************************************************************/
474
475 classinfo *class_array_of(classinfo *component)
476 {
477     s4 namelen;
478     char *namebuf;
479         classinfo *c;
480
481     /* Assemble the array class name */
482     namelen = component->name->blength;
483     
484     if (component->name->text[0] == '[') {
485         /* the component is itself an array */
486         namebuf = DMNEW(char, namelen + 1);
487         namebuf[0] = '[';
488         MCOPY(namebuf + 1, component->name->text, char, namelen);
489         namelen++;
490
491     } else {
492         /* the component is a non-array class */
493         namebuf = DMNEW(char, namelen + 3);
494         namebuf[0] = '[';
495         namebuf[1] = 'L';
496         MCOPY(namebuf + 2, component->name->text, char, namelen);
497         namebuf[2 + namelen] = ';';
498         namelen += 3;
499     }
500
501         c = class_new(utf_new(namebuf, namelen));
502
503         /* load this class ;-) and link it */
504
505         if (!c->loaded)
506                 c->loaded = true;
507
508         if (!c->linked)
509                 if (!class_link(c))
510                         return NULL;
511
512     return c;
513 }
514
515
516 /* class_multiarray_of *********************************************************
517
518    Returns an array class with the given dimension and element class.
519    The array class is dynamically created if neccessary.
520
521 *******************************************************************************/
522
523 classinfo *class_multiarray_of(s4 dim, classinfo *element)
524 {
525     s4 namelen;
526     char *namebuf;
527
528         if (dim < 1)
529                 panic("Invalid array dimension requested");
530
531     /* Assemble the array class name */
532     namelen = element->name->blength;
533     
534     if (element->name->text[0] == '[') {
535         /* the element is itself an array */
536         namebuf = DMNEW(char, namelen + dim);
537         memcpy(namebuf + dim, element->name->text, namelen);
538         namelen += dim;
539     }
540     else {
541         /* the element is a non-array class */
542         namebuf = DMNEW(char, namelen + 2 + dim);
543         namebuf[dim] = 'L';
544         memcpy(namebuf + dim + 1, element->name->text, namelen);
545         namelen += (2 + dim);
546         namebuf[namelen - 1] = ';';
547     }
548         memset(namebuf, '[', dim);
549
550     return class_new(utf_new(namebuf, namelen));
551 }
552
553
554 /*
555  * These are local overrides for various environment variables in Emacs.
556  * Please do not remove this and leave it at the end of the file, where
557  * Emacs will automagically detect them.
558  * ---------------------------------------------------------------------
559  * Local variables:
560  * mode: c
561  * indent-tabs-mode: t
562  * c-basic-offset: 4
563  * tab-width: 4
564  * End:
565  */