* src/vm/classcache.cpp,
authorAndreas HUBERT <andreas.hubert@gmx.at>
Tue, 14 Oct 2008 11:34:30 +0000 (13:34 +0200)
committerAndreas HUBERT <andreas.hubert@gmx.at>
Tue, 14 Oct 2008 11:34:30 +0000 (13:34 +0200)
  src/vm/classcache.hpp,
  src/vm/method.cpp,
  src/vm/method.hpp,
  src/vm/zip.cpp,
  src/vm/zip.hpp: Moved to C++.

--HG--
rename : src/vm/classcache.c => src/vm/classcache.cpp
rename : src/vm/classcache.h => src/vm/classcache.hpp
rename : src/vm/method.c => src/vm/method.cpp
rename : src/vm/method.h => src/vm/method.hpp
rename : src/vm/zip.c => src/vm/zip.cpp
rename : src/vm/zip.h => src/vm/zip.hpp

84 files changed:
src/mm/cacao-gc/final.h
src/mm/cacao-gc/rootset.h
src/mm/gc.hpp
src/native/jvmti/jvmti.c
src/native/localref.hpp
src/native/native.hpp
src/native/vm/cldc1.1/com_sun_cldc_io_ResourceInputStream.cpp
src/native/vm/gnuclasspath/gnu_java_lang_management_VMClassLoadingMXBeanImpl.cpp
src/native/vm/gnuclasspath/gnu_java_lang_management_VMThreadMXBeanImpl.cpp
src/native/vm/gnuclasspath/java_lang_VMClassLoader.cpp
src/native/vm/gnuclasspath/java_lang_reflect_VMMethod.cpp
src/native/vm/nativevm.cpp
src/native/vm/openjdk/jvm.cpp
src/native/vm/reflection.cpp
src/native/vm/reflection.hpp
src/threads/thread.cpp
src/toolbox/logging.h
src/vm/Makefile.am
src/vm/access.c
src/vm/access.h
src/vm/annotation.h
src/vm/class.cpp
src/vm/class.hpp
src/vm/classcache.c [deleted file]
src/vm/classcache.cpp [new file with mode: 0644]
src/vm/classcache.h [deleted file]
src/vm/classcache.hpp [new file with mode: 0644]
src/vm/descriptor.h
src/vm/exceptions.cpp
src/vm/exceptions.hpp
src/vm/javaobjects.hpp
src/vm/jit/allocator/liveness.c
src/vm/jit/allocator/simplereg.c
src/vm/jit/argument.cpp
src/vm/jit/argument.hpp
src/vm/jit/code.hpp
src/vm/jit/codegen-common.cpp
src/vm/jit/codegen-common.hpp
src/vm/jit/inline/inline.cpp
src/vm/jit/intrp/intrp.h
src/vm/jit/jit.cpp
src/vm/jit/jit.hpp
src/vm/jit/jitcache.cpp
src/vm/jit/jitcache.hpp
src/vm/jit/linenumbertable.hpp
src/vm/jit/loop/graph.h
src/vm/jit/loop/loop.h
src/vm/jit/mips/md-abi.c
src/vm/jit/oprofile-agent.hpp
src/vm/jit/optimizing/escape.c
src/vm/jit/optimizing/escape.h
src/vm/jit/optimizing/ifconv.c
src/vm/jit/optimizing/lsra.c
src/vm/jit/optimizing/profile.c
src/vm/jit/optimizing/recompiler.cpp
src/vm/jit/optimizing/recompiler.hpp
src/vm/jit/replace.cpp
src/vm/jit/replace.hpp
src/vm/jit/stacktrace.cpp
src/vm/jit/stubs.cpp
src/vm/jit/stubs.hpp
src/vm/jit/trace.hpp
src/vm/linker.c
src/vm/loader.cpp
src/vm/loader.hpp
src/vm/method.c [deleted file]
src/vm/method.cpp [new file with mode: 0644]
src/vm/method.h [deleted file]
src/vm/method.hpp [new file with mode: 0644]
src/vm/properties.cpp
src/vm/references.h
src/vm/resolve.cpp
src/vm/resolve.hpp
src/vm/signal.c
src/vm/stackmap.c
src/vm/stackmap.h
src/vm/statistics.c
src/vm/suck.cpp
src/vm/vm.cpp
src/vm/vm.hpp
src/vm/zip.c [deleted file]
src/vm/zip.cpp [new file with mode: 0644]
src/vm/zip.h [deleted file]
src/vm/zip.hpp [new file with mode: 0644]

index ebafe09b0e8aaaa1051a3bf8b4dd928a8f7f5995..d6798b29a772bcf0390bcd22994a706db6250470 100644 (file)
@@ -30,7 +30,7 @@
 #include "vm/types.h"
 
 #include "toolbox/list.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* Global Variables ***********************************************************/
index 9267d7fdb791f9975b1c946e54e6bf58a27c9f81..5c01e9828bd744ce4ca55cd177aed98655da8a50 100644 (file)
@@ -33,7 +33,7 @@ typedef struct rootset_t rootset_t;
 
 #include "threads/thread.hpp"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/replace.hpp"
 
index 5e0d5e644c5f53b96e1c34d702273c122d94b92d..0a0791205e7cb1e8a18ad94bf4bdf250c072be7c 100644 (file)
@@ -130,7 +130,7 @@ enum {
 
 // Includes.
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* function prototypes ********************************************************/
index 5e4878c24b7cd5ad25aad5a87cebf043e7b3d716..e152104dc03727f421198320dcd9683368b92726 100644 (file)
@@ -46,7 +46,7 @@
 #include "vm/jit/builtin.hpp"
 #include "vm/jit/asmpart.h"
 #include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "mm/gc.hpp"
 #include "toolbox/logging.h"
 #include "vm/options.h"
index 41142d9dbbd11fb263951753b05f9e871a9b5b50..11e212e38f22995a4ab90118d8133c40e06ed821 100644 (file)
@@ -35,7 +35,7 @@ typedef struct localref_table localref_table;
 #include "vm/types.h"
 
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* localref_table **************************************************************
index 33e9ae9bfd6246a8f34a845c86257b38f18d1f40..c373e96f146f17071e694f86f6d79c4df262dc07 100644 (file)
@@ -39,7 +39,7 @@
 #include "vm/class.hpp"
 #include "vm/global.h"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/os.hpp"
 #include "vm/utf8.h"
 
index 3d53b2cbf52e5d11e6f9f20984500dcf315e50f5..2ece32fc4ba96ee68313b3df4e261b3dced6b02a 100644 (file)
@@ -49,7 +49,7 @@
 #include "vm/string.hpp"
 #include "vm/types.h"
 #include "vm/vm.hpp" /* REMOVE ME: temporarily */
-#include "vm/zip.h"
+#include "vm/zip.hpp"
 
 
 static java_handle_t* zip_read_resource(list_classpath_entry *lce, utf *name)
index 069b7dffe4c0882dbc3f562f0cf4afdb58171788..c706681c933a4dbe55691df719b83d62a2fb10a0 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "toolbox/logging.h"
 
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/utf8.h"
 #include "vm/vm.hpp"
 
index 0ad83bcde2b47390b6d148c00a0008c671e1d7b2..f04140ff3851ccf8a8e11ba35278b614af15f778 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "toolbox/logging.h"
 
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/utf8.h"
 #include "vm/vm.hpp"
 
index cc22d92b15f51f2c03dcbac2eecfdc68b013ea14..41bfe177945a698c4a16fd78f0d1020f5ad244fc 100644 (file)
@@ -48,7 +48,7 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
@@ -60,7 +60,7 @@
 #include "vm/statistics.h"
 #include "vm/string.hpp"
 #include "vm/vm.hpp"
-#include "vm/zip.h"
+#include "vm/zip.hpp"
 
 #include "vm/jit/asmpart.h"
 
index 61a20f73779d0f33909b504e45f416781758ce5c..7d345caa655a4173d9f7ae04df31418159c8d718 100644 (file)
@@ -49,7 +49,7 @@
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
 #include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/resolve.hpp"
 #include "vm/string.hpp"
 
index c3f356fa568d3ae1ff014c915e4075d610817322..a61f61920a7792201cf92bb3c1bcdad6c161d57b 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "vm/class.hpp"
 #include "vm/initialize.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/os.hpp"
 
index 0ed70979bee69b493f0791f248c3a3269286ebe1..7a63880bab9f37cf002a76c0fa07959a9a75e56f 100644 (file)
@@ -73,7 +73,7 @@
 #endif
 
 #include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
index c2745b9fbd3c1c0eaac1ae04b850039e207eb641..a26a50c4a300044e39992c83eef1c6b5a9bee74a 100644 (file)
@@ -43,7 +43,7 @@
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
 #include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/string.hpp"
 
 
index c4fe674e261db912eded548e089f848ebdd172d0..2901c0ffeaba72fcf0f69f27c35d6f8f4b1e58b9 100644 (file)
@@ -33,7 +33,7 @@
 #include "native/native.hpp"
 
 #include "vm/field.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 class Reflection {
index 6f83faf5b146b8afd2241359f0865ebd65808b1c..8804f6eb55f06e37d07a6925c0c23545b1beb187 100644 (file)
@@ -51,7 +51,7 @@
 #include "vm/exceptions.hpp"
 #include "vm/globals.hpp"
 #include "vm/javaobjects.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
 #include "vm/utf8.h"
index bb4970cd19b730c0603017905b7c838bad91f258..eed61bd8dd9173fbc10d2483de899d05c97366d7 100644 (file)
@@ -32,7 +32,7 @@
 #include <stdarg.h>
 
 #include "vm/class.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/utf8.h"
 
 
index de4ea00bdf8c3ba709d16169d05806045a9b99ae..829fed607d0331a7b25074685fc27001f03cb8b7 100644 (file)
@@ -65,8 +65,8 @@ endif
 
 if ENABLE_ZLIB
 ZLIB_SOURCES = \
-       zip.c \
-       zip.h
+       zip.cpp \
+       zip.hpp
 endif
 
 noinst_HEADERS = \
@@ -85,8 +85,8 @@ libvm_la_SOURCES = \
        $(ASSERTION_SOURCES) \
        class.cpp \
        class.hpp \
-       classcache.c \
-       classcache.h \
+       classcache.cpp \
+       classcache.hpp \
        $(CYCLES_STATS_SOURCES) \
        descriptor.c \
        descriptor.h \
@@ -106,8 +106,8 @@ libvm_la_SOURCES = \
        linker.h \
        loader.cpp \
        loader.hpp \
-       method.c \
-       method.h \
+       method.cpp \
+       method.hpp \
        options.c \
        options.h \
        os.cpp \
index bd21bd782ed64b02233cb2b79459579c888a886c..218cff611f40cf4c802186778e8bc0ae599212cd 100644 (file)
@@ -40,7 +40,7 @@
 #include "vm/exceptions.hpp"
 #include "vm/field.hpp"
 #include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/stacktrace.hpp"
 
index 59c6ef781d987d469081317fa735846b1f02e2d5..d1a51f8754e3b1408e0db97a12f6d564562403e4 100644 (file)
@@ -37,7 +37,7 @@ extern "C" {
 #include "vm/class.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* macros *********************************************************************/
index 6facf2d41ac74753182b622e3f484ac1062d7de0..2a8b11616e25ecfe5b6b2c71fda36486c6117d1d 100644 (file)
@@ -35,7 +35,7 @@
 #include "vm/field.hpp"
 #include "vm/global.h"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* function prototypes ********************************************************/
index 1e479529b61ce124f11a7ff33fa9b02a83a24cfe..9a229f11b189971c11e74319fcf188062ceffe1a 100644 (file)
@@ -46,7 +46,7 @@
 #include "vm/array.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
index f643fd357850d1398b12e49b132475afa0b220e7..2f52ed77bb237923ee3d7e13e23ac4b9e4006e18 100644 (file)
@@ -47,7 +47,7 @@ typedef struct extra_classref extra_classref;
 #include "vm/global.h"
 #include "vm/linker.h"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/string.hpp"
 #include "vm/utf8.h"
diff --git a/src/vm/classcache.c b/src/vm/classcache.c
deleted file mode 100644 (file)
index 6324f2a..0000000
+++ /dev/null
@@ -1,1586 +0,0 @@
-/* src/vm/classcache.c - loaded class cache and loading constraints
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#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 "vm/classcache.h"
-#include "vm/exceptions.hpp"
-#include "vm/options.h"
-#include "vm/utf8.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 */
-
-/*============================================================================*/
-/* STATISTICS                                                                 */
-/*============================================================================*/
-
-/*#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_COUNT(cnt)
-#define CLASSCACHE_COUNTIF(cond,cnt)
-#endif
-
-/*============================================================================*/
-/* THREAD-SAFE LOCKING                                                        */
-/*============================================================================*/
-
-       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-       /* CAUTION: The static functions below are */
-       /*          NOT synchronized!              */
-       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-#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()
-#endif
-
-/*============================================================================*/
-/* GLOBAL VARIABLES                                                           */
-/*============================================================================*/
-
-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 class cache
-
-   Note: NOT synchronized!
-  
-*******************************************************************************/
-
-bool classcache_init(void)
-{
-       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 *************************************************
-   Create a new classcache_loader_entry struct
-   (internally used helper function)
-  
-   IN:
-       loader...........the ClassLoader object
-          next.............the next classcache_loader_entry
-
-   RETURN VALUE:
-       the new classcache_loader_entry
-  
-*******************************************************************************/
-
-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;
-}
-
-/* classcache_merge_loaders ****************************************************
-   Merge two lists of loaders into one
-   (internally used helper function)
-  
-   IN:
-       lista............first list (may be NULL)
-          listb............second list (may be NULL)
-
-   RETURN VALUE:
-       the merged list (may be NULL)
-
-   NOTE:
-       The lists given as arguments are destroyed!
-  
-*******************************************************************************/
-
-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. */
-
-       result = NULL;
-       chain = &result;
-
-       for (ldenA = lista; ldenA; ldenA = ldenA->next) {
-
-               for (ldenB = listb; ldenB; ldenB = ldenB->next) {
-                       if (ldenB->loader == ldenA->loader)
-                               goto common_element;
-               }
-
-               /* this loader is only in lista */
-               *chain = ldenA;
-               chain = &(ldenA->next);
-
-         common_element:
-               /* XXX free the duplicated element */
-               ;
-       }
-
-       /* concat listb to the result */
-       *chain = listb;
-
-       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
-   (internally used helper function)
-   
-   IN:
-       name.............the name to look up
-  
-   RETURN VALUE:
-       a pointer to the classcache_name_entry for this name, or
-       null if no entry was found.
-          
-*******************************************************************************/
-
-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                  */
-
-       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) {
-               /* entry found in hashtable */
-               CLASSCACHE_COUNT(stat_lookup_name_entry);
-
-               if (c->name == name)
-                       return c;
-
-               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
-   if it is not already in the cache.
-   (internally used helper function)
-   
-   IN:
-       name.............the name to look up / create an entry for
-  
-   RETURN VALUE:
-       a pointer to the classcache_name_entry for this 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               */
-       u4 i;
-
-       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) {
-               /* entry found in hashtable */
-               CLASSCACHE_COUNT(stat_lookup_new_name_entry);
-
-               if (c->name == name)
-                       return c;
-
-               c = c->hashlink;                    /* next element in external chain */
-       }
-
-       /* location in hashtable found, create new entry */
-
-       c = NEW(classcache_name_entry);
-
-       c->name = name;
-       c->classes = NULL;
-
-       /* insert entry into hashtable */
-       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 */
-       hashtable_classcache.entries++;
-       CLASSCACHE_COUNT(stat_classnames_stored);
-
-       if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
-               /* reorganization of hashtable */ 
-
-               classcache_name_entry *c2;
-               hashtable newhash;              /* the new hashtable */
-
-               CLASSCACHE_COUNT(stat_rehash_names);
-
-               /* create new hashtable, double the size */
-
-               hashtable_create(&newhash, hashtable_classcache.size * 2);
-               newhash.entries = hashtable_classcache.entries;
-
-               /* transfer elements to new hashtable */
-
-               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(hashtable_classcache.ptr, void *, hashtable_classcache.size);
-               hashtable_classcache = newhash;
-       }
-
-       return c;
-}
-
-
-/* classcache_lookup ***********************************************************
-   Lookup a possibly loaded class
-  
-   IN:
-       initloader.......initiating loader for resolving the class name
-       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(classloader_t *initloader, utf *classname)
-{
-       classcache_name_entry *en;
-       classcache_class_entry *clsen;
-       classcache_loader_entry *lden;
-       classinfo *cls = NULL;
-
-       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) {
-                       CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
-                       /* check if this entry has been loaded by initloader */
-
-                       for (lden = clsen->loaders; lden; lden = lden->next) {
-                               CLASSCACHE_COUNT(stat_lookup_loader_checked);
-                               if (lden->loader == initloader) {
-                                       /* found the loaded class entry */
-
-                                       assert(clsen->classobj);
-                                       cls = clsen->classobj;
-                                       goto found;
-                               }
-                       }
-               }
-       }
-
-  found:
-       CLASSCACHE_UNLOCK();
-       return cls;
-}
-
-
-/* classcache_lookup_defined ***************************************************
-   Lookup a class with the given name and defining loader
-  
-   IN:
-       defloader........defining loader
-       classname........class name
-  
-   RETURN VALUE:
-       The return value is a pointer to the cached class object,
-       or NULL, if the class is not in the cache.
-   
-*******************************************************************************/
-
-classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
-{
-       classcache_name_entry *en;
-       classcache_class_entry *clsen;
-       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) {
-                       if (!clsen->classobj)
-                               continue;
-
-                       /* check if this entry has been defined by defloader */
-                       if (clsen->classobj->classloader == defloader) {
-                               cls = clsen->classobj;
-                               goto 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. 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:
-       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
-   
-*******************************************************************************/
-
-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;
-#ifdef CLASSCACHE_VERBOSE
-       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);
-
-       assert(en);
-
-       /* iterate over all class entries */
-       for (clsen = en->classes; clsen; clsen = clsen->next) {
-
-               /* check if this entry has already been loaded by initloader */
-               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) {
-                       if (lden->loader == initloader) {
-                               /* 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);
-
-                               /* 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 */
-       /* initiating loader initloader                        */
-
-       clsen = NEW(classcache_class_entry);
-       clsen->classobj = cls;
-       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:
-#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;
-
-       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 cls;
-}
-
-/* classcache_find_loader ******************************************************
-   Find the class entry loaded by or constrained to a given loader
-   (internally used helper function)
-  
-   IN:
-       entry............the classcache_name_entry
-       loader...........the loader to look for
-  
-   RETURN VALUE:
-       the classcache_class_entry for the given loader, or
-          NULL if no entry was found
-   
-*******************************************************************************/
-
-static classcache_class_entry * classcache_find_loader(
-                                                                       classcache_name_entry * entry,
-                                                                       classloader_t * loader)
-{
-       classcache_class_entry *clsen;
-       classcache_loader_entry *lden;
-
-       assert(entry);
-
-       /* iterate over all class entries */
-       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) {
-                       if (lden->loader == loader)
-                               return clsen;   /* found */
-               }
-
-               /* check if loader is constrained to this entry */
-               for (lden = clsen->constraints; lden; lden = lden->next) {
-                       if (lden->loader == loader)
-                               return clsen;   /* found */
-               }
-       }
-
-       /* not found */
-       return NULL;
-}
-
-/* classcache_free_class_entry *************************************************
-   Free the memory used by a class entry
-  
-   IN:
-       clsen............the classcache_class_entry to free  
-          
-*******************************************************************************/
-
-static void classcache_free_class_entry(classcache_class_entry * clsen)
-{
-       classcache_loader_entry *lden;
-       classcache_loader_entry *next;
-
-       assert(clsen);
-
-       for (lden = clsen->loaders; lden; lden = next) {
-               next = lden->next;
-               FREE(lden, classcache_loader_entry);
-       }
-       for (lden = clsen->constraints; lden; lden = next) {
-               next = lden->next;
-               FREE(lden, classcache_loader_entry);
-       }
-
-       FREE(clsen, classcache_class_entry);
-}
-
-/* classcache_remove_class_entry ***********************************************
-   Remove a classcache_class_entry from the list of possible resolution of
-   a name entry
-   (internally used helper function)
-  
-   IN:
-       entry............the classcache_name_entry
-       clsen............the classcache_class_entry to remove
-  
-*******************************************************************************/
-
-static void classcache_remove_class_entry(classcache_name_entry * entry,
-                                                                                 classcache_class_entry * clsen)
-{
-       classcache_class_entry **chain;
-
-       assert(entry);
-       assert(clsen);
-
-       chain = &(entry->classes);
-       while (*chain) {
-               if (*chain == clsen) {
-                       *chain = clsen->next;
-                       classcache_free_class_entry(clsen);
-                       return;
-               }
-               chain = &((*chain)->next);
-       }
-}
-
-/* classcache_free_name_entry **************************************************
-   Free the memory used by a name entry
-  
-   IN:
-       entry............the classcache_name_entry to free  
-          
-*******************************************************************************/
-
-static void classcache_free_name_entry(classcache_name_entry * entry)
-{
-       classcache_class_entry *clsen;
-       classcache_class_entry *next;
-
-       assert(entry);
-
-       for (clsen = entry->classes; clsen; clsen = next) {
-               next = clsen->next;
-               classcache_free_class_entry(clsen);
-       }
-
-       FREE(entry, classcache_name_entry);
-}
-
-/* classcache_free *************************************************************
-   Free the memory used by the class cache
-
-   NOTE:
-       The class cache may not be used any more after this call, except
-          when it is reinitialized with classcache_init.
-  
-   Note: NOT synchronized!
-  
-*******************************************************************************/
-
-void classcache_free(void)
-{
-       u4 slot;
-       classcache_name_entry *entry;
-       classcache_name_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(hashtable_classcache.ptr, void*, hashtable_classcache.size);
-       hashtable_classcache.size = 0;
-       hashtable_classcache.entries = 0;
-       hashtable_classcache.ptr = NULL;
-}
-
-/* classcache_add_constraint ***************************************************
-   Add a loading constraint
-  
-   IN:
-       a................first initiating loader
-       b................second initiating loader
-       classname........class name
-  
-   RETURN VALUE:
-       true.............everything ok, the constraint has been added,
-       false............an exception has been thrown.
-   
-   Note: synchronized with global tablelock
-   
-*******************************************************************************/
-
-#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;
-
-       assert(classname);
-
-#ifdef CLASSCACHE_VERBOSE
-       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) {
-               CLASSCACHE_COUNT(stat_trivial_constraints);
-               return true;
-       }
-
-       CLASSCACHE_LOCK();
-
-       en = classcache_new_name(classname);
-
-       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);
-
-       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) {
-                       /* no, the constraint is violated */
-                       exceptions_throw_linkageerror("loading constraint violated: ",
-                                                                                 clsenA->classobj);
-                       goto return_exception;
-               }
-
-               /* yes, merge the entries */
-               classcache_merge_class_entries(en,clsenA,clsenB);
-               CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
-       }
-       else {
-               /* { at most one of the loaders has a corresponding entry } */
-
-               /* set clsenA to the single class entry we have */
-               if (!clsenA)
-                       clsenA = clsenB;
-
-               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->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);
-               }
-       }
-
-  return_success:
-       CLASSCACHE_UNLOCK();
-       return true;
-
-  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();
-}
-#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                                                                */
-/*============================================================================*/
-
-/* classcache_debug_dump *******************************************************
-   Print the contents of the loaded class cache to a stream
-  
-   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
-   
-*******************************************************************************/
-
-#ifndef NDEBUG
-void classcache_debug_dump(FILE * file,utf *only)
-{
-       classcache_name_entry *c;
-       classcache_class_entry *clsen;
-       classcache_loader_entry *lden;
-       u4 slot;
-
-       CLASSCACHE_LOCK();
-
-       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("");
-
-       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];
-
-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) {
-                               if (clsen->classobj) {
-                                       log_println("    loaded %p", (void *) clsen->classobj);
-                               }
-                               else {
-                                       log_println("    unresolved");
-                               }
-
-                               log_start();
-                               log_print("        loaders: ");
-                               for (lden = clsen->loaders; lden; lden = lden->next) {
-                                       log_print("<%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);
-                               }
-                               log_finish();
-                       }
-               }
-
-               if (only)
-                       break;
-       }
-       fprintf(file, "\n==============================================================\n\n");
-
-       CLASSCACHE_UNLOCK();
-}
-#endif /* NDEBUG */
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/classcache.cpp b/src/vm/classcache.cpp
new file mode 100644 (file)
index 0000000..5458ec8
--- /dev/null
@@ -0,0 +1,1595 @@
+/* src/vm/classcache.cpp - loaded class cache and loading constraints
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#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 "vm/classcache.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/options.h"
+#include "vm/utf8.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 */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*============================================================================*/
+/* STATISTICS                                                                 */
+/*============================================================================*/
+
+/*#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_COUNT(cnt)
+#define CLASSCACHE_COUNTIF(cond,cnt)
+#endif
+
+/*============================================================================*/
+/* THREAD-SAFE LOCKING                                                        */
+/*============================================================================*/
+
+       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+       /* CAUTION: The static functions below are */
+       /*          NOT synchronized!              */
+       /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+#if defined(ENABLE_THREADS)
+# define CLASSCACHE_LOCK()      classcache_hashtable_mutex->lock();
+# define CLASSCACHE_UNLOCK()    classcache_hashtable_mutex->unlock();
+#else
+# define CLASSCACHE_LOCK()
+# define CLASSCACHE_UNLOCK()
+#endif
+
+/*============================================================================*/
+/* GLOBAL VARIABLES                                                           */
+/*============================================================================*/
+
+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 class cache
+
+   Note: NOT synchronized!
+  
+*******************************************************************************/
+
+bool classcache_init(void)
+{
+       TRACESUBSYSTEMINITIALIZATION("classcache_init");
+
+       /* create the hashtable */
+
+       hashtable_create(&hashtable_classcache, CLASSCACHE_INIT_SIZE);
+
+#if defined(ENABLE_THREADS)
+       /* create utf hashtable mutex */
+
+       classcache_hashtable_mutex = new Mutex();
+#endif
+
+       /* everything's ok */
+
+       return true;
+}
+
+/* classcache_new_loader_entry *************************************************
+   Create a new classcache_loader_entry struct
+   (internally used helper function)
+  
+   IN:
+       loader...........the ClassLoader object
+          next.............the next classcache_loader_entry
+
+   RETURN VALUE:
+       the new classcache_loader_entry
+  
+*******************************************************************************/
+
+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;
+}
+
+/* classcache_merge_loaders ****************************************************
+   Merge two lists of loaders into one
+   (internally used helper function)
+  
+   IN:
+       lista............first list (may be NULL)
+          listb............second list (may be NULL)
+
+   RETURN VALUE:
+       the merged list (may be NULL)
+
+   NOTE:
+       The lists given as arguments are destroyed!
+  
+*******************************************************************************/
+
+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. */
+
+       result = NULL;
+       chain = &result;
+
+       for (ldenA = lista; ldenA; ldenA = ldenA->next) {
+
+               for (ldenB = listb; ldenB; ldenB = ldenB->next) {
+                       if (ldenB->loader == ldenA->loader)
+                               goto common_element;
+               }
+
+               /* this loader is only in lista */
+               *chain = ldenA;
+               chain = &(ldenA->next);
+
+         common_element:
+               /* XXX free the duplicated element */
+               ;
+       }
+
+       /* concat listb to the result */
+       *chain = listb;
+
+       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
+   (internally used helper function)
+   
+   IN:
+       name.............the name to look up
+  
+   RETURN VALUE:
+       a pointer to the classcache_name_entry for this name, or
+       null if no entry was found.
+          
+*******************************************************************************/
+
+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                  */
+
+       CLASSCACHE_COUNT(stat_lookup_name);
+
+       key  = CLASSCACHE_HASH(name->text, (u4) name->blength);
+       slot = key & (hashtable_classcache.size - 1);
+       c    = (classcache_name_entry*) hashtable_classcache.ptr[slot];
+
+       /* search external hash chain for the entry */
+
+       while (c) {
+               /* entry found in hashtable */
+               CLASSCACHE_COUNT(stat_lookup_name_entry);
+
+               if (c->name == name)
+                       return c;
+
+               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
+   if it is not already in the cache.
+   (internally used helper function)
+   
+   IN:
+       name.............the name to look up / create an entry for
+  
+   RETURN VALUE:
+       a pointer to the classcache_name_entry for this 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               */
+       u4 i;
+
+       CLASSCACHE_COUNT(stat_lookup_new_name);
+
+       key  = CLASSCACHE_HASH(name->text, (u4) name->blength);
+       slot = key & (hashtable_classcache.size - 1);
+       c    = (classcache_name_entry*) hashtable_classcache.ptr[slot];
+
+       /* search external hash chain for the entry */
+
+       while (c) {
+               /* entry found in hashtable */
+               CLASSCACHE_COUNT(stat_lookup_new_name_entry);
+
+               if (c->name == name)
+                       return c;
+
+               c = c->hashlink;                    /* next element in external chain */
+       }
+
+       /* location in hashtable found, create new entry */
+
+       c = NEW(classcache_name_entry);
+
+       c->name = name;
+       c->classes = NULL;
+
+       /* insert entry into hashtable */
+       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 */
+       hashtable_classcache.entries++;
+       CLASSCACHE_COUNT(stat_classnames_stored);
+
+       if ((hashtable_classcache.entries*2) > hashtable_classcache.size) {
+               /* reorganization of hashtable */ 
+
+               classcache_name_entry *c2;
+               hashtable newhash;              /* the new hashtable */
+
+               CLASSCACHE_COUNT(stat_rehash_names);
+
+               /* create new hashtable, double the size */
+
+               hashtable_create(&newhash, hashtable_classcache.size * 2);
+               newhash.entries = hashtable_classcache.entries;
+
+               /* transfer elements to new hashtable */
+
+               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(hashtable_classcache.ptr, void *, hashtable_classcache.size);
+               hashtable_classcache = newhash;
+       }
+
+       return c;
+}
+
+
+/* classcache_lookup ***********************************************************
+   Lookup a possibly loaded class
+  
+   IN:
+       initloader.......initiating loader for resolving the class name
+       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(classloader_t *initloader, utf *classname)
+{
+       classcache_name_entry *en;
+       classcache_class_entry *clsen;
+       classcache_loader_entry *lden;
+       classinfo *cls = NULL;
+
+       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) {
+                       CLASSCACHE_COUNT(stat_lookup_class_entry_checked);
+                       /* check if this entry has been loaded by initloader */
+
+                       for (lden = clsen->loaders; lden; lden = lden->next) {
+                               CLASSCACHE_COUNT(stat_lookup_loader_checked);
+                               if (lden->loader == initloader) {
+                                       /* found the loaded class entry */
+
+                                       assert(clsen->classobj);
+                                       cls = clsen->classobj;
+                                       goto found;
+                               }
+                       }
+               }
+       }
+
+  found:
+       CLASSCACHE_UNLOCK();
+       return cls;
+}
+
+
+/* classcache_lookup_defined ***************************************************
+   Lookup a class with the given name and defining loader
+  
+   IN:
+       defloader........defining loader
+       classname........class name
+  
+   RETURN VALUE:
+       The return value is a pointer to the cached class object,
+       or NULL, if the class is not in the cache.
+   
+*******************************************************************************/
+
+classinfo *classcache_lookup_defined(classloader_t *defloader, utf *classname)
+{
+       classcache_name_entry *en;
+       classcache_class_entry *clsen;
+       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) {
+                       if (!clsen->classobj)
+                               continue;
+
+                       /* check if this entry has been defined by defloader */
+                       if (clsen->classobj->classloader == defloader) {
+                               cls = clsen->classobj;
+                               goto 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. 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:
+       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
+   
+*******************************************************************************/
+
+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;
+#ifdef CLASSCACHE_VERBOSE
+       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);
+
+       assert(en);
+
+       /* iterate over all class entries */
+       for (clsen = en->classes; clsen; clsen = clsen->next) {
+
+               /* check if this entry has already been loaded by initloader */
+               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) {
+                       if (lden->loader == initloader) {
+                               /* 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);
+
+                               /* 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 */
+       /* initiating loader initloader                        */
+
+       clsen = NEW(classcache_class_entry);
+       clsen->classobj = cls;
+       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:
+#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;
+
+       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 cls;
+}
+
+/* classcache_find_loader ******************************************************
+   Find the class entry loaded by or constrained to a given loader
+   (internally used helper function)
+  
+   IN:
+       entry............the classcache_name_entry
+       loader...........the loader to look for
+  
+   RETURN VALUE:
+       the classcache_class_entry for the given loader, or
+          NULL if no entry was found
+   
+*******************************************************************************/
+
+static classcache_class_entry * classcache_find_loader(
+                                                                       classcache_name_entry * entry,
+                                                                       classloader_t * loader)
+{
+       classcache_class_entry *clsen;
+       classcache_loader_entry *lden;
+
+       assert(entry);
+
+       /* iterate over all class entries */
+       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) {
+                       if (lden->loader == loader)
+                               return clsen;   /* found */
+               }
+
+               /* check if loader is constrained to this entry */
+               for (lden = clsen->constraints; lden; lden = lden->next) {
+                       if (lden->loader == loader)
+                               return clsen;   /* found */
+               }
+       }
+
+       /* not found */
+       return NULL;
+}
+
+/* classcache_free_class_entry *************************************************
+   Free the memory used by a class entry
+  
+   IN:
+       clsen............the classcache_class_entry to free  
+          
+*******************************************************************************/
+
+static void classcache_free_class_entry(classcache_class_entry * clsen)
+{
+       classcache_loader_entry *lden;
+       classcache_loader_entry *next;
+
+       assert(clsen);
+
+       for (lden = clsen->loaders; lden; lden = next) {
+               next = lden->next;
+               FREE(lden, classcache_loader_entry);
+       }
+       for (lden = clsen->constraints; lden; lden = next) {
+               next = lden->next;
+               FREE(lden, classcache_loader_entry);
+       }
+
+       FREE(clsen, classcache_class_entry);
+}
+
+/* classcache_remove_class_entry ***********************************************
+   Remove a classcache_class_entry from the list of possible resolution of
+   a name entry
+   (internally used helper function)
+  
+   IN:
+       entry............the classcache_name_entry
+       clsen............the classcache_class_entry to remove
+  
+*******************************************************************************/
+
+static void classcache_remove_class_entry(classcache_name_entry * entry,
+                                                                                 classcache_class_entry * clsen)
+{
+       classcache_class_entry **chain;
+
+       assert(entry);
+       assert(clsen);
+
+       chain = &(entry->classes);
+       while (*chain) {
+               if (*chain == clsen) {
+                       *chain = clsen->next;
+                       classcache_free_class_entry(clsen);
+                       return;
+               }
+               chain = &((*chain)->next);
+       }
+}
+
+/* classcache_free_name_entry **************************************************
+   Free the memory used by a name entry
+  
+   IN:
+       entry............the classcache_name_entry to free  
+          
+*******************************************************************************/
+
+static void classcache_free_name_entry(classcache_name_entry * entry)
+{
+       classcache_class_entry *clsen;
+       classcache_class_entry *next;
+
+       assert(entry);
+
+       for (clsen = entry->classes; clsen; clsen = next) {
+               next = clsen->next;
+               classcache_free_class_entry(clsen);
+       }
+
+       FREE(entry, classcache_name_entry);
+}
+
+/* classcache_free *************************************************************
+   Free the memory used by the class cache
+
+   NOTE:
+       The class cache may not be used any more after this call, except
+          when it is reinitialized with classcache_init.
+  
+   Note: NOT synchronized!
+  
+*******************************************************************************/
+
+void classcache_free(void)
+{
+       u4 slot;
+       classcache_name_entry *entry;
+       classcache_name_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(hashtable_classcache.ptr, void*, hashtable_classcache.size);
+       hashtable_classcache.size = 0;
+       hashtable_classcache.entries = 0;
+       hashtable_classcache.ptr = NULL;
+}
+
+/* classcache_add_constraint ***************************************************
+   Add a loading constraint
+  
+   IN:
+       a................first initiating loader
+       b................second initiating loader
+       classname........class name
+  
+   RETURN VALUE:
+       true.............everything ok, the constraint has been added,
+       false............an exception has been thrown.
+   
+   Note: synchronized with global tablelock
+   
+*******************************************************************************/
+
+#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;
+
+       assert(classname);
+
+#ifdef CLASSCACHE_VERBOSE
+       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) {
+               CLASSCACHE_COUNT(stat_trivial_constraints);
+               return true;
+       }
+
+       CLASSCACHE_LOCK();
+
+       en = classcache_new_name(classname);
+
+       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);
+
+       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) {
+                       /* no, the constraint is violated */
+                       exceptions_throw_linkageerror("loading constraint violated: ",
+                                                                                 clsenA->classobj);
+                       goto return_exception;
+               }
+
+               /* yes, merge the entries */
+               classcache_merge_class_entries(en,clsenA,clsenB);
+               CLASSCACHE_COUNT(stat_nontriv_constraints_merged);
+       }
+       else {
+               /* { at most one of the loaders has a corresponding entry } */
+
+               /* set clsenA to the single class entry we have */
+               if (!clsenA)
+                       clsenA = clsenB;
+
+               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->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);
+               }
+       }
+
+  return_success:
+       CLASSCACHE_UNLOCK();
+       return true;
+
+  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 = (classcache_name_entry*) 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();
+}
+#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 = (classcache_name_entry*) 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                                                                */
+/*============================================================================*/
+
+/* classcache_debug_dump *******************************************************
+   Print the contents of the loaded class cache to a stream
+  
+   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
+   
+*******************************************************************************/
+
+#ifndef NDEBUG
+void classcache_debug_dump(FILE * file,utf *only)
+{
+       classcache_name_entry *c;
+       classcache_class_entry *clsen;
+       classcache_loader_entry *lden;
+       u4 slot;
+
+       CLASSCACHE_LOCK();
+
+       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("");
+
+       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];
+
+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) {
+                               if (clsen->classobj) {
+                                       log_println("    loaded %p", (void *) clsen->classobj);
+                               }
+                               else {
+                                       log_println("    unresolved");
+                               }
+
+                               log_start();
+                               log_print("        loaders: ");
+                               for (lden = clsen->loaders; lden; lden = lden->next) {
+                                       log_print("<%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);
+                               }
+                               log_finish();
+                       }
+               }
+
+               if (only)
+                       break;
+       }
+       fprintf(file, "\n==============================================================\n\n");
+
+       CLASSCACHE_UNLOCK();
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* NDEBUG */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/classcache.h b/src/vm/classcache.h
deleted file mode 100644 (file)
index 88d7a44..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/* src/vm/classcache.h - loaded class cache and loading constraints
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#ifndef _CLASSCACHE_H
-#define _CLASSCACHE_H
-
-#include "config.h"
-
-#include "vm/types.h"
-
-#include <stdio.h>  /* for FILE */
-
-#include "toolbox/hashtable.h"
-
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/loader.hpp"
-#include "vm/references.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* forward declarations *******************************************************/
-
-typedef struct classcache_name_entry classcache_name_entry;
-typedef struct classcache_class_entry classcache_class_entry;
-typedef struct classcache_loader_entry classcache_loader_entry;
-
-/* global variables ***********************************************************/
-
-extern hashtable hashtable_classcache;
-
-
-/* structs ********************************************************************/
-
-/*----------------------------------------------------------------------------*/
-/* The Loaded Class Cache                                                     */
-/*                                                                            */
-/* The loaded class cache is implemented as a two-level data structure.       */
-/*                                                                            */
-/* The first level is a hash table indexed by class names. For each class     */
-/* name in the cache there is a classcache_name_entry, which collects all     */
-/* information about classes with this class name.                            */
-/*                                                                            */
-/* Second level: For each classcache_name_entry there is a list of            */
-/* classcache_class_entry:s representing the possible different resolutions   */
-/* of the class name.                                                         */
-/*                                                                            */
-/* A classcache_class_entry records the following:                            */
-/*                                                                            */
-/* - the loaded class object, if this entry has been resolved, otherwise NULL */
-/* - the list of initiating loaders which have resolved the class name to     */
-/*   this class object                                                        */
-/* - the list of initiating loaders which are constrained to resolve this     */
-/*   class name to this class object in the future                            */
-/*                                                                            */
-/* The classcache_class_entry:s approximate the equivalence classes created   */
-/* by the loading constraints and the equivalence of loaded classes.          */
-/*                                                                            */
-/* When a loading constraint (loaderA,loaderB,NAME) is added, then the        */
-/* classcache_class_entry:s for NAME containing loaderA and loaderB resp.     */
-/* must be merged into one entry. If this is impossible, because the entries  */
-/* have already been resolved to different class objects, then the constraint */
-/* is violated and an expception must be thrown.                              */
-/*----------------------------------------------------------------------------*/
-
-
-/* classcache_name_entry
- *
- * For each classname a classcache_name_entry struct is created.
- */
-
-struct classcache_name_entry
-{
-       utf                     *name;        /* class name                       */
-       classcache_name_entry   *hashlink;    /* link for external chaining       */
-       classcache_class_entry  *classes;     /* equivalence classes for this name*/
-};
-
-struct classcache_class_entry
-{
-       classinfo               *classobj;    /* the loaded class object, or NULL */
-       classcache_loader_entry *loaders;
-       classcache_loader_entry *constraints;
-       classcache_class_entry  *next;        /* next class entry for same name   */
-};
-
-struct classcache_loader_entry
-{
-       classloader_t            *loader;     /* class loader object              */
-       classcache_loader_entry  *next;       /* next loader entry in the list    */
-};
-
-
-/* callback function type for  classcache_foreach_loaded_class */
-
-typedef void (*classcache_foreach_functionptr_t)(classinfo *, void *);
-
-
-/* function prototypes ********************************************************/
-
-/* initialize the loaded class cache */
-bool classcache_init(void);
-void classcache_free(void);
-
-classinfo * classcache_lookup(classloader_t *initloader,utf *classname);
-classinfo * classcache_lookup_defined(classloader_t *defloader,utf *classname);
-classinfo * classcache_lookup_defined_or_initiated(classloader_t *loader,utf *classname);
-
-bool classcache_store_unique(classinfo *cls);
-classinfo * classcache_store(classloader_t *initloader,classinfo *cls,bool mayfree);
-classinfo * classcache_store_defined(classinfo *cls);
-
-#if defined(ENABLE_VERIFIER)
-bool classcache_add_constraint(classloader_t *a,classloader_t *b,utf *classname);
-bool classcache_add_constraints_for_params(classloader_t *a,classloader_t *b,
-                                                                                  methodinfo *m);
-#endif
-
-s4 classcache_get_loaded_class_count(void);
-
-void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
-                                                                        void *data);
-
-#if defined(ENABLE_JVMTI)
-void classcache_get_loaded_classes(s4 *class_count_ptr,
-                                                                  classinfo ***classes_ptr);
-#endif
-
-#ifndef NDEBUG
-void classcache_debug_dump(FILE *file,utf *only);
-#endif
-       
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _CLASSCACHE_H */
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
-
diff --git a/src/vm/classcache.hpp b/src/vm/classcache.hpp
new file mode 100644 (file)
index 0000000..84ba736
--- /dev/null
@@ -0,0 +1,177 @@
+/* src/vm/classcache.hpp - loaded class cache and loading constraints
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#ifndef _CLASSCACHE_H
+#define _CLASSCACHE_H
+
+#include "config.h"
+
+#include "vm/types.h"
+
+#include <stdio.h>  /* for FILE */
+
+#include "toolbox/hashtable.h"
+
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/loader.hpp"
+#include "vm/references.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* forward declarations *******************************************************/
+
+typedef struct classcache_name_entry classcache_name_entry;
+typedef struct classcache_class_entry classcache_class_entry;
+typedef struct classcache_loader_entry classcache_loader_entry;
+
+/* global variables ***********************************************************/
+
+extern hashtable hashtable_classcache;
+
+
+/* structs ********************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* The Loaded Class Cache                                                     */
+/*                                                                            */
+/* The loaded class cache is implemented as a two-level data structure.       */
+/*                                                                            */
+/* The first level is a hash table indexed by class names. For each class     */
+/* name in the cache there is a classcache_name_entry, which collects all     */
+/* information about classes with this class name.                            */
+/*                                                                            */
+/* Second level: For each classcache_name_entry there is a list of            */
+/* classcache_class_entry:s representing the possible different resolutions   */
+/* of the class name.                                                         */
+/*                                                                            */
+/* A classcache_class_entry records the following:                            */
+/*                                                                            */
+/* - the loaded class object, if this entry has been resolved, otherwise NULL */
+/* - the list of initiating loaders which have resolved the class name to     */
+/*   this class object                                                        */
+/* - the list of initiating loaders which are constrained to resolve this     */
+/*   class name to this class object in the future                            */
+/*                                                                            */
+/* The classcache_class_entry:s approximate the equivalence classes created   */
+/* by the loading constraints and the equivalence of loaded classes.          */
+/*                                                                            */
+/* When a loading constraint (loaderA,loaderB,NAME) is added, then the        */
+/* classcache_class_entry:s for NAME containing loaderA and loaderB resp.     */
+/* must be merged into one entry. If this is impossible, because the entries  */
+/* have already been resolved to different class objects, then the constraint */
+/* is violated and an expception must be thrown.                              */
+/*----------------------------------------------------------------------------*/
+
+
+/* classcache_name_entry
+ *
+ * For each classname a classcache_name_entry struct is created.
+ */
+
+struct classcache_name_entry
+{
+       utf                     *name;        /* class name                       */
+       classcache_name_entry   *hashlink;    /* link for external chaining       */
+       classcache_class_entry  *classes;     /* equivalence classes for this name*/
+};
+
+struct classcache_class_entry
+{
+       classinfo               *classobj;    /* the loaded class object, or NULL */
+       classcache_loader_entry *loaders;
+       classcache_loader_entry *constraints;
+       classcache_class_entry  *next;        /* next class entry for same name   */
+};
+
+struct classcache_loader_entry
+{
+       classloader_t            *loader;     /* class loader object              */
+       classcache_loader_entry  *next;       /* next loader entry in the list    */
+};
+
+
+/* callback function type for  classcache_foreach_loaded_class */
+
+typedef void (*classcache_foreach_functionptr_t)(classinfo *, void *);
+
+
+/* function prototypes ********************************************************/
+
+/* initialize the loaded class cache */
+bool classcache_init(void);
+void classcache_free(void);
+
+classinfo * classcache_lookup(classloader_t *initloader,utf *classname);
+classinfo * classcache_lookup_defined(classloader_t *defloader,utf *classname);
+classinfo * classcache_lookup_defined_or_initiated(classloader_t *loader,utf *classname);
+
+bool classcache_store_unique(classinfo *cls);
+classinfo * classcache_store(classloader_t *initloader,classinfo *cls,bool mayfree);
+classinfo * classcache_store_defined(classinfo *cls);
+
+#if defined(ENABLE_VERIFIER)
+bool classcache_add_constraint(classloader_t *a,classloader_t *b,utf *classname);
+bool classcache_add_constraints_for_params(classloader_t *a,classloader_t *b,
+                                                                                  methodinfo *m);
+#endif
+
+s4 classcache_get_loaded_class_count(void);
+
+void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
+                                                                        void *data);
+
+#if defined(ENABLE_JVMTI)
+void classcache_get_loaded_classes(s4 *class_count_ptr,
+                                                                  classinfo ***classes_ptr);
+#endif
+
+#ifndef NDEBUG
+void classcache_debug_dump(FILE *file,utf *only);
+#endif
+       
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CLASSCACHE_H */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+
index a93f3f965cfae6025a76623fa1f4189cdd5f016a..bf6c69efb458d7d3360f72bf23170af3b75a18a7 100644 (file)
@@ -44,7 +44,7 @@ typedef struct methoddesc      methoddesc;
 
 #include "vm/class.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/utf8.h"
 
index a337beaeb6a3eea47f349102fdc668775d257bea..5f01f221ec791b015e8ce58e33dd7847429057a4 100644 (file)
@@ -52,7 +52,7 @@
 #include "vm/globals.hpp"
 #include "vm/javaobjects.hpp"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/os.hpp"
 #include "vm/string.hpp"
index 924679b7d96d049f3a32945ef869e600b89335fa..564ffff9f6f394d44c70802a73ecf4ad7e24aa24 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "vm/global.h"
 #include "vm/references.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* function prototypes ********************************************************/
index dc336cc76d9d1548a4b68779864f3ea0bcdf5747..f53021823dc92506107df2aba9a4c5834c4520e8 100644 (file)
@@ -39,7 +39,7 @@
 #include "vm/field.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 #ifdef __cplusplus
index d6bd012daef27a221039a5791988562dfa181ff5..de94a0f44dec49e543d95311902a3a1898488ea5 100644 (file)
@@ -38,7 +38,7 @@
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/resolve.hpp"
 #include "vm/jit/codegen-common.hpp"
 #include "vm/jit/jit.hpp"
index d1f63af188ae957816b2ca16c77db2ceaa72305b..f852229bf0b426b63f880ffa5ba7d9ab80314d06 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/resolve.hpp"
 #include "vm/string.hpp"
index a340cf5663552d1a4644ebe8b9cdd120645c8a29..a670883d6c6fce869f976adb1afdc5e344abae3e 100644 (file)
@@ -37,7 +37,7 @@
 #include "vm/array.hpp"
 #include "vm/descriptor.h"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/primitive.hpp"
 #include "vm/resolve.hpp"
 #include "vm/vm.hpp"
index 07ca62d5a52e4be41889bd89d37c39dcf0cbc67e..29c41360adf84391a47556d6ab5a9ad135aa1c4a 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdint.h>
 
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* function prototypes ********************************************************/
index fcdb08c686b06ecaf75b4e3a0973751e32e24dfb..51d2912939276c6f2e50f1e5d2add74445da817a 100644 (file)
@@ -36,7 +36,7 @@
 #include "toolbox/list.hpp"
 
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/exceptiontable.h"
 #if defined (ENABLE_JITCACHE)
index 47ad041c746bba5c21f8d237ba258fea267d6ee2..1ecbef32681cd84ad1f8a666a7512b47af89e657 100644 (file)
@@ -67,7 +67,7 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
 
index 8e676a495cc685f93f96b8cb065e8d3b621764be..98a7142369cf3284f97950090543d139d9398cae 100644 (file)
@@ -43,7 +43,7 @@ typedef struct dataref                dataref;
 #include "vm/jit/builtin.hpp"
 #include "vm/descriptor.h"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 
 #include "vm/jit/dseg.h"
index 2ba9156c2181739cdad0fd9409a9f7ea3b853a65..cb6d37cb701ca79ce1ba45554f7a534dab522a77 100644 (file)
@@ -44,7 +44,7 @@
 #include "vm/class.hpp"
 #include "vm/global.h"
 #include "vm/initialize.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/statistics.h"
 
index 03073954cc44247fa5120a284358b4abb0eece89..7c74c9a87644280a15abc4708ab204f756ceb950 100644 (file)
@@ -47,7 +47,7 @@ typedef s4 Cell;
 #include "vm/class.hpp"
 #include "vm/global.h"
 #include "vm/linker.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/resolve.hpp"
 
index 9817434123bc731352d8e634a7fa397eb926807b..ffd17e37b8d6b732133acafccd521e991cc64e35 100644 (file)
@@ -45,7 +45,7 @@
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/rt-timing.h"
 #include "vm/statistics.h"
index ecbb865cf24c3e297a1d196a7c4f117c0e78b761..6aab8851ecc9c302fdb745ac19bbb3d1a4916d6f 100644 (file)
@@ -37,7 +37,7 @@ typedef struct exception_entry exception_entry;
 #include "vm/types.h"
 
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/resolve.hpp"
 
index 6a38ccc04ed0644bf871dad85b77641d363355d7..124d0397345c11f22ec163c41acf05a005701199 100644 (file)
@@ -58,7 +58,7 @@ extern "C" {
 #include "mm/memory.h"
 #include "mm/codememory.h"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/resolve.hpp"
 #include "vm/types.h"
index 513aa5c3631345f37bb3c9427fa52a6021085f53..c40d1b4bd841ac818a4ae73a06929901e626b9fc 100644 (file)
@@ -38,7 +38,7 @@ extern "C" {
 #include <stdint.h>
 
 #include "vm/class.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 typedef enum cachedreftype {
        CRT_CODEINFO,
index 0d6143e171f21f36ab484a76a66004ba2d5d90ce..799a1c62eb1e84871eeae7a3fcffe2f51c40cdbe 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "toolbox/list.hpp"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/jit.hpp"
 #include "vm/jit/code.hpp"
index 2f597848506c9908b2cdf6417987b5ae6cb45cc7..320ceb582be797ba9f511dce9d3e8fe6bf4da8f1 100644 (file)
@@ -29,7 +29,7 @@
 #include "config.h"
 #include "vm/types.h"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/loop/loop.h"
 
index 0a2eaa54affa43b9861c776aec7223e1c88ab1b5..11080de743d04406f007582b8a6c00c9ce0f0422 100644 (file)
@@ -30,7 +30,7 @@
 #include "vm/types.h"
 
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/jit.hpp"
 
index a2d9157c6868bdba6fde3e4423fd73ed9bdc46b9..3b4be869c9e99f15e01b652a88f55dc2246e4276 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "vm/descriptor.h"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/abi.h"
 #include "vm/jit/stack.h"
index 14bc54968ca41958a206f86673049a1aef5c90d4..59d42505d38bd4ff809889d6fd40dc3b9729ecfb 100644 (file)
@@ -30,7 +30,7 @@
 
 extern "C" {
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include <opagent.h>
 
 }
index cd64a9c0929acee7553bd10eea74e995a1da0f0d..329ba02f066e6bd6f8b1971c0771483a9d3c950a 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 
 #include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 
 #include "vm/jit/jit.hpp"
 #include "vm/jit/optimizing/escape.h"
index 4b9b9ec4e1097bc100e84650f24e5814c8f8bc2b..b682be498492bbbf80213cd39b05355e2fd8a3b2 100644 (file)
@@ -25,7 +25,7 @@
 #define _VM_JIT_OPTIMIZING_ESCAPE_H
 
 #include "vm/jit/jit.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 typedef enum {
        ESCAPE_UNKNOWN,
index c463d1e2f1cef05bb70a93b9da0570ca75182934..9b292e64e4c72497e3eadfbc5401164cf79697be 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "vm/types.h"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/vm.hpp"
 
 #include "vm/jit/codegen-common.hpp"
index e5e571ef30c237398dfb054c0eb18f74caa59a35..5ea6e55d1b46cf7a14cd8f3237cec715788c69b2 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "vm/statistics.h"
 #include "vm/options.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/abi.h"
 #include "vm/jit/reg.h"
index dfffb133fa079c51b488532aebd8cbbb16bb4fd4..e397be6021bf31dc2313016d4226fadc7191a265 100644 (file)
@@ -37,8 +37,8 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
-#include "vm/classcache.h"
-#include "vm/method.h"
+#include "vm/classcache.hpp"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
 
index 8cd46d400fcbb3b92f5758b6defc333063b25ea3..4f3d5242620b67f44ffe68e4489763e611596a73 100644 (file)
@@ -34,7 +34,7 @@
 #include "threads/mutex.hpp"
 #include "threads/thread.hpp"
 
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
index 4a99d84d7f6b94bb52d2e32533e553bd131c5e38..86eba45d68e544bdeff9accdbba2ce311ca97300 100644 (file)
@@ -38,7 +38,7 @@
 #include "threads/condition.hpp"
 #include "threads/mutex.hpp"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 #ifdef __cplusplus
index 3fec92c75b33005da32ae041715867be850828de..427f0746a9228bf04242c82e96af16aaaa0098fc 100644 (file)
@@ -44,7 +44,7 @@
 
 #include "toolbox/logging.h"
 
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/globals.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
index 20b61ec7051fd06e5af27b991797d0f1baaf6623..5c520d5ec462c9eb6a8cdbe67886dd4e1c13c0d6 100644 (file)
@@ -57,7 +57,7 @@ typedef union  replace_val_t replace_val_t;
 #include "arch.h"
 #include "md-abi.h"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/reg.h"
 #include "vm/jit/stacktrace.hpp"
index 14050370570cfa1a493a69f5cce38669868fbd9a..9b63c7e176ea5e99c2af50f6fa33346d91ca674f 100644 (file)
@@ -53,7 +53,7 @@
 #include "vm/globals.hpp"
 #include "vm/javaobjects.hpp"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/string.hpp"
 #include "vm/vm.hpp"
index 42a6c442e9bec8b9ed3def83aa0f054093829475..66489b627a05f24eb5462a780e43708b26c21f50 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "mm/dumpmemory.hpp"
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 
 #include "vm/jit/abi.h"
index ac4041f391184a853aa8d140d2853bcf77571566..a8af31404f485e21832921db925c92ec16d42b59 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <stdint.h>
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #include "vm/jit/code.hpp"
 
index 06d808dbf454fcb56e56086f244fa6406a197329..14d1b61106ce5b804b2b75f1f54098fe3fb7bff1 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <stdint.h>
 
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 #if !defined(NDEBUG)
 
index e5883f0911d25fe8d1ac5967c3ab5f1495295084..8ee26ca3644fba87e59f2a44b3f337c3c93efb51 100644 (file)
@@ -42,7 +42,7 @@
 #include "vm/access.h"
 #include "vm/array.hpp"
 #include "vm/class.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/globals.hpp"
 #include "vm/loader.hpp"
index 4f1d36fff68d90f530ec0ac276fe36fd00431f18..32ac8e14c223f1da6a958169df43b29dbc52d42a 100644 (file)
 #include "toolbox/logging.h"
 
 #include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
 #include "vm/linker.h"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/package.hpp"
 #include "vm/primitive.hpp"
@@ -70,7 +70,7 @@
 #endif
 
 #if defined(ENABLE_ZLIB)
-# include "vm/zip.h"
+# include "vm/zip.hpp"
 #endif
 
 #include "vm/jit/stubs.hpp"
index d750b59e1553bcf2a8f716464523cafbd892e7f9..3e30e4a278335bbac03f62261085155852ae7131 100644 (file)
@@ -40,7 +40,7 @@ typedef struct classbuffer classbuffer;
 #include "vm/descriptor.h"
 #include "vm/class.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/utf8.h"
 
diff --git a/src/vm/method.c b/src/vm/method.c
deleted file mode 100644 (file)
index afaea99..0000000
+++ /dev/null
@@ -1,1219 +0,0 @@
-/* src/vm/method.c - method functions
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/llni.h"
-
-#include "threads/mutex.hpp"
-
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/class.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/method.h"
-#include "vm/options.h"
-#include "vm/resolve.hpp"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-#include "vm/vm.hpp"
-
-#include "vm/jit/code.hpp"
-#include "vm/jit/methodheader.h"
-#include "vm/jit/stubs.hpp"
-
-
-#if !defined(NDEBUG) && defined(ENABLE_INLINING)
-#define INLINELOG(code)  do { if (opt_TraceInlining) { code } } while (0)
-#else
-#define INLINELOG(code)
-#endif
-
-
-/* global variables ***********************************************************/
-
-methodinfo *method_java_lang_reflect_Method_invoke;
-
-
-/* method_init *****************************************************************
-
-   Initialize method subsystem.
-
-*******************************************************************************/
-
-void method_init(void)
-{
-#if defined(ENABLE_JAVASE)
-       /* Sanity check. */
-
-       if (class_java_lang_reflect_Method == NULL)
-               vm_abort("method_init: class_java_lang_reflect_Method is NULL");
-
-       /* Cache java.lang.reflect.Method.invoke() */
-
-       method_java_lang_reflect_Method_invoke =
-               class_findmethod(class_java_lang_reflect_Method, utf_invoke, NULL);
-
-       if (method_java_lang_reflect_Method_invoke == NULL)
-               vm_abort("method_init: Could not resolve method java.lang.reflect.Method.invoke().");
-#endif
-}
-
-
-/* method_load *****************************************************************
-
-   Loads a method from the class file and fills an existing methodinfo
-   structure.
-
-   method_info {
-       u2 access_flags;
-          u2 name_index;
-          u2 descriptor_index;
-          u2 attributes_count;
-          attribute_info attributes[attribute_count];
-   }
-
-   attribute_info {
-       u2 attribute_name_index;
-          u4 attribute_length;
-          u1 info[attribute_length];
-   }
-
-   LineNumberTable_attribute {
-       u2 attribute_name_index;
-          u4 attribute_length;
-          u2 line_number_table_length;
-          {
-              u2 start_pc;
-                  u2 line_number;
-          } line_number_table[line_number_table_length];
-   }
-
-*******************************************************************************/
-
-bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
-{
-       classinfo *c;
-       int argcount;
-       s4         i, j, k, l;
-       utf       *u;
-       u2         name_index;
-       u2         descriptor_index;
-       u2         attributes_count;
-       u2         attribute_name_index;
-       utf       *attribute_name;
-       u2         code_attributes_count;
-       u2         code_attribute_name_index;
-       utf       *code_attribute_name;
-
-       /* get classinfo */
-
-       c = cb->clazz;
-
-       m->mutex = Mutex_new();
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_all_methods++;
-#endif
-
-       /* all fields of m have been zeroed in load_class_from_classbuffer */
-
-       m->clazz = c;
-       
-       if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
-               return false;
-
-       /* access flags */
-
-       m->flags = suck_u2(cb);
-
-       /* name */
-
-       name_index = suck_u2(cb);
-
-       if (!(u = class_getconstant(c, name_index, CONSTANT_Utf8)))
-               return false;
-
-       m->name = u;
-
-       /* descriptor */
-
-       descriptor_index = suck_u2(cb);
-
-       if (!(u = class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
-               return false;
-
-       m->descriptor = u;
-
-       if (!descriptor_pool_add(descpool, u, &argcount))
-               return false;
-
-#ifdef ENABLE_VERIFIER
-       if (opt_verify) {
-               if (!is_valid_name_utf(m->name)) {
-                       exceptions_throw_classformaterror(c, "Method with invalid name");
-                       return false;
-               }
-
-               if (m->name->text[0] == '<' &&
-                       m->name != utf_init && m->name != utf_clinit) {
-                       exceptions_throw_classformaterror(c, "Method with invalid special name");
-                       return false;
-               }
-       }
-#endif /* ENABLE_VERIFIER */
-       
-       if (!(m->flags & ACC_STATIC))
-               argcount++; /* count the 'this' argument */
-
-#ifdef ENABLE_VERIFIER
-       if (opt_verify) {
-               if (argcount > 255) {
-                       exceptions_throw_classformaterror(c, "Too many arguments in signature");
-                       return false;
-               }
-
-               /* check flag consistency */
-               if (m->name != utf_clinit) {
-                       i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
-
-                       if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
-                               exceptions_throw_classformaterror(c,
-                                                                                                 "Illegal method modifiers: 0x%X",
-                                                                                                 m->flags);
-                               return false;
-                       }
-
-                       if (m->flags & ACC_ABSTRACT) {
-                               if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
-                                                                ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
-                                       exceptions_throw_classformaterror(c,
-                                                                                                         "Illegal method modifiers: 0x%X",
-                                                                                                         m->flags);
-                                       return false;
-                               }
-                       }
-
-                       if (c->flags & ACC_INTERFACE) {
-                               if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
-                                       exceptions_throw_classformaterror(c,
-                                                                                                         "Illegal method modifiers: 0x%X",
-                                                                                                         m->flags);
-                                       return false;
-                               }
-                       }
-
-                       if (m->name == utf_init) {
-                               if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
-                                                               ACC_NATIVE | ACC_ABSTRACT)) {
-                                       exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
-                                       return false;
-                               }
-                       }
-               }
-       }
-#endif /* ENABLE_VERIFIER */
-
-       /* mark the method as monomorphic until further notice */
-
-       m->flags |= ACC_METHOD_MONOMORPHIC;
-
-       /* non-abstract methods have an implementation in this class */
-
-       if (!(m->flags & ACC_ABSTRACT))
-               m->flags |= ACC_METHOD_IMPLEMENTED;
-               
-       if (!suck_check_classbuffer_size(cb, 2))
-               return false;
-
-       /* attributes count */
-
-       attributes_count = suck_u2(cb);
-
-       for (i = 0; i < attributes_count; i++) {
-               if (!suck_check_classbuffer_size(cb, 2))
-                       return false;
-
-               /* attribute name index */
-
-               attribute_name_index = suck_u2(cb);
-
-               attribute_name =
-                       class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
-
-               if (attribute_name == NULL)
-                       return false;
-
-               if (attribute_name == utf_Code) {
-                       /* Code */
-
-                       if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
-                               exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
-                               return false;
-                       }
-                       
-                       if (m->jcode) {
-                               exceptions_throw_classformaterror(c, "Multiple Code attributes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
-                               return false;
-
-                       suck_u4(cb);
-                       m->maxstack = suck_u2(cb);
-                       m->maxlocals = suck_u2(cb);
-
-                       if (m->maxlocals < argcount) {
-                               exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
-                               return false;
-                       }
-                       
-                       if (!suck_check_classbuffer_size(cb, 4))
-                               return false;
-
-                       m->jcodelength = suck_u4(cb);
-
-                       if (m->jcodelength == 0) {
-                               exceptions_throw_classformaterror(c, "Code of a method has length 0");
-                               return false;
-                       }
-                       
-                       if (m->jcodelength > 65535) {
-                               exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, m->jcodelength))
-                               return false;
-
-                       m->jcode = MNEW(u1, m->jcodelength);
-                       suck_nbytes(m->jcode, cb, m->jcodelength);
-
-                       if (!suck_check_classbuffer_size(cb, 2))
-                               return false;
-
-                       m->rawexceptiontablelength = suck_u2(cb);
-                       if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
-                               return false;
-
-                       m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
-
-#if defined(ENABLE_STATISTICS)
-                       if (opt_stat) {
-                               count_vmcode_len += m->jcodelength + 18;
-                               count_extable_len +=
-                                       m->rawexceptiontablelength * sizeof(raw_exception_entry);
-                       }
-#endif
-
-                       for (j = 0; j < m->rawexceptiontablelength; j++) {
-                               u4 idx;
-                               m->rawexceptiontable[j].startpc   = suck_u2(cb);
-                               m->rawexceptiontable[j].endpc     = suck_u2(cb);
-                               m->rawexceptiontable[j].handlerpc = suck_u2(cb);
-
-                               idx = suck_u2(cb);
-
-                               if (!idx) {
-                                       m->rawexceptiontable[j].catchtype.any = NULL;
-                               }
-                               else {
-                                       /* the classref is created later */
-                                       if (!(m->rawexceptiontable[j].catchtype.any =
-                                                 (utf *) class_getconstant(c, idx, CONSTANT_Class)))
-                                               return false;
-                               }
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 2))
-                               return false;
-
-                       /* code attributes count */
-
-                       code_attributes_count = suck_u2(cb);
-
-                       for (k = 0; k < code_attributes_count; k++) {
-                               if (!suck_check_classbuffer_size(cb, 2))
-                                       return false;
-
-                               /* code attribute name index */
-
-                               code_attribute_name_index = suck_u2(cb);
-
-                               code_attribute_name =
-                                       class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8);
-
-                               if (code_attribute_name == NULL)
-                                       return false;
-
-                               /* check which code attribute */
-
-                               if (code_attribute_name == utf_LineNumberTable) {
-                                       /* LineNumberTable */
-
-                                       if (!suck_check_classbuffer_size(cb, 4 + 2))
-                                               return false;
-
-                                       /* attribute length */
-
-                                       (void) suck_u4(cb);
-
-                                       /* line number table length */
-
-                                       m->linenumbercount = suck_u2(cb);
-
-                                       if (!suck_check_classbuffer_size(cb,
-                                                                                               (2 + 2) * m->linenumbercount))
-                                               return false;
-
-                                       m->linenumbers = MNEW(lineinfo, m->linenumbercount);
-
-#if defined(ENABLE_STATISTICS)
-                                       if (opt_stat)
-                                               size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
-#endif
-                                       
-                                       for (l = 0; l < m->linenumbercount; l++) {
-                                               m->linenumbers[l].start_pc    = suck_u2(cb);
-                                               m->linenumbers[l].line_number = suck_u2(cb);
-                                       }
-                               }
-#if defined(ENABLE_JAVASE)
-                               else if (code_attribute_name == utf_StackMapTable) {
-                                       /* StackTableMap */
-
-                                       if (!stackmap_load_attribute_stackmaptable(cb, m))
-                                               return false;
-                               }
-#endif
-                               else {
-                                       /* unknown code attribute */
-
-                                       if (!loader_skip_attribute_body(cb))
-                                               return false;
-                               }
-                       }
-               }
-               else if (attribute_name == utf_Exceptions) {
-                       /* Exceptions */
-
-                       if (m->thrownexceptions != NULL) {
-                               exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 4 + 2))
-                               return false;
-
-                       /* attribute length */
-
-                       (void) suck_u4(cb);
-
-                       m->thrownexceptionscount = suck_u2(cb);
-
-                       if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
-                               return false;
-
-                       m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
-
-                       for (j = 0; j < m->thrownexceptionscount; j++) {
-                               /* the classref is created later */
-                               if (!((m->thrownexceptions)[j].any =
-                                         (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
-                                       return false;
-                       }
-               }
-#if defined(ENABLE_JAVASE)
-               else if (attribute_name == utf_Signature) {
-                       /* Signature */
-
-                       if (!loader_load_attribute_signature(cb, &(m->signature)))
-                               return false;
-               }
-
-#if defined(ENABLE_ANNOTATIONS)
-               else if (attribute_name == utf_RuntimeVisibleAnnotations) {
-                       /* RuntimeVisibleAnnotations */
-                       if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
-                               return false;
-               }
-               else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
-                       /* RuntimeInvisibleAnnotations */
-                       if (!annotation_load_method_attribute_runtimeinvisibleannotations(cb, m))
-                               return false;
-               }
-               else if (attribute_name == utf_RuntimeVisibleParameterAnnotations) {
-                       /* RuntimeVisibleParameterAnnotations */
-                       if (!annotation_load_method_attribute_runtimevisibleparameterannotations(cb, m))
-                               return false;
-               }
-               else if (attribute_name == utf_RuntimeInvisibleParameterAnnotations) {
-                       /* RuntimeInvisibleParameterAnnotations */
-                       if (!annotation_load_method_attribute_runtimeinvisibleparameterannotations(cb, m))
-                               return false;
-               }
-               else if (attribute_name == utf_AnnotationDefault) {
-                       /* AnnotationDefault */
-                       if (!annotation_load_method_attribute_annotationdefault(cb, m))
-                               return false;
-               }
-#endif
-#endif
-               else {
-                       /* unknown attribute */
-
-                       if (!loader_skip_attribute_body(cb))
-                               return false;
-               }
-       }
-
-       if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
-               exceptions_throw_classformaterror(c, "Missing Code attribute");
-               return false;
-       }
-
-#if defined(ENABLE_REPLACEMENT)
-       /* initialize the hit countdown field */
-
-       m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
-#endif
-
-       /* everything was ok */
-
-       return true;
-}
-
-
-/* method_free *****************************************************************
-
-   Frees all memory that was allocated for this method.
-
-*******************************************************************************/
-
-void method_free(methodinfo *m)
-{
-       if (m->mutex)
-               Mutex_delete(m->mutex);
-
-       if (m->jcode)
-               MFREE(m->jcode, u1, m->jcodelength);
-
-       if (m->rawexceptiontable)
-               MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
-
-       code_free_code_of_method(m);
-
-       if (m->stubroutine) {
-               if (m->flags & ACC_NATIVE) {
-                       NativeStub_remove(m->stubroutine);
-               }
-               else {
-                       CompilerStub_remove(m->stubroutine);
-               }
-       }
-}
-
-
-/* method_canoverwrite *********************************************************
-
-   Check if m and old are identical with respect to type and
-   name. This means that old can be overwritten with m.
-       
-*******************************************************************************/
-
-bool method_canoverwrite(methodinfo *m, methodinfo *old)
-{
-       if (m->name != old->name)
-               return false;
-
-       if (m->descriptor != old->descriptor)
-               return false;
-
-       if (m->flags & ACC_STATIC)
-               return false;
-
-       return true;
-}
-
-
-/* method_new_builtin **********************************************************
-
-   Creates a minimal methodinfo structure for builtins. This comes handy
-   when dealing with builtin stubs or stacktraces.
-
-*******************************************************************************/
-
-methodinfo *method_new_builtin(builtintable_entry *bte)
-{
-       methodinfo *m;
-
-       /* allocate the methodinfo structure */
-
-       m = NEW(methodinfo);
-
-       /* initialize methodinfo structure */
-
-       MZERO(m, methodinfo, 1);
-       
-       m->mutex      = Mutex_new();
-       m->flags      = ACC_METHOD_BUILTIN;
-       m->parseddesc = bte->md;
-       m->name       = bte->name;
-       m->descriptor = bte->descriptor;
-
-       /* return the newly created methodinfo */
-
-       return m;
-}
-
-
-/* method_vftbl_lookup *********************************************************
-
-   Does a method lookup in the passed virtual function table.  This
-   function does exactly the same thing as JIT, but additionally
-   relies on the fact, that the methodinfo pointer is at the first
-   data segment slot (even for compiler stubs).
-
-*******************************************************************************/
-
-methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
-{
-       methodptr   mptr;
-       methodptr  *pmptr;
-       methodinfo *resm;                   /* pointer to new resolved method     */
-
-       /* If the method is not an instance method, just return it. */
-
-       if (m->flags & ACC_STATIC)
-               return m;
-
-       assert(vftbl);
-
-       /* Get the method from the virtual function table.  Is this an
-          interface method? */
-
-       if (m->clazz->flags & ACC_INTERFACE) {
-               pmptr = vftbl->interfacetable[-(m->clazz->index)];
-               mptr  = pmptr[(m - m->clazz->methods)];
-       }
-       else {
-               mptr = vftbl->table[m->vftblindex];
-       }
-
-       /* and now get the codeinfo pointer from the first data segment slot */
-
-       resm = code_get_methodinfo_for_pv(mptr);
-
-       return resm;
-}
-
-
-/* method_get_parametercount **************************************************
-
-   Use the descriptor of a method to determine the number of parameters
-   of the method. The this pointer of non-static methods is not counted.
-
-   IN:
-       m........the method of which the parameters should be counted
-
-   RETURN VALUE:
-       The parameter count or -1 on error.
-
-*******************************************************************************/
-
-int32_t method_get_parametercount(methodinfo *m)
-{
-       methoddesc *md;             /* method descriptor of m   */
-       int32_t     paramcount = 0; /* the parameter count of m */
-
-       md = m->parseddesc;
-       
-       /* is the descriptor fully parsed? */
-
-       if (md->params == NULL) {
-               if (!descriptor_params_from_paramtypes(md, m->flags)) {
-                       return -1;
-               }
-       }
-
-       paramcount = md->paramcount;
-
-       /* skip `this' pointer */
-
-       if (!(m->flags & ACC_STATIC)) {
-               --paramcount;
-       }
-
-       return paramcount;
-}
-
-
-/* method_get_parametertypearray ***********************************************
-
-   Use the descriptor of a method to generate a java.lang.Class array
-   which contains the classes of the parametertypes of the method.
-
-   This function is called by java.lang.reflect.{Constructor,Method}.
-
-*******************************************************************************/
-
-java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m)
-{
-       methoddesc                *md;
-       typedesc                  *paramtypes;
-       int32_t                    paramcount;
-       java_handle_objectarray_t *oa;
-       int32_t                    i;
-       classinfo                 *c;
-
-       md = m->parseddesc;
-
-       /* is the descriptor fully parsed? */
-
-       if (m->parseddesc->params == NULL)
-               if (!descriptor_params_from_paramtypes(md, m->flags))
-                       return NULL;
-
-       paramtypes = md->paramtypes;
-       paramcount = md->paramcount;
-
-       /* skip `this' pointer */
-
-       if (!(m->flags & ACC_STATIC)) {
-               paramtypes++;
-               paramcount--;
-       }
-
-       /* create class-array */
-
-       oa = builtin_anewarray(paramcount, class_java_lang_Class);
-
-       if (oa == NULL)
-               return NULL;
-
-    /* get classes */
-
-       for (i = 0; i < paramcount; i++) {
-               if (!resolve_class_from_typedesc(&paramtypes[i], true, false, &c))
-                       return NULL;
-
-               LLNI_array_direct(oa, i) = (java_object_t *) c;
-       }
-
-       return oa;
-}
-
-
-/* method_get_exceptionarray ***************************************************
-
-   Get the exceptions which can be thrown by a method.
-
-*******************************************************************************/
-
-java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m)
-{
-       java_handle_objectarray_t *oa;
-       classinfo                 *c;
-       s4                         i;
-
-       /* create class-array */
-
-       oa = builtin_anewarray(m->thrownexceptionscount, class_java_lang_Class);
-
-       if (oa == NULL)
-               return NULL;
-
-       /* iterate over all exceptions and store the class in the array */
-
-       for (i = 0; i < m->thrownexceptionscount; i++) {
-               c = resolve_classref_or_classinfo_eager(m->thrownexceptions[i], true);
-
-               if (c == NULL)
-                       return NULL;
-
-               LLNI_array_direct(oa, i) = (java_object_t *) c;
-       }
-
-       return oa;
-}
-
-
-/* method_returntype_get *******************************************************
-
-   Get the return type of the method.
-
-*******************************************************************************/
-
-classinfo *method_returntype_get(methodinfo *m)
-{
-       typedesc  *td;
-       classinfo *c;
-
-       td = &(m->parseddesc->returntype);
-
-       if (!resolve_class_from_typedesc(td, true, false, &c))
-               return NULL;
-
-       return c;
-}
-
-
-/* method_count_implementations ************************************************
-
-   Count the implementations of a method in a class cone (a class and all its
-   subclasses.)
-
-   IN:
-       m................the method to count
-          c................class at which to start the counting (this class and
-                           all its subclasses will be searched)
-
-   OUT:
-       *found...........if found != NULL, *found receives the method
-                           implementation that was found. This value is only
-                                               meaningful if the return value is 1.
-
-   RETURN VALUE:
-       the number of implementations found
-
-*******************************************************************************/
-
-s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
-{
-       s4          count;
-       methodinfo *mp;
-       methodinfo *mend;
-       classinfo  *child;
-
-       count = 0;
-
-       mp = c->methods;
-       mend = mp + c->methodscount;
-
-       for (; mp < mend; ++mp) {
-               if (method_canoverwrite(mp, m)) {
-                       if (found)
-                               *found = mp;
-                       count++;
-                       break;
-               }
-       }
-
-       for (child = c->sub; child != NULL; child = child->nextsub) {
-               count += method_count_implementations(m, child, found);
-       }
-
-       return count;
-}
-
-
-/* method_get_annotations ******************************************************
-
-   Get a methods' unparsed annotations in a byte array.
-
-   IN:
-       m........the method of which the annotations should be returned
-
-   RETURN VALUE:
-       The unparsed annotations in a byte array (or NULL if there aren't any).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_annotations(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
-       classinfo     *c;                  /* methods' declaring class          */
-       int            slot;               /* methods' slot                     */
-       java_handle_t *annotations;        /* methods' unparsed annotations     */
-       java_handle_t *method_annotations; /* all methods' unparsed annotations */
-                                          /* of the declaring class            */
-
-       c           = m->clazz;
-       slot        = m - c->methods;
-       annotations = NULL;
-
-       LLNI_classinfo_field_get(c, method_annotations, method_annotations);
-
-       /* the method_annotations array might be shorter then the method
-        * count if the methods above a certain index have no annotations.
-        */     
-       if (method_annotations != NULL &&
-               array_length_get(method_annotations) > slot) {
-               annotations = array_objectarray_element_get(
-                       (java_handle_objectarray_t*)method_annotations, slot);
-       }
-       
-       return (java_handle_bytearray_t*)annotations;
-#else
-       return NULL;
-#endif
-}
-
-
-/* method_get_parameterannotations ********************************************
-
-   Get a methods' unparsed parameter annotations in an array of byte
-   arrays.
-
-   IN:
-       m........the method of which the parameter annotations should be
-                   returned
-
-   RETURN VALUE:
-       The unparsed parameter annotations in a byte array (or NULL if
-          there aren't any).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
-       classinfo     *c;                           /* methods' declaring class */
-       int            slot;                        /* methods' slot            */
-       java_handle_t *parameterAnnotations;        /* methods' unparsed        */
-                                                   /* parameter annotations    */
-       java_handle_t *method_parameterannotations; /* all methods' unparsed    */
-                                                   /* parameter annotations of */
-                                                   /* the declaring class      */
-
-       c                    = m->clazz;
-       slot                 = m - c->methods;
-       parameterAnnotations = NULL;
-
-       LLNI_classinfo_field_get(
-               c, method_parameterannotations, method_parameterannotations);
-
-       /* the method_annotations array might be shorter then the method
-        * count if the methods above a certain index have no annotations.
-        */     
-       if (method_parameterannotations != NULL &&
-               array_length_get(method_parameterannotations) > slot) {
-               parameterAnnotations = array_objectarray_element_get(
-                               (java_handle_objectarray_t*)method_parameterannotations,
-                               slot);
-       }
-       
-       return (java_handle_bytearray_t*)parameterAnnotations;
-#else
-       return NULL;
-#endif
-}
-
-
-/* method_get_annotationdefault ***********************************************
-
-   Get a methods' unparsed annotation default value in a byte array.
-   
-   IN:
-       m........the method of which the annotation default value should be
-                   returned
-
-   RETURN VALUE:
-       The unparsed annotation default value in a byte array (or NULL if
-          there isn't one).
-
-*******************************************************************************/
-
-java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m)
-{
-#if defined(ENABLE_ANNOTATIONS)
-       classinfo     *c;                         /* methods' declaring class     */
-       int            slot;                      /* methods' slot                */
-       java_handle_t *annotationDefault;         /* methods' unparsed            */
-                                                 /* annotation default value     */
-       java_handle_t *method_annotationdefaults; /* all methods' unparsed        */
-                                                 /* annotation default values of */
-                                                 /* the declaring class          */
-
-       c                 = m->clazz;
-       slot              = m - c->methods;
-       annotationDefault = NULL;
-
-       LLNI_classinfo_field_get(
-               c, method_annotationdefaults, method_annotationdefaults);
-
-       /* the method_annotations array might be shorter then the method
-        * count if the methods above a certain index have no annotations.
-        */     
-       if (method_annotationdefaults != NULL &&
-               array_length_get(method_annotationdefaults) > slot) {
-               annotationDefault = array_objectarray_element_get(
-                               (java_handle_objectarray_t*)method_annotationdefaults, slot);
-       }
-       
-       return (java_handle_bytearray_t*)annotationDefault;
-#else
-       return NULL;
-#endif
-}
-
-
-/* method_add_to_worklist ******************************************************
-
-   Add the method to the given worklist. If the method already occurs in
-   the worklist, the worklist remains unchanged.
-
-*******************************************************************************/
-
-static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
-{
-       method_worklist *wi;
-
-       for (wi = *wl; wi != NULL; wi = wi->next)
-               if (wi->m == m)
-                       return;
-
-       wi = NEW(method_worklist);
-       wi->next = *wl;
-       wi->m = m;
-
-       *wl = wi;
-}
-
-
-/* method_add_assumption_monomorphic *******************************************
-
-   Record the assumption that the method is monomorphic.
-
-   IN:
-      m.................the method
-         caller............the caller making the assumption
-
-*******************************************************************************/
-
-void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
-{
-       method_assumption *as;
-
-       /* XXX LOCKING FOR THIS FUNCTION? */
-
-       /* check if we already have registered this assumption */
-
-       for (as = m->assumptions; as != NULL; as = as->next) {
-               if (as->context == caller)
-                       return;
-       }
-
-       /* register the assumption */
-
-       as = NEW(method_assumption);
-       as->next = m->assumptions;
-       as->context = caller;
-
-       m->assumptions = as;
-}
-
-/* method_break_assumption_monomorphic *****************************************
-
-   Break the assumption that this method is monomorphic. All callers that
-   have registered this assumption are added to the worklist.
-
-   IN:
-      m.................the method
-         wl................worklist where to add invalidated callers
-
-*******************************************************************************/
-
-void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
-{
-       method_assumption *as;
-
-       /* XXX LOCKING FOR THIS FUNCTION? */
-
-       for (as = m->assumptions; as != NULL; as = as->next) {
-               INLINELOG(
-                       printf("ASSUMPTION BROKEN (monomorphism): ");
-                       method_print(m);
-                       printf(" in ");
-                       method_println(as->context);
-               );
-
-               method_add_to_worklist(as->context, wl);
-
-#if defined(ENABLE_TLH) && 0
-               /* XXX hack */
-               method_assumption *as2;
-               as2 = m->assumptions;
-               m->assumptions = NULL;
-               method_break_assumption_monomorphic(as->context, wl);
-               /*
-               assert(m->assumptions == NULL);
-               m->assumptions = as2;*/
-#endif
-
-       }
-}
-
-/* method_printflags ***********************************************************
-
-   Prints the flags of a method to stdout like.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_printflags(methodinfo *m)
-{
-       if (m == NULL) {
-               printf("NULL");
-               return;
-       }
-
-       if (m->flags & ACC_PUBLIC)             printf(" PUBLIC");
-       if (m->flags & ACC_PRIVATE)            printf(" PRIVATE");
-       if (m->flags & ACC_PROTECTED)          printf(" PROTECTED");
-       if (m->flags & ACC_STATIC)             printf(" STATIC");
-       if (m->flags & ACC_FINAL)              printf(" FINAL");
-       if (m->flags & ACC_SYNCHRONIZED)       printf(" SYNCHRONIZED");
-       if (m->flags & ACC_VOLATILE)           printf(" VOLATILE");
-       if (m->flags & ACC_TRANSIENT)          printf(" TRANSIENT");
-       if (m->flags & ACC_NATIVE)             printf(" NATIVE");
-       if (m->flags & ACC_INTERFACE)          printf(" INTERFACE");
-       if (m->flags & ACC_ABSTRACT)           printf(" ABSTRACT");
-       if (m->flags & ACC_METHOD_BUILTIN)     printf(" (builtin)");
-       if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
-       if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_print ****************************************************************
-
-   Prints a method to stdout like:
-
-   java.lang.Object.<init>()V
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_print(methodinfo *m)
-{
-       if (m == NULL) {
-               printf("NULL");
-               return;
-       }
-
-       if (m->clazz != NULL)
-               utf_display_printable_ascii_classname(m->clazz->name);
-       else
-               printf("NULL");
-       printf(".");
-       utf_display_printable_ascii(m->name);
-       utf_display_printable_ascii(m->descriptor);
-
-       method_printflags(m);
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_println **************************************************************
-
-   Prints a method plus new line to stdout like:
-
-   java.lang.Object.<init>()V
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_println(methodinfo *m)
-{
-       if (opt_debugcolor) printf("\033[31m"); /* red */
-       method_print(m);
-       if (opt_debugcolor) printf("\033[m");   
-       printf("\n");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_methodref_print ******************************************************
-
-   Prints a method reference to stdout.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_methodref_print(constant_FMIref *mr)
-{
-       if (!mr) {
-               printf("(constant_FMIref *)NULL");
-               return;
-       }
-
-       if (IS_FMIREF_RESOLVED(mr)) {
-               printf("<method> ");
-               method_print(mr->p.method);
-       }
-       else {
-               printf("<methodref> ");
-               utf_display_printable_ascii_classname(mr->p.classref->name);
-               printf(".");
-               utf_display_printable_ascii(mr->name);
-               utf_display_printable_ascii(mr->descriptor);
-       }
-}
-#endif /* !defined(NDEBUG) */
-
-
-/* method_methodref_println ****************************************************
-
-   Prints a method reference to stdout, followed by a newline.
-
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void method_methodref_println(constant_FMIref *mr)
-{
-       method_methodref_print(mr);
-       printf("\n");
-}
-#endif /* !defined(NDEBUG) */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/method.cpp b/src/vm/method.cpp
new file mode 100644 (file)
index 0000000..4718423
--- /dev/null
@@ -0,0 +1,1226 @@
+/* src/vm/method.cpp - method functions
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/linker.h"
+#include "vm/loader.hpp"
+#include "vm/method.hpp"
+#include "vm/options.h"
+#include "vm/resolve.hpp"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+
+#include "vm/jit/code.hpp"
+#include "vm/jit/methodheader.h"
+#include "vm/jit/stubs.hpp"
+
+
+#if !defined(NDEBUG) && defined(ENABLE_INLINING)
+#define INLINELOG(code)  do { if (opt_TraceInlining) { code } } while (0)
+#else
+#define INLINELOG(code)
+#endif
+
+/* global variables ***********************************************************/
+
+methodinfo *method_java_lang_reflect_Method_invoke;
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* method_init *****************************************************************
+
+   Initialize method subsystem.
+
+*******************************************************************************/
+
+void method_init(void)
+{
+#if defined(ENABLE_JAVASE)
+       /* Sanity check. */
+
+       if (class_java_lang_reflect_Method == NULL)
+               vm_abort("method_init: class_java_lang_reflect_Method is NULL");
+
+       /* Cache java.lang.reflect.Method.invoke() */
+
+       method_java_lang_reflect_Method_invoke =
+               class_findmethod(class_java_lang_reflect_Method, utf_invoke, NULL);
+
+       if (method_java_lang_reflect_Method_invoke == NULL)
+               vm_abort("method_init: Could not resolve method java.lang.reflect.Method.invoke().");
+#endif
+}
+
+
+/* method_load *****************************************************************
+
+   Loads a method from the class file and fills an existing methodinfo
+   structure.
+
+   method_info {
+       u2 access_flags;
+          u2 name_index;
+          u2 descriptor_index;
+          u2 attributes_count;
+          attribute_info attributes[attribute_count];
+   }
+
+   attribute_info {
+       u2 attribute_name_index;
+          u4 attribute_length;
+          u1 info[attribute_length];
+   }
+
+   LineNumberTable_attribute {
+       u2 attribute_name_index;
+          u4 attribute_length;
+          u2 line_number_table_length;
+          {
+              u2 start_pc;
+                  u2 line_number;
+          } line_number_table[line_number_table_length];
+   }
+
+*******************************************************************************/
+
+bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
+{
+       classinfo *c;
+       int argcount;
+       s4         i, j, k, l;
+       utf       *u;
+       u2         name_index;
+       u2         descriptor_index;
+       u2         attributes_count;
+       u2         attribute_name_index;
+       utf       *attribute_name;
+       u2         code_attributes_count;
+       u2         code_attribute_name_index;
+       utf       *code_attribute_name;
+
+       /* get classinfo */
+
+       c = cb->clazz;
+
+       m->mutex = new Mutex();
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_all_methods++;
+#endif
+
+       /* all fields of m have been zeroed in load_class_from_classbuffer */
+
+       m->clazz = c;
+       
+       if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
+               return false;
+
+       /* access flags */
+
+       m->flags = suck_u2(cb);
+
+       /* name */
+
+       name_index = suck_u2(cb);
+
+       if (!(u = (utf*) class_getconstant(c, name_index, CONSTANT_Utf8)))
+               return false;
+
+       m->name = u;
+
+       /* descriptor */
+
+       descriptor_index = suck_u2(cb);
+
+       if (!(u = (utf*) class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
+               return false;
+
+       m->descriptor = u;
+
+       if (!descriptor_pool_add(descpool, u, &argcount))
+               return false;
+
+#ifdef ENABLE_VERIFIER
+       if (opt_verify) {
+               if (!is_valid_name_utf(m->name)) {
+                       exceptions_throw_classformaterror(c, "Method with invalid name");
+                       return false;
+               }
+
+               if (m->name->text[0] == '<' &&
+                       m->name != utf_init && m->name != utf_clinit) {
+                       exceptions_throw_classformaterror(c, "Method with invalid special name");
+                       return false;
+               }
+       }
+#endif /* ENABLE_VERIFIER */
+       
+       if (!(m->flags & ACC_STATIC))
+               argcount++; /* count the 'this' argument */
+
+#ifdef ENABLE_VERIFIER
+       if (opt_verify) {
+               if (argcount > 255) {
+                       exceptions_throw_classformaterror(c, "Too many arguments in signature");
+                       return false;
+               }
+
+               /* check flag consistency */
+               if (m->name != utf_clinit) {
+                       i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
+
+                       if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
+                               exceptions_throw_classformaterror(c,
+                                                                                                 "Illegal method modifiers: 0x%X",
+                                                                                                 m->flags);
+                               return false;
+                       }
+
+                       if (m->flags & ACC_ABSTRACT) {
+                               if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
+                                                                ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
+                                       exceptions_throw_classformaterror(c,
+                                                                                                         "Illegal method modifiers: 0x%X",
+                                                                                                         m->flags);
+                                       return false;
+                               }
+                       }
+
+                       if (c->flags & ACC_INTERFACE) {
+                               if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
+                                       exceptions_throw_classformaterror(c,
+                                                                                                         "Illegal method modifiers: 0x%X",
+                                                                                                         m->flags);
+                                       return false;
+                               }
+                       }
+
+                       if (m->name == utf_init) {
+                               if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+                                                               ACC_NATIVE | ACC_ABSTRACT)) {
+                                       exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
+                                       return false;
+                               }
+                       }
+               }
+       }
+#endif /* ENABLE_VERIFIER */
+
+       /* mark the method as monomorphic until further notice */
+
+       m->flags |= ACC_METHOD_MONOMORPHIC;
+
+       /* non-abstract methods have an implementation in this class */
+
+       if (!(m->flags & ACC_ABSTRACT))
+               m->flags |= ACC_METHOD_IMPLEMENTED;
+               
+       if (!suck_check_classbuffer_size(cb, 2))
+               return false;
+
+       /* attributes count */
+
+       attributes_count = suck_u2(cb);
+
+       for (i = 0; i < attributes_count; i++) {
+               if (!suck_check_classbuffer_size(cb, 2))
+                       return false;
+
+               /* attribute name index */
+
+               attribute_name_index = suck_u2(cb);
+
+               attribute_name =
+                       (utf*) class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
+
+               if (attribute_name == NULL)
+                       return false;
+
+               if (attribute_name == utf_Code) {
+                       /* Code */
+
+                       if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
+                               exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
+                               return false;
+                       }
+                       
+                       if (m->jcode) {
+                               exceptions_throw_classformaterror(c, "Multiple Code attributes");
+                               return false;
+                       }
+
+                       if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
+                               return false;
+
+                       suck_u4(cb);
+                       m->maxstack = suck_u2(cb);
+                       m->maxlocals = suck_u2(cb);
+
+                       if (m->maxlocals < argcount) {
+                               exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
+                               return false;
+                       }
+                       
+                       if (!suck_check_classbuffer_size(cb, 4))
+                               return false;
+
+                       m->jcodelength = suck_u4(cb);
+
+                       if (m->jcodelength == 0) {
+                               exceptions_throw_classformaterror(c, "Code of a method has length 0");
+                               return false;
+                       }
+                       
+                       if (m->jcodelength > 65535) {
+                               exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
+                               return false;
+                       }
+
+                       if (!suck_check_classbuffer_size(cb, m->jcodelength))
+                               return false;
+
+                       m->jcode = MNEW(u1, m->jcodelength);
+                       suck_nbytes(m->jcode, cb, m->jcodelength);
+
+                       if (!suck_check_classbuffer_size(cb, 2))
+                               return false;
+
+                       m->rawexceptiontablelength = suck_u2(cb);
+                       if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
+                               return false;
+
+                       m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
+
+#if defined(ENABLE_STATISTICS)
+                       if (opt_stat) {
+                               count_vmcode_len += m->jcodelength + 18;
+                               count_extable_len +=
+                                       m->rawexceptiontablelength * sizeof(raw_exception_entry);
+                       }
+#endif
+
+                       for (j = 0; j < m->rawexceptiontablelength; j++) {
+                               u4 idx;
+                               m->rawexceptiontable[j].startpc   = suck_u2(cb);
+                               m->rawexceptiontable[j].endpc     = suck_u2(cb);
+                               m->rawexceptiontable[j].handlerpc = suck_u2(cb);
+
+                               idx = suck_u2(cb);
+
+                               if (!idx) {
+                                       m->rawexceptiontable[j].catchtype.any = NULL;
+                               }
+                               else {
+                                       /* the classref is created later */
+                                       if (!(m->rawexceptiontable[j].catchtype.any =
+                                                 (utf *) class_getconstant(c, idx, CONSTANT_Class)))
+                                               return false;
+                               }
+                       }
+
+                       if (!suck_check_classbuffer_size(cb, 2))
+                               return false;
+
+                       /* code attributes count */
+
+                       code_attributes_count = suck_u2(cb);
+
+                       for (k = 0; k < code_attributes_count; k++) {
+                               if (!suck_check_classbuffer_size(cb, 2))
+                                       return false;
+
+                               /* code attribute name index */
+
+                               code_attribute_name_index = suck_u2(cb);
+
+                               code_attribute_name =
+                                       (utf*) class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8);
+
+                               if (code_attribute_name == NULL)
+                                       return false;
+
+                               /* check which code attribute */
+
+                               if (code_attribute_name == utf_LineNumberTable) {
+                                       /* LineNumberTable */
+
+                                       if (!suck_check_classbuffer_size(cb, 4 + 2))
+                                               return false;
+
+                                       /* attribute length */
+
+                                       (void) suck_u4(cb);
+
+                                       /* line number table length */
+
+                                       m->linenumbercount = suck_u2(cb);
+
+                                       if (!suck_check_classbuffer_size(cb,
+                                                                                               (2 + 2) * m->linenumbercount))
+                                               return false;
+
+                                       m->linenumbers = MNEW(lineinfo, m->linenumbercount);
+
+#if defined(ENABLE_STATISTICS)
+                                       if (opt_stat)
+                                               size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
+#endif
+                                       
+                                       for (l = 0; l < m->linenumbercount; l++) {
+                                               m->linenumbers[l].start_pc    = suck_u2(cb);
+                                               m->linenumbers[l].line_number = suck_u2(cb);
+                                       }
+                               }
+#if defined(ENABLE_JAVASE)
+                               else if (code_attribute_name == utf_StackMapTable) {
+                                       /* StackTableMap */
+
+                                       if (!stackmap_load_attribute_stackmaptable(cb, m))
+                                               return false;
+                               }
+#endif
+                               else {
+                                       /* unknown code attribute */
+
+                                       if (!loader_skip_attribute_body(cb))
+                                               return false;
+                               }
+                       }
+               }
+               else if (attribute_name == utf_Exceptions) {
+                       /* Exceptions */
+
+                       if (m->thrownexceptions != NULL) {
+                               exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
+                               return false;
+                       }
+
+                       if (!suck_check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       /* attribute length */
+
+                       (void) suck_u4(cb);
+
+                       m->thrownexceptionscount = suck_u2(cb);
+
+                       if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
+                               return false;
+
+                       m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
+
+                       for (j = 0; j < m->thrownexceptionscount; j++) {
+                               /* the classref is created later */
+                               if (!((m->thrownexceptions)[j].any =
+                                         (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
+                                       return false;
+                       }
+               }
+#if defined(ENABLE_JAVASE)
+               else if (attribute_name == utf_Signature) {
+                       /* Signature */
+
+                       if (!loader_load_attribute_signature(cb, &(m->signature)))
+                               return false;
+               }
+
+#if defined(ENABLE_ANNOTATIONS)
+               else if (attribute_name == utf_RuntimeVisibleAnnotations) {
+                       /* RuntimeVisibleAnnotations */
+                       if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
+                               return false;
+               }
+               else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
+                       /* RuntimeInvisibleAnnotations */
+                       if (!annotation_load_method_attribute_runtimeinvisibleannotations(cb, m))
+                               return false;
+               }
+               else if (attribute_name == utf_RuntimeVisibleParameterAnnotations) {
+                       /* RuntimeVisibleParameterAnnotations */
+                       if (!annotation_load_method_attribute_runtimevisibleparameterannotations(cb, m))
+                               return false;
+               }
+               else if (attribute_name == utf_RuntimeInvisibleParameterAnnotations) {
+                       /* RuntimeInvisibleParameterAnnotations */
+                       if (!annotation_load_method_attribute_runtimeinvisibleparameterannotations(cb, m))
+                               return false;
+               }
+               else if (attribute_name == utf_AnnotationDefault) {
+                       /* AnnotationDefault */
+                       if (!annotation_load_method_attribute_annotationdefault(cb, m))
+                               return false;
+               }
+#endif
+#endif
+               else {
+                       /* unknown attribute */
+
+                       if (!loader_skip_attribute_body(cb))
+                               return false;
+               }
+       }
+
+       if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
+               exceptions_throw_classformaterror(c, "Missing Code attribute");
+               return false;
+       }
+
+#if defined(ENABLE_REPLACEMENT)
+       /* initialize the hit countdown field */
+
+       m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
+#endif
+
+       /* everything was ok */
+
+       return true;
+}
+
+
+/* method_free *****************************************************************
+
+   Frees all memory that was allocated for this method.
+
+*******************************************************************************/
+
+void method_free(methodinfo *m)
+{
+       if (m->mutex)
+               delete m->mutex;
+
+       if (m->jcode)
+               MFREE(m->jcode, u1, m->jcodelength);
+
+       if (m->rawexceptiontable)
+               MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
+
+       code_free_code_of_method(m);
+
+       if (m->stubroutine) {
+               if (m->flags & ACC_NATIVE) {
+                       NativeStub::remove(m->stubroutine);
+               }
+               else {
+                       CompilerStub::remove(m->stubroutine);
+               }
+       }
+}
+
+
+/* method_canoverwrite *********************************************************
+
+   Check if m and old are identical with respect to type and
+   name. This means that old can be overwritten with m.
+       
+*******************************************************************************/
+
+bool method_canoverwrite(methodinfo *m, methodinfo *old)
+{
+       if (m->name != old->name)
+               return false;
+
+       if (m->descriptor != old->descriptor)
+               return false;
+
+       if (m->flags & ACC_STATIC)
+               return false;
+
+       return true;
+}
+
+
+/* method_new_builtin **********************************************************
+
+   Creates a minimal methodinfo structure for builtins. This comes handy
+   when dealing with builtin stubs or stacktraces.
+
+*******************************************************************************/
+
+methodinfo *method_new_builtin(builtintable_entry *bte)
+{
+       methodinfo *m;
+
+       /* allocate the methodinfo structure */
+
+       m = NEW(methodinfo);
+
+       /* initialize methodinfo structure */
+
+       MZERO(m, methodinfo, 1);
+       
+       m->mutex      = new Mutex();
+       m->flags      = ACC_METHOD_BUILTIN;
+       m->parseddesc = bte->md;
+       m->name       = bte->name;
+       m->descriptor = bte->descriptor;
+
+       /* return the newly created methodinfo */
+
+       return m;
+}
+
+
+/* method_vftbl_lookup *********************************************************
+
+   Does a method lookup in the passed virtual function table.  This
+   function does exactly the same thing as JIT, but additionally
+   relies on the fact, that the methodinfo pointer is at the first
+   data segment slot (even for compiler stubs).
+
+*******************************************************************************/
+
+methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
+{
+       methodptr   mptr;
+       methodptr  *pmptr;
+       methodinfo *resm;                   /* pointer to new resolved method     */
+
+       /* If the method is not an instance method, just return it. */
+
+       if (m->flags & ACC_STATIC)
+               return m;
+
+       assert(vftbl);
+
+       /* Get the method from the virtual function table.  Is this an
+          interface method? */
+
+       if (m->clazz->flags & ACC_INTERFACE) {
+               pmptr = vftbl->interfacetable[-(m->clazz->index)];
+               mptr  = pmptr[(m - m->clazz->methods)];
+       }
+       else {
+               mptr = vftbl->table[m->vftblindex];
+       }
+
+       /* and now get the codeinfo pointer from the first data segment slot */
+
+       resm = code_get_methodinfo_for_pv(mptr);
+
+       return resm;
+}
+
+
+/* method_get_parametercount **************************************************
+
+   Use the descriptor of a method to determine the number of parameters
+   of the method. The this pointer of non-static methods is not counted.
+
+   IN:
+       m........the method of which the parameters should be counted
+
+   RETURN VALUE:
+       The parameter count or -1 on error.
+
+*******************************************************************************/
+
+int32_t method_get_parametercount(methodinfo *m)
+{
+       methoddesc *md;             /* method descriptor of m   */
+       int32_t     paramcount = 0; /* the parameter count of m */
+
+       md = m->parseddesc;
+       
+       /* is the descriptor fully parsed? */
+
+       if (md->params == NULL) {
+               if (!descriptor_params_from_paramtypes(md, m->flags)) {
+                       return -1;
+               }
+       }
+
+       paramcount = md->paramcount;
+
+       /* skip `this' pointer */
+
+       if (!(m->flags & ACC_STATIC)) {
+               --paramcount;
+       }
+
+       return paramcount;
+}
+
+
+/* method_get_parametertypearray ***********************************************
+
+   Use the descriptor of a method to generate a java.lang.Class array
+   which contains the classes of the parametertypes of the method.
+
+   This function is called by java.lang.reflect.{Constructor,Method}.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m)
+{
+       methoddesc                *md;
+       typedesc                  *paramtypes;
+       int32_t                    paramcount;
+       java_handle_objectarray_t *oa;
+       int32_t                    i;
+       classinfo                 *c;
+
+       md = m->parseddesc;
+
+       /* is the descriptor fully parsed? */
+
+       if (m->parseddesc->params == NULL)
+               if (!descriptor_params_from_paramtypes(md, m->flags))
+                       return NULL;
+
+       paramtypes = md->paramtypes;
+       paramcount = md->paramcount;
+
+       /* skip `this' pointer */
+
+       if (!(m->flags & ACC_STATIC)) {
+               paramtypes++;
+               paramcount--;
+       }
+
+       /* create class-array */
+
+       oa = builtin_anewarray(paramcount, class_java_lang_Class);
+
+       if (oa == NULL)
+               return NULL;
+
+    /* get classes */
+
+       for (i = 0; i < paramcount; i++) {
+               if (!resolve_class_from_typedesc(&paramtypes[i], true, false, &c))
+                       return NULL;
+
+               LLNI_array_direct(oa, i) = (java_object_t *) c;
+       }
+
+       return oa;
+}
+
+
+/* method_get_exceptionarray ***************************************************
+
+   Get the exceptions which can be thrown by a method.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m)
+{
+       java_handle_objectarray_t *oa;
+       classinfo                 *c;
+       s4                         i;
+
+       /* create class-array */
+
+       oa = builtin_anewarray(m->thrownexceptionscount, class_java_lang_Class);
+
+       if (oa == NULL)
+               return NULL;
+
+       /* iterate over all exceptions and store the class in the array */
+
+       for (i = 0; i < m->thrownexceptionscount; i++) {
+               c = resolve_classref_or_classinfo_eager(m->thrownexceptions[i], true);
+
+               if (c == NULL)
+                       return NULL;
+
+               LLNI_array_direct(oa, i) = (java_object_t *) c;
+       }
+
+       return oa;
+}
+
+
+/* method_returntype_get *******************************************************
+
+   Get the return type of the method.
+
+*******************************************************************************/
+
+classinfo *method_returntype_get(methodinfo *m)
+{
+       typedesc  *td;
+       classinfo *c;
+
+       td = &(m->parseddesc->returntype);
+
+       if (!resolve_class_from_typedesc(td, true, false, &c))
+               return NULL;
+
+       return c;
+}
+
+
+/* method_count_implementations ************************************************
+
+   Count the implementations of a method in a class cone (a class and all its
+   subclasses.)
+
+   IN:
+       m................the method to count
+          c................class at which to start the counting (this class and
+                           all its subclasses will be searched)
+
+   OUT:
+       *found...........if found != NULL, *found receives the method
+                           implementation that was found. This value is only
+                                               meaningful if the return value is 1.
+
+   RETURN VALUE:
+       the number of implementations found
+
+*******************************************************************************/
+
+s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
+{
+       s4          count;
+       methodinfo *mp;
+       methodinfo *mend;
+       classinfo  *child;
+
+       count = 0;
+
+       mp = c->methods;
+       mend = mp + c->methodscount;
+
+       for (; mp < mend; ++mp) {
+               if (method_canoverwrite(mp, m)) {
+                       if (found)
+                               *found = mp;
+                       count++;
+                       break;
+               }
+       }
+
+       for (child = c->sub; child != NULL; child = child->nextsub) {
+               count += method_count_implementations(m, child, found);
+       }
+
+       return count;
+}
+
+
+/* method_get_annotations ******************************************************
+
+   Get a methods' unparsed annotations in a byte array.
+
+   IN:
+       m........the method of which the annotations should be returned
+
+   RETURN VALUE:
+       The unparsed annotations in a byte array (or NULL if there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+       classinfo     *c;                  /* methods' declaring class          */
+       int            slot;               /* methods' slot                     */
+       java_handle_t *annotations;        /* methods' unparsed annotations     */
+       java_handle_t *method_annotations; /* all methods' unparsed annotations */
+                                          /* of the declaring class            */
+
+       c           = m->clazz;
+       slot        = m - c->methods;
+       annotations = NULL;
+
+       LLNI_classinfo_field_get(c, method_annotations, method_annotations);
+
+       /* the method_annotations array might be shorter then the method
+        * count if the methods above a certain index have no annotations.
+        */     
+       if (method_annotations != NULL &&
+               array_length_get(method_annotations) > slot) {
+               annotations = array_objectarray_element_get(
+                       (java_handle_objectarray_t*)method_annotations, slot);
+       }
+       
+       return (java_handle_bytearray_t*)annotations;
+#else
+       return NULL;
+#endif
+}
+
+
+/* method_get_parameterannotations ********************************************
+
+   Get a methods' unparsed parameter annotations in an array of byte
+   arrays.
+
+   IN:
+       m........the method of which the parameter annotations should be
+                   returned
+
+   RETURN VALUE:
+       The unparsed parameter annotations in a byte array (or NULL if
+          there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+       classinfo     *c;                           /* methods' declaring class */
+       int            slot;                        /* methods' slot            */
+       java_handle_t *parameterAnnotations;        /* methods' unparsed        */
+                                                   /* parameter annotations    */
+       java_handle_t *method_parameterannotations; /* all methods' unparsed    */
+                                                   /* parameter annotations of */
+                                                   /* the declaring class      */
+
+       c                    = m->clazz;
+       slot                 = m - c->methods;
+       parameterAnnotations = NULL;
+
+       LLNI_classinfo_field_get(
+               c, method_parameterannotations, method_parameterannotations);
+
+       /* the method_annotations array might be shorter then the method
+        * count if the methods above a certain index have no annotations.
+        */     
+       if (method_parameterannotations != NULL &&
+               array_length_get(method_parameterannotations) > slot) {
+               parameterAnnotations = array_objectarray_element_get(
+                               (java_handle_objectarray_t*)method_parameterannotations,
+                               slot);
+       }
+       
+       return (java_handle_bytearray_t*)parameterAnnotations;
+#else
+       return NULL;
+#endif
+}
+
+
+/* method_get_annotationdefault ***********************************************
+
+   Get a methods' unparsed annotation default value in a byte array.
+   
+   IN:
+       m........the method of which the annotation default value should be
+                   returned
+
+   RETURN VALUE:
+       The unparsed annotation default value in a byte array (or NULL if
+          there isn't one).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+       classinfo     *c;                         /* methods' declaring class     */
+       int            slot;                      /* methods' slot                */
+       java_handle_t *annotationDefault;         /* methods' unparsed            */
+                                                 /* annotation default value     */
+       java_handle_t *method_annotationdefaults; /* all methods' unparsed        */
+                                                 /* annotation default values of */
+                                                 /* the declaring class          */
+
+       c                 = m->clazz;
+       slot              = m - c->methods;
+       annotationDefault = NULL;
+
+       LLNI_classinfo_field_get(
+               c, method_annotationdefaults, method_annotationdefaults);
+
+       /* the method_annotations array might be shorter then the method
+        * count if the methods above a certain index have no annotations.
+        */     
+       if (method_annotationdefaults != NULL &&
+               array_length_get(method_annotationdefaults) > slot) {
+               annotationDefault = array_objectarray_element_get(
+                               (java_handle_objectarray_t*)method_annotationdefaults, slot);
+       }
+       
+       return (java_handle_bytearray_t*)annotationDefault;
+#else
+       return NULL;
+#endif
+}
+
+
+/* method_add_to_worklist ******************************************************
+
+   Add the method to the given worklist. If the method already occurs in
+   the worklist, the worklist remains unchanged.
+
+*******************************************************************************/
+
+static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
+{
+       method_worklist *wi;
+
+       for (wi = *wl; wi != NULL; wi = wi->next)
+               if (wi->m == m)
+                       return;
+
+       wi = NEW(method_worklist);
+       wi->next = *wl;
+       wi->m = m;
+
+       *wl = wi;
+}
+
+
+/* method_add_assumption_monomorphic *******************************************
+
+   Record the assumption that the method is monomorphic.
+
+   IN:
+      m.................the method
+         caller............the caller making the assumption
+
+*******************************************************************************/
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
+{
+       method_assumption *as;
+
+       /* XXX LOCKING FOR THIS FUNCTION? */
+
+       /* check if we already have registered this assumption */
+
+       for (as = m->assumptions; as != NULL; as = as->next) {
+               if (as->context == caller)
+                       return;
+       }
+
+       /* register the assumption */
+
+       as = NEW(method_assumption);
+       as->next = m->assumptions;
+       as->context = caller;
+
+       m->assumptions = as;
+}
+
+/* method_break_assumption_monomorphic *****************************************
+
+   Break the assumption that this method is monomorphic. All callers that
+   have registered this assumption are added to the worklist.
+
+   IN:
+      m.................the method
+         wl................worklist where to add invalidated callers
+
+*******************************************************************************/
+
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
+{
+       method_assumption *as;
+
+       /* XXX LOCKING FOR THIS FUNCTION? */
+
+       for (as = m->assumptions; as != NULL; as = as->next) {
+               INLINELOG(
+                       printf("ASSUMPTION BROKEN (monomorphism): ");
+                       method_print(m);
+                       printf(" in ");
+                       method_println(as->context);
+               );
+
+               method_add_to_worklist(as->context, wl);
+
+#if defined(ENABLE_TLH) && 0
+               /* XXX hack */
+               method_assumption *as2;
+               as2 = m->assumptions;
+               m->assumptions = NULL;
+               method_break_assumption_monomorphic(as->context, wl);
+               /*
+               assert(m->assumptions == NULL);
+               m->assumptions = as2;*/
+#endif
+
+       }
+}
+
+/* method_printflags ***********************************************************
+
+   Prints the flags of a method to stdout like.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_printflags(methodinfo *m)
+{
+       if (m == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       if (m->flags & ACC_PUBLIC)             printf(" PUBLIC");
+       if (m->flags & ACC_PRIVATE)            printf(" PRIVATE");
+       if (m->flags & ACC_PROTECTED)          printf(" PROTECTED");
+       if (m->flags & ACC_STATIC)             printf(" STATIC");
+       if (m->flags & ACC_FINAL)              printf(" FINAL");
+       if (m->flags & ACC_SYNCHRONIZED)       printf(" SYNCHRONIZED");
+       if (m->flags & ACC_VOLATILE)           printf(" VOLATILE");
+       if (m->flags & ACC_TRANSIENT)          printf(" TRANSIENT");
+       if (m->flags & ACC_NATIVE)             printf(" NATIVE");
+       if (m->flags & ACC_INTERFACE)          printf(" INTERFACE");
+       if (m->flags & ACC_ABSTRACT)           printf(" ABSTRACT");
+       if (m->flags & ACC_METHOD_BUILTIN)     printf(" (builtin)");
+       if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
+       if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_print ****************************************************************
+
+   Prints a method to stdout like:
+
+   java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_print(methodinfo *m)
+{
+       if (m == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       if (m->clazz != NULL)
+               utf_display_printable_ascii_classname(m->clazz->name);
+       else
+               printf("NULL");
+       printf(".");
+       utf_display_printable_ascii(m->name);
+       utf_display_printable_ascii(m->descriptor);
+
+       method_printflags(m);
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_println **************************************************************
+
+   Prints a method plus new line to stdout like:
+
+   java.lang.Object.<init>()V
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_println(methodinfo *m)
+{
+       if (opt_debugcolor) printf("\033[31m"); /* red */
+       method_print(m);
+       if (opt_debugcolor) printf("\033[m");   
+       printf("\n");
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_methodref_print ******************************************************
+
+   Prints a method reference to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_print(constant_FMIref *mr)
+{
+       if (!mr) {
+               printf("(constant_FMIref *)NULL");
+               return;
+       }
+
+       if (IS_FMIREF_RESOLVED(mr)) {
+               printf("<method> ");
+               method_print(mr->p.method);
+       }
+       else {
+               printf("<methodref> ");
+               utf_display_printable_ascii_classname(mr->p.classref->name);
+               printf(".");
+               utf_display_printable_ascii(mr->name);
+               utf_display_printable_ascii(mr->descriptor);
+       }
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* method_methodref_println ****************************************************
+
+   Prints a method reference to stdout, followed by a newline.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void method_methodref_println(constant_FMIref *mr)
+{
+       method_methodref_print(mr);
+       printf("\n");
+}
+#endif /* !defined(NDEBUG) */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/method.h b/src/vm/method.h
deleted file mode 100644 (file)
index 994a6c2..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/* src/vm/method.h - method functions header
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#ifndef _METHOD_H
-#define _METHOD_H
-
-/* forward typedefs ***********************************************************/
-
-typedef struct methodinfo          methodinfo; 
-typedef struct raw_exception_entry raw_exception_entry;
-typedef struct lineinfo            lineinfo; 
-typedef struct method_assumption   method_assumption;
-typedef struct method_worklist     method_worklist;
-typedef struct codeinfo            codeinfo;
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "threads/mutex.hpp"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/descriptor.h"
-#include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/references.h"
-
-#if defined(ENABLE_JAVASE)
-# include "vm/stackmap.h"
-#endif
-
-#include "vm/utf8.h"
-
-
-#if defined(ENABLE_REPLACEMENT)
-/* Initial value for the hit countdown field of each method. */
-#define METHOD_INITIAL_HIT_COUNTDOWN  1000
-#endif
-
-
-/* methodinfo *****************************************************************/
-
-struct methodinfo {                 /* method structure                       */
-       Mutex        *mutex;            /* we need this in jit's locking          */
-       s4            flags;            /* ACC flags                              */
-       utf          *name;             /* name of method                         */
-       utf          *descriptor;       /* JavaVM descriptor string of method     */
-#if defined(ENABLE_JAVASE)
-       utf          *signature;        /* Signature attribute                    */
-       stack_map_t  *stack_map;        /* StackMapTable attribute                */
-#endif
-
-       methoddesc   *parseddesc;       /* parsed descriptor                      */
-                            
-       classinfo    *clazz;            /* class, the method belongs to           */
-       s4            vftblindex;       /* index of method in virtual function    */
-                                       /* table (if it is a virtual method)      */
-       s4            maxstack;         /* maximum stack depth of method          */
-       s4            maxlocals;        /* maximum number of local variables      */
-       s4            jcodelength;      /* length of JavaVM code                  */
-       u1           *jcode;            /* pointer to JavaVM code                 */
-
-       s4            rawexceptiontablelength;  /* exceptiontable length          */
-       raw_exception_entry *rawexceptiontable; /* the exceptiontable             */
-
-       u2            thrownexceptionscount; /* number of exceptions attribute    */
-       classref_or_classinfo *thrownexceptions; /* except. a method may throw    */
-
-       u2            linenumbercount;  /* number of linenumber attributes        */
-       lineinfo     *linenumbers;      /* array of lineinfo items                */
-
-       u1           *stubroutine;      /* stub for compiling or calling natives  */
-       codeinfo     *code;             /* current code of this method            */
-
-#if defined(ENABLE_LSRA)
-       s4            maxlifetimes;     /* helper for lsra                        */
-#endif
-
-       methodinfo   *overwrites;       /* method that is directly overwritten    */
-       method_assumption *assumptions; /* list of assumptions about this method  */
-
-#if defined(ENABLE_REPLACEMENT)
-       s4            hitcountdown;     /* decreased for each hit                 */
-#endif
-
-#if defined(ENABLE_DEBUG_FILTER)
-       u1            filtermatches;    /* flags indicating which filters the method matches */
-#endif
-
-#if defined(ENABLE_ESCAPE)
-       u1           *paramescape;
-#endif
-};
-
-/* method_assumption ***********************************************************
-
-   This struct is used for registering assumptions about methods.
-
-*******************************************************************************/
-
-struct method_assumption {
-       method_assumption *next;
-       methodinfo        *context;
-};
-
-
-/* method_worklist *************************************************************
-
-   List node used for method worklists.
-
-*******************************************************************************/
-
-struct method_worklist {
-       method_worklist *next;
-       methodinfo      *m;
-};
-
-
-/* raw_exception_entry ********************************************************/
-
-/* exception table entry read by the loader */
-
-struct raw_exception_entry {    /* exceptiontable entry in a method           */
-       classref_or_classinfo catchtype; /* catchtype of exc. (0 == catchall)     */
-       u2              startpc;    /* start pc of guarded area (inclusive)       */
-       u2              endpc;      /* end pc of guarded area (exklusive)         */
-       u2              handlerpc;  /* pc of exception handler                    */
-};
-
-
-/* lineinfo *******************************************************************/
-
-struct lineinfo {
-       u2 start_pc;
-       u2 line_number;
-};
-
-
-/* global variables ***********************************************************/
-
-extern methodinfo *method_java_lang_reflect_Method_invoke;
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* inline functions ***********************************************************/
-
-inline static bool method_is_builtin(methodinfo* m)
-{
-       return m->flags & ACC_METHOD_BUILTIN;
-}
-
-
-/* function prototypes ********************************************************/
-
-void method_init(void);
-
-bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool);
-void method_free(methodinfo *m);
-bool method_canoverwrite(methodinfo *m, methodinfo *old);
-
-methodinfo *method_new_builtin(builtintable_entry *bte);
-
-methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m);
-
-int32_t                    method_get_parametercount(methodinfo *m);
-java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m);
-java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m);
-classinfo                 *method_returntype_get(methodinfo *m);
-
-void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller);
-void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl);
-
-s4   method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found);
-
-java_handle_bytearray_t *method_get_annotations(methodinfo *m);
-java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m);
-java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m);
-
-#if !defined(NDEBUG)
-void method_printflags(methodinfo *m);
-void method_print(methodinfo *m);
-void method_println(methodinfo *m);
-void method_methodref_print(constant_FMIref *mr);
-void method_methodref_println(constant_FMIref *mr);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _METHOD_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/method.hpp b/src/vm/method.hpp
new file mode 100644 (file)
index 0000000..754bacc
--- /dev/null
@@ -0,0 +1,230 @@
+/* src/vm/method.hpp - method functions header
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#ifndef _METHOD_H
+#define _METHOD_H
+
+/* forward typedefs ***********************************************************/
+
+typedef struct methodinfo          methodinfo; 
+typedef struct raw_exception_entry raw_exception_entry;
+typedef struct lineinfo            lineinfo; 
+typedef struct method_assumption   method_assumption;
+typedef struct method_worklist     method_worklist;
+typedef struct codeinfo            codeinfo;
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/descriptor.h"
+#include "vm/global.h"
+#include "vm/linker.h"
+#include "vm/loader.hpp"
+#include "vm/references.h"
+
+#if defined(ENABLE_JAVASE)
+# include "vm/stackmap.h"
+#endif
+
+#include "vm/utf8.h"
+
+
+#if defined(ENABLE_REPLACEMENT)
+/* Initial value for the hit countdown field of each method. */
+#define METHOD_INITIAL_HIT_COUNTDOWN  1000
+#endif
+
+/* methodinfo *****************************************************************/
+
+struct methodinfo {                 /* method structure                       */
+       Mutex        *mutex;            /* we need this in jit's locking          */
+       s4            flags;            /* ACC flags                              */
+       utf          *name;             /* name of method                         */
+       utf          *descriptor;       /* JavaVM descriptor string of method     */
+#if defined(ENABLE_JAVASE)
+       utf          *signature;        /* Signature attribute                    */
+       stack_map_t  *stack_map;        /* StackMapTable attribute                */
+#endif
+
+       methoddesc   *parseddesc;       /* parsed descriptor                      */
+                            
+       classinfo    *clazz;            /* class, the method belongs to           */
+       s4            vftblindex;       /* index of method in virtual function    */
+                                       /* table (if it is a virtual method)      */
+       s4            maxstack;         /* maximum stack depth of method          */
+       s4            maxlocals;        /* maximum number of local variables      */
+       s4            jcodelength;      /* length of JavaVM code                  */
+       u1           *jcode;            /* pointer to JavaVM code                 */
+
+       s4            rawexceptiontablelength;  /* exceptiontable length          */
+       raw_exception_entry *rawexceptiontable; /* the exceptiontable             */
+
+       u2            thrownexceptionscount; /* number of exceptions attribute    */
+       classref_or_classinfo *thrownexceptions; /* except. a method may throw    */
+
+       u2            linenumbercount;  /* number of linenumber attributes        */
+       lineinfo     *linenumbers;      /* array of lineinfo items                */
+
+       u1           *stubroutine;      /* stub for compiling or calling natives  */
+       codeinfo     *code;             /* current code of this method            */
+
+#if defined(ENABLE_LSRA)
+       s4            maxlifetimes;     /* helper for lsra                        */
+#endif
+
+       methodinfo   *overwrites;       /* method that is directly overwritten    */
+       method_assumption *assumptions; /* list of assumptions about this method  */
+
+#if defined(ENABLE_REPLACEMENT)
+       s4            hitcountdown;     /* decreased for each hit                 */
+#endif
+
+#if defined(ENABLE_DEBUG_FILTER)
+       u1            filtermatches;    /* flags indicating which filters the method matches */
+#endif
+
+#if defined(ENABLE_ESCAPE)
+       u1           *paramescape;
+#endif
+};
+
+/* method_assumption ***********************************************************
+
+   This struct is used for registering assumptions about methods.
+
+*******************************************************************************/
+
+struct method_assumption {
+       method_assumption *next;
+       methodinfo        *context;
+};
+
+
+/* method_worklist *************************************************************
+
+   List node used for method worklists.
+
+*******************************************************************************/
+
+struct method_worklist {
+       method_worklist *next;
+       methodinfo      *m;
+};
+
+
+/* raw_exception_entry ********************************************************/
+
+/* exception table entry read by the loader */
+
+struct raw_exception_entry {    /* exceptiontable entry in a method           */
+       classref_or_classinfo catchtype; /* catchtype of exc. (0 == catchall)     */
+       u2              startpc;    /* start pc of guarded area (inclusive)       */
+       u2              endpc;      /* end pc of guarded area (exklusive)         */
+       u2              handlerpc;  /* pc of exception handler                    */
+};
+
+
+/* lineinfo *******************************************************************/
+
+struct lineinfo {
+       u2 start_pc;
+       u2 line_number;
+};
+
+
+/* global variables ***********************************************************/
+
+extern methodinfo *method_java_lang_reflect_Method_invoke;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* inline functions ***********************************************************/
+
+inline static bool method_is_builtin(methodinfo* m)
+{
+       return m->flags & ACC_METHOD_BUILTIN;
+}
+
+
+/* function prototypes ********************************************************/
+
+void method_init(void);
+
+bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool);
+void method_free(methodinfo *m);
+bool method_canoverwrite(methodinfo *m, methodinfo *old);
+
+methodinfo *method_new_builtin(builtintable_entry *bte);
+
+methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m);
+
+int32_t                    method_get_parametercount(methodinfo *m);
+java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m);
+java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m);
+classinfo                 *method_returntype_get(methodinfo *m);
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller);
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl);
+
+s4   method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found);
+
+java_handle_bytearray_t *method_get_annotations(methodinfo *m);
+java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m);
+java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m);
+
+#if !defined(NDEBUG)
+void method_printflags(methodinfo *m);
+void method_print(methodinfo *m);
+void method_println(methodinfo *m);
+void method_methodref_print(constant_FMIref *mr);
+void method_methodref_println(constant_FMIref *mr);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _METHOD_H */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
index f59188d2e672ce7eeb2d63e5d42890103fc79576..f5b66db4d3b487236a19f6461e24ebd148877eba 100644 (file)
@@ -42,7 +42,7 @@
 
 #include "vm/class.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/os.hpp"
 #include "vm/properties.hpp"
index f29d69fc594483a64a47f3b2676918f8e75beafe..a24d975f38bbf33ff2e84a694ea61f141f6524ff 100644 (file)
@@ -65,7 +65,7 @@ typedef union parseddesc {
 #include "vm/descriptor.h"
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/utf8.h"
 
 
index 0dc57ef3e31d6b288b1b487ef0c15cef93f58bf0..e5b90991e8995d84fc6357d8d9e504775bcdda37 100644 (file)
@@ -32,7 +32,7 @@
 #include "mm/memory.h"
 
 #include "vm/access.h"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/descriptor.h"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
index dc6ccfc1c36bee122d66b5d41428c383c051dd48..f75f1733813d7f5794871d966d1ab79d76559421 100644 (file)
@@ -40,7 +40,7 @@ typedef struct unresolved_subtype_set unresolved_subtype_set;
 #include "vm/class.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 
 #include "vm/jit/jit.hpp"
index 345db3dd2b2bc281c5efb9ef73c4dfe1f2407b82..ed7d495e4d9273953ea74f2f25532f09e509fdbc 100644 (file)
@@ -48,7 +48,7 @@
 
 #include "vm/exceptions.hpp"
 #include "vm/globals.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/signallocal.h"
 #include "vm/vm.hpp"
index ecbb6e916f667197ac3a791332e1021011197372..87117d05e8f6dc3a6590b4da9be4c53286bb178a 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "vm/class.hpp"
 #include "vm/exceptions.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/stackmap.h"
 #include "vm/statistics.h"
index ff9c5e581072e6cc6d1fbe81ca72af1c60aea689..fb900863d54dcc3e625cac28022a825a78bae754 100644 (file)
@@ -54,7 +54,7 @@ typedef struct Uninitialized_variable_info_t     Uninitialized_variable_info_t;
 
 #include "vm/global.h"
 #include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* verification_type_info *****************************************************/
@@ -206,11 +206,18 @@ union stack_map_frame_t {
        full_frame_t                              full_frame;
 };
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
 
 /* function prototypes ********************************************************/
 
 bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _STACKMAP_H */
 
 
index 8ab2f6fd509fee91404cca97fe80ad1577e98f24..2088b2d8a49e98fb84279f9fec85c2ef8e0212db 100644 (file)
@@ -51,7 +51,7 @@
 #include "vm/class.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/options.h"
 #include "vm/statistics.h"
 
index 8fd0699701f2be4217a3747e5ed0faa487b34336..1c1664a7ed4dfb94c2a78762701ddf57ff6668fc 100644 (file)
@@ -47,7 +47,7 @@
 #include "vm/properties.hpp"
 #include "vm/suck.hpp"
 #include "vm/vm.hpp"
-#include "vm/zip.h"
+#include "vm/zip.hpp"
 
 
 /* global variables ***********************************************************/
index f50e37732d3b5b91cfa91b46d7a23e9cdbc0f859..28fff0ae91e89fb3f1ac502a440a75e19957695a 100644 (file)
@@ -64,7 +64,7 @@
 #endif
 
 #include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/finalizer.h"
 #include "vm/global.h"
index 6e3d54d37c09e765d89ec7ba476d451dce388b3a..4a73ecc351cc86456f08dba13ef3d366d3267745 100644 (file)
@@ -120,7 +120,7 @@ int64_t VM_get_starttime();
 
 // Includes.
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 
 
 /* These C methods are the exported interface. ********************************/
diff --git a/src/vm/zip.c b/src/vm/zip.c
deleted file mode 100644 (file)
index 1091560..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/* src/vm/zip.c - ZIP file handling for bootstrap classloader
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <zlib.h>
-#include <sys/mman.h>
-
-#include "vm/types.h"
-
-#include "vm/descriptor.h" /* needed to prevent circular dependency */
-#include "toolbox/hashtable.h"
-
-#include "mm/memory.h"
-
-#include "vm/global.h"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-#include "vm/vm.hpp"
-#include "vm/zip.h"
-
-
-/* start size for classes hashtable *******************************************/
-
-#define HASHTABLE_CLASSES_SIZE    (1 << 10)
-
-
-/* info taken from:
-   http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
-*/
-
-/* all signatures in the ZIP file have a length of 4 bytes ********************/
-
-#define SIGNATURE_LENGTH    4
-
-/* Central directory structure *************************************************
-
-   [file header 1]
-   .
-   .
-   . 
-   [file header n]
-   [digital signature] 
-   
-   File header:
-   
-     central file header signature   4 bytes  (0x02014b50)
-     version made by                 2 bytes
-     version needed to extract       2 bytes
-     general purpose bit flag        2 bytes
-     compression method              2 bytes
-     last mod file time              2 bytes
-     last mod file date              2 bytes
-     crc-32                          4 bytes
-     compressed size                 4 bytes
-     uncompressed size               4 bytes
-     file name length                2 bytes
-     extra field length              2 bytes
-     file comment length             2 bytes
-     disk number start               2 bytes
-     internal file attributes        2 bytes
-     external file attributes        4 bytes
-     relative offset of local header 4 bytes
-   
-     file name (variable size)
-     extra field (variable size)
-     file comment (variable size)
-
-   Digital signature:
-   
-     header signature                4 bytes  (0x05054b50)
-     size of data                    2 bytes
-     signature data (variable size)
-
-*******************************************************************************/
-
-#define CDSFH_HEADER_SIZE            46
-
-#define CDSFH_SIGNATURE              0x02014b50
-#define CDSFH_COMPRESSION_METHOD     10
-#define CDSFH_COMPRESSED_SIZE        20
-#define CDSFH_UNCOMPRESSED_SIZE      24
-#define CDSFH_FILE_NAME_LENGTH       28
-#define CDSFH_EXTRA_FIELD_LENGTH     30
-#define CDSFH_FILE_COMMENT_LENGTH    32
-#define CDSFH_RELATIVE_OFFSET        42
-#define CDSFH_FILENAME               46
-
-typedef struct cdsfh cdsfh;
-
-struct cdsfh {
-       u2 compressionmethod;
-       u4 compressedsize;
-       u4 uncompressedsize;
-       u2 filenamelength;
-       u2 extrafieldlength;
-       u2 filecommentlength;
-       u4 relativeoffset;
-};
-
-
-/* End of central directory record *********************************************
-
-   end of central dir signature    4 bytes  (0x06054b50)
-   number of this disk             2 bytes
-   number of the disk with the
-   start of the central directory  2 bytes
-   total number of entries in the
-   central directory on this disk  2 bytes
-   total number of entries in
-   the central directory           2 bytes
-   size of the central directory   4 bytes
-   offset of start of central
-   directory with respect to
-   the starting disk number        4 bytes
-   .ZIP file comment length        2 bytes
-   .ZIP file comment       (variable size)
-
-*******************************************************************************/
-
-#define EOCDR_SIGNATURE              0x06054b50
-#define EOCDR_ENTRIES                10
-#define EOCDR_OFFSET                 16
-
-typedef struct eocdr eocdr;
-
-struct eocdr {
-       u2 entries;
-       u4 offset;
-};
-
-
-/* zip_open ********************************************************************
-
-   XXX
-
-*******************************************************************************/
-
-hashtable *zip_open(char *path)
-{
-       hashtable               *ht;
-       hashtable_zipfile_entry *htzfe;
-       int                      fd;
-       u1                       lfh_signature[SIGNATURE_LENGTH];
-       off_t                    len;
-       u1                      *filep;
-       s4                       i;
-       u1                      *p;
-       eocdr                    eocdr;
-       cdsfh                    cdsfh;
-       const char              *filename;
-       const char              *classext;
-       utf                     *u;
-       u4                       key;       /* hashkey computed from utf-text     */
-       u4                       slot;      /* slot in hashtable                  */
-
-       /* first of all, open the file */
-
-       if ((fd = open(path, O_RDONLY)) == -1)
-               return NULL;
-
-       /* check for signature in first local file header */
-
-       if (read(fd, lfh_signature, SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
-               return NULL;
-
-       if (SUCK_LE_U4(lfh_signature) != LFH_SIGNATURE)
-               return NULL;
-
-       /* get the file length */
-
-       if ((len = lseek(fd, 0, SEEK_END)) == -1)
-               return NULL;
-
-       /* we better mmap the file */
-
-       filep = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
-
-       /* some older compilers, like DEC OSF cc, don't like comparisons
-       on void* types */
-
-       if ((ptrint) filep == (ptrint) MAP_FAILED)
-               return NULL;
-
-       /* find end of central directory record */
-
-       for (p = filep + len; p >= filep; p--)
-               if (SUCK_LE_U4(p) == EOCDR_SIGNATURE)
-                       break;
-
-       /* get number of entries in central directory */
-
-       eocdr.entries = SUCK_LE_U2(p + EOCDR_ENTRIES);
-       eocdr.offset  = SUCK_LE_U4(p + EOCDR_OFFSET);
-
-       /* create hashtable for filenames */
-
-       ht = NEW(hashtable);
-
-       hashtable_create(ht, HASHTABLE_CLASSES_SIZE);
-
-       /* add all file entries into the hashtable */
-
-       for (i = 0, p = filep + eocdr.offset; i < eocdr.entries; i++) {
-               /* check file header signature */
-
-               if (SUCK_LE_U4(p) != CDSFH_SIGNATURE)
-                       return NULL;
-
-               /* we found an entry */
-
-               cdsfh.compressionmethod = SUCK_LE_U2(p + CDSFH_COMPRESSION_METHOD);
-               cdsfh.compressedsize    = SUCK_LE_U4(p + CDSFH_COMPRESSED_SIZE);
-               cdsfh.uncompressedsize  = SUCK_LE_U4(p + CDSFH_UNCOMPRESSED_SIZE);
-               cdsfh.filenamelength    = SUCK_LE_U2(p + CDSFH_FILE_NAME_LENGTH);
-               cdsfh.extrafieldlength  = SUCK_LE_U2(p + CDSFH_EXTRA_FIELD_LENGTH);
-               cdsfh.filecommentlength = SUCK_LE_U2(p + CDSFH_FILE_COMMENT_LENGTH);
-               cdsfh.relativeoffset    = SUCK_LE_U4(p + CDSFH_RELATIVE_OFFSET);
-
-               /* create utf8 string of filename, strip .class from classes */
-
-               filename = (const char *) (p + CDSFH_FILENAME);
-               classext = filename + cdsfh.filenamelength - strlen(".class");
-
-               /* skip directory entries */
-
-               if (filename[cdsfh.filenamelength - 1] != '/') {
-                       if (strncmp(classext, ".class", strlen(".class")) == 0)
-                               u = utf_new(filename, cdsfh.filenamelength - strlen(".class"));
-                       else
-                               u = utf_new(filename, cdsfh.filenamelength);
-
-                       /* insert class into hashtable */
-
-                       htzfe = NEW(hashtable_zipfile_entry);
-
-                       htzfe->filename          = u;
-                       htzfe->compressionmethod = cdsfh.compressionmethod;
-                       htzfe->compressedsize    = cdsfh.compressedsize;
-                       htzfe->uncompressedsize  = cdsfh.uncompressedsize;
-                       htzfe->data              = filep + cdsfh.relativeoffset;
-
-                       /* get hashtable slot */
-
-                       key  = utf_hashkey(u->text, u->blength);
-                       slot = key & (ht->size - 1);
-
-                       /* insert into external chain */
-
-                       htzfe->hashlink = ht->ptr[slot];
-
-                       /* insert hashtable zipfile entry */
-
-                       ht->ptr[slot] = htzfe;
-                       ht->entries++;
-               }
-
-               /* move to next central directory structure file header */
-
-               p = p +
-                       CDSFH_HEADER_SIZE +
-                       cdsfh.filenamelength +
-                       cdsfh.extrafieldlength +
-                       cdsfh.filecommentlength;
-       }
-
-       /* return pointer to hashtable */
-
-       return ht;
-}
-
-
-/* zip_find ********************************************************************
-
-   Search for the given filename in the classpath entries of a zip file.
-
-   NOTE: The '.class' extension is stripped when reading a zip file, so if
-   you want to find a .class file, you must search for its name _without_
-   the '.class' extension. 
-   XXX I dont like that, it makes foo and foo.class ambiguous. -Edwin
-
-   IN:
-      lce..........the classpath entries for the zip file
-         u............the filename to look for
-
-   RETURN VALUE:
-      hashtable_zipfile_entry * of the entry if found, or
-         NULL if not found
-
-*******************************************************************************/
-
-hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u)
-{
-       hashtable               *ht;
-       u4                       key;       /* hashkey computed from utf-text     */
-       u4                       slot;      /* slot in hashtable                  */
-       hashtable_zipfile_entry *htzfe;     /* hashtable element                  */
-
-       /* get classes hashtable from the classpath entry */
-
-       ht = lce->htclasses;
-
-       /* get the hashtable slot of the name searched */
-
-       key   = utf_hashkey(u->text, u->blength);
-       slot  = key & (ht->size - 1);
-       htzfe = ht->ptr[slot];
-
-       /* search external hash chain for utf-symbol */
-
-       while (htzfe) {
-               if (htzfe->filename == u)
-                       return htzfe;
-
-               /* next element in external chain */
-
-               htzfe = htzfe->hashlink;
-       }
-
-       /* file not found in this archive */
-
-       return NULL;
-}
-
-
-/* zip_get ********************************************************************
-
-   XXX
-
-*******************************************************************************/
-
-classbuffer *zip_get(list_classpath_entry *lce, classinfo *c)
-{
-       hashtable_zipfile_entry *htzfe;
-       lfh                      lfh;
-       u1                      *indata;
-       u1                      *outdata;
-       z_stream                 zs;
-       int                      err;
-       classbuffer             *cb;
-
-       /* try to find the class in the current archive */
-
-       htzfe = zip_find(lce, c->name);
-
-       if (htzfe == NULL)
-               return NULL;
-
-       /* read stuff from local file header */
-
-       lfh.filenamelength   = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
-       lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
-
-       indata = htzfe->data +
-               LFH_HEADER_SIZE +
-               lfh.filenamelength +
-               lfh.extrafieldlength;
-
-       /* allocate buffer for uncompressed data */
-
-       outdata = MNEW(u1, htzfe->uncompressedsize);
-
-       /* how is the file stored? */
-
-       switch (htzfe->compressionmethod) {
-       case Z_DEFLATED:
-               /* fill z_stream structure */
-
-               zs.next_in   = indata;
-               zs.avail_in  = htzfe->compressedsize;
-               zs.next_out  = outdata;
-               zs.avail_out = htzfe->uncompressedsize;
-
-               zs.zalloc = Z_NULL;
-               zs.zfree  = Z_NULL;
-               zs.opaque = Z_NULL;
-
-               /* initialize this inflate run */
-
-               if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
-                       vm_abort("zip_get: inflateInit2 failed: %s", strerror(errno));
-
-               /* decompress the file into buffer */
-
-               err = inflate(&zs, Z_SYNC_FLUSH);
-
-               if ((err != Z_STREAM_END) && (err != Z_OK))
-                       vm_abort("zip_get: inflate failed: %s", strerror(errno));
-
-               /* finish this inflate run */
-
-               if (inflateEnd(&zs) != Z_OK)
-                       vm_abort("zip_get: inflateEnd failed: %s", strerror(errno));
-               break;
-
-       case 0:
-               /* uncompressed file, just copy the data */
-               MCOPY(outdata, indata, u1, htzfe->compressedsize);
-               break;
-
-       default:
-               vm_abort("zip_get: unknown compression method %d",
-                                htzfe->compressionmethod);
-       }
-       
-       /* allocate classbuffer */
-
-       cb = NEW(classbuffer);
-
-       cb->clazz = c;
-       cb->size  = htzfe->uncompressedsize;
-       cb->data  = outdata;
-       cb->pos   = outdata;
-       cb->path  = lce->path;
-
-       /* return the filled classbuffer structure */
-
-       return cb;
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/zip.cpp b/src/vm/zip.cpp
new file mode 100644 (file)
index 0000000..841109a
--- /dev/null
@@ -0,0 +1,466 @@
+/* src/vm/zip.cpp - ZIP file handling for bootstrap classloader
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+#include <sys/mman.h>
+
+#include "vm/types.h"
+
+#include "vm/descriptor.h" /* needed to prevent circular dependency */
+#include "toolbox/hashtable.h"
+
+#include "mm/memory.h"
+
+#include "vm/global.h"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+#include "vm/zip.hpp"
+
+
+/* start size for classes hashtable *******************************************/
+
+#define HASHTABLE_CLASSES_SIZE    (1 << 10)
+
+
+/* info taken from:
+   http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
+*/
+
+/* all signatures in the ZIP file have a length of 4 bytes ********************/
+
+#define SIGNATURE_LENGTH    4
+
+/* Central directory structure *************************************************
+
+   [file header 1]
+   .
+   .
+   . 
+   [file header n]
+   [digital signature] 
+   
+   File header:
+   
+     central file header signature   4 bytes  (0x02014b50)
+     version made by                 2 bytes
+     version needed to extract       2 bytes
+     general purpose bit flag        2 bytes
+     compression method              2 bytes
+     last mod file time              2 bytes
+     last mod file date              2 bytes
+     crc-32                          4 bytes
+     compressed size                 4 bytes
+     uncompressed size               4 bytes
+     file name length                2 bytes
+     extra field length              2 bytes
+     file comment length             2 bytes
+     disk number start               2 bytes
+     internal file attributes        2 bytes
+     external file attributes        4 bytes
+     relative offset of local header 4 bytes
+   
+     file name (variable size)
+     extra field (variable size)
+     file comment (variable size)
+
+   Digital signature:
+   
+     header signature                4 bytes  (0x05054b50)
+     size of data                    2 bytes
+     signature data (variable size)
+
+*******************************************************************************/
+
+#define CDSFH_HEADER_SIZE            46
+
+#define CDSFH_SIGNATURE              0x02014b50
+#define CDSFH_COMPRESSION_METHOD     10
+#define CDSFH_COMPRESSED_SIZE        20
+#define CDSFH_UNCOMPRESSED_SIZE      24
+#define CDSFH_FILE_NAME_LENGTH       28
+#define CDSFH_EXTRA_FIELD_LENGTH     30
+#define CDSFH_FILE_COMMENT_LENGTH    32
+#define CDSFH_RELATIVE_OFFSET        42
+#define CDSFH_FILENAME               46
+
+typedef struct cdsfh cdsfh;
+
+struct cdsfh {
+       u2 compressionmethod;
+       u4 compressedsize;
+       u4 uncompressedsize;
+       u2 filenamelength;
+       u2 extrafieldlength;
+       u2 filecommentlength;
+       u4 relativeoffset;
+};
+
+
+/* End of central directory record *********************************************
+
+   end of central dir signature    4 bytes  (0x06054b50)
+   number of this disk             2 bytes
+   number of the disk with the
+   start of the central directory  2 bytes
+   total number of entries in the
+   central directory on this disk  2 bytes
+   total number of entries in
+   the central directory           2 bytes
+   size of the central directory   4 bytes
+   offset of start of central
+   directory with respect to
+   the starting disk number        4 bytes
+   .ZIP file comment length        2 bytes
+   .ZIP file comment       (variable size)
+
+*******************************************************************************/
+
+#define EOCDR_SIGNATURE              0x06054b50
+#define EOCDR_ENTRIES                10
+#define EOCDR_OFFSET                 16
+
+typedef struct eocdr eocdr;
+
+struct eocdr {
+       u2 entries;
+       u4 offset;
+};
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* zip_open ********************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+hashtable *zip_open(char *path)
+{
+       hashtable               *ht;
+       hashtable_zipfile_entry *htzfe;
+       int                      fd;
+       u1                       lfh_signature[SIGNATURE_LENGTH];
+       off_t                    len;
+       u1                      *filep;
+       s4                       i;
+       u1                      *p;
+       eocdr                    eocdr;
+       cdsfh                    cdsfh;
+       const char              *filename;
+       const char              *classext;
+       utf                     *u;
+       u4                       key;       /* hashkey computed from utf-text     */
+       u4                       slot;      /* slot in hashtable                  */
+
+       /* first of all, open the file */
+
+       if ((fd = open(path, O_RDONLY)) == -1)
+               return NULL;
+
+       /* check for signature in first local file header */
+
+       if (read(fd, lfh_signature, SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
+               return NULL;
+
+       if (SUCK_LE_U4(lfh_signature) != LFH_SIGNATURE)
+               return NULL;
+
+       /* get the file length */
+
+       if ((len = lseek(fd, 0, SEEK_END)) == -1)
+               return NULL;
+
+       /* we better mmap the file */
+
+       filep = (u1*) mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+       /* some older compilers, like DEC OSF cc, don't like comparisons
+       on void* types */
+
+       if ((ptrint) filep == (ptrint) MAP_FAILED)
+               return NULL;
+
+       /* find end of central directory record */
+
+       for (p = filep + len; p >= filep; p--)
+               if (SUCK_LE_U4(p) == EOCDR_SIGNATURE)
+                       break;
+
+       /* get number of entries in central directory */
+
+       eocdr.entries = SUCK_LE_U2(p + EOCDR_ENTRIES);
+       eocdr.offset  = SUCK_LE_U4(p + EOCDR_OFFSET);
+
+       /* create hashtable for filenames */
+
+       ht = NEW(hashtable);
+
+       hashtable_create(ht, HASHTABLE_CLASSES_SIZE);
+
+       /* add all file entries into the hashtable */
+
+       for (i = 0, p = filep + eocdr.offset; i < eocdr.entries; i++) {
+               /* check file header signature */
+
+               if (SUCK_LE_U4(p) != CDSFH_SIGNATURE)
+                       return NULL;
+
+               /* we found an entry */
+
+               cdsfh.compressionmethod = SUCK_LE_U2(p + CDSFH_COMPRESSION_METHOD);
+               cdsfh.compressedsize    = SUCK_LE_U4(p + CDSFH_COMPRESSED_SIZE);
+               cdsfh.uncompressedsize  = SUCK_LE_U4(p + CDSFH_UNCOMPRESSED_SIZE);
+               cdsfh.filenamelength    = SUCK_LE_U2(p + CDSFH_FILE_NAME_LENGTH);
+               cdsfh.extrafieldlength  = SUCK_LE_U2(p + CDSFH_EXTRA_FIELD_LENGTH);
+               cdsfh.filecommentlength = SUCK_LE_U2(p + CDSFH_FILE_COMMENT_LENGTH);
+               cdsfh.relativeoffset    = SUCK_LE_U4(p + CDSFH_RELATIVE_OFFSET);
+
+               /* create utf8 string of filename, strip .class from classes */
+
+               filename = (const char *) (p + CDSFH_FILENAME);
+               classext = filename + cdsfh.filenamelength - strlen(".class");
+
+               /* skip directory entries */
+
+               if (filename[cdsfh.filenamelength - 1] != '/') {
+                       if (strncmp(classext, ".class", strlen(".class")) == 0)
+                               u = utf_new(filename, cdsfh.filenamelength - strlen(".class"));
+                       else
+                               u = utf_new(filename, cdsfh.filenamelength);
+
+                       /* insert class into hashtable */
+
+                       htzfe = NEW(hashtable_zipfile_entry);
+
+                       htzfe->filename          = u;
+                       htzfe->compressionmethod = cdsfh.compressionmethod;
+                       htzfe->compressedsize    = cdsfh.compressedsize;
+                       htzfe->uncompressedsize  = cdsfh.uncompressedsize;
+                       htzfe->data              = filep + cdsfh.relativeoffset;
+
+                       /* get hashtable slot */
+
+                       key  = utf_hashkey(u->text, u->blength);
+                       slot = key & (ht->size - 1);
+
+                       /* insert into external chain */
+
+                       htzfe->hashlink = (hashtable_zipfile_entry*) ht->ptr[slot];
+
+                       /* insert hashtable zipfile entry */
+
+                       ht->ptr[slot] = htzfe;
+                       ht->entries++;
+               }
+
+               /* move to next central directory structure file header */
+
+               p = p +
+                       CDSFH_HEADER_SIZE +
+                       cdsfh.filenamelength +
+                       cdsfh.extrafieldlength +
+                       cdsfh.filecommentlength;
+       }
+
+       /* return pointer to hashtable */
+
+       return ht;
+}
+
+
+/* zip_find ********************************************************************
+
+   Search for the given filename in the classpath entries of a zip file.
+
+   NOTE: The '.class' extension is stripped when reading a zip file, so if
+   you want to find a .class file, you must search for its name _without_
+   the '.class' extension. 
+   XXX I dont like that, it makes foo and foo.class ambiguous. -Edwin
+
+   IN:
+      lce..........the classpath entries for the zip file
+         u............the filename to look for
+
+   RETURN VALUE:
+      hashtable_zipfile_entry * of the entry if found, or
+         NULL if not found
+
+*******************************************************************************/
+
+hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u)
+{
+       hashtable               *ht;
+       u4                       key;       /* hashkey computed from utf-text     */
+       u4                       slot;      /* slot in hashtable                  */
+       hashtable_zipfile_entry *htzfe;     /* hashtable element                  */
+
+       /* get classes hashtable from the classpath entry */
+
+       ht = lce->htclasses;
+
+       /* get the hashtable slot of the name searched */
+
+       key   = utf_hashkey(u->text, u->blength);
+       slot  = key & (ht->size - 1);
+       htzfe = (hashtable_zipfile_entry*) ht->ptr[slot];
+
+       /* search external hash chain for utf-symbol */
+
+       while (htzfe) {
+               if (htzfe->filename == u)
+                       return htzfe;
+
+               /* next element in external chain */
+
+               htzfe = htzfe->hashlink;
+       }
+
+       /* file not found in this archive */
+
+       return NULL;
+}
+
+
+/* zip_get ********************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+classbuffer *zip_get(list_classpath_entry *lce, classinfo *c)
+{
+       hashtable_zipfile_entry *htzfe;
+       lfh                      lfh;
+       u1                      *indata;
+       u1                      *outdata;
+       z_stream                 zs;
+       int                      err;
+       classbuffer             *cb;
+
+       /* try to find the class in the current archive */
+
+       htzfe = zip_find(lce, c->name);
+
+       if (htzfe == NULL)
+               return NULL;
+
+       /* read stuff from local file header */
+
+       lfh.filenamelength   = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
+       lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
+
+       indata = htzfe->data +
+               LFH_HEADER_SIZE +
+               lfh.filenamelength +
+               lfh.extrafieldlength;
+
+       /* allocate buffer for uncompressed data */
+
+       outdata = MNEW(u1, htzfe->uncompressedsize);
+
+       /* how is the file stored? */
+
+       switch (htzfe->compressionmethod) {
+       case Z_DEFLATED:
+               /* fill z_stream structure */
+
+               zs.next_in   = indata;
+               zs.avail_in  = htzfe->compressedsize;
+               zs.next_out  = outdata;
+               zs.avail_out = htzfe->uncompressedsize;
+
+               zs.zalloc = Z_NULL;
+               zs.zfree  = Z_NULL;
+               zs.opaque = Z_NULL;
+
+               /* initialize this inflate run */
+
+               if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
+                       vm_abort("zip_get: inflateInit2 failed: %s", strerror(errno));
+
+               /* decompress the file into buffer */
+
+               err = inflate(&zs, Z_SYNC_FLUSH);
+
+               if ((err != Z_STREAM_END) && (err != Z_OK))
+                       vm_abort("zip_get: inflate failed: %s", strerror(errno));
+
+               /* finish this inflate run */
+
+               if (inflateEnd(&zs) != Z_OK)
+                       vm_abort("zip_get: inflateEnd failed: %s", strerror(errno));
+               break;
+
+       case 0:
+               /* uncompressed file, just copy the data */
+               MCOPY(outdata, indata, u1, htzfe->compressedsize);
+               break;
+
+       default:
+               vm_abort("zip_get: unknown compression method %d",
+                                htzfe->compressionmethod);
+       }
+       
+       /* allocate classbuffer */
+
+       cb = NEW(classbuffer);
+
+       cb->clazz = c;
+       cb->size  = htzfe->uncompressedsize;
+       cb->data  = outdata;
+       cb->pos   = outdata;
+       cb->path  = lce->path;
+
+       /* return the filled classbuffer structure */
+
+       return cb;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/zip.h b/src/vm/zip.h
deleted file mode 100644 (file)
index b95dae1..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* src/vm/zip.c - ZIP file handling for bootstrap classloader
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   This file is part of CACAO.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#ifndef _ZIP_H
-#define _ZIP_H
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "toolbox/hashtable.h"
-
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/loader.hpp"
-#include "vm/suck.hpp"
-#include "vm/utf8.h"
-
-
-/* Local file header ***********************************************************
-
-   local file header signature     4 bytes  (0x04034b50)
-   version needed to extract       2 bytes
-   general purpose bit flag        2 bytes
-   compression method              2 bytes
-   last mod file time              2 bytes
-   last mod file date              2 bytes
-   crc-32                          4 bytes
-   compressed size                 4 bytes
-   uncompressed size               4 bytes
-   file name length                2 bytes
-   extra field length              2 bytes
-
-   file name (variable size)
-   extra field (variable size)
-
-*******************************************************************************/
-
-#define LFH_HEADER_SIZE              30
-
-#define LFH_SIGNATURE                0x04034b50
-#define LFH_FILE_NAME_LENGTH         26
-#define LFH_EXTRA_FIELD_LENGTH       28
-
-typedef struct lfh lfh;
-
-struct lfh {
-       u2 compressionmethod;
-       u4 compressedsize;
-       u4 uncompressedsize;
-       u2 filenamelength;
-       u2 extrafieldlength;
-};
-
-/* hashtable_zipfile_entry ****************************************************/
-
-typedef struct hashtable_zipfile_entry hashtable_zipfile_entry;
-
-struct hashtable_zipfile_entry {
-       utf                     *filename;
-       u2                       compressionmethod;
-       u4                       compressedsize;
-       u4                       uncompressedsize;
-       u1                      *data;
-       hashtable_zipfile_entry *hashlink;
-};
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-hashtable *zip_open(char *path);
-hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u);
-classbuffer *zip_get(list_classpath_entry *lce, classinfo *c);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZIP_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/src/vm/zip.hpp b/src/vm/zip.hpp
new file mode 100644 (file)
index 0000000..6605535
--- /dev/null
@@ -0,0 +1,118 @@
+/* src/vm/zip.cpp - ZIP file handling for bootstrap classloader
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#ifndef _ZIP_HPP
+#define _ZIP_HPP
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "toolbox/hashtable.h"
+
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/loader.hpp"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+
+
+/* Local file header ***********************************************************
+
+   local file header signature     4 bytes  (0x04034b50)
+   version needed to extract       2 bytes
+   general purpose bit flag        2 bytes
+   compression method              2 bytes
+   last mod file time              2 bytes
+   last mod file date              2 bytes
+   crc-32                          4 bytes
+   compressed size                 4 bytes
+   uncompressed size               4 bytes
+   file name length                2 bytes
+   extra field length              2 bytes
+
+   file name (variable size)
+   extra field (variable size)
+
+*******************************************************************************/
+
+#define LFH_HEADER_SIZE              30
+
+#define LFH_SIGNATURE                0x04034b50
+#define LFH_FILE_NAME_LENGTH         26
+#define LFH_EXTRA_FIELD_LENGTH       28
+
+typedef struct lfh lfh;
+
+struct lfh {
+       u2 compressionmethod;
+       u4 compressedsize;
+       u4 uncompressedsize;
+       u2 filenamelength;
+       u2 extrafieldlength;
+};
+
+/* hashtable_zipfile_entry ****************************************************/
+
+typedef struct hashtable_zipfile_entry hashtable_zipfile_entry;
+
+struct hashtable_zipfile_entry {
+       utf                     *filename;
+       u2                       compressionmethod;
+       u4                       compressedsize;
+       u4                       uncompressedsize;
+       u1                      *data;
+       hashtable_zipfile_entry *hashlink;
+};
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+hashtable *zip_open(char *path);
+hashtable_zipfile_entry *zip_find(list_classpath_entry *lce, utf *u);
+classbuffer *zip_get(list_classpath_entry *lce, classinfo *c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIP_HPP */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */