* src/threads/posix/lock.c: Moved to .cpp.
[cacao.git] / src / vm / classcache.c
index 60159aaedec73e5829810ba237b57992f6f19e03..6324f2a78787e0c012d30eab9b0109a0109481ca 100644 (file)
@@ -1,9 +1,7 @@
-/* vm/classcache.c - loaded class cache and loading constraints
+/* src/vm/classcache.c - loaded class cache and loading constraints
 
-   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+*/
 
-   Authors: Edwin Steiner
 
-   Changes:
+#include "config.h"
 
-   $Id: classcache.c 2241 2005-04-06 15:07:46Z edwin $
+#include <assert.h>
 
-*/
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "threads/lock.hpp"
+#include "threads/mutex.hpp"
+
+#include "toolbox/hashtable.h"
+#include "toolbox/logging.h"
 
-#include <assert.h>
 #include "vm/classcache.h"
+#include "vm/exceptions.hpp"
+#include "vm/options.h"
 #include "vm/utf8.h"
-#include "vm/tables.h"
-#include "vm/exceptions.h"
-#include "mm/memory.h"
+
+
+/*************************************************************************
+
+  Class Cache
+
+  The classcache has two functions:
+  
+       1) caching the resolution of class references
+       2) storing and checking loading constraints
+
+  We will use the following terms in this description:
+
+       N          a class name: a utf string
+       (N,L)      a class reference with initiating loader L and class name N
+       C          a class (object): the result of resolving a reference (N,L)
+               We will write resultion as
+                               C = *(N,L)
+       (N,L1,L2)  a loading constraint indicating that (N,L1) and (N,L2) must
+                  resolve to the same class C. So (N,L1,L2) means
+                               *(N,L1) = *(N,L2)
+
+  The functions of the classcache require:
+
+    1) a mapping (N,L) |--> C for looking up prior resolution results.
+       2) storing the current set of loading constraints { (N,L1,L2) }
+
+  These functions can be rearranged like that:
+
+    a mapping N |--> (a mapping L |--> C or NULL, 
+                         a set of constraints {(L1,L2)})
+
+  Thus we can treat the mapping and constraints for each name N
+  separately. The implementation does this by keeping a hash table
+  mapping a name N to a `classcache_name_entry` which contains all
+  info with respect to N.
+
+  For a class name N we can define an equivalence relation ~N~ on
+  class loaders:
+
+       L1 ~N~ L2  <==>  *(N,L1) = *(N,L2)
+
+  A loading constraint (N,L1,L2) implies L1 ~N~ L2.
+
+  Also, if two references (N,L1) and (N,L2) resolve to the same class C
+  we have L1 ~N~ L2 because class loaders are required to return
+  consistent resolutions for a name N [XXX].
+
+  A `classcache_name_entry` keeps a set of tuples { (Cx,IL,CL) },
+  where
+               Cx...is a class C or NULL
+               IL...is the set of initiating loaders
+               CL...is the set of constrained loaders
+               
+  Such a tuple is called `classcache_class_entry` in the source code.
+
+  The following holds for each tuple (Cx,IL,CL):
+
+    .  (Cx is NULL) implies IL = {}.
+          
+       .  If Cx is a class, IL is the set of loaders that have been
+          recorded as initiating loaders for Cx. IL may be the
+          empty set {} in case Cx has already been defined but no
+          initiating loader has been recorded, yet.
+  
+    .  (IL u CL) is a subset of an equivalence class of ~N~.
+
+                (This means that all loaders in IL and CL must resolve
+                the name N to the same class.)
+
+  The following holds for the set of tuples { (Cx,IL,CL) }:
+
+    .  For a given class C there is at most one tuple with Cx = C
+          in the set. (There may be an arbitrary number of tuples
+          with Cx = NULL, however.)
+
+       .  For a given loader L there is at most one tuple with
+          L in (IL u CL).
+
+  The implementation stores sets of loaders as linked lists of
+  `classcache_loader_entry`s.
+
+  Comments about manipulating the classcache can be found in the
+  individual functions below.
+*************************************************************************/
+
 
 /* initial number of slots in the classcache hash table */
 #define CLASSCACHE_INIT_SIZE  2048
 /* DEBUG HELPERS                                                              */
 /*============================================================================*/
 
-/*#define CLASSCACHE_VERBOSE*/
+/* #define CLASSCACHE_VERBOSE */
 
-#ifndef NDEBUG
-#define CLASSCACHE_DEBUG
-#endif
+/*============================================================================*/
+/* STATISTICS                                                                 */
+/*============================================================================*/
 
-#ifdef CLASSCACHE_DEBUG
-#define CLASSCACHE_ASSERT(cond)  assert(cond)
+/*#define CLASSCACHE_STATS*/
+
+#ifdef CLASSCACHE_STATS
+static int stat_classnames_stored = 0;
+static int stat_classes_stored = 0;
+static int stat_trivial_constraints = 0;
+static int stat_nontriv_constraints = 0;
+static int stat_nontriv_constraints_both = 0;
+static int stat_nontriv_constraints_merged = 0;
+static int stat_nontriv_constraints_one = 0;
+static int stat_nontriv_constraints_none = 0;
+static int stat_new_loader_entry = 0;
+static int stat_merge_class_entries = 0;
+static int stat_merge_loader_entries = 0;
+static int stat_lookup = 0;
+static int stat_lookup_class_entry_checked = 0;
+static int stat_lookup_loader_checked = 0;
+static int stat_lookup_name = 0;
+static int stat_lookup_name_entry = 0;
+static int stat_lookup_name_notfound = 0;
+static int stat_lookup_new_name = 0;
+static int stat_lookup_new_name_entry = 0;
+static int stat_lookup_new_name_collisions = 0;
+static int stat_rehash_names = 0;
+static int stat_rehash_names_collisions = 0;
+
+#define CLASSCACHE_COUNT(cnt)  (cnt)++
+#define CLASSCACHE_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
+
+void classcache_print_statistics(FILE *file) {
+       fprintf(file,"classnames stored   : %8d\n",stat_classnames_stored);
+       fprintf(file,"classes stored      : %8d\n",stat_classes_stored);
+       fprintf(file,"trivial constraints : %8d\n",stat_trivial_constraints);
+       fprintf(file,"non-triv constraints: %8d\n",stat_nontriv_constraints);
+       fprintf(file,"   both loaders rec.: %8d\n",stat_nontriv_constraints_both);
+       fprintf(file,"       merged       : %8d\n",stat_nontriv_constraints_merged);
+       fprintf(file,"   one loader rec.  : %8d\n",stat_nontriv_constraints_one);
+       fprintf(file,"   no loaders rec.  : %8d\n",stat_nontriv_constraints_none);
+       fprintf(file,"new loader entries  : %8d\n",stat_new_loader_entry);
+       fprintf(file,"merge class entries : %8d\n",stat_merge_class_entries);
+       fprintf(file,"merge loader entries: %8d\n",stat_merge_loader_entries);
+       fprintf(file,"lookups             : %8d\n",stat_lookup);
+       fprintf(file,"   class entries ckd: %8d\n",stat_lookup_class_entry_checked);
+       fprintf(file,"   loader checked   : %8d\n",stat_lookup_loader_checked);
+       fprintf(file,"lookup name         : %8d\n",stat_lookup_name);
+       fprintf(file,"   entries checked  : %8d\n",stat_lookup_name_entry);
+       fprintf(file,"   not found        : %8d\n",stat_lookup_name_notfound);
+       fprintf(file,"lookup (new) name   : %8d\n",stat_lookup_new_name);
+       fprintf(file,"   entries checked  : %8d\n",stat_lookup_new_name_entry);
+       fprintf(file,"   new collisions   : %8d\n",stat_lookup_new_name_collisions);
+       fprintf(file,"names rehashed      : %8d times\n",stat_rehash_names);
+       fprintf(file,"    collisions      : %8d\n",stat_rehash_names_collisions);
+}
 #else
-#define CLASSCACHE_ASSERT(cond)
+#define CLASSCACHE_COUNT(cnt)
+#define CLASSCACHE_COUNTIF(cond,cnt)
 #endif
 
 /*============================================================================*/
 /* THREAD-SAFE LOCKING                                                        */
 /*============================================================================*/
 
-    /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-    /* CAUTION: The static functions below are */
-    /*          NOT synchronized!              */
-    /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+       /* CAUTION: The static functions below are */
+       /*          NOT synchronized!              */
+       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-#  define CLASSCACHE_LOCK()    tables_lock()
-#  define CLASSCACHE_UNLOCK()  tables_unlock()
+#if defined(ENABLE_THREADS)
+# define CLASSCACHE_LOCK()      Mutex_lock(classcache_hashtable_mutex)
+# define CLASSCACHE_UNLOCK()    Mutex_unlock(classcache_hashtable_mutex)
 #else
-#  define CLASSCACHE_LOCK()
-#  define CLASSCACHE_UNLOCK()
+# define CLASSCACHE_LOCK()
+# define CLASSCACHE_UNLOCK()
 #endif
 
 /*============================================================================*/
 /* GLOBAL VARIABLES                                                           */
 /*============================================================================*/
 
-hashtable classcache_hash;
+hashtable hashtable_classcache;
+
+#if defined(ENABLE_THREADS)
+static Mutex *classcache_hashtable_mutex;
+#endif
+
 
 /*============================================================================*/
 /*                                                                            */
 /*============================================================================*/
 
+/* prototypes */
+
+static void classcache_free_class_entry(classcache_class_entry *clsen);
+static void classcache_remove_class_entry(classcache_name_entry *en,
+                                                                                 classcache_class_entry *clsen);
+
+/* hash function to use */
+
+#define CLASSCACHE_HASH utf_full_hashkey
+
 /* classcache_init *************************************************************
  
-   Initialize the loaded class cache
+   Initialize the class cache
 
    Note: NOT synchronized!
   
 *******************************************************************************/
 
-void 
-classcache_init()
+bool classcache_init(void)
 {
-       init_hashtable(&classcache_hash,CLASSCACHE_INIT_SIZE);
+       TRACESUBSYSTEMINITIALIZATION("classcache_init");
+
+       /* create the hashtable */
+
+       hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
+
+#if defined(ENABLE_THREADS)
+       /* create utf hashtable mutex */
+
+       classcache_hashtable_mutex = Mutex_new();
+#endif
+
+       /* everything's ok */
+
+       return true;
 }
 
 /* classcache_new_loader_entry *************************************************
@@ -113,14 +283,16 @@ classcache_init()
   
 *******************************************************************************/
 
-static classcache_loader_entry *
-classcache_new_loader_entry(classloader *loader,classcache_loader_entry *next)
+static classcache_loader_entry * classcache_new_loader_entry(
+                                                                       classloader_t * loader,
+                                                                       classcache_loader_entry * next)
 {
        classcache_loader_entry *lden;
 
        lden = NEW(classcache_loader_entry);
        lden->loader = loader;
        lden->next = next;
+       CLASSCACHE_COUNT(stat_new_loader_entry);
 
        return lden;
 }
@@ -142,15 +314,17 @@ classcache_new_loader_entry(classloader *loader,classcache_loader_entry *next)
   
 *******************************************************************************/
 
-static classcache_loader_entry *
-classcache_merge_loaders(classcache_loader_entry *lista,
-                                classcache_loader_entry *listb)
+static classcache_loader_entry * classcache_merge_loaders(
+                                                                       classcache_loader_entry * lista,
+                                                                       classcache_loader_entry * listb)
 {
        classcache_loader_entry *result;
        classcache_loader_entry *ldenA;
        classcache_loader_entry *ldenB;
        classcache_loader_entry **chain;
-       
+
+       CLASSCACHE_COUNT(stat_merge_loader_entries);
+
        /* XXX This is a quadratic algorithm. If this ever
         * becomes a problem, the loader lists should be
         * stored as sorted lists and merged in linear time. */
@@ -158,9 +332,9 @@ classcache_merge_loaders(classcache_loader_entry *lista,
        result = NULL;
        chain = &result;
 
-       for (ldenA=lista; ldenA; ldenA=ldenA->next) {
-               
-               for (ldenB=listb; ldenB; ldenB=ldenB->next) {
+       for (ldenA = lista; ldenA; ldenA = ldenA->next) {
+
+               for (ldenB = listb; ldenB; ldenB = ldenB->next) {
                        if (ldenB->loader == ldenA->loader)
                                goto common_element;
                }
@@ -169,7 +343,7 @@ classcache_merge_loaders(classcache_loader_entry *lista,
                *chain = ldenA;
                chain = &(ldenA->next);
 
-common_element:
+         common_element:
                /* XXX free the duplicated element */
                ;
        }
@@ -180,6 +354,66 @@ common_element:
        return result;
 }
 
+/* classcache_merge_class_entries **********************************************
+   Merge two `classcache_class_entry`s into one.
+   (internally used helper function)
+  
+   IN:
+       en...............the classcache_name_entry containing both class entries
+       clsenA...........first class entry, will receive the result
+          clsenB...........second class entry
+
+   PRE-CONDITION:
+       Either both entries must have the same classobj, or one of them has
+          classobj == NULL.
+
+   NOTE:
+       clsenB is freed by this function!
+  
+*******************************************************************************/
+
+static void classcache_merge_class_entries(classcache_name_entry *en,
+                                                                                  classcache_class_entry *clsenA,
+                                                                                  classcache_class_entry *clsenB)
+{
+#ifdef CLASSCACHE_VERBOSE
+       char logbuffer[1024];
+#endif
+       
+       assert(en);
+       assert(clsenA);
+       assert(clsenB);
+       assert(!clsenA->classobj || !clsenB->classobj || clsenA->classobj == clsenB->classobj);
+
+#ifdef CLASSCACHE_VERBOSE
+       sprintf(logbuffer,"classcache_merge_class_entries(%p,%p->%p,%p->%p) ", 
+                       (void*)en,(void*)clsenA,(void*)clsenA->classobj,(void*)clsenB,(void*)clsenB->classobj);
+       if (clsenA->classobj)
+               utf_cat_classname(logbuffer, clsenA->classobj->name);
+       if (clsenB->classobj)
+               utf_cat_classname(logbuffer, clsenB->classobj->name);
+       log_println(logbuffer);
+#endif
+
+       CLASSCACHE_COUNT(stat_merge_class_entries);
+
+       /* clsenB will be merged into clsenA */
+       clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
+       clsenB->loaders = NULL; /* these have been freed or reused */
+
+       clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
+                                                                                                  clsenB->constraints);
+       clsenB->constraints = NULL; /* these have been freed or reused */
+
+       if (!clsenA->classobj)
+               clsenA->classobj = clsenB->classobj;
+
+       /* remove clsenB from the list of class entries */
+       classcache_remove_class_entry(en, clsenB);
+}
+
+
 /* classcache_lookup_name ******************************************************
  
    Lookup a name in the first level of the cache
@@ -193,37 +427,38 @@ common_element:
        null if no entry was found.
           
 *******************************************************************************/
-static classcache_name_entry *
-classcache_lookup_name(utf *name)
+
+static classcache_name_entry *classcache_lookup_name(utf *name)
 {
-       classcache_name_entry * c;     /* hash table element */
-       u4 key;           /* hashkey computed from classname */
-       u4 slot;          /* slot in hashtable               */
-       u2 i;
+       classcache_name_entry *c;           /* hash table element                 */
+       u4 key;                             /* hashkey computed from classname    */
+       u4 slot;                            /* slot in hashtable                  */
 
-       key  = utf_hashkey(name->text, name->blength);
-       slot = key & (classcache_hash.size - 1);
-       c    = classcache_hash.ptr[slot];
+       CLASSCACHE_COUNT(stat_lookup_name);
+
+       key  = CLASSCACHE_HASH(name->text, (u4) name->blength);
+       slot = key & (hashtable_classcache.size - 1);
+       c    = hashtable_classcache.ptr[slot];
 
        /* search external hash chain for the entry */
+
        while (c) {
-               if (c->name->blength == name->blength) {
-                       for (i = 0; i < name->blength; i++)
-                               if (name->text[i] != c->name->text[i]) goto nomatch;
-                                               
-                       /* entry found in hashtable */
+               /* entry found in hashtable */
+               CLASSCACHE_COUNT(stat_lookup_name_entry);
+
+               if (c->name == name)
                        return c;
-               }
-                       
-       nomatch:
-               c = c->hashlink; /* next element in external chain */
+
+               c = c->hashlink;                    /* next element in external chain */
        }
 
        /* not found */
+
+       CLASSCACHE_COUNT(stat_lookup_name_notfound);
        return NULL;
 }
 
+
 /* classcache_new_name *********************************************************
  
    Return a classcache_name_entry for the given name. The entry is created
@@ -237,31 +472,30 @@ classcache_lookup_name(utf *name)
        a pointer to the classcache_name_entry for this name
           
 *******************************************************************************/
-static classcache_name_entry *
-classcache_new_name(utf *name)
+
+static classcache_name_entry *classcache_new_name(utf *name)
 {
-       classcache_name_entry * c;     /* hash table element */
-       u4 key;           /* hashkey computed from classname */
-       u4 slot;          /* slot in hashtable               */
-       u2 i;
+       classcache_name_entry *c;       /* hash table element */
+       u4 key;                                         /* hashkey computed from classname */
+       u4 slot;                                        /* slot in hashtable               */
+       u4 i;
 
-       key  = utf_hashkey(name->text, name->blength);
-       slot = key & (classcache_hash.size - 1);
-       c    = classcache_hash.ptr[slot];
+       CLASSCACHE_COUNT(stat_lookup_new_name);
+
+       key  = CLASSCACHE_HASH(name->text, (u4) name->blength);
+       slot = key & (hashtable_classcache.size - 1);
+       c    = hashtable_classcache.ptr[slot];
 
        /* search external hash chain for the entry */
+
        while (c) {
-               if (c->name->blength == name->blength) {
-                       for (i = 0; i < name->blength; i++)
-                               if (name->text[i] != c->name->text[i]) goto nomatch;
-                                               
-                       /* entry found in hashtable */
+               /* entry found in hashtable */
+               CLASSCACHE_COUNT(stat_lookup_new_name_entry);
+
+               if (c->name == name)
                        return c;
-               }
-                       
-       nomatch:
-               c = c->hashlink; /* next element in external chain */
+
+               c = c->hashlink;                    /* next element in external chain */
        }
 
        /* location in hashtable found, create new entry */
@@ -272,47 +506,54 @@ classcache_new_name(utf *name)
        c->classes = NULL;
 
        /* insert entry into hashtable */
-       c->hashlink = classcache_hash.ptr[slot];
-       classcache_hash.ptr[slot] = c;
+       c->hashlink = (classcache_name_entry *) hashtable_classcache.ptr[slot];
+       CLASSCACHE_COUNTIF(c->hashlink,stat_lookup_new_name_collisions);
+       hashtable_classcache.ptr[slot] = c;
 
        /* update number of hashtable-entries */
-       classcache_hash.entries++;
+       hashtable_classcache.entries++;
+       CLASSCACHE_COUNT(stat_classnames_stored);
 
-       if (classcache_hash.entries > (classcache_hash.size * 2)) {
+       if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
+               /* reorganization of hashtable */ 
 
-               /* reorganization of hashtable, average length of 
-                  the external chains is approx. 2                */  
+               classcache_name_entry *c2;
+               hashtable newhash;              /* the new hashtable */
 
-               u4 i;
-               classcache_name_entry *c;
-               hashtable newhash;  /* the new hashtable */
+               CLASSCACHE_COUNT(stat_rehash_names);
 
                /* create new hashtable, double the size */
-               init_hashtable(&newhash, classcache_hash.size * 2);
-               newhash.entries = classcache_hash.entries;
+
+               hashtable_create(&newhash, hashtable_classcache.size * 2);
+               newhash.entries = hashtable_classcache.entries;
 
                /* transfer elements to new hashtable */
-               for (i = 0; i < classcache_hash.size; i++) {
-                       c = (classcache_name_entry *) classcache_hash.ptr[i];
-                       while (c) {
-                               classcache_name_entry *nextc = c->hashlink;
-                               u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
-                                               
-                               c->hashlink = newhash.ptr[slot];
-                               newhash.ptr[slot] = c;
-
-                               c = nextc;
+
+               for (i = 0; i < hashtable_classcache.size; i++) {
+                       c2 = (classcache_name_entry *) hashtable_classcache.ptr[i];
+                       while (c2) {
+                               classcache_name_entry *nextc = c2->hashlink;
+                               u4 newslot =
+                                       (CLASSCACHE_HASH(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
+
+                               c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
+                               CLASSCACHE_COUNTIF(c2->hashlink,stat_rehash_names_collisions);
+                               newhash.ptr[newslot] = c2;
+
+                               c2 = nextc;
                        }
                }
-       
-               /* dispose old table */ 
-               MFREE(classcache_hash.ptr, void*, classcache_hash.size);
-               classcache_hash = newhash;
+
+               /* dispose old table */
+
+               MFREE(hashtable_classcache.ptr, void *, hashtable_classcache.size);
+               hashtable_classcache = newhash;
        }
 
        return c;
 }
 
+
 /* classcache_lookup ***********************************************************
  
    Lookup a possibly loaded class
@@ -329,8 +570,7 @@ classcache_new_name(utf *name)
    
 *******************************************************************************/
 
-classinfo *
-classcache_lookup(classloader *initloader,utf *classname)
+classinfo *classcache_lookup(classloader_t *initloader, utf *classname)
 {
        classcache_name_entry *en;
        classcache_class_entry *clsen;
@@ -339,27 +579,35 @@ classcache_lookup(classloader *initloader,utf *classname)
 
        CLASSCACHE_LOCK();
 
+       CLASSCACHE_COUNT(stat_lookup);
        en = classcache_lookup_name(classname);
-       
+
        if (en) {
                /* iterate over all class entries */
-               for (clsen=en->classes; clsen; clsen=clsen->next) {
+
+               for (clsen = en->classes; clsen; clsen = clsen->next) {
+                       CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
                        /* check if this entry has been loaded by initloader */
-                       for (lden=clsen->loaders; lden; lden=lden->next) {
+
+                       for (lden = clsen->loaders; lden; lden = lden->next) {
+                               CLASSCACHE_COUNT(stat_lookup_loader_checked);
                                if (lden->loader == initloader) {
                                        /* found the loaded class entry */
-                                       CLASSCACHE_ASSERT(clsen->classobj);
+
+                                       assert(clsen->classobj);
                                        cls = clsen->classobj;
                                        goto found;
                                }
                        }
                }
        }
-found:
+
+  found:
        CLASSCACHE_UNLOCK();
        return cls;
 }
 
+
 /* classcache_lookup_defined ***************************************************
  
    Lookup a class with the given name and defining loader
@@ -374,24 +622,22 @@ found:
    
 *******************************************************************************/
 
-classinfo * 
-classcache_lookup_defined(classloader *defloader,utf *classname)
+classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
 {
        classcache_name_entry *en;
        classcache_class_entry *clsen;
-       classcache_loader_entry *lden;
        classinfo *cls = NULL;
 
        CLASSCACHE_LOCK();
 
        en = classcache_lookup_name(classname);
-       
+
        if (en) {
                /* iterate over all class entries */
-               for (clsen=en->classes; clsen; clsen=clsen->next) {
+               for (clsen = en->classes; clsen; clsen = clsen->next) {
                        if (!clsen->classobj)
                                continue;
-                       
+
                        /* check if this entry has been defined by defloader */
                        if (clsen->classobj->classloader == defloader) {
                                cls = clsen->classobj;
@@ -399,85 +645,204 @@ classcache_lookup_defined(classloader *defloader,utf *classname)
                        }
                }
        }
-found:
+
+  found:
+       CLASSCACHE_UNLOCK();
+       return cls;
+}
+
+
+/* classcache_lookup_defined_or_initiated **************************************
+   Lookup a class that has been defined or initiated by the given loader
+  
+   IN:
+       loader...........defining or initiating loader
+       classname........class name to look up
+  
+   RETURN VALUE:
+       The return value is a pointer to the cached class object,
+       or NULL, if the class is not in the cache.
+
+   Note: synchronized with global tablelock
+   
+*******************************************************************************/
+
+classinfo *classcache_lookup_defined_or_initiated(classloader_t *loader, 
+                                                                                                 utf *classname)
+{
+       classcache_name_entry *en;
+       classcache_class_entry *clsen;
+       classcache_loader_entry *lden;
+       classinfo *cls = NULL;
+
+       CLASSCACHE_LOCK();
+
+       en = classcache_lookup_name(classname);
+
+       if (en) {
+               /* iterate over all class entries */
+
+               for (clsen = en->classes; clsen; clsen = clsen->next) {
+
+                       /* check if this entry has been defined by loader */
+                       if (clsen->classobj && clsen->classobj->classloader == loader) {
+                               cls = clsen->classobj;
+                               goto found;
+                       }
+                       
+                       /* check if this entry has been initiated by loader */
+                       for (lden = clsen->loaders; lden; lden = lden->next) {
+                               if (lden->loader == loader) {
+                                       /* found the loaded class entry */
+
+                                       assert(clsen->classobj);
+                                       cls = clsen->classobj;
+                                       goto found;
+                               }
+                       }
+               }
+       }
+
+  found:
        CLASSCACHE_UNLOCK();
        return cls;
 }
 
+
 /* classcache_store ************************************************************
    
-   Store a loaded class
+   Store a loaded class. If a class of the same name has already been stored
+   with the same initiating loader, then the given class CLS is freed (if
+   possible) and the previously stored class is returned.
   
    IN:
        initloader.......initiating loader used to load the class
+                           (may be NULL indicating the bootstrap loader)
        cls..............class object to cache
+          mayfree..........true if CLS may be freed in case another class is
+                           returned
   
    RETURN VALUE:
-       true.............everything ok, the class was stored in
-                        the cache if necessary,
-       false............an exception has been thrown.
+       cls..............everything ok, the class was stored in the cache,
+          other classinfo..another class with the same (initloader,name) has been
+                           stored earlier. CLS has been freed[1] and the earlier
+                                               stored class is returned.
+       NULL.............an exception has been thrown.
    
    Note: synchronized with global tablelock
+
+   [1]...in case MAYFREE is true
    
 *******************************************************************************/
 
-bool
-classcache_store(classloader *initloader,classinfo *cls)
+classinfo *classcache_store(classloader_t *initloader, classinfo *cls,
+                                                       bool mayfree)
 {
        classcache_name_entry *en;
        classcache_class_entry *clsen;
+       classcache_class_entry *clsenB;
        classcache_loader_entry *lden;
-
-       CLASSCACHE_ASSERT(cls);
-       CLASSCACHE_ASSERT(cls->loaded);
-
 #ifdef CLASSCACHE_VERBOSE
-       fprintf(stderr,"classcache_store(%p,",initloader);
-       utf_fprint_classname(stderr,cls->name);
-       fprintf(stderr,")\n");
+       char logbuffer[1024];
 #endif
+       
+       assert(cls);
+       assert(cls->state & CLASS_LOADED);
 
        CLASSCACHE_LOCK();
 
+#ifdef CLASSCACHE_VERBOSE
+       sprintf(logbuffer,"classcache_store (%p,%d,%p=", (void*)initloader,mayfree,(void*)cls);
+       utf_cat_classname(logbuffer, cls->name);
+       strcat(logbuffer,")");
+       log_println(logbuffer);
+#endif
+
        en = classcache_new_name(cls->name);
 
-       CLASSCACHE_ASSERT(en);
-       
+       assert(en);
+
        /* iterate over all class entries */
-       for (clsen=en->classes; clsen; clsen=clsen->next) {
-               
-#ifdef CLASSCACHE_DEBUG
+       for (clsen = en->classes; clsen; clsen = clsen->next) {
+
                /* check if this entry has already been loaded by initloader */
-               /* It never should have been loaded before! */
-               for (lden=clsen->loaders; lden; lden=lden->next) {
-                       if (lden->loader == initloader)
-                               CLASSCACHE_ASSERT(false);
-               }
+               for (lden = clsen->loaders; lden; lden = lden->next) {
+                       if (lden->loader == initloader) {
+                          if (clsen->classobj != cls) {
+                                       /* A class with the same (initloader,name) pair has been stored already. */
+                                       /* We free the given class and return the earlier one.                   */
+#ifdef CLASSCACHE_VERBOSE
+                                       log_println("replacing %p with earlier loaded class %p",cls,clsen->classobj);
 #endif
+                                       assert(clsen->classobj);
+                                       if (mayfree)
+                                               class_free(cls);
+                                       cls = clsen->classobj;
+                          }
+                          goto return_success;
+                       }
+               }
+
+               /* {This entry has not been resolved with initloader} */
 
                /* check if initloader is constrained to this entry */
-               for (lden=clsen->constraints; lden; lden=lden->next) {
+               for (lden = clsen->constraints; lden; lden = lden->next) {
                        if (lden->loader == initloader) {
-                               /* we have to use this entry */
-                               /* check if is has already been resolved to another class */
-                               if (clsen->classobj && clsen->classobj != cls) {
-                                       /* a loading constraint is violated */
-                                       *exceptionptr = new_exception_message(string_java_lang_LinkageError,
-                                                       "loading constraint violated XXX add message");
-                                       goto return_exception;
+                               /* we have to use this entry. check if it has been resolved */
+                               if (clsen->classobj) {
+                                       /* check if is has already been resolved to another class */
+                                       if (clsen->classobj != cls) {
+                                               /* a loading constraint is violated */
+                                               exceptions_throw_linkageerror("loading constraint violated: ", cls);
+                                               goto return_exception;
+                                       }
+
+                                       /* record initloader as initiating loader */
+                                       clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+                                       goto return_success;
                                }
 
+                               /* {this is the first resolution for this entry} */
                                /* record initloader as initiating loader */
-                               clsen->loaders = classcache_new_loader_entry(initloader,clsen->loaders);
+                               clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+
+                               /* maybe we can merge this entry with another one */
+                               for (clsenB = en->classes; clsenB; clsenB = clsenB->next) {
+                                       /* we dont want the entry that we have already */
+                                       if (clsenB->classobj == cls) {
+                                               /* this entry has the same classobj. let's merge them */
+                                               classcache_merge_class_entries(en,clsen,clsenB);
+                                               goto return_success;
+                                       }
+                               }
 
                                /* record the loaded class object */
                                clsen->classobj = cls;
+                               CLASSCACHE_COUNT(stat_classes_stored);
 
                                /* done */
                                goto return_success;
                        }
                }
-               
+
+       }
+
+       /* {There is no class entry containing initloader as initiating 
+        *  or constrained loader.} */
+
+       /* we look for a class entry with the same classobj we want to store */
+       for (clsen = en->classes; clsen; clsen = clsen->next) {
+               if (clsen->classobj == cls) {
+                       /* this entry is about the same classobj. let's use it */
+                       /* check if this entry has already been loaded by initloader */
+                       for (lden = clsen->loaders; lden; lden = lden->next) {
+                               if (lden->loader == initloader)
+                                       goto return_success;
+                       }
+                       clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
+                       goto return_success;
+               }
        }
 
        /* create a new class entry for this class object with */
@@ -485,19 +850,139 @@ classcache_store(classloader *initloader,classinfo *cls)
 
        clsen = NEW(classcache_class_entry);
        clsen->classobj = cls;
-       clsen->loaders = classcache_new_loader_entry(initloader,NULL);
+       clsen->loaders = classcache_new_loader_entry(initloader, NULL);
        clsen->constraints = NULL;
 
        clsen->next = en->classes;
        en->classes = clsen;
+       CLASSCACHE_COUNT(stat_classes_stored);
 
-return_success:
+  return_success:
+#ifdef CLASSCACHE_VERBOSE
+       classcache_debug_dump(stdout,cls->name);
+#endif
        CLASSCACHE_UNLOCK();
+       return cls;
+
+  return_exception:
+       CLASSCACHE_UNLOCK();
+       return NULL;                            /* exception */
+}
+
+/* classcache_store_unique *****************************************************
+   
+   Store a loaded class as loaded by the bootstrap loader. This is a wrapper 
+   aroung classcache_store that throws an exception if a class with the same 
+   name has already been loaded by the bootstrap loader.
+
+   This function is used to register a few special classes during startup.
+   It should not be used otherwise.
+  
+   IN:
+       cls..............class object to cache
+  
+   RETURN VALUE:
+       true.............everything ok, the class was stored.
+       false............an exception has been thrown.
+   
+   Note: synchronized with global tablelock
+   
+*******************************************************************************/
+
+bool classcache_store_unique(classinfo *cls)
+{
+       classinfo *result;
+
+       result = classcache_store(NULL,cls,false);
+       if (result == NULL)
+               return false;
+
+       if (result != cls) {
+               exceptions_throw_internalerror("class already stored in the class cache");
+               return false;
+       }
+
        return true;
+}
+
+/* classcache_store_defined ****************************************************
+   
+   Store a loaded class after it has been defined. If the class has already
+   been defined by the same defining loader in another thread, free the given
+   class and returned the one which has been defined earlier.
+  
+   IN:
+       cls..............class object to store. classloader must be set
+                           (classloader may be NULL, for bootloader)
+  
+   RETURN VALUE:
+       cls..............everything ok, the class was stored the cache,
+          other classinfo..the class had already been defined, CLS was freed, the
+                           class which was defined earlier is returned,
+       NULL.............an exception has been thrown.
+   
+*******************************************************************************/
+
+classinfo *classcache_store_defined(classinfo *cls)
+{
+       classcache_name_entry *en;
+       classcache_class_entry *clsen;
+#ifdef CLASSCACHE_VERBOSE
+       char logbuffer[1024];
+#endif
+
+       assert(cls);
+       assert(cls->state & CLASS_LOADED);
+
+       CLASSCACHE_LOCK();
+
+#ifdef CLASSCACHE_VERBOSE
+       sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
+       utf_cat_classname(logbuffer, cls->name);
+       strcat(logbuffer,")");
+       log_println(logbuffer);
+#endif
+
+       en = classcache_new_name(cls->name);
+
+       assert(en);
+
+       /* iterate over all class entries */
+       for (clsen = en->classes; clsen; clsen = clsen->next) {
+               
+               /* check if this class has been defined by the same classloader */
+               if (clsen->classobj && clsen->classobj->classloader == cls->classloader) {
+                       /* we found an earlier definition, delete the newer one */
+                       /* (if it is a different classinfo)                     */
+                       if (clsen->classobj != cls) {
+#ifdef CLASSCACHE_VERBOSE
+                               log_println("replacing %p with earlier defined class %p",cls,clsen->classobj);
+#endif
+                               class_free(cls);
+                               cls = clsen->classobj;
+                       }
+                       goto return_success;
+               }
+       }
+
+       /* create a new class entry for this class object */
+       /* the list of initiating loaders is empty at this point */
+
+       clsen = NEW(classcache_class_entry);
+       clsen->classobj = cls;
+       clsen->loaders = NULL;
+       clsen->constraints = NULL;
 
-return_exception:
+       clsen->next = en->classes;
+       en->classes = clsen;
+       CLASSCACHE_COUNT(stat_classes_stored);
+
+return_success:
+#ifdef CLASSCACHE_VERBOSE
+       classcache_debug_dump(stdout,cls->name);
+#endif
        CLASSCACHE_UNLOCK();
-       return false; /* exception */
+       return cls;
 }
 
 /* classcache_find_loader ******************************************************
@@ -515,27 +1000,28 @@ return_exception:
    
 *******************************************************************************/
 
-static classcache_class_entry *
-classcache_find_loader(classcache_name_entry *entry,classloader *loader)
+static classcache_class_entry * classcache_find_loader(
+                                                                       classcache_name_entry * entry,
+                                                                       classloader_t * loader)
 {
        classcache_class_entry *clsen;
        classcache_loader_entry *lden;
-       
-       CLASSCACHE_ASSERT(entry);
+
+       assert(entry);
 
        /* iterate over all class entries */
-       for (clsen=entry->classes; clsen; clsen=clsen->next) {
-               
+       for (clsen = entry->classes; clsen; clsen = clsen->next) {
+
                /* check if this entry has already been loaded by initloader */
-               for (lden=clsen->loaders; lden; lden=lden->next) {
+               for (lden = clsen->loaders; lden; lden = lden->next) {
                        if (lden->loader == loader)
-                               return clsen; /* found */
+                               return clsen;   /* found */
                }
-               
+
                /* check if loader is constrained to this entry */
-               for (lden=clsen->constraints; lden; lden=lden->next) {
+               for (lden = clsen->constraints; lden; lden = lden->next) {
                        if (lden->loader == loader)
-                               return clsen; /* found */
+                               return clsen;   /* found */
                }
        }
 
@@ -552,24 +1038,23 @@ classcache_find_loader(classcache_name_entry *entry,classloader *loader)
           
 *******************************************************************************/
 
-static void
-classcache_free_class_entry(classcache_class_entry *clsen)
+static void classcache_free_class_entry(classcache_class_entry * clsen)
 {
        classcache_loader_entry *lden;
        classcache_loader_entry *next;
-       
-       CLASSCACHE_ASSERT(clsen);
 
-       for (lden=clsen->loaders; lden; lden=next) {
+       assert(clsen);
+
+       for (lden = clsen->loaders; lden; lden = next) {
                next = lden->next;
-               FREE(lden,classcache_loader_entry);
+               FREE(lden, classcache_loader_entry);
        }
-       for (lden=clsen->constraints; lden; lden=next) {
+       for (lden = clsen->constraints; lden; lden = next) {
                next = lden->next;
-               FREE(lden,classcache_loader_entry);
+               FREE(lden, classcache_loader_entry);
        }
 
-       FREE(clsen,classcache_class_entry);
+       FREE(clsen, classcache_class_entry);
 }
 
 /* classcache_remove_class_entry ***********************************************
@@ -584,14 +1069,13 @@ classcache_free_class_entry(classcache_class_entry *clsen)
   
 *******************************************************************************/
 
-static void
-classcache_remove_class_entry(classcache_name_entry *entry,
-                                                         classcache_class_entry *clsen)
+static void classcache_remove_class_entry(classcache_name_entry * entry,
+                                                                                 classcache_class_entry * clsen)
 {
        classcache_class_entry **chain;
 
-       CLASSCACHE_ASSERT(entry);
-       CLASSCACHE_ASSERT(clsen);
+       assert(entry);
+       assert(clsen);
 
        chain = &(entry->classes);
        while (*chain) {
@@ -613,20 +1097,19 @@ classcache_remove_class_entry(classcache_name_entry *entry,
           
 *******************************************************************************/
 
-static void
-classcache_free_name_entry(classcache_name_entry *entry)
+static void classcache_free_name_entry(classcache_name_entry * entry)
 {
        classcache_class_entry *clsen;
        classcache_class_entry *next;
-       
-       CLASSCACHE_ASSERT(entry);
 
-       for (clsen=entry->classes; clsen; clsen=next) {
+       assert(entry);
+
+       for (clsen = entry->classes; clsen; clsen = next) {
                next = clsen->next;
                classcache_free_class_entry(clsen);
        }
 
-       FREE(entry,classcache_name_entry);
+       FREE(entry, classcache_name_entry);
 }
 
 /* classcache_free *************************************************************
@@ -641,27 +1124,23 @@ classcache_free_name_entry(classcache_name_entry *entry)
   
 *******************************************************************************/
 
-void 
-classcache_free()
+void classcache_free(void)
 {
        u4 slot;
        classcache_name_entry *entry;
        classcache_name_entry *next;
 
-       for (slot=0; slot<classcache_hash.size; ++slot) {
-               for (entry=(classcache_name_entry *)classcache_hash.ptr[slot];
-                        entry;
-                        entry = next)
-               {
+       for (slot = 0; slot < hashtable_classcache.size; ++slot) {
+               for (entry = (classcache_name_entry *) hashtable_classcache.ptr[slot]; entry; entry = next) {
                        next = entry->hashlink;
                        classcache_free_name_entry(entry);
                }
        }
 
-       MFREE(classcache_hash.ptr,voidptr,classcache_hash.size);
-       classcache_hash.size = 0;
-       classcache_hash.entries = 0;
-       classcache_hash.ptr = NULL;
+       MFREE(hashtable_classcache.ptr, void*, hashtable_classcache.size);
+       hashtable_classcache.size = 0;
+       hashtable_classcache.entries = 0;
+       hashtable_classcache.ptr = NULL;
 }
 
 /* classcache_add_constraint ***************************************************
@@ -681,65 +1160,62 @@ classcache_free()
    
 *******************************************************************************/
 
-bool
-classcache_add_constraint(classloader *a,classloader *b,utf *classname)
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraint(classloader_t * a,
+                                                          classloader_t * b,
+                                                          utf * classname)
 {
        classcache_name_entry *en;
        classcache_class_entry *clsenA;
        classcache_class_entry *clsenB;
 
-       CLASSCACHE_ASSERT(classname);
+       assert(classname);
 
 #ifdef CLASSCACHE_VERBOSE
-       fprintf(stderr,"classcache_add_constraint(%p,%p,",(void*)a,(void*)b);
-       utf_fprint_classname(stderr,classname);
-       fprintf(stderr,")\n");
+       log_start();
+       log_print("classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
+       utf_fprint_printable_ascii_classname(stdout, classname);
+       log_print(")\n");
+       log_finish();
 #endif
 
        /* a constraint with a == b is trivially satisfied */
-       if (a == b)
+       if (a == b) {
+               CLASSCACHE_COUNT(stat_trivial_constraints);
                return true;
+       }
 
        CLASSCACHE_LOCK();
 
        en = classcache_new_name(classname);
 
-       CLASSCACHE_ASSERT(en);
-       
+       assert(en);
+       CLASSCACHE_COUNT(stat_nontriv_constraints);
+
        /* find the entry loaded by / constrained to each loader */
-       clsenA = classcache_find_loader(en,a);
-       clsenB = classcache_find_loader(en,b);
+       clsenA = classcache_find_loader(en, a);
+       clsenB = classcache_find_loader(en, b);
 
        if (clsenA && clsenB) {
                /* { both loaders have corresponding entries } */
+               CLASSCACHE_COUNT(stat_nontriv_constraints_both);
 
                /* if the entries are the same, the constraint is already recorded */
                if (clsenA == clsenB)
                        goto return_success;
 
                /* check if the entries can be merged */
-               if (clsenA->classobj && clsenB->classobj && clsenA->classobj != clsenB->classobj) {
+               if (clsenA->classobj && clsenB->classobj
+                       && clsenA->classobj != clsenB->classobj) {
                        /* no, the constraint is violated */
-                       *exceptionptr = new_exception_message(string_java_lang_LinkageError,
-                                       "loading constraint violated XXX add message");
+                       exceptions_throw_linkageerror("loading constraint violated: ",
+                                                                                 clsenA->classobj);
                        goto return_exception;
                }
 
                /* yes, merge the entries */
-               /* clsenB will be merged into clsenA */
-               clsenA->loaders = classcache_merge_loaders(clsenA->loaders,
-                                                                                                  clsenB->loaders);
-               clsenB->loaders = NULL;
-               
-               clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
-                                                                                                          clsenB->constraints);
-               clsenB->constraints = NULL;
-
-               if (!clsenA->classobj)
-                       clsenA->classobj = clsenB->classobj;
-               
-               /* remove clsenB from the list of class entries */
-               classcache_remove_class_entry(en,clsenB);
+               classcache_merge_class_entries(en,clsenA,clsenB);
+               CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
        }
        else {
                /* { at most one of the loaders has a corresponding entry } */
@@ -750,35 +1226,269 @@ classcache_add_constraint(classloader *a,classloader *b,utf *classname)
 
                if (!clsenA) {
                        /* { no loader has a corresponding entry } */
+                       CLASSCACHE_COUNT(stat_nontriv_constraints_none);
 
                        /* create a new class entry with the constraint (a,b,en->name) */
                        clsenA = NEW(classcache_class_entry);
                        clsenA->classobj = NULL;
                        clsenA->loaders = NULL;
-                       clsenA->constraints = classcache_new_loader_entry(b,NULL);
-                       clsenA->constraints = classcache_new_loader_entry(a,clsenA->constraints);
+                       clsenA->constraints = classcache_new_loader_entry(b, NULL);
+                       clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
 
                        clsenA->next = en->classes;
                        en->classes = clsenA;
                }
                else {
+                       CLASSCACHE_COUNT(stat_nontriv_constraints_one);
+
                        /* make b the loader that has no corresponding entry */
                        if (clsenB)
                                b = a;
-                       
+
                        /* loader b must be added to entry clsenA */
-                       clsenA->constraints = classcache_new_loader_entry(b,clsenA->constraints);
+                       clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
                }
        }
 
-return_success:
+  return_success:
        CLASSCACHE_UNLOCK();
        return true;
 
-return_exception:
+  return_exception:
+       CLASSCACHE_UNLOCK();
+       return false;                           /* exception */
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+/* classcache_add_constraints_for_params ***************************************
+   Add loading constraints for the parameters and return type of 
+   the given method.
+  
+   IN:
+       a................first initiating loader
+       b................second initiating loader
+       m................methodinfo 
+  
+   RETURN VALUE:
+       true.............everything ok, the constraints have been added,
+       false............an exception has been thrown.
+   
+   Note: synchronized with global tablelock
+   
+*******************************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraints_for_params(classloader_t * a,
+                                                                                  classloader_t * b,
+                                                                                  methodinfo *m)
+{
+       methoddesc *md;
+       typedesc *td;
+       s4 i;
+
+       /* a constraint with a == b is trivially satisfied */
+
+       if (a == b) {
+               return true;
+       }
+
+       /* get the parsed descriptor */
+
+       assert(m);
+       md = m->parseddesc;
+       assert(md);
+
+       /* constrain the return type */
+
+       if (md->returntype.type == TYPE_ADR) {
+               if (!classcache_add_constraint(a, b, md->returntype.classref->name))
+                       return false; /* exception */
+       }
+
+       /* constrain each reference type used in the parameters */
+
+       td = md->paramtypes;
+       i = md->paramcount;
+       for (; i--; td++) {
+               if (td->type != TYPE_ADR)
+                       continue;
+
+               if (!classcache_add_constraint(a, b, td->classref->name))
+                       return false; /* exception */
+       }
+
+       /* everything ok */
+       return true;
+}
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* classcache_number_of_loaded_classes *****************************************
+
+   Counts the number of loaded classes and returns it.
+
+   Note: This function assumes that the CLASSCACHE_LOCK is held by the
+   caller!
+
+*******************************************************************************/
+
+static s4 classcache_number_of_loaded_classes(void)
+{
+       classcache_name_entry  *en;
+       classcache_class_entry *clsen;
+       s4                      number;
+       s4                      i;
+
+       /* initialize class counter */
+
+       number = 0;
+
+       for (i = 0; i < hashtable_classcache.size; i++) {
+               /* iterate over hashlink */
+
+               for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+                       /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+                       if (en->name->text[0] == '$')
+                               continue;
+
+                       /* iterate over classes with same name */
+
+                       for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+                               /* get only loaded classes */
+
+                               if (clsen->classobj != NULL)
+                                       number++;
+                       }
+               }
+       }
+
+       return number;
+}
+
+
+/* classcache_get_loaded_class_count *******************************************
+
+   Counts the number of loaded classes and returns it.
+
+*******************************************************************************/
+
+s4 classcache_get_loaded_class_count(void)
+{
+       s4 count;
+
+       CLASSCACHE_LOCK();
+
+       count = classcache_number_of_loaded_classes();
+       
+       CLASSCACHE_UNLOCK();
+
+       return count;
+}
+
+
+/* classcache_get_loaded_classes ***********************************************
+
+   Returns an array of all loaded classes as array.  The array is
+   allocaed on the Java heap.
+
+*******************************************************************************/
+
+#if defined(ENABLE_JVMTI)
+void classcache_get_loaded_classes(s4 *class_count_ptr,
+                                                                  classinfo ***classes_ptr)
+{
+       classinfo              **classes;
+       s4                       class_count;
+       classcache_name_entry   *en;
+       classcache_class_entry  *clsen;
+       s4                       i;
+       s4                       j;
+
+       CLASSCACHE_LOCK();
+
+       /* get the number of loaded classes and allocate the array */
+
+       class_count = classcache_number_of_loaded_classes();
+
+       classes = GCMNEW(classinfo*, class_count);
+
+       /* look in every slot of the hashtable */
+
+       for (i = 0, j = 0; i < hashtable_classcache.size; i++) {
+               /* iterate over hashlink */
+
+               for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+                       /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+                       if (en->name->text[0] == '$')
+                               continue;
+
+                       /* iterate over classes with same name */
+
+                       for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+                               /* get only loaded classes */
+
+                               if (clsen->classobj != NULL) {
+                                       classes[j] = clsen->classobj;
+                                       j++;
+                               }
+                       }
+               }
+       }
+
+       /* pass the return values */
+
+       *class_count_ptr = class_count;
+       *classes_ptr     = classes;
+
        CLASSCACHE_UNLOCK();
-       return false; /* exception */
 }
+#endif /* defined(ENABLE_JVMTI) */
+
+
+/* classcache_foreach_loaded_class *********************************************
+
+   Calls the given function for each loaded class.
+
+*******************************************************************************/
+
+void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
+                                                                        void *data)
+{
+       classcache_name_entry   *en;
+       classcache_class_entry  *clsen;
+       s4                       i;
+
+       CLASSCACHE_LOCK();
+
+       /* look in every slot of the hashtable */
+
+       for (i = 0; i < hashtable_classcache.size; i++) {
+               /* iterate over hashlink */
+
+               for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
+                       /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
+
+                       if (en->name->text[0] == '$')
+                               continue;
+
+                       /* iterate over classes with same name */
+
+                       for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
+                               /* get only loaded classes */
+
+                               if (clsen->classobj != NULL) {
+                                       (*func)(clsen->classobj, data);
+                               }
+                       }
+               }
+       }
+
+       CLASSCACHE_UNLOCK();
+}
+
 
 /*============================================================================*/
 /* DEBUG DUMPS                                                                */
@@ -790,13 +1500,16 @@ return_exception:
   
    IN:
        file.............output stream
+          only.............if != NULL, only print entries for this name
+                           (Currently we print also the rest of the hash chain to
+                                                get a feel for the average length of hash chains.)
   
    Note: synchronized with global tablelock
    
 *******************************************************************************/
 
-void
-classcache_debug_dump(FILE *file)
+#ifndef NDEBUG
+void classcache_debug_dump(FILE * file,utf *only)
 {
        classcache_name_entry *c;
        classcache_class_entry *clsen;
@@ -805,42 +1518,58 @@ classcache_debug_dump(FILE *file)
 
        CLASSCACHE_LOCK();
 
-       fprintf(file,"\n=== [loaded class cache] =====================================\n\n");
-       fprintf(file,"hash size   : %d\n",classcache_hash.size);
-       fprintf(file,"hash entries: %d\n",classcache_hash.entries);
-       fprintf(file,"\n");
+       log_println("=== [loaded class cache] =====================================");
+       log_println("hash size   : %d", (int) hashtable_classcache.size);
+       log_println("hash entries: %d", (int) hashtable_classcache.entries);
+       log_println("");
 
-       for (slot=0; slot<classcache_hash.size; ++slot) {
-               c = (classcache_name_entry *) classcache_hash.ptr[slot];
+       if (only) {
+               c = classcache_lookup_name(only);
+               slot = 0; /* avoid compiler warning */
+               goto dump_it;
+       }
+
+       for (slot = 0; slot < hashtable_classcache.size; ++slot) {
+               c = (classcache_name_entry *) hashtable_classcache.ptr[slot];
 
-               for (; c; c=c->hashlink) {
-                       utf_fprint_classname(file,c->name);
-                       fprintf(file,"\n");
+dump_it:
+               for (; c; c = c->hashlink) {
+                       utf_fprint_printable_ascii_classname(file, c->name);
+                       fprintf(file, "\n");
 
                        /* iterate over all class entries */
-                       for (clsen=c->classes; clsen; clsen=clsen->next) {
+                       for (clsen = c->classes; clsen; clsen = clsen->next) {
                                if (clsen->classobj) {
-                                       fprintf(file,"    loaded %p\n",(void*)clsen->classobj);
+                                       log_println("    loaded %p", (void *) clsen->classobj);
                                }
                                else {
-                                       fprintf(file,"    unresolved\n");
+                                       log_println("    unresolved");
                                }
-                               fprintf(file,"        loaders:");
-                               for (lden=clsen->loaders; lden; lden=lden->next) {
-                                       fprintf(file,"<%p> %p",(void *)lden,(void *)lden->loader);
+
+                               log_start();
+                               log_print("        loaders: ");
+                               for (lden = clsen->loaders; lden; lden = lden->next) {
+                                       log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
                                }
-                               fprintf(file,"\n        constraints:");
-                               for (lden=clsen->constraints; lden; lden=lden->next) {
-                                       fprintf(file,"<%p> %p",(void *)lden,(void *)lden->loader);
+                               log_finish();
+
+                               log_start();
+                               log_print("        constraints: ");
+                               for (lden = clsen->constraints; lden; lden = lden->next) {
+                                       log_print("<%p> %p ", (void *) lden, (void *) lden->loader);
                                }
-                               fprintf(file,"\n");
+                               log_finish();
                        }
                }
+
+               if (only)
+                       break;
        }
-       fprintf(file,"\n==============================================================\n\n");
+       fprintf(file, "\n==============================================================\n\n");
 
        CLASSCACHE_UNLOCK();
 }
+#endif /* NDEBUG */
 
 /*
  * These are local overrides for various environment variables in Emacs.
@@ -855,4 +1584,3 @@ classcache_debug_dump(FILE *file)
  * End:
  * vim:noexpandtab:sw=4:ts=4:
  */
-