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 2309 2005-04-15 14:29:04Z 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 *******************************************************************************/
100 init_hashtable(&classcache_hash, CLASSCACHE_INIT_SIZE);
103 /* classcache_new_loader_entry *************************************************
105 Create a new classcache_loader_entry struct
106 (internally used helper function)
109 loader...........the ClassLoader object
110 next.............the next classcache_loader_entry
113 the new classcache_loader_entry
115 *******************************************************************************/
117 static classcache_loader_entry *
118 classcache_new_loader_entry(
119 /*@shared@*/ /*@null@*/ classloader * loader,
120 /*@only @*/ /*@null@*/ classcache_loader_entry * next)
122 classcache_loader_entry *lden;
124 lden = NEW(classcache_loader_entry);
125 lden->loader = loader;
131 /* classcache_merge_loaders ****************************************************
133 Merge two lists of loaders into one
134 (internally used helper function)
137 lista............first list (may be NULL)
138 listb............second list (may be NULL)
141 the merged list (may be NULL)
144 The lists given as arguments are destroyed!
146 *******************************************************************************/
148 static /*@null@*/ classcache_loader_entry *
149 classcache_merge_loaders(
150 /*@null@*/ classcache_loader_entry * lista,
151 /*@null@*/ classcache_loader_entry * listb)
153 classcache_loader_entry *result;
154 classcache_loader_entry *ldenA;
155 classcache_loader_entry *ldenB;
156 classcache_loader_entry **chain;
158 /* XXX This is a quadratic algorithm. If this ever
159 * becomes a problem, the loader lists should be
160 * stored as sorted lists and merged in linear time. */
165 for (ldenA = lista; ldenA != NULL; ldenA = ldenA->next) {
167 for (ldenB = listb; ldenB != NULL; ldenB = ldenB->next) {
168 if (ldenB->loader == ldenA->loader)
172 /* this loader is only in lista */
174 chain = &(ldenA->next);
177 /* XXX free the duplicated element */
181 /* concat listb to the result */
187 /* classcache_lookup_name ******************************************************
189 Lookup a name in the first level of the cache
190 (internally used helper function)
193 name.............the name to look up
196 a pointer to the classcache_name_entry for this name, or
197 null if no entry was found.
199 *******************************************************************************/
201 static /*@exposed@*/ /*@null@*/ classcache_name_entry *
202 classcache_lookup_name(
203 /*@shared@*/ utf * name)
205 classcache_name_entry *c; /* hash table element */
206 u4 key; /* hashkey computed from classname */
207 u4 slot; /* slot in hashtable */
210 key = utf_hashkey(name->text, (u4) name->blength);
211 slot = key & (classcache_hash.size - 1);
212 c = classcache_hash.ptr[slot];
214 /* search external hash chain for the entry */
216 if (c->name->blength == name->blength) {
217 for (i = 0; i < (u4) name->blength; i++)
218 if (name->text[i] != c->name->text[i])
221 /* entry found in hashtable */
226 c = c->hashlink; /* next element in external chain */
233 /* classcache_new_name *********************************************************
235 Return a classcache_name_entry for the given name. The entry is created
236 if it is not already in the cache.
237 (internally used helper function)
240 name.............the name to look up / create an entry for
243 a pointer to the classcache_name_entry for this name
245 *******************************************************************************/
247 static /*@exposed@*/ classcache_name_entry *
249 /*@shared@*/ utf * name)
251 classcache_name_entry *c; /* hash table element */
252 u4 key; /* hashkey computed from classname */
253 u4 slot; /* slot in hashtable */
256 key = utf_hashkey(name->text, (u4) name->blength);
257 slot = key & (classcache_hash.size - 1);
258 c = classcache_hash.ptr[slot];
260 /* search external hash chain for the entry */
262 if (c->name->blength == name->blength) {
263 for (i = 0; i < (u4) name->blength; i++)
264 if (name->text[i] != c->name->text[i])
267 /* entry found in hashtable */
272 c = c->hashlink; /* next element in external chain */
275 /* location in hashtable found, create new entry */
277 c = NEW(classcache_name_entry);
282 /* insert entry into hashtable */
283 c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
284 classcache_hash.ptr[slot] = c;
286 /* update number of hashtable-entries */
287 classcache_hash.entries++;
289 if (classcache_hash.entries > (classcache_hash.size * 2)) {
291 /* reorganization of hashtable, average length of
292 the external chains is approx. 2 */
294 classcache_name_entry *c2;
295 hashtable newhash; /* the new hashtable */
297 /* create new hashtable, double the size */
298 init_hashtable(&newhash, classcache_hash.size * 2);
299 newhash.entries = classcache_hash.entries;
301 /* transfer elements to new hashtable */
302 for (i = 0; i < classcache_hash.size; i++) {
303 c2 = (classcache_name_entry *) classcache_hash.ptr[i];
305 classcache_name_entry *nextc = c2->hashlink;
307 (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
309 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
310 newhash.ptr[newslot] = c2;
316 /* dispose old table */
317 MFREE(classcache_hash.ptr, void *,
318 classcache_hash.size);
319 classcache_hash = newhash;
325 /* classcache_lookup ***********************************************************
327 Lookup a possibly loaded class
330 initloader.......initiating loader for resolving the class name
331 classname........class name to look up
334 The return value is a pointer to the cached class object,
335 or NULL, if the class is not in the cache.
337 Note: synchronized with global tablelock
339 *******************************************************************************/
341 /*@null@*/ classinfo *
343 /*@shared@*/ classloader * initloader,
344 /*@shared@*/ utf * classname)
346 classcache_name_entry *en;
347 classcache_class_entry *clsen;
348 classcache_loader_entry *lden;
349 classinfo *cls = NULL;
353 en = classcache_lookup_name(classname);
356 /* iterate over all class entries */
357 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
358 /* check if this entry has been loaded by initloader */
359 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
360 if (lden->loader == initloader) {
361 /* found the loaded class entry */
362 CLASSCACHE_ASSERT(clsen->classobj != NULL);
363 cls = clsen->classobj;
374 /* classcache_lookup_defined ***************************************************
376 Lookup a class with the given name and defining loader
379 defloader........defining loader
380 classname........class name
383 The return value is a pointer to the cached class object,
384 or NULL, if the class is not in the cache.
386 *******************************************************************************/
388 /*@null@*/ classinfo *
389 classcache_lookup_defined(
390 /*@shared@*/ classloader * defloader,
391 /*@shared@*/ utf * classname)
393 classcache_name_entry *en;
394 classcache_class_entry *clsen;
395 classinfo *cls = NULL;
399 en = classcache_lookup_name(classname);
402 /* iterate over all class entries */
403 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
404 if (!clsen->classobj)
407 /* check if this entry has been defined by defloader */
408 if (clsen->classobj->classloader == defloader) {
409 cls = clsen->classobj;
419 /* classcache_store ************************************************************
424 initloader.......initiating loader used to load the class
425 cls..............class object to cache
428 true.............everything ok, the class was stored in
429 the cache if necessary,
430 false............an exception has been thrown.
432 Note: synchronized with global tablelock
434 *******************************************************************************/
438 /*@shared@*/ /*@null@*/ classloader * initloader,
439 /*@shared@*/ classinfo * cls)
441 classcache_name_entry *en;
442 classcache_class_entry *clsen;
443 classcache_loader_entry *lden;
445 CLASSCACHE_ASSERT(cls != NULL);
446 CLASSCACHE_ASSERT(cls->loaded != NULL);
448 #ifdef CLASSCACHE_VERBOSE
449 fprintf(stderr, "classcache_store(%p,", initloader);
450 utf_fprint_classname(stderr, cls->name);
451 fprintf(stderr, ")\n");
456 en = classcache_new_name(cls->name);
458 CLASSCACHE_ASSERT(en != NULL);
460 /* iterate over all class entries */
461 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
463 #ifdef CLASSCACHE_DEBUG
464 /* check if this entry has already been loaded by initloader */
465 /* It never should have been loaded before! */
466 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
467 if (lden->loader == initloader)
468 CLASSCACHE_ASSERT(false);
472 /* check if initloader is constrained to this entry */
473 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
474 if (lden->loader == initloader) {
475 /* we have to use this entry */
476 /* check if is has already been resolved to another class */
477 if (clsen->classobj != NULL && clsen->classobj != cls) {
478 /* a loading constraint is violated */
479 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
480 "loading constraint violated XXX add message");
481 goto return_exception;
484 /* record initloader as initiating loader */
485 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
487 /* record the loaded class object */
488 clsen->classobj = cls;
497 /* create a new class entry for this class object with */
498 /* initiating loader initloader */
500 clsen = NEW(classcache_class_entry);
501 clsen->classobj = cls;
502 clsen->loaders = classcache_new_loader_entry(initloader, NULL);
503 clsen->constraints = NULL;
505 clsen->next = en->classes;
514 return false; /* exception */
517 /* classcache_find_loader ******************************************************
519 Find the class entry loaded by or constrained to a given loader
520 (internally used helper function)
523 entry............the classcache_name_entry
524 loader...........the loader to look for
527 the classcache_class_entry for the given loader, or
528 NULL if no entry was found
530 *******************************************************************************/
532 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
533 classcache_find_loader(
534 classcache_name_entry * entry,
535 /*@shared@*/ /*@null@*/ classloader * loader)
537 classcache_class_entry *clsen;
538 classcache_loader_entry *lden;
540 CLASSCACHE_ASSERT(entry != NULL);
542 /* iterate over all class entries */
543 for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
545 /* check if this entry has already been loaded by initloader */
546 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
547 if (lden->loader == loader)
548 return clsen; /* found */
551 /* check if loader is constrained to this entry */
552 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
553 if (lden->loader == loader)
554 return clsen; /* found */
562 /* classcache_free_class_entry *************************************************
564 Free the memory used by a class entry
567 clsen............the classcache_class_entry to free
569 *******************************************************************************/
572 classcache_free_class_entry(
573 classcache_class_entry * clsen)
575 classcache_loader_entry *lden;
576 classcache_loader_entry *next;
578 CLASSCACHE_ASSERT(clsen != NULL);
580 for (lden = clsen->loaders; lden != NULL; lden = next) {
582 FREE(lden, classcache_loader_entry);
584 for (lden = clsen->constraints; lden != NULL; lden = next) {
586 FREE(lden, classcache_loader_entry);
589 FREE(clsen, classcache_class_entry);
592 /* classcache_remove_class_entry ***********************************************
594 Remove a classcache_class_entry from the list of possible resolution of
596 (internally used helper function)
599 entry............the classcache_name_entry
600 clsen............the classcache_class_entry to remove
602 *******************************************************************************/
605 classcache_remove_class_entry(
606 classcache_name_entry * entry,
607 classcache_class_entry * clsen)
609 classcache_class_entry **chain;
611 CLASSCACHE_ASSERT(entry != NULL);
612 CLASSCACHE_ASSERT(clsen != NULL);
614 chain = &(entry->classes);
616 if (*chain == clsen) {
617 *chain = clsen->next;
618 classcache_free_class_entry(clsen);
621 chain = &((*chain)->next);
625 /* classcache_free_name_entry **************************************************
627 Free the memory used by a name entry
630 entry............the classcache_name_entry to free
632 *******************************************************************************/
635 classcache_free_name_entry(
636 classcache_name_entry * entry)
638 classcache_class_entry *clsen;
639 classcache_class_entry *next;
641 CLASSCACHE_ASSERT(entry != NULL);
643 for (clsen = entry->classes; clsen; clsen = next) {
645 classcache_free_class_entry(clsen);
648 FREE(entry, classcache_name_entry);
651 /* classcache_free *************************************************************
653 Free the memory used by the class cache
656 The class cache may not be used any more after this call, except
657 when it is reinitialized with classcache_init.
659 Note: NOT synchronized!
661 *******************************************************************************/
666 /*@globals killed classcache_hash@*/
669 classcache_name_entry *entry;
670 classcache_name_entry *next;
672 for (slot = 0; slot < classcache_hash.size; ++slot) {
673 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
674 next = entry->hashlink;
675 classcache_free_name_entry(entry);
679 MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
680 classcache_hash.size = 0;
681 classcache_hash.entries = 0;
682 classcache_hash.ptr = NULL;
685 /* classcache_add_constraint ***************************************************
687 Add a loading constraint
690 a................first initiating loader
691 b................second initiating loader
692 classname........class name
695 true.............everything ok, the constraint has been added,
696 false............an exception has been thrown.
698 Note: synchronized with global tablelock
700 *******************************************************************************/
703 classcache_add_constraint(
704 /*@shared@*/ /*@null@*/ classloader * a,
705 /*@shared@*/ /*@null@*/ classloader * b,
706 /*@shared@*/ utf * classname)
708 classcache_name_entry *en;
709 classcache_class_entry *clsenA;
710 classcache_class_entry *clsenB;
712 CLASSCACHE_ASSERT(classname != NULL);
714 #ifdef CLASSCACHE_VERBOSE
715 fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
716 utf_fprint_classname(stderr, classname);
717 fprintf(stderr, ")\n");
720 /* a constraint with a == b is trivially satisfied */
726 en = classcache_new_name(classname);
728 CLASSCACHE_ASSERT(en != NULL);
730 /* find the entry loaded by / constrained to each loader */
731 clsenA = classcache_find_loader(en, a);
732 clsenB = classcache_find_loader(en, b);
734 if (clsenA != NULL && clsenB != NULL) {
735 /* { both loaders have corresponding entries } */
737 /* if the entries are the same, the constraint is already recorded */
738 if (clsenA == clsenB)
741 /* check if the entries can be merged */
742 if (clsenA->classobj != NULL && clsenB->classobj != NULL
743 && clsenA->classobj != clsenB->classobj) {
744 /* no, the constraint is violated */
745 *exceptionptr = new_exception_message(string_java_lang_LinkageError,
746 "loading constraint violated XXX add message");
747 goto return_exception;
750 /* yes, merge the entries */
751 /* clsenB will be merged into clsenA */
752 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
753 clsenB->loaders = NULL;
755 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
756 clsenB->constraints);
757 clsenB->constraints = NULL;
759 if (!clsenA->classobj)
760 clsenA->classobj = clsenB->classobj;
762 /* remove clsenB from the list of class entries */
763 classcache_remove_class_entry(en, clsenB);
766 /* { at most one of the loaders has a corresponding entry } */
768 /* set clsenA to the single class entry we have */
773 /* { no loader has a corresponding entry } */
775 /* create a new class entry with the constraint (a,b,en->name) */
776 clsenA = NEW(classcache_class_entry);
777 clsenA->classobj = NULL;
778 clsenA->loaders = NULL;
779 clsenA->constraints = classcache_new_loader_entry(b, NULL);
780 clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
782 clsenA->next = en->classes;
783 en->classes = clsenA;
786 /* make b the loader that has no corresponding entry */
790 /* loader b must be added to entry clsenA */
791 clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
801 return false; /* exception */
804 /*============================================================================*/
806 /*============================================================================*/
808 /* classcache_debug_dump *******************************************************
810 Print the contents of the loaded class cache to a stream
813 file.............output stream
815 Note: synchronized with global tablelock
817 *******************************************************************************/
820 classcache_debug_dump(
821 /*@shared@*/ FILE * file)
823 classcache_name_entry *c;
824 classcache_class_entry *clsen;
825 classcache_loader_entry *lden;
830 fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
831 fprintf(file, "hash size : %d\n", (int) classcache_hash.size);
832 fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
835 for (slot = 0; slot < classcache_hash.size; ++slot) {
836 c = (classcache_name_entry *) classcache_hash.ptr[slot];
838 for (; c != NULL; c = c->hashlink) {
839 utf_fprint_classname(file, c->name);
842 /* iterate over all class entries */
843 for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
844 if (clsen->classobj) {
845 fprintf(file, " loaded %p\n", (void *) clsen->classobj);
848 fprintf(file, " unresolved\n");
850 fprintf(file, " loaders:");
851 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
852 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
854 fprintf(file, "\n constraints:");
855 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
856 fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
862 fprintf(file, "\n==============================================================\n\n");
868 * These are local overrides for various environment variables in Emacs.
869 * Please do not remove this and leave it at the end of the file, where
870 * Emacs will automagically detect them.
871 * ---------------------------------------------------------------------
874 * indent-tabs-mode: t
878 * vim:noexpandtab:sw=4:ts=4: