1 /* vm/classcache.c - loaded class cache and loading constraints
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Edwin Steiner
31 $Id: classcache.c 2195 2005-04-03 16:53:16Z edwin $
36 #include "vm/classcache.h"
38 #include "vm/tables.h"
39 #include "vm/exceptions.h"
40 #include "mm/memory.h"
42 /* initial number of slots in the classcache hash table */
43 #define CLASSCACHE_INIT_SIZE 2048
45 /*============================================================================*/
47 /*============================================================================*/
49 /*#define CLASSCACHE_VERBOSE*/
52 #define CLASSCACHE_DEBUG
55 #ifdef CLASSCACHE_DEBUG
56 #define CLASSCACHE_ASSERT(cond) assert(cond)
58 #define CLASSCACHE_ASSERT(cond)
61 /*============================================================================*/
62 /* THREAD-SAFE LOCKING */
63 /*============================================================================*/
65 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
66 /* CAUTION: The static functions below are */
67 /* NOT synchronized! */
68 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
70 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
71 # define CLASSCACHE_LOCK() tables_lock()
72 # define CLASSCACHE_UNLOCK() tables_unlock()
74 # define CLASSCACHE_LOCK()
75 # define CLASSCACHE_UNLOCK()
78 /*============================================================================*/
79 /* GLOBAL VARIABLES */
80 /*============================================================================*/
82 hashtable classcache_hash;
84 /*============================================================================*/
86 /*============================================================================*/
88 /* classcache_init *************************************************************
90 Initialize the loaded class cache
92 Note: NOT synchronized!
94 *******************************************************************************/
99 init_hashtable(&classcache_hash,CLASSCACHE_INIT_SIZE);
102 /* classcache_new_loader_entry *************************************************
104 Create a new classcache_loader_entry struct
105 (internally used helper function)
108 loader...........the ClassLoader object
109 next.............the next classcache_loader_entry
112 the new classcache_loader_entry
114 *******************************************************************************/
116 static classcache_loader_entry *
117 classcache_new_loader_entry(classloader *loader,classcache_loader_entry *next)
119 classcache_loader_entry *lden;
121 lden = NEW(classcache_loader_entry);
122 lden->loader = loader;
128 /* classcache_merge_loaders ****************************************************
130 Merge two lists of loaders into one
131 (internally used helper function)
134 lista............first list (may be NULL)
135 listb............second list (may be NULL)
138 the merged list (may be NULL)
141 The lists given as arguments are destroyed!
143 *******************************************************************************/
145 static classcache_loader_entry *
146 classcache_merge_loaders(classcache_loader_entry *lista,
147 classcache_loader_entry *listb)
149 classcache_loader_entry *result;
150 classcache_loader_entry *ldenA;
151 classcache_loader_entry *ldenB;
152 classcache_loader_entry **chain;
154 /* XXX This is a quadratic algorithm. If this ever
155 * becomes a problem, the loader lists should be
156 * stored as sorted lists and merged in linear time. */
161 for (ldenA=lista; ldenA; ldenA=ldenA->next) {
163 for (ldenB=listb; ldenB; ldenB=ldenB->next) {
164 if (ldenB->loader == ldenA->loader)
168 /* this loader is only in lista */
170 chain = &(ldenA->next);
173 /* XXX free the duplicated element */
177 /* concat listb to the result */
183 /* classcache_lookup_name ******************************************************
185 Lookup a name in the first level of the cache
186 (internally used helper function)
189 name.............the name to look up
192 a pointer to the classcache_name_entry for this name, or
193 null if no entry was found.
195 *******************************************************************************/
197 static classcache_name_entry *
198 classcache_lookup_name(utf *name)
200 classcache_name_entry * c; /* hash table element */
201 u4 key; /* hashkey computed from classname */
202 u4 slot; /* slot in hashtable */
205 key = utf_hashkey(name->text, name->blength);
206 slot = key & (classcache_hash.size - 1);
207 c = classcache_hash.ptr[slot];
209 /* search external hash chain for the entry */
211 if (c->name->blength == name->blength) {
212 for (i = 0; i < name->blength; i++)
213 if (name->text[i] != c->name->text[i]) goto nomatch;
215 /* entry found in hashtable */
220 c = c->hashlink; /* next element in external chain */
227 /* classcache_new_name *********************************************************
229 Return a classcache_name_entry for the given name. The entry is created
230 if it is not already in the cache.
231 (internally used helper function)
234 name.............the name to look up / create an entry for
237 a pointer to the classcache_name_entry for this name
239 *******************************************************************************/
241 static classcache_name_entry *
242 classcache_new_name(utf *name)
244 classcache_name_entry * c; /* hash table element */
245 u4 key; /* hashkey computed from classname */
246 u4 slot; /* slot in hashtable */
249 key = utf_hashkey(name->text, name->blength);
250 slot = key & (classcache_hash.size - 1);
251 c = classcache_hash.ptr[slot];
253 /* search external hash chain for the entry */
255 if (c->name->blength == name->blength) {
256 for (i = 0; i < name->blength; i++)
257 if (name->text[i] != c->name->text[i]) goto nomatch;
259 /* entry found in hashtable */
264 c = c->hashlink; /* next element in external chain */
267 /* location in hashtable found, create new entry */
269 c = NEW(classcache_name_entry);
274 /* insert entry into hashtable */
275 c->hashlink = classcache_hash.ptr[slot];
276 classcache_hash.ptr[slot] = c;
278 /* update number of hashtable-entries */
279 classcache_hash.entries++;
281 if (classcache_hash.entries > (classcache_hash.size * 2)) {
283 /* reorganization of hashtable, average length of
284 the external chains is approx. 2 */
287 classcache_name_entry *c;
288 hashtable newhash; /* the new hashtable */
290 /* create new hashtable, double the size */
291 init_hashtable(&newhash, classcache_hash.size * 2);
292 newhash.entries = classcache_hash.entries;
294 /* transfer elements to new hashtable */
295 for (i = 0; i < classcache_hash.size; i++) {
296 c = (classcache_name_entry *) classcache_hash.ptr[i];
298 classcache_name_entry *nextc = c->hashlink;
299 u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
301 c->hashlink = newhash.ptr[slot];
302 newhash.ptr[slot] = c;
308 /* dispose old table */
309 MFREE(classcache_hash.ptr, void*, classcache_hash.size);
310 classcache_hash = newhash;
316 /* classcache_lookup ***********************************************************
318 Lookup a possibly loaded class
321 initloader.......initiating loader for resolving the class name
322 classname........class name to look up
325 The return value is a pointer to the cached class object,
326 or NULL, if the class is not in the cache.
328 Note: synchronized with global tablelock
330 *******************************************************************************/
333 classcache_lookup(classloader *initloader,utf *classname)
335 classcache_name_entry *en;
336 classcache_class_entry *clsen;
337 classcache_loader_entry *lden;
338 classinfo *cls = NULL;
342 en = classcache_lookup_name(classname);
345 /* iterate over all class entries */
346 for (clsen=en->classes; clsen; clsen=clsen->next) {
347 /* check if this entry has been loaded by initloader */
348 for (lden=clsen->loaders; lden; lden=lden->next) {
349 if (lden->loader == initloader) {
350 /* found the loaded class entry */
351 CLASSCACHE_ASSERT(clsen->classobj);
352 cls = clsen->classobj;
363 /* classcache_lookup_defined ***************************************************
365 Lookup a class with the given name and defining loader
368 defloader........defining loader
369 classname........class name
372 The return value is a pointer to the cached class object,
373 or NULL, if the class is not in the cache.
375 *******************************************************************************/
378 classcache_lookup_defined(classloader *defloader,utf *classname)
380 classcache_name_entry *en;
381 classcache_class_entry *clsen;
382 classcache_loader_entry *lden;
383 classinfo *cls = NULL;
387 en = classcache_lookup_name(classname);
390 /* iterate over all class entries */
391 for (clsen=en->classes; clsen; clsen=clsen->next) {
392 if (!clsen->classobj)
395 /* check if this entry has been defined by defloader */
396 if (clsen->classobj->classloader == defloader) {
397 cls = clsen->classobj;
407 /* classcache_store ************************************************************
412 initloader.......initiating loader used to load the class
413 cls..............class object to cache
416 true.............everything ok, the class was stored in
417 the cache if necessary,
418 false............an exception has been thrown.
420 Note: synchronized with global tablelock
422 *******************************************************************************/
425 classcache_store(classloader *initloader,classinfo *cls)
427 classcache_name_entry *en;
428 classcache_class_entry *clsen;
429 classcache_loader_entry *lden;
431 CLASSCACHE_ASSERT(cls);
432 CLASSCACHE_ASSERT(cls->loaded);
434 #ifdef CLASSCACHE_VERBOSE
435 fprintf(stderr,"classcache_store(%p,",initloader);
436 utf_fprint_classname(stderr,cls->name);
437 fprintf(stderr,")\n");
442 en = classcache_new_name(cls->name);
444 CLASSCACHE_ASSERT(en);
446 /* iterate over all class entries */
447 for (clsen=en->classes; clsen; clsen=clsen->next) {
449 #ifdef CLASSCACHE_DEBUG
450 /* check if this entry has already been loaded by initloader */
451 /* It never should have been loaded before! */
452 for (lden=clsen->loaders; lden; lden=lden->next) {
453 if (lden->loader == initloader)
454 CLASSCACHE_ASSERT(false);
458 /* check if initloader is constrained to this entry */
459 for (lden=clsen->constraints; lden; lden=lden->next) {
460 if (lden->loader == initloader) {
461 /* we have to use this entry */
462 /* check if is has already been resolved to another class */
463 if (clsen->classobj && clsen->classobj != cls) {
464 /* a loading constraint is violated */
465 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
466 "loading constraint violated XXX add message");
467 goto return_exception;
470 /* record initloader as initiating loader */
471 clsen->loaders = classcache_new_loader_entry(initloader,clsen->loaders);
473 /* record the loaded class object */
474 clsen->classobj = cls;
483 /* create a new class entry for this class object with */
484 /* initiating loader initloader */
486 clsen = NEW(classcache_class_entry);
487 clsen->classobj = cls;
488 clsen->loaders = classcache_new_loader_entry(initloader,NULL);
489 clsen->constraints = NULL;
491 clsen->next = en->classes;
500 return false; /* exception */
503 /* classcache_find_loader ******************************************************
505 Find the class entry loaded by or constrained to a given loader
506 (internally used helper function)
509 entry............the classcache_name_entry
510 loader...........the loader to look for
513 the classcache_class_entry for the given loader, or
514 NULL if no entry was found
516 *******************************************************************************/
518 static classcache_class_entry *
519 classcache_find_loader(classcache_name_entry *entry,classloader *loader)
521 classcache_class_entry *clsen;
522 classcache_loader_entry *lden;
524 CLASSCACHE_ASSERT(entry);
526 /* iterate over all class entries */
527 for (clsen=entry->classes; clsen; clsen=clsen->next) {
529 /* check if this entry has already been loaded by initloader */
530 for (lden=clsen->loaders; lden; lden=lden->next) {
531 if (lden->loader == loader)
532 return clsen; /* found */
535 /* check if loader is constrained to this entry */
536 for (lden=clsen->constraints; lden; lden=lden->next) {
537 if (lden->loader == loader)
538 return clsen; /* found */
546 /* classcache_free_class_entry *************************************************
548 Free the memory used by a class entry
551 clsen............the classcache_class_entry to free
553 *******************************************************************************/
556 classcache_free_class_entry(classcache_class_entry *clsen)
558 classcache_loader_entry *lden;
559 classcache_loader_entry *next;
561 CLASSCACHE_ASSERT(clsen);
563 for (lden=clsen->loaders; lden; lden=next) {
565 FREE(lden,classcache_loader_entry);
567 for (lden=clsen->constraints; lden; lden=next) {
569 FREE(lden,classcache_loader_entry);
572 FREE(clsen,classcache_class_entry);
575 /* classcache_remove_class_entry ***********************************************
577 Remove a classcache_class_entry from the list of possible resolution of
579 (internally used helper function)
582 entry............the classcache_name_entry
583 clsen............the classcache_class_entry to remove
585 *******************************************************************************/
588 classcache_remove_class_entry(classcache_name_entry *entry,
589 classcache_class_entry *clsen)
591 classcache_class_entry **chain;
593 CLASSCACHE_ASSERT(entry);
594 CLASSCACHE_ASSERT(clsen);
596 chain = &(entry->classes);
598 if (*chain == clsen) {
599 *chain = clsen->next;
600 classcache_free_class_entry(clsen);
603 chain = &((*chain)->next);
607 /* classcache_free_name_entry **************************************************
609 Free the memory used by a name entry
612 entry............the classcache_name_entry to free
614 *******************************************************************************/
617 classcache_free_name_entry(classcache_name_entry *entry)
619 classcache_class_entry *clsen;
620 classcache_class_entry *next;
622 CLASSCACHE_ASSERT(entry);
624 for (clsen=entry->classes; clsen; clsen=next) {
626 classcache_free_class_entry(clsen);
629 FREE(entry,classcache_name_entry);
632 /* classcache_free *************************************************************
634 Free the memory used by the class cache
637 The class cache may not be used any more after this call, except
638 when it is reinitialized with classcache_init.
640 Note: NOT synchronized!
642 *******************************************************************************/
648 classcache_name_entry *entry;
649 classcache_name_entry *next;
651 for (slot=0; slot<classcache_hash.size; ++slot) {
652 for (entry=(classcache_name_entry *)classcache_hash.ptr[slot];
656 next = entry->hashlink;
657 classcache_free_name_entry(entry);
661 MFREE(classcache_hash.ptr,voidptr,classcache_hash.size);
662 classcache_hash.size = 0;
663 classcache_hash.entries = 0;
664 classcache_hash.ptr = NULL;
667 /* classcache_add_constraint ***************************************************
669 Add a loading constraint
672 a................first initiating loader
673 b................second initiating loader
674 classname........class name
677 true.............everything ok, the constraint has been added,
678 false............an exception has been thrown.
680 Note: synchronized with global tablelock
682 *******************************************************************************/
685 classcache_add_constraint(classloader *a,classloader *b,utf *classname)
687 classcache_name_entry *en;
688 classcache_class_entry *clsenA;
689 classcache_class_entry *clsenB;
691 CLASSCACHE_ASSERT(classname);
693 #ifdef CLASSCACHE_VERBOSE
694 fprintf(stderr,"classcache_add_constraint(%p,%p,",(void*)a,(void*)b);
695 utf_fprint_classname(stderr,classname);
696 fprintf(stderr,")\n");
699 /* a constraint with a == b is trivially satisfied */
705 en = classcache_new_name(classname);
707 CLASSCACHE_ASSERT(en);
709 /* find the entry loaded by / constrained to each loader */
710 clsenA = classcache_find_loader(en,a);
711 clsenB = classcache_find_loader(en,b);
713 if (clsenA && clsenB) {
714 /* { both loaders have corresponding entries } */
716 /* if the entries are the same, the constraint is already recorded */
717 if (clsenA == clsenB)
720 /* check if the entries can be merged */
721 if (clsenA->classobj && clsenB->classobj && clsenA->classobj != clsenB->classobj) {
722 /* no, the constraint is violated */
723 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
724 "loading constraint violated XXX add message");
725 goto return_exception;
728 /* yes, merge the entries */
729 /* clsenB will be merged into clsenA */
730 clsenA->loaders = classcache_merge_loaders(clsenA->loaders,
733 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
734 clsenB->constraints);
736 if (!clsenA->classobj)
737 clsenA->classobj = clsenB->classobj;
739 /* remove clsenB from the list of class entries */
740 classcache_remove_class_entry(en,clsenB);
743 /* { at most one of the loaders has a corresponding entry } */
745 /* set clsenA to the single class entry we have */
750 /* { no loader has a corresponding entry } */
752 /* create a new class entry with the constraint (a,b,en->name) */
753 clsenA = NEW(classcache_class_entry);
754 clsenA->classobj = NULL;
755 clsenA->loaders = NULL;
756 clsenA->constraints = classcache_new_loader_entry(b,NULL);
757 clsenA->constraints = classcache_new_loader_entry(a,clsenA->constraints);
759 clsenA->next = en->classes;
760 en->classes = clsenA;
763 /* make b the loader that has no corresponding entry */
767 /* loader b must be added to entry clsenA */
768 clsenA->constraints = classcache_new_loader_entry(b,clsenA->constraints);
778 return false; /* exception */
781 /*============================================================================*/
783 /*============================================================================*/
785 /* classcache_debug_dump *******************************************************
787 Print the contents of the loaded class cache to a stream
790 file.............output stream
792 Note: synchronized with global tablelock
794 *******************************************************************************/
797 classcache_debug_dump(FILE *file)
799 classcache_name_entry *c;
800 classcache_class_entry *clsen;
801 classcache_loader_entry *lden;
806 fprintf(file,"\n=== [loaded class cache] =====================================\n\n");
807 fprintf(file,"hash size : %d\n",classcache_hash.size);
808 fprintf(file,"hash entries: %d\n",classcache_hash.entries);
811 for (slot=0; slot<classcache_hash.size; ++slot) {
812 c = (classcache_name_entry *) classcache_hash.ptr[slot];
814 for (; c; c=c->hashlink) {
815 utf_fprint_classname(file,c->name);
818 /* iterate over all class entries */
819 for (clsen=c->classes; clsen; clsen=clsen->next) {
820 fprintf(file," %s\n",(clsen->classobj) ? "loaded" : "unresolved");
821 fprintf(file," loaders:");
822 for (lden=clsen->loaders; lden; lden=lden->next) {
823 fprintf(file," %p",(void *)lden->loader);
825 fprintf(file,"\n constraints:");
826 for (lden=clsen->constraints; lden; lden=lden->next) {
827 fprintf(file," %p",(void *)lden->loader);
833 fprintf(file,"\n==============================================================\n\n");
839 * These are local overrides for various environment variables in Emacs.
840 * Please do not remove this and leave it at the end of the file, where
841 * Emacs will automagically detect them.
842 * ---------------------------------------------------------------------
845 * indent-tabs-mode: t
849 * vim:noexpandtab:sw=4:ts=4: